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 /*
226be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/systm.h>
277c478bd9Sstevel@tonic-gate #include <sys/stream.h>
281d19ca10Svi #include <sys/cmn_err.h>
297c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
307c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
317c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
327c478bd9Sstevel@tonic-gate #include <sys/socket.h>
337c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
347c478bd9Sstevel@tonic-gate #include <sys/list.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include <netinet/in.h>
377c478bd9Sstevel@tonic-gate #include <netinet/ip6.h>
387c478bd9Sstevel@tonic-gate #include <netinet/sctp.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <inet/common.h>
417c478bd9Sstevel@tonic-gate #include <inet/ip.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip6.h>
43bd670b35SErik Nordmark #include <inet/ip_ire.h>
447c478bd9Sstevel@tonic-gate #include <inet/ip_if.h>
457c478bd9Sstevel@tonic-gate #include <inet/ipclassifier.h>
467c478bd9Sstevel@tonic-gate #include <inet/sctp_ip.h>
477c478bd9Sstevel@tonic-gate #include "sctp_impl.h"
487c478bd9Sstevel@tonic-gate #include "sctp_addr.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void		sctp_ipif_inactive(sctp_ipif_t *);
517c478bd9Sstevel@tonic-gate static sctp_ipif_t	*sctp_lookup_ipif_addr(in6_addr_t *, boolean_t,
52e35d2278Svi 			    zoneid_t, boolean_t, uint_t, uint_t, boolean_t,
53e35d2278Svi 			    sctp_stack_t *);
547c478bd9Sstevel@tonic-gate static int		sctp_get_all_ipifs(sctp_t *, int);
55f551bb10Svi static int		sctp_ipif_hash_insert(sctp_t *, sctp_ipif_t *, int,
56e35d2278Svi 			    boolean_t, boolean_t);
5792baa190SGeorge Shepherd static void		sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *,
5892baa190SGeorge Shepherd 			    boolean_t);
59c31292eeSkcpoon static void		sctp_fix_saddr(sctp_t *, in6_addr_t *);
607c478bd9Sstevel@tonic-gate static int		sctp_compare_ipif_list(sctp_ipif_hash_t *,
617c478bd9Sstevel@tonic-gate 			    sctp_ipif_hash_t *);
627c478bd9Sstevel@tonic-gate static int		sctp_copy_ipifs(sctp_ipif_hash_t *, sctp_t *, int);
63f551bb10Svi 
64e35d2278Svi #define	SCTP_ADDR4_HASH(addr)	\
65e35d2278Svi 	(((addr) ^ ((addr) >> 8) ^ ((addr) >> 16) ^ ((addr) >> 24)) &	\
66e35d2278Svi 	(SCTP_IPIF_HASH - 1))
67e35d2278Svi 
68e35d2278Svi #define	SCTP_ADDR6_HASH(addr)	\
69e35d2278Svi 	(((addr).s6_addr32[3] ^						\
70e35d2278Svi 	(((addr).s6_addr32[3] ^ (addr).s6_addr32[2]) >> 12)) &		\
71e35d2278Svi 	(SCTP_IPIF_HASH - 1))
72e35d2278Svi 
73e35d2278Svi #define	SCTP_IPIF_ADDR_HASH(addr, isv6)					\
74e35d2278Svi 	((isv6) ? SCTP_ADDR6_HASH((addr)) : 				\
75e35d2278Svi 	SCTP_ADDR4_HASH((addr)._S6_un._S6_u32[3]))
76e35d2278Svi 
777c478bd9Sstevel@tonic-gate #define	SCTP_IPIF_USABLE(sctp_ipif_state)	\
787c478bd9Sstevel@tonic-gate 	((sctp_ipif_state) == SCTP_IPIFS_UP ||	\
79f551bb10Svi 	(sctp_ipif_state) ==  SCTP_IPIFS_DOWN)
80f551bb10Svi 
81f551bb10Svi #define	SCTP_IPIF_DISCARD(sctp_ipif_flags)	\
82f551bb10Svi 	((sctp_ipif_flags) & (IPIF_PRIVATE | IPIF_DEPRECATED))
83f551bb10Svi 
841d8c4025Svi #define	SCTP_IS_IPIF_LOOPBACK(ipif)		\
851d8c4025Svi 	((ipif)->sctp_ipif_ill->sctp_ill_flags & PHYI_LOOPBACK)
861d8c4025Svi 
871d8c4025Svi #define	SCTP_IS_IPIF_LINKLOCAL(ipif)		\
881d8c4025Svi 	((ipif)->sctp_ipif_isv6 && 		\
891d8c4025Svi 	IN6_IS_ADDR_LINKLOCAL(&(ipif)->sctp_ipif_saddr))
90f551bb10Svi 
91f551bb10Svi #define	SCTP_UNSUPP_AF(ipif, supp_af)	\
92f551bb10Svi 	((!(ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V4)) ||	\
93f551bb10Svi 	((ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V6)))
947c478bd9Sstevel@tonic-gate 
955d0bc3edSsommerfe #define	SCTP_IPIF_ZONE_MATCH(sctp, ipif) 				\
965d0bc3edSsommerfe 	IPCL_ZONE_MATCH((sctp)->sctp_connp, (ipif)->sctp_ipif_zoneid)
975d0bc3edSsommerfe 
987c478bd9Sstevel@tonic-gate #define	SCTP_ILL_HASH_FN(index)		((index) % SCTP_ILL_HASH)
997c478bd9Sstevel@tonic-gate #define	SCTP_ILL_TO_PHYINDEX(ill)	((ill)->ill_phyint->phyint_ifindex)
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate  * SCTP Interface list manipulation functions, locking used.
1037c478bd9Sstevel@tonic-gate  */
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Delete an SCTP IPIF from the list if the refcount goes to 0 and it is
1077c478bd9Sstevel@tonic-gate  * marked as condemned. Also, check if the ILL needs to go away.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static void
sctp_ipif_inactive(sctp_ipif_t * sctp_ipif)1107c478bd9Sstevel@tonic-gate sctp_ipif_inactive(sctp_ipif_t *sctp_ipif)
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
113e35d2278Svi 	uint_t		hindex;
1147c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
115f4b3ec61Sdh 	sctp_stack_t	*sctps = sctp_ipif->sctp_ipif_ill->
116f4b3ec61Sdh 	    sctp_ill_netstack->netstack_sctp;
1177c478bd9Sstevel@tonic-gate 
118f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
119f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1207c478bd9Sstevel@tonic-gate 
121e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(sctp_ipif->sctp_ipif_saddr,
122e35d2278Svi 	    sctp_ipif->sctp_ipif_isv6);
123e35d2278Svi 
1247c478bd9Sstevel@tonic-gate 	sctp_ill = sctp_ipif->sctp_ipif_ill;
1257c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ill != NULL);
1267c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(sctp_ill->sctp_ill_index);
1277c478bd9Sstevel@tonic-gate 	if (sctp_ipif->sctp_ipif_state != SCTP_IPIFS_CONDEMNED ||
1287c478bd9Sstevel@tonic-gate 	    sctp_ipif->sctp_ipif_refcnt != 0) {
129f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
130f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
1317c478bd9Sstevel@tonic-gate 		return;
1327c478bd9Sstevel@tonic-gate 	}
133e35d2278Svi 	list_remove(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
134f4b3ec61Sdh 	    sctp_ipif);
135e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count--;
136f4b3ec61Sdh 	sctps->sctps_g_ipifs_count--;
1377c478bd9Sstevel@tonic-gate 	rw_destroy(&sctp_ipif->sctp_ipif_lock);
1387c478bd9Sstevel@tonic-gate 	kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1397c478bd9Sstevel@tonic-gate 
140*640c1670SJosef 'Jeff' Sipek 	atomic_dec_32(&sctp_ill->sctp_ill_ipifcnt);
141f4b3ec61Sdh 	if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
142f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
1437c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0 &&
1447c478bd9Sstevel@tonic-gate 		    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
145f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[ill_index].
146f4b3ec61Sdh 			    sctp_ill_list, (void *)sctp_ill);
147f4b3ec61Sdh 			sctps->sctps_g_ills[ill_index].ill_count--;
148f4b3ec61Sdh 			sctps->sctps_ills_count--;
1497c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
1507c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_name_length);
1517c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 	}
154f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
155f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Lookup an SCTP IPIF given an IP address. Increments sctp_ipif refcnt.
160e35d2278Svi  * We are either looking for a IPIF with the given address before
161e35d2278Svi  * inserting it into the global list or looking for an IPIF for an
162e35d2278Svi  * address given an SCTP. In the former case we always check the zoneid,
163e35d2278Svi  * but for the latter case, check_zid could be B_FALSE if the connp
164e35d2278Svi  * for the sctp has conn_all_zones set. When looking for an address we
165e35d2278Svi  * give preference to one that is up, so even though we may find one that
166e35d2278Svi  * is not up we keep looking if there is one up, we hold the down addr
167e35d2278Svi  * in backup_ipif in case we don't find one that is up - i.e. we return
168e35d2278Svi  * the backup_ipif in that case. Note that if we are looking for. If we
169e35d2278Svi  * are specifically looking for an up address, then usable will be set
170e35d2278Svi  * to true.
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate static sctp_ipif_t *
sctp_lookup_ipif_addr(in6_addr_t * addr,boolean_t refhold,zoneid_t zoneid,boolean_t check_zid,uint_t ifindex,uint_t seqid,boolean_t usable,sctp_stack_t * sctps)173e35d2278Svi sctp_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid,
174e35d2278Svi     boolean_t check_zid, uint_t ifindex, uint_t seqid, boolean_t usable,
175e35d2278Svi     sctp_stack_t *sctps)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	int		j;
1787c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
179e35d2278Svi 	sctp_ipif_t	*backup_ipif = NULL;
180e35d2278Svi 	int		hindex;
181e35d2278Svi 
182e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1837c478bd9Sstevel@tonic-gate 
184f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
185e35d2278Svi 	if (sctps->sctps_g_ipifs[hindex].ipif_count == 0) {
186e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
187e35d2278Svi 		return (NULL);
188e35d2278Svi 	}
189e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
190e35d2278Svi 	for (j = 0; j < sctps->sctps_g_ipifs[hindex].ipif_count; j++) {
191e35d2278Svi 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
192e35d2278Svi 		if ((!check_zid ||
193e35d2278Svi 		    (sctp_ipif->sctp_ipif_zoneid == ALL_ZONES ||
194e35d2278Svi 		    zoneid == sctp_ipif->sctp_ipif_zoneid)) &&
195e35d2278Svi 		    (ifindex == 0 || ifindex ==
196e35d2278Svi 		    sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
197e35d2278Svi 		    ((seqid != 0 && seqid == sctp_ipif->sctp_ipif_id) ||
198e35d2278Svi 		    (IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
199e35d2278Svi 		    addr)))) {
200e35d2278Svi 			if (!usable || sctp_ipif->sctp_ipif_state ==
201e35d2278Svi 			    SCTP_IPIFS_UP) {
2027c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2037c478bd9Sstevel@tonic-gate 				if (refhold)
2047c478bd9Sstevel@tonic-gate 					SCTP_IPIF_REFHOLD(sctp_ipif);
205f4b3ec61Sdh 				rw_exit(&sctps->sctps_g_ipifs_lock);
2067c478bd9Sstevel@tonic-gate 				return (sctp_ipif);
207e35d2278Svi 			} else if (sctp_ipif->sctp_ipif_state ==
208e35d2278Svi 			    SCTP_IPIFS_DOWN && backup_ipif == NULL) {
209e35d2278Svi 				backup_ipif = sctp_ipif;
2107c478bd9Sstevel@tonic-gate 			}
2117c478bd9Sstevel@tonic-gate 		}
212e35d2278Svi 		rw_exit(&sctp_ipif->sctp_ipif_lock);
213e35d2278Svi 		sctp_ipif = list_next(
214e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
215e35d2278Svi 	}
216e35d2278Svi 	if (backup_ipif != NULL) {
217e35d2278Svi 		if (refhold)
218e35d2278Svi 			SCTP_IPIF_REFHOLD(backup_ipif);
219e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
220e35d2278Svi 		return (backup_ipif);
2217c478bd9Sstevel@tonic-gate 	}
222f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2237c478bd9Sstevel@tonic-gate 	return (NULL);
2247c478bd9Sstevel@tonic-gate }
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate /*
2277c478bd9Sstevel@tonic-gate  * Populate the list with all the SCTP ipifs for a given ipversion.
2287c478bd9Sstevel@tonic-gate  * Increments sctp_ipif refcnt.
2297c478bd9Sstevel@tonic-gate  * Called with no locks held.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate static int
sctp_get_all_ipifs(sctp_t * sctp,int sleep)2327c478bd9Sstevel@tonic-gate sctp_get_all_ipifs(sctp_t *sctp, int sleep)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
2357c478bd9Sstevel@tonic-gate 	int			i;
2367c478bd9Sstevel@tonic-gate 	int			j;
2377c478bd9Sstevel@tonic-gate 	int			error = 0;
238a22dfb13SVenugopal Iyer 	sctp_stack_t		*sctps = sctp->sctp_sctps;
239a22dfb13SVenugopal Iyer 	boolean_t		isv6;
240bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
2417c478bd9Sstevel@tonic-gate 
242f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
2437c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
244f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[i].ipif_count == 0)
2457c478bd9Sstevel@tonic-gate 			continue;
246f4b3ec61Sdh 		sctp_ipif = list_head(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
247f4b3ec61Sdh 		for (j = 0; j < sctps->sctps_g_ipifs[i].ipif_count; j++) {
2487c478bd9Sstevel@tonic-gate 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
249a22dfb13SVenugopal Iyer 			isv6 = sctp_ipif->sctp_ipif_isv6;
250f551bb10Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
2517c478bd9Sstevel@tonic-gate 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
2525d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
253a22dfb13SVenugopal Iyer 			    SCTP_IS_ADDR_UNSPEC(!isv6,
254a22dfb13SVenugopal Iyer 			    sctp_ipif->sctp_ipif_saddr) ||
255bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET && isv6) ||
256bd670b35SErik Nordmark 			    (connp->conn_ipv6_v6only && !isv6)) {
2577c478bd9Sstevel@tonic-gate 				rw_exit(&sctp_ipif->sctp_ipif_lock);
2587c478bd9Sstevel@tonic-gate 				sctp_ipif = list_next(
259f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
260f4b3ec61Sdh 				    sctp_ipif);
2617c478bd9Sstevel@tonic-gate 				continue;
2627c478bd9Sstevel@tonic-gate 			}
2637c478bd9Sstevel@tonic-gate 			rw_exit(&sctp_ipif->sctp_ipif_lock);
2647c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFHOLD(sctp_ipif);
265f551bb10Svi 			error = sctp_ipif_hash_insert(sctp, sctp_ipif, sleep,
266e35d2278Svi 			    B_FALSE, B_FALSE);
267e35d2278Svi 			if (error != 0 && error != EALREADY)
2687c478bd9Sstevel@tonic-gate 				goto free_stuff;
269f4b3ec61Sdh 			sctp_ipif = list_next(
270f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2717c478bd9Sstevel@tonic-gate 			    sctp_ipif);
2727c478bd9Sstevel@tonic-gate 		}
2737c478bd9Sstevel@tonic-gate 	}
274f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2757c478bd9Sstevel@tonic-gate 	return (0);
2767c478bd9Sstevel@tonic-gate free_stuff:
277f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
2787c478bd9Sstevel@tonic-gate 	sctp_free_saddrs(sctp);
2797c478bd9Sstevel@tonic-gate 	return (ENOMEM);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * Given a list of address, fills in the list of SCTP ipifs if all the addresses
2847c478bd9Sstevel@tonic-gate  * are present in the SCTP interface list, return number of addresses filled
2851d8c4025Svi  * or error. If the caller wants the list of addresses, it sends a pre-allocated
2861d8c4025Svi  * buffer - list. Currently, this list is only used on a clustered node when
2871d8c4025Svi  * the SCTP is in the listen state (from sctp_bind_add()). When called on a
2881d8c4025Svi  * clustered node, the input is always a list of addresses (even if the
2891d8c4025Svi  * original bind() was to INADDR_ANY).
2907c478bd9Sstevel@tonic-gate  * Called with no locks held.
2917c478bd9Sstevel@tonic-gate  */
2927c478bd9Sstevel@tonic-gate int
sctp_valid_addr_list(sctp_t * sctp,const void * addrs,uint32_t addrcnt,uchar_t * list,size_t lsize)2931d8c4025Svi sctp_valid_addr_list(sctp_t *sctp, const void *addrs, uint32_t addrcnt,
2941d8c4025Svi     uchar_t *list, size_t lsize)
2957c478bd9Sstevel@tonic-gate {
2967c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
2977c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
2987c478bd9Sstevel@tonic-gate 	struct in_addr		*addr4;
2997c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
3007c478bd9Sstevel@tonic-gate 	int			cnt;
3017c478bd9Sstevel@tonic-gate 	int			err = 0;
3027c478bd9Sstevel@tonic-gate 	int			saddr_cnt = 0;
3037c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*ipif;
3047c478bd9Sstevel@tonic-gate 	boolean_t		bind_to_all = B_FALSE;
3057c478bd9Sstevel@tonic-gate 	boolean_t		check_addrs = B_FALSE;
3067c478bd9Sstevel@tonic-gate 	boolean_t		check_lport = B_FALSE;
3071d8c4025Svi 	uchar_t			*p = list;
308bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Need to check for port and address depending on the state.
3127c478bd9Sstevel@tonic-gate 	 * After a socket is bound, we need to make sure that subsequent
3137c478bd9Sstevel@tonic-gate 	 * bindx() has correct port.  After an association is established,
3147c478bd9Sstevel@tonic-gate 	 * we need to check for changing the bound address to invalid
3157c478bd9Sstevel@tonic-gate 	 * addresses.
3167c478bd9Sstevel@tonic-gate 	 */
3177c478bd9Sstevel@tonic-gate 	if (sctp->sctp_state >= SCTPS_BOUND) {
3187c478bd9Sstevel@tonic-gate 		check_lport = B_TRUE;
3197c478bd9Sstevel@tonic-gate 		if (sctp->sctp_state > SCTPS_LISTEN)
3207c478bd9Sstevel@tonic-gate 			check_addrs = B_TRUE;
3217c478bd9Sstevel@tonic-gate 	}
3221d8c4025Svi 
3237c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
3247c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
3257c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
3267c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
3277c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addrcnt; cnt++) {
3287c478bd9Sstevel@tonic-gate 		boolean_t	lookup_saddr = B_TRUE;
3291d8c4025Svi 		uint_t		ifindex = 0;
3307c478bd9Sstevel@tonic-gate 
331bd670b35SErik Nordmark 		switch (connp->conn_family) {
3327c478bd9Sstevel@tonic-gate 		case AF_INET:
3337c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
3347c478bd9Sstevel@tonic-gate 			if (sin4->sin_family != AF_INET || (check_lport &&
335bd670b35SErik Nordmark 			    sin4->sin_port != connp->conn_lport)) {
3367c478bd9Sstevel@tonic-gate 				err = EINVAL;
3377c478bd9Sstevel@tonic-gate 				goto free_ret;
3387c478bd9Sstevel@tonic-gate 			}
3397c478bd9Sstevel@tonic-gate 			addr4 = &sin4->sin_addr;
3407c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3417c478bd9Sstevel@tonic-gate 			    (addr4->s_addr == INADDR_ANY ||
3427c478bd9Sstevel@tonic-gate 			    addr4->s_addr == INADDR_BROADCAST ||
343c4f4b3c8Skcpoon 			    CLASSD(addr4->s_addr))) {
3447c478bd9Sstevel@tonic-gate 				err = EINVAL;
3457c478bd9Sstevel@tonic-gate 				goto free_ret;
3467c478bd9Sstevel@tonic-gate 			}
3477c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(addr4, &addr);
3487c478bd9Sstevel@tonic-gate 			if (!check_addrs && addr4->s_addr == INADDR_ANY) {
3497c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3507c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3517c478bd9Sstevel@tonic-gate 			}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 			break;
3547c478bd9Sstevel@tonic-gate 		case AF_INET6:
3557c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
3567c478bd9Sstevel@tonic-gate 			if (sin6->sin6_family != AF_INET6 || (check_lport &&
357bd670b35SErik Nordmark 			    sin6->sin6_port != connp->conn_lport)) {
3587c478bd9Sstevel@tonic-gate 				err = EINVAL;
3597c478bd9Sstevel@tonic-gate 				goto free_ret;
3607c478bd9Sstevel@tonic-gate 			}
3617c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
3621d8c4025Svi 			/* Contains the interface index */
3631d8c4025Svi 			ifindex = sin6->sin6_scope_id;
364bd670b35SErik Nordmark 			if (connp->conn_ipv6_v6only &&
3657c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_V4MAPPED(&addr)) {
3667c478bd9Sstevel@tonic-gate 				err = EAFNOSUPPORT;
3677c478bd9Sstevel@tonic-gate 				goto free_ret;
3687c478bd9Sstevel@tonic-gate 			}
3697c478bd9Sstevel@tonic-gate 			if (check_addrs &&
3707c478bd9Sstevel@tonic-gate 			    (IN6_IS_ADDR_LINKLOCAL(&addr) ||
3717c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_MULTICAST(&addr) ||
3727c478bd9Sstevel@tonic-gate 			    IN6_IS_ADDR_UNSPECIFIED(&addr))) {
3737c478bd9Sstevel@tonic-gate 				err = EINVAL;
3747c478bd9Sstevel@tonic-gate 				goto free_ret;
3757c478bd9Sstevel@tonic-gate 			}
3767c478bd9Sstevel@tonic-gate 			if (!check_addrs && IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3777c478bd9Sstevel@tonic-gate 				lookup_saddr = B_FALSE;
3787c478bd9Sstevel@tonic-gate 				bind_to_all = B_TRUE;
3797c478bd9Sstevel@tonic-gate 			}
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 			break;
3827c478bd9Sstevel@tonic-gate 		default:
3837c478bd9Sstevel@tonic-gate 			err = EAFNOSUPPORT;
3847c478bd9Sstevel@tonic-gate 			goto free_ret;
3857c478bd9Sstevel@tonic-gate 		}
3867c478bd9Sstevel@tonic-gate 		if (lookup_saddr) {
387e35d2278Svi 			ipif = sctp_lookup_ipif_addr(&addr, B_TRUE,
388bd670b35SErik Nordmark 			    IPCL_ZONEID(connp), !connp->conn_allzones,
389e35d2278Svi 			    ifindex, 0, B_TRUE, sctp->sctp_sctps);
3907c478bd9Sstevel@tonic-gate 			if (ipif == NULL) {
3917c478bd9Sstevel@tonic-gate 				/* Address not in the list */
3927c478bd9Sstevel@tonic-gate 				err = EINVAL;
3937c478bd9Sstevel@tonic-gate 				goto free_ret;
3941d8c4025Svi 			} else if (check_addrs && SCTP_IS_IPIF_LOOPBACK(ipif) &&
3951d8c4025Svi 			    cl_sctp_check_addrs == NULL) {
3967c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
3977c478bd9Sstevel@tonic-gate 				err = EINVAL;
3987c478bd9Sstevel@tonic-gate 				goto free_ret;
3997c478bd9Sstevel@tonic-gate 			}
4007c478bd9Sstevel@tonic-gate 		}
4017c478bd9Sstevel@tonic-gate 		if (!bind_to_all) {
402f551bb10Svi 			/*
403f551bb10Svi 			 * If an address is added after association setup,
404f551bb10Svi 			 * we need to wait for the peer to send us an ASCONF
405f551bb10Svi 			 * ACK before we can start using it.
406f551bb10Svi 			 * saddr_ipif_dontsrc will be reset (to 0) when we
407f551bb10Svi 			 * get the ASCONF ACK for this address.
408f551bb10Svi 			 */
409f551bb10Svi 			err = sctp_ipif_hash_insert(sctp, ipif, KM_SLEEP,
410e35d2278Svi 			    check_addrs ? B_TRUE : B_FALSE, B_FALSE);
4117c478bd9Sstevel@tonic-gate 			if (err != 0) {
4127c478bd9Sstevel@tonic-gate 				SCTP_IPIF_REFRELE(ipif);
4137c478bd9Sstevel@tonic-gate 				if (check_addrs && err == EALREADY)
4147c478bd9Sstevel@tonic-gate 					err = EADDRINUSE;
4157c478bd9Sstevel@tonic-gate 				goto free_ret;
4167c478bd9Sstevel@tonic-gate 			}
4177c478bd9Sstevel@tonic-gate 			saddr_cnt++;
4181d8c4025Svi 			if (lsize >= sizeof (addr)) {
4191d8c4025Svi 				bcopy(&addr, p, sizeof (addr));
4201d8c4025Svi 				p += sizeof (addr);
4211d8c4025Svi 				lsize -= sizeof (addr);
4221d8c4025Svi 			}
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate 	if (bind_to_all) {
4267c478bd9Sstevel@tonic-gate 		/*
4277c478bd9Sstevel@tonic-gate 		 * Free whatever we might have added before encountering
4287c478bd9Sstevel@tonic-gate 		 * inaddr_any.
4297c478bd9Sstevel@tonic-gate 		 */
4307c478bd9Sstevel@tonic-gate 		if (sctp->sctp_nsaddrs > 0) {
4317c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp);
4327c478bd9Sstevel@tonic-gate 			ASSERT(sctp->sctp_nsaddrs == 0);
4337c478bd9Sstevel@tonic-gate 		}
4347c478bd9Sstevel@tonic-gate 		err = sctp_get_all_ipifs(sctp, KM_SLEEP);
4357c478bd9Sstevel@tonic-gate 		if (err != 0)
4367c478bd9Sstevel@tonic-gate 			return (err);
4377c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 1;
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4407c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4417c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4427c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4437c478bd9Sstevel@tonic-gate 	return (0);
4447c478bd9Sstevel@tonic-gate free_ret:
4457c478bd9Sstevel@tonic-gate 	if (saddr_cnt != 0)
4467c478bd9Sstevel@tonic-gate 		sctp_del_saddr_list(sctp, addrs, saddr_cnt, B_TRUE);
4477c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
4487c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4497c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
4507c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4517c478bd9Sstevel@tonic-gate 	return (err);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate static int
sctp_ipif_hash_insert(sctp_t * sctp,sctp_ipif_t * ipif,int sleep,boolean_t dontsrc,boolean_t allow_dup)455f551bb10Svi sctp_ipif_hash_insert(sctp_t *sctp, sctp_ipif_t *ipif, int sleep,
456e35d2278Svi     boolean_t dontsrc, boolean_t allow_dup)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	int			cnt;
4597c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
460e35d2278Svi 	int			hindex;
461e35d2278Svi 
462e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
463e35d2278Svi 	    ipif->sctp_ipif_isv6);
46492baa190SGeorge Shepherd 	rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
465e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
466e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
467e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
468e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
469e35d2278Svi 			if (ipif->sctp_ipif_id !=
470e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id &&
471e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_state ==
472e35d2278Svi 			    SCTP_IPIFS_DOWN && ipif->sctp_ipif_state ==
473e35d2278Svi 			    SCTP_IPIFS_UP) {
474e35d2278Svi 				SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
475e35d2278Svi 				ipif_obj->saddr_ipifp = ipif;
476e35d2278Svi 				ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
47792baa190SGeorge Shepherd 				rw_exit(
47892baa190SGeorge Shepherd 				    &sctp->sctp_saddrs[hindex].ipif_hash_lock);
479e35d2278Svi 				return (0);
480e35d2278Svi 			} else if (!allow_dup || ipif->sctp_ipif_id ==
481e35d2278Svi 			    ipif_obj->saddr_ipifp->sctp_ipif_id) {
48292baa190SGeorge Shepherd 				rw_exit(
48392baa190SGeorge Shepherd 				    &sctp->sctp_saddrs[hindex].ipif_hash_lock);
484e35d2278Svi 				return (EALREADY);
485e35d2278Svi 			}
486e35d2278Svi 		}
487e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
4887c478bd9Sstevel@tonic-gate 		    ipif_obj);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	ipif_obj = kmem_zalloc(sizeof (sctp_saddr_ipif_t), sleep);
4917c478bd9Sstevel@tonic-gate 	if (ipif_obj == NULL) {
49292baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
4937c478bd9Sstevel@tonic-gate 		/* Need to do something */
4947c478bd9Sstevel@tonic-gate 		return (ENOMEM);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 	ipif_obj->saddr_ipifp = ipif;
497f551bb10Svi 	ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
498e35d2278Svi 	list_insert_tail(&sctp->sctp_saddrs[hindex].sctp_ipif_list, ipif_obj);
499e35d2278Svi 	sctp->sctp_saddrs[hindex].ipif_count++;
5007c478bd9Sstevel@tonic-gate 	sctp->sctp_nsaddrs++;
50192baa190SGeorge Shepherd 	rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5027c478bd9Sstevel@tonic-gate 	return (0);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
505c31292eeSkcpoon /*
506c31292eeSkcpoon  * Given a source address, walk through the peer address list to see
507c31292eeSkcpoon  * if the source address is being used.  If it is, reset that.
508bd670b35SErik Nordmark  * A cleared saddr will then make sctp_make_mp lookup the destination again
509bd670b35SErik Nordmark  * and as part of that look for a new source.
510c31292eeSkcpoon  */
511c31292eeSkcpoon static void
sctp_fix_saddr(sctp_t * sctp,in6_addr_t * saddr)512c31292eeSkcpoon sctp_fix_saddr(sctp_t *sctp, in6_addr_t *saddr)
513c31292eeSkcpoon {
514c31292eeSkcpoon 	sctp_faddr_t	*fp;
515c31292eeSkcpoon 
5166be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
5176be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (!IN6_ARE_ADDR_EQUAL(&fp->sf_saddr, saddr))
518c31292eeSkcpoon 			continue;
5196be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		V6_SET_ZERO(fp->sf_saddr);
520c31292eeSkcpoon 	}
521c31292eeSkcpoon }
522c31292eeSkcpoon 
5237c478bd9Sstevel@tonic-gate static void
sctp_ipif_hash_remove(sctp_t * sctp,sctp_ipif_t * ipif,boolean_t locked)52492baa190SGeorge Shepherd sctp_ipif_hash_remove(sctp_t *sctp, sctp_ipif_t *ipif, boolean_t locked)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	int			cnt;
5277c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*ipif_obj;
528e35d2278Svi 	int			hindex;
529e35d2278Svi 
530e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
531e35d2278Svi 	    ipif->sctp_ipif_isv6);
53292baa190SGeorge Shepherd 	if (!locked)
53392baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
534e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
535e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
536e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
537e35d2278Svi 		    &ipif->sctp_ipif_saddr)) {
538e35d2278Svi 			list_remove(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5397c478bd9Sstevel@tonic-gate 			    ipif_obj);
540e35d2278Svi 			sctp->sctp_saddrs[hindex].ipif_count--;
5417c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
542c31292eeSkcpoon 			sctp_fix_saddr(sctp, &ipif->sctp_ipif_saddr);
5437c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
5447c478bd9Sstevel@tonic-gate 			kmem_free(ipif_obj, sizeof (sctp_saddr_ipif_t));
5457c478bd9Sstevel@tonic-gate 			break;
5467c478bd9Sstevel@tonic-gate 		}
547e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5487c478bd9Sstevel@tonic-gate 		    ipif_obj);
5497c478bd9Sstevel@tonic-gate 	}
55092baa190SGeorge Shepherd 	if (!locked)
55192baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate static int
sctp_compare_ipif_list(sctp_ipif_hash_t * list1,sctp_ipif_hash_t * list2)5557c478bd9Sstevel@tonic-gate sctp_compare_ipif_list(sctp_ipif_hash_t *list1, sctp_ipif_hash_t *list2)
5567c478bd9Sstevel@tonic-gate {
5577c478bd9Sstevel@tonic-gate 	int			i;
5587c478bd9Sstevel@tonic-gate 	int			j;
5597c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj1;
5607c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj2;
5617c478bd9Sstevel@tonic-gate 	int			overlap = 0;
5627c478bd9Sstevel@tonic-gate 
56392baa190SGeorge Shepherd 	rw_enter(&list1->ipif_hash_lock, RW_READER);
56492baa190SGeorge Shepherd 	rw_enter(&list2->ipif_hash_lock, RW_READER);
5657c478bd9Sstevel@tonic-gate 	obj1 = list_head(&list1->sctp_ipif_list);
5667c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
5677c478bd9Sstevel@tonic-gate 		obj2 = list_head(&list2->sctp_ipif_list);
5687c478bd9Sstevel@tonic-gate 		for (j = 0; j < list2->ipif_count; j++) {
569e35d2278Svi 			if (IN6_ARE_ADDR_EQUAL(
570e35d2278Svi 			    &obj1->saddr_ipifp->sctp_ipif_saddr,
571e35d2278Svi 			    &obj2->saddr_ipifp->sctp_ipif_saddr)) {
5727c478bd9Sstevel@tonic-gate 				overlap++;
5737c478bd9Sstevel@tonic-gate 				break;
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 			obj2 = list_next(&list2->sctp_ipif_list,
5767c478bd9Sstevel@tonic-gate 			    obj2);
5777c478bd9Sstevel@tonic-gate 		}
5787c478bd9Sstevel@tonic-gate 		obj1 = list_next(&list1->sctp_ipif_list, obj1);
5797c478bd9Sstevel@tonic-gate 	}
58092baa190SGeorge Shepherd 	rw_exit(&list1->ipif_hash_lock);
58192baa190SGeorge Shepherd 	rw_exit(&list2->ipif_hash_lock);
5827c478bd9Sstevel@tonic-gate 	return (overlap);
5837c478bd9Sstevel@tonic-gate }
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate int
sctp_compare_saddrs(sctp_t * sctp1,sctp_t * sctp2)5867c478bd9Sstevel@tonic-gate sctp_compare_saddrs(sctp_t *sctp1, sctp_t *sctp2)
5877c478bd9Sstevel@tonic-gate {
5887c478bd9Sstevel@tonic-gate 	int		i;
5897c478bd9Sstevel@tonic-gate 	int		overlap = 0;
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
5927c478bd9Sstevel@tonic-gate 		overlap += sctp_compare_ipif_list(&sctp1->sctp_saddrs[i],
5937c478bd9Sstevel@tonic-gate 		    &sctp2->sctp_saddrs[i]);
5947c478bd9Sstevel@tonic-gate 	}
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	if (sctp1->sctp_nsaddrs == sctp2->sctp_nsaddrs &&
5977c478bd9Sstevel@tonic-gate 	    overlap == sctp1->sctp_nsaddrs) {
5987c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_EQUAL);
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (overlap == sctp1->sctp_nsaddrs)
6027c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_SUBSET);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	if (overlap > 0)
6057c478bd9Sstevel@tonic-gate 		return (SCTP_ADDR_OVERLAP);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	return (SCTP_ADDR_DISJOINT);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate static int
sctp_copy_ipifs(sctp_ipif_hash_t * list1,sctp_t * sctp2,int sleep)6117c478bd9Sstevel@tonic-gate sctp_copy_ipifs(sctp_ipif_hash_t *list1, sctp_t *sctp2, int sleep)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	int			i;
6147c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6157c478bd9Sstevel@tonic-gate 	int			error = 0;
6167c478bd9Sstevel@tonic-gate 
61792baa190SGeorge Shepherd 	rw_enter(&list1->ipif_hash_lock, RW_READER);
6187c478bd9Sstevel@tonic-gate 	obj = list_head(&list1->sctp_ipif_list);
6197c478bd9Sstevel@tonic-gate 	for (i = 0; i < list1->ipif_count; i++) {
6207c478bd9Sstevel@tonic-gate 		SCTP_IPIF_REFHOLD(obj->saddr_ipifp);
621f551bb10Svi 		error = sctp_ipif_hash_insert(sctp2, obj->saddr_ipifp, sleep,
622e35d2278Svi 		    B_FALSE, B_FALSE);
623e35d2278Svi 		ASSERT(error != EALREADY);
62492baa190SGeorge Shepherd 		if (error != 0) {
62592baa190SGeorge Shepherd 			rw_exit(&list1->ipif_hash_lock);
6267c478bd9Sstevel@tonic-gate 			return (error);
62792baa190SGeorge Shepherd 		}
6287c478bd9Sstevel@tonic-gate 		obj = list_next(&list1->sctp_ipif_list, obj);
6297c478bd9Sstevel@tonic-gate 	}
63092baa190SGeorge Shepherd 	rw_exit(&list1->ipif_hash_lock);
6317c478bd9Sstevel@tonic-gate 	return (error);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate int
sctp_dup_saddrs(sctp_t * sctp1,sctp_t * sctp2,int sleep)6357c478bd9Sstevel@tonic-gate sctp_dup_saddrs(sctp_t *sctp1, sctp_t *sctp2, int sleep)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	int	error = 0;
6387c478bd9Sstevel@tonic-gate 	int	i;
6397c478bd9Sstevel@tonic-gate 
640f551bb10Svi 	if (sctp1 == NULL || sctp1->sctp_bound_to_all == 1)
6417c478bd9Sstevel@tonic-gate 		return (sctp_get_all_ipifs(sctp2, sleep));
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
64492baa190SGeorge Shepherd 		rw_enter(&sctp1->sctp_saddrs[i].ipif_hash_lock, RW_READER);
64592baa190SGeorge Shepherd 		if (sctp1->sctp_saddrs[i].ipif_count == 0) {
64692baa190SGeorge Shepherd 			rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6477c478bd9Sstevel@tonic-gate 			continue;
64892baa190SGeorge Shepherd 		}
6497c478bd9Sstevel@tonic-gate 		error = sctp_copy_ipifs(&sctp1->sctp_saddrs[i], sctp2, sleep);
6507c478bd9Sstevel@tonic-gate 		if (error != 0) {
65192baa190SGeorge Shepherd 			rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6527c478bd9Sstevel@tonic-gate 			sctp_free_saddrs(sctp2);
6537c478bd9Sstevel@tonic-gate 			return (error);
6547c478bd9Sstevel@tonic-gate 		}
65592baa190SGeorge Shepherd 		rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 	return (0);
6587c478bd9Sstevel@tonic-gate }
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate void
sctp_free_saddrs(sctp_t * sctp)6617c478bd9Sstevel@tonic-gate sctp_free_saddrs(sctp_t *sctp)
6627c478bd9Sstevel@tonic-gate {
6637c478bd9Sstevel@tonic-gate 	int			i;
6647c478bd9Sstevel@tonic-gate 	int			l;
6657c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
6687c478bd9Sstevel@tonic-gate 		return;
6697c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
67092baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
67192baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
67292baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6737c478bd9Sstevel@tonic-gate 			continue;
67492baa190SGeorge Shepherd 		}
6757c478bd9Sstevel@tonic-gate 		obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6767c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
6777c478bd9Sstevel@tonic-gate 			list_remove(&sctp->sctp_saddrs[i].sctp_ipif_list, obj);
6787c478bd9Sstevel@tonic-gate 			SCTP_IPIF_REFRELE(obj->saddr_ipifp);
6797c478bd9Sstevel@tonic-gate 			sctp->sctp_nsaddrs--;
6807c478bd9Sstevel@tonic-gate 			kmem_free(obj, sizeof (sctp_saddr_ipif_t));
6817c478bd9Sstevel@tonic-gate 			obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6827c478bd9Sstevel@tonic-gate 		}
6837c478bd9Sstevel@tonic-gate 		sctp->sctp_saddrs[i].ipif_count = 0;
68492baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6857c478bd9Sstevel@tonic-gate 	}
686f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
687f551bb10Svi 		sctp->sctp_bound_to_all = 0;
6887c478bd9Sstevel@tonic-gate 	ASSERT(sctp->sctp_nsaddrs == 0);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * Add/Delete the given ILL from the SCTP ILL list. Called with no locks
6937c478bd9Sstevel@tonic-gate  * held.
6947c478bd9Sstevel@tonic-gate  */
6957c478bd9Sstevel@tonic-gate void
sctp_update_ill(ill_t * ill,int op)6967c478bd9Sstevel@tonic-gate sctp_update_ill(ill_t *ill, int op)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	int		i;
6997c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill = NULL;
7007c478bd9Sstevel@tonic-gate 	uint_t		index;
701f4b3ec61Sdh 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
702f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
7037c478bd9Sstevel@tonic-gate 
704f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
707f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
708f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
7091d19ca10Svi 		if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
7101d19ca10Svi 		    (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
7117c478bd9Sstevel@tonic-gate 			break;
7121d19ca10Svi 		}
713f4b3ec61Sdh 		sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
7147c478bd9Sstevel@tonic-gate 		    sctp_ill);
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	switch (op) {
7187c478bd9Sstevel@tonic-gate 	case SCTP_ILL_INSERT:
7197c478bd9Sstevel@tonic-gate 		if (sctp_ill != NULL) {
7207c478bd9Sstevel@tonic-gate 			/* Unmark it if it is condemned */
7217c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED)
7227c478bd9Sstevel@tonic-gate 				sctp_ill->sctp_ill_state = 0;
723f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7247c478bd9Sstevel@tonic-gate 			return;
7257c478bd9Sstevel@tonic-gate 		}
7267c478bd9Sstevel@tonic-gate 		sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
7277c478bd9Sstevel@tonic-gate 		/* Need to re-try? */
7287c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
7291d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7301d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
731f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7327c478bd9Sstevel@tonic-gate 			return;
7337c478bd9Sstevel@tonic-gate 		}
734e35d2278Svi 		sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
735e35d2278Svi 		    KM_NOSLEEP);
7367c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_name == NULL) {
7371d19ca10Svi 			cmn_err(CE_WARN, "sctp_update_ill: error adding "
7381d19ca10Svi 			    "ILL %p to SCTP's ILL list", (void *)ill);
7397c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
740f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7417c478bd9Sstevel@tonic-gate 			return;
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 		bcopy(ill->ill_name, sctp_ill->sctp_ill_name,
7447c478bd9Sstevel@tonic-gate 		    ill->ill_name_length);
7457c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_name_length = ill->ill_name_length;
7467c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
7477c478bd9Sstevel@tonic-gate 		sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
748f4b3ec61Sdh 		sctp_ill->sctp_ill_netstack = ns;	/* No netstack_hold */
7491d19ca10Svi 		sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
750f4b3ec61Sdh 		list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
7517c478bd9Sstevel@tonic-gate 		    (void *)sctp_ill);
752f4b3ec61Sdh 		sctps->sctps_g_ills[index].ill_count++;
753f4b3ec61Sdh 		sctps->sctps_ills_count++;
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate 		break;
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	case SCTP_ILL_REMOVE:
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 		if (sctp_ill == NULL) {
760f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
7617c478bd9Sstevel@tonic-gate 			return;
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		if (sctp_ill->sctp_ill_ipifcnt == 0) {
764f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[index].sctp_ill_list,
7657c478bd9Sstevel@tonic-gate 			    (void *)sctp_ill);
766f4b3ec61Sdh 			sctps->sctps_g_ills[index].ill_count--;
767f4b3ec61Sdh 			sctps->sctps_ills_count--;
7687c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill->sctp_ill_name,
7697c478bd9Sstevel@tonic-gate 			    ill->ill_name_length);
7707c478bd9Sstevel@tonic-gate 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
7717c478bd9Sstevel@tonic-gate 		} else {
7727c478bd9Sstevel@tonic-gate 			sctp_ill->sctp_ill_state = SCTP_ILLS_CONDEMNED;
7737c478bd9Sstevel@tonic-gate 		}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 		break;
7767c478bd9Sstevel@tonic-gate 	}
777f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate 
7801d19ca10Svi /*
7811d19ca10Svi  * The ILL's index is being changed, just remove it from the old list,
7821d19ca10Svi  * change the SCTP ILL's index and re-insert using the new index.
7831d19ca10Svi  */
7841d19ca10Svi void
sctp_ill_reindex(ill_t * ill,uint_t orig_ill_index)7851d19ca10Svi sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
7861d19ca10Svi {
7871d19ca10Svi 	sctp_ill_t	*sctp_ill = NULL;
7881d19ca10Svi 	sctp_ill_t	*nxt_sill;
7891d19ca10Svi 	uint_t		indx;
7901d19ca10Svi 	uint_t		nindx;
7911d19ca10Svi 	boolean_t	once = B_FALSE;
7921d19ca10Svi 	netstack_t	*ns = ill->ill_ipst->ips_netstack;
7931d19ca10Svi 	sctp_stack_t	*sctps = ns->netstack_sctp;
7941d19ca10Svi 
7951d19ca10Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7961d19ca10Svi 
7971d19ca10Svi 	indx = SCTP_ILL_HASH_FN(orig_ill_index);
7981d19ca10Svi 	nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
7991d19ca10Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
8001d19ca10Svi 	while (sctp_ill != NULL) {
8011d19ca10Svi 		nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
8021d19ca10Svi 		    sctp_ill);
8031d19ca10Svi 		if (sctp_ill->sctp_ill_index == orig_ill_index) {
8041d19ca10Svi 			sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
8051d19ca10Svi 			/*
8061d19ca10Svi 			 * if the new index hashes to the same value, all's
8071d19ca10Svi 			 * done.
8081d19ca10Svi 			 */
8091d19ca10Svi 			if (nindx != indx) {
8101d19ca10Svi 				list_remove(
8111d19ca10Svi 				    &sctps->sctps_g_ills[indx].sctp_ill_list,
8121d19ca10Svi 				    (void *)sctp_ill);
8131d19ca10Svi 				sctps->sctps_g_ills[indx].ill_count--;
8141d19ca10Svi 				list_insert_tail(
8151d19ca10Svi 				    &sctps->sctps_g_ills[nindx].sctp_ill_list,
8161d19ca10Svi 				    (void *)sctp_ill);
8171d19ca10Svi 				sctps->sctps_g_ills[nindx].ill_count++;
8181d19ca10Svi 			}
8191d19ca10Svi 			if (once)
8201d19ca10Svi 				break;
8211d19ca10Svi 			/* We might have one for v4 and for v6 */
8221d19ca10Svi 			once = B_TRUE;
8231d19ca10Svi 		}
8241d19ca10Svi 		sctp_ill = nxt_sill;
8251d19ca10Svi 	}
8261d19ca10Svi 	rw_exit(&sctps->sctps_g_ills_lock);
8271d19ca10Svi }
8281d19ca10Svi 
8297c478bd9Sstevel@tonic-gate /* move ipif from f_ill to t_ill */
8307c478bd9Sstevel@tonic-gate void
sctp_move_ipif(ipif_t * ipif,ill_t * f_ill,ill_t * t_ill)8317c478bd9Sstevel@tonic-gate sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
8327c478bd9Sstevel@tonic-gate {
8337c478bd9Sstevel@tonic-gate 	sctp_ill_t	*fsctp_ill = NULL;
8347c478bd9Sstevel@tonic-gate 	sctp_ill_t	*tsctp_ill = NULL;
8357c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
836e35d2278Svi 	uint_t		hindex;
8377c478bd9Sstevel@tonic-gate 	int		i;
838f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
839f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
8407c478bd9Sstevel@tonic-gate 
841f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
842f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
8437c478bd9Sstevel@tonic-gate 
844e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
845e35d2278Svi 	fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
846e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8471d19ca10Svi 		if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
8481d19ca10Svi 		    fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
8497c478bd9Sstevel@tonic-gate 			break;
8501d19ca10Svi 		}
851e35d2278Svi 		fsctp_ill = list_next(
852e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 
855e35d2278Svi 	hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
856e35d2278Svi 	tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
857e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8581d19ca10Svi 		if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
8591d19ca10Svi 		    tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
8607c478bd9Sstevel@tonic-gate 			break;
8611d19ca10Svi 		}
862e35d2278Svi 		tsctp_ill = list_next(
863e35d2278Svi 		    &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 
866e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
867e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
868e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
869e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
8707c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid)
8717c478bd9Sstevel@tonic-gate 			break;
872f4b3ec61Sdh 		sctp_ipif = list_next(
873e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
8747c478bd9Sstevel@tonic-gate 	}
8757c478bd9Sstevel@tonic-gate 	/* Should be an ASSERT? */
8767c478bd9Sstevel@tonic-gate 	if (fsctp_ill == NULL || tsctp_ill == NULL || sctp_ipif == NULL) {
8777c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_move_ipif: error moving ipif %p from %p to %p\n",
8787c478bd9Sstevel@tonic-gate 		    (void *)ipif, (void *)f_ill, (void *)t_ill));
879f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
880f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
8817c478bd9Sstevel@tonic-gate 		return;
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 	rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
8847c478bd9Sstevel@tonic-gate 	ASSERT(sctp_ipif->sctp_ipif_ill == fsctp_ill);
8857c478bd9Sstevel@tonic-gate 	sctp_ipif->sctp_ipif_ill = tsctp_ill;
8867c478bd9Sstevel@tonic-gate 	rw_exit(&sctp_ipif->sctp_ipif_lock);
887*640c1670SJosef 'Jeff' Sipek 	atomic_dec_32(&fsctp_ill->sctp_ill_ipifcnt);
8881a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&tsctp_ill->sctp_ill_ipifcnt);
889f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
890f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate 
893e35d2278Svi /*
894e35d2278Svi  * Walk the list of SCTPs and find each that has oipif in it's saddr list, and
895e35d2278Svi  * if so replace it with nipif.
896e35d2278Svi  */
897e35d2278Svi void
sctp_update_saddrs(sctp_ipif_t * oipif,sctp_ipif_t * nipif,int idx,sctp_stack_t * sctps)898e35d2278Svi sctp_update_saddrs(sctp_ipif_t *oipif, sctp_ipif_t *nipif, int idx,
899e35d2278Svi     sctp_stack_t *sctps)
900e35d2278Svi {
901e35d2278Svi 	sctp_t			*sctp;
902e35d2278Svi 	sctp_t			*sctp_prev = NULL;
903e35d2278Svi 	sctp_saddr_ipif_t	*sobj;
904e35d2278Svi 	int			count;
905e35d2278Svi 
906e35d2278Svi 	mutex_enter(&sctps->sctps_g_lock);
907bd670b35SErik Nordmark 	sctp = list_head(&sctps->sctps_g_list);
908e35d2278Svi 	while (sctp != NULL && oipif->sctp_ipif_refcnt > 0) {
909e35d2278Svi 		mutex_enter(&sctp->sctp_reflock);
910e35d2278Svi 		if (sctp->sctp_condemned ||
911e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count <= 0) {
912e35d2278Svi 			mutex_exit(&sctp->sctp_reflock);
913e35d2278Svi 			sctp = list_next(&sctps->sctps_g_list, sctp);
914e35d2278Svi 			continue;
915e35d2278Svi 		}
916e35d2278Svi 		sctp->sctp_refcnt++;
917e35d2278Svi 		mutex_exit(&sctp->sctp_reflock);
918e35d2278Svi 		mutex_exit(&sctps->sctps_g_lock);
919e35d2278Svi 		if (sctp_prev != NULL)
920e35d2278Svi 			SCTP_REFRELE(sctp_prev);
921e35d2278Svi 
922e35d2278Svi 		RUN_SCTP(sctp);
923e35d2278Svi 		sobj = list_head(&sctp->sctp_saddrs[idx].sctp_ipif_list);
924e35d2278Svi 		for (count = 0; count <
925e35d2278Svi 		    sctp->sctp_saddrs[idx].ipif_count; count++) {
926e35d2278Svi 			if (sobj->saddr_ipifp == oipif) {
927e35d2278Svi 				SCTP_IPIF_REFHOLD(nipif);
928e35d2278Svi 				sobj->saddr_ipifp = nipif;
929e35d2278Svi 				ASSERT(oipif->sctp_ipif_refcnt > 0);
930e35d2278Svi 				/* We have the writer lock */
931e35d2278Svi 				oipif->sctp_ipif_refcnt--;
932e35d2278Svi 				/*
933e35d2278Svi 				 * Can't have more than one referring
934e35d2278Svi 				 * to the same sctp_ipif.
935e35d2278Svi 				 */
936e35d2278Svi 				break;
937e35d2278Svi 			}
938e35d2278Svi 			sobj = list_next(&sctp->sctp_saddrs[idx].sctp_ipif_list,
939e35d2278Svi 			    sobj);
940e35d2278Svi 		}
941e35d2278Svi 		WAKE_SCTP(sctp);
942e35d2278Svi 		sctp_prev = sctp;
943e35d2278Svi 		mutex_enter(&sctps->sctps_g_lock);
944e35d2278Svi 		sctp = list_next(&sctps->sctps_g_list, sctp);
945e35d2278Svi 	}
946e35d2278Svi 	mutex_exit(&sctps->sctps_g_lock);
947e35d2278Svi 	if (sctp_prev != NULL)
948e35d2278Svi 		SCTP_REFRELE(sctp_prev);
949e35d2278Svi }
950e35d2278Svi 
951e35d2278Svi /*
952e35d2278Svi  * Given an ipif, walk the hash list in the global ipif table and for
953e35d2278Svi  * any other SCTP ipif with the same address and non-zero reference, walk
954e35d2278Svi  * the SCTP list and update the saddr list, if required, to point to the
955d0e58000SVenugopal Iyer  * new SCTP ipif. If it is a loopback interface, then there could be
956d0e58000SVenugopal Iyer  * multiple interfaces with 127.0.0.1 if there are zones configured, so
957d0e58000SVenugopal Iyer  * check the zoneid in addition to the address.
958e35d2278Svi  */
959e35d2278Svi void
sctp_chk_and_updt_saddr(int hindex,sctp_ipif_t * ipif,sctp_stack_t * sctps)960e35d2278Svi sctp_chk_and_updt_saddr(int hindex, sctp_ipif_t *ipif, sctp_stack_t *sctps)
961e35d2278Svi {
962e35d2278Svi 	int		cnt;
963e35d2278Svi 	sctp_ipif_t	*sipif;
964e35d2278Svi 
965e35d2278Svi 	ASSERT(sctps->sctps_g_ipifs[hindex].ipif_count > 0);
966e35d2278Svi 	ASSERT(ipif->sctp_ipif_state == SCTP_IPIFS_UP);
967e35d2278Svi 
968e35d2278Svi 	sipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
969e35d2278Svi 	for (cnt = 0; cnt < sctps->sctps_g_ipifs[hindex].ipif_count; cnt++) {
970e35d2278Svi 		rw_enter(&sipif->sctp_ipif_lock, RW_WRITER);
971e35d2278Svi 		if (sipif->sctp_ipif_id != ipif->sctp_ipif_id &&
972e35d2278Svi 		    IN6_ARE_ADDR_EQUAL(&sipif->sctp_ipif_saddr,
973d0e58000SVenugopal Iyer 		    &ipif->sctp_ipif_saddr) && sipif->sctp_ipif_refcnt > 0 &&
974d0e58000SVenugopal Iyer 		    (!SCTP_IS_IPIF_LOOPBACK(ipif) || ipif->sctp_ipif_zoneid ==
975d0e58000SVenugopal Iyer 		    sipif->sctp_ipif_zoneid)) {
976e35d2278Svi 			/*
977e35d2278Svi 			 * There can only be one address up at any time
978e35d2278Svi 			 * and we are here because ipif has been brought
979e35d2278Svi 			 * up.
980e35d2278Svi 			 */
981e35d2278Svi 			ASSERT(sipif->sctp_ipif_state != SCTP_IPIFS_UP);
982e35d2278Svi 			/*
983e35d2278Svi 			 * Someone has a reference to this we need to update to
984e35d2278Svi 			 * point to the new sipif.
985e35d2278Svi 			 */
986e35d2278Svi 			sctp_update_saddrs(sipif, ipif, hindex, sctps);
987e35d2278Svi 		}
988e35d2278Svi 		rw_exit(&sipif->sctp_ipif_lock);
989e35d2278Svi 		sipif = list_next(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
990e35d2278Svi 		    sipif);
991e35d2278Svi 	}
992e35d2278Svi }
993e35d2278Svi 
994e35d2278Svi /*
995e35d2278Svi  * Insert a new SCTP ipif using 'ipif'. v6addr is the address that existed
996e35d2278Svi  * prior to the current address in 'ipif'. Only when an existing address
997e35d2278Svi  * is changed on an IPIF, will v6addr be specified. If the IPIF already
998e35d2278Svi  * exists in the global SCTP ipif table, then we either removed it, if
999e35d2278Svi  * it doesn't have any existing reference, or mark it condemned otherwise.
1000e35d2278Svi  * If an address is being brought up (IPIF_UP), then we need to scan
1001e35d2278Svi  * the SCTP list to check if there is any SCTP that points to the *same*
1002e35d2278Svi  * address on a different SCTP ipif and update in that case.
1003e35d2278Svi  */
1004e35d2278Svi void
sctp_update_ipif_addr(ipif_t * ipif,in6_addr_t v6addr)1005e35d2278Svi sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
1006e35d2278Svi {
1007e35d2278Svi 	ill_t		*ill = ipif->ipif_ill;
1008e35d2278Svi 	int		i;
1009e35d2278Svi 	sctp_ill_t	*sctp_ill;
1010e35d2278Svi 	sctp_ill_t	*osctp_ill;
1011e35d2278Svi 	sctp_ipif_t	*sctp_ipif = NULL;
1012e35d2278Svi 	sctp_ipif_t	*osctp_ipif = NULL;
1013e35d2278Svi 	uint_t		ill_index;
1014e35d2278Svi 	int		hindex;
1015e35d2278Svi 	sctp_stack_t	*sctps;
1016e35d2278Svi 
1017e35d2278Svi 	sctps = ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp;
1018e35d2278Svi 
1019e35d2278Svi 	/* Index for new address */
1020e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr, ill->ill_isv6);
1021e35d2278Svi 
1022e35d2278Svi 	/*
1023e35d2278Svi 	 * The address on this IPIF is changing, we need to look for
1024e35d2278Svi 	 * this old address and mark it condemned, before creating
1025e35d2278Svi 	 * one for the new address.
1026e35d2278Svi 	 */
1027e35d2278Svi 	osctp_ipif = sctp_lookup_ipif_addr(&v6addr, B_FALSE,
1028e35d2278Svi 	    ipif->ipif_zoneid, B_TRUE, SCTP_ILL_TO_PHYINDEX(ill),
1029e35d2278Svi 	    ipif->ipif_seqid, B_FALSE, sctps);
1030e35d2278Svi 
1031e35d2278Svi 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1032e35d2278Svi 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1033e35d2278Svi 
1034e35d2278Svi 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1035e35d2278Svi 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1036e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
10371d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
10381d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
1039e35d2278Svi 			break;
10401d19ca10Svi 		}
1041e35d2278Svi 		sctp_ill = list_next(
1042e35d2278Svi 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
1043e35d2278Svi 	}
1044e35d2278Svi 
1045e35d2278Svi 	if (sctp_ill == NULL) {
10461d19ca10Svi 		ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
1047e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1048e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
10491d19ca10Svi 		return;
1050e35d2278Svi 	}
1051e35d2278Svi 
1052e35d2278Svi 	if (osctp_ipif != NULL) {
1053e35d2278Svi 
1054e35d2278Svi 		/* The address is the same? */
1055e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &v6addr)) {
1056e35d2278Svi 			boolean_t	chk_n_updt = B_FALSE;
1057e35d2278Svi 
1058e35d2278Svi 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
1059e35d2278Svi 			rw_enter(&osctp_ipif->sctp_ipif_lock, RW_WRITER);
1060e35d2278Svi 			if (ipif->ipif_flags & IPIF_UP &&
1061e35d2278Svi 			    osctp_ipif->sctp_ipif_state != SCTP_IPIFS_UP) {
1062e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1063e35d2278Svi 				chk_n_updt = B_TRUE;
1064e35d2278Svi 			} else {
1065e35d2278Svi 				osctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1066e35d2278Svi 			}
1067e35d2278Svi 			osctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1068e35d2278Svi 			rw_exit(&osctp_ipif->sctp_ipif_lock);
1069e35d2278Svi 			if (chk_n_updt) {
1070e35d2278Svi 				sctp_chk_and_updt_saddr(hindex, osctp_ipif,
1071e35d2278Svi 				    sctps);
1072e35d2278Svi 			}
1073e35d2278Svi 			rw_exit(&sctps->sctps_g_ipifs_lock);
1074e35d2278Svi 			rw_exit(&sctps->sctps_g_ills_lock);
1075e35d2278Svi 			return;
1076e35d2278Svi 		}
1077e35d2278Svi 		/*
1078e35d2278Svi 		 * We are effectively removing this address from the ILL.
1079e35d2278Svi 		 */
1080e35d2278Svi 		if (osctp_ipif->sctp_ipif_refcnt != 0) {
1081e35d2278Svi 			osctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1082e35d2278Svi 		} else {
1083e35d2278Svi 			list_t		*ipif_list;
1084e35d2278Svi 			int		ohindex;
1085e35d2278Svi 
1086e35d2278Svi 			osctp_ill = osctp_ipif->sctp_ipif_ill;
1087e35d2278Svi 			/* hash index for the old one */
1088e35d2278Svi 			ohindex = SCTP_IPIF_ADDR_HASH(
1089e35d2278Svi 			    osctp_ipif->sctp_ipif_saddr,
1090e35d2278Svi 			    osctp_ipif->sctp_ipif_isv6);
1091e35d2278Svi 
1092e35d2278Svi 			ipif_list =
1093e35d2278Svi 			    &sctps->sctps_g_ipifs[ohindex].sctp_ipif_list;
1094e35d2278Svi 
1095e35d2278Svi 			list_remove(ipif_list, (void *)osctp_ipif);
1096e35d2278Svi 			sctps->sctps_g_ipifs[ohindex].ipif_count--;
1097e35d2278Svi 			sctps->sctps_g_ipifs_count--;
1098e35d2278Svi 			rw_destroy(&osctp_ipif->sctp_ipif_lock);
1099e35d2278Svi 			kmem_free(osctp_ipif, sizeof (sctp_ipif_t));
1100*640c1670SJosef 'Jeff' Sipek 			atomic_dec_32(&osctp_ill->sctp_ill_ipifcnt);
1101e35d2278Svi 		}
1102e35d2278Svi 	}
1103e35d2278Svi 
1104e35d2278Svi 	sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
1105e35d2278Svi 	/* Try again? */
1106e35d2278Svi 	if (sctp_ipif == NULL) {
11071d19ca10Svi 		cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
11081d19ca10Svi 		    "IPIF %p to SCTP's IPIF list", (void *)ipif);
1109e35d2278Svi 		rw_exit(&sctps->sctps_g_ipifs_lock);
1110e35d2278Svi 		rw_exit(&sctps->sctps_g_ills_lock);
1111e35d2278Svi 		return;
1112e35d2278Svi 	}
1113e35d2278Svi 	sctps->sctps_g_ipifs_count++;
1114e35d2278Svi 	rw_init(&sctp_ipif->sctp_ipif_lock, NULL, RW_DEFAULT, NULL);
1115e35d2278Svi 	sctp_ipif->sctp_ipif_saddr = ipif->ipif_v6lcl_addr;
1116e35d2278Svi 	sctp_ipif->sctp_ipif_ill = sctp_ill;
1117e35d2278Svi 	sctp_ipif->sctp_ipif_isv6 = ill->ill_isv6;
1118e35d2278Svi 	sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1119e35d2278Svi 	sctp_ipif->sctp_ipif_id = ipif->ipif_seqid;
1120e35d2278Svi 	if (ipif->ipif_flags & IPIF_UP)
1121e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1122e35d2278Svi 	else
1123e35d2278Svi 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1124e35d2278Svi 	sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
1125e35d2278Svi 	/*
1126e35d2278Svi 	 * We add it to the head so that it is quicker to find good/recent
1127e35d2278Svi 	 * additions.
1128e35d2278Svi 	 */
1129e35d2278Svi 	list_insert_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
1130e35d2278Svi 	    (void *)sctp_ipif);
1131e35d2278Svi 	sctps->sctps_g_ipifs[hindex].ipif_count++;
11321a5e258fSJosef 'Jeff' Sipek 	atomic_inc_32(&sctp_ill->sctp_ill_ipifcnt);
1133e35d2278Svi 	if (sctp_ipif->sctp_ipif_state == SCTP_IPIFS_UP)
1134e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif, sctps);
1135e35d2278Svi 	rw_exit(&sctps->sctps_g_ipifs_lock);
1136e35d2278Svi 	rw_exit(&sctps->sctps_g_ills_lock);
1137e35d2278Svi }
1138e35d2278Svi 
11397c478bd9Sstevel@tonic-gate /* Insert, Remove,  Mark up or Mark down the ipif */
11407c478bd9Sstevel@tonic-gate void
sctp_update_ipif(ipif_t * ipif,int op)11417c478bd9Sstevel@tonic-gate sctp_update_ipif(ipif_t *ipif, int op)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	ill_t		*ill = ipif->ipif_ill;
11447c478bd9Sstevel@tonic-gate 	int		i;
11457c478bd9Sstevel@tonic-gate 	sctp_ill_t	*sctp_ill;
11467c478bd9Sstevel@tonic-gate 	sctp_ipif_t	*sctp_ipif;
11477c478bd9Sstevel@tonic-gate 	uint_t		ill_index;
1148e35d2278Svi 	uint_t		hindex;
1149f4b3ec61Sdh 	netstack_t	*ns = ipif->ipif_ill->ill_ipst->ips_netstack;
1150f4b3ec61Sdh 	sctp_stack_t	*sctps = ns->netstack_sctp;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	ip2dbg(("sctp_update_ipif: %s %d\n", ill->ill_name, ipif->ipif_seqid));
11537c478bd9Sstevel@tonic-gate 
1154f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1155f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
1158f4b3ec61Sdh 	sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
1159f4b3ec61Sdh 	for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
11601d19ca10Svi 		if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
11611d19ca10Svi 		    sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
11627c478bd9Sstevel@tonic-gate 			break;
11631d19ca10Svi 		}
1164f4b3ec61Sdh 		sctp_ill = list_next(
1165f4b3ec61Sdh 		    &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 	if (sctp_ill == NULL) {
1168f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1169f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11707c478bd9Sstevel@tonic-gate 		return;
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 
1173e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
1174e35d2278Svi 	    ipif->ipif_ill->ill_isv6);
1175e35d2278Svi 	sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
1176e35d2278Svi 	for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
1177e35d2278Svi 		if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid) {
1178e35d2278Svi 			ASSERT(IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
1179e35d2278Svi 			    &ipif->ipif_v6lcl_addr));
11807c478bd9Sstevel@tonic-gate 			break;
1181e35d2278Svi 		}
1182f4b3ec61Sdh 		sctp_ipif = list_next(
1183e35d2278Svi 		    &sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11847c478bd9Sstevel@tonic-gate 		    sctp_ipif);
11857c478bd9Sstevel@tonic-gate 	}
1186e35d2278Svi 	if (sctp_ipif == NULL) {
11877c478bd9Sstevel@tonic-gate 		ip1dbg(("sctp_update_ipif: null sctp_ipif for %d\n", op));
1188f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ipifs_lock);
1189f4b3ec61Sdh 		rw_exit(&sctps->sctps_g_ills_lock);
11907c478bd9Sstevel@tonic-gate 		return;
11917c478bd9Sstevel@tonic-gate 	}
1192e35d2278Svi 	ASSERT(sctp_ill == sctp_ipif->sctp_ipif_ill);
11937c478bd9Sstevel@tonic-gate 	switch (op) {
11947c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_REMOVE:
11957c478bd9Sstevel@tonic-gate 	{
11967c478bd9Sstevel@tonic-gate 		list_t		*ipif_list;
11977c478bd9Sstevel@tonic-gate 		list_t		*ill_list;
11987c478bd9Sstevel@tonic-gate 
1199f4b3ec61Sdh 		ill_list = &sctps->sctps_g_ills[ill_index].sctp_ill_list;
1200e35d2278Svi 		ipif_list = &sctps->sctps_g_ipifs[hindex].sctp_ipif_list;
12017c478bd9Sstevel@tonic-gate 		if (sctp_ipif->sctp_ipif_refcnt != 0) {
12027c478bd9Sstevel@tonic-gate 			sctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
1203f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ipifs_lock);
1204f4b3ec61Sdh 			rw_exit(&sctps->sctps_g_ills_lock);
12057c478bd9Sstevel@tonic-gate 			return;
12067c478bd9Sstevel@tonic-gate 		}
12077c478bd9Sstevel@tonic-gate 		list_remove(ipif_list, (void *)sctp_ipif);
1208e35d2278Svi 		sctps->sctps_g_ipifs[hindex].ipif_count--;
1209f4b3ec61Sdh 		sctps->sctps_g_ipifs_count--;
12107c478bd9Sstevel@tonic-gate 		rw_destroy(&sctp_ipif->sctp_ipif_lock);
12117c478bd9Sstevel@tonic-gate 		kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1212*640c1670SJosef 'Jeff' Sipek 		atomic_dec_32(&sctp_ill->sctp_ill_ipifcnt);
1213f4b3ec61Sdh 		if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
1214f4b3ec61Sdh 			rw_downgrade(&sctps->sctps_g_ipifs_lock);
12157c478bd9Sstevel@tonic-gate 			if (sctp_ill->sctp_ill_ipifcnt == 0 &&
12167c478bd9Sstevel@tonic-gate 			    sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
12177c478bd9Sstevel@tonic-gate 				list_remove(ill_list, (void *)sctp_ill);
1218f4b3ec61Sdh 				sctps->sctps_ills_count--;
1219f4b3ec61Sdh 				sctps->sctps_g_ills[ill_index].ill_count--;
12207c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill->sctp_ill_name,
12217c478bd9Sstevel@tonic-gate 				    sctp_ill->sctp_ill_name_length);
12227c478bd9Sstevel@tonic-gate 				kmem_free(sctp_ill, sizeof (sctp_ill_t));
12237c478bd9Sstevel@tonic-gate 			}
12247c478bd9Sstevel@tonic-gate 		}
12257c478bd9Sstevel@tonic-gate 		break;
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UP:
12297c478bd9Sstevel@tonic-gate 
1230f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12317c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12327c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1233e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12347c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
1235e35d2278Svi 		sctp_chk_and_updt_saddr(hindex, sctp_ipif,
1236e35d2278Svi 		    ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 		break;
12397c478bd9Sstevel@tonic-gate 
12407c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_UPDATE:
12417c478bd9Sstevel@tonic-gate 
1242f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12437c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12447c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1245f551bb10Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12467c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 		break;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	case SCTP_IPIF_DOWN:
12517c478bd9Sstevel@tonic-gate 
1252f4b3ec61Sdh 		rw_downgrade(&sctps->sctps_g_ipifs_lock);
12537c478bd9Sstevel@tonic-gate 		rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12547c478bd9Sstevel@tonic-gate 		sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
1255e35d2278Svi 		sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12567c478bd9Sstevel@tonic-gate 		rw_exit(&sctp_ipif->sctp_ipif_lock);
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate 		break;
12597c478bd9Sstevel@tonic-gate 	}
1260f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
1261f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ills_lock);
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate  * SCTP source address list manipulaton, locking not used (except for
12667c478bd9Sstevel@tonic-gate  * sctp locking by the caller.
12677c478bd9Sstevel@tonic-gate  */
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate /* Remove a specific saddr from the list */
12707c478bd9Sstevel@tonic-gate void
sctp_del_saddr(sctp_t * sctp,sctp_saddr_ipif_t * sp)12717c478bd9Sstevel@tonic-gate sctp_del_saddr(sctp_t *sctp, sctp_saddr_ipif_t *sp)
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12747c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12757c478bd9Sstevel@tonic-gate 
12767c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12777c478bd9Sstevel@tonic-gate 		mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12787c478bd9Sstevel@tonic-gate 
127992baa190SGeorge Shepherd 	sctp_ipif_hash_remove(sctp, sp->saddr_ipifp, B_FALSE);
12807c478bd9Sstevel@tonic-gate 
1281f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
12827c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	if (sctp->sctp_conn_tfp != NULL)
12857c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	if (sctp->sctp_listen_tfp != NULL)
12887c478bd9Sstevel@tonic-gate 		mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12897c478bd9Sstevel@tonic-gate }
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate /*
12927c478bd9Sstevel@tonic-gate  * Delete source address from the existing list. No error checking done here
12937c478bd9Sstevel@tonic-gate  * Called with no locks held.
12947c478bd9Sstevel@tonic-gate  */
12957c478bd9Sstevel@tonic-gate void
sctp_del_saddr_list(sctp_t * sctp,const void * addrs,int addcnt,boolean_t fanout_locked)12967c478bd9Sstevel@tonic-gate sctp_del_saddr_list(sctp_t *sctp, const void *addrs, int addcnt,
12977c478bd9Sstevel@tonic-gate     boolean_t fanout_locked)
12987c478bd9Sstevel@tonic-gate {
12997c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
13007c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
13017c478bd9Sstevel@tonic-gate 	int			cnt;
13027c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
13037c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13041d8c4025Svi 	int			ifindex = 0;
1305bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
13067c478bd9Sstevel@tonic-gate 
13071d8c4025Svi 	ASSERT(sctp->sctp_nsaddrs >= addcnt);
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
13107c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
13117c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
13127c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
13137c478bd9Sstevel@tonic-gate 			mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
13147c478bd9Sstevel@tonic-gate 	}
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < addcnt; cnt++) {
1317bd670b35SErik Nordmark 		switch (connp->conn_family) {
13187c478bd9Sstevel@tonic-gate 		case AF_INET:
13197c478bd9Sstevel@tonic-gate 			sin4 = (struct sockaddr_in *)addrs + cnt;
13207c478bd9Sstevel@tonic-gate 			IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &addr);
13217c478bd9Sstevel@tonic-gate 			break;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 		case AF_INET6:
13247c478bd9Sstevel@tonic-gate 			sin6 = (struct sockaddr_in6 *)addrs + cnt;
13257c478bd9Sstevel@tonic-gate 			addr = sin6->sin6_addr;
13261d8c4025Svi 			ifindex = sin6->sin6_scope_id;
13277c478bd9Sstevel@tonic-gate 			break;
13287c478bd9Sstevel@tonic-gate 		}
1329e35d2278Svi 		sctp_ipif = sctp_lookup_ipif_addr(&addr, B_FALSE,
1330bd670b35SErik Nordmark 		    IPCL_ZONEID(connp), !connp->conn_allzones,
1331e35d2278Svi 		    ifindex, 0, B_TRUE, sctp->sctp_sctps);
13327c478bd9Sstevel@tonic-gate 		ASSERT(sctp_ipif != NULL);
133392baa190SGeorge Shepherd 		sctp_ipif_hash_remove(sctp, sctp_ipif, B_FALSE);
13347c478bd9Sstevel@tonic-gate 	}
1335f551bb10Svi 	if (sctp->sctp_bound_to_all == 1)
13367c478bd9Sstevel@tonic-gate 		sctp->sctp_bound_to_all = 0;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	if (!fanout_locked) {
13397c478bd9Sstevel@tonic-gate 		if (sctp->sctp_conn_tfp != NULL)
13407c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
13417c478bd9Sstevel@tonic-gate 		if (sctp->sctp_listen_tfp != NULL)
13427c478bd9Sstevel@tonic-gate 			mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
13437c478bd9Sstevel@tonic-gate 	}
13447c478bd9Sstevel@tonic-gate }
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate /*
13477c478bd9Sstevel@tonic-gate  * Given an address get the corresponding entry from the list
13487c478bd9Sstevel@tonic-gate  * Called with no locks held.
13497c478bd9Sstevel@tonic-gate  */
13507c478bd9Sstevel@tonic-gate sctp_saddr_ipif_t *
sctp_saddr_lookup(sctp_t * sctp,in6_addr_t * addr,uint_t ifindex)13511d8c4025Svi sctp_saddr_lookup(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
13527c478bd9Sstevel@tonic-gate {
1353e35d2278Svi 	int			cnt;
1354e35d2278Svi 	sctp_saddr_ipif_t	*ipif_obj;
1355e35d2278Svi 	int			hindex;
13567c478bd9Sstevel@tonic-gate 	sctp_ipif_t		*sctp_ipif;
13577c478bd9Sstevel@tonic-gate 
1358e35d2278Svi 	hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
135992baa190SGeorge Shepherd 	rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_READER);
136092baa190SGeorge Shepherd 	if (sctp->sctp_saddrs[hindex].ipif_count == 0) {
136192baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
13627c478bd9Sstevel@tonic-gate 		return (NULL);
136392baa190SGeorge Shepherd 	}
13647c478bd9Sstevel@tonic-gate 
1365e35d2278Svi 	ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
1366e35d2278Svi 	for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
1367e35d2278Svi 		sctp_ipif = ipif_obj->saddr_ipifp;
1368e35d2278Svi 		/*
1369e35d2278Svi 		 * Zone check shouldn't be needed.
1370e35d2278Svi 		 */
1371e35d2278Svi 		if (IN6_ARE_ADDR_EQUAL(addr, &sctp_ipif->sctp_ipif_saddr) &&
1372e35d2278Svi 		    (ifindex == 0 ||
1373e35d2278Svi 		    ifindex == sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
1374e35d2278Svi 		    SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state)) {
137592baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
1376e35d2278Svi 			return (ipif_obj);
1377e35d2278Svi 		}
1378e35d2278Svi 		ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
1379e35d2278Svi 		    ipif_obj);
1380e35d2278Svi 	}
138192baa190SGeorge Shepherd 	rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
1382e35d2278Svi 	return (NULL);
13837c478bd9Sstevel@tonic-gate }
13847c478bd9Sstevel@tonic-gate 
1385f551bb10Svi /* Given an address, add it to the source address list */
1386f551bb10Svi int
sctp_saddr_add_addr(sctp_t * sctp,in6_addr_t * addr,uint_t ifindex)13871d8c4025Svi sctp_saddr_add_addr(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
1388f551bb10Svi {
1389f551bb10Svi 	sctp_ipif_t		*sctp_ipif;
1390bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1391f551bb10Svi 
1392bd670b35SErik Nordmark 	sctp_ipif = sctp_lookup_ipif_addr(addr, B_TRUE, IPCL_ZONEID(connp),
1393bd670b35SErik Nordmark 	    !connp->conn_allzones, ifindex, 0, B_TRUE, sctp->sctp_sctps);
1394f551bb10Svi 	if (sctp_ipif == NULL)
1395f551bb10Svi 		return (EINVAL);
1396f551bb10Svi 
1397e35d2278Svi 	if (sctp_ipif_hash_insert(sctp, sctp_ipif, KM_NOSLEEP, B_FALSE,
1398e35d2278Svi 	    B_FALSE) != 0) {
1399f551bb10Svi 		SCTP_IPIF_REFRELE(sctp_ipif);
1400f551bb10Svi 		return (EINVAL);
1401f551bb10Svi 	}
1402f551bb10Svi 	return (0);
1403f551bb10Svi }
1404f551bb10Svi 
1405f551bb10Svi /*
1406f551bb10Svi  * Remove or mark as dontsrc addresses that are currently not part of the
1407f551bb10Svi  * association. One would delete addresses when processing an INIT and
1408f551bb10Svi  * mark as dontsrc when processing an INIT-ACK.
1409f551bb10Svi  */
1410f551bb10Svi void
sctp_check_saddr(sctp_t * sctp,int supp_af,boolean_t delete,in6_addr_t * no_del_addr)1411c31292eeSkcpoon sctp_check_saddr(sctp_t *sctp, int supp_af, boolean_t delete,
1412c31292eeSkcpoon     in6_addr_t *no_del_addr)
1413f551bb10Svi {
1414f551bb10Svi 	int			i;
1415f551bb10Svi 	int			l;
1416f551bb10Svi 	sctp_saddr_ipif_t	*obj;
1417f551bb10Svi 	int			scanned = 0;
1418f551bb10Svi 	int			naddr;
1419f551bb10Svi 	int			nsaddr;
1420bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1421f551bb10Svi 
1422f551bb10Svi 	ASSERT(!sctp->sctp_loopback && !sctp->sctp_linklocal && supp_af != 0);
1423f551bb10Svi 
1424f551bb10Svi 	/*
1425f551bb10Svi 	 * Irregardless of the supported address in the INIT, v4
1426f551bb10Svi 	 * must be supported.
1427f551bb10Svi 	 */
1428bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET)
1429f551bb10Svi 		supp_af = PARM_SUPP_V4;
1430f551bb10Svi 
1431f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
1432f551bb10Svi 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
143392baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
143492baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
143592baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1436f551bb10Svi 			continue;
143792baa190SGeorge Shepherd 		}
1438f551bb10Svi 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1439f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1440f551bb10Svi 		for (l = 0; l < naddr; l++) {
1441f551bb10Svi 			sctp_ipif_t	*ipif;
1442f551bb10Svi 
1443f551bb10Svi 			ipif = obj->saddr_ipifp;
1444f551bb10Svi 			scanned++;
1445f551bb10Svi 
1446c31292eeSkcpoon 			if (IN6_ARE_ADDR_EQUAL(&ipif->sctp_ipif_saddr,
1447c31292eeSkcpoon 			    no_del_addr)) {
1448c31292eeSkcpoon 				goto next_obj;
1449c31292eeSkcpoon 			}
1450c31292eeSkcpoon 
1451f551bb10Svi 			/*
1452f551bb10Svi 			 * Delete/mark dontsrc loopback/linklocal addresses and
1453f551bb10Svi 			 * unsupported address.
14541d8c4025Svi 			 * On a clustered node, we trust the clustering module
14551d8c4025Svi 			 * to do the right thing w.r.t loopback addresses, so
14561d8c4025Svi 			 * we ignore loopback addresses in this check.
1457f551bb10Svi 			 */
14581d8c4025Svi 			if ((SCTP_IS_IPIF_LOOPBACK(ipif) &&
14591d8c4025Svi 			    cl_sctp_check_addrs == NULL) ||
14601d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(ipif) ||
1461f551bb10Svi 			    SCTP_UNSUPP_AF(ipif, supp_af)) {
1462f551bb10Svi 				if (!delete) {
1463f551bb10Svi 					obj->saddr_ipif_unconfirmed = 1;
1464f551bb10Svi 					goto next_obj;
1465f551bb10Svi 				}
1466f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1467f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1468f551bb10Svi 				if (scanned < nsaddr) {
1469f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1470f551bb10Svi 					    sctp_ipif_list, obj);
147192baa190SGeorge Shepherd 					sctp_ipif_hash_remove(sctp, ipif,
147292baa190SGeorge Shepherd 					    B_TRUE);
1473f551bb10Svi 					continue;
1474f551bb10Svi 				}
147592baa190SGeorge Shepherd 				sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
1476f551bb10Svi 			}
1477f551bb10Svi 	next_obj:
147892baa190SGeorge Shepherd 			if (scanned >= nsaddr) {
147992baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1480f551bb10Svi 				return;
148192baa190SGeorge Shepherd 			}
1482f551bb10Svi 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
1483f551bb10Svi 			    obj);
1484f551bb10Svi 		}
148592baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1486f551bb10Svi 	}
1487f551bb10Svi }
1488f551bb10Svi 
1489f551bb10Svi 
14907c478bd9Sstevel@tonic-gate /* Get the first valid address from the list. Called with no locks held */
14917c478bd9Sstevel@tonic-gate in6_addr_t
sctp_get_valid_addr(sctp_t * sctp,boolean_t isv6,boolean_t * addr_set)1492c31292eeSkcpoon sctp_get_valid_addr(sctp_t *sctp, boolean_t isv6, boolean_t *addr_set)
14937c478bd9Sstevel@tonic-gate {
14947c478bd9Sstevel@tonic-gate 	int			i;
14957c478bd9Sstevel@tonic-gate 	int			l;
14967c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
14977c478bd9Sstevel@tonic-gate 	int			scanned = 0;
14987c478bd9Sstevel@tonic-gate 	in6_addr_t		addr;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
150192baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
150292baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
150392baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15047c478bd9Sstevel@tonic-gate 			continue;
150592baa190SGeorge Shepherd 		}
15067c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15077c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15087c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
1511f551bb10Svi 			if (!SCTP_DONT_SRC(obj) &&
15127c478bd9Sstevel@tonic-gate 			    ipif->sctp_ipif_isv6 == isv6 &&
1513f551bb10Svi 			    ipif->sctp_ipif_state == SCTP_IPIFS_UP) {
1514c31292eeSkcpoon 				*addr_set = B_TRUE;
151592baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15167c478bd9Sstevel@tonic-gate 				return (ipif->sctp_ipif_saddr);
15177c478bd9Sstevel@tonic-gate 			}
15187c478bd9Sstevel@tonic-gate 			scanned++;
151992baa190SGeorge Shepherd 			if (scanned >= sctp->sctp_nsaddrs) {
152092baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15217c478bd9Sstevel@tonic-gate 				goto got_none;
152292baa190SGeorge Shepherd 			}
15237c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
15247c478bd9Sstevel@tonic-gate 			    obj);
15257c478bd9Sstevel@tonic-gate 		}
152692baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15277c478bd9Sstevel@tonic-gate 	}
15287c478bd9Sstevel@tonic-gate got_none:
15297c478bd9Sstevel@tonic-gate 	/* Need to double check this */
15307c478bd9Sstevel@tonic-gate 	if (isv6 == B_TRUE)
15317c478bd9Sstevel@tonic-gate 		addr =  ipv6_all_zeros;
15327c478bd9Sstevel@tonic-gate 	else
15337c478bd9Sstevel@tonic-gate 		IN6_IPADDR_TO_V4MAPPED(0, &addr);
1534c31292eeSkcpoon 	*addr_set = B_FALSE;
15357c478bd9Sstevel@tonic-gate 	return (addr);
15367c478bd9Sstevel@tonic-gate }
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate /*
15397c478bd9Sstevel@tonic-gate  * Return the list of local addresses of an association.  The parameter
15407c478bd9Sstevel@tonic-gate  * myaddrs is supposed to be either (struct sockaddr_in *) or (struct
15417c478bd9Sstevel@tonic-gate  * sockaddr_in6 *) depending on the address family.
15427c478bd9Sstevel@tonic-gate  */
15437c478bd9Sstevel@tonic-gate int
sctp_getmyaddrs(void * conn,void * myaddrs,int * addrcnt)15447c478bd9Sstevel@tonic-gate sctp_getmyaddrs(void *conn, void *myaddrs, int *addrcnt)
15457c478bd9Sstevel@tonic-gate {
15467c478bd9Sstevel@tonic-gate 	int			i;
15477c478bd9Sstevel@tonic-gate 	int			l;
15487c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
15497c478bd9Sstevel@tonic-gate 	sctp_t			*sctp = (sctp_t *)conn;
1550bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
1551bd670b35SErik Nordmark 	int			family = connp->conn_family;
15527c478bd9Sstevel@tonic-gate 	int			max = *addrcnt;
15537c478bd9Sstevel@tonic-gate 	size_t			added = 0;
15547c478bd9Sstevel@tonic-gate 	struct sockaddr_in6	*sin6;
15557c478bd9Sstevel@tonic-gate 	struct sockaddr_in	*sin4;
15567c478bd9Sstevel@tonic-gate 	int			scanned = 0;
15577c478bd9Sstevel@tonic-gate 	boolean_t		skip_lback = B_FALSE;
1558bd670b35SErik Nordmark 	ip_xmit_attr_t		*ixa = connp->conn_ixa;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	if (sctp->sctp_nsaddrs == 0)
15617c478bd9Sstevel@tonic-gate 		return (EINVAL);
15627c478bd9Sstevel@tonic-gate 
15631d8c4025Svi 	/*
15641d8c4025Svi 	 * Skip loopback addresses for non-loopback assoc., ignore
15651d8c4025Svi 	 * this on a clustered node.
15661d8c4025Svi 	 */
15671d8c4025Svi 	if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback &&
15681d8c4025Svi 	    (cl_sctp_check_addrs == NULL)) {
15697c478bd9Sstevel@tonic-gate 		skip_lback = B_TRUE;
15701d8c4025Svi 	}
15711d8c4025Svi 
15727c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
157392baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
157492baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
157592baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15767c478bd9Sstevel@tonic-gate 			continue;
157792baa190SGeorge Shepherd 		}
15787c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15797c478bd9Sstevel@tonic-gate 		for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15807c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif = obj->saddr_ipifp;
15817c478bd9Sstevel@tonic-gate 			in6_addr_t	addr = ipif->sctp_ipif_saddr;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 			scanned++;
15847c478bd9Sstevel@tonic-gate 			if ((ipif->sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
1585f551bb10Svi 			    SCTP_DONT_SRC(obj) ||
15861d8c4025Svi 			    (SCTP_IS_IPIF_LOOPBACK(ipif) && skip_lback)) {
158792baa190SGeorge Shepherd 				if (scanned >= sctp->sctp_nsaddrs) {
158892baa190SGeorge Shepherd 					rw_exit(&sctp->
158992baa190SGeorge Shepherd 					    sctp_saddrs[i].ipif_hash_lock);
15907c478bd9Sstevel@tonic-gate 					goto done;
159192baa190SGeorge Shepherd 				}
15927c478bd9Sstevel@tonic-gate 				obj = list_next(&sctp->sctp_saddrs[i].
15937c478bd9Sstevel@tonic-gate 				    sctp_ipif_list, obj);
15947c478bd9Sstevel@tonic-gate 				continue;
15957c478bd9Sstevel@tonic-gate 			}
15967c478bd9Sstevel@tonic-gate 			switch (family) {
15977c478bd9Sstevel@tonic-gate 			case AF_INET:
15987c478bd9Sstevel@tonic-gate 				sin4 = (struct sockaddr_in *)myaddrs + added;
15997c478bd9Sstevel@tonic-gate 				sin4->sin_family = AF_INET;
1600bd670b35SErik Nordmark 				sin4->sin_port = connp->conn_lport;
16017c478bd9Sstevel@tonic-gate 				IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
16027c478bd9Sstevel@tonic-gate 				break;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 			case AF_INET6:
16057c478bd9Sstevel@tonic-gate 				sin6 = (struct sockaddr_in6 *)myaddrs + added;
16067c478bd9Sstevel@tonic-gate 				sin6->sin6_family = AF_INET6;
1607bd670b35SErik Nordmark 				sin6->sin6_port = connp->conn_lport;
16087c478bd9Sstevel@tonic-gate 				sin6->sin6_addr = addr;
1609bd670b35SErik Nordmark 				/*
1610bd670b35SErik Nordmark 				 * Note that flowinfo is only returned for
1611bd670b35SErik Nordmark 				 * getpeername just like for TCP and UDP.
1612bd670b35SErik Nordmark 				 */
1613bd670b35SErik Nordmark 				sin6->sin6_flowinfo = 0;
1614bd670b35SErik Nordmark 
1615bd670b35SErik Nordmark 				if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
1616bd670b35SErik Nordmark 				    (ixa->ixa_flags & IXAF_SCOPEID_SET))
1617bd670b35SErik Nordmark 					sin6->sin6_scope_id = ixa->ixa_scopeid;
1618bd670b35SErik Nordmark 				else
1619bd670b35SErik Nordmark 					sin6->sin6_scope_id = 0;
1620bd670b35SErik Nordmark 				sin6->__sin6_src_id = 0;
16217c478bd9Sstevel@tonic-gate 				break;
16227c478bd9Sstevel@tonic-gate 			}
16237c478bd9Sstevel@tonic-gate 			added++;
162492baa190SGeorge Shepherd 			if (added >= max || scanned >= sctp->sctp_nsaddrs) {
162592baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16267c478bd9Sstevel@tonic-gate 				goto done;
162792baa190SGeorge Shepherd 			}
16287c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
16297c478bd9Sstevel@tonic-gate 			    obj);
16307c478bd9Sstevel@tonic-gate 		}
163192baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16327c478bd9Sstevel@tonic-gate 	}
16337c478bd9Sstevel@tonic-gate done:
16347c478bd9Sstevel@tonic-gate 	*addrcnt = added;
16357c478bd9Sstevel@tonic-gate 	return (0);
16367c478bd9Sstevel@tonic-gate }
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate /*
1639df19b344Svi  * Given the supported address family, walk through the source address list
1640df19b344Svi  * and return the total length of the available addresses. If 'p' is not
1641df19b344Svi  * null, construct the parameter list for the addresses in 'p'.
1642f551bb10Svi  * 'modify' will only be set when we want the source address list to
1643f551bb10Svi  * be modified. The source address list will be modified only when
1644f551bb10Svi  * generating an INIT chunk. For generating an INIT-ACK 'modify' will
1645f551bb10Svi  * be false since the 'sctp' will be that of the listener.
16467c478bd9Sstevel@tonic-gate  */
16477c478bd9Sstevel@tonic-gate size_t
sctp_saddr_info(sctp_t * sctp,int supp_af,uchar_t * p,boolean_t modify)1648f551bb10Svi sctp_saddr_info(sctp_t *sctp, int supp_af, uchar_t *p, boolean_t modify)
16497c478bd9Sstevel@tonic-gate {
16507c478bd9Sstevel@tonic-gate 	int			i;
16517c478bd9Sstevel@tonic-gate 	int			l;
16527c478bd9Sstevel@tonic-gate 	sctp_saddr_ipif_t	*obj;
1653df19b344Svi 	size_t			paramlen = 0;
16547c478bd9Sstevel@tonic-gate 	sctp_parm_hdr_t		*hdr;
16557c478bd9Sstevel@tonic-gate 	int			scanned = 0;
1656f551bb10Svi 	int			naddr;
1657f551bb10Svi 	int			nsaddr;
16581d8c4025Svi 	boolean_t		del_ll = B_FALSE;
16591d8c4025Svi 	boolean_t		del_lb = B_FALSE;
16601d8c4025Svi 
16611d8c4025Svi 
16621d8c4025Svi 	/*
16631d8c4025Svi 	 * On a clustered node don't bother changing anything
16641d8c4025Svi 	 * on the loopback interface.
16651d8c4025Svi 	 */
16661d8c4025Svi 	if (modify && !sctp->sctp_loopback && (cl_sctp_check_addrs == NULL))
16671d8c4025Svi 		del_lb = B_TRUE;
1668f551bb10Svi 
16691d8c4025Svi 	if (modify && !sctp->sctp_linklocal)
16701d8c4025Svi 		del_ll = B_TRUE;
16717c478bd9Sstevel@tonic-gate 
1672f551bb10Svi 	nsaddr = sctp->sctp_nsaddrs;
16737c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
167492baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
167592baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[i].ipif_count == 0) {
167692baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16777c478bd9Sstevel@tonic-gate 			continue;
167892baa190SGeorge Shepherd 		}
16797c478bd9Sstevel@tonic-gate 		obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1680f551bb10Svi 		naddr = sctp->sctp_saddrs[i].ipif_count;
1681f551bb10Svi 		for (l = 0; l < naddr; l++) {
16827c478bd9Sstevel@tonic-gate 			in6_addr_t	addr;
16837c478bd9Sstevel@tonic-gate 			sctp_ipif_t	*ipif;
16841d8c4025Svi 			boolean_t	ipif_lb;
16851d8c4025Svi 			boolean_t	ipif_ll;
1686f551bb10Svi 			boolean_t	unsupp_af;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 			ipif = obj->saddr_ipifp;
16897c478bd9Sstevel@tonic-gate 			scanned++;
1690f551bb10Svi 
16911d8c4025Svi 			ipif_lb = SCTP_IS_IPIF_LOOPBACK(ipif);
16921d8c4025Svi 			ipif_ll = SCTP_IS_IPIF_LINKLOCAL(ipif);
1693f551bb10Svi 			unsupp_af = SCTP_UNSUPP_AF(ipif, supp_af);
1694f551bb10Svi 			/*
1695f551bb10Svi 			 * We need to either delete or skip loopback/linklocal
16961d8c4025Svi 			 * or unsupported addresses, if required.
1697f551bb10Svi 			 */
16981d8c4025Svi 			if ((ipif_ll && del_ll) || (ipif_lb && del_lb) ||
16991d8c4025Svi 			    (unsupp_af && modify)) {
1700f551bb10Svi 				if (sctp->sctp_bound_to_all == 1)
1701f551bb10Svi 					sctp->sctp_bound_to_all = 0;
1702f551bb10Svi 				if (scanned < nsaddr) {
1703f551bb10Svi 					obj = list_next(&sctp->sctp_saddrs[i].
1704f551bb10Svi 					    sctp_ipif_list, obj);
170592baa190SGeorge Shepherd 					sctp_ipif_hash_remove(sctp, ipif,
170692baa190SGeorge Shepherd 					    B_TRUE);
1707f551bb10Svi 					continue;
1708f551bb10Svi 				}
170992baa190SGeorge Shepherd 				sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
171092baa190SGeorge Shepherd 
1711f551bb10Svi 				goto next_addr;
17121d8c4025Svi 			} else if (ipif_ll || unsupp_af ||
17131d8c4025Svi 			    (ipif_lb && (cl_sctp_check_addrs == NULL))) {
1714df19b344Svi 				goto next_addr;
17157c478bd9Sstevel@tonic-gate 			}
1716f551bb10Svi 
1717f551bb10Svi 			if (!SCTP_IPIF_USABLE(ipif->sctp_ipif_state))
1718f551bb10Svi 				goto next_addr;
1719df19b344Svi 			if (p != NULL)
1720df19b344Svi 				hdr = (sctp_parm_hdr_t *)(p + paramlen);
17217c478bd9Sstevel@tonic-gate 			addr = ipif->sctp_ipif_saddr;
1722f551bb10Svi 			if (!ipif->sctp_ipif_isv6) {
17237c478bd9Sstevel@tonic-gate 				struct in_addr	*v4;
17247c478bd9Sstevel@tonic-gate 
1725df19b344Svi 				if (p != NULL) {
1726df19b344Svi 					hdr->sph_type = htons(PARM_ADDR4);
1727df19b344Svi 					hdr->sph_len = htons(PARM_ADDR4_LEN);
1728df19b344Svi 					v4 = (struct in_addr *)(hdr + 1);
1729df19b344Svi 					IN6_V4MAPPED_TO_INADDR(&addr, v4);
1730df19b344Svi 				}
1731df19b344Svi 				paramlen += PARM_ADDR4_LEN;
1732f551bb10Svi 			} else {
1733df19b344Svi 				if (p != NULL) {
1734df19b344Svi 					hdr->sph_type = htons(PARM_ADDR6);
1735df19b344Svi 					hdr->sph_len = htons(PARM_ADDR6_LEN);
1736df19b344Svi 					bcopy(&addr, hdr + 1, sizeof (addr));
1737df19b344Svi 				}
1738df19b344Svi 				paramlen += PARM_ADDR6_LEN;
17397c478bd9Sstevel@tonic-gate 			}
1740df19b344Svi next_addr:
174192baa190SGeorge Shepherd 			if (scanned >= nsaddr) {
174292baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1743df19b344Svi 				return (paramlen);
174492baa190SGeorge Shepherd 			}
17457c478bd9Sstevel@tonic-gate 			obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
17467c478bd9Sstevel@tonic-gate 			    obj);
17477c478bd9Sstevel@tonic-gate 		}
174892baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
17497c478bd9Sstevel@tonic-gate 	}
1750df19b344Svi 	return (paramlen);
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate 
17531d8c4025Svi /*
17541d8c4025Svi  * This is used on a clustered node to obtain a list of addresses, the list
17551d8c4025Svi  * consists of sockaddr_in structs for v4 and sockaddr_in6 for v6. The list
17561d8c4025Svi  * is then passed onto the clustering module which sends back the correct
17571d8c4025Svi  * list based on the port info. Regardless of the input, i.e INADDR_ANY
17581d8c4025Svi  * or specific address(es), we create the list since it could be modified by
17591d8c4025Svi  * the clustering module. When given a list of addresses, we simply
17601d8c4025Svi  * create the list of sockaddr_in or sockaddr_in6 structs using those
17611d8c4025Svi  * addresses. If there is an INADDR_ANY in the input list, or if the
17621d8c4025Svi  * input is INADDR_ANY, we create a list of sockaddr_in or sockaddr_in6
17631d8c4025Svi  * structs consisting all the addresses in the global interface list
17641d8c4025Svi  * except those that are hosted on the loopback interface. We create
17651d8c4025Svi  * a list of sockaddr_in[6] structs just so that it can be directly input
17661d8c4025Svi  * to sctp_valid_addr_list() once the clustering module has processed it.
17671d8c4025Svi  */
17681d8c4025Svi int
sctp_get_addrlist(sctp_t * sctp,const void * addrs,uint32_t * addrcnt,uchar_t ** addrlist,int * uspec,size_t * size)17691d8c4025Svi sctp_get_addrlist(sctp_t *sctp, const void *addrs, uint32_t *addrcnt,
17701d8c4025Svi     uchar_t **addrlist, int *uspec, size_t *size)
17711d8c4025Svi {
17721d8c4025Svi 	int			cnt;
17731d8c4025Svi 	int			icnt;
17741d8c4025Svi 	sctp_ipif_t		*sctp_ipif;
17751d8c4025Svi 	struct sockaddr_in	*s4;
17761d8c4025Svi 	struct sockaddr_in6	*s6;
17771d8c4025Svi 	uchar_t			*p;
17781d8c4025Svi 	int			err = 0;
1779f4b3ec61Sdh 	sctp_stack_t		*sctps = sctp->sctp_sctps;
1780bd670b35SErik Nordmark 	conn_t			*connp = sctp->sctp_connp;
17811d8c4025Svi 
17821d8c4025Svi 	*addrlist = NULL;
17831d8c4025Svi 	*size = 0;
17841d8c4025Svi 
17851d8c4025Svi 	/*
17861d8c4025Svi 	 * Create a list of sockaddr_in[6] structs using the input list.
17871d8c4025Svi 	 */
1788bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
17891d8c4025Svi 		*size = sizeof (struct sockaddr_in) * *addrcnt;
17901d8c4025Svi 		*addrlist = kmem_zalloc(*size,  KM_SLEEP);
17911d8c4025Svi 		p = *addrlist;
17921d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
17931d8c4025Svi 			s4 = (struct sockaddr_in *)addrs + cnt;
17941d8c4025Svi 			/*
17951d8c4025Svi 			 * We need to create a list of all the available
17961d8c4025Svi 			 * addresses if there is an INADDR_ANY. However,
17971d8c4025Svi 			 * if we are beyond LISTEN, then this is invalid
17981d8c4025Svi 			 * (see sctp_valid_addr_list(). So, we just fail
17991d8c4025Svi 			 * it here rather than wait till it fails in
18001d8c4025Svi 			 * sctp_valid_addr_list().
18011d8c4025Svi 			 */
18021d8c4025Svi 			if (s4->sin_addr.s_addr == INADDR_ANY) {
18031d8c4025Svi 				kmem_free(*addrlist, *size);
18041d8c4025Svi 				*addrlist = NULL;
18051d8c4025Svi 				*size = 0;
18061d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
18071d8c4025Svi 					*addrcnt = 0;
18081d8c4025Svi 					return (EINVAL);
18091d8c4025Svi 				}
18101d8c4025Svi 				if (uspec != NULL)
18111d8c4025Svi 					*uspec = 1;
18121d8c4025Svi 				goto get_all_addrs;
18131d8c4025Svi 			} else {
18141d8c4025Svi 				bcopy(s4, p, sizeof (*s4));
18151d8c4025Svi 				p += sizeof (*s4);
18161d8c4025Svi 			}
18171d8c4025Svi 		}
18181d8c4025Svi 	} else {
18191d8c4025Svi 		*size = sizeof (struct sockaddr_in6) * *addrcnt;
18201d8c4025Svi 		*addrlist = kmem_zalloc(*size, KM_SLEEP);
18211d8c4025Svi 		p = *addrlist;
18221d8c4025Svi 		for (cnt = 0; cnt < *addrcnt; cnt++) {
18231d8c4025Svi 			s6 = (struct sockaddr_in6 *)addrs + cnt;
18241d8c4025Svi 			/*
18251d8c4025Svi 			 * Comments for INADDR_ANY, above, apply here too.
18261d8c4025Svi 			 */
18271d8c4025Svi 			if (IN6_IS_ADDR_UNSPECIFIED(&s6->sin6_addr)) {
18281d8c4025Svi 				kmem_free(*addrlist, *size);
18291d8c4025Svi 				*size = 0;
18301d8c4025Svi 				*addrlist = NULL;
18311d8c4025Svi 				if (sctp->sctp_state > SCTPS_LISTEN) {
18321d8c4025Svi 					*addrcnt = 0;
18331d8c4025Svi 					return (EINVAL);
18341d8c4025Svi 				}
18351d8c4025Svi 				if (uspec != NULL)
18361d8c4025Svi 					*uspec = 1;
18371d8c4025Svi 				goto get_all_addrs;
18381d8c4025Svi 			} else {
18391d8c4025Svi 				bcopy(addrs, p, sizeof (*s6));
18401d8c4025Svi 				p += sizeof (*s6);
18411d8c4025Svi 			}
18421d8c4025Svi 		}
18431d8c4025Svi 	}
18441d8c4025Svi 	return (err);
18451d8c4025Svi get_all_addrs:
18461d8c4025Svi 
18471d8c4025Svi 	/*
18481d8c4025Svi 	 * Allocate max possible size. We allocate the max. size here because
18491d8c4025Svi 	 * the clustering module could end up adding addresses to the list.
18501d8c4025Svi 	 * We allocate upfront so that the clustering module need to bother
18511d8c4025Svi 	 * re-sizing the list.
18521d8c4025Svi 	 */
1853bd670b35SErik Nordmark 	if (connp->conn_family == AF_INET) {
1854f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in) *
1855f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1856f4b3ec61Sdh 	} else {
1857f4b3ec61Sdh 		*size = sizeof (struct sockaddr_in6) *
1858f4b3ec61Sdh 		    sctps->sctps_g_ipifs_count;
1859f4b3ec61Sdh 	}
18601d8c4025Svi 	*addrlist = kmem_zalloc(*size, KM_SLEEP);
18611d8c4025Svi 	*addrcnt = 0;
18621d8c4025Svi 	p = *addrlist;
1863f4b3ec61Sdh 	rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
18641d8c4025Svi 
18651d8c4025Svi 	/*
18661d8c4025Svi 	 * Walk through the global interface list and add all addresses,
18671d8c4025Svi 	 * except those that are hosted on loopback interfaces.
18681d8c4025Svi 	 */
18691d8c4025Svi 	for (cnt = 0; cnt <  SCTP_IPIF_HASH; cnt++) {
1870f4b3ec61Sdh 		if (sctps->sctps_g_ipifs[cnt].ipif_count == 0)
18711d8c4025Svi 			continue;
1872f4b3ec61Sdh 		sctp_ipif = list_head(
1873f4b3ec61Sdh 		    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list);
1874f4b3ec61Sdh 		for (icnt = 0;
1875f4b3ec61Sdh 		    icnt < sctps->sctps_g_ipifs[cnt].ipif_count;
1876f4b3ec61Sdh 		    icnt++) {
18771d8c4025Svi 			in6_addr_t	addr;
18781d8c4025Svi 
18791d8c4025Svi 			rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
18801d8c4025Svi 			addr = sctp_ipif->sctp_ipif_saddr;
18811d8c4025Svi 			if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
18821d8c4025Svi 			    !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
18831d8c4025Svi 			    SCTP_IS_IPIF_LOOPBACK(sctp_ipif) ||
18841d8c4025Svi 			    SCTP_IS_IPIF_LINKLOCAL(sctp_ipif) ||
18855d0bc3edSsommerfe 			    !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
1886bd670b35SErik Nordmark 			    (connp->conn_family == AF_INET &&
18871d8c4025Svi 			    sctp_ipif->sctp_ipif_isv6) ||
18881d8c4025Svi 			    (sctp->sctp_connp->conn_ipv6_v6only &&
18891d8c4025Svi 			    !sctp_ipif->sctp_ipif_isv6)) {
18901d8c4025Svi 				rw_exit(&sctp_ipif->sctp_ipif_lock);
18911d8c4025Svi 				sctp_ipif = list_next(
1892f4b3ec61Sdh 				    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
18931d8c4025Svi 				    sctp_ipif);
18941d8c4025Svi 				continue;
18951d8c4025Svi 			}
18961d8c4025Svi 			rw_exit(&sctp_ipif->sctp_ipif_lock);
1897bd670b35SErik Nordmark 			if (connp->conn_family == AF_INET) {
18981d8c4025Svi 				s4 = (struct sockaddr_in *)p;
18991d8c4025Svi 				IN6_V4MAPPED_TO_INADDR(&addr, &s4->sin_addr);
19001d8c4025Svi 				s4->sin_family = AF_INET;
19011d8c4025Svi 				p += sizeof (*s4);
19021d8c4025Svi 			} else {
19031d8c4025Svi 				s6 = (struct sockaddr_in6 *)p;
19041d8c4025Svi 				s6->sin6_addr = addr;
19051d8c4025Svi 				s6->sin6_family = AF_INET6;
19061d8c4025Svi 				s6->sin6_scope_id =
19071d8c4025Svi 				    sctp_ipif->sctp_ipif_ill->sctp_ill_index;
19081d8c4025Svi 				p += sizeof (*s6);
19091d8c4025Svi 			}
19101d8c4025Svi 			(*addrcnt)++;
1911f4b3ec61Sdh 			sctp_ipif = list_next(
1912f4b3ec61Sdh 			    &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
19131d8c4025Svi 			    sctp_ipif);
19141d8c4025Svi 		}
19151d8c4025Svi 	}
1916f4b3ec61Sdh 	rw_exit(&sctps->sctps_g_ipifs_lock);
19171d8c4025Svi 	return (err);
19181d8c4025Svi }
19191d8c4025Svi 
19201d8c4025Svi /*
19211d8c4025Svi  * Get a list of addresses from the source address list. The  caller is
19221d8c4025Svi  * responsible for allocating sufficient buffer for this.
19231d8c4025Svi  */
19241d8c4025Svi void
sctp_get_saddr_list(sctp_t * sctp,uchar_t * p,size_t psize)19251d8c4025Svi sctp_get_saddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
19261d8c4025Svi {
19271d8c4025Svi 	int			cnt;
19281d8c4025Svi 	int			icnt;
19291d8c4025Svi 	sctp_saddr_ipif_t	*obj;
19301d8c4025Svi 	int			naddr;
19311d8c4025Svi 	int			scanned = 0;
19321d8c4025Svi 
19331d8c4025Svi 	for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
193492baa190SGeorge Shepherd 		rw_enter(&sctp->sctp_saddrs[cnt].ipif_hash_lock, RW_READER);
193592baa190SGeorge Shepherd 		if (sctp->sctp_saddrs[cnt].ipif_count == 0) {
193692baa190SGeorge Shepherd 			rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19371d8c4025Svi 			continue;
193892baa190SGeorge Shepherd 		}
19391d8c4025Svi 		obj = list_head(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
19401d8c4025Svi 		naddr = sctp->sctp_saddrs[cnt].ipif_count;
19411d8c4025Svi 		for (icnt = 0; icnt < naddr; icnt++) {
19421d8c4025Svi 			sctp_ipif_t	*ipif;
19431d8c4025Svi 
194492baa190SGeorge Shepherd 			if (psize < sizeof (ipif->sctp_ipif_saddr)) {
194592baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19461d8c4025Svi 				return;
194792baa190SGeorge Shepherd 			}
19481d8c4025Svi 
19491d8c4025Svi 			scanned++;
19501d8c4025Svi 			ipif = obj->saddr_ipifp;
19511d8c4025Svi 			bcopy(&ipif->sctp_ipif_saddr, p,
19521d8c4025Svi 			    sizeof (ipif->sctp_ipif_saddr));
19531d8c4025Svi 			p += sizeof (ipif->sctp_ipif_saddr);
19541d8c4025Svi 			psize -= sizeof (ipif->sctp_ipif_saddr);
195592baa190SGeorge Shepherd 			if (scanned >= sctp->sctp_nsaddrs) {
195692baa190SGeorge Shepherd 				rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19571d8c4025Svi 				return;
195892baa190SGeorge Shepherd 			}
1959f4b3ec61Sdh 			obj = list_next(
1960f4b3ec61Sdh 			    &sctp->sctp_saddrs[icnt].sctp_ipif_list,
19611d8c4025Svi 			    obj);
19621d8c4025Svi 		}
196392baa190SGeorge Shepherd 		rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
19641d8c4025Svi 	}
19651d8c4025Svi }
19661d8c4025Svi 
19671d8c4025Svi /*
19681d8c4025Svi  * Get a list of addresses from the remote address list. The  caller is
19691d8c4025Svi  * responsible for allocating sufficient buffer for this.
19701d8c4025Svi  */
19711d8c4025Svi void
sctp_get_faddr_list(sctp_t * sctp,uchar_t * p,size_t psize)19721d8c4025Svi sctp_get_faddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
19731d8c4025Svi {
19741d8c4025Svi 	sctp_faddr_t	*fp;
19751d8c4025Svi 
19766be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 	for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
19776be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		if (psize < sizeof (fp->sf_faddr))
19781d8c4025Svi 			return;
19796be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		bcopy(&fp->sf_faddr, p, sizeof (fp->sf_faddr));
19806be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		p += sizeof (fp->sf_faddr);
19816be61d4eSchandrasekar marimuthu - Sun Microsystems - Bangalore India 		psize -= sizeof (fp->sf_faddr);
19821d8c4025Svi 	}
19831d8c4025Svi }
19847c478bd9Sstevel@tonic-gate 
1985f4b3ec61Sdh static void
sctp_free_ills(sctp_stack_t * sctps)1986f4b3ec61Sdh sctp_free_ills(sctp_stack_t *sctps)
1987f4b3ec61Sdh {
1988f4b3ec61Sdh 	int			i;
1989f4b3ec61Sdh 	int			l;
1990f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
1991f4b3ec61Sdh 
1992f4b3ec61Sdh 	if (sctps->sctps_ills_count == 0)
1993f4b3ec61Sdh 		return;
1994f4b3ec61Sdh 
1995f4b3ec61Sdh 	for (i = 0; i < SCTP_ILL_HASH; i++) {
1996f4b3ec61Sdh 		sctp_ill = list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
1997f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ills[i].ill_count; l++) {
1998f4b3ec61Sdh 			ASSERT(sctp_ill->sctp_ill_ipifcnt == 0);
1999f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ills[i].sctp_ill_list,
2000f4b3ec61Sdh 			    sctp_ill);
2001f4b3ec61Sdh 			sctps->sctps_ills_count--;
2002f4b3ec61Sdh 			kmem_free(sctp_ill->sctp_ill_name,
2003f4b3ec61Sdh 			    sctp_ill->sctp_ill_name_length);
2004f4b3ec61Sdh 			kmem_free(sctp_ill, sizeof (sctp_ill_t));
2005f4b3ec61Sdh 			sctp_ill =
2006f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
2007f4b3ec61Sdh 		}
2008f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
2009f4b3ec61Sdh 	}
2010f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0);
2011f4b3ec61Sdh }
2012f4b3ec61Sdh 
2013f4b3ec61Sdh static void
sctp_free_ipifs(sctp_stack_t * sctps)2014f4b3ec61Sdh sctp_free_ipifs(sctp_stack_t *sctps)
2015f4b3ec61Sdh {
2016f4b3ec61Sdh 	int			i;
2017f4b3ec61Sdh 	int			l;
2018f4b3ec61Sdh 	sctp_ipif_t	*sctp_ipif;
2019f4b3ec61Sdh 	sctp_ill_t	*sctp_ill;
2020f4b3ec61Sdh 
2021f4b3ec61Sdh 	if (sctps->sctps_g_ipifs_count == 0)
2022f4b3ec61Sdh 		return;
2023f4b3ec61Sdh 
2024f4b3ec61Sdh 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
2025f4b3ec61Sdh 		sctp_ipif = list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2026f4b3ec61Sdh 		for (l = 0; l < sctps->sctps_g_ipifs[i].ipif_count; l++) {
2027f4b3ec61Sdh 			sctp_ill = sctp_ipif->sctp_ipif_ill;
2028f4b3ec61Sdh 
2029f4b3ec61Sdh 			list_remove(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
2030f4b3ec61Sdh 			    sctp_ipif);
2031f4b3ec61Sdh 			sctps->sctps_g_ipifs_count--;
2032*640c1670SJosef 'Jeff' Sipek 			atomic_dec_32(&sctp_ill->sctp_ill_ipifcnt);
2033f4b3ec61Sdh 			kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
2034f4b3ec61Sdh 			sctp_ipif =
2035f4b3ec61Sdh 			    list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2036f4b3ec61Sdh 		}
2037f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
2038f4b3ec61Sdh 	}
2039f4b3ec61Sdh 	ASSERT(sctps->sctps_g_ipifs_count == 0);
2040f4b3ec61Sdh }
2041f4b3ec61Sdh 
2042f4b3ec61Sdh 
20437c478bd9Sstevel@tonic-gate /* Initialize the SCTP ILL list and lock */
20447c478bd9Sstevel@tonic-gate void
sctp_saddr_init(sctp_stack_t * sctps)2045f4b3ec61Sdh sctp_saddr_init(sctp_stack_t *sctps)
20467c478bd9Sstevel@tonic-gate {
20477c478bd9Sstevel@tonic-gate 	int	i;
20487c478bd9Sstevel@tonic-gate 
2049f4b3ec61Sdh 	sctps->sctps_g_ills = kmem_zalloc(sizeof (sctp_ill_hash_t) *
2050f4b3ec61Sdh 	    SCTP_ILL_HASH, KM_SLEEP);
2051f4b3ec61Sdh 	sctps->sctps_g_ipifs = kmem_zalloc(sizeof (sctp_ipif_hash_t) *
2052f4b3ec61Sdh 	    SCTP_IPIF_HASH, KM_SLEEP);
2053f4b3ec61Sdh 
2054f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ills_lock, NULL, RW_DEFAULT, NULL);
2055f4b3ec61Sdh 	rw_init(&sctps->sctps_g_ipifs_lock, NULL, RW_DEFAULT, NULL);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++) {
2058f4b3ec61Sdh 		sctps->sctps_g_ills[i].ill_count = 0;
2059f4b3ec61Sdh 		list_create(&sctps->sctps_g_ills[i].sctp_ill_list,
2060f4b3ec61Sdh 		    sizeof (sctp_ill_t),
20617c478bd9Sstevel@tonic-gate 		    offsetof(sctp_ill_t, sctp_ills));
20627c478bd9Sstevel@tonic-gate 	}
20637c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++) {
2064f4b3ec61Sdh 		sctps->sctps_g_ipifs[i].ipif_count = 0;
2065f4b3ec61Sdh 		list_create(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
20667c478bd9Sstevel@tonic-gate 		    sizeof (sctp_ipif_t), offsetof(sctp_ipif_t, sctp_ipifs));
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate }
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate void
sctp_saddr_fini(sctp_stack_t * sctps)2071f4b3ec61Sdh sctp_saddr_fini(sctp_stack_t *sctps)
20727c478bd9Sstevel@tonic-gate {
20737c478bd9Sstevel@tonic-gate 	int	i;
20747c478bd9Sstevel@tonic-gate 
2075f4b3ec61Sdh 	sctp_free_ipifs(sctps);
2076f4b3ec61Sdh 	sctp_free_ills(sctps);
2077f4b3ec61Sdh 
20787c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_ILL_HASH; i++)
2079f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ills[i].sctp_ill_list);
20807c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCTP_IPIF_HASH; i++)
2081f4b3ec61Sdh 		list_destroy(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2082f4b3ec61Sdh 
2083f4b3ec61Sdh 	ASSERT(sctps->sctps_ills_count == 0 && sctps->sctps_g_ipifs_count == 0);
2084f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ills, sizeof (sctp_ill_hash_t) *
2085f4b3ec61Sdh 	    SCTP_ILL_HASH);
2086f4b3ec61Sdh 	sctps->sctps_g_ills = NULL;
2087f4b3ec61Sdh 	kmem_free(sctps->sctps_g_ipifs, sizeof (sctp_ipif_hash_t) *
2088f4b3ec61Sdh 	    SCTP_IPIF_HASH);
2089f4b3ec61Sdh 	sctps->sctps_g_ipifs = NULL;
2090f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ills_lock);
2091f4b3ec61Sdh 	rw_destroy(&sctps->sctps_g_ipifs_lock);
20927c478bd9Sstevel@tonic-gate }
2093