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>
44bd670b35SErik 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);
58*92baa190SGeorge Shepherd static void		sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *,
59*92baa190SGeorge Shepherd 			    boolean_t);
60c31292eeSkcpoon static void		sctp_fix_saddr(sctp_t *, in6_addr_t *);
617c478bd9Sstevel@tonic-gate static int		sctp_compare_ipif_list(sctp_ipif_hash_t *,
627c478bd9Sstevel@tonic-gate 			    sctp_ipif_hash_t *);
637c478bd9Sstevel@tonic-gate static int		sctp_copy_ipifs(sctp_ipif_hash_t *, sctp_t *, int);
64f551bb10Svi 
65e35d2278Svi #define	SCTP_ADDR4_HASH(addr)	\
66e35d2278Svi 	(((addr) ^ ((addr) >> 8) ^ ((addr) >> 16) ^ ((addr) >> 24)) &	\
67e35d2278Svi 	(SCTP_IPIF_HASH - 1))
68e35d2278Svi 
69e35d2278Svi #define	SCTP_ADDR6_HASH(addr)	\
70e35d2278Svi 	(((addr).s6_addr32[3] ^						\
71e35d2278Svi 	(((addr).s6_addr32[3] ^ (addr).s6_addr32[2]) >> 12)) &		\
72e35d2278Svi 	(SCTP_IPIF_HASH - 1))
73e35d2278Svi 
74e35d2278Svi #define	SCTP_IPIF_ADDR_HASH(addr, isv6)					\
75e35d2278Svi 	((isv6) ? SCTP_ADDR6_HASH((addr)) : 				\
76e35d2278Svi 	SCTP_ADDR4_HASH((addr)._S6_un._S6_u32[3]))
77e35d2278Svi 
787c478bd9Sstevel@tonic-gate #define	SCTP_IPIF_USABLE(sctp_ipif_state)	\
797c478bd9Sstevel@tonic-gate 	((sctp_ipif_state) == SCTP_IPIFS_UP ||	\
80f551bb10Svi 	(sctp_ipif_state) ==  SCTP_IPIFS_DOWN)
81f551bb10Svi 
82f551bb10Svi #define	SCTP_IPIF_DISCARD(sctp_ipif_flags)	\
83f551bb10Svi 	((sctp_ipif_flags) & (IPIF_PRIVATE | IPIF_DEPRECATED))
84f551bb10Svi 
851d8c4025Svi #define	SCTP_IS_IPIF_LOOPBACK(ipif)		\
861d8c4025Svi 	((ipif)->sctp_ipif_ill->sctp_ill_flags & PHYI_LOOPBACK)
871d8c4025Svi 
881d8c4025Svi #define	SCTP_IS_IPIF_LINKLOCAL(ipif)		\
891d8c4025Svi 	((ipif)->sctp_ipif_isv6 && 		\
901d8c4025Svi 	IN6_IS_ADDR_LINKLOCAL(&(ipif)->sctp_ipif_saddr))
91f551bb10Svi 
92f551bb10Svi #define	SCTP_UNSUPP_AF(ipif, supp_af)	\
93f551bb10Svi 	((!(ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V4)) ||	\
94f551bb10Svi 	((ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V6)))
957c478bd9Sstevel@tonic-gate 
965d0bc3edSsommerfe #define	SCTP_IPIF_ZONE_MATCH(sctp, ipif) 				\
975d0bc3edSsommerfe 	IPCL_ZONE_MATCH((sctp)->sctp_connp, (ipif)->sctp_ipif_zoneid)
985d0bc3edSsommerfe 
997c478bd9Sstevel@tonic-gate #define	SCTP_ILL_HASH_FN(index)		((index) % SCTP_ILL_HASH)
1007c478bd9Sstevel@tonic-gate #define	SCTP_ILL_TO_PHYINDEX(ill)	((ill)->ill_phyint->phyint_ifindex)
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * SCTP Interface list manipulation functions, locking used.
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * Delete an SCTP IPIF from the list if the refcount goes to 0 and it is
1087c478bd9Sstevel@tonic-gate  * marked as condemned. Also, check if the ILL needs to go away.
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static void
1117c478bd9Sstevel@tonic-gate sctp_ipif_inactive(sctp_ipif_t *sctp_ipif)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
114e35d2278Svi 	uint_t		hindex;
1157c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
116f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp_ipif->sctp_ipif_ill->
117f4b3ec61Sdh 	    sctp_ill_netstack->netstack_sctp;
1187c478bd9Sstevel@tonic-gate 
119f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
120f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1217c478bd9Sstevel@tonic-gate 
122e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(sctp_ipif->sctp_ipif_saddr,
123e35d2278Svi 	    sctp_ipif->sctp_ipif_isv6);
124e35d2278Svi 
1257c478bd9Sstevel@tonic-gate 	sctp_ill = sctp_ipif->sctp_ipif_ill;
1267c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ill != NULL);
1277c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(sctp_ill->sctp_ill_index);
1287c478bd9Sstevel@tonic-gate 	if (sctp_ipif->sctp_ipif_state != SCTP_IPIFS_CONDEMNED ||
1297c478bd9Sstevel@tonic-gate 	    sctp_ipif->sctp_ipif_refcnt != 0) {
130f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
131f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
1327c478bd9Sstevel@tonic-gate 		return;
1337c478bd9Sstevel@tonic-gate 	}
134e35d2278Svi 	list_remove(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
135f4b3ec61Sdh 	    sctp_ipif);
136e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count--;
137f4b3ec61Sdh 	sctps->sctps_g_ipifs_count--;
1387c478bd9Sstevel@tonic-gate 	rw_destroy(&sctp_ipif->sctp_ipif_lock);
1397c478bd9Sstevel@tonic-gate 	kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
142f4b3ec61Sdh 	if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
143f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
1447c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0 &&
1457c478bd9Sstevel@tonic-gate 		    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
146f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[ill_index].
147f4b3ec61Sdh 			    sctp_ill_list, (void *)sctp_ill);
148f4b3ec61Sdh 			sctps->sctps_g_ills[ill_index].ill_count--;
149f4b3ec61Sdh 			sctps->sctps_ills_count--;
1507c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
1517c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_name_length);
1527c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
1537c478bd9Sstevel@tonic-gate 		}
1547c478bd9Sstevel@tonic-gate 	}
155f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
156f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * Lookup an SCTP IPIF given an IP address. Increments sctp_ipif refcnt.
161e35d2278Svi  * We are either looking for a IPIF with the given address before
162e35d2278Svi  * inserting it into the global list or looking for an IPIF for an
163e35d2278Svi  * address given an SCTP. In the former case we always check the zoneid,
164e35d2278Svi  * but for the latter case, check_zid could be B_FALSE if the connp
165e35d2278Svi  * for the sctp has conn_all_zones set. When looking for an address we
166e35d2278Svi  * give preference to one that is up, so even though we may find one that
167e35d2278Svi  * is not up we keep looking if there is one up, we hold the down addr
168e35d2278Svi  * in backup_ipif in case we don't find one that is up - i.e. we return
169e35d2278Svi  * the backup_ipif in that case. Note that if we are looking for. If we
170e35d2278Svi  * are specifically looking for an up address, then usable will be set
171e35d2278Svi  * to true.
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate static sctp_ipif_t *
174e35d2278Svi sctp_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid,
175e35d2278Svi     boolean_t check_zid, uint_t ifindex, uint_t seqid, boolean_t usable,
176e35d2278Svi     sctp_stack_t *sctps)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	int		j;
1797c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
180e35d2278Svi 	sctp_ipif_t	*backup_ipif = NULL;
181e35d2278Svi 	int		hindex;
182e35d2278Svi 
183e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1847c478bd9Sstevel@tonic-gate 
185f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
186e35d2278Svi 	if (sctps->sctps_g_ipifs[hindex].ipif_count == 0) {
187e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
188e35d2278Svi 		return (NULL);
189e35d2278Svi 	}
190e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
191e35d2278Svi 	for (j = 0; j < sctps->sctps_g_ipifs[hindex].ipif_count; j++) {
192e35d2278Svi 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
193e35d2278Svi 		if ((!check_zid ||
194e35d2278Svi 		    (sctp_ipif->sctp_ipif_zoneid == ALL_ZONES ||
195e35d2278Svi 		    zoneid == sctp_ipif->sctp_ipif_zoneid)) &&
196e35d2278Svi 		    (ifindex == 0 || ifindex ==
197e35d2278Svi 		    sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
198e35d2278Svi 		    ((seqid != 0 && seqid == sctp_ipif->sctp_ipif_id) ||
199e35d2278Svi 		    (IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
200e35d2278Svi 		    addr)))) {
201e35d2278Svi 			if (!usable || sctp_ipif->sctp_ipif_state ==
202e35d2278Svi 			    SCTP_IPIFS_UP) {
2037c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2047c478bd9Sstevel@tonic-gate 				if (refhold)
2057c478bd9Sstevel@tonic-gate 					SCTP_IPIF_REFHOLD(sctp_ipif);
206f4b3ec61Sdh 				rw_exit(&sctps->sctps_g_ipifs_lock);
2077c478bd9Sstevel@tonic-gate 				return (sctp_ipif);
208e35d2278Svi 			} else if (sctp_ipif->sctp_ipif_state ==
209e35d2278Svi 			    SCTP_IPIFS_DOWN && backup_ipif == NULL) {
210e35d2278Svi 				backup_ipif = sctp_ipif;
2117c478bd9Sstevel@tonic-gate 			}
2127c478bd9Sstevel@tonic-gate 		}
213e35d2278Svi 		rw_exit(&sctp_ipif->sctp_ipif_lock);
214e35d2278Svi 		sctp_ipif = list_next(
215e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
216e35d2278Svi 	}
217e35d2278Svi 	if (backup_ipif != NULL) {
218e35d2278Svi 		if (refhold)
219e35d2278Svi 			SCTP_IPIF_REFHOLD(backup_ipif);
220e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
221e35d2278Svi 		return (backup_ipif);
2227c478bd9Sstevel@tonic-gate 	}
223f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2247c478bd9Sstevel@tonic-gate 	return (NULL);
2257c478bd9Sstevel@tonic-gate }
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate /*
2287c478bd9Sstevel@tonic-gate  * Populate the list with all the SCTP ipifs for a given ipversion.
2297c478bd9Sstevel@tonic-gate  * Increments sctp_ipif refcnt.
2307c478bd9Sstevel@tonic-gate  * Called with no locks held.
2317c478bd9Sstevel@tonic-gate  */
2327c478bd9Sstevel@tonic-gate static int
2337c478bd9Sstevel@tonic-gate sctp_get_all_ipifs(sctp_t *sctp, int sleep)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
2367c478bd9Sstevel@tonic-gate 	int			i;
2377c478bd9Sstevel@tonic-gate 	int			j;
2387c478bd9Sstevel@tonic-gate 	int			error = 0;
239a22dfb13SVenugopal Iyer 	sctp_stack_t		*sctps = sctp->sctp_sctps;
240a22dfb13SVenugopal Iyer 	boolean_t		isv6;
241bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
2427c478bd9Sstevel@tonic-gate 
243f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
2447c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
245f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[i].ipif_count == 0)
2467c478bd9Sstevel@tonic-gate 			continue;
247f4b3ec61Sdh 		sctp_ipif = list_head(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
248f4b3ec61Sdh 		for (j = 0; j < sctps->sctps_g_ipifs[i].ipif_count; j++) {
2497c478bd9Sstevel@tonic-gate 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
250a22dfb13SVenugopal Iyer 			isv6 = sctp_ipif->sctp_ipif_isv6;
251f551bb10Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
2527c478bd9Sstevel@tonic-gate 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
2535d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
254a22dfb13SVenugopal Iyer 			    SCTP_IS_ADDR_UNSPEC(!isv6,
255a22dfb13SVenugopal Iyer 			    sctp_ipif->sctp_ipif_saddr) ||
256bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET && isv6) ||
257bd670b35SErik Nordmark 			    (connp->conn_ipv6_v6only && !isv6)) {
2587c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2597c478bd9Sstevel@tonic-gate 				sctp_ipif = list_next(
260f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
261f4b3ec61Sdh 				    sctp_ipif);
2627c478bd9Sstevel@tonic-gate 				continue;
2637c478bd9Sstevel@tonic-gate 			}
2647c478bd9Sstevel@tonic-gate 			rw_exit(&sctp_ipif->sctp_ipif_lock);
2657c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFHOLD(sctp_ipif);
266f551bb10Svi 			error = sctp_ipif_hash_insert(sctp, sctp_ipif, sleep,
267e35d2278Svi 			    B_FALSE, B_FALSE);
268e35d2278Svi 			if (error != 0 && error != EALREADY)
2697c478bd9Sstevel@tonic-gate 				goto free_stuff;
270f4b3ec61Sdh 			sctp_ipif = list_next(
271f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2727c478bd9Sstevel@tonic-gate 			    sctp_ipif);
2737c478bd9Sstevel@tonic-gate 		}
2747c478bd9Sstevel@tonic-gate 	}
275f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2767c478bd9Sstevel@tonic-gate 	return (0);
2777c478bd9Sstevel@tonic-gate free_stuff:
278f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2797c478bd9Sstevel@tonic-gate 	sctp_free_saddrs(sctp);
2807c478bd9Sstevel@tonic-gate 	return (ENOMEM);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate  * Given a list of address, fills in the list of SCTP ipifs if all the addresses
2857c478bd9Sstevel@tonic-gate  * are present in the SCTP interface list, return number of addresses filled
2861d8c4025Svi  * or error. If the caller wants the list of addresses, it sends a pre-allocated
2871d8c4025Svi  * buffer - list. Currently, this list is only used on a clustered node when
2881d8c4025Svi  * the SCTP is in the listen state (from sctp_bind_add()). When called on a
2891d8c4025Svi  * clustered node, the input is always a list of addresses (even if the
2901d8c4025Svi  * original bind() was to INADDR_ANY).
2917c478bd9Sstevel@tonic-gate  * Called with no locks held.
2927c478bd9Sstevel@tonic-gate  */
2937c478bd9Sstevel@tonic-gate int
2941d8c4025Svi sctp_valid_addr_list(sctp_t *sctp, const void *addrs, uint32_t addrcnt,
2951d8c4025Svi     uchar_t *list, size_t lsize)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
2987c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
2997c478bd9Sstevel@tonic-gate 	struct in_addr		*addr4;
3007c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
3017c478bd9Sstevel@tonic-gate 	int			cnt;
3027c478bd9Sstevel@tonic-gate 	int			err = 0;
3037c478bd9Sstevel@tonic-gate 	int			saddr_cnt = 0;
3047c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*ipif;
3057c478bd9Sstevel@tonic-gate 	boolean_t		bind_to_all = B_FALSE;
3067c478bd9Sstevel@tonic-gate 	boolean_t		check_addrs = B_FALSE;
3077c478bd9Sstevel@tonic-gate 	boolean_t		check_lport = B_FALSE;
3081d8c4025Svi 	uchar_t			*p = list;
309bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * Need to check for port and address depending on the state.
3137c478bd9Sstevel@tonic-gate 	 * After a socket is bound, we need to make sure that subsequent
3147c478bd9Sstevel@tonic-gate 	 * bindx() has correct port.  After an association is established,
3157c478bd9Sstevel@tonic-gate 	 * we need to check for changing the bound address to invalid
3167c478bd9Sstevel@tonic-gate 	 * addresses.
3177c478bd9Sstevel@tonic-gate 	 */
3187c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state >= SCTPS_BOUND) {
3197c478bd9Sstevel@tonic-gate 		check_lport = B_TRUE;
3207c478bd9Sstevel@tonic-gate 		if (sctp->sctp_state > SCTPS_LISTEN)
3217c478bd9Sstevel@tonic-gate 			check_addrs = B_TRUE;
3227c478bd9Sstevel@tonic-gate 	}
3231d8c4025Svi 
3247c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
3257c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
3267c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
3277c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
3287c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addrcnt; cnt++) {
3297c478bd9Sstevel@tonic-gate 		boolean_t	lookup_saddr = B_TRUE;
3301d8c4025Svi 		uint_t		ifindex = 0;
3317c478bd9Sstevel@tonic-gate 
332bd670b35SErik Nordmark 		switch (connp->conn_family) {
3337c478bd9Sstevel@tonic-gate 		case AF_INET:
3347c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
3357c478bd9Sstevel@tonic-gate 			if (sin4->sin_family != AF_INET || (check_lport &&
336bd670b35SErik Nordmark 			    sin4->sin_port != connp->conn_lport)) {
3377c478bd9Sstevel@tonic-gate 				err = EINVAL;
3387c478bd9Sstevel@tonic-gate 				goto free_ret;
3397c478bd9Sstevel@tonic-gate 			}
3407c478bd9Sstevel@tonic-gate 			addr4 = &sin4->sin_addr;
3417c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3427c478bd9Sstevel@tonic-gate 			    (addr4->s_addr == INADDR_ANY ||
3437c478bd9Sstevel@tonic-gate 			    addr4->s_addr == INADDR_BROADCAST ||
344c4f4b3c8Skcpoon 			    CLASSD(addr4->s_addr))) {
3457c478bd9Sstevel@tonic-gate 				err = EINVAL;
3467c478bd9Sstevel@tonic-gate 				goto free_ret;
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(addr4, &addr);
3497c478bd9Sstevel@tonic-gate 			if (!check_addrs && addr4->s_addr == INADDR_ANY) {
3507c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3517c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3527c478bd9Sstevel@tonic-gate 			}
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 			break;
3557c478bd9Sstevel@tonic-gate 		case AF_INET6:
3567c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
3577c478bd9Sstevel@tonic-gate 			if (sin6->sin6_family != AF_INET6 || (check_lport &&
358bd670b35SErik Nordmark 			    sin6->sin6_port != connp->conn_lport)) {
3597c478bd9Sstevel@tonic-gate 				err = EINVAL;
3607c478bd9Sstevel@tonic-gate 				goto free_ret;
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
3631d8c4025Svi 			/* Contains the interface index */
3641d8c4025Svi 			ifindex = sin6->sin6_scope_id;
365bd670b35SErik Nordmark 			if (connp->conn_ipv6_v6only &&
3667c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&addr)) {
3677c478bd9Sstevel@tonic-gate 				err = EAFNOSUPPORT;
3687c478bd9Sstevel@tonic-gate 				goto free_ret;
3697c478bd9Sstevel@tonic-gate 			}
3707c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3717c478bd9Sstevel@tonic-gate 			    (IN6_IS_ADDR_LINKLOCAL(&addr) ||
3727c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&addr) ||
3737c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_UNSPECIFIED(&addr))) {
3747c478bd9Sstevel@tonic-gate 				err = EINVAL;
3757c478bd9Sstevel@tonic-gate 				goto free_ret;
3767c478bd9Sstevel@tonic-gate 			}
3777c478bd9Sstevel@tonic-gate 			if (!check_addrs && IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3787c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3797c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3807c478bd9Sstevel@tonic-gate 			}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 			break;
3837c478bd9Sstevel@tonic-gate 		default:
3847c478bd9Sstevel@tonic-gate 			err = EAFNOSUPPORT;
3857c478bd9Sstevel@tonic-gate 			goto free_ret;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 		if (lookup_saddr) {
388e35d2278Svi 			ipif = sctp_lookup_ipif_addr(&addr, B_TRUE,
389bd670b35SErik Nordmark 			    IPCL_ZONEID(connp), !connp->conn_allzones,
390e35d2278Svi 			    ifindex, 0, B_TRUE, sctp->sctp_sctps);
3917c478bd9Sstevel@tonic-gate 			if (ipif == NULL) {
3927c478bd9Sstevel@tonic-gate 				/* Address not in the list */
3937c478bd9Sstevel@tonic-gate 				err = EINVAL;
3947c478bd9Sstevel@tonic-gate 				goto free_ret;
3951d8c4025Svi 			} else if (check_addrs && SCTP_IS_IPIF_LOOPBACK(ipif) &&
3961d8c4025Svi 			    cl_sctp_check_addrs == NULL) {
3977c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
3987c478bd9Sstevel@tonic-gate 				err = EINVAL;
3997c478bd9Sstevel@tonic-gate 				goto free_ret;
4007c478bd9Sstevel@tonic-gate 			}
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 		if (!bind_to_all) {
403f551bb10Svi 			/*
404f551bb10Svi 			 * If an address is added after association setup,
405f551bb10Svi 			 * we need to wait for the peer to send us an ASCONF
406f551bb10Svi 			 * ACK before we can start using it.
407f551bb10Svi 			 * saddr_ipif_dontsrc will be reset (to 0) when we
408f551bb10Svi 			 * get the ASCONF ACK for this address.
409f551bb10Svi 			 */
410f551bb10Svi 			err = sctp_ipif_hash_insert(sctp, ipif, KM_SLEEP,
411e35d2278Svi 			    check_addrs ? B_TRUE : B_FALSE, B_FALSE);
4127c478bd9Sstevel@tonic-gate 			if (err != 0) {
4137c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
4147c478bd9Sstevel@tonic-gate 				if (check_addrs && err == EALREADY)
4157c478bd9Sstevel@tonic-gate 					err = EADDRINUSE;
4167c478bd9Sstevel@tonic-gate 				goto free_ret;
4177c478bd9Sstevel@tonic-gate 			}
4187c478bd9Sstevel@tonic-gate 			saddr_cnt++;
4191d8c4025Svi 			if (lsize >= sizeof (addr)) {
4201d8c4025Svi 				bcopy(&addr, p, sizeof (addr));
4211d8c4025Svi 				p += sizeof (addr);
4221d8c4025Svi 				lsize -= sizeof (addr);
4231d8c4025Svi 			}
4247c478bd9Sstevel@tonic-gate 		}
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 	if (bind_to_all) {
4277c478bd9Sstevel@tonic-gate 		/*
4287c478bd9Sstevel@tonic-gate 		 * Free whatever we might have added before encountering
4297c478bd9Sstevel@tonic-gate 		 * inaddr_any.
4307c478bd9Sstevel@tonic-gate 		 */
4317c478bd9Sstevel@tonic-gate 		if (sctp->sctp_nsaddrs > 0) {
4327c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp);
4337c478bd9Sstevel@tonic-gate 			ASSERT(sctp->sctp_nsaddrs == 0);
4347c478bd9Sstevel@tonic-gate 		}
4357c478bd9Sstevel@tonic-gate 		err = sctp_get_all_ipifs(sctp, KM_SLEEP);
4367c478bd9Sstevel@tonic-gate 		if (err != 0)
4377c478bd9Sstevel@tonic-gate 			return (err);
4387c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4417c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4427c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4437c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4447c478bd9Sstevel@tonic-gate 	return (0);
4457c478bd9Sstevel@tonic-gate free_ret:
4467c478bd9Sstevel@tonic-gate 	if (saddr_cnt != 0)
4477c478bd9Sstevel@tonic-gate 		sctp_del_saddr_list(sctp, addrs, saddr_cnt, B_TRUE);
4487c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4497c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4507c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4517c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4527c478bd9Sstevel@tonic-gate 	return (err);
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate static int
456f551bb10Svi sctp_ipif_hash_insert(sctp_t *sctp, sctp_ipif_t *ipif, int sleep,
457e35d2278Svi     boolean_t dontsrc, boolean_t allow_dup)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	int			cnt;
4607c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
461e35d2278Svi 	int			hindex;
462e35d2278Svi 
463e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
464e35d2278Svi 	    ipif->sctp_ipif_isv6);
465*92baa190SGeorge Shepherd 	rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
466e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
467e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
468e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
469e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
470e35d2278Svi 			if (ipif->sctp_ipif_id !=
471e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id &&
472e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_state ==
473e35d2278Svi 			    SCTP_IPIFS_DOWN && ipif->sctp_ipif_state ==
474e35d2278Svi 			    SCTP_IPIFS_UP) {
475e35d2278Svi 				SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
476e35d2278Svi 				ipif_obj->saddr_ipifp = ipif;
477e35d2278Svi 				ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
478*92baa190SGeorge Shepherd 				rw_exit(
479*92baa190SGeorge Shepherd 				    &sctp->sctp_saddrs[hindex].ipif_hash_lock);
480e35d2278Svi 				return (0);
481e35d2278Svi 			} else if (!allow_dup || ipif->sctp_ipif_id ==
482e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id) {
483*92baa190SGeorge Shepherd 				rw_exit(
484*92baa190SGeorge Shepherd 				    &sctp->sctp_saddrs[hindex].ipif_hash_lock);
485e35d2278Svi 				return (EALREADY);
486e35d2278Svi 			}
487e35d2278Svi 		}
488e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
4897c478bd9Sstevel@tonic-gate 		    ipif_obj);
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 	ipif_obj = kmem_zalloc(sizeof (sctp_saddr_ipif_t), sleep);
4927c478bd9Sstevel@tonic-gate 	if (ipif_obj == NULL) {
493*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
4947c478bd9Sstevel@tonic-gate 		/* Need to do something */
4957c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4967c478bd9Sstevel@tonic-gate 	}
4977c478bd9Sstevel@tonic-gate 	ipif_obj->saddr_ipifp = ipif;
498f551bb10Svi 	ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
499e35d2278Svi 	list_insert_tail(&sctp->sctp_saddrs[hindex].sctp_ipif_list, ipif_obj);
500e35d2278Svi 	sctp->sctp_saddrs[hindex].ipif_count++;
5017c478bd9Sstevel@tonic-gate 	sctp->sctp_nsaddrs++;
502*92baa190SGeorge Shepherd 	rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5037c478bd9Sstevel@tonic-gate 	return (0);
5047c478bd9Sstevel@tonic-gate }
5057c478bd9Sstevel@tonic-gate 
506c31292eeSkcpoon /*
507c31292eeSkcpoon  * Given a source address, walk through the peer address list to see
508c31292eeSkcpoon  * if the source address is being used.  If it is, reset that.
509bd670b35SErik Nordmark  * A cleared saddr will then make sctp_make_mp lookup the destination again
510bd670b35SErik Nordmark  * and as part of that look for a new source.
511c31292eeSkcpoon  */
512c31292eeSkcpoon static void
513c31292eeSkcpoon sctp_fix_saddr(sctp_t *sctp, in6_addr_t *saddr)
514c31292eeSkcpoon {
515c31292eeSkcpoon 	sctp_faddr_t	*fp;
516c31292eeSkcpoon 
517c31292eeSkcpoon 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
518c31292eeSkcpoon 		if (!IN6_ARE_ADDR_EQUAL(&fp->saddr, saddr))
519c31292eeSkcpoon 			continue;
520c31292eeSkcpoon 		V6_SET_ZERO(fp->saddr);
521c31292eeSkcpoon 	}
522c31292eeSkcpoon }
523c31292eeSkcpoon 
5247c478bd9Sstevel@tonic-gate static void
525*92baa190SGeorge Shepherd sctp_ipif_hash_remove(sctp_t *sctp, sctp_ipif_t *ipif, boolean_t locked)
5267c478bd9Sstevel@tonic-gate {
5277c478bd9Sstevel@tonic-gate 	int			cnt;
5287c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
529e35d2278Svi 	int			hindex;
530e35d2278Svi 
531e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
532e35d2278Svi 	    ipif->sctp_ipif_isv6);
533*92baa190SGeorge Shepherd 	if (!locked)
534*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
535e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
536e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
537e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
538e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
539e35d2278Svi 			list_remove(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5407c478bd9Sstevel@tonic-gate 			    ipif_obj);
541e35d2278Svi 			sctp->sctp_saddrs[hindex].ipif_count--;
5427c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
543c31292eeSkcpoon 			sctp_fix_saddr(sctp, &ipif->sctp_ipif_saddr);
5447c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
5457c478bd9Sstevel@tonic-gate 			kmem_free(ipif_obj, sizeof (sctp_saddr_ipif_t));
5467c478bd9Sstevel@tonic-gate 			break;
5477c478bd9Sstevel@tonic-gate 		}
548e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5497c478bd9Sstevel@tonic-gate 		    ipif_obj);
5507c478bd9Sstevel@tonic-gate 	}
551*92baa190SGeorge Shepherd 	if (!locked)
552*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate static int
5567c478bd9Sstevel@tonic-gate sctp_compare_ipif_list(sctp_ipif_hash_t *list1, sctp_ipif_hash_t *list2)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	int			i;
5597c478bd9Sstevel@tonic-gate 	int			j;
5607c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj1;
5617c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj2;
5627c478bd9Sstevel@tonic-gate 	int			overlap = 0;
5637c478bd9Sstevel@tonic-gate 
564*92baa190SGeorge Shepherd 	rw_enter(&list1->ipif_hash_lock, RW_READER);
565*92baa190SGeorge Shepherd 	rw_enter(&list2->ipif_hash_lock, RW_READER);
5667c478bd9Sstevel@tonic-gate 	obj1 = list_head(&list1->sctp_ipif_list);
5677c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
5687c478bd9Sstevel@tonic-gate 		obj2 = list_head(&list2->sctp_ipif_list);
5697c478bd9Sstevel@tonic-gate 		for (j = 0; j < list2->ipif_count; j++) {
570e35d2278Svi 			if (IN6_ARE_ADDR_EQUAL(
571e35d2278Svi 			    &obj1->saddr_ipifp->sctp_ipif_saddr,
572e35d2278Svi 			    &obj2->saddr_ipifp->sctp_ipif_saddr)) {
5737c478bd9Sstevel@tonic-gate 				overlap++;
5747c478bd9Sstevel@tonic-gate 				break;
5757c478bd9Sstevel@tonic-gate 			}
5767c478bd9Sstevel@tonic-gate 			obj2 = list_next(&list2->sctp_ipif_list,
5777c478bd9Sstevel@tonic-gate 			    obj2);
5787c478bd9Sstevel@tonic-gate 		}
5797c478bd9Sstevel@tonic-gate 		obj1 = list_next(&list1->sctp_ipif_list, obj1);
5807c478bd9Sstevel@tonic-gate 	}
581*92baa190SGeorge Shepherd 	rw_exit(&list1->ipif_hash_lock);
582*92baa190SGeorge Shepherd 	rw_exit(&list2->ipif_hash_lock);
5837c478bd9Sstevel@tonic-gate 	return (overlap);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate int
5877c478bd9Sstevel@tonic-gate sctp_compare_saddrs(sctp_t *sctp1, sctp_t *sctp2)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	int		i;
5907c478bd9Sstevel@tonic-gate 	int		overlap = 0;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
5937c478bd9Sstevel@tonic-gate 		overlap += sctp_compare_ipif_list(&sctp1->sctp_saddrs[i],
5947c478bd9Sstevel@tonic-gate 		    &sctp2->sctp_saddrs[i]);
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (sctp1->sctp_nsaddrs == sctp2->sctp_nsaddrs &&
5987c478bd9Sstevel@tonic-gate 	    overlap == sctp1->sctp_nsaddrs) {
5997c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_EQUAL);
6007c478bd9Sstevel@tonic-gate 	}
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	if (overlap == sctp1->sctp_nsaddrs)
6037c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_SUBSET);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (overlap > 0)
6067c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_OVERLAP);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	return (SCTP_ADDR_DISJOINT);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate static int
6127c478bd9Sstevel@tonic-gate sctp_copy_ipifs(sctp_ipif_hash_t *list1, sctp_t *sctp2, int sleep)
6137c478bd9Sstevel@tonic-gate {
6147c478bd9Sstevel@tonic-gate 	int			i;
6157c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6167c478bd9Sstevel@tonic-gate 	int			error = 0;
6177c478bd9Sstevel@tonic-gate 
618*92baa190SGeorge Shepherd 	rw_enter(&list1->ipif_hash_lock, RW_READER);
6197c478bd9Sstevel@tonic-gate 	obj = list_head(&list1->sctp_ipif_list);
6207c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
6217c478bd9Sstevel@tonic-gate 		SCTP_IPIF_REFHOLD(obj->saddr_ipifp);
622f551bb10Svi 		error = sctp_ipif_hash_insert(sctp2, obj->saddr_ipifp, sleep,
623e35d2278Svi 		    B_FALSE, B_FALSE);
624e35d2278Svi 		ASSERT(error != EALREADY);
625*92baa190SGeorge Shepherd 		if (error != 0) {
626*92baa190SGeorge Shepherd 			rw_exit(&list1->ipif_hash_lock);
6277c478bd9Sstevel@tonic-gate 			return (error);
628*92baa190SGeorge Shepherd 		}
6297c478bd9Sstevel@tonic-gate 		obj = list_next(&list1->sctp_ipif_list, obj);
6307c478bd9Sstevel@tonic-gate 	}
631*92baa190SGeorge Shepherd 	rw_exit(&list1->ipif_hash_lock);
6327c478bd9Sstevel@tonic-gate 	return (error);
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate int
6367c478bd9Sstevel@tonic-gate sctp_dup_saddrs(sctp_t *sctp1, sctp_t *sctp2, int sleep)
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	int	error = 0;
6397c478bd9Sstevel@tonic-gate 	int	i;
6407c478bd9Sstevel@tonic-gate 
641f551bb10Svi 	if (sctp1 == NULL || sctp1->sctp_bound_to_all == 1)
6427c478bd9Sstevel@tonic-gate 		return (sctp_get_all_ipifs(sctp2, sleep));
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
645*92baa190SGeorge Shepherd 		rw_enter(&sctp1->sctp_saddrs[i].ipif_hash_lock, RW_READER);
646*92baa190SGeorge Shepherd 		if (sctp1->sctp_saddrs[i].ipif_count == 0) {
647*92baa190SGeorge Shepherd 			rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6487c478bd9Sstevel@tonic-gate 			continue;
649*92baa190SGeorge Shepherd 		}
6507c478bd9Sstevel@tonic-gate 		error = sctp_copy_ipifs(&sctp1->sctp_saddrs[i], sctp2, sleep);
6517c478bd9Sstevel@tonic-gate 		if (error != 0) {
652*92baa190SGeorge Shepherd 			rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6537c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp2);
6547c478bd9Sstevel@tonic-gate 			return (error);
6557c478bd9Sstevel@tonic-gate 		}
656*92baa190SGeorge Shepherd 		rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 	return (0);
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate void
6627c478bd9Sstevel@tonic-gate sctp_free_saddrs(sctp_t *sctp)
6637c478bd9Sstevel@tonic-gate {
6647c478bd9Sstevel@tonic-gate 	int			i;
6657c478bd9Sstevel@tonic-gate 	int			l;
6667c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
6697c478bd9Sstevel@tonic-gate 		return;
6707c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
671*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
672*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
673*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6747c478bd9Sstevel@tonic-gate 			continue;
675*92baa190SGeorge Shepherd 		}
6767c478bd9Sstevel@tonic-gate 		obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6777c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
6787c478bd9Sstevel@tonic-gate 			list_remove(&sctp->sctp_saddrs[i].sctp_ipif_list, obj);
6797c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(obj->saddr_ipifp);
6807c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
6817c478bd9Sstevel@tonic-gate 			kmem_free(obj, sizeof (sctp_saddr_ipif_t));
6827c478bd9Sstevel@tonic-gate 			obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 		sctp->sctp_saddrs[i].ipif_count = 0;
685*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6867c478bd9Sstevel@tonic-gate 	}
687f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
688f551bb10Svi 		sctp->sctp_bound_to_all = 0;
6897c478bd9Sstevel@tonic-gate 	ASSERT(sctp->sctp_nsaddrs == 0);
6907c478bd9Sstevel@tonic-gate }
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate /*
6937c478bd9Sstevel@tonic-gate  * Add/Delete the given ILL from the SCTP ILL list. Called with no locks
6947c478bd9Sstevel@tonic-gate  * held.
6957c478bd9Sstevel@tonic-gate  */
6967c478bd9Sstevel@tonic-gate void
6977c478bd9Sstevel@tonic-gate sctp_update_ill(ill_t *ill, int op)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	int		i;
7007c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill = NULL;
7017c478bd9Sstevel@tonic-gate 	uint_t		index;
702f4b3ec61Sdh 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
703f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
7047c478bd9Sstevel@tonic-gate 
705f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
708f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
709f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
7101d19ca10Svi 		if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
7111d19ca10Svi 		    (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
7127c478bd9Sstevel@tonic-gate 			break;
7131d19ca10Svi 		}
714f4b3ec61Sdh 		sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
7157c478bd9Sstevel@tonic-gate 		    sctp_ill);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	switch (op) {
7197c478bd9Sstevel@tonic-gate 	case SCTP_ILL_INSERT:
7207c478bd9Sstevel@tonic-gate 		if (sctp_ill != NULL) {
7217c478bd9Sstevel@tonic-gate 			/* Unmark it if it is condemned */
7227c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED)
7237c478bd9Sstevel@tonic-gate 				sctp_ill->sctp_ill_state = 0;
724f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7257c478bd9Sstevel@tonic-gate 			return;
7267c478bd9Sstevel@tonic-gate 		}
7277c478bd9Sstevel@tonic-gate 		sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
7287c478bd9Sstevel@tonic-gate 		/* Need to re-try? */
7297c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
7301d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7311d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
732f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7337c478bd9Sstevel@tonic-gate 			return;
7347c478bd9Sstevel@tonic-gate 		}
735e35d2278Svi 		sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
736e35d2278Svi 		    KM_NOSLEEP);
7377c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_name == NULL) {
7381d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7391d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
7407c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
741f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7427c478bd9Sstevel@tonic-gate 			return;
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 		bcopy(ill->ill_name, sctp_ill->sctp_ill_name,
7457c478bd9Sstevel@tonic-gate 		    ill->ill_name_length);
7467c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_name_length = ill->ill_name_length;
7477c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
7487c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
749f4b3ec61Sdh 		sctp_ill->sctp_ill_netstack = ns;	/* No netstack_hold */
7501d19ca10Svi 		sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
751f4b3ec61Sdh 		list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
7527c478bd9Sstevel@tonic-gate 		    (void *)sctp_ill);
753f4b3ec61Sdh 		sctps->sctps_g_ills[index].ill_count++;
754f4b3ec61Sdh 		sctps->sctps_ills_count++;
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		break;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	case SCTP_ILL_REMOVE:
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
761f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7627c478bd9Sstevel@tonic-gate 			return;
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0) {
765f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[index].sctp_ill_list,
7667c478bd9Sstevel@tonic-gate 			    (void *)sctp_ill);
767f4b3ec61Sdh 			sctps->sctps_g_ills[index].ill_count--;
768f4b3ec61Sdh 			sctps->sctps_ills_count--;
7697c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
7707c478bd9Sstevel@tonic-gate 			    ill->ill_name_length);
7717c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
7727c478bd9Sstevel@tonic-gate 		} else {
7737c478bd9Sstevel@tonic-gate 			sctp_ill->sctp_ill_state = SCTP_ILLS_CONDEMNED;
7747c478bd9Sstevel@tonic-gate 		}
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 		break;
7777c478bd9Sstevel@tonic-gate 	}
778f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate 
7811d19ca10Svi /*
7821d19ca10Svi  * The ILL's index is being changed, just remove it from the old list,
7831d19ca10Svi  * change the SCTP ILL's index and re-insert using the new index.
7841d19ca10Svi  */
7851d19ca10Svi void
7861d19ca10Svi sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
7871d19ca10Svi {
7881d19ca10Svi 	sctp_ill_t	*sctp_ill = NULL;
7891d19ca10Svi 	sctp_ill_t	*nxt_sill;
7901d19ca10Svi 	uint_t		indx;
7911d19ca10Svi 	uint_t		nindx;
7921d19ca10Svi 	boolean_t	once = B_FALSE;
7931d19ca10Svi 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
7941d19ca10Svi 	sctp_stack_t	*sctps = ns->netstack_sctp;
7951d19ca10Svi 
7961d19ca10Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7971d19ca10Svi 
7981d19ca10Svi 	indx = SCTP_ILL_HASH_FN(orig_ill_index);
7991d19ca10Svi 	nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
8001d19ca10Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
8011d19ca10Svi 	while (sctp_ill != NULL) {
8021d19ca10Svi 		nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
8031d19ca10Svi 		    sctp_ill);
8041d19ca10Svi 		if (sctp_ill->sctp_ill_index == orig_ill_index) {
8051d19ca10Svi 			sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
8061d19ca10Svi 			/*
8071d19ca10Svi 			 * if the new index hashes to the same value, all's
8081d19ca10Svi 			 * done.
8091d19ca10Svi 			 */
8101d19ca10Svi 			if (nindx != indx) {
8111d19ca10Svi 				list_remove(
8121d19ca10Svi 				    &sctps->sctps_g_ills[indx].sctp_ill_list,
8131d19ca10Svi 				    (void *)sctp_ill);
8141d19ca10Svi 				sctps->sctps_g_ills[indx].ill_count--;
8151d19ca10Svi 				list_insert_tail(
8161d19ca10Svi 				    &sctps->sctps_g_ills[nindx].sctp_ill_list,
8171d19ca10Svi 				    (void *)sctp_ill);
8181d19ca10Svi 				sctps->sctps_g_ills[nindx].ill_count++;
8191d19ca10Svi 			}
8201d19ca10Svi 			if (once)
8211d19ca10Svi 				break;
8221d19ca10Svi 			/* We might have one for v4 and for v6 */
8231d19ca10Svi 			once = B_TRUE;
8241d19ca10Svi 		}
8251d19ca10Svi 		sctp_ill = nxt_sill;
8261d19ca10Svi 	}
8271d19ca10Svi 	rw_exit(&sctps->sctps_g_ills_lock);
8281d19ca10Svi }
8291d19ca10Svi 
8307c478bd9Sstevel@tonic-gate /* move ipif from f_ill to t_ill */
8317c478bd9Sstevel@tonic-gate void
8327c478bd9Sstevel@tonic-gate sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
8337c478bd9Sstevel@tonic-gate {
8347c478bd9Sstevel@tonic-gate 	sctp_ill_t	*fsctp_ill = NULL;
8357c478bd9Sstevel@tonic-gate 	sctp_ill_t	*tsctp_ill = NULL;
8367c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
837e35d2278Svi 	uint_t		hindex;
8387c478bd9Sstevel@tonic-gate 	int		i;
839f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
840f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
8417c478bd9Sstevel@tonic-gate 
842f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
843f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
8447c478bd9Sstevel@tonic-gate 
845e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
846e35d2278Svi 	fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
847e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8481d19ca10Svi 		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
8491d19ca10Svi 		    fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
8507c478bd9Sstevel@tonic-gate 			break;
8511d19ca10Svi 		}
852e35d2278Svi 		fsctp_ill = list_next(
853e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
856e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
857e35d2278Svi 	tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
858e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8591d19ca10Svi 		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
8601d19ca10Svi 		    tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
8617c478bd9Sstevel@tonic-gate 			break;
8621d19ca10Svi 		}
863e35d2278Svi 		tsctp_ill = list_next(
864e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
8657c478bd9Sstevel@tonic-gate 	}
8667c478bd9Sstevel@tonic-gate 
867e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
868e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
869e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
870e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
8717c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid)
8727c478bd9Sstevel@tonic-gate 			break;
873f4b3ec61Sdh 		sctp_ipif = list_next(
874e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 	/* Should be an ASSERT? */
8777c478bd9Sstevel@tonic-gate 	if (fsctp_ill == NULL || tsctp_ill == NULL || sctp_ipif == NULL) {
8787c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_move_ipif: error moving ipif %p from %p to %p\n",
8797c478bd9Sstevel@tonic-gate 		    (void *)ipif, (void *)f_ill, (void *)t_ill));
880f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
881f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
8827c478bd9Sstevel@tonic-gate 		return;
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 	rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
8857c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ipif->sctp_ipif_ill == fsctp_ill);
8867c478bd9Sstevel@tonic-gate 	sctp_ipif->sctp_ipif_ill = tsctp_ill;
8877c478bd9Sstevel@tonic-gate 	rw_exit(&sctp_ipif->sctp_ipif_lock);
8887c478bd9Sstevel@tonic-gate 	(void) atomic_add_32_nv(&fsctp_ill->sctp_ill_ipifcnt, -1);
8897c478bd9Sstevel@tonic-gate 	atomic_add_32(&tsctp_ill->sctp_ill_ipifcnt, 1);
890f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
891f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
8927c478bd9Sstevel@tonic-gate }
8937c478bd9Sstevel@tonic-gate 
894e35d2278Svi /*
895e35d2278Svi  * Walk the list of SCTPs and find each that has oipif in it's saddr list, and
896e35d2278Svi  * if so replace it with nipif.
897e35d2278Svi  */
898e35d2278Svi void
899e35d2278Svi sctp_update_saddrs(sctp_ipif_t *oipif, sctp_ipif_t *nipif, int idx,
900e35d2278Svi     sctp_stack_t *sctps)
901e35d2278Svi {
902e35d2278Svi 	sctp_t			*sctp;
903e35d2278Svi 	sctp_t			*sctp_prev = NULL;
904e35d2278Svi 	sctp_saddr_ipif_t	*sobj;
905e35d2278Svi 	int			count;
906e35d2278Svi 
907e35d2278Svi 	mutex_enter(&sctps->sctps_g_lock);
908bd670b35SErik Nordmark 	sctp = list_head(&sctps->sctps_g_list);
909e35d2278Svi 	while (sctp != NULL && oipif->sctp_ipif_refcnt > 0) {
910e35d2278Svi 		mutex_enter(&sctp->sctp_reflock);
911e35d2278Svi 		if (sctp->sctp_condemned ||
912e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count <= 0) {
913e35d2278Svi 			mutex_exit(&sctp->sctp_reflock);
914e35d2278Svi 			sctp = list_next(&sctps->sctps_g_list, sctp);
915e35d2278Svi 			continue;
916e35d2278Svi 		}
917e35d2278Svi 		sctp->sctp_refcnt++;
918e35d2278Svi 		mutex_exit(&sctp->sctp_reflock);
919e35d2278Svi 		mutex_exit(&sctps->sctps_g_lock);
920e35d2278Svi 		if (sctp_prev != NULL)
921e35d2278Svi 			SCTP_REFRELE(sctp_prev);
922e35d2278Svi 
923e35d2278Svi 		RUN_SCTP(sctp);
924e35d2278Svi 		sobj = list_head(&sctp->sctp_saddrs[idx].sctp_ipif_list);
925e35d2278Svi 		for (count = 0; count <
926e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count; count++) {
927e35d2278Svi 			if (sobj->saddr_ipifp == oipif) {
928e35d2278Svi 				SCTP_IPIF_REFHOLD(nipif);
929e35d2278Svi 				sobj->saddr_ipifp = nipif;
930e35d2278Svi 				ASSERT(oipif->sctp_ipif_refcnt > 0);
931e35d2278Svi 				/* We have the writer lock */
932e35d2278Svi 				oipif->sctp_ipif_refcnt--;
933e35d2278Svi 				/*
934e35d2278Svi 				 * Can't have more than one referring
935e35d2278Svi 				 * to the same sctp_ipif.
936e35d2278Svi 				 */
937e35d2278Svi 				break;
938e35d2278Svi 			}
939e35d2278Svi 			sobj = list_next(&sctp->sctp_saddrs[idx].sctp_ipif_list,
940e35d2278Svi 			    sobj);
941e35d2278Svi 		}
942e35d2278Svi 		WAKE_SCTP(sctp);
943e35d2278Svi 		sctp_prev = sctp;
944e35d2278Svi 		mutex_enter(&sctps->sctps_g_lock);
945e35d2278Svi 		sctp = list_next(&sctps->sctps_g_list, sctp);
946e35d2278Svi 	}
947e35d2278Svi 	mutex_exit(&sctps->sctps_g_lock);
948e35d2278Svi 	if (sctp_prev != NULL)
949e35d2278Svi 		SCTP_REFRELE(sctp_prev);
950e35d2278Svi }
951e35d2278Svi 
952e35d2278Svi /*
953e35d2278Svi  * Given an ipif, walk the hash list in the global ipif table and for
954e35d2278Svi  * any other SCTP ipif with the same address and non-zero reference, walk
955e35d2278Svi  * the SCTP list and update the saddr list, if required, to point to the
956d0e58000SVenugopal Iyer  * new SCTP ipif. If it is a loopback interface, then there could be
957d0e58000SVenugopal Iyer  * multiple interfaces with 127.0.0.1 if there are zones configured, so
958d0e58000SVenugopal Iyer  * check the zoneid in addition to the address.
959e35d2278Svi  */
960e35d2278Svi void
961e35d2278Svi sctp_chk_and_updt_saddr(int hindex, sctp_ipif_t *ipif, sctp_stack_t *sctps)
962e35d2278Svi {
963e35d2278Svi 	int		cnt;
964e35d2278Svi 	sctp_ipif_t	*sipif;
965e35d2278Svi 
966e35d2278Svi 	ASSERT(sctps->sctps_g_ipifs[hindex].ipif_count > 0);
967e35d2278Svi 	ASSERT(ipif->sctp_ipif_state == SCTP_IPIFS_UP);
968e35d2278Svi 
969e35d2278Svi 	sipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
970e35d2278Svi 	for (cnt = 0; cnt < sctps->sctps_g_ipifs[hindex].ipif_count; cnt++) {
971e35d2278Svi 		rw_enter(&sipif->sctp_ipif_lock, RW_WRITER);
972e35d2278Svi 		if (sipif->sctp_ipif_id != ipif->sctp_ipif_id &&
973e35d2278Svi 		    IN6_ARE_ADDR_EQUAL(&sipif->sctp_ipif_saddr,
974d0e58000SVenugopal Iyer 		    &ipif->sctp_ipif_saddr) && sipif->sctp_ipif_refcnt > 0 &&
975d0e58000SVenugopal Iyer 		    (!SCTP_IS_IPIF_LOOPBACK(ipif) || ipif->sctp_ipif_zoneid ==
976d0e58000SVenugopal Iyer 		    sipif->sctp_ipif_zoneid)) {
977e35d2278Svi 			/*
978e35d2278Svi 			 * There can only be one address up at any time
979e35d2278Svi 			 * and we are here because ipif has been brought
980e35d2278Svi 			 * up.
981e35d2278Svi 			 */
982e35d2278Svi 			ASSERT(sipif->sctp_ipif_state != SCTP_IPIFS_UP);
983e35d2278Svi 			/*
984e35d2278Svi 			 * Someone has a reference to this we need to update to
985e35d2278Svi 			 * point to the new sipif.
986e35d2278Svi 			 */
987e35d2278Svi 			sctp_update_saddrs(sipif, ipif, hindex, sctps);
988e35d2278Svi 		}
989e35d2278Svi 		rw_exit(&sipif->sctp_ipif_lock);
990e35d2278Svi 		sipif = list_next(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
991e35d2278Svi 		    sipif);
992e35d2278Svi 	}
993e35d2278Svi }
994e35d2278Svi 
995e35d2278Svi /*
996e35d2278Svi  * Insert a new SCTP ipif using 'ipif'. v6addr is the address that existed
997e35d2278Svi  * prior to the current address in 'ipif'. Only when an existing address
998e35d2278Svi  * is changed on an IPIF, will v6addr be specified. If the IPIF already
999e35d2278Svi  * exists in the global SCTP ipif table, then we either removed it, if
1000e35d2278Svi  * it doesn't have any existing reference, or mark it condemned otherwise.
1001e35d2278Svi  * If an address is being brought up (IPIF_UP), then we need to scan
1002e35d2278Svi  * the SCTP list to check if there is any SCTP that points to the *same*
1003e35d2278Svi  * address on a different SCTP ipif and update in that case.
1004e35d2278Svi  */
1005e35d2278Svi void
1006e35d2278Svi sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
1007e35d2278Svi {
1008e35d2278Svi 	ill_t		*ill = ipif->ipif_ill;
1009e35d2278Svi 	int		i;
1010e35d2278Svi 	sctp_ill_t	*sctp_ill;
1011e35d2278Svi 	sctp_ill_t	*osctp_ill;
1012e35d2278Svi 	sctp_ipif_t	*sctp_ipif = NULL;
1013e35d2278Svi 	sctp_ipif_t	*osctp_ipif = NULL;
1014e35d2278Svi 	uint_t		ill_index;
1015e35d2278Svi 	int		hindex;
1016e35d2278Svi 	sctp_stack_t	*sctps;
1017e35d2278Svi 
1018e35d2278Svi 	sctps = ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp;
1019e35d2278Svi 
1020e35d2278Svi 	/* Index for new address */
1021e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr, ill->ill_isv6);
1022e35d2278Svi 
1023e35d2278Svi 	/*
1024e35d2278Svi 	 * The address on this IPIF is changing, we need to look for
1025e35d2278Svi 	 * this old address and mark it condemned, before creating
1026e35d2278Svi 	 * one for the new address.
1027e35d2278Svi 	 */
1028e35d2278Svi 	osctp_ipif = sctp_lookup_ipif_addr(&v6addr, B_FALSE,
1029e35d2278Svi 	    ipif->ipif_zoneid, B_TRUE, SCTP_ILL_TO_PHYINDEX(ill),
1030e35d2278Svi 	    ipif->ipif_seqid, B_FALSE, sctps);
1031e35d2278Svi 
1032e35d2278Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1033e35d2278Svi 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1034e35d2278Svi 
1035e35d2278Svi 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1036e35d2278Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1037e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
10381d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
10391d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
1040e35d2278Svi 			break;
10411d19ca10Svi 		}
1042e35d2278Svi 		sctp_ill = list_next(
1043e35d2278Svi 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
1044e35d2278Svi 	}
1045e35d2278Svi 
1046e35d2278Svi 	if (sctp_ill == NULL) {
10471d19ca10Svi 		ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
1048e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1049e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
10501d19ca10Svi 		return;
1051e35d2278Svi 	}
1052e35d2278Svi 
1053e35d2278Svi 	if (osctp_ipif != NULL) {
1054e35d2278Svi 
1055e35d2278Svi 		/* The address is the same? */
1056e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &v6addr)) {
1057e35d2278Svi 			boolean_t	chk_n_updt = B_FALSE;
1058e35d2278Svi 
1059e35d2278Svi 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
1060e35d2278Svi 			rw_enter(&osctp_ipif->sctp_ipif_lock, RW_WRITER);
1061e35d2278Svi 			if (ipif->ipif_flags & IPIF_UP &&
1062e35d2278Svi 			    osctp_ipif->sctp_ipif_state != SCTP_IPIFS_UP) {
1063e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1064e35d2278Svi 				chk_n_updt = B_TRUE;
1065e35d2278Svi 			} else {
1066e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1067e35d2278Svi 			}
1068e35d2278Svi 			osctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1069e35d2278Svi 			rw_exit(&osctp_ipif->sctp_ipif_lock);
1070e35d2278Svi 			if (chk_n_updt) {
1071e35d2278Svi 				sctp_chk_and_updt_saddr(hindex, osctp_ipif,
1072e35d2278Svi 				    sctps);
1073e35d2278Svi 			}
1074e35d2278Svi 			rw_exit(&sctps->sctps_g_ipifs_lock);
1075e35d2278Svi 			rw_exit(&sctps->sctps_g_ills_lock);
1076e35d2278Svi 			return;
1077e35d2278Svi 		}
1078e35d2278Svi 		/*
1079e35d2278Svi 		 * We are effectively removing this address from the ILL.
1080e35d2278Svi 		 */
1081e35d2278Svi 		if (osctp_ipif->sctp_ipif_refcnt != 0) {
1082e35d2278Svi 			osctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1083e35d2278Svi 		} else {
1084e35d2278Svi 			list_t		*ipif_list;
1085e35d2278Svi 			int		ohindex;
1086e35d2278Svi 
1087e35d2278Svi 			osctp_ill = osctp_ipif->sctp_ipif_ill;
1088e35d2278Svi 			/* hash index for the old one */
1089e35d2278Svi 			ohindex = SCTP_IPIF_ADDR_HASH(
1090e35d2278Svi 			    osctp_ipif->sctp_ipif_saddr,
1091e35d2278Svi 			    osctp_ipif->sctp_ipif_isv6);
1092e35d2278Svi 
1093e35d2278Svi 			ipif_list =
1094e35d2278Svi 			    &sctps->sctps_g_ipifs[ohindex].sctp_ipif_list;
1095e35d2278Svi 
1096e35d2278Svi 			list_remove(ipif_list, (void *)osctp_ipif);
1097e35d2278Svi 			sctps->sctps_g_ipifs[ohindex].ipif_count--;
1098e35d2278Svi 			sctps->sctps_g_ipifs_count--;
1099e35d2278Svi 			rw_destroy(&osctp_ipif->sctp_ipif_lock);
1100e35d2278Svi 			kmem_free(osctp_ipif, sizeof (sctp_ipif_t));
1101e35d2278Svi 			(void) atomic_add_32_nv(&osctp_ill->sctp_ill_ipifcnt,
1102e35d2278Svi 			    -1);
1103e35d2278Svi 		}
1104e35d2278Svi 	}
1105e35d2278Svi 
1106e35d2278Svi 	sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
1107e35d2278Svi 	/* Try again? */
1108e35d2278Svi 	if (sctp_ipif == NULL) {
11091d19ca10Svi 		cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
11101d19ca10Svi 		    "IPIF %p to SCTP's IPIF list", (void *)ipif);
1111e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1112e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
1113e35d2278Svi 		return;
1114e35d2278Svi 	}
1115e35d2278Svi 	sctps->sctps_g_ipifs_count++;
1116e35d2278Svi 	rw_init(&sctp_ipif->sctp_ipif_lock, NULL, RW_DEFAULT, NULL);
1117e35d2278Svi 	sctp_ipif->sctp_ipif_saddr = ipif->ipif_v6lcl_addr;
1118e35d2278Svi 	sctp_ipif->sctp_ipif_ill = sctp_ill;
1119e35d2278Svi 	sctp_ipif->sctp_ipif_isv6 = ill->ill_isv6;
1120e35d2278Svi 	sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1121e35d2278Svi 	sctp_ipif->sctp_ipif_id = ipif->ipif_seqid;
1122e35d2278Svi 	if (ipif->ipif_flags & IPIF_UP)
1123e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1124e35d2278Svi 	else
1125e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1126e35d2278Svi 	sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1127e35d2278Svi 	/*
1128e35d2278Svi 	 * We add it to the head so that it is quicker to find good/recent
1129e35d2278Svi 	 * additions.
1130e35d2278Svi 	 */
1131e35d2278Svi 	list_insert_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
1132e35d2278Svi 	    (void *)sctp_ipif);
1133e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count++;
1134e35d2278Svi 	atomic_add_32(&sctp_ill->sctp_ill_ipifcnt, 1);
1135e35d2278Svi 	if (sctp_ipif->sctp_ipif_state == SCTP_IPIFS_UP)
1136e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif, sctps);
1137e35d2278Svi 	rw_exit(&sctps->sctps_g_ipifs_lock);
1138e35d2278Svi 	rw_exit(&sctps->sctps_g_ills_lock);
1139e35d2278Svi }
1140e35d2278Svi 
11417c478bd9Sstevel@tonic-gate /* Insert, Remove,  Mark up or Mark down the ipif */
11427c478bd9Sstevel@tonic-gate void
11437c478bd9Sstevel@tonic-gate sctp_update_ipif(ipif_t *ipif, int op)
11447c478bd9Sstevel@tonic-gate {
11457c478bd9Sstevel@tonic-gate 	ill_t		*ill = ipif->ipif_ill;
11467c478bd9Sstevel@tonic-gate 	int		i;
11477c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
11487c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
11497c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
1150e35d2278Svi 	uint_t		hindex;
1151f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
1152f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	ip2dbg(("sctp_update_ipif: %s %d\n", ill->ill_name, ipif->ipif_seqid));
11557c478bd9Sstevel@tonic-gate 
1156f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1157f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1160f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1161f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
11621d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
11631d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
11647c478bd9Sstevel@tonic-gate 			break;
11651d19ca10Svi 		}
1166f4b3ec61Sdh 		sctp_ill = list_next(
1167f4b3ec61Sdh 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
11687c478bd9Sstevel@tonic-gate 	}
11697c478bd9Sstevel@tonic-gate 	if (sctp_ill == NULL) {
1170f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1171f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11727c478bd9Sstevel@tonic-gate 		return;
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
1175e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
1176e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
1177e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
1178e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
1179e35d2278Svi 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid) {
1180e35d2278Svi 			ASSERT(IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
1181e35d2278Svi 			    &ipif->ipif_v6lcl_addr));
11827c478bd9Sstevel@tonic-gate 			break;
1183e35d2278Svi 		}
1184f4b3ec61Sdh 		sctp_ipif = list_next(
1185e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11867c478bd9Sstevel@tonic-gate 		    sctp_ipif);
11877c478bd9Sstevel@tonic-gate 	}
1188e35d2278Svi 	if (sctp_ipif == NULL) {
11897c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_update_ipif: null sctp_ipif for %d\n", op));
1190f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1191f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11927c478bd9Sstevel@tonic-gate 		return;
11937c478bd9Sstevel@tonic-gate 	}
1194e35d2278Svi 	ASSERT(sctp_ill == sctp_ipif->sctp_ipif_ill);
11957c478bd9Sstevel@tonic-gate 	switch (op) {
11967c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_REMOVE:
11977c478bd9Sstevel@tonic-gate 	{
11987c478bd9Sstevel@tonic-gate 		list_t		*ipif_list;
11997c478bd9Sstevel@tonic-gate 		list_t		*ill_list;
12007c478bd9Sstevel@tonic-gate 
1201f4b3ec61Sdh 		ill_list = &sctps->sctps_g_ills[ill_index].sctp_ill_list;
1202e35d2278Svi 		ipif_list = &sctps->sctps_g_ipifs[hindex].sctp_ipif_list;
12037c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_refcnt != 0) {
12047c478bd9Sstevel@tonic-gate 			sctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1205f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ipifs_lock);
1206f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
12077c478bd9Sstevel@tonic-gate 			return;
12087c478bd9Sstevel@tonic-gate 		}
12097c478bd9Sstevel@tonic-gate 		list_remove(ipif_list, (void *)sctp_ipif);
1210e35d2278Svi 		sctps->sctps_g_ipifs[hindex].ipif_count--;
1211f4b3ec61Sdh 		sctps->sctps_g_ipifs_count--;
12127c478bd9Sstevel@tonic-gate 		rw_destroy(&sctp_ipif->sctp_ipif_lock);
12137c478bd9Sstevel@tonic-gate 		kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
12147c478bd9Sstevel@tonic-gate 		(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
1215f4b3ec61Sdh 		if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
1216f4b3ec61Sdh 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
12177c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_ipifcnt == 0 &&
12187c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
12197c478bd9Sstevel@tonic-gate 				list_remove(ill_list, (void *)sctp_ill);
1220f4b3ec61Sdh 				sctps->sctps_ills_count--;
1221f4b3ec61Sdh 				sctps->sctps_g_ills[ill_index].ill_count--;
12227c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill->sctp_ill_name,
12237c478bd9Sstevel@tonic-gate 				    sctp_ill->sctp_ill_name_length);
12247c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill, sizeof (sctp_ill_t));
12257c478bd9Sstevel@tonic-gate 			}
12267c478bd9Sstevel@tonic-gate 		}
12277c478bd9Sstevel@tonic-gate 		break;
12287c478bd9Sstevel@tonic-gate 	}
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UP:
12317c478bd9Sstevel@tonic-gate 
1232f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12337c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12347c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1235e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12367c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
1237e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif,
1238e35d2278Svi 		    ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp);
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 		break;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UPDATE:
12437c478bd9Sstevel@tonic-gate 
1244f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12457c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12467c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1247f551bb10Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12487c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 		break;
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_DOWN:
12537c478bd9Sstevel@tonic-gate 
1254f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12557c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12567c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1257e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12587c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 		break;
12617c478bd9Sstevel@tonic-gate 	}
1262f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
1263f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate /*
12677c478bd9Sstevel@tonic-gate  * SCTP source address list manipulaton, locking not used (except for
12687c478bd9Sstevel@tonic-gate  * sctp locking by the caller.
12697c478bd9Sstevel@tonic-gate  */
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /* Remove a specific saddr from the list */
12727c478bd9Sstevel@tonic-gate void
12737c478bd9Sstevel@tonic-gate sctp_del_saddr(sctp_t *sctp, sctp_saddr_ipif_t *sp)
12747c478bd9Sstevel@tonic-gate {
12757c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12767c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12797c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12807c478bd9Sstevel@tonic-gate 
1281*92baa190SGeorge Shepherd 	sctp_ipif_hash_remove(sctp, sp->saddr_ipifp, B_FALSE);
12827c478bd9Sstevel@tonic-gate 
1283f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
12847c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12877c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12907c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate /*
12947c478bd9Sstevel@tonic-gate  * Delete source address from the existing list. No error checking done here
12957c478bd9Sstevel@tonic-gate  * Called with no locks held.
12967c478bd9Sstevel@tonic-gate  */
12977c478bd9Sstevel@tonic-gate void
12987c478bd9Sstevel@tonic-gate sctp_del_saddr_list(sctp_t *sctp, const void *addrs, int addcnt,
12997c478bd9Sstevel@tonic-gate     boolean_t fanout_locked)
13007c478bd9Sstevel@tonic-gate {
13017c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
13027c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
13037c478bd9Sstevel@tonic-gate 	int			cnt;
13047c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
13057c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13061d8c4025Svi 	int			ifindex = 0;
1307bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
13087c478bd9Sstevel@tonic-gate 
13091d8c4025Svi 	ASSERT(sctp->sctp_nsaddrs >= addcnt);
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
13127c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
13137c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
13147c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
13157c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addcnt; cnt++) {
1319bd670b35SErik Nordmark 		switch (connp->conn_family) {
13207c478bd9Sstevel@tonic-gate 		case AF_INET:
13217c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
13227c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &addr);
13237c478bd9Sstevel@tonic-gate 			break;
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		case AF_INET6:
13267c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
13277c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
13281d8c4025Svi 			ifindex = sin6->sin6_scope_id;
13297c478bd9Sstevel@tonic-gate 			break;
13307c478bd9Sstevel@tonic-gate 		}
1331e35d2278Svi 		sctp_ipif = sctp_lookup_ipif_addr(&addr, B_FALSE,
1332bd670b35SErik Nordmark 		    IPCL_ZONEID(connp), !connp->conn_allzones,
1333e35d2278Svi 		    ifindex, 0, B_TRUE, sctp->sctp_sctps);
13347c478bd9Sstevel@tonic-gate 		ASSERT(sctp_ipif != NULL);
1335*92baa190SGeorge Shepherd 		sctp_ipif_hash_remove(sctp, sctp_ipif, B_FALSE);
13367c478bd9Sstevel@tonic-gate 	}
1337f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
13387c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
13417c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
13427c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
13437c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
13447c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate /*
13497c478bd9Sstevel@tonic-gate  * Given an address get the corresponding entry from the list
13507c478bd9Sstevel@tonic-gate  * Called with no locks held.
13517c478bd9Sstevel@tonic-gate  */
13527c478bd9Sstevel@tonic-gate sctp_saddr_ipif_t *
13531d8c4025Svi sctp_saddr_lookup(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
13547c478bd9Sstevel@tonic-gate {
1355e35d2278Svi 	int			cnt;
1356e35d2278Svi 	sctp_saddr_ipif_t	*ipif_obj;
1357e35d2278Svi 	int			hindex;
13587c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13597c478bd9Sstevel@tonic-gate 
1360e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1361*92baa190SGeorge Shepherd 	rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_READER);
1362*92baa190SGeorge Shepherd 	if (sctp->sctp_saddrs[hindex].ipif_count == 0) {
1363*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
13647c478bd9Sstevel@tonic-gate 		return (NULL);
1365*92baa190SGeorge Shepherd 	}
13667c478bd9Sstevel@tonic-gate 
1367e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
1368e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
1369e35d2278Svi 		sctp_ipif = ipif_obj->saddr_ipifp;
1370e35d2278Svi 		/*
1371e35d2278Svi 		 * Zone check shouldn't be needed.
1372e35d2278Svi 		 */
1373e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(addr, &sctp_ipif->sctp_ipif_saddr) &&
1374e35d2278Svi 		    (ifindex == 0 ||
1375e35d2278Svi 		    ifindex == sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
1376e35d2278Svi 		    SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state)) {
1377*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
1378e35d2278Svi 			return (ipif_obj);
1379e35d2278Svi 		}
1380e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
1381e35d2278Svi 		    ipif_obj);
1382e35d2278Svi 	}
1383*92baa190SGeorge Shepherd 	rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
1384e35d2278Svi 	return (NULL);
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate 
1387f551bb10Svi /* Given an address, add it to the source address list */
1388f551bb10Svi int
13891d8c4025Svi sctp_saddr_add_addr(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
1390f551bb10Svi {
1391f551bb10Svi 	sctp_ipif_t		*sctp_ipif;
1392bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1393f551bb10Svi 
1394bd670b35SErik Nordmark 	sctp_ipif = sctp_lookup_ipif_addr(addr, B_TRUE, IPCL_ZONEID(connp),
1395bd670b35SErik Nordmark 	    !connp->conn_allzones, ifindex, 0, B_TRUE, sctp->sctp_sctps);
1396f551bb10Svi 	if (sctp_ipif == NULL)
1397f551bb10Svi 		return (EINVAL);
1398f551bb10Svi 
1399e35d2278Svi 	if (sctp_ipif_hash_insert(sctp, sctp_ipif, KM_NOSLEEP, B_FALSE,
1400e35d2278Svi 	    B_FALSE) != 0) {
1401f551bb10Svi 		SCTP_IPIF_REFRELE(sctp_ipif);
1402f551bb10Svi 		return (EINVAL);
1403f551bb10Svi 	}
1404f551bb10Svi 	return (0);
1405f551bb10Svi }
1406f551bb10Svi 
1407f551bb10Svi /*
1408f551bb10Svi  * Remove or mark as dontsrc addresses that are currently not part of the
1409f551bb10Svi  * association. One would delete addresses when processing an INIT and
1410f551bb10Svi  * mark as dontsrc when processing an INIT-ACK.
1411f551bb10Svi  */
1412f551bb10Svi void
1413c31292eeSkcpoon sctp_check_saddr(sctp_t *sctp, int supp_af, boolean_t delete,
1414c31292eeSkcpoon     in6_addr_t *no_del_addr)
1415f551bb10Svi {
1416f551bb10Svi 	int			i;
1417f551bb10Svi 	int			l;
1418f551bb10Svi 	sctp_saddr_ipif_t	*obj;
1419f551bb10Svi 	int			scanned = 0;
1420f551bb10Svi 	int			naddr;
1421f551bb10Svi 	int			nsaddr;
1422bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1423f551bb10Svi 
1424f551bb10Svi 	ASSERT(!sctp->sctp_loopback && !sctp->sctp_linklocal && supp_af != 0);
1425f551bb10Svi 
1426f551bb10Svi 	/*
1427f551bb10Svi 	 * Irregardless of the supported address in the INIT, v4
1428f551bb10Svi 	 * must be supported.
1429f551bb10Svi 	 */
1430bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET)
1431f551bb10Svi 		supp_af = PARM_SUPP_V4;
1432f551bb10Svi 
1433f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
1434f551bb10Svi 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1435*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
1436*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
1437*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1438f551bb10Svi 			continue;
1439*92baa190SGeorge Shepherd 		}
1440f551bb10Svi 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1441f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1442f551bb10Svi 		for (l = 0; l < naddr; l++) {
1443f551bb10Svi 			sctp_ipif_t	*ipif;
1444f551bb10Svi 
1445f551bb10Svi 			ipif = obj->saddr_ipifp;
1446f551bb10Svi 			scanned++;
1447f551bb10Svi 
1448c31292eeSkcpoon 			if (IN6_ARE_ADDR_EQUAL(&ipif->sctp_ipif_saddr,
1449c31292eeSkcpoon 			    no_del_addr)) {
1450c31292eeSkcpoon 				goto next_obj;
1451c31292eeSkcpoon 			}
1452c31292eeSkcpoon 
1453f551bb10Svi 			/*
1454f551bb10Svi 			 * Delete/mark dontsrc loopback/linklocal addresses and
1455f551bb10Svi 			 * unsupported address.
14561d8c4025Svi 			 * On a clustered node, we trust the clustering module
14571d8c4025Svi 			 * to do the right thing w.r.t loopback addresses, so
14581d8c4025Svi 			 * we ignore loopback addresses in this check.
1459f551bb10Svi 			 */
14601d8c4025Svi 			if ((SCTP_IS_IPIF_LOOPBACK(ipif) &&
14611d8c4025Svi 			    cl_sctp_check_addrs == NULL) ||
14621d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(ipif) ||
1463f551bb10Svi 			    SCTP_UNSUPP_AF(ipif, supp_af)) {
1464f551bb10Svi 				if (!delete) {
1465f551bb10Svi 					obj->saddr_ipif_unconfirmed = 1;
1466f551bb10Svi 					goto next_obj;
1467f551bb10Svi 				}
1468f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1469f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1470f551bb10Svi 				if (scanned < nsaddr) {
1471f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1472f551bb10Svi 					    sctp_ipif_list, obj);
1473*92baa190SGeorge Shepherd 					sctp_ipif_hash_remove(sctp, ipif,
1474*92baa190SGeorge Shepherd 					    B_TRUE);
1475f551bb10Svi 					continue;
1476f551bb10Svi 				}
1477*92baa190SGeorge Shepherd 				sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
1478f551bb10Svi 			}
1479f551bb10Svi 	next_obj:
1480*92baa190SGeorge Shepherd 			if (scanned >= nsaddr) {
1481*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1482f551bb10Svi 				return;
1483*92baa190SGeorge Shepherd 			}
1484f551bb10Svi 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
1485f551bb10Svi 			    obj);
1486f551bb10Svi 		}
1487*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1488f551bb10Svi 	}
1489f551bb10Svi }
1490f551bb10Svi 
1491f551bb10Svi 
14927c478bd9Sstevel@tonic-gate /* Get the first valid address from the list. Called with no locks held */
14937c478bd9Sstevel@tonic-gate in6_addr_t
1494c31292eeSkcpoon sctp_get_valid_addr(sctp_t *sctp, boolean_t isv6, boolean_t *addr_set)
14957c478bd9Sstevel@tonic-gate {
14967c478bd9Sstevel@tonic-gate 	int			i;
14977c478bd9Sstevel@tonic-gate 	int			l;
14987c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
14997c478bd9Sstevel@tonic-gate 	int			scanned = 0;
15007c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1503*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
1504*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
1505*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15067c478bd9Sstevel@tonic-gate 			continue;
1507*92baa190SGeorge Shepherd 		}
15087c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15097c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15107c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
1513f551bb10Svi 			if (!SCTP_DONT_SRC(obj) &&
15147c478bd9Sstevel@tonic-gate 			    ipif->sctp_ipif_isv6 == isv6 &&
1515f551bb10Svi 			    ipif->sctp_ipif_state == SCTP_IPIFS_UP) {
1516c31292eeSkcpoon 				*addr_set = B_TRUE;
1517*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15187c478bd9Sstevel@tonic-gate 				return (ipif->sctp_ipif_saddr);
15197c478bd9Sstevel@tonic-gate 			}
15207c478bd9Sstevel@tonic-gate 			scanned++;
1521*92baa190SGeorge Shepherd 			if (scanned >= sctp->sctp_nsaddrs) {
1522*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15237c478bd9Sstevel@tonic-gate 				goto got_none;
1524*92baa190SGeorge Shepherd 			}
15257c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
15267c478bd9Sstevel@tonic-gate 			    obj);
15277c478bd9Sstevel@tonic-gate 		}
1528*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15297c478bd9Sstevel@tonic-gate 	}
15307c478bd9Sstevel@tonic-gate got_none:
15317c478bd9Sstevel@tonic-gate 	/* Need to double check this */
15327c478bd9Sstevel@tonic-gate 	if (isv6 == B_TRUE)
15337c478bd9Sstevel@tonic-gate 		addr =  ipv6_all_zeros;
15347c478bd9Sstevel@tonic-gate 	else
15357c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(0, &addr);
1536c31292eeSkcpoon 	*addr_set = B_FALSE;
15377c478bd9Sstevel@tonic-gate 	return (addr);
15387c478bd9Sstevel@tonic-gate }
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate /*
15417c478bd9Sstevel@tonic-gate  * Return the list of local addresses of an association.  The parameter
15427c478bd9Sstevel@tonic-gate  * myaddrs is supposed to be either (struct sockaddr_in *) or (struct
15437c478bd9Sstevel@tonic-gate  * sockaddr_in6 *) depending on the address family.
15447c478bd9Sstevel@tonic-gate  */
15457c478bd9Sstevel@tonic-gate int
15467c478bd9Sstevel@tonic-gate sctp_getmyaddrs(void *conn, void *myaddrs, int *addrcnt)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate 	int			i;
15497c478bd9Sstevel@tonic-gate 	int			l;
15507c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
15517c478bd9Sstevel@tonic-gate 	sctp_t			*sctp = (sctp_t *)conn;
1552bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1553bd670b35SErik Nordmark 	int			family = connp->conn_family;
15547c478bd9Sstevel@tonic-gate 	int			max = *addrcnt;
15557c478bd9Sstevel@tonic-gate 	size_t			added = 0;
15567c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
15577c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
15587c478bd9Sstevel@tonic-gate 	int			scanned = 0;
15597c478bd9Sstevel@tonic-gate 	boolean_t		skip_lback = B_FALSE;
1560bd670b35SErik Nordmark 	ip_xmit_attr_t		*ixa = connp->conn_ixa;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
15637c478bd9Sstevel@tonic-gate 		return (EINVAL);
15647c478bd9Sstevel@tonic-gate 
15651d8c4025Svi 	/*
15661d8c4025Svi 	 * Skip loopback addresses for non-loopback assoc., ignore
15671d8c4025Svi 	 * this on a clustered node.
15681d8c4025Svi 	 */
15691d8c4025Svi 	if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback &&
15701d8c4025Svi 	    (cl_sctp_check_addrs == NULL)) {
15717c478bd9Sstevel@tonic-gate 		skip_lback = B_TRUE;
15721d8c4025Svi 	}
15731d8c4025Svi 
15747c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1575*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
1576*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
1577*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15787c478bd9Sstevel@tonic-gate 			continue;
1579*92baa190SGeorge Shepherd 		}
15807c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15817c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15827c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif = obj->saddr_ipifp;
15837c478bd9Sstevel@tonic-gate 			in6_addr_t	addr = ipif->sctp_ipif_saddr;
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 			scanned++;
15867c478bd9Sstevel@tonic-gate 			if ((ipif->sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
1587f551bb10Svi 			    SCTP_DONT_SRC(obj) ||
15881d8c4025Svi 			    (SCTP_IS_IPIF_LOOPBACK(ipif) && skip_lback)) {
1589*92baa190SGeorge Shepherd 				if (scanned >= sctp->sctp_nsaddrs) {
1590*92baa190SGeorge Shepherd 					rw_exit(&sctp->
1591*92baa190SGeorge Shepherd 					    sctp_saddrs[i].ipif_hash_lock);
15927c478bd9Sstevel@tonic-gate 					goto done;
1593*92baa190SGeorge Shepherd 				}
15947c478bd9Sstevel@tonic-gate 				obj = list_next(&sctp->sctp_saddrs[i].
15957c478bd9Sstevel@tonic-gate 				    sctp_ipif_list, obj);
15967c478bd9Sstevel@tonic-gate 				continue;
15977c478bd9Sstevel@tonic-gate 			}
15987c478bd9Sstevel@tonic-gate 			switch (family) {
15997c478bd9Sstevel@tonic-gate 			case AF_INET:
16007c478bd9Sstevel@tonic-gate 				sin4 = (struct sockaddr_in *)myaddrs + added;
16017c478bd9Sstevel@tonic-gate 				sin4->sin_family = AF_INET;
1602bd670b35SErik Nordmark 				sin4->sin_port = connp->conn_lport;
16037c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
16047c478bd9Sstevel@tonic-gate 				break;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 			case AF_INET6:
16077c478bd9Sstevel@tonic-gate 				sin6 = (struct sockaddr_in6 *)myaddrs + added;
16087c478bd9Sstevel@tonic-gate 				sin6->sin6_family = AF_INET6;
1609bd670b35SErik Nordmark 				sin6->sin6_port = connp->conn_lport;
16107c478bd9Sstevel@tonic-gate 				sin6->sin6_addr = addr;
1611bd670b35SErik Nordmark 				/*
1612bd670b35SErik Nordmark 				 * Note that flowinfo is only returned for
1613bd670b35SErik Nordmark 				 * getpeername just like for TCP and UDP.
1614bd670b35SErik Nordmark 				 */
1615bd670b35SErik Nordmark 				sin6->sin6_flowinfo = 0;
1616bd670b35SErik Nordmark 
1617bd670b35SErik Nordmark 				if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
1618bd670b35SErik Nordmark 				    (ixa->ixa_flags & IXAF_SCOPEID_SET))
1619bd670b35SErik Nordmark 					sin6->sin6_scope_id = ixa->ixa_scopeid;
1620bd670b35SErik Nordmark 				else
1621bd670b35SErik Nordmark 					sin6->sin6_scope_id = 0;
1622bd670b35SErik Nordmark 				sin6->__sin6_src_id = 0;
16237c478bd9Sstevel@tonic-gate 				break;
16247c478bd9Sstevel@tonic-gate 			}
16257c478bd9Sstevel@tonic-gate 			added++;
1626*92baa190SGeorge Shepherd 			if (added >= max || scanned >= sctp->sctp_nsaddrs) {
1627*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16287c478bd9Sstevel@tonic-gate 				goto done;
1629*92baa190SGeorge Shepherd 			}
16307c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
16317c478bd9Sstevel@tonic-gate 			    obj);
16327c478bd9Sstevel@tonic-gate 		}
1633*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16347c478bd9Sstevel@tonic-gate 	}
16357c478bd9Sstevel@tonic-gate done:
16367c478bd9Sstevel@tonic-gate 	*addrcnt = added;
16377c478bd9Sstevel@tonic-gate 	return (0);
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate /*
1641df19b344Svi  * Given the supported address family, walk through the source address list
1642df19b344Svi  * and return the total length of the available addresses. If 'p' is not
1643df19b344Svi  * null, construct the parameter list for the addresses in 'p'.
1644f551bb10Svi  * 'modify' will only be set when we want the source address list to
1645f551bb10Svi  * be modified. The source address list will be modified only when
1646f551bb10Svi  * generating an INIT chunk. For generating an INIT-ACK 'modify' will
1647f551bb10Svi  * be false since the 'sctp' will be that of the listener.
16487c478bd9Sstevel@tonic-gate  */
16497c478bd9Sstevel@tonic-gate size_t
1650f551bb10Svi sctp_saddr_info(sctp_t *sctp, int supp_af, uchar_t *p, boolean_t modify)
16517c478bd9Sstevel@tonic-gate {
16527c478bd9Sstevel@tonic-gate 	int			i;
16537c478bd9Sstevel@tonic-gate 	int			l;
16547c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
1655df19b344Svi 	size_t			paramlen = 0;
16567c478bd9Sstevel@tonic-gate 	sctp_parm_hdr_t		*hdr;
16577c478bd9Sstevel@tonic-gate 	int			scanned = 0;
1658f551bb10Svi 	int			naddr;
1659f551bb10Svi 	int			nsaddr;
16601d8c4025Svi 	boolean_t		del_ll = B_FALSE;
16611d8c4025Svi 	boolean_t		del_lb = B_FALSE;
16621d8c4025Svi 
16631d8c4025Svi 
16641d8c4025Svi 	/*
16651d8c4025Svi 	 * On a clustered node don't bother changing anything
16661d8c4025Svi 	 * on the loopback interface.
16671d8c4025Svi 	 */
16681d8c4025Svi 	if (modify && !sctp->sctp_loopback && (cl_sctp_check_addrs == NULL))
16691d8c4025Svi 		del_lb = B_TRUE;
1670f551bb10Svi 
16711d8c4025Svi 	if (modify && !sctp->sctp_linklocal)
16721d8c4025Svi 		del_ll = B_TRUE;
16737c478bd9Sstevel@tonic-gate 
1674f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
16757c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
1676*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
1677*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
1678*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16797c478bd9Sstevel@tonic-gate 			continue;
1680*92baa190SGeorge Shepherd 		}
16817c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1682f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1683f551bb10Svi 		for (l = 0; l < naddr; l++) {
16847c478bd9Sstevel@tonic-gate 			in6_addr_t	addr;
16857c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
16861d8c4025Svi 			boolean_t	ipif_lb;
16871d8c4025Svi 			boolean_t	ipif_ll;
1688f551bb10Svi 			boolean_t	unsupp_af;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
16917c478bd9Sstevel@tonic-gate 			scanned++;
1692f551bb10Svi 
16931d8c4025Svi 			ipif_lb = SCTP_IS_IPIF_LOOPBACK(ipif);
16941d8c4025Svi 			ipif_ll = SCTP_IS_IPIF_LINKLOCAL(ipif);
1695f551bb10Svi 			unsupp_af = SCTP_UNSUPP_AF(ipif, supp_af);
1696f551bb10Svi 			/*
1697f551bb10Svi 			 * We need to either delete or skip loopback/linklocal
16981d8c4025Svi 			 * or unsupported addresses, if required.
1699f551bb10Svi 			 */
17001d8c4025Svi 			if ((ipif_ll && del_ll) || (ipif_lb && del_lb) ||
17011d8c4025Svi 			    (unsupp_af && modify)) {
1702f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1703f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1704f551bb10Svi 				if (scanned < nsaddr) {
1705f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1706f551bb10Svi 					    sctp_ipif_list, obj);
1707*92baa190SGeorge Shepherd 					sctp_ipif_hash_remove(sctp, ipif,
1708*92baa190SGeorge Shepherd 					    B_TRUE);
1709f551bb10Svi 					continue;
1710f551bb10Svi 				}
1711*92baa190SGeorge Shepherd 				sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
1712*92baa190SGeorge Shepherd 
1713f551bb10Svi 				goto next_addr;
17141d8c4025Svi 			} else if (ipif_ll || unsupp_af ||
17151d8c4025Svi 			    (ipif_lb && (cl_sctp_check_addrs == NULL))) {
1716df19b344Svi 				goto next_addr;
17177c478bd9Sstevel@tonic-gate 			}
1718f551bb10Svi 
1719f551bb10Svi 			if (!SCTP_IPIF_USABLE(ipif->sctp_ipif_state))
1720f551bb10Svi 				goto next_addr;
1721df19b344Svi 			if (p != NULL)
1722df19b344Svi 				hdr = (sctp_parm_hdr_t *)(p + paramlen);
17237c478bd9Sstevel@tonic-gate 			addr = ipif->sctp_ipif_saddr;
1724f551bb10Svi 			if (!ipif->sctp_ipif_isv6) {
17257c478bd9Sstevel@tonic-gate 				struct in_addr	*v4;
17267c478bd9Sstevel@tonic-gate 
1727df19b344Svi 				if (p != NULL) {
1728df19b344Svi 					hdr->sph_type = htons(PARM_ADDR4);
1729df19b344Svi 					hdr->sph_len = htons(PARM_ADDR4_LEN);
1730df19b344Svi 					v4 = (struct in_addr *)(hdr + 1);
1731df19b344Svi 					IN6_V4MAPPED_TO_INADDR(&addr, v4);
1732df19b344Svi 				}
1733df19b344Svi 				paramlen += PARM_ADDR4_LEN;
1734f551bb10Svi 			} else {
1735df19b344Svi 				if (p != NULL) {
1736df19b344Svi 					hdr->sph_type = htons(PARM_ADDR6);
1737df19b344Svi 					hdr->sph_len = htons(PARM_ADDR6_LEN);
1738df19b344Svi 					bcopy(&addr, hdr + 1, sizeof (addr));
1739df19b344Svi 				}
1740df19b344Svi 				paramlen += PARM_ADDR6_LEN;
17417c478bd9Sstevel@tonic-gate 			}
1742df19b344Svi next_addr:
1743*92baa190SGeorge Shepherd 			if (scanned >= nsaddr) {
1744*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1745df19b344Svi 				return (paramlen);
1746*92baa190SGeorge Shepherd 			}
17477c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
17487c478bd9Sstevel@tonic-gate 			    obj);
17497c478bd9Sstevel@tonic-gate 		}
1750*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
17517c478bd9Sstevel@tonic-gate 	}
1752df19b344Svi 	return (paramlen);
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate 
17551d8c4025Svi /*
17561d8c4025Svi  * This is used on a clustered node to obtain a list of addresses, the list
17571d8c4025Svi  * consists of sockaddr_in structs for v4 and sockaddr_in6 for v6. The list
17581d8c4025Svi  * is then passed onto the clustering module which sends back the correct
17591d8c4025Svi  * list based on the port info. Regardless of the input, i.e INADDR_ANY
17601d8c4025Svi  * or specific address(es), we create the list since it could be modified by
17611d8c4025Svi  * the clustering module. When given a list of addresses, we simply
17621d8c4025Svi  * create the list of sockaddr_in or sockaddr_in6 structs using those
17631d8c4025Svi  * addresses. If there is an INADDR_ANY in the input list, or if the
17641d8c4025Svi  * input is INADDR_ANY, we create a list of sockaddr_in or sockaddr_in6
17651d8c4025Svi  * structs consisting all the addresses in the global interface list
17661d8c4025Svi  * except those that are hosted on the loopback interface. We create
17671d8c4025Svi  * a list of sockaddr_in[6] structs just so that it can be directly input
17681d8c4025Svi  * to sctp_valid_addr_list() once the clustering module has processed it.
17691d8c4025Svi  */
17701d8c4025Svi int
17711d8c4025Svi sctp_get_addrlist(sctp_t *sctp, const void *addrs, uint32_t *addrcnt,
17721d8c4025Svi     uchar_t **addrlist, int *uspec, size_t *size)
17731d8c4025Svi {
17741d8c4025Svi 	int			cnt;
17751d8c4025Svi 	int			icnt;
17761d8c4025Svi 	sctp_ipif_t		*sctp_ipif;
17771d8c4025Svi 	struct sockaddr_in	*s4;
17781d8c4025Svi 	struct sockaddr_in6	*s6;
17791d8c4025Svi 	uchar_t			*p;
17801d8c4025Svi 	int			err = 0;
1781f4b3ec61Sdh 	sctp_stack_t		*sctps = sctp->sctp_sctps;
1782bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
17831d8c4025Svi 
17841d8c4025Svi 	*addrlist = NULL;
17851d8c4025Svi 	*size = 0;
17861d8c4025Svi 
17871d8c4025Svi 	/*
17881d8c4025Svi 	 * Create a list of sockaddr_in[6] structs using the input list.
17891d8c4025Svi 	 */
1790bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
17911d8c4025Svi 		*size = sizeof (struct sockaddr_in) * *addrcnt;
17921d8c4025Svi 		*addrlist = kmem_zalloc(*size,  KM_SLEEP);
17931d8c4025Svi 		p = *addrlist;
17941d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
17951d8c4025Svi 			s4 = (struct sockaddr_in *)addrs + cnt;
17961d8c4025Svi 			/*
17971d8c4025Svi 			 * We need to create a list of all the available
17981d8c4025Svi 			 * addresses if there is an INADDR_ANY. However,
17991d8c4025Svi 			 * if we are beyond LISTEN, then this is invalid
18001d8c4025Svi 			 * (see sctp_valid_addr_list(). So, we just fail
18011d8c4025Svi 			 * it here rather than wait till it fails in
18021d8c4025Svi 			 * sctp_valid_addr_list().
18031d8c4025Svi 			 */
18041d8c4025Svi 			if (s4->sin_addr.s_addr == INADDR_ANY) {
18051d8c4025Svi 				kmem_free(*addrlist, *size);
18061d8c4025Svi 				*addrlist = NULL;
18071d8c4025Svi 				*size = 0;
18081d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
18091d8c4025Svi 					*addrcnt = 0;
18101d8c4025Svi 					return (EINVAL);
18111d8c4025Svi 				}
18121d8c4025Svi 				if (uspec != NULL)
18131d8c4025Svi 					*uspec = 1;
18141d8c4025Svi 				goto get_all_addrs;
18151d8c4025Svi 			} else {
18161d8c4025Svi 				bcopy(s4, p, sizeof (*s4));
18171d8c4025Svi 				p += sizeof (*s4);
18181d8c4025Svi 			}
18191d8c4025Svi 		}
18201d8c4025Svi 	} else {
18211d8c4025Svi 		*size = sizeof (struct sockaddr_in6) * *addrcnt;
18221d8c4025Svi 		*addrlist = kmem_zalloc(*size, KM_SLEEP);
18231d8c4025Svi 		p = *addrlist;
18241d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
18251d8c4025Svi 			s6 = (struct sockaddr_in6 *)addrs + cnt;
18261d8c4025Svi 			/*
18271d8c4025Svi 			 * Comments for INADDR_ANY, above, apply here too.
18281d8c4025Svi 			 */
18291d8c4025Svi 			if (IN6_IS_ADDR_UNSPECIFIED(&s6->sin6_addr)) {
18301d8c4025Svi 				kmem_free(*addrlist, *size);
18311d8c4025Svi 				*size = 0;
18321d8c4025Svi 				*addrlist = NULL;
18331d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
18341d8c4025Svi 					*addrcnt = 0;
18351d8c4025Svi 					return (EINVAL);
18361d8c4025Svi 				}
18371d8c4025Svi 				if (uspec != NULL)
18381d8c4025Svi 					*uspec = 1;
18391d8c4025Svi 				goto get_all_addrs;
18401d8c4025Svi 			} else {
18411d8c4025Svi 				bcopy(addrs, p, sizeof (*s6));
18421d8c4025Svi 				p += sizeof (*s6);
18431d8c4025Svi 			}
18441d8c4025Svi 		}
18451d8c4025Svi 	}
18461d8c4025Svi 	return (err);
18471d8c4025Svi get_all_addrs:
18481d8c4025Svi 
18491d8c4025Svi 	/*
18501d8c4025Svi 	 * Allocate max possible size. We allocate the max. size here because
18511d8c4025Svi 	 * the clustering module could end up adding addresses to the list.
18521d8c4025Svi 	 * We allocate upfront so that the clustering module need to bother
18531d8c4025Svi 	 * re-sizing the list.
18541d8c4025Svi 	 */
1855bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
1856f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in) *
1857f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1858f4b3ec61Sdh 	} else {
1859f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in6) *
1860f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1861f4b3ec61Sdh 	}
18621d8c4025Svi 	*addrlist = kmem_zalloc(*size, KM_SLEEP);
18631d8c4025Svi 	*addrcnt = 0;
18641d8c4025Svi 	p = *addrlist;
1865f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
18661d8c4025Svi 
18671d8c4025Svi 	/*
18681d8c4025Svi 	 * Walk through the global interface list and add all addresses,
18691d8c4025Svi 	 * except those that are hosted on loopback interfaces.
18701d8c4025Svi 	 */
18711d8c4025Svi 	for (cnt = 0; cnt <  SCTP_IPIF_HASH; cnt++) {
1872f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[cnt].ipif_count == 0)
18731d8c4025Svi 			continue;
1874f4b3ec61Sdh 		sctp_ipif = list_head(
1875f4b3ec61Sdh 		    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list);
1876f4b3ec61Sdh 		for (icnt = 0;
1877f4b3ec61Sdh 		    icnt < sctps->sctps_g_ipifs[cnt].ipif_count;
1878f4b3ec61Sdh 		    icnt++) {
18791d8c4025Svi 			in6_addr_t	addr;
18801d8c4025Svi 
18811d8c4025Svi 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
18821d8c4025Svi 			addr = sctp_ipif->sctp_ipif_saddr;
18831d8c4025Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
18841d8c4025Svi 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
18851d8c4025Svi 			    SCTP_IS_IPIF_LOOPBACK(sctp_ipif) ||
18861d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(sctp_ipif) ||
18875d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
1888bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET &&
18891d8c4025Svi 			    sctp_ipif->sctp_ipif_isv6) ||
18901d8c4025Svi 			    (sctp->sctp_connp->conn_ipv6_v6only &&
18911d8c4025Svi 			    !sctp_ipif->sctp_ipif_isv6)) {
18921d8c4025Svi 				rw_exit(&sctp_ipif->sctp_ipif_lock);
18931d8c4025Svi 				sctp_ipif = list_next(
1894f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
18951d8c4025Svi 				    sctp_ipif);
18961d8c4025Svi 				continue;
18971d8c4025Svi 			}
18981d8c4025Svi 			rw_exit(&sctp_ipif->sctp_ipif_lock);
1899bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET) {
19001d8c4025Svi 				s4 = (struct sockaddr_in *)p;
19011d8c4025Svi 				IN6_V4MAPPED_TO_INADDR(&addr, &s4->sin_addr);
19021d8c4025Svi 				s4->sin_family = AF_INET;
19031d8c4025Svi 				p += sizeof (*s4);
19041d8c4025Svi 			} else {
19051d8c4025Svi 				s6 = (struct sockaddr_in6 *)p;
19061d8c4025Svi 				s6->sin6_addr = addr;
19071d8c4025Svi 				s6->sin6_family = AF_INET6;
19081d8c4025Svi 				s6->sin6_scope_id =
19091d8c4025Svi 				    sctp_ipif->sctp_ipif_ill->sctp_ill_index;
19101d8c4025Svi 				p += sizeof (*s6);
19111d8c4025Svi 			}
19121d8c4025Svi 			(*addrcnt)++;
1913f4b3ec61Sdh 			sctp_ipif = list_next(
1914f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
19151d8c4025Svi 			    sctp_ipif);
19161d8c4025Svi 		}
19171d8c4025Svi 	}
1918f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
19191d8c4025Svi 	return (err);
19201d8c4025Svi }
19211d8c4025Svi 
19221d8c4025Svi /*
19231d8c4025Svi  * Get a list of addresses from the source address list. The  caller is
19241d8c4025Svi  * responsible for allocating sufficient buffer for this.
19251d8c4025Svi  */
19261d8c4025Svi void
19271d8c4025Svi sctp_get_saddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
19281d8c4025Svi {
19291d8c4025Svi 	int			cnt;
19301d8c4025Svi 	int			icnt;
19311d8c4025Svi 	sctp_saddr_ipif_t	*obj;
19321d8c4025Svi 	int			naddr;
19331d8c4025Svi 	int			scanned = 0;
19341d8c4025Svi 
19351d8c4025Svi 	for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
1936*92baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[cnt].ipif_hash_lock, RW_READER);
1937*92baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[cnt].ipif_count == 0) {
1938*92baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19391d8c4025Svi 			continue;
1940*92baa190SGeorge Shepherd 		}
19411d8c4025Svi 		obj = list_head(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
19421d8c4025Svi 		naddr = sctp->sctp_saddrs[cnt].ipif_count;
19431d8c4025Svi 		for (icnt = 0; icnt < naddr; icnt++) {
19441d8c4025Svi 			sctp_ipif_t	*ipif;
19451d8c4025Svi 
1946*92baa190SGeorge Shepherd 			if (psize < sizeof (ipif->sctp_ipif_saddr)) {
1947*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19481d8c4025Svi 				return;
1949*92baa190SGeorge Shepherd 			}
19501d8c4025Svi 
19511d8c4025Svi 			scanned++;
19521d8c4025Svi 			ipif = obj->saddr_ipifp;
19531d8c4025Svi 			bcopy(&ipif->sctp_ipif_saddr, p,
19541d8c4025Svi 			    sizeof (ipif->sctp_ipif_saddr));
19551d8c4025Svi 			p += sizeof (ipif->sctp_ipif_saddr);
19561d8c4025Svi 			psize -= sizeof (ipif->sctp_ipif_saddr);
1957*92baa190SGeorge Shepherd 			if (scanned >= sctp->sctp_nsaddrs) {
1958*92baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19591d8c4025Svi 				return;
1960*92baa190SGeorge Shepherd 			}
1961f4b3ec61Sdh 			obj = list_next(
1962f4b3ec61Sdh 			    &sctp->sctp_saddrs[icnt].sctp_ipif_list,
19631d8c4025Svi 			    obj);
19641d8c4025Svi 		}
1965*92baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19661d8c4025Svi 	}
19671d8c4025Svi }
19681d8c4025Svi 
19691d8c4025Svi /*
19701d8c4025Svi  * Get a list of addresses from the remote address list. The  caller is
19711d8c4025Svi  * responsible for allocating sufficient buffer for this.
19721d8c4025Svi  */
19731d8c4025Svi void
19741d8c4025Svi sctp_get_faddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
19751d8c4025Svi {
19761d8c4025Svi 	sctp_faddr_t	*fp;
19771d8c4025Svi 
19781d8c4025Svi 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->next) {
19791d8c4025Svi 		if (psize < sizeof (fp->faddr))
19801d8c4025Svi 			return;
19811d8c4025Svi 		bcopy(&fp->faddr, p, sizeof (fp->faddr));
19821d8c4025Svi 		p += sizeof (fp->faddr);
19831d8c4025Svi 		psize -= sizeof (fp->faddr);
19841d8c4025Svi 	}
19851d8c4025Svi }
19867c478bd9Sstevel@tonic-gate 
1987f4b3ec61Sdh static void
1988f4b3ec61Sdh sctp_free_ills(sctp_stack_t *sctps)
1989f4b3ec61Sdh {
1990f4b3ec61Sdh 	int			i;
1991f4b3ec61Sdh 	int			l;
1992f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1993f4b3ec61Sdh 
1994f4b3ec61Sdh 	if (sctps->sctps_ills_count == 0)
1995f4b3ec61Sdh 		return;
1996f4b3ec61Sdh 
1997f4b3ec61Sdh 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1998f4b3ec61Sdh 		sctp_ill = list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1999f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ills[i].ill_count; l++) {
2000f4b3ec61Sdh 			ASSERT(sctp_ill->sctp_ill_ipifcnt == 0);
2001f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[i].sctp_ill_list,
2002f4b3ec61Sdh 			    sctp_ill);
2003f4b3ec61Sdh 			sctps->sctps_ills_count--;
2004f4b3ec61Sdh 			kmem_free(sctp_ill->sctp_ill_name,
2005f4b3ec61Sdh 			    sctp_ill->sctp_ill_name_length);
2006f4b3ec61Sdh 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
2007f4b3ec61Sdh 			sctp_ill =
2008f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
2009f4b3ec61Sdh 		}
2010f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
2011f4b3ec61Sdh 	}
2012f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0);
2013f4b3ec61Sdh }
2014f4b3ec61Sdh 
2015f4b3ec61Sdh static void
2016f4b3ec61Sdh sctp_free_ipifs(sctp_stack_t *sctps)
2017f4b3ec61Sdh {
2018f4b3ec61Sdh 	int			i;
2019f4b3ec61Sdh 	int			l;
2020f4b3ec61Sdh 	sctp_ipif_t	*sctp_ipif;
2021f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
2022f4b3ec61Sdh 
2023f4b3ec61Sdh 	if (sctps->sctps_g_ipifs_count == 0)
2024f4b3ec61Sdh 		return;
2025f4b3ec61Sdh 
2026f4b3ec61Sdh 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
2027f4b3ec61Sdh 		sctp_ipif = list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2028f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ipifs[i].ipif_count; l++) {
2029f4b3ec61Sdh 			sctp_ill = sctp_ipif->sctp_ipif_ill;
2030f4b3ec61Sdh 
2031f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
2032f4b3ec61Sdh 			    sctp_ipif);
2033f4b3ec61Sdh 			sctps->sctps_g_ipifs_count--;
2034f4b3ec61Sdh 			(void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt,
2035f4b3ec61Sdh 			    -1);
2036f4b3ec61Sdh 			kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
2037f4b3ec61Sdh 			sctp_ipif =
2038f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2039f4b3ec61Sdh 		}
2040f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
2041f4b3ec61Sdh 	}
2042f4b3ec61Sdh 	ASSERT(sctps->sctps_g_ipifs_count == 0);
2043f4b3ec61Sdh }
2044f4b3ec61Sdh 
2045f4b3ec61Sdh 
20467c478bd9Sstevel@tonic-gate /* Initialize the SCTP ILL list and lock */
20477c478bd9Sstevel@tonic-gate void
2048f4b3ec61Sdh sctp_saddr_init(sctp_stack_t *sctps)
20497c478bd9Sstevel@tonic-gate {
20507c478bd9Sstevel@tonic-gate 	int	i;
20517c478bd9Sstevel@tonic-gate 
2052f4b3ec61Sdh 	sctps->sctps_g_ills = kmem_zalloc(sizeof (sctp_ill_hash_t) *
2053f4b3ec61Sdh 	    SCTP_ILL_HASH, KM_SLEEP);
2054f4b3ec61Sdh 	sctps->sctps_g_ipifs = kmem_zalloc(sizeof (sctp_ipif_hash_t) *
2055f4b3ec61Sdh 	    SCTP_IPIF_HASH, KM_SLEEP);
2056f4b3ec61Sdh 
2057f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ills_lock, NULL, RW_DEFAULT, NULL);
2058f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ipifs_lock, NULL, RW_DEFAULT, NULL);
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++) {
2061f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
2062f4b3ec61Sdh 		list_create(&sctps->sctps_g_ills[i].sctp_ill_list,
2063f4b3ec61Sdh 		    sizeof (sctp_ill_t),
20647c478bd9Sstevel@tonic-gate 		    offsetof(sctp_ill_t, sctp_ills));
20657c478bd9Sstevel@tonic-gate 	}
20667c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
2067f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
2068f4b3ec61Sdh 		list_create(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
20697c478bd9Sstevel@tonic-gate 		    sizeof (sctp_ipif_t), offsetof(sctp_ipif_t, sctp_ipifs));
20707c478bd9Sstevel@tonic-gate 	}
20717c478bd9Sstevel@tonic-gate }
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate void
2074f4b3ec61Sdh sctp_saddr_fini(sctp_stack_t *sctps)
20757c478bd9Sstevel@tonic-gate {
20767c478bd9Sstevel@tonic-gate 	int	i;
20777c478bd9Sstevel@tonic-gate 
2078f4b3ec61Sdh 	sctp_free_ipifs(sctps);
2079f4b3ec61Sdh 	sctp_free_ills(sctps);
2080f4b3ec61Sdh 
20817c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++)
2082f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ills[i].sctp_ill_list);
20837c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++)
2084f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2085f4b3ec61Sdh 
2086f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0 && sctps->sctps_g_ipifs_count == 0);
2087f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ills, sizeof (sctp_ill_hash_t) *
2088f4b3ec61Sdh 	    SCTP_ILL_HASH);
2089f4b3ec61Sdh 	sctps->sctps_g_ills = NULL;
2090f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ipifs, sizeof (sctp_ipif_hash_t) *
2091f4b3ec61Sdh 	    SCTP_IPIF_HASH);
2092f4b3ec61Sdh 	sctps->sctps_g_ipifs = NULL;
2093f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ills_lock);
2094f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ipifs_lock);
20957c478bd9Sstevel@tonic-gate }
2096