10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51676Sjpk * Common Development and Distribution License (the "License").
61676Sjpk * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*13009SChandrasekar.Marimuthu@Sun.COM * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/systm.h>
270Sstevel@tonic-gate #include <sys/stream.h>
284311Svi117747 #include <sys/cmn_err.h>
290Sstevel@tonic-gate #include <sys/ddi.h>
300Sstevel@tonic-gate #include <sys/sunddi.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <sys/sysmacros.h>
340Sstevel@tonic-gate #include <sys/list.h>
350Sstevel@tonic-gate
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <netinet/ip6.h>
380Sstevel@tonic-gate #include <netinet/sctp.h>
390Sstevel@tonic-gate
400Sstevel@tonic-gate #include <inet/common.h>
410Sstevel@tonic-gate #include <inet/ip.h>
420Sstevel@tonic-gate #include <inet/ip6.h>
4311042SErik.Nordmark@Sun.COM #include <inet/ip_ire.h>
440Sstevel@tonic-gate #include <inet/ip_if.h>
450Sstevel@tonic-gate #include <inet/ipclassifier.h>
460Sstevel@tonic-gate #include <inet/sctp_ip.h>
470Sstevel@tonic-gate #include "sctp_impl.h"
480Sstevel@tonic-gate #include "sctp_addr.h"
490Sstevel@tonic-gate
500Sstevel@tonic-gate static void sctp_ipif_inactive(sctp_ipif_t *);
510Sstevel@tonic-gate static sctp_ipif_t *sctp_lookup_ipif_addr(in6_addr_t *, boolean_t,
523510Svi117747 zoneid_t, boolean_t, uint_t, uint_t, boolean_t,
533510Svi117747 sctp_stack_t *);
540Sstevel@tonic-gate static int sctp_get_all_ipifs(sctp_t *, int);
55432Svi117747 static int sctp_ipif_hash_insert(sctp_t *, sctp_ipif_t *, int,
563510Svi117747 boolean_t, boolean_t);
5711373SGeorge.Shepherd@Sun.COM static void sctp_ipif_hash_remove(sctp_t *, sctp_ipif_t *,
5811373SGeorge.Shepherd@Sun.COM boolean_t);
594818Skcpoon static void sctp_fix_saddr(sctp_t *, in6_addr_t *);
600Sstevel@tonic-gate static int sctp_compare_ipif_list(sctp_ipif_hash_t *,
610Sstevel@tonic-gate sctp_ipif_hash_t *);
620Sstevel@tonic-gate static int sctp_copy_ipifs(sctp_ipif_hash_t *, sctp_t *, int);
63432Svi117747
643510Svi117747 #define SCTP_ADDR4_HASH(addr) \
653510Svi117747 (((addr) ^ ((addr) >> 8) ^ ((addr) >> 16) ^ ((addr) >> 24)) & \
663510Svi117747 (SCTP_IPIF_HASH - 1))
673510Svi117747
683510Svi117747 #define SCTP_ADDR6_HASH(addr) \
693510Svi117747 (((addr).s6_addr32[3] ^ \
703510Svi117747 (((addr).s6_addr32[3] ^ (addr).s6_addr32[2]) >> 12)) & \
713510Svi117747 (SCTP_IPIF_HASH - 1))
723510Svi117747
733510Svi117747 #define SCTP_IPIF_ADDR_HASH(addr, isv6) \
743510Svi117747 ((isv6) ? SCTP_ADDR6_HASH((addr)) : \
753510Svi117747 SCTP_ADDR4_HASH((addr)._S6_un._S6_u32[3]))
763510Svi117747
770Sstevel@tonic-gate #define SCTP_IPIF_USABLE(sctp_ipif_state) \
780Sstevel@tonic-gate ((sctp_ipif_state) == SCTP_IPIFS_UP || \
79432Svi117747 (sctp_ipif_state) == SCTP_IPIFS_DOWN)
80432Svi117747
81432Svi117747 #define SCTP_IPIF_DISCARD(sctp_ipif_flags) \
82432Svi117747 ((sctp_ipif_flags) & (IPIF_PRIVATE | IPIF_DEPRECATED))
83432Svi117747
84852Svi117747 #define SCTP_IS_IPIF_LOOPBACK(ipif) \
85852Svi117747 ((ipif)->sctp_ipif_ill->sctp_ill_flags & PHYI_LOOPBACK)
86852Svi117747
87852Svi117747 #define SCTP_IS_IPIF_LINKLOCAL(ipif) \
88852Svi117747 ((ipif)->sctp_ipif_isv6 && \
89852Svi117747 IN6_IS_ADDR_LINKLOCAL(&(ipif)->sctp_ipif_saddr))
90432Svi117747
91432Svi117747 #define SCTP_UNSUPP_AF(ipif, supp_af) \
92432Svi117747 ((!(ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V4)) || \
93432Svi117747 ((ipif)->sctp_ipif_isv6 && !((supp_af) & PARM_SUPP_V6)))
940Sstevel@tonic-gate
952263Ssommerfe #define SCTP_IPIF_ZONE_MATCH(sctp, ipif) \
962263Ssommerfe IPCL_ZONE_MATCH((sctp)->sctp_connp, (ipif)->sctp_ipif_zoneid)
972263Ssommerfe
980Sstevel@tonic-gate #define SCTP_ILL_HASH_FN(index) ((index) % SCTP_ILL_HASH)
990Sstevel@tonic-gate #define SCTP_ILL_TO_PHYINDEX(ill) ((ill)->ill_phyint->phyint_ifindex)
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate * SCTP Interface list manipulation functions, locking used.
1030Sstevel@tonic-gate */
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate * Delete an SCTP IPIF from the list if the refcount goes to 0 and it is
1070Sstevel@tonic-gate * marked as condemned. Also, check if the ILL needs to go away.
1080Sstevel@tonic-gate */
1090Sstevel@tonic-gate static void
sctp_ipif_inactive(sctp_ipif_t * sctp_ipif)1100Sstevel@tonic-gate sctp_ipif_inactive(sctp_ipif_t *sctp_ipif)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate sctp_ill_t *sctp_ill;
1133510Svi117747 uint_t hindex;
1140Sstevel@tonic-gate uint_t ill_index;
1153448Sdh155122 sctp_stack_t *sctps = sctp_ipif->sctp_ipif_ill->
1163448Sdh155122 sctp_ill_netstack->netstack_sctp;
1170Sstevel@tonic-gate
1183448Sdh155122 rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
1193448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
1200Sstevel@tonic-gate
1213510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(sctp_ipif->sctp_ipif_saddr,
1223510Svi117747 sctp_ipif->sctp_ipif_isv6);
1233510Svi117747
1240Sstevel@tonic-gate sctp_ill = sctp_ipif->sctp_ipif_ill;
1250Sstevel@tonic-gate ASSERT(sctp_ill != NULL);
1260Sstevel@tonic-gate ill_index = SCTP_ILL_HASH_FN(sctp_ill->sctp_ill_index);
1270Sstevel@tonic-gate if (sctp_ipif->sctp_ipif_state != SCTP_IPIFS_CONDEMNED ||
1280Sstevel@tonic-gate sctp_ipif->sctp_ipif_refcnt != 0) {
1293448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
1303448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
1310Sstevel@tonic-gate return;
1320Sstevel@tonic-gate }
1333510Svi117747 list_remove(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
1343448Sdh155122 sctp_ipif);
1353510Svi117747 sctps->sctps_g_ipifs[hindex].ipif_count--;
1363448Sdh155122 sctps->sctps_g_ipifs_count--;
1370Sstevel@tonic-gate rw_destroy(&sctp_ipif->sctp_ipif_lock);
1380Sstevel@tonic-gate kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate (void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
1413448Sdh155122 if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
1423448Sdh155122 rw_downgrade(&sctps->sctps_g_ipifs_lock);
1430Sstevel@tonic-gate if (sctp_ill->sctp_ill_ipifcnt == 0 &&
1440Sstevel@tonic-gate sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
1453448Sdh155122 list_remove(&sctps->sctps_g_ills[ill_index].
1463448Sdh155122 sctp_ill_list, (void *)sctp_ill);
1473448Sdh155122 sctps->sctps_g_ills[ill_index].ill_count--;
1483448Sdh155122 sctps->sctps_ills_count--;
1490Sstevel@tonic-gate kmem_free(sctp_ill->sctp_ill_name,
1500Sstevel@tonic-gate sctp_ill->sctp_ill_name_length);
1510Sstevel@tonic-gate kmem_free(sctp_ill, sizeof (sctp_ill_t));
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate }
1543448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
1553448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate /*
1590Sstevel@tonic-gate * Lookup an SCTP IPIF given an IP address. Increments sctp_ipif refcnt.
1603510Svi117747 * We are either looking for a IPIF with the given address before
1613510Svi117747 * inserting it into the global list or looking for an IPIF for an
1623510Svi117747 * address given an SCTP. In the former case we always check the zoneid,
1633510Svi117747 * but for the latter case, check_zid could be B_FALSE if the connp
1643510Svi117747 * for the sctp has conn_all_zones set. When looking for an address we
1653510Svi117747 * give preference to one that is up, so even though we may find one that
1663510Svi117747 * is not up we keep looking if there is one up, we hold the down addr
1673510Svi117747 * in backup_ipif in case we don't find one that is up - i.e. we return
1683510Svi117747 * the backup_ipif in that case. Note that if we are looking for. If we
1693510Svi117747 * are specifically looking for an up address, then usable will be set
1703510Svi117747 * to true.
1710Sstevel@tonic-gate */
1720Sstevel@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)1733510Svi117747 sctp_lookup_ipif_addr(in6_addr_t *addr, boolean_t refhold, zoneid_t zoneid,
1743510Svi117747 boolean_t check_zid, uint_t ifindex, uint_t seqid, boolean_t usable,
1753510Svi117747 sctp_stack_t *sctps)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate int j;
1780Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
1793510Svi117747 sctp_ipif_t *backup_ipif = NULL;
1803510Svi117747 int hindex;
1810Sstevel@tonic-gate
1823510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
1833510Svi117747
1843448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
1853510Svi117747 if (sctps->sctps_g_ipifs[hindex].ipif_count == 0) {
1863510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
1873510Svi117747 return (NULL);
1883510Svi117747 }
1893510Svi117747 sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
1903510Svi117747 for (j = 0; j < sctps->sctps_g_ipifs[hindex].ipif_count; j++) {
1913510Svi117747 rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
1923510Svi117747 if ((!check_zid ||
1933510Svi117747 (sctp_ipif->sctp_ipif_zoneid == ALL_ZONES ||
1943510Svi117747 zoneid == sctp_ipif->sctp_ipif_zoneid)) &&
1953510Svi117747 (ifindex == 0 || ifindex ==
1963510Svi117747 sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
1973510Svi117747 ((seqid != 0 && seqid == sctp_ipif->sctp_ipif_id) ||
1983510Svi117747 (IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
1993510Svi117747 addr)))) {
2003510Svi117747 if (!usable || sctp_ipif->sctp_ipif_state ==
2013510Svi117747 SCTP_IPIFS_UP) {
2020Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
2030Sstevel@tonic-gate if (refhold)
2040Sstevel@tonic-gate SCTP_IPIF_REFHOLD(sctp_ipif);
2053448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
2060Sstevel@tonic-gate return (sctp_ipif);
2073510Svi117747 } else if (sctp_ipif->sctp_ipif_state ==
2083510Svi117747 SCTP_IPIFS_DOWN && backup_ipif == NULL) {
2093510Svi117747 backup_ipif = sctp_ipif;
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate }
2123510Svi117747 rw_exit(&sctp_ipif->sctp_ipif_lock);
2133510Svi117747 sctp_ipif = list_next(
2143510Svi117747 &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
2153510Svi117747 }
2163510Svi117747 if (backup_ipif != NULL) {
2173510Svi117747 if (refhold)
2183510Svi117747 SCTP_IPIF_REFHOLD(backup_ipif);
2193510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
2203510Svi117747 return (backup_ipif);
2210Sstevel@tonic-gate }
2223448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
2230Sstevel@tonic-gate return (NULL);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate * Populate the list with all the SCTP ipifs for a given ipversion.
2280Sstevel@tonic-gate * Increments sctp_ipif refcnt.
2290Sstevel@tonic-gate * Called with no locks held.
2300Sstevel@tonic-gate */
2310Sstevel@tonic-gate static int
sctp_get_all_ipifs(sctp_t * sctp,int sleep)2320Sstevel@tonic-gate sctp_get_all_ipifs(sctp_t *sctp, int sleep)
2330Sstevel@tonic-gate {
2340Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
2350Sstevel@tonic-gate int i;
2360Sstevel@tonic-gate int j;
2370Sstevel@tonic-gate int error = 0;
2388903SVenu.Iyer@Sun.COM sctp_stack_t *sctps = sctp->sctp_sctps;
2398903SVenu.Iyer@Sun.COM boolean_t isv6;
24011042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
2410Sstevel@tonic-gate
2423448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
2430Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
2443448Sdh155122 if (sctps->sctps_g_ipifs[i].ipif_count == 0)
2450Sstevel@tonic-gate continue;
2463448Sdh155122 sctp_ipif = list_head(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
2473448Sdh155122 for (j = 0; j < sctps->sctps_g_ipifs[i].ipif_count; j++) {
2480Sstevel@tonic-gate rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
2498903SVenu.Iyer@Sun.COM isv6 = sctp_ipif->sctp_ipif_isv6;
250432Svi117747 if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
2510Sstevel@tonic-gate !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
2522263Ssommerfe !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
2538903SVenu.Iyer@Sun.COM SCTP_IS_ADDR_UNSPEC(!isv6,
2548903SVenu.Iyer@Sun.COM sctp_ipif->sctp_ipif_saddr) ||
25511042SErik.Nordmark@Sun.COM (connp->conn_family == AF_INET && isv6) ||
25611042SErik.Nordmark@Sun.COM (connp->conn_ipv6_v6only && !isv6)) {
2570Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
2580Sstevel@tonic-gate sctp_ipif = list_next(
2593448Sdh155122 &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2603448Sdh155122 sctp_ipif);
2610Sstevel@tonic-gate continue;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
2640Sstevel@tonic-gate SCTP_IPIF_REFHOLD(sctp_ipif);
265432Svi117747 error = sctp_ipif_hash_insert(sctp, sctp_ipif, sleep,
2663510Svi117747 B_FALSE, B_FALSE);
2673510Svi117747 if (error != 0 && error != EALREADY)
2680Sstevel@tonic-gate goto free_stuff;
2693448Sdh155122 sctp_ipif = list_next(
2703448Sdh155122 &sctps->sctps_g_ipifs[i].sctp_ipif_list,
2710Sstevel@tonic-gate sctp_ipif);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate }
2743448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
2750Sstevel@tonic-gate return (0);
2760Sstevel@tonic-gate free_stuff:
2773448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
2780Sstevel@tonic-gate sctp_free_saddrs(sctp);
2790Sstevel@tonic-gate return (ENOMEM);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate * Given a list of address, fills in the list of SCTP ipifs if all the addresses
2840Sstevel@tonic-gate * are present in the SCTP interface list, return number of addresses filled
285852Svi117747 * or error. If the caller wants the list of addresses, it sends a pre-allocated
286852Svi117747 * buffer - list. Currently, this list is only used on a clustered node when
287852Svi117747 * the SCTP is in the listen state (from sctp_bind_add()). When called on a
288852Svi117747 * clustered node, the input is always a list of addresses (even if the
289852Svi117747 * original bind() was to INADDR_ANY).
2900Sstevel@tonic-gate * Called with no locks held.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate int
sctp_valid_addr_list(sctp_t * sctp,const void * addrs,uint32_t addrcnt,uchar_t * list,size_t lsize)293852Svi117747 sctp_valid_addr_list(sctp_t *sctp, const void *addrs, uint32_t addrcnt,
294852Svi117747 uchar_t *list, size_t lsize)
2950Sstevel@tonic-gate {
2960Sstevel@tonic-gate struct sockaddr_in *sin4;
2970Sstevel@tonic-gate struct sockaddr_in6 *sin6;
2980Sstevel@tonic-gate struct in_addr *addr4;
2990Sstevel@tonic-gate in6_addr_t addr;
3000Sstevel@tonic-gate int cnt;
3010Sstevel@tonic-gate int err = 0;
3020Sstevel@tonic-gate int saddr_cnt = 0;
3030Sstevel@tonic-gate sctp_ipif_t *ipif;
3040Sstevel@tonic-gate boolean_t bind_to_all = B_FALSE;
3050Sstevel@tonic-gate boolean_t check_addrs = B_FALSE;
3060Sstevel@tonic-gate boolean_t check_lport = B_FALSE;
307852Svi117747 uchar_t *p = list;
30811042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate /*
3110Sstevel@tonic-gate * Need to check for port and address depending on the state.
3120Sstevel@tonic-gate * After a socket is bound, we need to make sure that subsequent
3130Sstevel@tonic-gate * bindx() has correct port. After an association is established,
3140Sstevel@tonic-gate * we need to check for changing the bound address to invalid
3150Sstevel@tonic-gate * addresses.
3160Sstevel@tonic-gate */
3170Sstevel@tonic-gate if (sctp->sctp_state >= SCTPS_BOUND) {
3180Sstevel@tonic-gate check_lport = B_TRUE;
3190Sstevel@tonic-gate if (sctp->sctp_state > SCTPS_LISTEN)
3200Sstevel@tonic-gate check_addrs = B_TRUE;
3210Sstevel@tonic-gate }
322852Svi117747
3230Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
3240Sstevel@tonic-gate mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
3250Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
3260Sstevel@tonic-gate mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
3270Sstevel@tonic-gate for (cnt = 0; cnt < addrcnt; cnt++) {
3280Sstevel@tonic-gate boolean_t lookup_saddr = B_TRUE;
329852Svi117747 uint_t ifindex = 0;
3300Sstevel@tonic-gate
33111042SErik.Nordmark@Sun.COM switch (connp->conn_family) {
3320Sstevel@tonic-gate case AF_INET:
3330Sstevel@tonic-gate sin4 = (struct sockaddr_in *)addrs + cnt;
3340Sstevel@tonic-gate if (sin4->sin_family != AF_INET || (check_lport &&
33511042SErik.Nordmark@Sun.COM sin4->sin_port != connp->conn_lport)) {
3360Sstevel@tonic-gate err = EINVAL;
3370Sstevel@tonic-gate goto free_ret;
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate addr4 = &sin4->sin_addr;
3400Sstevel@tonic-gate if (check_addrs &&
3410Sstevel@tonic-gate (addr4->s_addr == INADDR_ANY ||
3420Sstevel@tonic-gate addr4->s_addr == INADDR_BROADCAST ||
3435215Skcpoon CLASSD(addr4->s_addr))) {
3440Sstevel@tonic-gate err = EINVAL;
3450Sstevel@tonic-gate goto free_ret;
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(addr4, &addr);
3480Sstevel@tonic-gate if (!check_addrs && addr4->s_addr == INADDR_ANY) {
3490Sstevel@tonic-gate lookup_saddr = B_FALSE;
3500Sstevel@tonic-gate bind_to_all = B_TRUE;
3510Sstevel@tonic-gate }
3520Sstevel@tonic-gate
3530Sstevel@tonic-gate break;
3540Sstevel@tonic-gate case AF_INET6:
3550Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addrs + cnt;
3560Sstevel@tonic-gate if (sin6->sin6_family != AF_INET6 || (check_lport &&
35711042SErik.Nordmark@Sun.COM sin6->sin6_port != connp->conn_lport)) {
3580Sstevel@tonic-gate err = EINVAL;
3590Sstevel@tonic-gate goto free_ret;
3600Sstevel@tonic-gate }
3610Sstevel@tonic-gate addr = sin6->sin6_addr;
362852Svi117747 /* Contains the interface index */
363852Svi117747 ifindex = sin6->sin6_scope_id;
36411042SErik.Nordmark@Sun.COM if (connp->conn_ipv6_v6only &&
3650Sstevel@tonic-gate IN6_IS_ADDR_V4MAPPED(&addr)) {
3660Sstevel@tonic-gate err = EAFNOSUPPORT;
3670Sstevel@tonic-gate goto free_ret;
3680Sstevel@tonic-gate }
3690Sstevel@tonic-gate if (check_addrs &&
3700Sstevel@tonic-gate (IN6_IS_ADDR_LINKLOCAL(&addr) ||
3710Sstevel@tonic-gate IN6_IS_ADDR_MULTICAST(&addr) ||
3720Sstevel@tonic-gate IN6_IS_ADDR_UNSPECIFIED(&addr))) {
3730Sstevel@tonic-gate err = EINVAL;
3740Sstevel@tonic-gate goto free_ret;
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate if (!check_addrs && IN6_IS_ADDR_UNSPECIFIED(&addr)) {
3770Sstevel@tonic-gate lookup_saddr = B_FALSE;
3780Sstevel@tonic-gate bind_to_all = B_TRUE;
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate break;
3820Sstevel@tonic-gate default:
3830Sstevel@tonic-gate err = EAFNOSUPPORT;
3840Sstevel@tonic-gate goto free_ret;
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate if (lookup_saddr) {
3873510Svi117747 ipif = sctp_lookup_ipif_addr(&addr, B_TRUE,
38811042SErik.Nordmark@Sun.COM IPCL_ZONEID(connp), !connp->conn_allzones,
3893510Svi117747 ifindex, 0, B_TRUE, sctp->sctp_sctps);
3900Sstevel@tonic-gate if (ipif == NULL) {
3910Sstevel@tonic-gate /* Address not in the list */
3920Sstevel@tonic-gate err = EINVAL;
3930Sstevel@tonic-gate goto free_ret;
394852Svi117747 } else if (check_addrs && SCTP_IS_IPIF_LOOPBACK(ipif) &&
395852Svi117747 cl_sctp_check_addrs == NULL) {
3960Sstevel@tonic-gate SCTP_IPIF_REFRELE(ipif);
3970Sstevel@tonic-gate err = EINVAL;
3980Sstevel@tonic-gate goto free_ret;
3990Sstevel@tonic-gate }
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate if (!bind_to_all) {
402432Svi117747 /*
403432Svi117747 * If an address is added after association setup,
404432Svi117747 * we need to wait for the peer to send us an ASCONF
405432Svi117747 * ACK before we can start using it.
406432Svi117747 * saddr_ipif_dontsrc will be reset (to 0) when we
407432Svi117747 * get the ASCONF ACK for this address.
408432Svi117747 */
409432Svi117747 err = sctp_ipif_hash_insert(sctp, ipif, KM_SLEEP,
4103510Svi117747 check_addrs ? B_TRUE : B_FALSE, B_FALSE);
4110Sstevel@tonic-gate if (err != 0) {
4120Sstevel@tonic-gate SCTP_IPIF_REFRELE(ipif);
4130Sstevel@tonic-gate if (check_addrs && err == EALREADY)
4140Sstevel@tonic-gate err = EADDRINUSE;
4150Sstevel@tonic-gate goto free_ret;
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate saddr_cnt++;
418852Svi117747 if (lsize >= sizeof (addr)) {
419852Svi117747 bcopy(&addr, p, sizeof (addr));
420852Svi117747 p += sizeof (addr);
421852Svi117747 lsize -= sizeof (addr);
422852Svi117747 }
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate if (bind_to_all) {
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate * Free whatever we might have added before encountering
4280Sstevel@tonic-gate * inaddr_any.
4290Sstevel@tonic-gate */
4300Sstevel@tonic-gate if (sctp->sctp_nsaddrs > 0) {
4310Sstevel@tonic-gate sctp_free_saddrs(sctp);
4320Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs == 0);
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate err = sctp_get_all_ipifs(sctp, KM_SLEEP);
4350Sstevel@tonic-gate if (err != 0)
4360Sstevel@tonic-gate return (err);
4370Sstevel@tonic-gate sctp->sctp_bound_to_all = 1;
4380Sstevel@tonic-gate }
4390Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
4400Sstevel@tonic-gate mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4410Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
4420Sstevel@tonic-gate mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4430Sstevel@tonic-gate return (0);
4440Sstevel@tonic-gate free_ret:
4450Sstevel@tonic-gate if (saddr_cnt != 0)
4460Sstevel@tonic-gate sctp_del_saddr_list(sctp, addrs, saddr_cnt, B_TRUE);
4470Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
4480Sstevel@tonic-gate mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
4490Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
4500Sstevel@tonic-gate mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
4510Sstevel@tonic-gate return (err);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate static int
sctp_ipif_hash_insert(sctp_t * sctp,sctp_ipif_t * ipif,int sleep,boolean_t dontsrc,boolean_t allow_dup)455432Svi117747 sctp_ipif_hash_insert(sctp_t *sctp, sctp_ipif_t *ipif, int sleep,
4563510Svi117747 boolean_t dontsrc, boolean_t allow_dup)
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate int cnt;
4590Sstevel@tonic-gate sctp_saddr_ipif_t *ipif_obj;
4603510Svi117747 int hindex;
4610Sstevel@tonic-gate
4623510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
4633510Svi117747 ipif->sctp_ipif_isv6);
46411373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
4653510Svi117747 ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
4663510Svi117747 for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
4673510Svi117747 if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
4683510Svi117747 &ipif->sctp_ipif_saddr)) {
4693510Svi117747 if (ipif->sctp_ipif_id !=
4703510Svi117747 ipif_obj->saddr_ipifp->sctp_ipif_id &&
4713510Svi117747 ipif_obj->saddr_ipifp->sctp_ipif_state ==
4723510Svi117747 SCTP_IPIFS_DOWN && ipif->sctp_ipif_state ==
4733510Svi117747 SCTP_IPIFS_UP) {
4743510Svi117747 SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
4753510Svi117747 ipif_obj->saddr_ipifp = ipif;
4763510Svi117747 ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
47711373SGeorge.Shepherd@Sun.COM rw_exit(
47811373SGeorge.Shepherd@Sun.COM &sctp->sctp_saddrs[hindex].ipif_hash_lock);
4793510Svi117747 return (0);
4803510Svi117747 } else if (!allow_dup || ipif->sctp_ipif_id ==
4813510Svi117747 ipif_obj->saddr_ipifp->sctp_ipif_id) {
48211373SGeorge.Shepherd@Sun.COM rw_exit(
48311373SGeorge.Shepherd@Sun.COM &sctp->sctp_saddrs[hindex].ipif_hash_lock);
4843510Svi117747 return (EALREADY);
4853510Svi117747 }
4863510Svi117747 }
4873510Svi117747 ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
4880Sstevel@tonic-gate ipif_obj);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate ipif_obj = kmem_zalloc(sizeof (sctp_saddr_ipif_t), sleep);
4910Sstevel@tonic-gate if (ipif_obj == NULL) {
49211373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
4930Sstevel@tonic-gate /* Need to do something */
4940Sstevel@tonic-gate return (ENOMEM);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate ipif_obj->saddr_ipifp = ipif;
497432Svi117747 ipif_obj->saddr_ipif_dontsrc = dontsrc ? 1 : 0;
4983510Svi117747 list_insert_tail(&sctp->sctp_saddrs[hindex].sctp_ipif_list, ipif_obj);
4993510Svi117747 sctp->sctp_saddrs[hindex].ipif_count++;
5000Sstevel@tonic-gate sctp->sctp_nsaddrs++;
50111373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5020Sstevel@tonic-gate return (0);
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate
5054818Skcpoon /*
5064818Skcpoon * Given a source address, walk through the peer address list to see
5074818Skcpoon * if the source address is being used. If it is, reset that.
50811042SErik.Nordmark@Sun.COM * A cleared saddr will then make sctp_make_mp lookup the destination again
50911042SErik.Nordmark@Sun.COM * and as part of that look for a new source.
5104818Skcpoon */
5114818Skcpoon static void
sctp_fix_saddr(sctp_t * sctp,in6_addr_t * saddr)5124818Skcpoon sctp_fix_saddr(sctp_t *sctp, in6_addr_t *saddr)
5134818Skcpoon {
5144818Skcpoon sctp_faddr_t *fp;
5154818Skcpoon
516*13009SChandrasekar.Marimuthu@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
517*13009SChandrasekar.Marimuthu@Sun.COM if (!IN6_ARE_ADDR_EQUAL(&fp->sf_saddr, saddr))
5184818Skcpoon continue;
519*13009SChandrasekar.Marimuthu@Sun.COM V6_SET_ZERO(fp->sf_saddr);
5204818Skcpoon }
5214818Skcpoon }
5224818Skcpoon
5230Sstevel@tonic-gate static void
sctp_ipif_hash_remove(sctp_t * sctp,sctp_ipif_t * ipif,boolean_t locked)52411373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp_t *sctp, sctp_ipif_t *ipif, boolean_t locked)
5250Sstevel@tonic-gate {
5260Sstevel@tonic-gate int cnt;
5270Sstevel@tonic-gate sctp_saddr_ipif_t *ipif_obj;
5283510Svi117747 int hindex;
5290Sstevel@tonic-gate
5303510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(ipif->sctp_ipif_saddr,
5313510Svi117747 ipif->sctp_ipif_isv6);
53211373SGeorge.Shepherd@Sun.COM if (!locked)
53311373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_WRITER);
5343510Svi117747 ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
5353510Svi117747 for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
5363510Svi117747 if (IN6_ARE_ADDR_EQUAL(&ipif_obj->saddr_ipifp->sctp_ipif_saddr,
5373510Svi117747 &ipif->sctp_ipif_saddr)) {
5383510Svi117747 list_remove(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5390Sstevel@tonic-gate ipif_obj);
5403510Svi117747 sctp->sctp_saddrs[hindex].ipif_count--;
5410Sstevel@tonic-gate sctp->sctp_nsaddrs--;
5424818Skcpoon sctp_fix_saddr(sctp, &ipif->sctp_ipif_saddr);
5430Sstevel@tonic-gate SCTP_IPIF_REFRELE(ipif_obj->saddr_ipifp);
5440Sstevel@tonic-gate kmem_free(ipif_obj, sizeof (sctp_saddr_ipif_t));
5450Sstevel@tonic-gate break;
5460Sstevel@tonic-gate }
5473510Svi117747 ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
5480Sstevel@tonic-gate ipif_obj);
5490Sstevel@tonic-gate }
55011373SGeorge.Shepherd@Sun.COM if (!locked)
55111373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate static int
sctp_compare_ipif_list(sctp_ipif_hash_t * list1,sctp_ipif_hash_t * list2)5550Sstevel@tonic-gate sctp_compare_ipif_list(sctp_ipif_hash_t *list1, sctp_ipif_hash_t *list2)
5560Sstevel@tonic-gate {
5570Sstevel@tonic-gate int i;
5580Sstevel@tonic-gate int j;
5590Sstevel@tonic-gate sctp_saddr_ipif_t *obj1;
5600Sstevel@tonic-gate sctp_saddr_ipif_t *obj2;
5610Sstevel@tonic-gate int overlap = 0;
5620Sstevel@tonic-gate
56311373SGeorge.Shepherd@Sun.COM rw_enter(&list1->ipif_hash_lock, RW_READER);
56411373SGeorge.Shepherd@Sun.COM rw_enter(&list2->ipif_hash_lock, RW_READER);
5650Sstevel@tonic-gate obj1 = list_head(&list1->sctp_ipif_list);
5660Sstevel@tonic-gate for (i = 0; i < list1->ipif_count; i++) {
5670Sstevel@tonic-gate obj2 = list_head(&list2->sctp_ipif_list);
5680Sstevel@tonic-gate for (j = 0; j < list2->ipif_count; j++) {
5693510Svi117747 if (IN6_ARE_ADDR_EQUAL(
5703510Svi117747 &obj1->saddr_ipifp->sctp_ipif_saddr,
5713510Svi117747 &obj2->saddr_ipifp->sctp_ipif_saddr)) {
5720Sstevel@tonic-gate overlap++;
5730Sstevel@tonic-gate break;
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate obj2 = list_next(&list2->sctp_ipif_list,
5760Sstevel@tonic-gate obj2);
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate obj1 = list_next(&list1->sctp_ipif_list, obj1);
5790Sstevel@tonic-gate }
58011373SGeorge.Shepherd@Sun.COM rw_exit(&list1->ipif_hash_lock);
58111373SGeorge.Shepherd@Sun.COM rw_exit(&list2->ipif_hash_lock);
5820Sstevel@tonic-gate return (overlap);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate int
sctp_compare_saddrs(sctp_t * sctp1,sctp_t * sctp2)5860Sstevel@tonic-gate sctp_compare_saddrs(sctp_t *sctp1, sctp_t *sctp2)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate int i;
5890Sstevel@tonic-gate int overlap = 0;
5900Sstevel@tonic-gate
5910Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
5920Sstevel@tonic-gate overlap += sctp_compare_ipif_list(&sctp1->sctp_saddrs[i],
5930Sstevel@tonic-gate &sctp2->sctp_saddrs[i]);
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate if (sctp1->sctp_nsaddrs == sctp2->sctp_nsaddrs &&
5970Sstevel@tonic-gate overlap == sctp1->sctp_nsaddrs) {
5980Sstevel@tonic-gate return (SCTP_ADDR_EQUAL);
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate
6010Sstevel@tonic-gate if (overlap == sctp1->sctp_nsaddrs)
6020Sstevel@tonic-gate return (SCTP_ADDR_SUBSET);
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate if (overlap > 0)
6050Sstevel@tonic-gate return (SCTP_ADDR_OVERLAP);
6060Sstevel@tonic-gate
6070Sstevel@tonic-gate return (SCTP_ADDR_DISJOINT);
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate static int
sctp_copy_ipifs(sctp_ipif_hash_t * list1,sctp_t * sctp2,int sleep)6110Sstevel@tonic-gate sctp_copy_ipifs(sctp_ipif_hash_t *list1, sctp_t *sctp2, int sleep)
6120Sstevel@tonic-gate {
6130Sstevel@tonic-gate int i;
6140Sstevel@tonic-gate sctp_saddr_ipif_t *obj;
6150Sstevel@tonic-gate int error = 0;
6160Sstevel@tonic-gate
61711373SGeorge.Shepherd@Sun.COM rw_enter(&list1->ipif_hash_lock, RW_READER);
6180Sstevel@tonic-gate obj = list_head(&list1->sctp_ipif_list);
6190Sstevel@tonic-gate for (i = 0; i < list1->ipif_count; i++) {
6200Sstevel@tonic-gate SCTP_IPIF_REFHOLD(obj->saddr_ipifp);
621432Svi117747 error = sctp_ipif_hash_insert(sctp2, obj->saddr_ipifp, sleep,
6223510Svi117747 B_FALSE, B_FALSE);
6233510Svi117747 ASSERT(error != EALREADY);
62411373SGeorge.Shepherd@Sun.COM if (error != 0) {
62511373SGeorge.Shepherd@Sun.COM rw_exit(&list1->ipif_hash_lock);
6260Sstevel@tonic-gate return (error);
62711373SGeorge.Shepherd@Sun.COM }
6280Sstevel@tonic-gate obj = list_next(&list1->sctp_ipif_list, obj);
6290Sstevel@tonic-gate }
63011373SGeorge.Shepherd@Sun.COM rw_exit(&list1->ipif_hash_lock);
6310Sstevel@tonic-gate return (error);
6320Sstevel@tonic-gate }
6330Sstevel@tonic-gate
6340Sstevel@tonic-gate int
sctp_dup_saddrs(sctp_t * sctp1,sctp_t * sctp2,int sleep)6350Sstevel@tonic-gate sctp_dup_saddrs(sctp_t *sctp1, sctp_t *sctp2, int sleep)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate int error = 0;
6380Sstevel@tonic-gate int i;
6390Sstevel@tonic-gate
640432Svi117747 if (sctp1 == NULL || sctp1->sctp_bound_to_all == 1)
6410Sstevel@tonic-gate return (sctp_get_all_ipifs(sctp2, sleep));
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
64411373SGeorge.Shepherd@Sun.COM rw_enter(&sctp1->sctp_saddrs[i].ipif_hash_lock, RW_READER);
64511373SGeorge.Shepherd@Sun.COM if (sctp1->sctp_saddrs[i].ipif_count == 0) {
64611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6470Sstevel@tonic-gate continue;
64811373SGeorge.Shepherd@Sun.COM }
6490Sstevel@tonic-gate error = sctp_copy_ipifs(&sctp1->sctp_saddrs[i], sctp2, sleep);
6500Sstevel@tonic-gate if (error != 0) {
65111373SGeorge.Shepherd@Sun.COM rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6520Sstevel@tonic-gate sctp_free_saddrs(sctp2);
6530Sstevel@tonic-gate return (error);
6540Sstevel@tonic-gate }
65511373SGeorge.Shepherd@Sun.COM rw_exit(&sctp1->sctp_saddrs[i].ipif_hash_lock);
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate return (0);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate void
sctp_free_saddrs(sctp_t * sctp)6610Sstevel@tonic-gate sctp_free_saddrs(sctp_t *sctp)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate int i;
6640Sstevel@tonic-gate int l;
6650Sstevel@tonic-gate sctp_saddr_ipif_t *obj;
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate if (sctp->sctp_nsaddrs == 0)
6680Sstevel@tonic-gate return;
6690Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
67011373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
67111373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[i].ipif_count == 0) {
67211373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6730Sstevel@tonic-gate continue;
67411373SGeorge.Shepherd@Sun.COM }
6750Sstevel@tonic-gate obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6760Sstevel@tonic-gate for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
6770Sstevel@tonic-gate list_remove(&sctp->sctp_saddrs[i].sctp_ipif_list, obj);
6780Sstevel@tonic-gate SCTP_IPIF_REFRELE(obj->saddr_ipifp);
6790Sstevel@tonic-gate sctp->sctp_nsaddrs--;
6800Sstevel@tonic-gate kmem_free(obj, sizeof (sctp_saddr_ipif_t));
6810Sstevel@tonic-gate obj = list_tail(&sctp->sctp_saddrs[i].sctp_ipif_list);
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate sctp->sctp_saddrs[i].ipif_count = 0;
68411373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
6850Sstevel@tonic-gate }
686432Svi117747 if (sctp->sctp_bound_to_all == 1)
687432Svi117747 sctp->sctp_bound_to_all = 0;
6880Sstevel@tonic-gate ASSERT(sctp->sctp_nsaddrs == 0);
6890Sstevel@tonic-gate }
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * Add/Delete the given ILL from the SCTP ILL list. Called with no locks
6930Sstevel@tonic-gate * held.
6940Sstevel@tonic-gate */
6950Sstevel@tonic-gate void
sctp_update_ill(ill_t * ill,int op)6960Sstevel@tonic-gate sctp_update_ill(ill_t *ill, int op)
6970Sstevel@tonic-gate {
6980Sstevel@tonic-gate int i;
6990Sstevel@tonic-gate sctp_ill_t *sctp_ill = NULL;
7000Sstevel@tonic-gate uint_t index;
7013448Sdh155122 netstack_t *ns = ill->ill_ipst->ips_netstack;
7023448Sdh155122 sctp_stack_t *sctps = ns->netstack_sctp;
7030Sstevel@tonic-gate
7043448Sdh155122 rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7050Sstevel@tonic-gate
7060Sstevel@tonic-gate index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
7073448Sdh155122 sctp_ill = list_head(&sctps->sctps_g_ills[index].sctp_ill_list);
7083448Sdh155122 for (i = 0; i < sctps->sctps_g_ills[index].ill_count; i++) {
7094311Svi117747 if ((sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill)) &&
7104311Svi117747 (sctp_ill->sctp_ill_isv6 == ill->ill_isv6)) {
7110Sstevel@tonic-gate break;
7124311Svi117747 }
7133448Sdh155122 sctp_ill = list_next(&sctps->sctps_g_ills[index].sctp_ill_list,
7140Sstevel@tonic-gate sctp_ill);
7150Sstevel@tonic-gate }
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate switch (op) {
7180Sstevel@tonic-gate case SCTP_ILL_INSERT:
7190Sstevel@tonic-gate if (sctp_ill != NULL) {
7200Sstevel@tonic-gate /* Unmark it if it is condemned */
7210Sstevel@tonic-gate if (sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED)
7220Sstevel@tonic-gate sctp_ill->sctp_ill_state = 0;
7233448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
7240Sstevel@tonic-gate return;
7250Sstevel@tonic-gate }
7260Sstevel@tonic-gate sctp_ill = kmem_zalloc(sizeof (sctp_ill_t), KM_NOSLEEP);
7270Sstevel@tonic-gate /* Need to re-try? */
7280Sstevel@tonic-gate if (sctp_ill == NULL) {
7294311Svi117747 cmn_err(CE_WARN, "sctp_update_ill: error adding "
7304311Svi117747 "ILL %p to SCTP's ILL list", (void *)ill);
7313448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
7320Sstevel@tonic-gate return;
7330Sstevel@tonic-gate }
7343510Svi117747 sctp_ill->sctp_ill_name = kmem_zalloc(ill->ill_name_length,
7353510Svi117747 KM_NOSLEEP);
7360Sstevel@tonic-gate if (sctp_ill->sctp_ill_name == NULL) {
7374311Svi117747 cmn_err(CE_WARN, "sctp_update_ill: error adding "
7384311Svi117747 "ILL %p to SCTP's ILL list", (void *)ill);
7390Sstevel@tonic-gate kmem_free(sctp_ill, sizeof (sctp_ill_t));
7403448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
7410Sstevel@tonic-gate return;
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate bcopy(ill->ill_name, sctp_ill->sctp_ill_name,
7440Sstevel@tonic-gate ill->ill_name_length);
7450Sstevel@tonic-gate sctp_ill->sctp_ill_name_length = ill->ill_name_length;
7460Sstevel@tonic-gate sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
7470Sstevel@tonic-gate sctp_ill->sctp_ill_flags = ill->ill_phyint->phyint_flags;
7483448Sdh155122 sctp_ill->sctp_ill_netstack = ns; /* No netstack_hold */
7494311Svi117747 sctp_ill->sctp_ill_isv6 = ill->ill_isv6;
7503448Sdh155122 list_insert_tail(&sctps->sctps_g_ills[index].sctp_ill_list,
7510Sstevel@tonic-gate (void *)sctp_ill);
7523448Sdh155122 sctps->sctps_g_ills[index].ill_count++;
7533448Sdh155122 sctps->sctps_ills_count++;
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate break;
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate case SCTP_ILL_REMOVE:
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate if (sctp_ill == NULL) {
7603448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
7610Sstevel@tonic-gate return;
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate if (sctp_ill->sctp_ill_ipifcnt == 0) {
7643448Sdh155122 list_remove(&sctps->sctps_g_ills[index].sctp_ill_list,
7650Sstevel@tonic-gate (void *)sctp_ill);
7663448Sdh155122 sctps->sctps_g_ills[index].ill_count--;
7673448Sdh155122 sctps->sctps_ills_count--;
7680Sstevel@tonic-gate kmem_free(sctp_ill->sctp_ill_name,
7690Sstevel@tonic-gate ill->ill_name_length);
7700Sstevel@tonic-gate kmem_free(sctp_ill, sizeof (sctp_ill_t));
7710Sstevel@tonic-gate } else {
7720Sstevel@tonic-gate sctp_ill->sctp_ill_state = SCTP_ILLS_CONDEMNED;
7730Sstevel@tonic-gate }
7740Sstevel@tonic-gate
7750Sstevel@tonic-gate break;
7760Sstevel@tonic-gate }
7773448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate
7804311Svi117747 /*
7814311Svi117747 * The ILL's index is being changed, just remove it from the old list,
7824311Svi117747 * change the SCTP ILL's index and re-insert using the new index.
7834311Svi117747 */
7844311Svi117747 void
sctp_ill_reindex(ill_t * ill,uint_t orig_ill_index)7854311Svi117747 sctp_ill_reindex(ill_t *ill, uint_t orig_ill_index)
7864311Svi117747 {
7874311Svi117747 sctp_ill_t *sctp_ill = NULL;
7884311Svi117747 sctp_ill_t *nxt_sill;
7894311Svi117747 uint_t indx;
7904311Svi117747 uint_t nindx;
7914311Svi117747 boolean_t once = B_FALSE;
7924311Svi117747 netstack_t *ns = ill->ill_ipst->ips_netstack;
7934311Svi117747 sctp_stack_t *sctps = ns->netstack_sctp;
7944311Svi117747
7954311Svi117747 rw_enter(&sctps->sctps_g_ills_lock, RW_WRITER);
7964311Svi117747
7974311Svi117747 indx = SCTP_ILL_HASH_FN(orig_ill_index);
7984311Svi117747 nindx = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
7994311Svi117747 sctp_ill = list_head(&sctps->sctps_g_ills[indx].sctp_ill_list);
8004311Svi117747 while (sctp_ill != NULL) {
8014311Svi117747 nxt_sill = list_next(&sctps->sctps_g_ills[indx].sctp_ill_list,
8024311Svi117747 sctp_ill);
8034311Svi117747 if (sctp_ill->sctp_ill_index == orig_ill_index) {
8044311Svi117747 sctp_ill->sctp_ill_index = SCTP_ILL_TO_PHYINDEX(ill);
8054311Svi117747 /*
8064311Svi117747 * if the new index hashes to the same value, all's
8074311Svi117747 * done.
8084311Svi117747 */
8094311Svi117747 if (nindx != indx) {
8104311Svi117747 list_remove(
8114311Svi117747 &sctps->sctps_g_ills[indx].sctp_ill_list,
8124311Svi117747 (void *)sctp_ill);
8134311Svi117747 sctps->sctps_g_ills[indx].ill_count--;
8144311Svi117747 list_insert_tail(
8154311Svi117747 &sctps->sctps_g_ills[nindx].sctp_ill_list,
8164311Svi117747 (void *)sctp_ill);
8174311Svi117747 sctps->sctps_g_ills[nindx].ill_count++;
8184311Svi117747 }
8194311Svi117747 if (once)
8204311Svi117747 break;
8214311Svi117747 /* We might have one for v4 and for v6 */
8224311Svi117747 once = B_TRUE;
8234311Svi117747 }
8244311Svi117747 sctp_ill = nxt_sill;
8254311Svi117747 }
8264311Svi117747 rw_exit(&sctps->sctps_g_ills_lock);
8274311Svi117747 }
8284311Svi117747
8290Sstevel@tonic-gate /* move ipif from f_ill to t_ill */
8300Sstevel@tonic-gate void
sctp_move_ipif(ipif_t * ipif,ill_t * f_ill,ill_t * t_ill)8310Sstevel@tonic-gate sctp_move_ipif(ipif_t *ipif, ill_t *f_ill, ill_t *t_ill)
8320Sstevel@tonic-gate {
8330Sstevel@tonic-gate sctp_ill_t *fsctp_ill = NULL;
8340Sstevel@tonic-gate sctp_ill_t *tsctp_ill = NULL;
8350Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
8363510Svi117747 uint_t hindex;
8370Sstevel@tonic-gate int i;
8383448Sdh155122 netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack;
8393448Sdh155122 sctp_stack_t *sctps = ns->netstack_sctp;
8400Sstevel@tonic-gate
8413448Sdh155122 rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
8423448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
8430Sstevel@tonic-gate
8443510Svi117747 hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(f_ill));
8453510Svi117747 fsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
8463510Svi117747 for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8474311Svi117747 if (fsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(f_ill) &&
8484311Svi117747 fsctp_ill->sctp_ill_isv6 == f_ill->ill_isv6) {
8490Sstevel@tonic-gate break;
8504311Svi117747 }
8513510Svi117747 fsctp_ill = list_next(
8523510Svi117747 &sctps->sctps_g_ills[hindex].sctp_ill_list, fsctp_ill);
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate
8553510Svi117747 hindex = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(t_ill));
8563510Svi117747 tsctp_ill = list_head(&sctps->sctps_g_ills[hindex].sctp_ill_list);
8573510Svi117747 for (i = 0; i < sctps->sctps_g_ills[hindex].ill_count; i++) {
8584311Svi117747 if (tsctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(t_ill) &&
8594311Svi117747 tsctp_ill->sctp_ill_isv6 == t_ill->ill_isv6) {
8600Sstevel@tonic-gate break;
8614311Svi117747 }
8623510Svi117747 tsctp_ill = list_next(
8633510Svi117747 &sctps->sctps_g_ills[hindex].sctp_ill_list, tsctp_ill);
8640Sstevel@tonic-gate }
8650Sstevel@tonic-gate
8663510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
8673510Svi117747 ipif->ipif_ill->ill_isv6);
8683510Svi117747 sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
8693510Svi117747 for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
8700Sstevel@tonic-gate if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid)
8710Sstevel@tonic-gate break;
8723448Sdh155122 sctp_ipif = list_next(
8733510Svi117747 &sctps->sctps_g_ipifs[hindex].sctp_ipif_list, sctp_ipif);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate /* Should be an ASSERT? */
8760Sstevel@tonic-gate if (fsctp_ill == NULL || tsctp_ill == NULL || sctp_ipif == NULL) {
8770Sstevel@tonic-gate ip1dbg(("sctp_move_ipif: error moving ipif %p from %p to %p\n",
8780Sstevel@tonic-gate (void *)ipif, (void *)f_ill, (void *)t_ill));
8793448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
8803448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
8810Sstevel@tonic-gate return;
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
8840Sstevel@tonic-gate ASSERT(sctp_ipif->sctp_ipif_ill == fsctp_ill);
8850Sstevel@tonic-gate sctp_ipif->sctp_ipif_ill = tsctp_ill;
8860Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
8870Sstevel@tonic-gate (void) atomic_add_32_nv(&fsctp_ill->sctp_ill_ipifcnt, -1);
8880Sstevel@tonic-gate atomic_add_32(&tsctp_ill->sctp_ill_ipifcnt, 1);
8893448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
8903448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
8910Sstevel@tonic-gate }
8920Sstevel@tonic-gate
8933510Svi117747 /*
8943510Svi117747 * Walk the list of SCTPs and find each that has oipif in it's saddr list, and
8953510Svi117747 * if so replace it with nipif.
8963510Svi117747 */
8973510Svi117747 void
sctp_update_saddrs(sctp_ipif_t * oipif,sctp_ipif_t * nipif,int idx,sctp_stack_t * sctps)8983510Svi117747 sctp_update_saddrs(sctp_ipif_t *oipif, sctp_ipif_t *nipif, int idx,
8993510Svi117747 sctp_stack_t *sctps)
9003510Svi117747 {
9013510Svi117747 sctp_t *sctp;
9023510Svi117747 sctp_t *sctp_prev = NULL;
9033510Svi117747 sctp_saddr_ipif_t *sobj;
9043510Svi117747 int count;
9053510Svi117747
9063510Svi117747 mutex_enter(&sctps->sctps_g_lock);
90711042SErik.Nordmark@Sun.COM sctp = list_head(&sctps->sctps_g_list);
9083510Svi117747 while (sctp != NULL && oipif->sctp_ipif_refcnt > 0) {
9093510Svi117747 mutex_enter(&sctp->sctp_reflock);
9103510Svi117747 if (sctp->sctp_condemned ||
9113510Svi117747 sctp->sctp_saddrs[idx].ipif_count <= 0) {
9123510Svi117747 mutex_exit(&sctp->sctp_reflock);
9133510Svi117747 sctp = list_next(&sctps->sctps_g_list, sctp);
9143510Svi117747 continue;
9153510Svi117747 }
9163510Svi117747 sctp->sctp_refcnt++;
9173510Svi117747 mutex_exit(&sctp->sctp_reflock);
9183510Svi117747 mutex_exit(&sctps->sctps_g_lock);
9193510Svi117747 if (sctp_prev != NULL)
9203510Svi117747 SCTP_REFRELE(sctp_prev);
9213510Svi117747
9223510Svi117747 RUN_SCTP(sctp);
9233510Svi117747 sobj = list_head(&sctp->sctp_saddrs[idx].sctp_ipif_list);
9243510Svi117747 for (count = 0; count <
9253510Svi117747 sctp->sctp_saddrs[idx].ipif_count; count++) {
9263510Svi117747 if (sobj->saddr_ipifp == oipif) {
9273510Svi117747 SCTP_IPIF_REFHOLD(nipif);
9283510Svi117747 sobj->saddr_ipifp = nipif;
9293510Svi117747 ASSERT(oipif->sctp_ipif_refcnt > 0);
9303510Svi117747 /* We have the writer lock */
9313510Svi117747 oipif->sctp_ipif_refcnt--;
9323510Svi117747 /*
9333510Svi117747 * Can't have more than one referring
9343510Svi117747 * to the same sctp_ipif.
9353510Svi117747 */
9363510Svi117747 break;
9373510Svi117747 }
9383510Svi117747 sobj = list_next(&sctp->sctp_saddrs[idx].sctp_ipif_list,
9393510Svi117747 sobj);
9403510Svi117747 }
9413510Svi117747 WAKE_SCTP(sctp);
9423510Svi117747 sctp_prev = sctp;
9433510Svi117747 mutex_enter(&sctps->sctps_g_lock);
9443510Svi117747 sctp = list_next(&sctps->sctps_g_list, sctp);
9453510Svi117747 }
9463510Svi117747 mutex_exit(&sctps->sctps_g_lock);
9473510Svi117747 if (sctp_prev != NULL)
9483510Svi117747 SCTP_REFRELE(sctp_prev);
9493510Svi117747 }
9503510Svi117747
9513510Svi117747 /*
9523510Svi117747 * Given an ipif, walk the hash list in the global ipif table and for
9533510Svi117747 * any other SCTP ipif with the same address and non-zero reference, walk
9543510Svi117747 * the SCTP list and update the saddr list, if required, to point to the
9559705SVenu.Iyer@Sun.COM * new SCTP ipif. If it is a loopback interface, then there could be
9569705SVenu.Iyer@Sun.COM * multiple interfaces with 127.0.0.1 if there are zones configured, so
9579705SVenu.Iyer@Sun.COM * check the zoneid in addition to the address.
9583510Svi117747 */
9593510Svi117747 void
sctp_chk_and_updt_saddr(int hindex,sctp_ipif_t * ipif,sctp_stack_t * sctps)9603510Svi117747 sctp_chk_and_updt_saddr(int hindex, sctp_ipif_t *ipif, sctp_stack_t *sctps)
9613510Svi117747 {
9623510Svi117747 int cnt;
9633510Svi117747 sctp_ipif_t *sipif;
9643510Svi117747
9653510Svi117747 ASSERT(sctps->sctps_g_ipifs[hindex].ipif_count > 0);
9663510Svi117747 ASSERT(ipif->sctp_ipif_state == SCTP_IPIFS_UP);
9673510Svi117747
9683510Svi117747 sipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
9693510Svi117747 for (cnt = 0; cnt < sctps->sctps_g_ipifs[hindex].ipif_count; cnt++) {
9703510Svi117747 rw_enter(&sipif->sctp_ipif_lock, RW_WRITER);
9713510Svi117747 if (sipif->sctp_ipif_id != ipif->sctp_ipif_id &&
9723510Svi117747 IN6_ARE_ADDR_EQUAL(&sipif->sctp_ipif_saddr,
9739705SVenu.Iyer@Sun.COM &ipif->sctp_ipif_saddr) && sipif->sctp_ipif_refcnt > 0 &&
9749705SVenu.Iyer@Sun.COM (!SCTP_IS_IPIF_LOOPBACK(ipif) || ipif->sctp_ipif_zoneid ==
9759705SVenu.Iyer@Sun.COM sipif->sctp_ipif_zoneid)) {
9763510Svi117747 /*
9773510Svi117747 * There can only be one address up at any time
9783510Svi117747 * and we are here because ipif has been brought
9793510Svi117747 * up.
9803510Svi117747 */
9813510Svi117747 ASSERT(sipif->sctp_ipif_state != SCTP_IPIFS_UP);
9823510Svi117747 /*
9833510Svi117747 * Someone has a reference to this we need to update to
9843510Svi117747 * point to the new sipif.
9853510Svi117747 */
9863510Svi117747 sctp_update_saddrs(sipif, ipif, hindex, sctps);
9873510Svi117747 }
9883510Svi117747 rw_exit(&sipif->sctp_ipif_lock);
9893510Svi117747 sipif = list_next(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
9903510Svi117747 sipif);
9913510Svi117747 }
9923510Svi117747 }
9933510Svi117747
9943510Svi117747 /*
9953510Svi117747 * Insert a new SCTP ipif using 'ipif'. v6addr is the address that existed
9963510Svi117747 * prior to the current address in 'ipif'. Only when an existing address
9973510Svi117747 * is changed on an IPIF, will v6addr be specified. If the IPIF already
9983510Svi117747 * exists in the global SCTP ipif table, then we either removed it, if
9993510Svi117747 * it doesn't have any existing reference, or mark it condemned otherwise.
10003510Svi117747 * If an address is being brought up (IPIF_UP), then we need to scan
10013510Svi117747 * the SCTP list to check if there is any SCTP that points to the *same*
10023510Svi117747 * address on a different SCTP ipif and update in that case.
10033510Svi117747 */
10043510Svi117747 void
sctp_update_ipif_addr(ipif_t * ipif,in6_addr_t v6addr)10053510Svi117747 sctp_update_ipif_addr(ipif_t *ipif, in6_addr_t v6addr)
10063510Svi117747 {
10073510Svi117747 ill_t *ill = ipif->ipif_ill;
10083510Svi117747 int i;
10093510Svi117747 sctp_ill_t *sctp_ill;
10103510Svi117747 sctp_ill_t *osctp_ill;
10113510Svi117747 sctp_ipif_t *sctp_ipif = NULL;
10123510Svi117747 sctp_ipif_t *osctp_ipif = NULL;
10133510Svi117747 uint_t ill_index;
10143510Svi117747 int hindex;
10153510Svi117747 sctp_stack_t *sctps;
10163510Svi117747
10173510Svi117747 sctps = ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp;
10183510Svi117747
10193510Svi117747 /* Index for new address */
10203510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr, ill->ill_isv6);
10213510Svi117747
10223510Svi117747 /*
10233510Svi117747 * The address on this IPIF is changing, we need to look for
10243510Svi117747 * this old address and mark it condemned, before creating
10253510Svi117747 * one for the new address.
10263510Svi117747 */
10273510Svi117747 osctp_ipif = sctp_lookup_ipif_addr(&v6addr, B_FALSE,
10283510Svi117747 ipif->ipif_zoneid, B_TRUE, SCTP_ILL_TO_PHYINDEX(ill),
10293510Svi117747 ipif->ipif_seqid, B_FALSE, sctps);
10303510Svi117747
10313510Svi117747 rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
10323510Svi117747 rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
10333510Svi117747
10343510Svi117747 ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
10353510Svi117747 sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
10363510Svi117747 for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
10374311Svi117747 if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
10384311Svi117747 sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
10393510Svi117747 break;
10404311Svi117747 }
10413510Svi117747 sctp_ill = list_next(
10423510Svi117747 &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
10433510Svi117747 }
10443510Svi117747
10453510Svi117747 if (sctp_ill == NULL) {
10464311Svi117747 ip1dbg(("sctp_update_ipif_addr: ill not found ..\n"));
10473510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
10483510Svi117747 rw_exit(&sctps->sctps_g_ills_lock);
10494311Svi117747 return;
10503510Svi117747 }
10513510Svi117747
10523510Svi117747 if (osctp_ipif != NULL) {
10533510Svi117747
10543510Svi117747 /* The address is the same? */
10553510Svi117747 if (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, &v6addr)) {
10563510Svi117747 boolean_t chk_n_updt = B_FALSE;
10573510Svi117747
10583510Svi117747 rw_downgrade(&sctps->sctps_g_ipifs_lock);
10593510Svi117747 rw_enter(&osctp_ipif->sctp_ipif_lock, RW_WRITER);
10603510Svi117747 if (ipif->ipif_flags & IPIF_UP &&
10613510Svi117747 osctp_ipif->sctp_ipif_state != SCTP_IPIFS_UP) {
10623510Svi117747 osctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
10633510Svi117747 chk_n_updt = B_TRUE;
10643510Svi117747 } else {
10653510Svi117747 osctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
10663510Svi117747 }
10673510Svi117747 osctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
10683510Svi117747 rw_exit(&osctp_ipif->sctp_ipif_lock);
10693510Svi117747 if (chk_n_updt) {
10703510Svi117747 sctp_chk_and_updt_saddr(hindex, osctp_ipif,
10713510Svi117747 sctps);
10723510Svi117747 }
10733510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
10743510Svi117747 rw_exit(&sctps->sctps_g_ills_lock);
10753510Svi117747 return;
10763510Svi117747 }
10773510Svi117747 /*
10783510Svi117747 * We are effectively removing this address from the ILL.
10793510Svi117747 */
10803510Svi117747 if (osctp_ipif->sctp_ipif_refcnt != 0) {
10813510Svi117747 osctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
10823510Svi117747 } else {
10833510Svi117747 list_t *ipif_list;
10843510Svi117747 int ohindex;
10853510Svi117747
10863510Svi117747 osctp_ill = osctp_ipif->sctp_ipif_ill;
10873510Svi117747 /* hash index for the old one */
10883510Svi117747 ohindex = SCTP_IPIF_ADDR_HASH(
10893510Svi117747 osctp_ipif->sctp_ipif_saddr,
10903510Svi117747 osctp_ipif->sctp_ipif_isv6);
10913510Svi117747
10923510Svi117747 ipif_list =
10933510Svi117747 &sctps->sctps_g_ipifs[ohindex].sctp_ipif_list;
10943510Svi117747
10953510Svi117747 list_remove(ipif_list, (void *)osctp_ipif);
10963510Svi117747 sctps->sctps_g_ipifs[ohindex].ipif_count--;
10973510Svi117747 sctps->sctps_g_ipifs_count--;
10983510Svi117747 rw_destroy(&osctp_ipif->sctp_ipif_lock);
10993510Svi117747 kmem_free(osctp_ipif, sizeof (sctp_ipif_t));
11003510Svi117747 (void) atomic_add_32_nv(&osctp_ill->sctp_ill_ipifcnt,
11013510Svi117747 -1);
11023510Svi117747 }
11033510Svi117747 }
11043510Svi117747
11053510Svi117747 sctp_ipif = kmem_zalloc(sizeof (sctp_ipif_t), KM_NOSLEEP);
11063510Svi117747 /* Try again? */
11073510Svi117747 if (sctp_ipif == NULL) {
11084311Svi117747 cmn_err(CE_WARN, "sctp_update_ipif_addr: error adding "
11094311Svi117747 "IPIF %p to SCTP's IPIF list", (void *)ipif);
11103510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
11113510Svi117747 rw_exit(&sctps->sctps_g_ills_lock);
11123510Svi117747 return;
11133510Svi117747 }
11143510Svi117747 sctps->sctps_g_ipifs_count++;
11153510Svi117747 rw_init(&sctp_ipif->sctp_ipif_lock, NULL, RW_DEFAULT, NULL);
11163510Svi117747 sctp_ipif->sctp_ipif_saddr = ipif->ipif_v6lcl_addr;
11173510Svi117747 sctp_ipif->sctp_ipif_ill = sctp_ill;
11183510Svi117747 sctp_ipif->sctp_ipif_isv6 = ill->ill_isv6;
11193510Svi117747 sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
11203510Svi117747 sctp_ipif->sctp_ipif_id = ipif->ipif_seqid;
11213510Svi117747 if (ipif->ipif_flags & IPIF_UP)
11223510Svi117747 sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
11233510Svi117747 else
11243510Svi117747 sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
11253510Svi117747 sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
11263510Svi117747 /*
11273510Svi117747 * We add it to the head so that it is quicker to find good/recent
11283510Svi117747 * additions.
11293510Svi117747 */
11303510Svi117747 list_insert_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11313510Svi117747 (void *)sctp_ipif);
11323510Svi117747 sctps->sctps_g_ipifs[hindex].ipif_count++;
11333510Svi117747 atomic_add_32(&sctp_ill->sctp_ill_ipifcnt, 1);
11343510Svi117747 if (sctp_ipif->sctp_ipif_state == SCTP_IPIFS_UP)
11353510Svi117747 sctp_chk_and_updt_saddr(hindex, sctp_ipif, sctps);
11363510Svi117747 rw_exit(&sctps->sctps_g_ipifs_lock);
11373510Svi117747 rw_exit(&sctps->sctps_g_ills_lock);
11383510Svi117747 }
11393510Svi117747
11400Sstevel@tonic-gate /* Insert, Remove, Mark up or Mark down the ipif */
11410Sstevel@tonic-gate void
sctp_update_ipif(ipif_t * ipif,int op)11420Sstevel@tonic-gate sctp_update_ipif(ipif_t *ipif, int op)
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate ill_t *ill = ipif->ipif_ill;
11450Sstevel@tonic-gate int i;
11460Sstevel@tonic-gate sctp_ill_t *sctp_ill;
11470Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
11480Sstevel@tonic-gate uint_t ill_index;
11493510Svi117747 uint_t hindex;
11503448Sdh155122 netstack_t *ns = ipif->ipif_ill->ill_ipst->ips_netstack;
11513448Sdh155122 sctp_stack_t *sctps = ns->netstack_sctp;
11520Sstevel@tonic-gate
11530Sstevel@tonic-gate ip2dbg(("sctp_update_ipif: %s %d\n", ill->ill_name, ipif->ipif_seqid));
11540Sstevel@tonic-gate
11553448Sdh155122 rw_enter(&sctps->sctps_g_ills_lock, RW_READER);
11563448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_WRITER);
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate ill_index = SCTP_ILL_HASH_FN(SCTP_ILL_TO_PHYINDEX(ill));
11593448Sdh155122 sctp_ill = list_head(&sctps->sctps_g_ills[ill_index].sctp_ill_list);
11603448Sdh155122 for (i = 0; i < sctps->sctps_g_ills[ill_index].ill_count; i++) {
11614311Svi117747 if (sctp_ill->sctp_ill_index == SCTP_ILL_TO_PHYINDEX(ill) &&
11624311Svi117747 sctp_ill->sctp_ill_isv6 == ill->ill_isv6) {
11630Sstevel@tonic-gate break;
11644311Svi117747 }
11653448Sdh155122 sctp_ill = list_next(
11663448Sdh155122 &sctps->sctps_g_ills[ill_index].sctp_ill_list, sctp_ill);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate if (sctp_ill == NULL) {
11693448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
11703448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
11710Sstevel@tonic-gate return;
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate
11743510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(ipif->ipif_v6lcl_addr,
11753510Svi117747 ipif->ipif_ill->ill_isv6);
11763510Svi117747 sctp_ipif = list_head(&sctps->sctps_g_ipifs[hindex].sctp_ipif_list);
11773510Svi117747 for (i = 0; i < sctps->sctps_g_ipifs[hindex].ipif_count; i++) {
11783510Svi117747 if (sctp_ipif->sctp_ipif_id == ipif->ipif_seqid) {
11793510Svi117747 ASSERT(IN6_ARE_ADDR_EQUAL(&sctp_ipif->sctp_ipif_saddr,
11803510Svi117747 &ipif->ipif_v6lcl_addr));
11810Sstevel@tonic-gate break;
11823510Svi117747 }
11833448Sdh155122 sctp_ipif = list_next(
11843510Svi117747 &sctps->sctps_g_ipifs[hindex].sctp_ipif_list,
11850Sstevel@tonic-gate sctp_ipif);
11860Sstevel@tonic-gate }
11873510Svi117747 if (sctp_ipif == NULL) {
11880Sstevel@tonic-gate ip1dbg(("sctp_update_ipif: null sctp_ipif for %d\n", op));
11893448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
11903448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
11910Sstevel@tonic-gate return;
11920Sstevel@tonic-gate }
11933510Svi117747 ASSERT(sctp_ill == sctp_ipif->sctp_ipif_ill);
11940Sstevel@tonic-gate switch (op) {
11950Sstevel@tonic-gate case SCTP_IPIF_REMOVE:
11960Sstevel@tonic-gate {
11970Sstevel@tonic-gate list_t *ipif_list;
11980Sstevel@tonic-gate list_t *ill_list;
11990Sstevel@tonic-gate
12003448Sdh155122 ill_list = &sctps->sctps_g_ills[ill_index].sctp_ill_list;
12013510Svi117747 ipif_list = &sctps->sctps_g_ipifs[hindex].sctp_ipif_list;
12020Sstevel@tonic-gate if (sctp_ipif->sctp_ipif_refcnt != 0) {
12030Sstevel@tonic-gate sctp_ipif->sctp_ipif_state = SCTP_IPIFS_CONDEMNED;
12043448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
12053448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
12060Sstevel@tonic-gate return;
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate list_remove(ipif_list, (void *)sctp_ipif);
12093510Svi117747 sctps->sctps_g_ipifs[hindex].ipif_count--;
12103448Sdh155122 sctps->sctps_g_ipifs_count--;
12110Sstevel@tonic-gate rw_destroy(&sctp_ipif->sctp_ipif_lock);
12120Sstevel@tonic-gate kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
12130Sstevel@tonic-gate (void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt, -1);
12143448Sdh155122 if (rw_tryupgrade(&sctps->sctps_g_ills_lock) != 0) {
12153448Sdh155122 rw_downgrade(&sctps->sctps_g_ipifs_lock);
12160Sstevel@tonic-gate if (sctp_ill->sctp_ill_ipifcnt == 0 &&
12170Sstevel@tonic-gate sctp_ill->sctp_ill_state == SCTP_ILLS_CONDEMNED) {
12180Sstevel@tonic-gate list_remove(ill_list, (void *)sctp_ill);
12193448Sdh155122 sctps->sctps_ills_count--;
12203448Sdh155122 sctps->sctps_g_ills[ill_index].ill_count--;
12210Sstevel@tonic-gate kmem_free(sctp_ill->sctp_ill_name,
12220Sstevel@tonic-gate sctp_ill->sctp_ill_name_length);
12230Sstevel@tonic-gate kmem_free(sctp_ill, sizeof (sctp_ill_t));
12240Sstevel@tonic-gate }
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate break;
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate
12290Sstevel@tonic-gate case SCTP_IPIF_UP:
12300Sstevel@tonic-gate
12313448Sdh155122 rw_downgrade(&sctps->sctps_g_ipifs_lock);
12320Sstevel@tonic-gate rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12330Sstevel@tonic-gate sctp_ipif->sctp_ipif_state = SCTP_IPIFS_UP;
1234432Svi117747 sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12350Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
12363510Svi117747 sctp_chk_and_updt_saddr(hindex, sctp_ipif,
12373510Svi117747 ipif->ipif_ill->ill_ipst->ips_netstack->netstack_sctp);
12380Sstevel@tonic-gate
12390Sstevel@tonic-gate break;
12400Sstevel@tonic-gate
12410Sstevel@tonic-gate case SCTP_IPIF_UPDATE:
12420Sstevel@tonic-gate
12433448Sdh155122 rw_downgrade(&sctps->sctps_g_ipifs_lock);
12440Sstevel@tonic-gate rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12450Sstevel@tonic-gate sctp_ipif->sctp_ipif_zoneid = ipif->ipif_zoneid;
1246432Svi117747 sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12470Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate break;
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate case SCTP_IPIF_DOWN:
12520Sstevel@tonic-gate
12533448Sdh155122 rw_downgrade(&sctps->sctps_g_ipifs_lock);
12540Sstevel@tonic-gate rw_enter(&sctp_ipif->sctp_ipif_lock, RW_WRITER);
12550Sstevel@tonic-gate sctp_ipif->sctp_ipif_state = SCTP_IPIFS_DOWN;
12563510Svi117747 sctp_ipif->sctp_ipif_flags = ipif->ipif_flags;
12570Sstevel@tonic-gate rw_exit(&sctp_ipif->sctp_ipif_lock);
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate break;
12600Sstevel@tonic-gate }
12613448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
12623448Sdh155122 rw_exit(&sctps->sctps_g_ills_lock);
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate /*
12660Sstevel@tonic-gate * SCTP source address list manipulaton, locking not used (except for
12670Sstevel@tonic-gate * sctp locking by the caller.
12680Sstevel@tonic-gate */
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate /* Remove a specific saddr from the list */
12710Sstevel@tonic-gate void
sctp_del_saddr(sctp_t * sctp,sctp_saddr_ipif_t * sp)12720Sstevel@tonic-gate sctp_del_saddr(sctp_t *sctp, sctp_saddr_ipif_t *sp)
12730Sstevel@tonic-gate {
12740Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
12750Sstevel@tonic-gate mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
12760Sstevel@tonic-gate
12770Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
12780Sstevel@tonic-gate mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
12790Sstevel@tonic-gate
128011373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, sp->saddr_ipifp, B_FALSE);
12810Sstevel@tonic-gate
1282432Svi117747 if (sctp->sctp_bound_to_all == 1)
12830Sstevel@tonic-gate sctp->sctp_bound_to_all = 0;
12840Sstevel@tonic-gate
12850Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
12860Sstevel@tonic-gate mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
12890Sstevel@tonic-gate mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate * Delete source address from the existing list. No error checking done here
12940Sstevel@tonic-gate * Called with no locks held.
12950Sstevel@tonic-gate */
12960Sstevel@tonic-gate void
sctp_del_saddr_list(sctp_t * sctp,const void * addrs,int addcnt,boolean_t fanout_locked)12970Sstevel@tonic-gate sctp_del_saddr_list(sctp_t *sctp, const void *addrs, int addcnt,
12980Sstevel@tonic-gate boolean_t fanout_locked)
12990Sstevel@tonic-gate {
13000Sstevel@tonic-gate struct sockaddr_in *sin4;
13010Sstevel@tonic-gate struct sockaddr_in6 *sin6;
13020Sstevel@tonic-gate int cnt;
13030Sstevel@tonic-gate in6_addr_t addr;
13040Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
1305852Svi117747 int ifindex = 0;
130611042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
13070Sstevel@tonic-gate
1308852Svi117747 ASSERT(sctp->sctp_nsaddrs >= addcnt);
13090Sstevel@tonic-gate
13100Sstevel@tonic-gate if (!fanout_locked) {
13110Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
13120Sstevel@tonic-gate mutex_enter(&sctp->sctp_conn_tfp->tf_lock);
13130Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
13140Sstevel@tonic-gate mutex_enter(&sctp->sctp_listen_tfp->tf_lock);
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate for (cnt = 0; cnt < addcnt; cnt++) {
131811042SErik.Nordmark@Sun.COM switch (connp->conn_family) {
13190Sstevel@tonic-gate case AF_INET:
13200Sstevel@tonic-gate sin4 = (struct sockaddr_in *)addrs + cnt;
13210Sstevel@tonic-gate IN6_INADDR_TO_V4MAPPED(&sin4->sin_addr, &addr);
13220Sstevel@tonic-gate break;
13230Sstevel@tonic-gate
13240Sstevel@tonic-gate case AF_INET6:
13250Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)addrs + cnt;
13260Sstevel@tonic-gate addr = sin6->sin6_addr;
1327852Svi117747 ifindex = sin6->sin6_scope_id;
13280Sstevel@tonic-gate break;
13290Sstevel@tonic-gate }
13303510Svi117747 sctp_ipif = sctp_lookup_ipif_addr(&addr, B_FALSE,
133111042SErik.Nordmark@Sun.COM IPCL_ZONEID(connp), !connp->conn_allzones,
13323510Svi117747 ifindex, 0, B_TRUE, sctp->sctp_sctps);
13330Sstevel@tonic-gate ASSERT(sctp_ipif != NULL);
133411373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, sctp_ipif, B_FALSE);
13350Sstevel@tonic-gate }
1336432Svi117747 if (sctp->sctp_bound_to_all == 1)
13370Sstevel@tonic-gate sctp->sctp_bound_to_all = 0;
13380Sstevel@tonic-gate
13390Sstevel@tonic-gate if (!fanout_locked) {
13400Sstevel@tonic-gate if (sctp->sctp_conn_tfp != NULL)
13410Sstevel@tonic-gate mutex_exit(&sctp->sctp_conn_tfp->tf_lock);
13420Sstevel@tonic-gate if (sctp->sctp_listen_tfp != NULL)
13430Sstevel@tonic-gate mutex_exit(&sctp->sctp_listen_tfp->tf_lock);
13440Sstevel@tonic-gate }
13450Sstevel@tonic-gate }
13460Sstevel@tonic-gate
13470Sstevel@tonic-gate /*
13480Sstevel@tonic-gate * Given an address get the corresponding entry from the list
13490Sstevel@tonic-gate * Called with no locks held.
13500Sstevel@tonic-gate */
13510Sstevel@tonic-gate sctp_saddr_ipif_t *
sctp_saddr_lookup(sctp_t * sctp,in6_addr_t * addr,uint_t ifindex)1352852Svi117747 sctp_saddr_lookup(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
13530Sstevel@tonic-gate {
13543510Svi117747 int cnt;
13553510Svi117747 sctp_saddr_ipif_t *ipif_obj;
13563510Svi117747 int hindex;
13570Sstevel@tonic-gate sctp_ipif_t *sctp_ipif;
13580Sstevel@tonic-gate
13593510Svi117747 hindex = SCTP_IPIF_ADDR_HASH(*addr, !IN6_IS_ADDR_V4MAPPED(addr));
136011373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[hindex].ipif_hash_lock, RW_READER);
136111373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[hindex].ipif_count == 0) {
136211373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
13630Sstevel@tonic-gate return (NULL);
136411373SGeorge.Shepherd@Sun.COM }
13650Sstevel@tonic-gate
13663510Svi117747 ipif_obj = list_head(&sctp->sctp_saddrs[hindex].sctp_ipif_list);
13673510Svi117747 for (cnt = 0; cnt < sctp->sctp_saddrs[hindex].ipif_count; cnt++) {
13683510Svi117747 sctp_ipif = ipif_obj->saddr_ipifp;
13693510Svi117747 /*
13703510Svi117747 * Zone check shouldn't be needed.
13713510Svi117747 */
13723510Svi117747 if (IN6_ARE_ADDR_EQUAL(addr, &sctp_ipif->sctp_ipif_saddr) &&
13733510Svi117747 (ifindex == 0 ||
13743510Svi117747 ifindex == sctp_ipif->sctp_ipif_ill->sctp_ill_index) &&
13753510Svi117747 SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state)) {
137611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
13773510Svi117747 return (ipif_obj);
13783510Svi117747 }
13793510Svi117747 ipif_obj = list_next(&sctp->sctp_saddrs[hindex].sctp_ipif_list,
13803510Svi117747 ipif_obj);
13813510Svi117747 }
138211373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[hindex].ipif_hash_lock);
13833510Svi117747 return (NULL);
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate
1386432Svi117747 /* Given an address, add it to the source address list */
1387432Svi117747 int
sctp_saddr_add_addr(sctp_t * sctp,in6_addr_t * addr,uint_t ifindex)1388852Svi117747 sctp_saddr_add_addr(sctp_t *sctp, in6_addr_t *addr, uint_t ifindex)
1389432Svi117747 {
1390432Svi117747 sctp_ipif_t *sctp_ipif;
139111042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
1392432Svi117747
139311042SErik.Nordmark@Sun.COM sctp_ipif = sctp_lookup_ipif_addr(addr, B_TRUE, IPCL_ZONEID(connp),
139411042SErik.Nordmark@Sun.COM !connp->conn_allzones, ifindex, 0, B_TRUE, sctp->sctp_sctps);
1395432Svi117747 if (sctp_ipif == NULL)
1396432Svi117747 return (EINVAL);
1397432Svi117747
13983510Svi117747 if (sctp_ipif_hash_insert(sctp, sctp_ipif, KM_NOSLEEP, B_FALSE,
13993510Svi117747 B_FALSE) != 0) {
1400432Svi117747 SCTP_IPIF_REFRELE(sctp_ipif);
1401432Svi117747 return (EINVAL);
1402432Svi117747 }
1403432Svi117747 return (0);
1404432Svi117747 }
1405432Svi117747
1406432Svi117747 /*
1407432Svi117747 * Remove or mark as dontsrc addresses that are currently not part of the
1408432Svi117747 * association. One would delete addresses when processing an INIT and
1409432Svi117747 * mark as dontsrc when processing an INIT-ACK.
1410432Svi117747 */
1411432Svi117747 void
sctp_check_saddr(sctp_t * sctp,int supp_af,boolean_t delete,in6_addr_t * no_del_addr)14124818Skcpoon sctp_check_saddr(sctp_t *sctp, int supp_af, boolean_t delete,
14134818Skcpoon in6_addr_t *no_del_addr)
1414432Svi117747 {
1415432Svi117747 int i;
1416432Svi117747 int l;
1417432Svi117747 sctp_saddr_ipif_t *obj;
1418432Svi117747 int scanned = 0;
1419432Svi117747 int naddr;
1420432Svi117747 int nsaddr;
142111042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
1422432Svi117747
1423432Svi117747 ASSERT(!sctp->sctp_loopback && !sctp->sctp_linklocal && supp_af != 0);
1424432Svi117747
1425432Svi117747 /*
1426432Svi117747 * Irregardless of the supported address in the INIT, v4
1427432Svi117747 * must be supported.
1428432Svi117747 */
142911042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET)
1430432Svi117747 supp_af = PARM_SUPP_V4;
1431432Svi117747
1432432Svi117747 nsaddr = sctp->sctp_nsaddrs;
1433432Svi117747 for (i = 0; i < SCTP_IPIF_HASH; i++) {
143411373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
143511373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[i].ipif_count == 0) {
143611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1437432Svi117747 continue;
143811373SGeorge.Shepherd@Sun.COM }
1439432Svi117747 obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1440432Svi117747 naddr = sctp->sctp_saddrs[i].ipif_count;
1441432Svi117747 for (l = 0; l < naddr; l++) {
1442432Svi117747 sctp_ipif_t *ipif;
1443432Svi117747
1444432Svi117747 ipif = obj->saddr_ipifp;
1445432Svi117747 scanned++;
1446432Svi117747
14474818Skcpoon if (IN6_ARE_ADDR_EQUAL(&ipif->sctp_ipif_saddr,
14484818Skcpoon no_del_addr)) {
14494818Skcpoon goto next_obj;
14504818Skcpoon }
14514818Skcpoon
1452432Svi117747 /*
1453432Svi117747 * Delete/mark dontsrc loopback/linklocal addresses and
1454432Svi117747 * unsupported address.
1455852Svi117747 * On a clustered node, we trust the clustering module
1456852Svi117747 * to do the right thing w.r.t loopback addresses, so
1457852Svi117747 * we ignore loopback addresses in this check.
1458432Svi117747 */
1459852Svi117747 if ((SCTP_IS_IPIF_LOOPBACK(ipif) &&
1460852Svi117747 cl_sctp_check_addrs == NULL) ||
1461852Svi117747 SCTP_IS_IPIF_LINKLOCAL(ipif) ||
1462432Svi117747 SCTP_UNSUPP_AF(ipif, supp_af)) {
1463432Svi117747 if (!delete) {
1464432Svi117747 obj->saddr_ipif_unconfirmed = 1;
1465432Svi117747 goto next_obj;
1466432Svi117747 }
1467432Svi117747 if (sctp->sctp_bound_to_all == 1)
1468432Svi117747 sctp->sctp_bound_to_all = 0;
1469432Svi117747 if (scanned < nsaddr) {
1470432Svi117747 obj = list_next(&sctp->sctp_saddrs[i].
1471432Svi117747 sctp_ipif_list, obj);
147211373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, ipif,
147311373SGeorge.Shepherd@Sun.COM B_TRUE);
1474432Svi117747 continue;
1475432Svi117747 }
147611373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
1477432Svi117747 }
1478432Svi117747 next_obj:
147911373SGeorge.Shepherd@Sun.COM if (scanned >= nsaddr) {
148011373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1481432Svi117747 return;
148211373SGeorge.Shepherd@Sun.COM }
1483432Svi117747 obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
1484432Svi117747 obj);
1485432Svi117747 }
148611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1487432Svi117747 }
1488432Svi117747 }
1489432Svi117747
1490432Svi117747
14910Sstevel@tonic-gate /* Get the first valid address from the list. Called with no locks held */
14920Sstevel@tonic-gate in6_addr_t
sctp_get_valid_addr(sctp_t * sctp,boolean_t isv6,boolean_t * addr_set)14934818Skcpoon sctp_get_valid_addr(sctp_t *sctp, boolean_t isv6, boolean_t *addr_set)
14940Sstevel@tonic-gate {
14950Sstevel@tonic-gate int i;
14960Sstevel@tonic-gate int l;
14970Sstevel@tonic-gate sctp_saddr_ipif_t *obj;
14980Sstevel@tonic-gate int scanned = 0;
14990Sstevel@tonic-gate in6_addr_t addr;
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
150211373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
150311373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[i].ipif_count == 0) {
150411373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15050Sstevel@tonic-gate continue;
150611373SGeorge.Shepherd@Sun.COM }
15070Sstevel@tonic-gate obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15080Sstevel@tonic-gate for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15090Sstevel@tonic-gate sctp_ipif_t *ipif;
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate ipif = obj->saddr_ipifp;
1512432Svi117747 if (!SCTP_DONT_SRC(obj) &&
15130Sstevel@tonic-gate ipif->sctp_ipif_isv6 == isv6 &&
1514432Svi117747 ipif->sctp_ipif_state == SCTP_IPIFS_UP) {
15154818Skcpoon *addr_set = B_TRUE;
151611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15170Sstevel@tonic-gate return (ipif->sctp_ipif_saddr);
15180Sstevel@tonic-gate }
15190Sstevel@tonic-gate scanned++;
152011373SGeorge.Shepherd@Sun.COM if (scanned >= sctp->sctp_nsaddrs) {
152111373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15220Sstevel@tonic-gate goto got_none;
152311373SGeorge.Shepherd@Sun.COM }
15240Sstevel@tonic-gate obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
15250Sstevel@tonic-gate obj);
15260Sstevel@tonic-gate }
152711373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15280Sstevel@tonic-gate }
15290Sstevel@tonic-gate got_none:
15300Sstevel@tonic-gate /* Need to double check this */
15310Sstevel@tonic-gate if (isv6 == B_TRUE)
15320Sstevel@tonic-gate addr = ipv6_all_zeros;
15330Sstevel@tonic-gate else
15340Sstevel@tonic-gate IN6_IPADDR_TO_V4MAPPED(0, &addr);
15354818Skcpoon *addr_set = B_FALSE;
15360Sstevel@tonic-gate return (addr);
15370Sstevel@tonic-gate }
15380Sstevel@tonic-gate
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate * Return the list of local addresses of an association. The parameter
15410Sstevel@tonic-gate * myaddrs is supposed to be either (struct sockaddr_in *) or (struct
15420Sstevel@tonic-gate * sockaddr_in6 *) depending on the address family.
15430Sstevel@tonic-gate */
15440Sstevel@tonic-gate int
sctp_getmyaddrs(void * conn,void * myaddrs,int * addrcnt)15450Sstevel@tonic-gate sctp_getmyaddrs(void *conn, void *myaddrs, int *addrcnt)
15460Sstevel@tonic-gate {
15470Sstevel@tonic-gate int i;
15480Sstevel@tonic-gate int l;
15490Sstevel@tonic-gate sctp_saddr_ipif_t *obj;
15500Sstevel@tonic-gate sctp_t *sctp = (sctp_t *)conn;
155111042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
155211042SErik.Nordmark@Sun.COM int family = connp->conn_family;
15530Sstevel@tonic-gate int max = *addrcnt;
15540Sstevel@tonic-gate size_t added = 0;
15550Sstevel@tonic-gate struct sockaddr_in6 *sin6;
15560Sstevel@tonic-gate struct sockaddr_in *sin4;
15570Sstevel@tonic-gate int scanned = 0;
15580Sstevel@tonic-gate boolean_t skip_lback = B_FALSE;
155911042SErik.Nordmark@Sun.COM ip_xmit_attr_t *ixa = connp->conn_ixa;
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate if (sctp->sctp_nsaddrs == 0)
15620Sstevel@tonic-gate return (EINVAL);
15630Sstevel@tonic-gate
1564852Svi117747 /*
1565852Svi117747 * Skip loopback addresses for non-loopback assoc., ignore
1566852Svi117747 * this on a clustered node.
1567852Svi117747 */
1568852Svi117747 if (sctp->sctp_state >= SCTPS_ESTABLISHED && !sctp->sctp_loopback &&
1569852Svi117747 (cl_sctp_check_addrs == NULL)) {
15700Sstevel@tonic-gate skip_lback = B_TRUE;
1571852Svi117747 }
1572852Svi117747
15730Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
157411373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_READER);
157511373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[i].ipif_count == 0) {
157611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
15770Sstevel@tonic-gate continue;
157811373SGeorge.Shepherd@Sun.COM }
15790Sstevel@tonic-gate obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
15800Sstevel@tonic-gate for (l = 0; l < sctp->sctp_saddrs[i].ipif_count; l++) {
15810Sstevel@tonic-gate sctp_ipif_t *ipif = obj->saddr_ipifp;
15820Sstevel@tonic-gate in6_addr_t addr = ipif->sctp_ipif_saddr;
15830Sstevel@tonic-gate
15840Sstevel@tonic-gate scanned++;
15850Sstevel@tonic-gate if ((ipif->sctp_ipif_state == SCTP_IPIFS_CONDEMNED) ||
1586432Svi117747 SCTP_DONT_SRC(obj) ||
1587852Svi117747 (SCTP_IS_IPIF_LOOPBACK(ipif) && skip_lback)) {
158811373SGeorge.Shepherd@Sun.COM if (scanned >= sctp->sctp_nsaddrs) {
158911373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->
159011373SGeorge.Shepherd@Sun.COM sctp_saddrs[i].ipif_hash_lock);
15910Sstevel@tonic-gate goto done;
159211373SGeorge.Shepherd@Sun.COM }
15930Sstevel@tonic-gate obj = list_next(&sctp->sctp_saddrs[i].
15940Sstevel@tonic-gate sctp_ipif_list, obj);
15950Sstevel@tonic-gate continue;
15960Sstevel@tonic-gate }
15970Sstevel@tonic-gate switch (family) {
15980Sstevel@tonic-gate case AF_INET:
15990Sstevel@tonic-gate sin4 = (struct sockaddr_in *)myaddrs + added;
16000Sstevel@tonic-gate sin4->sin_family = AF_INET;
160111042SErik.Nordmark@Sun.COM sin4->sin_port = connp->conn_lport;
16020Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&addr, &sin4->sin_addr);
16030Sstevel@tonic-gate break;
16040Sstevel@tonic-gate
16050Sstevel@tonic-gate case AF_INET6:
16060Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)myaddrs + added;
16070Sstevel@tonic-gate sin6->sin6_family = AF_INET6;
160811042SErik.Nordmark@Sun.COM sin6->sin6_port = connp->conn_lport;
16090Sstevel@tonic-gate sin6->sin6_addr = addr;
161011042SErik.Nordmark@Sun.COM /*
161111042SErik.Nordmark@Sun.COM * Note that flowinfo is only returned for
161211042SErik.Nordmark@Sun.COM * getpeername just like for TCP and UDP.
161311042SErik.Nordmark@Sun.COM */
161411042SErik.Nordmark@Sun.COM sin6->sin6_flowinfo = 0;
161511042SErik.Nordmark@Sun.COM
161611042SErik.Nordmark@Sun.COM if (IN6_IS_ADDR_LINKSCOPE(&sin6->sin6_addr) &&
161711042SErik.Nordmark@Sun.COM (ixa->ixa_flags & IXAF_SCOPEID_SET))
161811042SErik.Nordmark@Sun.COM sin6->sin6_scope_id = ixa->ixa_scopeid;
161911042SErik.Nordmark@Sun.COM else
162011042SErik.Nordmark@Sun.COM sin6->sin6_scope_id = 0;
162111042SErik.Nordmark@Sun.COM sin6->__sin6_src_id = 0;
16220Sstevel@tonic-gate break;
16230Sstevel@tonic-gate }
16240Sstevel@tonic-gate added++;
162511373SGeorge.Shepherd@Sun.COM if (added >= max || scanned >= sctp->sctp_nsaddrs) {
162611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16270Sstevel@tonic-gate goto done;
162811373SGeorge.Shepherd@Sun.COM }
16290Sstevel@tonic-gate obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
16300Sstevel@tonic-gate obj);
16310Sstevel@tonic-gate }
163211373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16330Sstevel@tonic-gate }
16340Sstevel@tonic-gate done:
16350Sstevel@tonic-gate *addrcnt = added;
16360Sstevel@tonic-gate return (0);
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate /*
1640252Svi117747 * Given the supported address family, walk through the source address list
1641252Svi117747 * and return the total length of the available addresses. If 'p' is not
1642252Svi117747 * null, construct the parameter list for the addresses in 'p'.
1643432Svi117747 * 'modify' will only be set when we want the source address list to
1644432Svi117747 * be modified. The source address list will be modified only when
1645432Svi117747 * generating an INIT chunk. For generating an INIT-ACK 'modify' will
1646432Svi117747 * be false since the 'sctp' will be that of the listener.
16470Sstevel@tonic-gate */
16480Sstevel@tonic-gate size_t
sctp_saddr_info(sctp_t * sctp,int supp_af,uchar_t * p,boolean_t modify)1649432Svi117747 sctp_saddr_info(sctp_t *sctp, int supp_af, uchar_t *p, boolean_t modify)
16500Sstevel@tonic-gate {
16510Sstevel@tonic-gate int i;
16520Sstevel@tonic-gate int l;
16530Sstevel@tonic-gate sctp_saddr_ipif_t *obj;
1654252Svi117747 size_t paramlen = 0;
16550Sstevel@tonic-gate sctp_parm_hdr_t *hdr;
16560Sstevel@tonic-gate int scanned = 0;
1657432Svi117747 int naddr;
1658432Svi117747 int nsaddr;
1659852Svi117747 boolean_t del_ll = B_FALSE;
1660852Svi117747 boolean_t del_lb = B_FALSE;
1661852Svi117747
16620Sstevel@tonic-gate
1663852Svi117747 /*
1664852Svi117747 * On a clustered node don't bother changing anything
1665852Svi117747 * on the loopback interface.
1666852Svi117747 */
1667852Svi117747 if (modify && !sctp->sctp_loopback && (cl_sctp_check_addrs == NULL))
1668852Svi117747 del_lb = B_TRUE;
1669852Svi117747
1670852Svi117747 if (modify && !sctp->sctp_linklocal)
1671852Svi117747 del_ll = B_TRUE;
1672432Svi117747
1673432Svi117747 nsaddr = sctp->sctp_nsaddrs;
16740Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
167511373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[i].ipif_hash_lock, RW_WRITER);
167611373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[i].ipif_count == 0) {
167711373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
16780Sstevel@tonic-gate continue;
167911373SGeorge.Shepherd@Sun.COM }
16800Sstevel@tonic-gate obj = list_head(&sctp->sctp_saddrs[i].sctp_ipif_list);
1681432Svi117747 naddr = sctp->sctp_saddrs[i].ipif_count;
1682432Svi117747 for (l = 0; l < naddr; l++) {
16830Sstevel@tonic-gate in6_addr_t addr;
16840Sstevel@tonic-gate sctp_ipif_t *ipif;
1685852Svi117747 boolean_t ipif_lb;
1686852Svi117747 boolean_t ipif_ll;
1687432Svi117747 boolean_t unsupp_af;
16880Sstevel@tonic-gate
16890Sstevel@tonic-gate ipif = obj->saddr_ipifp;
16900Sstevel@tonic-gate scanned++;
1691432Svi117747
1692852Svi117747 ipif_lb = SCTP_IS_IPIF_LOOPBACK(ipif);
1693852Svi117747 ipif_ll = SCTP_IS_IPIF_LINKLOCAL(ipif);
1694432Svi117747 unsupp_af = SCTP_UNSUPP_AF(ipif, supp_af);
1695432Svi117747 /*
1696432Svi117747 * We need to either delete or skip loopback/linklocal
1697852Svi117747 * or unsupported addresses, if required.
1698432Svi117747 */
1699852Svi117747 if ((ipif_ll && del_ll) || (ipif_lb && del_lb) ||
1700852Svi117747 (unsupp_af && modify)) {
1701432Svi117747 if (sctp->sctp_bound_to_all == 1)
1702432Svi117747 sctp->sctp_bound_to_all = 0;
1703432Svi117747 if (scanned < nsaddr) {
1704432Svi117747 obj = list_next(&sctp->sctp_saddrs[i].
1705432Svi117747 sctp_ipif_list, obj);
170611373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, ipif,
170711373SGeorge.Shepherd@Sun.COM B_TRUE);
1708432Svi117747 continue;
1709432Svi117747 }
171011373SGeorge.Shepherd@Sun.COM sctp_ipif_hash_remove(sctp, ipif, B_TRUE);
171111373SGeorge.Shepherd@Sun.COM
1712432Svi117747 goto next_addr;
1713852Svi117747 } else if (ipif_ll || unsupp_af ||
1714852Svi117747 (ipif_lb && (cl_sctp_check_addrs == NULL))) {
1715252Svi117747 goto next_addr;
17160Sstevel@tonic-gate }
1717432Svi117747
1718432Svi117747 if (!SCTP_IPIF_USABLE(ipif->sctp_ipif_state))
1719432Svi117747 goto next_addr;
1720252Svi117747 if (p != NULL)
1721252Svi117747 hdr = (sctp_parm_hdr_t *)(p + paramlen);
17220Sstevel@tonic-gate addr = ipif->sctp_ipif_saddr;
1723432Svi117747 if (!ipif->sctp_ipif_isv6) {
17240Sstevel@tonic-gate struct in_addr *v4;
17250Sstevel@tonic-gate
1726252Svi117747 if (p != NULL) {
1727252Svi117747 hdr->sph_type = htons(PARM_ADDR4);
1728252Svi117747 hdr->sph_len = htons(PARM_ADDR4_LEN);
1729252Svi117747 v4 = (struct in_addr *)(hdr + 1);
1730252Svi117747 IN6_V4MAPPED_TO_INADDR(&addr, v4);
1731252Svi117747 }
1732252Svi117747 paramlen += PARM_ADDR4_LEN;
1733432Svi117747 } else {
1734252Svi117747 if (p != NULL) {
1735252Svi117747 hdr->sph_type = htons(PARM_ADDR6);
1736252Svi117747 hdr->sph_len = htons(PARM_ADDR6_LEN);
1737252Svi117747 bcopy(&addr, hdr + 1, sizeof (addr));
1738252Svi117747 }
1739252Svi117747 paramlen += PARM_ADDR6_LEN;
17400Sstevel@tonic-gate }
1741252Svi117747 next_addr:
174211373SGeorge.Shepherd@Sun.COM if (scanned >= nsaddr) {
174311373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
1744252Svi117747 return (paramlen);
174511373SGeorge.Shepherd@Sun.COM }
17460Sstevel@tonic-gate obj = list_next(&sctp->sctp_saddrs[i].sctp_ipif_list,
17470Sstevel@tonic-gate obj);
17480Sstevel@tonic-gate }
174911373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[i].ipif_hash_lock);
17500Sstevel@tonic-gate }
1751252Svi117747 return (paramlen);
17520Sstevel@tonic-gate }
17530Sstevel@tonic-gate
1754852Svi117747 /*
1755852Svi117747 * This is used on a clustered node to obtain a list of addresses, the list
1756852Svi117747 * consists of sockaddr_in structs for v4 and sockaddr_in6 for v6. The list
1757852Svi117747 * is then passed onto the clustering module which sends back the correct
1758852Svi117747 * list based on the port info. Regardless of the input, i.e INADDR_ANY
1759852Svi117747 * or specific address(es), we create the list since it could be modified by
1760852Svi117747 * the clustering module. When given a list of addresses, we simply
1761852Svi117747 * create the list of sockaddr_in or sockaddr_in6 structs using those
1762852Svi117747 * addresses. If there is an INADDR_ANY in the input list, or if the
1763852Svi117747 * input is INADDR_ANY, we create a list of sockaddr_in or sockaddr_in6
1764852Svi117747 * structs consisting all the addresses in the global interface list
1765852Svi117747 * except those that are hosted on the loopback interface. We create
1766852Svi117747 * a list of sockaddr_in[6] structs just so that it can be directly input
1767852Svi117747 * to sctp_valid_addr_list() once the clustering module has processed it.
1768852Svi117747 */
1769852Svi117747 int
sctp_get_addrlist(sctp_t * sctp,const void * addrs,uint32_t * addrcnt,uchar_t ** addrlist,int * uspec,size_t * size)1770852Svi117747 sctp_get_addrlist(sctp_t *sctp, const void *addrs, uint32_t *addrcnt,
1771852Svi117747 uchar_t **addrlist, int *uspec, size_t *size)
1772852Svi117747 {
1773852Svi117747 int cnt;
1774852Svi117747 int icnt;
1775852Svi117747 sctp_ipif_t *sctp_ipif;
1776852Svi117747 struct sockaddr_in *s4;
1777852Svi117747 struct sockaddr_in6 *s6;
1778852Svi117747 uchar_t *p;
1779852Svi117747 int err = 0;
17803448Sdh155122 sctp_stack_t *sctps = sctp->sctp_sctps;
178111042SErik.Nordmark@Sun.COM conn_t *connp = sctp->sctp_connp;
1782852Svi117747
1783852Svi117747 *addrlist = NULL;
1784852Svi117747 *size = 0;
1785852Svi117747
1786852Svi117747 /*
1787852Svi117747 * Create a list of sockaddr_in[6] structs using the input list.
1788852Svi117747 */
178911042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
1790852Svi117747 *size = sizeof (struct sockaddr_in) * *addrcnt;
1791852Svi117747 *addrlist = kmem_zalloc(*size, KM_SLEEP);
1792852Svi117747 p = *addrlist;
1793852Svi117747 for (cnt = 0; cnt < *addrcnt; cnt++) {
1794852Svi117747 s4 = (struct sockaddr_in *)addrs + cnt;
1795852Svi117747 /*
1796852Svi117747 * We need to create a list of all the available
1797852Svi117747 * addresses if there is an INADDR_ANY. However,
1798852Svi117747 * if we are beyond LISTEN, then this is invalid
1799852Svi117747 * (see sctp_valid_addr_list(). So, we just fail
1800852Svi117747 * it here rather than wait till it fails in
1801852Svi117747 * sctp_valid_addr_list().
1802852Svi117747 */
1803852Svi117747 if (s4->sin_addr.s_addr == INADDR_ANY) {
1804852Svi117747 kmem_free(*addrlist, *size);
1805852Svi117747 *addrlist = NULL;
1806852Svi117747 *size = 0;
1807852Svi117747 if (sctp->sctp_state > SCTPS_LISTEN) {
1808852Svi117747 *addrcnt = 0;
1809852Svi117747 return (EINVAL);
1810852Svi117747 }
1811852Svi117747 if (uspec != NULL)
1812852Svi117747 *uspec = 1;
1813852Svi117747 goto get_all_addrs;
1814852Svi117747 } else {
1815852Svi117747 bcopy(s4, p, sizeof (*s4));
1816852Svi117747 p += sizeof (*s4);
1817852Svi117747 }
1818852Svi117747 }
1819852Svi117747 } else {
1820852Svi117747 *size = sizeof (struct sockaddr_in6) * *addrcnt;
1821852Svi117747 *addrlist = kmem_zalloc(*size, KM_SLEEP);
1822852Svi117747 p = *addrlist;
1823852Svi117747 for (cnt = 0; cnt < *addrcnt; cnt++) {
1824852Svi117747 s6 = (struct sockaddr_in6 *)addrs + cnt;
1825852Svi117747 /*
1826852Svi117747 * Comments for INADDR_ANY, above, apply here too.
1827852Svi117747 */
1828852Svi117747 if (IN6_IS_ADDR_UNSPECIFIED(&s6->sin6_addr)) {
1829852Svi117747 kmem_free(*addrlist, *size);
1830852Svi117747 *size = 0;
1831852Svi117747 *addrlist = NULL;
1832852Svi117747 if (sctp->sctp_state > SCTPS_LISTEN) {
1833852Svi117747 *addrcnt = 0;
1834852Svi117747 return (EINVAL);
1835852Svi117747 }
1836852Svi117747 if (uspec != NULL)
1837852Svi117747 *uspec = 1;
1838852Svi117747 goto get_all_addrs;
1839852Svi117747 } else {
1840852Svi117747 bcopy(addrs, p, sizeof (*s6));
1841852Svi117747 p += sizeof (*s6);
1842852Svi117747 }
1843852Svi117747 }
1844852Svi117747 }
1845852Svi117747 return (err);
1846852Svi117747 get_all_addrs:
1847852Svi117747
1848852Svi117747 /*
1849852Svi117747 * Allocate max possible size. We allocate the max. size here because
1850852Svi117747 * the clustering module could end up adding addresses to the list.
1851852Svi117747 * We allocate upfront so that the clustering module need to bother
1852852Svi117747 * re-sizing the list.
1853852Svi117747 */
185411042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
18553448Sdh155122 *size = sizeof (struct sockaddr_in) *
18563448Sdh155122 sctps->sctps_g_ipifs_count;
18573448Sdh155122 } else {
18583448Sdh155122 *size = sizeof (struct sockaddr_in6) *
18593448Sdh155122 sctps->sctps_g_ipifs_count;
18603448Sdh155122 }
1861852Svi117747 *addrlist = kmem_zalloc(*size, KM_SLEEP);
1862852Svi117747 *addrcnt = 0;
1863852Svi117747 p = *addrlist;
18643448Sdh155122 rw_enter(&sctps->sctps_g_ipifs_lock, RW_READER);
1865852Svi117747
1866852Svi117747 /*
1867852Svi117747 * Walk through the global interface list and add all addresses,
1868852Svi117747 * except those that are hosted on loopback interfaces.
1869852Svi117747 */
1870852Svi117747 for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
18713448Sdh155122 if (sctps->sctps_g_ipifs[cnt].ipif_count == 0)
1872852Svi117747 continue;
18733448Sdh155122 sctp_ipif = list_head(
18743448Sdh155122 &sctps->sctps_g_ipifs[cnt].sctp_ipif_list);
18753448Sdh155122 for (icnt = 0;
18763448Sdh155122 icnt < sctps->sctps_g_ipifs[cnt].ipif_count;
18773448Sdh155122 icnt++) {
1878852Svi117747 in6_addr_t addr;
1879852Svi117747
1880852Svi117747 rw_enter(&sctp_ipif->sctp_ipif_lock, RW_READER);
1881852Svi117747 addr = sctp_ipif->sctp_ipif_saddr;
1882852Svi117747 if (SCTP_IPIF_DISCARD(sctp_ipif->sctp_ipif_flags) ||
1883852Svi117747 !SCTP_IPIF_USABLE(sctp_ipif->sctp_ipif_state) ||
1884852Svi117747 SCTP_IS_IPIF_LOOPBACK(sctp_ipif) ||
1885852Svi117747 SCTP_IS_IPIF_LINKLOCAL(sctp_ipif) ||
18862263Ssommerfe !SCTP_IPIF_ZONE_MATCH(sctp, sctp_ipif) ||
188711042SErik.Nordmark@Sun.COM (connp->conn_family == AF_INET &&
1888852Svi117747 sctp_ipif->sctp_ipif_isv6) ||
1889852Svi117747 (sctp->sctp_connp->conn_ipv6_v6only &&
1890852Svi117747 !sctp_ipif->sctp_ipif_isv6)) {
1891852Svi117747 rw_exit(&sctp_ipif->sctp_ipif_lock);
1892852Svi117747 sctp_ipif = list_next(
18933448Sdh155122 &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
1894852Svi117747 sctp_ipif);
1895852Svi117747 continue;
1896852Svi117747 }
1897852Svi117747 rw_exit(&sctp_ipif->sctp_ipif_lock);
189811042SErik.Nordmark@Sun.COM if (connp->conn_family == AF_INET) {
1899852Svi117747 s4 = (struct sockaddr_in *)p;
1900852Svi117747 IN6_V4MAPPED_TO_INADDR(&addr, &s4->sin_addr);
1901852Svi117747 s4->sin_family = AF_INET;
1902852Svi117747 p += sizeof (*s4);
1903852Svi117747 } else {
1904852Svi117747 s6 = (struct sockaddr_in6 *)p;
1905852Svi117747 s6->sin6_addr = addr;
1906852Svi117747 s6->sin6_family = AF_INET6;
1907852Svi117747 s6->sin6_scope_id =
1908852Svi117747 sctp_ipif->sctp_ipif_ill->sctp_ill_index;
1909852Svi117747 p += sizeof (*s6);
1910852Svi117747 }
1911852Svi117747 (*addrcnt)++;
19123448Sdh155122 sctp_ipif = list_next(
19133448Sdh155122 &sctps->sctps_g_ipifs[cnt].sctp_ipif_list,
1914852Svi117747 sctp_ipif);
1915852Svi117747 }
1916852Svi117747 }
19173448Sdh155122 rw_exit(&sctps->sctps_g_ipifs_lock);
1918852Svi117747 return (err);
1919852Svi117747 }
1920852Svi117747
1921852Svi117747 /*
1922852Svi117747 * Get a list of addresses from the source address list. The caller is
1923852Svi117747 * responsible for allocating sufficient buffer for this.
1924852Svi117747 */
1925852Svi117747 void
sctp_get_saddr_list(sctp_t * sctp,uchar_t * p,size_t psize)1926852Svi117747 sctp_get_saddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
1927852Svi117747 {
1928852Svi117747 int cnt;
1929852Svi117747 int icnt;
1930852Svi117747 sctp_saddr_ipif_t *obj;
1931852Svi117747 int naddr;
1932852Svi117747 int scanned = 0;
1933852Svi117747
1934852Svi117747 for (cnt = 0; cnt < SCTP_IPIF_HASH; cnt++) {
193511373SGeorge.Shepherd@Sun.COM rw_enter(&sctp->sctp_saddrs[cnt].ipif_hash_lock, RW_READER);
193611373SGeorge.Shepherd@Sun.COM if (sctp->sctp_saddrs[cnt].ipif_count == 0) {
193711373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
1938852Svi117747 continue;
193911373SGeorge.Shepherd@Sun.COM }
1940852Svi117747 obj = list_head(&sctp->sctp_saddrs[cnt].sctp_ipif_list);
1941852Svi117747 naddr = sctp->sctp_saddrs[cnt].ipif_count;
1942852Svi117747 for (icnt = 0; icnt < naddr; icnt++) {
1943852Svi117747 sctp_ipif_t *ipif;
1944852Svi117747
194511373SGeorge.Shepherd@Sun.COM if (psize < sizeof (ipif->sctp_ipif_saddr)) {
194611373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
1947852Svi117747 return;
194811373SGeorge.Shepherd@Sun.COM }
1949852Svi117747
1950852Svi117747 scanned++;
1951852Svi117747 ipif = obj->saddr_ipifp;
1952852Svi117747 bcopy(&ipif->sctp_ipif_saddr, p,
1953852Svi117747 sizeof (ipif->sctp_ipif_saddr));
1954852Svi117747 p += sizeof (ipif->sctp_ipif_saddr);
1955852Svi117747 psize -= sizeof (ipif->sctp_ipif_saddr);
195611373SGeorge.Shepherd@Sun.COM if (scanned >= sctp->sctp_nsaddrs) {
195711373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
1958852Svi117747 return;
195911373SGeorge.Shepherd@Sun.COM }
19603448Sdh155122 obj = list_next(
19613448Sdh155122 &sctp->sctp_saddrs[icnt].sctp_ipif_list,
1962852Svi117747 obj);
1963852Svi117747 }
196411373SGeorge.Shepherd@Sun.COM rw_exit(&sctp->sctp_saddrs[cnt].ipif_hash_lock);
1965852Svi117747 }
1966852Svi117747 }
1967852Svi117747
1968852Svi117747 /*
1969852Svi117747 * Get a list of addresses from the remote address list. The caller is
1970852Svi117747 * responsible for allocating sufficient buffer for this.
1971852Svi117747 */
1972852Svi117747 void
sctp_get_faddr_list(sctp_t * sctp,uchar_t * p,size_t psize)1973852Svi117747 sctp_get_faddr_list(sctp_t *sctp, uchar_t *p, size_t psize)
1974852Svi117747 {
1975852Svi117747 sctp_faddr_t *fp;
1976852Svi117747
1977*13009SChandrasekar.Marimuthu@Sun.COM for (fp = sctp->sctp_faddrs; fp != NULL; fp = fp->sf_next) {
1978*13009SChandrasekar.Marimuthu@Sun.COM if (psize < sizeof (fp->sf_faddr))
1979852Svi117747 return;
1980*13009SChandrasekar.Marimuthu@Sun.COM bcopy(&fp->sf_faddr, p, sizeof (fp->sf_faddr));
1981*13009SChandrasekar.Marimuthu@Sun.COM p += sizeof (fp->sf_faddr);
1982*13009SChandrasekar.Marimuthu@Sun.COM psize -= sizeof (fp->sf_faddr);
1983852Svi117747 }
1984852Svi117747 }
19850Sstevel@tonic-gate
19863448Sdh155122 static void
sctp_free_ills(sctp_stack_t * sctps)19873448Sdh155122 sctp_free_ills(sctp_stack_t *sctps)
19883448Sdh155122 {
19893448Sdh155122 int i;
19903448Sdh155122 int l;
19913448Sdh155122 sctp_ill_t *sctp_ill;
19923448Sdh155122
19933448Sdh155122 if (sctps->sctps_ills_count == 0)
19943448Sdh155122 return;
19953448Sdh155122
19963448Sdh155122 for (i = 0; i < SCTP_ILL_HASH; i++) {
19973448Sdh155122 sctp_ill = list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
19983448Sdh155122 for (l = 0; l < sctps->sctps_g_ills[i].ill_count; l++) {
19993448Sdh155122 ASSERT(sctp_ill->sctp_ill_ipifcnt == 0);
20003448Sdh155122 list_remove(&sctps->sctps_g_ills[i].sctp_ill_list,
20013448Sdh155122 sctp_ill);
20023448Sdh155122 sctps->sctps_ills_count--;
20033448Sdh155122 kmem_free(sctp_ill->sctp_ill_name,
20043448Sdh155122 sctp_ill->sctp_ill_name_length);
20053448Sdh155122 kmem_free(sctp_ill, sizeof (sctp_ill_t));
20063448Sdh155122 sctp_ill =
20073448Sdh155122 list_tail(&sctps->sctps_g_ills[i].sctp_ill_list);
20083448Sdh155122 }
20093448Sdh155122 sctps->sctps_g_ills[i].ill_count = 0;
20103448Sdh155122 }
20113448Sdh155122 ASSERT(sctps->sctps_ills_count == 0);
20123448Sdh155122 }
20133448Sdh155122
20143448Sdh155122 static void
sctp_free_ipifs(sctp_stack_t * sctps)20153448Sdh155122 sctp_free_ipifs(sctp_stack_t *sctps)
20163448Sdh155122 {
20173448Sdh155122 int i;
20183448Sdh155122 int l;
20193448Sdh155122 sctp_ipif_t *sctp_ipif;
20203448Sdh155122 sctp_ill_t *sctp_ill;
20213448Sdh155122
20223448Sdh155122 if (sctps->sctps_g_ipifs_count == 0)
20233448Sdh155122 return;
20243448Sdh155122
20253448Sdh155122 for (i = 0; i < SCTP_IPIF_HASH; i++) {
20263448Sdh155122 sctp_ipif = list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
20273448Sdh155122 for (l = 0; l < sctps->sctps_g_ipifs[i].ipif_count; l++) {
20283448Sdh155122 sctp_ill = sctp_ipif->sctp_ipif_ill;
20293448Sdh155122
20303448Sdh155122 list_remove(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
20313448Sdh155122 sctp_ipif);
20323448Sdh155122 sctps->sctps_g_ipifs_count--;
20333448Sdh155122 (void) atomic_add_32_nv(&sctp_ill->sctp_ill_ipifcnt,
20343448Sdh155122 -1);
20353448Sdh155122 kmem_free(sctp_ipif, sizeof (sctp_ipif_t));
20363448Sdh155122 sctp_ipif =
20373448Sdh155122 list_tail(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
20383448Sdh155122 }
20393448Sdh155122 sctps->sctps_g_ipifs[i].ipif_count = 0;
20403448Sdh155122 }
20413448Sdh155122 ASSERT(sctps->sctps_g_ipifs_count == 0);
20423448Sdh155122 }
20433448Sdh155122
20443448Sdh155122
20450Sstevel@tonic-gate /* Initialize the SCTP ILL list and lock */
20460Sstevel@tonic-gate void
sctp_saddr_init(sctp_stack_t * sctps)20473448Sdh155122 sctp_saddr_init(sctp_stack_t *sctps)
20480Sstevel@tonic-gate {
20490Sstevel@tonic-gate int i;
20500Sstevel@tonic-gate
20513448Sdh155122 sctps->sctps_g_ills = kmem_zalloc(sizeof (sctp_ill_hash_t) *
20523448Sdh155122 SCTP_ILL_HASH, KM_SLEEP);
20533448Sdh155122 sctps->sctps_g_ipifs = kmem_zalloc(sizeof (sctp_ipif_hash_t) *
20543448Sdh155122 SCTP_IPIF_HASH, KM_SLEEP);
20553448Sdh155122
20563448Sdh155122 rw_init(&sctps->sctps_g_ills_lock, NULL, RW_DEFAULT, NULL);
20573448Sdh155122 rw_init(&sctps->sctps_g_ipifs_lock, NULL, RW_DEFAULT, NULL);
20580Sstevel@tonic-gate
20590Sstevel@tonic-gate for (i = 0; i < SCTP_ILL_HASH; i++) {
20603448Sdh155122 sctps->sctps_g_ills[i].ill_count = 0;
20613448Sdh155122 list_create(&sctps->sctps_g_ills[i].sctp_ill_list,
20623448Sdh155122 sizeof (sctp_ill_t),
20630Sstevel@tonic-gate offsetof(sctp_ill_t, sctp_ills));
20640Sstevel@tonic-gate }
20650Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++) {
20663448Sdh155122 sctps->sctps_g_ipifs[i].ipif_count = 0;
20673448Sdh155122 list_create(&sctps->sctps_g_ipifs[i].sctp_ipif_list,
20680Sstevel@tonic-gate sizeof (sctp_ipif_t), offsetof(sctp_ipif_t, sctp_ipifs));
20690Sstevel@tonic-gate }
20700Sstevel@tonic-gate }
20710Sstevel@tonic-gate
20720Sstevel@tonic-gate void
sctp_saddr_fini(sctp_stack_t * sctps)20733448Sdh155122 sctp_saddr_fini(sctp_stack_t *sctps)
20740Sstevel@tonic-gate {
20750Sstevel@tonic-gate int i;
20760Sstevel@tonic-gate
20773448Sdh155122 sctp_free_ipifs(sctps);
20783448Sdh155122 sctp_free_ills(sctps);
20793448Sdh155122
20800Sstevel@tonic-gate for (i = 0; i < SCTP_ILL_HASH; i++)
20813448Sdh155122 list_destroy(&sctps->sctps_g_ills[i].sctp_ill_list);
20820Sstevel@tonic-gate for (i = 0; i < SCTP_IPIF_HASH; i++)
20833448Sdh155122 list_destroy(&sctps->sctps_g_ipifs[i].sctp_ipif_list);
20843448Sdh155122
20853448Sdh155122 ASSERT(sctps->sctps_ills_count == 0 && sctps->sctps_g_ipifs_count == 0);
20863448Sdh155122 kmem_free(sctps->sctps_g_ills, sizeof (sctp_ill_hash_t) *
20873448Sdh155122 SCTP_ILL_HASH);
20883448Sdh155122 sctps->sctps_g_ills = NULL;
20893448Sdh155122 kmem_free(sctps->sctps_g_ipifs, sizeof (sctp_ipif_hash_t) *
20903448Sdh155122 SCTP_IPIF_HASH);
20913448Sdh155122 sctps->sctps_g_ipifs = NULL;
20923448Sdh155122 rw_destroy(&sctps->sctps_g_ills_lock);
20933448Sdh155122 rw_destroy(&sctps->sctps_g_ipifs_lock);
20940Sstevel@tonic-gate }
2095