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 /*
22e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/systm.h>
287c478bd9Sstevel@tonic-gate #include <sys/stream.h>
291d19ca10Svi #include <sys/cmn_err.h>
307c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
317c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
337c478bd9Sstevel@tonic-gate #include <sys/socket.h>
347c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
357c478bd9Sstevel@tonic-gate #include <sys/list.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <netinet/in.h>
387c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
397c478bd9Sstevel@tonic-gate #include <netinet/sctp.h>
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <inet/common.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip.h>
437c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
44*bd670b35SErik Nordmark #include <inet/ip_ire.h>
457c478bd9Sstevel@tonic-gate #include <inet/ip_if.h>
467c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
477c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
487c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
497c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static void		sctp_ipif_inactive(sctp_ipif_t *);
527c478bd9Sstevel@tonic-gate static sctp_ipif_t	*sctp_lookup_ipif_addr(in6_addr_t *, boolean_t,
53e35d2278Svi 			    zoneid_t, boolean_t, uint_t, uint_t, boolean_t,
54e35d2278Svi 			    sctp_stack_t *);
557c478bd9Sstevel@tonic-gate static int		sctp_get_all_ipifs(sctp_t *, int);
56f551bb10Svi static int		sctp_ipif_hash_insert(sctp_t *, sctp_ipif_t *, int,
57e35d2278Svi 			    boolean_t, boolean_t);
587c478bd9Sstevel@tonic-gate static void		sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *);
59c31292eeSkcpoon static void		sctp_fix_saddr(sctp_t *, in6_addr_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;
238a22dfb13SVenugopal Iyer 	sctp_stack_t		*sctps = sctp->sctp_sctps;
239a22dfb13SVenugopal Iyer 	boolean_t		isv6;
240*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
2417c478bd9Sstevel@tonic-gate 
242f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
2437c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
244f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[i].ipif_count == 0)
2457c478bd9Sstevel@tonic-gate 			continue;
246f4b3ec61Sdh 		sctp_ipif = list_head(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
247f4b3ec61Sdh 		for (j = 0; j < sctps->sctps_g_ipifs[i].ipif_count; j++) {
2487c478bd9Sstevel@tonic-gate 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
249a22dfb13SVenugopal Iyer 			isv6 = sctp_ipif->sctp_ipif_isv6;
250f551bb10Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
2517c478bd9Sstevel@tonic-gate 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
2525d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
253a22dfb13SVenugopal Iyer 			    SCTP_IS_ADDR_UNSPEC(!isv6,
254a22dfb13SVenugopal Iyer 			    sctp_ipif->sctp_ipif_saddr) ||
255*bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET && isv6) ||
256*bd670b35SErik Nordmark 			    (connp->conn_ipv6_v6only && !isv6)) {
2577c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2587c478bd9Sstevel@tonic-gate 				sctp_ipif = list_next(
259f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
260f4b3ec61Sdh 				    sctp_ipif);
2617c478bd9Sstevel@tonic-gate 				continue;
2627c478bd9Sstevel@tonic-gate 			}
2637c478bd9Sstevel@tonic-gate 			rw_exit(&sctp_ipif->sctp_ipif_lock);
2647c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFHOLD(sctp_ipif);
265f551bb10Svi 			error = sctp_ipif_hash_insert(sctp, sctp_ipif, sleep,
266e35d2278Svi 			    B_FALSE, B_FALSE);
267e35d2278Svi 			if (error != 0 && error != EALREADY)
2687c478bd9Sstevel@tonic-gate 				goto free_stuff;
269f4b3ec61Sdh 			sctp_ipif = list_next(
270f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2717c478bd9Sstevel@tonic-gate 			    sctp_ipif);
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 	}
274f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2757c478bd9Sstevel@tonic-gate 	return (0);
2767c478bd9Sstevel@tonic-gate free_stuff:
277f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2787c478bd9Sstevel@tonic-gate 	sctp_free_saddrs(sctp);
2797c478bd9Sstevel@tonic-gate 	return (ENOMEM);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * Given a list of address, fills in the list of SCTP ipifs if all the addresses
2847c478bd9Sstevel@tonic-gate  * are present in the SCTP interface list, return number of addresses filled
2851d8c4025Svi  * or error. If the caller wants the list of addresses, it sends a pre-allocated
2861d8c4025Svi  * buffer - list. Currently, this list is only used on a clustered node when
2871d8c4025Svi  * the SCTP is in the listen state (from sctp_bind_add()). When called on a
2881d8c4025Svi  * clustered node, the input is always a list of addresses (even if the
2891d8c4025Svi  * original bind() was to INADDR_ANY).
2907c478bd9Sstevel@tonic-gate  * Called with no locks held.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate int
2931d8c4025Svi sctp_valid_addr_list(sctp_t *sctp, const void *addrs, uint32_t addrcnt,
2941d8c4025Svi     uchar_t *list, size_t lsize)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
2977c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
2987c478bd9Sstevel@tonic-gate 	struct in_addr		*addr4;
2997c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
3007c478bd9Sstevel@tonic-gate 	int			cnt;
3017c478bd9Sstevel@tonic-gate 	int			err = 0;
3027c478bd9Sstevel@tonic-gate 	int			saddr_cnt = 0;
3037c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*ipif;
3047c478bd9Sstevel@tonic-gate 	boolean_t		bind_to_all = B_FALSE;
3057c478bd9Sstevel@tonic-gate 	boolean_t		check_addrs = B_FALSE;
3067c478bd9Sstevel@tonic-gate 	boolean_t		check_lport = B_FALSE;
3071d8c4025Svi 	uchar_t			*p = list;
308*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Need to check for port and address depending on the state.
3127c478bd9Sstevel@tonic-gate 	 * After a socket is bound, we need to make sure that subsequent
3137c478bd9Sstevel@tonic-gate 	 * bindx() has correct port.  After an association is established,
3147c478bd9Sstevel@tonic-gate 	 * we need to check for changing the bound address to invalid
3157c478bd9Sstevel@tonic-gate 	 * addresses.
3167c478bd9Sstevel@tonic-gate 	 */
3177c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state >= SCTPS_BOUND) {
3187c478bd9Sstevel@tonic-gate 		check_lport = B_TRUE;
3197c478bd9Sstevel@tonic-gate 		if (sctp->sctp_state > SCTPS_LISTEN)
3207c478bd9Sstevel@tonic-gate 			check_addrs = B_TRUE;
3217c478bd9Sstevel@tonic-gate 	}
3221d8c4025Svi 
3237c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
3247c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
3257c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
3267c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
3277c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addrcnt; cnt++) {
3287c478bd9Sstevel@tonic-gate 		boolean_t	lookup_saddr = B_TRUE;
3291d8c4025Svi 		uint_t		ifindex = 0;
3307c478bd9Sstevel@tonic-gate 
331*bd670b35SErik Nordmark 		switch (connp->conn_family) {
3327c478bd9Sstevel@tonic-gate 		case AF_INET:
3337c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
3347c478bd9Sstevel@tonic-gate 			if (sin4->sin_family != AF_INET || (check_lport &&
335*bd670b35SErik Nordmark 			    sin4->sin_port != connp->conn_lport)) {
3367c478bd9Sstevel@tonic-gate 				err = EINVAL;
3377c478bd9Sstevel@tonic-gate 				goto free_ret;
3387c478bd9Sstevel@tonic-gate 			}
3397c478bd9Sstevel@tonic-gate 			addr4 = &sin4->sin_addr;
3407c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3417c478bd9Sstevel@tonic-gate 			    (addr4->s_addr == INADDR_ANY ||
3427c478bd9Sstevel@tonic-gate 			    addr4->s_addr == INADDR_BROADCAST ||
343c4f4b3c8Skcpoon 			    CLASSD(addr4->s_addr))) {
3447c478bd9Sstevel@tonic-gate 				err = EINVAL;
3457c478bd9Sstevel@tonic-gate 				goto free_ret;
3467c478bd9Sstevel@tonic-gate 			}
3477c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(addr4, &addr);
3487c478bd9Sstevel@tonic-gate 			if (!check_addrs && addr4->s_addr == INADDR_ANY) {
3497c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3507c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3517c478bd9Sstevel@tonic-gate 			}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 			break;
3547c478bd9Sstevel@tonic-gate 		case AF_INET6:
3557c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
3567c478bd9Sstevel@tonic-gate 			if (sin6->sin6_family != AF_INET6 || (check_lport &&
357*bd670b35SErik Nordmark 			    sin6->sin6_port != connp->conn_lport)) {
3587c478bd9Sstevel@tonic-gate 				err = EINVAL;
3597c478bd9Sstevel@tonic-gate 				goto free_ret;
3607c478bd9Sstevel@tonic-gate 			}
3617c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
3621d8c4025Svi 			/* Contains the interface index */
3631d8c4025Svi 			ifindex = sin6->sin6_scope_id;
364*bd670b35SErik Nordmark 			if (connp->conn_ipv6_v6only &&
3657c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&addr)) {
3667c478bd9Sstevel@tonic-gate 				err = EAFNOSUPPORT;
3677c478bd9Sstevel@tonic-gate 				goto free_ret;
3687c478bd9Sstevel@tonic-gate 			}
3697c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3707c478bd9Sstevel@tonic-gate 			    (IN6_IS_ADDR_LINKLOCAL(&addr) ||
3717c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&addr) ||
3727c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_UNSPECIFIED(&addr))) {
3737c478bd9Sstevel@tonic-gate 				err = EINVAL;
3747c478bd9Sstevel@tonic-gate 				goto free_ret;
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate 			if (!check_addrs && IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3777c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3787c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3797c478bd9Sstevel@tonic-gate 			}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 			break;
3827c478bd9Sstevel@tonic-gate 		default:
3837c478bd9Sstevel@tonic-gate 			err = EAFNOSUPPORT;
3847c478bd9Sstevel@tonic-gate 			goto free_ret;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		if (lookup_saddr) {
387e35d2278Svi 			ipif = sctp_lookup_ipif_addr(&addr, B_TRUE,
388*bd670b35SErik Nordmark 			    IPCL_ZONEID(connp), !connp->conn_allzones,
389e35d2278Svi 			    ifindex, 0, B_TRUE, sctp->sctp_sctps);
3907c478bd9Sstevel@tonic-gate 			if (ipif == NULL) {
3917c478bd9Sstevel@tonic-gate 				/* Address not in the list */
3927c478bd9Sstevel@tonic-gate 				err = EINVAL;
3937c478bd9Sstevel@tonic-gate 				goto free_ret;
3941d8c4025Svi 			} else if (check_addrs && SCTP_IS_IPIF_LOOPBACK(ipif) &&
3951d8c4025Svi 			    cl_sctp_check_addrs == NULL) {
3967c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
3977c478bd9Sstevel@tonic-gate 				err = EINVAL;
3987c478bd9Sstevel@tonic-gate 				goto free_ret;
3997c478bd9Sstevel@tonic-gate 			}
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 		if (!bind_to_all) {
402f551bb10Svi 			/*
403f551bb10Svi 			 * If an address is added after association setup,
404f551bb10Svi 			 * we need to wait for the peer to send us an ASCONF
405f551bb10Svi 			 * ACK before we can start using it.
406f551bb10Svi 			 * saddr_ipif_dontsrc will be reset (to 0) when we
407f551bb10Svi 			 * get the ASCONF ACK for this address.
408f551bb10Svi 			 */
409f551bb10Svi 			err = sctp_ipif_hash_insert(sctp, ipif, KM_SLEEP,
410e35d2278Svi 			    check_addrs ? B_TRUE : B_FALSE, B_FALSE);
4117c478bd9Sstevel@tonic-gate 			if (err != 0) {
4127c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
4137c478bd9Sstevel@tonic-gate 				if (check_addrs && err == EALREADY)
4147c478bd9Sstevel@tonic-gate 					err = EADDRINUSE;
4157c478bd9Sstevel@tonic-gate 				goto free_ret;
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 			saddr_cnt++;
4181d8c4025Svi 			if (lsize >= sizeof (addr)) {
4191d8c4025Svi 				bcopy(&addr, p, sizeof (addr));
4201d8c4025Svi 				p += sizeof (addr);
4211d8c4025Svi 				lsize -= sizeof (addr);
4221d8c4025Svi 			}
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	if (bind_to_all) {
4267c478bd9Sstevel@tonic-gate 		/*
4277c478bd9Sstevel@tonic-gate 		 * Free whatever we might have added before encountering
4287c478bd9Sstevel@tonic-gate 		 * inaddr_any.
4297c478bd9Sstevel@tonic-gate 		 */
4307c478bd9Sstevel@tonic-gate 		if (sctp->sctp_nsaddrs > 0) {
4317c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp);
4327c478bd9Sstevel@tonic-gate 			ASSERT(sctp->sctp_nsaddrs == 0);
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 		err = sctp_get_all_ipifs(sctp, KM_SLEEP);
4357c478bd9Sstevel@tonic-gate 		if (err != 0)
4367c478bd9Sstevel@tonic-gate 			return (err);
4377c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4407c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4417c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4427c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4437c478bd9Sstevel@tonic-gate 	return (0);
4447c478bd9Sstevel@tonic-gate free_ret:
4457c478bd9Sstevel@tonic-gate 	if (saddr_cnt != 0)
4467c478bd9Sstevel@tonic-gate 		sctp_del_saddr_list(sctp, addrs, saddr_cnt, B_TRUE);
4477c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4487c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4497c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4507c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4517c478bd9Sstevel@tonic-gate 	return (err);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate static int
455f551bb10Svi sctp_ipif_hash_insert(sctp_t *sctp, sctp_ipif_t *ipif, int sleep,
456e35d2278Svi     boolean_t dontsrc, boolean_t allow_dup)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	int			cnt;
4597c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
460e35d2278Svi 	int			hindex;
461e35d2278Svi 
462e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
463e35d2278Svi 	    ipif->sctp_ipif_isv6);
464e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
465e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
466e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
467e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
468e35d2278Svi 			if (ipif->sctp_ipif_id !=
469e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id &&
470e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_state ==
471e35d2278Svi 			    SCTP_IPIFS_DOWN && ipif->sctp_ipif_state ==
472e35d2278Svi 			    SCTP_IPIFS_UP) {
473e35d2278Svi 				SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
474e35d2278Svi 				ipif_obj->saddr_ipifp = ipif;
475e35d2278Svi 				ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
476e35d2278Svi 				return (0);
477e35d2278Svi 			} else if (!allow_dup || ipif->sctp_ipif_id ==
478e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id) {
479e35d2278Svi 				return (EALREADY);
480e35d2278Svi 			}
481e35d2278Svi 		}
482e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
4837c478bd9Sstevel@tonic-gate 		    ipif_obj);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate 	ipif_obj = kmem_zalloc(sizeof (sctp_saddr_ipif_t), sleep);
4867c478bd9Sstevel@tonic-gate 	if (ipif_obj == NULL) {
4877c478bd9Sstevel@tonic-gate 		/* Need to do something */
4887c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	ipif_obj->saddr_ipifp = ipif;
491f551bb10Svi 	ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
492e35d2278Svi 	list_insert_tail(&sctp->sctp_saddrs[hindex].sctp_ipif_list, ipif_obj);
493e35d2278Svi 	sctp->sctp_saddrs[hindex].ipif_count++;
4947c478bd9Sstevel@tonic-gate 	sctp->sctp_nsaddrs++;
4957c478bd9Sstevel@tonic-gate 	return (0);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate 
498c31292eeSkcpoon /*
499c31292eeSkcpoon  * Given a source address, walk through the peer address list to see
500c31292eeSkcpoon  * if the source address is being used.  If it is, reset that.
501*bd670b35SErik Nordmark  * A cleared saddr will then make sctp_make_mp lookup the destination again
502*bd670b35SErik Nordmark  * and as part of that look for a new source.
503c31292eeSkcpoon  */
504c31292eeSkcpoon static void
505c31292eeSkcpoon sctp_fix_saddr(sctp_t *sctp, in6_addr_t *saddr)
506c31292eeSkcpoon {
507c31292eeSkcpoon 	sctp_faddr_t	*fp;
508c31292eeSkcpoon 
509c31292eeSkcpoon 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
510c31292eeSkcpoon 		if (!IN6_ARE_ADDR_EQUAL(&fp->saddr, saddr))
511c31292eeSkcpoon 			continue;
512c31292eeSkcpoon 		V6_SET_ZERO(fp->saddr);
513c31292eeSkcpoon 	}
514c31292eeSkcpoon }
515c31292eeSkcpoon 
5167c478bd9Sstevel@tonic-gate static void
5177c478bd9Sstevel@tonic-gate sctp_ipif_hash_remove(sctp_t *sctp, sctp_ipif_t *ipif)
5187c478bd9Sstevel@tonic-gate {
5197c478bd9Sstevel@tonic-gate 	int			cnt;
5207c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
521e35d2278Svi 	int			hindex;
522e35d2278Svi 
523e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
524e35d2278Svi 	    ipif->sctp_ipif_isv6);
525e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
526e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
527e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
528e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
529e35d2278Svi 			list_remove(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5307c478bd9Sstevel@tonic-gate 			    ipif_obj);
531e35d2278Svi 			sctp->sctp_saddrs[hindex].ipif_count--;
5327c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
533c31292eeSkcpoon 			sctp_fix_saddr(sctp, &ipif->sctp_ipif_saddr);
5347c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
5357c478bd9Sstevel@tonic-gate 			kmem_free(ipif_obj, sizeof (sctp_saddr_ipif_t));
5367c478bd9Sstevel@tonic-gate 			break;
5377c478bd9Sstevel@tonic-gate 		}
538e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5397c478bd9Sstevel@tonic-gate 		    ipif_obj);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate }
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate static int
5447c478bd9Sstevel@tonic-gate sctp_compare_ipif_list(sctp_ipif_hash_t *list1, sctp_ipif_hash_t *list2)
5457c478bd9Sstevel@tonic-gate {
5467c478bd9Sstevel@tonic-gate 	int			i;
5477c478bd9Sstevel@tonic-gate 	int			j;
5487c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj1;
5497c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj2;
5507c478bd9Sstevel@tonic-gate 	int			overlap = 0;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	obj1 = list_head(&list1->sctp_ipif_list);
5537c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
5547c478bd9Sstevel@tonic-gate 		obj2 = list_head(&list2->sctp_ipif_list);
5557c478bd9Sstevel@tonic-gate 		for (j = 0; j < list2->ipif_count; j++) {
556e35d2278Svi 			if (IN6_ARE_ADDR_EQUAL(
557e35d2278Svi 			    &obj1->saddr_ipifp->sctp_ipif_saddr,
558e35d2278Svi 			    &obj2->saddr_ipifp->sctp_ipif_saddr)) {
5597c478bd9Sstevel@tonic-gate 				overlap++;
5607c478bd9Sstevel@tonic-gate 				break;
5617c478bd9Sstevel@tonic-gate 			}
5627c478bd9Sstevel@tonic-gate 			obj2 = list_next(&list2->sctp_ipif_list,
5637c478bd9Sstevel@tonic-gate 			    obj2);
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 		obj1 = list_next(&list1->sctp_ipif_list, obj1);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 	return (overlap);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate int
5717c478bd9Sstevel@tonic-gate sctp_compare_saddrs(sctp_t *sctp1, sctp_t *sctp2)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	int		i;
5747c478bd9Sstevel@tonic-gate 	int		overlap = 0;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
5777c478bd9Sstevel@tonic-gate 		overlap += sctp_compare_ipif_list(&sctp1->sctp_saddrs[i],
5787c478bd9Sstevel@tonic-gate 		    &sctp2->sctp_saddrs[i]);
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (sctp1->sctp_nsaddrs == sctp2->sctp_nsaddrs &&
5827c478bd9Sstevel@tonic-gate 	    overlap == sctp1->sctp_nsaddrs) {
5837c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_EQUAL);
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if (overlap == sctp1->sctp_nsaddrs)
5877c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_SUBSET);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	if (overlap > 0)
5907c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_OVERLAP);
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	return (SCTP_ADDR_DISJOINT);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate static int
5967c478bd9Sstevel@tonic-gate sctp_copy_ipifs(sctp_ipif_hash_t *list1, sctp_t *sctp2, int sleep)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	int			i;
5997c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6007c478bd9Sstevel@tonic-gate 	int			error = 0;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	obj = list_head(&list1->sctp_ipif_list);
6037c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
6047c478bd9Sstevel@tonic-gate 		SCTP_IPIF_REFHOLD(obj->saddr_ipifp);
605f551bb10Svi 		error = sctp_ipif_hash_insert(sctp2, obj->saddr_ipifp, sleep,
606e35d2278Svi 		    B_FALSE, B_FALSE);
607e35d2278Svi 		ASSERT(error != EALREADY);
6087c478bd9Sstevel@tonic-gate 		if (error != 0)
6097c478bd9Sstevel@tonic-gate 			return (error);
6107c478bd9Sstevel@tonic-gate 		obj = list_next(&list1->sctp_ipif_list, obj);
6117c478bd9Sstevel@tonic-gate 	}
6127c478bd9Sstevel@tonic-gate 	return (error);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate int
6167c478bd9Sstevel@tonic-gate sctp_dup_saddrs(sctp_t *sctp1, sctp_t *sctp2, int sleep)
6177c478bd9Sstevel@tonic-gate {
6187c478bd9Sstevel@tonic-gate 	int	error = 0;
6197c478bd9Sstevel@tonic-gate 	int	i;
6207c478bd9Sstevel@tonic-gate 
621f551bb10Svi 	if (sctp1 == NULL || sctp1->sctp_bound_to_all == 1)
6227c478bd9Sstevel@tonic-gate 		return (sctp_get_all_ipifs(sctp2, sleep));
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
6257c478bd9Sstevel@tonic-gate 		if (sctp1->sctp_saddrs[i].ipif_count == 0)
6267c478bd9Sstevel@tonic-gate 			continue;
6277c478bd9Sstevel@tonic-gate 		error = sctp_copy_ipifs(&sctp1->sctp_saddrs[i], sctp2, sleep);
6287c478bd9Sstevel@tonic-gate 		if (error != 0) {
6297c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp2);
6307c478bd9Sstevel@tonic-gate 			return (error);
6317c478bd9Sstevel@tonic-gate 		}
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 	return (0);
6347c478bd9Sstevel@tonic-gate }
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate void
6377c478bd9Sstevel@tonic-gate sctp_free_saddrs(sctp_t *sctp)
6387c478bd9Sstevel@tonic-gate {
6397c478bd9Sstevel@tonic-gate 	int			i;
6407c478bd9Sstevel@tonic-gate 	int			l;
6417c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
6447c478bd9Sstevel@tonic-gate 		return;
6457c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
6467c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
6477c478bd9Sstevel@tonic-gate 			continue;
6487c478bd9Sstevel@tonic-gate 		obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6497c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
6507c478bd9Sstevel@tonic-gate 			list_remove(&sctp->sctp_saddrs[i].sctp_ipif_list, obj);
6517c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(obj->saddr_ipifp);
6527c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
6537c478bd9Sstevel@tonic-gate 			kmem_free(obj, sizeof (sctp_saddr_ipif_t));
6547c478bd9Sstevel@tonic-gate 			obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 		sctp->sctp_saddrs[i].ipif_count = 0;
6577c478bd9Sstevel@tonic-gate 	}
658f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
659f551bb10Svi 		sctp->sctp_bound_to_all = 0;
6607c478bd9Sstevel@tonic-gate 	ASSERT(sctp->sctp_nsaddrs == 0);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * Add/Delete the given ILL from the SCTP ILL list. Called with no locks
6657c478bd9Sstevel@tonic-gate  * held.
6667c478bd9Sstevel@tonic-gate  */
6677c478bd9Sstevel@tonic-gate void
6687c478bd9Sstevel@tonic-gate sctp_update_ill(ill_t *ill, int op)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	int		i;
6717c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill = NULL;
6727c478bd9Sstevel@tonic-gate 	uint_t		index;
673f4b3ec61Sdh 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
674f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
6757c478bd9Sstevel@tonic-gate 
676f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
679f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
680f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
6811d19ca10Svi 		if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
6821d19ca10Svi 		    (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
6837c478bd9Sstevel@tonic-gate 			break;
6841d19ca10Svi 		}
685f4b3ec61Sdh 		sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
6867c478bd9Sstevel@tonic-gate 		    sctp_ill);
6877c478bd9Sstevel@tonic-gate 	}
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	switch (op) {
6907c478bd9Sstevel@tonic-gate 	case SCTP_ILL_INSERT:
6917c478bd9Sstevel@tonic-gate 		if (sctp_ill != NULL) {
6927c478bd9Sstevel@tonic-gate 			/* Unmark it if it is condemned */
6937c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED)
6947c478bd9Sstevel@tonic-gate 				sctp_ill->sctp_ill_state = 0;
695f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
6967c478bd9Sstevel@tonic-gate 			return;
6977c478bd9Sstevel@tonic-gate 		}
6987c478bd9Sstevel@tonic-gate 		sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
6997c478bd9Sstevel@tonic-gate 		/* Need to re-try? */
7007c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
7011d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7021d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
703f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7047c478bd9Sstevel@tonic-gate 			return;
7057c478bd9Sstevel@tonic-gate 		}
706e35d2278Svi 		sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
707e35d2278Svi 		    KM_NOSLEEP);
7087c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_name == NULL) {
7091d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7101d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
7117c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
712f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7137c478bd9Sstevel@tonic-gate 			return;
7147c478bd9Sstevel@tonic-gate 		}
7157c478bd9Sstevel@tonic-gate 		bcopy(ill->ill_name, sctp_ill->sctp_ill_name,
7167c478bd9Sstevel@tonic-gate 		    ill->ill_name_length);
7177c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_name_length = ill->ill_name_length;
7187c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
7197c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
720f4b3ec61Sdh 		sctp_ill->sctp_ill_netstack = ns;	/* No netstack_hold */
7211d19ca10Svi 		sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
722f4b3ec61Sdh 		list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
7237c478bd9Sstevel@tonic-gate 		    (void *)sctp_ill);
724f4b3ec61Sdh 		sctps->sctps_g_ills[index].ill_count++;
725f4b3ec61Sdh 		sctps->sctps_ills_count++;
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 		break;
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate 	case SCTP_ILL_REMOVE:
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
732f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7337c478bd9Sstevel@tonic-gate 			return;
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0) {
736f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[index].sctp_ill_list,
7377c478bd9Sstevel@tonic-gate 			    (void *)sctp_ill);
738f4b3ec61Sdh 			sctps->sctps_g_ills[index].ill_count--;
739f4b3ec61Sdh 			sctps->sctps_ills_count--;
7407c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
7417c478bd9Sstevel@tonic-gate 			    ill->ill_name_length);
7427c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
7437c478bd9Sstevel@tonic-gate 		} else {
7447c478bd9Sstevel@tonic-gate 			sctp_ill->sctp_ill_state = SCTP_ILLS_CONDEMNED;
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		break;
7487c478bd9Sstevel@tonic-gate 	}
749f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
7507c478bd9Sstevel@tonic-gate }
7517c478bd9Sstevel@tonic-gate 
7521d19ca10Svi /*
7531d19ca10Svi  * The ILL's index is being changed, just remove it from the old list,
7541d19ca10Svi  * change the SCTP ILL's index and re-insert using the new index.
7551d19ca10Svi  */
7561d19ca10Svi void
7571d19ca10Svi sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
7581d19ca10Svi {
7591d19ca10Svi 	sctp_ill_t	*sctp_ill = NULL;
7601d19ca10Svi 	sctp_ill_t	*nxt_sill;
7611d19ca10Svi 	uint_t		indx;
7621d19ca10Svi 	uint_t		nindx;
7631d19ca10Svi 	boolean_t	once = B_FALSE;
7641d19ca10Svi 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
7651d19ca10Svi 	sctp_stack_t	*sctps = ns->netstack_sctp;
7661d19ca10Svi 
7671d19ca10Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7681d19ca10Svi 
7691d19ca10Svi 	indx = SCTP_ILL_HASH_FN(orig_ill_index);
7701d19ca10Svi 	nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
7711d19ca10Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
7721d19ca10Svi 	while (sctp_ill != NULL) {
7731d19ca10Svi 		nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
7741d19ca10Svi 		    sctp_ill);
7751d19ca10Svi 		if (sctp_ill->sctp_ill_index == orig_ill_index) {
7761d19ca10Svi 			sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
7771d19ca10Svi 			/*
7781d19ca10Svi 			 * if the new index hashes to the same value, all's
7791d19ca10Svi 			 * done.
7801d19ca10Svi 			 */
7811d19ca10Svi 			if (nindx != indx) {
7821d19ca10Svi 				list_remove(
7831d19ca10Svi 				    &sctps->sctps_g_ills[indx].sctp_ill_list,
7841d19ca10Svi 				    (void *)sctp_ill);
7851d19ca10Svi 				sctps->sctps_g_ills[indx].ill_count--;
7861d19ca10Svi 				list_insert_tail(
7871d19ca10Svi 				    &sctps->sctps_g_ills[nindx].sctp_ill_list,
7881d19ca10Svi 				    (void *)sctp_ill);
7891d19ca10Svi 				sctps->sctps_g_ills[nindx].ill_count++;
7901d19ca10Svi 			}
7911d19ca10Svi 			if (once)
7921d19ca10Svi 				break;
7931d19ca10Svi 			/* We might have one for v4 and for v6 */
7941d19ca10Svi 			once = B_TRUE;
7951d19ca10Svi 		}
7961d19ca10Svi 		sctp_ill = nxt_sill;
7971d19ca10Svi 	}
7981d19ca10Svi 	rw_exit(&sctps->sctps_g_ills_lock);
7991d19ca10Svi }
8001d19ca10Svi 
8017c478bd9Sstevel@tonic-gate /* move ipif from f_ill to t_ill */
8027c478bd9Sstevel@tonic-gate void
8037c478bd9Sstevel@tonic-gate sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	sctp_ill_t	*fsctp_ill = NULL;
8067c478bd9Sstevel@tonic-gate 	sctp_ill_t	*tsctp_ill = NULL;
8077c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
808e35d2278Svi 	uint_t		hindex;
8097c478bd9Sstevel@tonic-gate 	int		i;
810f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
811f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
8127c478bd9Sstevel@tonic-gate 
813f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
814f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
8157c478bd9Sstevel@tonic-gate 
816e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
817e35d2278Svi 	fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
818e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8191d19ca10Svi 		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
8201d19ca10Svi 		    fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
8217c478bd9Sstevel@tonic-gate 			break;
8221d19ca10Svi 		}
823e35d2278Svi 		fsctp_ill = list_next(
824e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
827e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
828e35d2278Svi 	tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
829e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8301d19ca10Svi 		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
8311d19ca10Svi 		    tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
8327c478bd9Sstevel@tonic-gate 			break;
8331d19ca10Svi 		}
834e35d2278Svi 		tsctp_ill = list_next(
835e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
838e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
839e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
840e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
841e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
8427c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid)
8437c478bd9Sstevel@tonic-gate 			break;
844f4b3ec61Sdh 		sctp_ipif = list_next(
845e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
8467c478bd9Sstevel@tonic-gate 	}
8477c478bd9Sstevel@tonic-gate 	/* Should be an ASSERT? */
8487c478bd9Sstevel@tonic-gate 	if (fsctp_ill == NULL || tsctp_ill == NULL || sctp_ipif == NULL) {
8497c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_move_ipif: error moving ipif %p from %p to %p\n",
8507c478bd9Sstevel@tonic-gate 		    (void *)ipif, (void *)f_ill, (void *)t_ill));
851f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
852f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
8537c478bd9Sstevel@tonic-gate 		return;
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 	rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
8567c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ipif->sctp_ipif_ill == fsctp_ill);
8577c478bd9Sstevel@tonic-gate 	sctp_ipif->sctp_ipif_ill = tsctp_ill;
8587c478bd9Sstevel@tonic-gate 	rw_exit(&sctp_ipif->sctp_ipif_lock);
8597c478bd9Sstevel@tonic-gate 	(void) atomic_add_32_nv(&fsctp_ill->sctp_ill_ipifcnt, -1);
8607c478bd9Sstevel@tonic-gate 	atomic_add_32(&tsctp_ill->sctp_ill_ipifcnt, 1);
861f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
862f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
865e35d2278Svi /*
866e35d2278Svi  * Walk the list of SCTPs and find each that has oipif in it's saddr list, and
867e35d2278Svi  * if so replace it with nipif.
868e35d2278Svi  */
869e35d2278Svi void
870e35d2278Svi sctp_update_saddrs(sctp_ipif_t *oipif, sctp_ipif_t *nipif, int idx,
871e35d2278Svi     sctp_stack_t *sctps)
872e35d2278Svi {
873e35d2278Svi 	sctp_t			*sctp;
874e35d2278Svi 	sctp_t			*sctp_prev = NULL;
875e35d2278Svi 	sctp_saddr_ipif_t	*sobj;
876e35d2278Svi 	int			count;
877e35d2278Svi 
878e35d2278Svi 	mutex_enter(&sctps->sctps_g_lock);
879*bd670b35SErik Nordmark 	sctp = list_head(&sctps->sctps_g_list);
880e35d2278Svi 	while (sctp != NULL && oipif->sctp_ipif_refcnt > 0) {
881e35d2278Svi 		mutex_enter(&sctp->sctp_reflock);
882e35d2278Svi 		if (sctp->sctp_condemned ||
883e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count <= 0) {
884e35d2278Svi 			mutex_exit(&sctp->sctp_reflock);
885e35d2278Svi 			sctp = list_next(&sctps->sctps_g_list, sctp);
886e35d2278Svi 			continue;
887e35d2278Svi 		}
888e35d2278Svi 		sctp->sctp_refcnt++;
889e35d2278Svi 		mutex_exit(&sctp->sctp_reflock);
890e35d2278Svi 		mutex_exit(&sctps->sctps_g_lock);
891e35d2278Svi 		if (sctp_prev != NULL)
892e35d2278Svi 			SCTP_REFRELE(sctp_prev);
893e35d2278Svi 
894e35d2278Svi 		RUN_SCTP(sctp);
895e35d2278Svi 		sobj = list_head(&sctp->sctp_saddrs[idx].sctp_ipif_list);
896e35d2278Svi 		for (count = 0; count <
897e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count; count++) {
898e35d2278Svi 			if (sobj->saddr_ipifp == oipif) {
899e35d2278Svi 				SCTP_IPIF_REFHOLD(nipif);
900e35d2278Svi 				sobj->saddr_ipifp = nipif;
901e35d2278Svi 				ASSERT(oipif->sctp_ipif_refcnt > 0);
902e35d2278Svi 				/* We have the writer lock */
903e35d2278Svi 				oipif->sctp_ipif_refcnt--;
904e35d2278Svi 				/*
905e35d2278Svi 				 * Can't have more than one referring
906e35d2278Svi 				 * to the same sctp_ipif.
907e35d2278Svi 				 */
908e35d2278Svi 				break;
909e35d2278Svi 			}
910e35d2278Svi 			sobj = list_next(&sctp->sctp_saddrs[idx].sctp_ipif_list,
911e35d2278Svi 			    sobj);
912e35d2278Svi 		}
913e35d2278Svi 		WAKE_SCTP(sctp);
914e35d2278Svi 		sctp_prev = sctp;
915e35d2278Svi 		mutex_enter(&sctps->sctps_g_lock);
916e35d2278Svi 		sctp = list_next(&sctps->sctps_g_list, sctp);
917e35d2278Svi 	}
918e35d2278Svi 	mutex_exit(&sctps->sctps_g_lock);
919e35d2278Svi 	if (sctp_prev != NULL)
920e35d2278Svi 		SCTP_REFRELE(sctp_prev);
921e35d2278Svi }
922e35d2278Svi 
923e35d2278Svi /*
924e35d2278Svi  * Given an ipif, walk the hash list in the global ipif table and for
925e35d2278Svi  * any other SCTP ipif with the same address and non-zero reference, walk
926e35d2278Svi  * the SCTP list and update the saddr list, if required, to point to the
927d0e58000SVenugopal Iyer  * new SCTP ipif. If it is a loopback interface, then there could be
928d0e58000SVenugopal Iyer  * multiple interfaces with 127.0.0.1 if there are zones configured, so
929d0e58000SVenugopal Iyer  * check the zoneid in addition to the address.
930e35d2278Svi  */
931e35d2278Svi void
932e35d2278Svi sctp_chk_and_updt_saddr(int hindex, sctp_ipif_t *ipif, sctp_stack_t *sctps)
933e35d2278Svi {
934e35d2278Svi 	int		cnt;
935e35d2278Svi 	sctp_ipif_t	*sipif;
936e35d2278Svi 
937e35d2278Svi 	ASSERT(sctps->sctps_g_ipifs[hindex].ipif_count > 0);
938e35d2278Svi 	ASSERT(ipif->sctp_ipif_state == SCTP_IPIFS_UP);
939e35d2278Svi 
940e35d2278Svi 	sipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
941e35d2278Svi 	for (cnt = 0; cnt < sctps->sctps_g_ipifs[hindex].ipif_count; cnt++) {
942e35d2278Svi 		rw_enter(&sipif->sctp_ipif_lock, RW_WRITER);
943e35d2278Svi 		if (sipif->sctp_ipif_id != ipif->sctp_ipif_id &&
944e35d2278Svi 		    IN6_ARE_ADDR_EQUAL(&sipif->sctp_ipif_saddr,
945d0e58000SVenugopal Iyer 		    &ipif->sctp_ipif_saddr) && sipif->sctp_ipif_refcnt > 0 &&
946d0e58000SVenugopal Iyer 		    (!SCTP_IS_IPIF_LOOPBACK(ipif) || ipif->sctp_ipif_zoneid ==
947d0e58000SVenugopal Iyer 		    sipif->sctp_ipif_zoneid)) {
948e35d2278Svi 			/*
949e35d2278Svi 			 * There can only be one address up at any time
950e35d2278Svi 			 * and we are here because ipif has been brought
951e35d2278Svi 			 * up.
952e35d2278Svi 			 */
953e35d2278Svi 			ASSERT(sipif->sctp_ipif_state != SCTP_IPIFS_UP);
954e35d2278Svi 			/*
955e35d2278Svi 			 * Someone has a reference to this we need to update to
956e35d2278Svi 			 * point to the new sipif.
957e35d2278Svi 			 */
958e35d2278Svi 			sctp_update_saddrs(sipif, ipif, hindex, sctps);
959e35d2278Svi 		}
960e35d2278Svi 		rw_exit(&sipif->sctp_ipif_lock);
961e35d2278Svi 		sipif = list_next(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
962e35d2278Svi 		    sipif);
963e35d2278Svi 	}
964e35d2278Svi }
965e35d2278Svi 
966e35d2278Svi /*
967e35d2278Svi  * Insert a new SCTP ipif using 'ipif'. v6addr is the address that existed
968e35d2278Svi  * prior to the current address in 'ipif'. Only when an existing address
969e35d2278Svi  * is changed on an IPIF, will v6addr be specified. If the IPIF already
970e35d2278Svi  * exists in the global SCTP ipif table, then we either removed it, if
971e35d2278Svi  * it doesn't have any existing reference, or mark it condemned otherwise.
972e35d2278Svi  * If an address is being brought up (IPIF_UP), then we need to scan
973e35d2278Svi  * the SCTP list to check if there is any SCTP that points to the *same*
974e35d2278Svi  * address on a different SCTP ipif and update in that case.
975e35d2278Svi  */
976e35d2278Svi void
977e35d2278Svi sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
978e35d2278Svi {
979e35d2278Svi 	ill_t		*ill = ipif->ipif_ill;
980e35d2278Svi 	int		i;
981e35d2278Svi 	sctp_ill_t	*sctp_ill;
982e35d2278Svi 	sctp_ill_t	*osctp_ill;
983e35d2278Svi 	sctp_ipif_t	*sctp_ipif = NULL;
984e35d2278Svi 	sctp_ipif_t	*osctp_ipif = NULL;
985e35d2278Svi 	uint_t		ill_index;
986e35d2278Svi 	int		hindex;
987e35d2278Svi 	sctp_stack_t	*sctps;
988e35d2278Svi 
989e35d2278Svi 	sctps = ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp;
990e35d2278Svi 
991e35d2278Svi 	/* Index for new address */
992e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr, ill->ill_isv6);
993e35d2278Svi 
994e35d2278Svi 	/*
995e35d2278Svi 	 * The address on this IPIF is changing, we need to look for
996e35d2278Svi 	 * this old address and mark it condemned, before creating
997e35d2278Svi 	 * one for the new address.
998e35d2278Svi 	 */
999e35d2278Svi 	osctp_ipif = sctp_lookup_ipif_addr(&v6addr, B_FALSE,
1000e35d2278Svi 	    ipif->ipif_zoneid, B_TRUE, SCTP_ILL_TO_PHYINDEX(ill),
1001e35d2278Svi 	    ipif->ipif_seqid, B_FALSE, sctps);
1002e35d2278Svi 
1003e35d2278Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1004e35d2278Svi 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1005e35d2278Svi 
1006e35d2278Svi 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1007e35d2278Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1008e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
10091d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
10101d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
1011e35d2278Svi 			break;
10121d19ca10Svi 		}
1013e35d2278Svi 		sctp_ill = list_next(
1014e35d2278Svi 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
1015e35d2278Svi 	}
1016e35d2278Svi 
1017e35d2278Svi 	if (sctp_ill == NULL) {
10181d19ca10Svi 		ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
1019e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1020e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
10211d19ca10Svi 		return;
1022e35d2278Svi 	}
1023e35d2278Svi 
1024e35d2278Svi 	if (osctp_ipif != NULL) {
1025e35d2278Svi 
1026e35d2278Svi 		/* The address is the same? */
1027e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &v6addr)) {
1028e35d2278Svi 			boolean_t	chk_n_updt = B_FALSE;
1029e35d2278Svi 
1030e35d2278Svi 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
1031e35d2278Svi 			rw_enter(&osctp_ipif->sctp_ipif_lock, RW_WRITER);
1032e35d2278Svi 			if (ipif->ipif_flags & IPIF_UP &&
1033e35d2278Svi 			    osctp_ipif->sctp_ipif_state != SCTP_IPIFS_UP) {
1034e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1035e35d2278Svi 				chk_n_updt = B_TRUE;
1036e35d2278Svi 			} else {
1037e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1038e35d2278Svi 			}
1039e35d2278Svi 			osctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1040e35d2278Svi 			rw_exit(&osctp_ipif->sctp_ipif_lock);
1041e35d2278Svi 			if (chk_n_updt) {
1042e35d2278Svi 				sctp_chk_and_updt_saddr(hindex, osctp_ipif,
1043e35d2278Svi 				    sctps);
1044e35d2278Svi 			}
1045e35d2278Svi 			rw_exit(&sctps->sctps_g_ipifs_lock);
1046e35d2278Svi 			rw_exit(&sctps->sctps_g_ills_lock);
1047e35d2278Svi 			return;
1048e35d2278Svi 		}
1049e35d2278Svi 		/*
1050e35d2278Svi 		 * We are effectively removing this address from the ILL.
1051e35d2278Svi 		 */
1052e35d2278Svi 		if (osctp_ipif->sctp_ipif_refcnt != 0) {
1053e35d2278Svi 			osctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1054e35d2278Svi 		} else {
1055e35d2278Svi 			list_t		*ipif_list;
1056e35d2278Svi 			int		ohindex;
1057e35d2278Svi 
1058e35d2278Svi 			osctp_ill = osctp_ipif->sctp_ipif_ill;
1059e35d2278Svi 			/* hash index for the old one */
1060e35d2278Svi 			ohindex = SCTP_IPIF_ADDR_HASH(
1061e35d2278Svi 			    osctp_ipif->sctp_ipif_saddr,
1062e35d2278Svi 			    osctp_ipif->sctp_ipif_isv6);
1063e35d2278Svi 
1064e35d2278Svi 			ipif_list =
1065e35d2278Svi 			    &sctps->sctps_g_ipifs[ohindex].sctp_ipif_list;
1066e35d2278Svi 
1067e35d2278Svi 			list_remove(ipif_list, (void *)osctp_ipif);
1068e35d2278Svi 			sctps->sctps_g_ipifs[ohindex].ipif_count--;
1069e35d2278Svi 			sctps->sctps_g_ipifs_count--;
1070e35d2278Svi 			rw_destroy(&osctp_ipif->sctp_ipif_lock);
1071e35d2278Svi 			kmem_free(osctp_ipif, sizeof (sctp_ipif_t));
1072e35d2278Svi 			(void) atomic_add_32_nv(&osctp_ill->sctp_ill_ipifcnt,
1073e35d2278Svi 			    -1);
1074e35d2278Svi 		}
1075e35d2278Svi 	}
1076e35d2278Svi 
1077e35d2278Svi 	sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
1078e35d2278Svi 	/* Try again? */
1079e35d2278Svi 	if (sctp_ipif == NULL) {
10801d19ca10Svi 		cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
10811d19ca10Svi 		    "IPIF %p to SCTP's IPIF list", (void *)ipif);
1082e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1083e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
1084e35d2278Svi 		return;
1085e35d2278Svi 	}
1086e35d2278Svi 	sctps->sctps_g_ipifs_count++;
1087e35d2278Svi 	rw_init(&sctp_ipif->sctp_ipif_lock, NULL, RW_DEFAULT, NULL);
1088e35d2278Svi 	sctp_ipif->sctp_ipif_saddr = ipif->ipif_v6lcl_addr;
1089e35d2278Svi 	sctp_ipif->sctp_ipif_ill = sctp_ill;
1090e35d2278Svi 	sctp_ipif->sctp_ipif_isv6 = ill->ill_isv6;
1091e35d2278Svi 	sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1092e35d2278Svi 	sctp_ipif->sctp_ipif_id = ipif->ipif_seqid;
1093e35d2278Svi 	if (ipif->ipif_flags & IPIF_UP)
1094e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1095e35d2278Svi 	else
1096e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1097e35d2278Svi 	sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1098e35d2278Svi 	/*
1099e35d2278Svi 	 * We add it to the head so that it is quicker to find good/recent
1100e35d2278Svi 	 * additions.
1101e35d2278Svi 	 */
1102e35d2278Svi 	list_insert_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
1103e35d2278Svi 	    (void *)sctp_ipif);
1104e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count++;
1105e35d2278Svi 	atomic_add_32(&sctp_ill->sctp_ill_ipifcnt, 1);
1106e35d2278Svi 	if (sctp_ipif->sctp_ipif_state == SCTP_IPIFS_UP)
1107e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif, sctps);
1108e35d2278Svi 	rw_exit(&sctps->sctps_g_ipifs_lock);
1109e35d2278Svi 	rw_exit(&sctps->sctps_g_ills_lock);
1110e35d2278Svi }
1111e35d2278Svi 
11127c478bd9Sstevel@tonic-gate /* Insert, Remove,  Mark up or Mark down the ipif */
11137c478bd9Sstevel@tonic-gate void
11147c478bd9Sstevel@tonic-gate sctp_update_ipif(ipif_t *ipif, int op)
11157c478bd9Sstevel@tonic-gate {
11167c478bd9Sstevel@tonic-gate 	ill_t		*ill = ipif->ipif_ill;
11177c478bd9Sstevel@tonic-gate 	int		i;
11187c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
11197c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
11207c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
1121e35d2278Svi 	uint_t		hindex;
1122f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
1123f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	ip2dbg(("sctp_update_ipif: %s %d\n", ill->ill_name, ipif->ipif_seqid));
11267c478bd9Sstevel@tonic-gate 
1127f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1128f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1131f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1132f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
11331d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
11341d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
11357c478bd9Sstevel@tonic-gate 			break;
11361d19ca10Svi 		}
1137f4b3ec61Sdh 		sctp_ill = list_next(
1138f4b3ec61Sdh 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate 	if (sctp_ill == NULL) {
1141f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1142f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11437c478bd9Sstevel@tonic-gate 		return;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
1146e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
1147e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
1148e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
1149e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
1150e35d2278Svi 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid) {
1151e35d2278Svi 			ASSERT(IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
1152e35d2278Svi 			    &ipif->ipif_v6lcl_addr));
11537c478bd9Sstevel@tonic-gate 			break;
1154e35d2278Svi 		}
1155f4b3ec61Sdh 		sctp_ipif = list_next(
1156e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11577c478bd9Sstevel@tonic-gate 		    sctp_ipif);
11587c478bd9Sstevel@tonic-gate 	}
1159e35d2278Svi 	if (sctp_ipif == NULL) {
11607c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_update_ipif: null sctp_ipif for %d\n", op));
1161f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1162f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11637c478bd9Sstevel@tonic-gate 		return;
11647c478bd9Sstevel@tonic-gate 	}
1165e35d2278Svi 	ASSERT(sctp_ill == sctp_ipif->sctp_ipif_ill);
11667c478bd9Sstevel@tonic-gate 	switch (op) {
11677c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_REMOVE:
11687c478bd9Sstevel@tonic-gate 	{
11697c478bd9Sstevel@tonic-gate 		list_t		*ipif_list;
11707c478bd9Sstevel@tonic-gate 		list_t		*ill_list;
11717c478bd9Sstevel@tonic-gate 
1172f4b3ec61Sdh 		ill_list = &sctps->sctps_g_ills[ill_index].sctp_ill_list;
1173e35d2278Svi 		ipif_list = &sctps->sctps_g_ipifs[hindex].sctp_ipif_list;
11747c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_refcnt != 0) {
11757c478bd9Sstevel@tonic-gate 			sctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1176f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ipifs_lock);
1177f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
11787c478bd9Sstevel@tonic-gate 			return;
11797c478bd9Sstevel@tonic-gate 		}
11807c478bd9Sstevel@tonic-gate 		list_remove(ipif_list, (void *)sctp_ipif);
1181e35d2278Svi 		sctps->sctps_g_ipifs[hindex].ipif_count--;
1182f4b3ec61Sdh 		sctps->sctps_g_ipifs_count--;
11837c478bd9Sstevel@tonic-gate 		rw_destroy(&sctp_ipif->sctp_ipif_lock);
11847c478bd9Sstevel@tonic-gate 		kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
11857c478bd9Sstevel@tonic-gate 		(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
1186f4b3ec61Sdh 		if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
1187f4b3ec61Sdh 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
11887c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_ipifcnt == 0 &&
11897c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
11907c478bd9Sstevel@tonic-gate 				list_remove(ill_list, (void *)sctp_ill);
1191f4b3ec61Sdh 				sctps->sctps_ills_count--;
1192f4b3ec61Sdh 				sctps->sctps_g_ills[ill_index].ill_count--;
11937c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill->sctp_ill_name,
11947c478bd9Sstevel@tonic-gate 				    sctp_ill->sctp_ill_name_length);
11957c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill, sizeof (sctp_ill_t));
11967c478bd9Sstevel@tonic-gate 			}
11977c478bd9Sstevel@tonic-gate 		}
11987c478bd9Sstevel@tonic-gate 		break;
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UP:
12027c478bd9Sstevel@tonic-gate 
1203f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12047c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12057c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1206e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12077c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
1208e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif,
1209e35d2278Svi 		    ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp);
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 		break;
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UPDATE:
12147c478bd9Sstevel@tonic-gate 
1215f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12167c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12177c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1218f551bb10Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12197c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 		break;
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_DOWN:
12247c478bd9Sstevel@tonic-gate 
1225f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12267c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12277c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1228e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12297c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 		break;
12327c478bd9Sstevel@tonic-gate 	}
1233f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
1234f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
12357c478bd9Sstevel@tonic-gate }
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate /*
12387c478bd9Sstevel@tonic-gate  * SCTP source address list manipulaton, locking not used (except for
12397c478bd9Sstevel@tonic-gate  * sctp locking by the caller.
12407c478bd9Sstevel@tonic-gate  */
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate /* Remove a specific saddr from the list */
12437c478bd9Sstevel@tonic-gate void
12447c478bd9Sstevel@tonic-gate sctp_del_saddr(sctp_t *sctp, sctp_saddr_ipif_t *sp)
12457c478bd9Sstevel@tonic-gate {
12467c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12477c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12507c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	sctp_ipif_hash_remove(sctp, sp->saddr_ipifp);
12537c478bd9Sstevel@tonic-gate 
1254f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
12557c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12587c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12617c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate  * Delete source address from the existing list. No error checking done here
12667c478bd9Sstevel@tonic-gate  * Called with no locks held.
12677c478bd9Sstevel@tonic-gate  */
12687c478bd9Sstevel@tonic-gate void
12697c478bd9Sstevel@tonic-gate sctp_del_saddr_list(sctp_t *sctp, const void *addrs, int addcnt,
12707c478bd9Sstevel@tonic-gate     boolean_t fanout_locked)
12717c478bd9Sstevel@tonic-gate {
12727c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
12737c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
12747c478bd9Sstevel@tonic-gate 	int			cnt;
12757c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
12767c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
12771d8c4025Svi 	int			ifindex = 0;
1278*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
12797c478bd9Sstevel@tonic-gate 
12801d8c4025Svi 	ASSERT(sctp->sctp_nsaddrs >= addcnt);
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
12837c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
12847c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12857c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
12867c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12877c478bd9Sstevel@tonic-gate 	}
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addcnt; cnt++) {
1290*bd670b35SErik Nordmark 		switch (connp->conn_family) {
12917c478bd9Sstevel@tonic-gate 		case AF_INET:
12927c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
12937c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &addr);
12947c478bd9Sstevel@tonic-gate 			break;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate 		case AF_INET6:
12977c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
12987c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
12991d8c4025Svi 			ifindex = sin6->sin6_scope_id;
13007c478bd9Sstevel@tonic-gate 			break;
13017c478bd9Sstevel@tonic-gate 		}
1302e35d2278Svi 		sctp_ipif = sctp_lookup_ipif_addr(&addr, B_FALSE,
1303*bd670b35SErik Nordmark 		    IPCL_ZONEID(connp), !connp->conn_allzones,
1304e35d2278Svi 		    ifindex, 0, B_TRUE, sctp->sctp_sctps);
13057c478bd9Sstevel@tonic-gate 		ASSERT(sctp_ipif != NULL);
13067c478bd9Sstevel@tonic-gate 		sctp_ipif_hash_remove(sctp, sctp_ipif);
13077c478bd9Sstevel@tonic-gate 	}
1308f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
13097c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
13127c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
13137c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
13147c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
13157c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate /*
13207c478bd9Sstevel@tonic-gate  * Given an address get the corresponding entry from the list
13217c478bd9Sstevel@tonic-gate  * Called with no locks held.
13227c478bd9Sstevel@tonic-gate  */
13237c478bd9Sstevel@tonic-gate sctp_saddr_ipif_t *
13241d8c4025Svi sctp_saddr_lookup(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
13257c478bd9Sstevel@tonic-gate {
1326e35d2278Svi 	int			cnt;
1327e35d2278Svi 	sctp_saddr_ipif_t	*ipif_obj;
1328e35d2278Svi 	int			hindex;
13297c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13307c478bd9Sstevel@tonic-gate 
1331e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1332e35d2278Svi 	if (sctp->sctp_saddrs[hindex].ipif_count == 0)
13337c478bd9Sstevel@tonic-gate 		return (NULL);
13347c478bd9Sstevel@tonic-gate 
1335e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
1336e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
1337e35d2278Svi 		sctp_ipif = ipif_obj->saddr_ipifp;
1338e35d2278Svi 		/*
1339e35d2278Svi 		 * Zone check shouldn't be needed.
1340e35d2278Svi 		 */
1341e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(addr, &sctp_ipif->sctp_ipif_saddr) &&
1342e35d2278Svi 		    (ifindex == 0 ||
1343e35d2278Svi 		    ifindex == sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
1344e35d2278Svi 		    SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state)) {
1345e35d2278Svi 			return (ipif_obj);
1346e35d2278Svi 		}
1347e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
1348e35d2278Svi 		    ipif_obj);
1349e35d2278Svi 	}
1350e35d2278Svi 	return (NULL);
13517c478bd9Sstevel@tonic-gate }
13527c478bd9Sstevel@tonic-gate 
1353f551bb10Svi /* Given an address, add it to the source address list */
1354f551bb10Svi int
13551d8c4025Svi sctp_saddr_add_addr(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
1356f551bb10Svi {
1357f551bb10Svi 	sctp_ipif_t		*sctp_ipif;
1358*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1359f551bb10Svi 
1360*bd670b35SErik Nordmark 	sctp_ipif = sctp_lookup_ipif_addr(addr, B_TRUE, IPCL_ZONEID(connp),
1361*bd670b35SErik Nordmark 	    !connp->conn_allzones, ifindex, 0, B_TRUE, sctp->sctp_sctps);
1362f551bb10Svi 	if (sctp_ipif == NULL)
1363f551bb10Svi 		return (EINVAL);
1364f551bb10Svi 
1365e35d2278Svi 	if (sctp_ipif_hash_insert(sctp, sctp_ipif, KM_NOSLEEP, B_FALSE,
1366e35d2278Svi 	    B_FALSE) != 0) {
1367f551bb10Svi 		SCTP_IPIF_REFRELE(sctp_ipif);
1368f551bb10Svi 		return (EINVAL);
1369f551bb10Svi 	}
1370f551bb10Svi 	return (0);
1371f551bb10Svi }
1372f551bb10Svi 
1373f551bb10Svi /*
1374f551bb10Svi  * Remove or mark as dontsrc addresses that are currently not part of the
1375f551bb10Svi  * association. One would delete addresses when processing an INIT and
1376f551bb10Svi  * mark as dontsrc when processing an INIT-ACK.
1377f551bb10Svi  */
1378f551bb10Svi void
1379c31292eeSkcpoon sctp_check_saddr(sctp_t *sctp, int supp_af, boolean_t delete,
1380c31292eeSkcpoon     in6_addr_t *no_del_addr)
1381f551bb10Svi {
1382f551bb10Svi 	int			i;
1383f551bb10Svi 	int			l;
1384f551bb10Svi 	sctp_saddr_ipif_t	*obj;
1385f551bb10Svi 	int			scanned = 0;
1386f551bb10Svi 	int			naddr;
1387f551bb10Svi 	int			nsaddr;
1388*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1389f551bb10Svi 
1390f551bb10Svi 	ASSERT(!sctp->sctp_loopback && !sctp->sctp_linklocal && supp_af != 0);
1391f551bb10Svi 
1392f551bb10Svi 	/*
1393f551bb10Svi 	 * Irregardless of the supported address in the INIT, v4
1394f551bb10Svi 	 * must be supported.
1395f551bb10Svi 	 */
1396*bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET)
1397f551bb10Svi 		supp_af = PARM_SUPP_V4;
1398f551bb10Svi 
1399f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
1400f551bb10Svi 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1401f551bb10Svi 		if (sctp->sctp_saddrs[i].ipif_count == 0)
1402f551bb10Svi 			continue;
1403f551bb10Svi 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1404f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1405f551bb10Svi 		for (l = 0; l < naddr; l++) {
1406f551bb10Svi 			sctp_ipif_t	*ipif;
1407f551bb10Svi 
1408f551bb10Svi 			ipif = obj->saddr_ipifp;
1409f551bb10Svi 			scanned++;
1410f551bb10Svi 
1411c31292eeSkcpoon 			if (IN6_ARE_ADDR_EQUAL(&ipif->sctp_ipif_saddr,
1412c31292eeSkcpoon 			    no_del_addr)) {
1413c31292eeSkcpoon 				goto next_obj;
1414c31292eeSkcpoon 			}
1415c31292eeSkcpoon 
1416f551bb10Svi 			/*
1417f551bb10Svi 			 * Delete/mark dontsrc loopback/linklocal addresses and
1418f551bb10Svi 			 * unsupported address.
14191d8c4025Svi 			 * On a clustered node, we trust the clustering module
14201d8c4025Svi 			 * to do the right thing w.r.t loopback addresses, so
14211d8c4025Svi 			 * we ignore loopback addresses in this check.
1422f551bb10Svi 			 */
14231d8c4025Svi 			if ((SCTP_IS_IPIF_LOOPBACK(ipif) &&
14241d8c4025Svi 			    cl_sctp_check_addrs == NULL) ||
14251d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(ipif) ||
1426f551bb10Svi 			    SCTP_UNSUPP_AF(ipif, supp_af)) {
1427f551bb10Svi 				if (!delete) {
1428f551bb10Svi 					obj->saddr_ipif_unconfirmed = 1;
1429f551bb10Svi 					goto next_obj;
1430f551bb10Svi 				}
1431f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1432f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1433f551bb10Svi 				if (scanned < nsaddr) {
1434f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1435f551bb10Svi 					    sctp_ipif_list, obj);
1436f551bb10Svi 					sctp_ipif_hash_remove(sctp, ipif);
1437f551bb10Svi 					continue;
1438f551bb10Svi 				}
1439f551bb10Svi 				sctp_ipif_hash_remove(sctp, ipif);
1440f551bb10Svi 			}
1441f551bb10Svi 	next_obj:
1442f551bb10Svi 			if (scanned >= nsaddr)
1443f551bb10Svi 				return;
1444f551bb10Svi 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
1445f551bb10Svi 			    obj);
1446f551bb10Svi 		}
1447f551bb10Svi 	}
1448f551bb10Svi }
1449f551bb10Svi 
1450f551bb10Svi 
14517c478bd9Sstevel@tonic-gate /* Get the first valid address from the list. Called with no locks held */
14527c478bd9Sstevel@tonic-gate in6_addr_t
1453c31292eeSkcpoon sctp_get_valid_addr(sctp_t *sctp, boolean_t isv6, boolean_t *addr_set)
14547c478bd9Sstevel@tonic-gate {
14557c478bd9Sstevel@tonic-gate 	int			i;
14567c478bd9Sstevel@tonic-gate 	int			l;
14577c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
14587c478bd9Sstevel@tonic-gate 	int			scanned = 0;
14597c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
14627c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
14637c478bd9Sstevel@tonic-gate 			continue;
14647c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
14657c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
14667c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
1469f551bb10Svi 			if (!SCTP_DONT_SRC(obj) &&
14707c478bd9Sstevel@tonic-gate 			    ipif->sctp_ipif_isv6 == isv6 &&
1471f551bb10Svi 			    ipif->sctp_ipif_state == SCTP_IPIFS_UP) {
1472c31292eeSkcpoon 				*addr_set = B_TRUE;
14737c478bd9Sstevel@tonic-gate 				return (ipif->sctp_ipif_saddr);
14747c478bd9Sstevel@tonic-gate 			}
14757c478bd9Sstevel@tonic-gate 			scanned++;
14767c478bd9Sstevel@tonic-gate 			if (scanned >= sctp->sctp_nsaddrs)
14777c478bd9Sstevel@tonic-gate 				goto got_none;
14787c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
14797c478bd9Sstevel@tonic-gate 			    obj);
14807c478bd9Sstevel@tonic-gate 		}
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate got_none:
14837c478bd9Sstevel@tonic-gate 	/* Need to double check this */
14847c478bd9Sstevel@tonic-gate 	if (isv6 == B_TRUE)
14857c478bd9Sstevel@tonic-gate 		addr =  ipv6_all_zeros;
14867c478bd9Sstevel@tonic-gate 	else
14877c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(0, &addr);
1488c31292eeSkcpoon 	*addr_set = B_FALSE;
14897c478bd9Sstevel@tonic-gate 	return (addr);
14907c478bd9Sstevel@tonic-gate }
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate /*
14937c478bd9Sstevel@tonic-gate  * Return the list of local addresses of an association.  The parameter
14947c478bd9Sstevel@tonic-gate  * myaddrs is supposed to be either (struct sockaddr_in *) or (struct
14957c478bd9Sstevel@tonic-gate  * sockaddr_in6 *) depending on the address family.
14967c478bd9Sstevel@tonic-gate  */
14977c478bd9Sstevel@tonic-gate int
14987c478bd9Sstevel@tonic-gate sctp_getmyaddrs(void *conn, void *myaddrs, int *addrcnt)
14997c478bd9Sstevel@tonic-gate {
15007c478bd9Sstevel@tonic-gate 	int			i;
15017c478bd9Sstevel@tonic-gate 	int			l;
15027c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
15037c478bd9Sstevel@tonic-gate 	sctp_t			*sctp = (sctp_t *)conn;
1504*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1505*bd670b35SErik Nordmark 	int			family = connp->conn_family;
15067c478bd9Sstevel@tonic-gate 	int			max = *addrcnt;
15077c478bd9Sstevel@tonic-gate 	size_t			added = 0;
15087c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
15097c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
15107c478bd9Sstevel@tonic-gate 	int			scanned = 0;
15117c478bd9Sstevel@tonic-gate 	boolean_t		skip_lback = B_FALSE;
1512*bd670b35SErik Nordmark 	ip_xmit_attr_t		*ixa = connp->conn_ixa;
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
15157c478bd9Sstevel@tonic-gate 		return (EINVAL);
15167c478bd9Sstevel@tonic-gate 
15171d8c4025Svi 	/*
15181d8c4025Svi 	 * Skip loopback addresses for non-loopback assoc., ignore
15191d8c4025Svi 	 * this on a clustered node.
15201d8c4025Svi 	 */
15211d8c4025Svi 	if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback &&
15221d8c4025Svi 	    (cl_sctp_check_addrs == NULL)) {
15237c478bd9Sstevel@tonic-gate 		skip_lback = B_TRUE;
15241d8c4025Svi 	}
15251d8c4025Svi 
15267c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
15277c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
15287c478bd9Sstevel@tonic-gate 			continue;
15297c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15307c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15317c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif = obj->saddr_ipifp;
15327c478bd9Sstevel@tonic-gate 			in6_addr_t	addr = ipif->sctp_ipif_saddr;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 			scanned++;
15357c478bd9Sstevel@tonic-gate 			if ((ipif->sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
1536f551bb10Svi 			    SCTP_DONT_SRC(obj) ||
15371d8c4025Svi 			    (SCTP_IS_IPIF_LOOPBACK(ipif) && skip_lback)) {
15387c478bd9Sstevel@tonic-gate 				if (scanned >= sctp->sctp_nsaddrs)
15397c478bd9Sstevel@tonic-gate 					goto done;
15407c478bd9Sstevel@tonic-gate 				obj = list_next(&sctp->sctp_saddrs[i].
15417c478bd9Sstevel@tonic-gate 				    sctp_ipif_list, obj);
15427c478bd9Sstevel@tonic-gate 				continue;
15437c478bd9Sstevel@tonic-gate 			}
15447c478bd9Sstevel@tonic-gate 			switch (family) {
15457c478bd9Sstevel@tonic-gate 			case AF_INET:
15467c478bd9Sstevel@tonic-gate 				sin4 = (struct sockaddr_in *)myaddrs + added;
15477c478bd9Sstevel@tonic-gate 				sin4->sin_family = AF_INET;
1548*bd670b35SErik Nordmark 				sin4->sin_port = connp->conn_lport;
15497c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
15507c478bd9Sstevel@tonic-gate 				break;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 			case AF_INET6:
15537c478bd9Sstevel@tonic-gate 				sin6 = (struct sockaddr_in6 *)myaddrs + added;
15547c478bd9Sstevel@tonic-gate 				sin6->sin6_family = AF_INET6;
1555*bd670b35SErik Nordmark 				sin6->sin6_port = connp->conn_lport;
15567c478bd9Sstevel@tonic-gate 				sin6->sin6_addr = addr;
1557*bd670b35SErik Nordmark 				/*
1558*bd670b35SErik Nordmark 				 * Note that flowinfo is only returned for
1559*bd670b35SErik Nordmark 				 * getpeername just like for TCP and UDP.
1560*bd670b35SErik Nordmark 				 */
1561*bd670b35SErik Nordmark 				sin6->sin6_flowinfo = 0;
1562*bd670b35SErik Nordmark 
1563*bd670b35SErik Nordmark 				if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
1564*bd670b35SErik Nordmark 				    (ixa->ixa_flags & IXAF_SCOPEID_SET))
1565*bd670b35SErik Nordmark 					sin6->sin6_scope_id = ixa->ixa_scopeid;
1566*bd670b35SErik Nordmark 				else
1567*bd670b35SErik Nordmark 					sin6->sin6_scope_id = 0;
1568*bd670b35SErik Nordmark 				sin6->__sin6_src_id = 0;
15697c478bd9Sstevel@tonic-gate 				break;
15707c478bd9Sstevel@tonic-gate 			}
15717c478bd9Sstevel@tonic-gate 			added++;
15727c478bd9Sstevel@tonic-gate 			if (added >= max || scanned >= sctp->sctp_nsaddrs)
15737c478bd9Sstevel@tonic-gate 				goto done;
15747c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
15757c478bd9Sstevel@tonic-gate 			    obj);
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 	}
15787c478bd9Sstevel@tonic-gate done:
15797c478bd9Sstevel@tonic-gate 	*addrcnt = added;
15807c478bd9Sstevel@tonic-gate 	return (0);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /*
1584df19b344Svi  * Given the supported address family, walk through the source address list
1585df19b344Svi  * and return the total length of the available addresses. If 'p' is not
1586df19b344Svi  * null, construct the parameter list for the addresses in 'p'.
1587f551bb10Svi  * 'modify' will only be set when we want the source address list to
1588f551bb10Svi  * be modified. The source address list will be modified only when
1589f551bb10Svi  * generating an INIT chunk. For generating an INIT-ACK 'modify' will
1590f551bb10Svi  * be false since the 'sctp' will be that of the listener.
15917c478bd9Sstevel@tonic-gate  */
15927c478bd9Sstevel@tonic-gate size_t
1593f551bb10Svi sctp_saddr_info(sctp_t *sctp, int supp_af, uchar_t *p, boolean_t modify)
15947c478bd9Sstevel@tonic-gate {
15957c478bd9Sstevel@tonic-gate 	int			i;
15967c478bd9Sstevel@tonic-gate 	int			l;
15977c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
1598df19b344Svi 	size_t			paramlen = 0;
15997c478bd9Sstevel@tonic-gate 	sctp_parm_hdr_t		*hdr;
16007c478bd9Sstevel@tonic-gate 	int			scanned = 0;
1601f551bb10Svi 	int			naddr;
1602f551bb10Svi 	int			nsaddr;
16031d8c4025Svi 	boolean_t		del_ll = B_FALSE;
16041d8c4025Svi 	boolean_t		del_lb = B_FALSE;
16051d8c4025Svi 
16061d8c4025Svi 
16071d8c4025Svi 	/*
16081d8c4025Svi 	 * On a clustered node don't bother changing anything
16091d8c4025Svi 	 * on the loopback interface.
16101d8c4025Svi 	 */
16111d8c4025Svi 	if (modify && !sctp->sctp_loopback && (cl_sctp_check_addrs == NULL))
16121d8c4025Svi 		del_lb = B_TRUE;
1613f551bb10Svi 
16141d8c4025Svi 	if (modify && !sctp->sctp_linklocal)
16151d8c4025Svi 		del_ll = B_TRUE;
16167c478bd9Sstevel@tonic-gate 
1617f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
16187c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
16197c478bd9Sstevel@tonic-gate 		if (sctp->sctp_saddrs[i].ipif_count == 0)
16207c478bd9Sstevel@tonic-gate 			continue;
16217c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1622f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1623f551bb10Svi 		for (l = 0; l < naddr; l++) {
16247c478bd9Sstevel@tonic-gate 			in6_addr_t	addr;
16257c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
16261d8c4025Svi 			boolean_t	ipif_lb;
16271d8c4025Svi 			boolean_t	ipif_ll;
1628f551bb10Svi 			boolean_t	unsupp_af;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
16317c478bd9Sstevel@tonic-gate 			scanned++;
1632f551bb10Svi 
16331d8c4025Svi 			ipif_lb = SCTP_IS_IPIF_LOOPBACK(ipif);
16341d8c4025Svi 			ipif_ll = SCTP_IS_IPIF_LINKLOCAL(ipif);
1635f551bb10Svi 			unsupp_af = SCTP_UNSUPP_AF(ipif, supp_af);
1636f551bb10Svi 			/*
1637f551bb10Svi 			 * We need to either delete or skip loopback/linklocal
16381d8c4025Svi 			 * or unsupported addresses, if required.
1639f551bb10Svi 			 */
16401d8c4025Svi 			if ((ipif_ll && del_ll) || (ipif_lb && del_lb) ||
16411d8c4025Svi 			    (unsupp_af && modify)) {
1642f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1643f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1644f551bb10Svi 				if (scanned < nsaddr) {
1645f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1646f551bb10Svi 					    sctp_ipif_list, obj);
1647f551bb10Svi 					sctp_ipif_hash_remove(sctp, ipif);
1648f551bb10Svi 					continue;
1649f551bb10Svi 				}
1650f551bb10Svi 				sctp_ipif_hash_remove(sctp, ipif);
1651f551bb10Svi 				goto next_addr;
16521d8c4025Svi 			} else if (ipif_ll || unsupp_af ||
16531d8c4025Svi 			    (ipif_lb && (cl_sctp_check_addrs == NULL))) {
1654df19b344Svi 				goto next_addr;
16557c478bd9Sstevel@tonic-gate 			}
1656f551bb10Svi 
1657f551bb10Svi 			if (!SCTP_IPIF_USABLE(ipif->sctp_ipif_state))
1658f551bb10Svi 				goto next_addr;
1659df19b344Svi 			if (p != NULL)
1660df19b344Svi 				hdr = (sctp_parm_hdr_t *)(p + paramlen);
16617c478bd9Sstevel@tonic-gate 			addr = ipif->sctp_ipif_saddr;
1662f551bb10Svi 			if (!ipif->sctp_ipif_isv6) {
16637c478bd9Sstevel@tonic-gate 				struct in_addr	*v4;
16647c478bd9Sstevel@tonic-gate 
1665df19b344Svi 				if (p != NULL) {
1666df19b344Svi 					hdr->sph_type = htons(PARM_ADDR4);
1667df19b344Svi 					hdr->sph_len = htons(PARM_ADDR4_LEN);
1668df19b344Svi 					v4 = (struct in_addr *)(hdr + 1);
1669df19b344Svi 					IN6_V4MAPPED_TO_INADDR(&addr, v4);
1670df19b344Svi 				}
1671df19b344Svi 				paramlen += PARM_ADDR4_LEN;
1672f551bb10Svi 			} else {
1673df19b344Svi 				if (p != NULL) {
1674df19b344Svi 					hdr->sph_type = htons(PARM_ADDR6);
1675df19b344Svi 					hdr->sph_len = htons(PARM_ADDR6_LEN);
1676df19b344Svi 					bcopy(&addr, hdr + 1, sizeof (addr));
1677df19b344Svi 				}
1678df19b344Svi 				paramlen += PARM_ADDR6_LEN;
16797c478bd9Sstevel@tonic-gate 			}
1680df19b344Svi next_addr:
1681f551bb10Svi 			if (scanned >= nsaddr)
1682df19b344Svi 				return (paramlen);
16837c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
16847c478bd9Sstevel@tonic-gate 			    obj);
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 	}
1687df19b344Svi 	return (paramlen);
16887c478bd9Sstevel@tonic-gate }
16897c478bd9Sstevel@tonic-gate 
16901d8c4025Svi /*
16911d8c4025Svi  * This is used on a clustered node to obtain a list of addresses, the list
16921d8c4025Svi  * consists of sockaddr_in structs for v4 and sockaddr_in6 for v6. The list
16931d8c4025Svi  * is then passed onto the clustering module which sends back the correct
16941d8c4025Svi  * list based on the port info. Regardless of the input, i.e INADDR_ANY
16951d8c4025Svi  * or specific address(es), we create the list since it could be modified by
16961d8c4025Svi  * the clustering module. When given a list of addresses, we simply
16971d8c4025Svi  * create the list of sockaddr_in or sockaddr_in6 structs using those
16981d8c4025Svi  * addresses. If there is an INADDR_ANY in the input list, or if the
16991d8c4025Svi  * input is INADDR_ANY, we create a list of sockaddr_in or sockaddr_in6
17001d8c4025Svi  * structs consisting all the addresses in the global interface list
17011d8c4025Svi  * except those that are hosted on the loopback interface. We create
17021d8c4025Svi  * a list of sockaddr_in[6] structs just so that it can be directly input
17031d8c4025Svi  * to sctp_valid_addr_list() once the clustering module has processed it.
17041d8c4025Svi  */
17051d8c4025Svi int
17061d8c4025Svi sctp_get_addrlist(sctp_t *sctp, const void *addrs, uint32_t *addrcnt,
17071d8c4025Svi     uchar_t **addrlist, int *uspec, size_t *size)
17081d8c4025Svi {
17091d8c4025Svi 	int			cnt;
17101d8c4025Svi 	int			icnt;
17111d8c4025Svi 	sctp_ipif_t		*sctp_ipif;
17121d8c4025Svi 	struct sockaddr_in	*s4;
17131d8c4025Svi 	struct sockaddr_in6	*s6;
17141d8c4025Svi 	uchar_t			*p;
17151d8c4025Svi 	int			err = 0;
1716f4b3ec61Sdh 	sctp_stack_t		*sctps = sctp->sctp_sctps;
1717*bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
17181d8c4025Svi 
17191d8c4025Svi 	*addrlist = NULL;
17201d8c4025Svi 	*size = 0;
17211d8c4025Svi 
17221d8c4025Svi 	/*
17231d8c4025Svi 	 * Create a list of sockaddr_in[6] structs using the input list.
17241d8c4025Svi 	 */
1725*bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
17261d8c4025Svi 		*size = sizeof (struct sockaddr_in) * *addrcnt;
17271d8c4025Svi 		*addrlist = kmem_zalloc(*size,  KM_SLEEP);
17281d8c4025Svi 		p = *addrlist;
17291d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
17301d8c4025Svi 			s4 = (struct sockaddr_in *)addrs + cnt;
17311d8c4025Svi 			/*
17321d8c4025Svi 			 * We need to create a list of all the available
17331d8c4025Svi 			 * addresses if there is an INADDR_ANY. However,
17341d8c4025Svi 			 * if we are beyond LISTEN, then this is invalid
17351d8c4025Svi 			 * (see sctp_valid_addr_list(). So, we just fail
17361d8c4025Svi 			 * it here rather than wait till it fails in
17371d8c4025Svi 			 * sctp_valid_addr_list().
17381d8c4025Svi 			 */
17391d8c4025Svi 			if (s4->sin_addr.s_addr == INADDR_ANY) {
17401d8c4025Svi 				kmem_free(*addrlist, *size);
17411d8c4025Svi 				*addrlist = NULL;
17421d8c4025Svi 				*size = 0;
17431d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
17441d8c4025Svi 					*addrcnt = 0;
17451d8c4025Svi 					return (EINVAL);
17461d8c4025Svi 				}
17471d8c4025Svi 				if (uspec != NULL)
17481d8c4025Svi 					*uspec = 1;
17491d8c4025Svi 				goto get_all_addrs;
17501d8c4025Svi 			} else {
17511d8c4025Svi 				bcopy(s4, p, sizeof (*s4));
17521d8c4025Svi 				p += sizeof (*s4);
17531d8c4025Svi 			}
17541d8c4025Svi 		}
17551d8c4025Svi 	} else {
17561d8c4025Svi 		*size = sizeof (struct sockaddr_in6) * *addrcnt;
17571d8c4025Svi 		*addrlist = kmem_zalloc(*size, KM_SLEEP);
17581d8c4025Svi 		p = *addrlist;
17591d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
17601d8c4025Svi 			s6 = (struct sockaddr_in6 *)addrs + cnt;
17611d8c4025Svi 			/*
17621d8c4025Svi 			 * Comments for INADDR_ANY, above, apply here too.
17631d8c4025Svi 			 */
17641d8c4025Svi 			if (IN6_IS_ADDR_UNSPECIFIED(&s6->sin6_addr)) {
17651d8c4025Svi 				kmem_free(*addrlist, *size);
17661d8c4025Svi 				*size = 0;
17671d8c4025Svi 				*addrlist = NULL;
17681d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
17691d8c4025Svi 					*addrcnt = 0;
17701d8c4025Svi 					return (EINVAL);
17711d8c4025Svi 				}
17721d8c4025Svi 				if (uspec != NULL)
17731d8c4025Svi 					*uspec = 1;
17741d8c4025Svi 				goto get_all_addrs;
17751d8c4025Svi 			} else {
17761d8c4025Svi 				bcopy(addrs, p, sizeof (*s6));
17771d8c4025Svi 				p += sizeof (*s6);
17781d8c4025Svi 			}
17791d8c4025Svi 		}
17801d8c4025Svi 	}
17811d8c4025Svi 	return (err);
17821d8c4025Svi get_all_addrs:
17831d8c4025Svi 
17841d8c4025Svi 	/*
17851d8c4025Svi 	 * Allocate max possible size. We allocate the max. size here because
17861d8c4025Svi 	 * the clustering module could end up adding addresses to the list.
17871d8c4025Svi 	 * We allocate upfront so that the clustering module need to bother
17881d8c4025Svi 	 * re-sizing the list.
17891d8c4025Svi 	 */
1790*bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
1791f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in) *
1792f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1793f4b3ec61Sdh 	} else {
1794f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in6) *
1795f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1796f4b3ec61Sdh 	}
17971d8c4025Svi 	*addrlist = kmem_zalloc(*size, KM_SLEEP);
17981d8c4025Svi 	*addrcnt = 0;
17991d8c4025Svi 	p = *addrlist;
1800f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
18011d8c4025Svi 
18021d8c4025Svi 	/*
18031d8c4025Svi 	 * Walk through the global interface list and add all addresses,
18041d8c4025Svi 	 * except those that are hosted on loopback interfaces.
18051d8c4025Svi 	 */
18061d8c4025Svi 	for (cnt = 0; cnt <  SCTP_IPIF_HASH; cnt++) {
1807f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[cnt].ipif_count == 0)
18081d8c4025Svi 			continue;
1809f4b3ec61Sdh 		sctp_ipif = list_head(
1810f4b3ec61Sdh 		    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list);
1811f4b3ec61Sdh 		for (icnt = 0;
1812f4b3ec61Sdh 		    icnt < sctps->sctps_g_ipifs[cnt].ipif_count;
1813f4b3ec61Sdh 		    icnt++) {
18141d8c4025Svi 			in6_addr_t	addr;
18151d8c4025Svi 
18161d8c4025Svi 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
18171d8c4025Svi 			addr = sctp_ipif->sctp_ipif_saddr;
18181d8c4025Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
18191d8c4025Svi 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
18201d8c4025Svi 			    SCTP_IS_IPIF_LOOPBACK(sctp_ipif) ||
18211d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(sctp_ipif) ||
18225d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
1823*bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET &&
18241d8c4025Svi 			    sctp_ipif->sctp_ipif_isv6) ||
18251d8c4025Svi 			    (sctp->sctp_connp->conn_ipv6_v6only &&
18261d8c4025Svi 			    !sctp_ipif->sctp_ipif_isv6)) {
18271d8c4025Svi 				rw_exit(&sctp_ipif->sctp_ipif_lock);
18281d8c4025Svi 				sctp_ipif = list_next(
1829f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
18301d8c4025Svi 				    sctp_ipif);
18311d8c4025Svi 				continue;
18321d8c4025Svi 			}
18331d8c4025Svi 			rw_exit(&sctp_ipif->sctp_ipif_lock);
1834*bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET) {
18351d8c4025Svi 				s4 = (struct sockaddr_in *)p;
18361d8c4025Svi 				IN6_V4MAPPED_TO_INADDR(&addr, &s4->sin_addr);
18371d8c4025Svi 				s4->sin_family = AF_INET;
18381d8c4025Svi 				p += sizeof (*s4);
18391d8c4025Svi 			} else {
18401d8c4025Svi 				s6 = (struct sockaddr_in6 *)p;
18411d8c4025Svi 				s6->sin6_addr = addr;
18421d8c4025Svi 				s6->sin6_family = AF_INET6;
18431d8c4025Svi 				s6->sin6_scope_id =
18441d8c4025Svi 				    sctp_ipif->sctp_ipif_ill->sctp_ill_index;
18451d8c4025Svi 				p += sizeof (*s6);
18461d8c4025Svi 			}
18471d8c4025Svi 			(*addrcnt)++;
1848f4b3ec61Sdh 			sctp_ipif = list_next(
1849f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
18501d8c4025Svi 			    sctp_ipif);
18511d8c4025Svi 		}
18521d8c4025Svi 	}
1853f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
18541d8c4025Svi 	return (err);
18551d8c4025Svi }
18561d8c4025Svi 
18571d8c4025Svi /*
18581d8c4025Svi  * Get a list of addresses from the source address list. The  caller is
18591d8c4025Svi  * responsible for allocating sufficient buffer for this.
18601d8c4025Svi  */
18611d8c4025Svi void
18621d8c4025Svi sctp_get_saddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
18631d8c4025Svi {
18641d8c4025Svi 	int			cnt;
18651d8c4025Svi 	int			icnt;
18661d8c4025Svi 	sctp_saddr_ipif_t	*obj;
18671d8c4025Svi 	int			naddr;
18681d8c4025Svi 	int			scanned = 0;
18691d8c4025Svi 
18701d8c4025Svi 	for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
18711d8c4025Svi 		if (sctp->sctp_saddrs[cnt].ipif_count == 0)
18721d8c4025Svi 			continue;
18731d8c4025Svi 		obj = list_head(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
18741d8c4025Svi 		naddr = sctp->sctp_saddrs[cnt].ipif_count;
18751d8c4025Svi 		for (icnt = 0; icnt < naddr; icnt++) {
18761d8c4025Svi 			sctp_ipif_t	*ipif;
18771d8c4025Svi 
18781d8c4025Svi 			if (psize < sizeof (ipif->sctp_ipif_saddr))
18791d8c4025Svi 				return;
18801d8c4025Svi 
18811d8c4025Svi 			scanned++;
18821d8c4025Svi 			ipif = obj->saddr_ipifp;
18831d8c4025Svi 			bcopy(&ipif->sctp_ipif_saddr, p,
18841d8c4025Svi 			    sizeof (ipif->sctp_ipif_saddr));
18851d8c4025Svi 			p += sizeof (ipif->sctp_ipif_saddr);
18861d8c4025Svi 			psize -= sizeof (ipif->sctp_ipif_saddr);
18871d8c4025Svi 			if (scanned >= sctp->sctp_nsaddrs)
18881d8c4025Svi 				return;
1889f4b3ec61Sdh 			obj = list_next(
1890f4b3ec61Sdh 			    &sctp->sctp_saddrs[icnt].sctp_ipif_list,
18911d8c4025Svi 			    obj);
18921d8c4025Svi 		}
18931d8c4025Svi 	}
18941d8c4025Svi }
18951d8c4025Svi 
18961d8c4025Svi /*
18971d8c4025Svi  * Get a list of addresses from the remote address list. The  caller is
18981d8c4025Svi  * responsible for allocating sufficient buffer for this.
18991d8c4025Svi  */
19001d8c4025Svi void
19011d8c4025Svi sctp_get_faddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
19021d8c4025Svi {
19031d8c4025Svi 	sctp_faddr_t	*fp;
19041d8c4025Svi 
19051d8c4025Svi 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
19061d8c4025Svi 		if (psize < sizeof (fp->faddr))
19071d8c4025Svi 			return;
19081d8c4025Svi 		bcopy(&fp->faddr, p, sizeof (fp->faddr));
19091d8c4025Svi 		p += sizeof (fp->faddr);
19101d8c4025Svi 		psize -= sizeof (fp->faddr);
19111d8c4025Svi 	}
19121d8c4025Svi }
19137c478bd9Sstevel@tonic-gate 
1914f4b3ec61Sdh static void
1915f4b3ec61Sdh sctp_free_ills(sctp_stack_t *sctps)
1916f4b3ec61Sdh {
1917f4b3ec61Sdh 	int			i;
1918f4b3ec61Sdh 	int			l;
1919f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1920f4b3ec61Sdh 
1921f4b3ec61Sdh 	if (sctps->sctps_ills_count == 0)
1922f4b3ec61Sdh 		return;
1923f4b3ec61Sdh 
1924f4b3ec61Sdh 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1925f4b3ec61Sdh 		sctp_ill = list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1926f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ills[i].ill_count; l++) {
1927f4b3ec61Sdh 			ASSERT(sctp_ill->sctp_ill_ipifcnt == 0);
1928f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[i].sctp_ill_list,
1929f4b3ec61Sdh 			    sctp_ill);
1930f4b3ec61Sdh 			sctps->sctps_ills_count--;
1931f4b3ec61Sdh 			kmem_free(sctp_ill->sctp_ill_name,
1932f4b3ec61Sdh 			    sctp_ill->sctp_ill_name_length);
1933f4b3ec61Sdh 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
1934f4b3ec61Sdh 			sctp_ill =
1935f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1936f4b3ec61Sdh 		}
1937f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
1938f4b3ec61Sdh 	}
1939f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0);
1940f4b3ec61Sdh }
1941f4b3ec61Sdh 
1942f4b3ec61Sdh static void
1943f4b3ec61Sdh sctp_free_ipifs(sctp_stack_t *sctps)
1944f4b3ec61Sdh {
1945f4b3ec61Sdh 	int			i;
1946f4b3ec61Sdh 	int			l;
1947f4b3ec61Sdh 	sctp_ipif_t	*sctp_ipif;
1948f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1949f4b3ec61Sdh 
1950f4b3ec61Sdh 	if (sctps->sctps_g_ipifs_count == 0)
1951f4b3ec61Sdh 		return;
1952f4b3ec61Sdh 
1953f4b3ec61Sdh 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1954f4b3ec61Sdh 		sctp_ipif = list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
1955f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ipifs[i].ipif_count; l++) {
1956f4b3ec61Sdh 			sctp_ill = sctp_ipif->sctp_ipif_ill;
1957f4b3ec61Sdh 
1958f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
1959f4b3ec61Sdh 			    sctp_ipif);
1960f4b3ec61Sdh 			sctps->sctps_g_ipifs_count--;
1961f4b3ec61Sdh 			(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt,
1962f4b3ec61Sdh 			    -1);
1963f4b3ec61Sdh 			kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1964f4b3ec61Sdh 			sctp_ipif =
1965f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
1966f4b3ec61Sdh 		}
1967f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
1968f4b3ec61Sdh 	}
1969f4b3ec61Sdh 	ASSERT(sctps->sctps_g_ipifs_count == 0);
1970f4b3ec61Sdh }
1971f4b3ec61Sdh 
1972f4b3ec61Sdh 
19737c478bd9Sstevel@tonic-gate /* Initialize the SCTP ILL list and lock */
19747c478bd9Sstevel@tonic-gate void
1975f4b3ec61Sdh sctp_saddr_init(sctp_stack_t *sctps)
19767c478bd9Sstevel@tonic-gate {
19777c478bd9Sstevel@tonic-gate 	int	i;
19787c478bd9Sstevel@tonic-gate 
1979f4b3ec61Sdh 	sctps->sctps_g_ills = kmem_zalloc(sizeof (sctp_ill_hash_t) *
1980f4b3ec61Sdh 	    SCTP_ILL_HASH, KM_SLEEP);
1981f4b3ec61Sdh 	sctps->sctps_g_ipifs = kmem_zalloc(sizeof (sctp_ipif_hash_t) *
1982f4b3ec61Sdh 	    SCTP_IPIF_HASH, KM_SLEEP);
1983f4b3ec61Sdh 
1984f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ills_lock, NULL, RW_DEFAULT, NULL);
1985f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ipifs_lock, NULL, RW_DEFAULT, NULL);
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1988f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
1989f4b3ec61Sdh 		list_create(&sctps->sctps_g_ills[i].sctp_ill_list,
1990f4b3ec61Sdh 		    sizeof (sctp_ill_t),
19917c478bd9Sstevel@tonic-gate 		    offsetof(sctp_ill_t, sctp_ills));
19927c478bd9Sstevel@tonic-gate 	}
19937c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1994f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
1995f4b3ec61Sdh 		list_create(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
19967c478bd9Sstevel@tonic-gate 		    sizeof (sctp_ipif_t), offsetof(sctp_ipif_t, sctp_ipifs));
19977c478bd9Sstevel@tonic-gate 	}
19987c478bd9Sstevel@tonic-gate }
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate void
2001f4b3ec61Sdh sctp_saddr_fini(sctp_stack_t *sctps)
20027c478bd9Sstevel@tonic-gate {
20037c478bd9Sstevel@tonic-gate 	int	i;
20047c478bd9Sstevel@tonic-gate 
2005f4b3ec61Sdh 	sctp_free_ipifs(sctps);
2006f4b3ec61Sdh 	sctp_free_ills(sctps);
2007f4b3ec61Sdh 
20087c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++)
2009f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ills[i].sctp_ill_list);
20107c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++)
2011f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2012f4b3ec61Sdh 
2013f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0 && sctps->sctps_g_ipifs_count == 0);
2014f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ills, sizeof (sctp_ill_hash_t) *
2015f4b3ec61Sdh 	    SCTP_ILL_HASH);
2016f4b3ec61Sdh 	sctps->sctps_g_ills = NULL;
2017f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ipifs, sizeof (sctp_ipif_hash_t) *
2018f4b3ec61Sdh 	    SCTP_IPIF_HASH);
2019f4b3ec61Sdh 	sctps->sctps_g_ipifs = NULL;
2020f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ills_lock);
2021f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ipifs_lock);
20227c478bd9Sstevel@tonic-gate }
2023