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
53448Sdh155122 * Common Development and Distribution License (the "License").
63448Sdh155122 * 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*11042SErik.Nordmark@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <sys/socket.h>
280Sstevel@tonic-gate #include <sys/ksynch.h>
290Sstevel@tonic-gate #include <sys/kmem.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/systm.h>
320Sstevel@tonic-gate #include <sys/sysmacros.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/strsun.h>
350Sstevel@tonic-gate #include <sys/zone.h>
360Sstevel@tonic-gate #include <netinet/in.h>
370Sstevel@tonic-gate #include <inet/common.h>
380Sstevel@tonic-gate #include <inet/ip.h>
390Sstevel@tonic-gate #include <inet/ip6.h>
400Sstevel@tonic-gate #include <inet/ip6_asp.h>
410Sstevel@tonic-gate #include <inet/ip_ire.h>
42*11042SErik.Nordmark@Sun.COM #include <inet/ip_if.h>
433448Sdh155122 #include <inet/ipclassifier.h>
440Sstevel@tonic-gate
450Sstevel@tonic-gate #define IN6ADDR_MASK128_INIT \
460Sstevel@tonic-gate { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU }
470Sstevel@tonic-gate #define IN6ADDR_MASK96_INIT { 0xffffffffU, 0xffffffffU, 0xffffffffU, 0 }
480Sstevel@tonic-gate #ifdef _BIG_ENDIAN
490Sstevel@tonic-gate #define IN6ADDR_MASK16_INIT { 0xffff0000U, 0, 0, 0 }
500Sstevel@tonic-gate #else
510Sstevel@tonic-gate #define IN6ADDR_MASK16_INIT { 0x0000ffffU, 0, 0, 0 }
520Sstevel@tonic-gate #endif
530Sstevel@tonic-gate
540Sstevel@tonic-gate
550Sstevel@tonic-gate /*
560Sstevel@tonic-gate * This table is ordered such that longest prefix matches are hit first
570Sstevel@tonic-gate * (longer prefix lengths first). The last entry must be the "default"
580Sstevel@tonic-gate * entry (::0/0).
590Sstevel@tonic-gate */
600Sstevel@tonic-gate static ip6_asp_t default_ip6_asp_table[] = {
610Sstevel@tonic-gate { IN6ADDR_LOOPBACK_INIT, IN6ADDR_MASK128_INIT,
620Sstevel@tonic-gate "Loopback", 50 },
630Sstevel@tonic-gate { IN6ADDR_ANY_INIT, IN6ADDR_MASK96_INIT,
640Sstevel@tonic-gate "IPv4_Compatible", 20 },
650Sstevel@tonic-gate #ifdef _BIG_ENDIAN
660Sstevel@tonic-gate { { 0, 0, 0x0000ffffU, 0 }, IN6ADDR_MASK96_INIT,
670Sstevel@tonic-gate "IPv4", 10 },
680Sstevel@tonic-gate { { 0x20020000U, 0, 0, 0 }, IN6ADDR_MASK16_INIT,
690Sstevel@tonic-gate "6to4", 30 },
700Sstevel@tonic-gate #else
710Sstevel@tonic-gate { { 0, 0, 0xffff0000U, 0 }, IN6ADDR_MASK96_INIT,
720Sstevel@tonic-gate "IPv4", 10 },
730Sstevel@tonic-gate { { 0x00000220U, 0, 0, 0 }, IN6ADDR_MASK16_INIT,
740Sstevel@tonic-gate "6to4", 30 },
750Sstevel@tonic-gate #endif
760Sstevel@tonic-gate { IN6ADDR_ANY_INIT, IN6ADDR_ANY_INIT,
770Sstevel@tonic-gate "Default", 40 }
780Sstevel@tonic-gate };
790Sstevel@tonic-gate
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * The IPv6 Default Address Selection policy table.
820Sstevel@tonic-gate * Until someone up above reconfigures the policy table, use the global
830Sstevel@tonic-gate * default. The table needs no lock since the only way to alter it is
840Sstevel@tonic-gate * through the SIOCSIP6ADDRPOLICY which is exclusive in ip.
850Sstevel@tonic-gate */
860Sstevel@tonic-gate static void ip6_asp_copy(ip6_asp_t *, ip6_asp_t *, uint_t);
873448Sdh155122 static void ip6_asp_check_for_updates(ip_stack_t *);
880Sstevel@tonic-gate
890Sstevel@tonic-gate void
ip6_asp_init(ip_stack_t * ipst)903448Sdh155122 ip6_asp_init(ip_stack_t *ipst)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate /* Initialize the table lock */
933448Sdh155122 mutex_init(&ipst->ips_ip6_asp_lock, NULL, MUTEX_DEFAULT, NULL);
943448Sdh155122
953448Sdh155122 ipst->ips_ip6_asp_table = default_ip6_asp_table;
963448Sdh155122
973448Sdh155122 ipst->ips_ip6_asp_table_count =
983448Sdh155122 sizeof (default_ip6_asp_table) / sizeof (ip6_asp_t);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate
1010Sstevel@tonic-gate void
ip6_asp_free(ip_stack_t * ipst)1023448Sdh155122 ip6_asp_free(ip_stack_t *ipst)
1030Sstevel@tonic-gate {
1043448Sdh155122 if (ipst->ips_ip6_asp_table != default_ip6_asp_table) {
1053448Sdh155122 kmem_free(ipst->ips_ip6_asp_table,
1063448Sdh155122 ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
1073448Sdh155122 ipst->ips_ip6_asp_table = NULL;
1080Sstevel@tonic-gate }
1093448Sdh155122 mutex_destroy(&ipst->ips_ip6_asp_lock);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate * Return false if the table is being updated. Else, increment the ref
1140Sstevel@tonic-gate * count and return true.
1150Sstevel@tonic-gate */
1160Sstevel@tonic-gate boolean_t
ip6_asp_can_lookup(ip_stack_t * ipst)1173448Sdh155122 ip6_asp_can_lookup(ip_stack_t *ipst)
1180Sstevel@tonic-gate {
1193448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
1203448Sdh155122 if (ipst->ips_ip6_asp_uip) {
1213448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
1220Sstevel@tonic-gate return (B_FALSE);
1230Sstevel@tonic-gate }
1243448Sdh155122 IP6_ASP_TABLE_REFHOLD(ipst);
1253448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
1260Sstevel@tonic-gate return (B_TRUE);
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate void
ip6_asp_pending_op(queue_t * q,mblk_t * mp,aspfunc_t func)1310Sstevel@tonic-gate ip6_asp_pending_op(queue_t *q, mblk_t *mp, aspfunc_t func)
1320Sstevel@tonic-gate {
1333448Sdh155122 conn_t *connp = Q_TO_CONN(q);
1343448Sdh155122 ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate ASSERT((mp->b_prev == NULL) && (mp->b_queue == NULL) &&
1370Sstevel@tonic-gate (mp->b_next == NULL));
1380Sstevel@tonic-gate mp->b_queue = (void *)q;
1390Sstevel@tonic-gate mp->b_prev = (void *)func;
1400Sstevel@tonic-gate mp->b_next = NULL;
1410Sstevel@tonic-gate
1423448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
1433448Sdh155122 if (ipst->ips_ip6_asp_pending_ops == NULL) {
1443448Sdh155122 ASSERT(ipst->ips_ip6_asp_pending_ops_tail == NULL);
1453448Sdh155122 ipst->ips_ip6_asp_pending_ops =
1463448Sdh155122 ipst->ips_ip6_asp_pending_ops_tail = mp;
1470Sstevel@tonic-gate } else {
1483448Sdh155122 ipst->ips_ip6_asp_pending_ops_tail->b_next = mp;
1493448Sdh155122 ipst->ips_ip6_asp_pending_ops_tail = mp;
1500Sstevel@tonic-gate }
1513448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static void
ip6_asp_complete_op(ip_stack_t * ipst)1553448Sdh155122 ip6_asp_complete_op(ip_stack_t *ipst)
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate mblk_t *mp;
1580Sstevel@tonic-gate queue_t *q;
1590Sstevel@tonic-gate aspfunc_t func;
1600Sstevel@tonic-gate
1613448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
1623448Sdh155122 while (ipst->ips_ip6_asp_pending_ops != NULL) {
1633448Sdh155122 mp = ipst->ips_ip6_asp_pending_ops;
1643448Sdh155122 ipst->ips_ip6_asp_pending_ops = mp->b_next;
1650Sstevel@tonic-gate mp->b_next = NULL;
1663448Sdh155122 if (ipst->ips_ip6_asp_pending_ops == NULL)
1673448Sdh155122 ipst->ips_ip6_asp_pending_ops_tail = NULL;
1683448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate q = (queue_t *)mp->b_queue;
1710Sstevel@tonic-gate func = (aspfunc_t)mp->b_prev;
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate mp->b_prev = NULL;
1740Sstevel@tonic-gate mp->b_queue = NULL;
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate
1770Sstevel@tonic-gate (*func)(NULL, q, mp, NULL);
1783448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
1790Sstevel@tonic-gate }
1803448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
1810Sstevel@tonic-gate }
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /*
1840Sstevel@tonic-gate * Decrement reference count. When it gets to 0, we check for (pending)
1850Sstevel@tonic-gate * saved update to the table, if any.
1860Sstevel@tonic-gate */
1870Sstevel@tonic-gate void
ip6_asp_table_refrele(ip_stack_t * ipst)1883448Sdh155122 ip6_asp_table_refrele(ip_stack_t *ipst)
1890Sstevel@tonic-gate {
1903448Sdh155122 IP6_ASP_TABLE_REFRELE(ipst);
1910Sstevel@tonic-gate }
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate /*
1940Sstevel@tonic-gate * This function is guaranteed never to return a NULL pointer. It
1950Sstevel@tonic-gate * will always return information from one of the entries in the
1960Sstevel@tonic-gate * asp_table (which will never be empty). If a pointer is passed
1970Sstevel@tonic-gate * in for the precedence, the precedence value will be set; a
1980Sstevel@tonic-gate * pointer to the label will be returned by the function.
1990Sstevel@tonic-gate *
2000Sstevel@tonic-gate * Since the table is only anticipated to have five or six entries
2010Sstevel@tonic-gate * total, the lookup algorithm hasn't been optimized to anything
2020Sstevel@tonic-gate * better than O(n).
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate char *
ip6_asp_lookup(const in6_addr_t * addr,uint32_t * precedence,ip_stack_t * ipst)2053448Sdh155122 ip6_asp_lookup(const in6_addr_t *addr, uint32_t *precedence, ip_stack_t *ipst)
2060Sstevel@tonic-gate {
2070Sstevel@tonic-gate ip6_asp_t *aspp;
2080Sstevel@tonic-gate ip6_asp_t *match = NULL;
2090Sstevel@tonic-gate ip6_asp_t *default_policy;
2100Sstevel@tonic-gate
2113448Sdh155122 aspp = ipst->ips_ip6_asp_table;
2120Sstevel@tonic-gate /* The default entry must always be the last one */
2133448Sdh155122 default_policy = aspp + ipst->ips_ip6_asp_table_count - 1;
2140Sstevel@tonic-gate
2150Sstevel@tonic-gate while (match == NULL) {
2160Sstevel@tonic-gate if (aspp == default_policy) {
2170Sstevel@tonic-gate match = aspp;
2180Sstevel@tonic-gate } else {
2190Sstevel@tonic-gate if (V6_MASK_EQ(*addr, aspp->ip6_asp_mask,
2200Sstevel@tonic-gate aspp->ip6_asp_prefix))
2210Sstevel@tonic-gate match = aspp;
2220Sstevel@tonic-gate else
2230Sstevel@tonic-gate aspp++;
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate if (precedence != NULL)
2280Sstevel@tonic-gate *precedence = match->ip6_asp_precedence;
2290Sstevel@tonic-gate return (match->ip6_asp_label);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate * If we had deferred updating the table because of outstanding references,
2340Sstevel@tonic-gate * do it now. Note, we don't do error checking on the queued IOCTL mblk, since
2350Sstevel@tonic-gate * ip_sioctl_ip6addrpolicy() has already done it for us.
2360Sstevel@tonic-gate */
2370Sstevel@tonic-gate void
ip6_asp_check_for_updates(ip_stack_t * ipst)2383448Sdh155122 ip6_asp_check_for_updates(ip_stack_t *ipst)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate ip6_asp_t *table;
2410Sstevel@tonic-gate size_t table_size;
2420Sstevel@tonic-gate mblk_t *data_mp, *mp;
2430Sstevel@tonic-gate struct iocblk *iocp;
2440Sstevel@tonic-gate
2453448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
2463448Sdh155122 if (ipst->ips_ip6_asp_pending_update == NULL ||
2473448Sdh155122 ipst->ips_ip6_asp_refcnt > 0) {
2483448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
2490Sstevel@tonic-gate return;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate
2523448Sdh155122 mp = ipst->ips_ip6_asp_pending_update;
2533448Sdh155122 ipst->ips_ip6_asp_pending_update = NULL;
2540Sstevel@tonic-gate ASSERT(mp->b_prev != NULL);
2550Sstevel@tonic-gate
2563448Sdh155122 ipst->ips_ip6_asp_uip = B_TRUE;
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
2590Sstevel@tonic-gate data_mp = mp->b_cont;
2600Sstevel@tonic-gate if (data_mp == NULL) {
2610Sstevel@tonic-gate table = NULL;
2620Sstevel@tonic-gate table_size = iocp->ioc_count;
2630Sstevel@tonic-gate } else {
2640Sstevel@tonic-gate table = (ip6_asp_t *)data_mp->b_rptr;
2650Sstevel@tonic-gate table_size = iocp->ioc_count;
2660Sstevel@tonic-gate }
2670Sstevel@tonic-gate
2683448Sdh155122 ip6_asp_replace(mp, table, table_size, B_TRUE, ipst,
2690Sstevel@tonic-gate iocp->ioc_flag & IOC_MODELS);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * ip6_asp_replace replaces the contents of the IPv6 address selection
2740Sstevel@tonic-gate * policy table with those specified in new_table. If new_table is NULL,
2750Sstevel@tonic-gate * this indicates that the caller wishes ip to use the default policy
2760Sstevel@tonic-gate * table. The caller is responsible for making sure that there are exactly
2770Sstevel@tonic-gate * new_count policy entries in new_table.
2780Sstevel@tonic-gate */
2793448Sdh155122 /*ARGSUSED5*/
2800Sstevel@tonic-gate void
ip6_asp_replace(mblk_t * mp,ip6_asp_t * new_table,size_t new_size,boolean_t locked,ip_stack_t * ipst,model_t datamodel)2810Sstevel@tonic-gate ip6_asp_replace(mblk_t *mp, ip6_asp_t *new_table, size_t new_size,
2823448Sdh155122 boolean_t locked, ip_stack_t *ipst, model_t datamodel)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate int ret_val = 0;
2850Sstevel@tonic-gate ip6_asp_t *tmp_table;
2860Sstevel@tonic-gate uint_t count;
2870Sstevel@tonic-gate queue_t *q;
2880Sstevel@tonic-gate struct iocblk *iocp;
2890Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
2900Sstevel@tonic-gate size_t ip6_asp_size = SIZEOF_STRUCT(ip6_asp, datamodel);
2910Sstevel@tonic-gate #else
2920Sstevel@tonic-gate const size_t ip6_asp_size = sizeof (ip6_asp_t);
2930Sstevel@tonic-gate #endif
2940Sstevel@tonic-gate
2950Sstevel@tonic-gate if (new_size % ip6_asp_size != 0) {
2960Sstevel@tonic-gate ip1dbg(("ip6_asp_replace: invalid table size\n"));
2970Sstevel@tonic-gate ret_val = EINVAL;
2980Sstevel@tonic-gate if (locked)
2990Sstevel@tonic-gate goto unlock_end;
3000Sstevel@tonic-gate goto replace_end;
3010Sstevel@tonic-gate } else {
3020Sstevel@tonic-gate count = new_size / ip6_asp_size;
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate if (!locked)
3073448Sdh155122 mutex_enter(&ipst->ips_ip6_asp_lock);
3080Sstevel@tonic-gate /*
3090Sstevel@tonic-gate * Check if we are in the process of creating any IRE using the
3100Sstevel@tonic-gate * current information. If so, wait till that is done.
3110Sstevel@tonic-gate */
3123448Sdh155122 if (!locked && ipst->ips_ip6_asp_refcnt > 0) {
3130Sstevel@tonic-gate /* Save this request for later processing */
3143448Sdh155122 if (ipst->ips_ip6_asp_pending_update == NULL) {
3153448Sdh155122 ipst->ips_ip6_asp_pending_update = mp;
3160Sstevel@tonic-gate } else {
3170Sstevel@tonic-gate /* Let's not queue multiple requests for now */
3180Sstevel@tonic-gate ip1dbg(("ip6_asp_replace: discarding request\n"));
3193448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
3200Sstevel@tonic-gate ret_val = EAGAIN;
3210Sstevel@tonic-gate goto replace_end;
3220Sstevel@tonic-gate }
3233448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
3240Sstevel@tonic-gate return;
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate /* Prevent lookups till the table have been updated */
3280Sstevel@tonic-gate if (!locked)
3293448Sdh155122 ipst->ips_ip6_asp_uip = B_TRUE;
3300Sstevel@tonic-gate
3313448Sdh155122 ASSERT(ipst->ips_ip6_asp_refcnt == 0);
3320Sstevel@tonic-gate
3330Sstevel@tonic-gate if (new_table == NULL) {
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * This is a special case. The user wants to revert
3360Sstevel@tonic-gate * back to using the default table.
3370Sstevel@tonic-gate */
3383448Sdh155122 if (ipst->ips_ip6_asp_table == default_ip6_asp_table)
3390Sstevel@tonic-gate goto unlock_end;
3400Sstevel@tonic-gate
3413448Sdh155122 kmem_free(ipst->ips_ip6_asp_table,
3423448Sdh155122 ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
3433448Sdh155122 ipst->ips_ip6_asp_table = default_ip6_asp_table;
3443448Sdh155122 ipst->ips_ip6_asp_table_count =
3450Sstevel@tonic-gate sizeof (default_ip6_asp_table) / sizeof (ip6_asp_t);
3460Sstevel@tonic-gate goto unlock_end;
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate
3490Sstevel@tonic-gate if (count == 0) {
3500Sstevel@tonic-gate ret_val = EINVAL;
3510Sstevel@tonic-gate ip1dbg(("ip6_asp_replace: empty table\n"));
3520Sstevel@tonic-gate goto unlock_end;
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate
3550Sstevel@tonic-gate if ((tmp_table = kmem_alloc(count * sizeof (ip6_asp_t), KM_NOSLEEP)) ==
3560Sstevel@tonic-gate NULL) {
3570Sstevel@tonic-gate ret_val = ENOMEM;
3580Sstevel@tonic-gate goto unlock_end;
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
3620Sstevel@tonic-gate
3630Sstevel@tonic-gate /*
3640Sstevel@tonic-gate * If 'new_table' -actually- originates from a 32-bit process
3650Sstevel@tonic-gate * then the nicely aligned ip6_asp_label array will be
3660Sstevel@tonic-gate * subtlely misaligned on this kernel, because the structure
3670Sstevel@tonic-gate * is 8 byte aligned in the kernel, but only 4 byte aligned in
3680Sstevel@tonic-gate * userland. Fix it up here.
3690Sstevel@tonic-gate *
3700Sstevel@tonic-gate * XX64 See the notes in ip_sioctl_ip6addrpolicy. Perhaps we could
3710Sstevel@tonic-gate * do the datamodel transformation (below) there instead of here?
3720Sstevel@tonic-gate */
3730Sstevel@tonic-gate if (datamodel == IOC_ILP32) {
3740Sstevel@tonic-gate ip6_asp_t *dst;
3750Sstevel@tonic-gate ip6_asp32_t *src;
3760Sstevel@tonic-gate int i;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate if ((dst = kmem_zalloc(count * sizeof (*dst),
3790Sstevel@tonic-gate KM_NOSLEEP)) == NULL) {
3800Sstevel@tonic-gate kmem_free(tmp_table, count * sizeof (ip6_asp_t));
3810Sstevel@tonic-gate ret_val = ENOMEM;
3820Sstevel@tonic-gate goto unlock_end;
3830Sstevel@tonic-gate }
3840Sstevel@tonic-gate
3850Sstevel@tonic-gate /*
3860Sstevel@tonic-gate * Copy each element of the table from ip6_asp32_t
3870Sstevel@tonic-gate * format into ip6_asp_t format. Fortunately, since
3880Sstevel@tonic-gate * we're just dealing with a trailing structure pad,
3890Sstevel@tonic-gate * we can do this straightforwardly with a flurry of
3900Sstevel@tonic-gate * bcopying.
3910Sstevel@tonic-gate */
3920Sstevel@tonic-gate src = (void *)new_table;
3930Sstevel@tonic-gate for (i = 0; i < count; i++)
3940Sstevel@tonic-gate bcopy(src + i, dst + i, sizeof (*src));
3950Sstevel@tonic-gate
3960Sstevel@tonic-gate ip6_asp_copy(dst, tmp_table, count);
3970Sstevel@tonic-gate kmem_free(dst, count * sizeof (*dst));
3980Sstevel@tonic-gate } else
3990Sstevel@tonic-gate #endif
4000Sstevel@tonic-gate ip6_asp_copy(new_table, tmp_table, count);
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /* Make sure the last entry is the default entry */
4030Sstevel@tonic-gate if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_table[count - 1].ip6_asp_prefix) ||
4040Sstevel@tonic-gate !IN6_IS_ADDR_UNSPECIFIED(&tmp_table[count - 1].ip6_asp_mask)) {
4050Sstevel@tonic-gate ret_val = EINVAL;
4060Sstevel@tonic-gate kmem_free(tmp_table, count * sizeof (ip6_asp_t));
4070Sstevel@tonic-gate ip1dbg(("ip6_asp_replace: bad table: no default entry\n"));
4080Sstevel@tonic-gate goto unlock_end;
4090Sstevel@tonic-gate }
4103448Sdh155122 if (ipst->ips_ip6_asp_table != default_ip6_asp_table) {
4113448Sdh155122 kmem_free(ipst->ips_ip6_asp_table,
4123448Sdh155122 ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
4130Sstevel@tonic-gate }
4143448Sdh155122 ipst->ips_ip6_asp_table = tmp_table;
4153448Sdh155122 ipst->ips_ip6_asp_table_count = count;
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate unlock_end:
4183448Sdh155122 ipst->ips_ip6_asp_uip = B_FALSE;
4193448Sdh155122 mutex_exit(&ipst->ips_ip6_asp_lock);
4200Sstevel@tonic-gate
421*11042SErik.Nordmark@Sun.COM /* Let conn_ixa caching know that source address selection changed */
422*11042SErik.Nordmark@Sun.COM ip_update_source_selection(ipst);
423*11042SErik.Nordmark@Sun.COM
4240Sstevel@tonic-gate replace_end:
4250Sstevel@tonic-gate /* Reply to the ioctl */
4260Sstevel@tonic-gate q = (queue_t *)mp->b_prev;
4270Sstevel@tonic-gate mp->b_prev = NULL;
4280Sstevel@tonic-gate if (q == NULL) {
4290Sstevel@tonic-gate freemsg(mp);
4300Sstevel@tonic-gate goto check_binds;
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
4330Sstevel@tonic-gate iocp->ioc_error = ret_val;
4340Sstevel@tonic-gate iocp->ioc_count = 0;
4350Sstevel@tonic-gate DB_TYPE(mp) = (iocp->ioc_error == 0) ? M_IOCACK : M_IOCNAK;
4360Sstevel@tonic-gate qreply(q, mp);
4370Sstevel@tonic-gate check_binds:
4383448Sdh155122 ip6_asp_complete_op(ipst);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate /*
4420Sstevel@tonic-gate * Copies the contents of src_table to dst_table, and sorts the
4430Sstevel@tonic-gate * entries in decending order of prefix lengths. It assumes that both
4440Sstevel@tonic-gate * tables are appropriately sized to contain count entries.
4450Sstevel@tonic-gate */
4460Sstevel@tonic-gate static void
ip6_asp_copy(ip6_asp_t * src_table,ip6_asp_t * dst_table,uint_t count)4470Sstevel@tonic-gate ip6_asp_copy(ip6_asp_t *src_table, ip6_asp_t *dst_table, uint_t count)
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate ip6_asp_t *src_ptr, *src_limit, *dst_ptr, *dst_limit, *dp;
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate dst_table[0] = src_table[0];
4520Sstevel@tonic-gate if (count == 1)
4530Sstevel@tonic-gate return;
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate * Sort the entries in descending order of prefix lengths.
4570Sstevel@tonic-gate *
4580Sstevel@tonic-gate * Note: this should be a small table. In 99% of cases, we
4590Sstevel@tonic-gate * expect the table to have 5 entries. In the remaining 1%
4600Sstevel@tonic-gate * of cases, we expect the table to have one or two more
4610Sstevel@tonic-gate * entries. It would be very rare for the table to have
4620Sstevel@tonic-gate * double-digit entries.
4630Sstevel@tonic-gate */
4640Sstevel@tonic-gate src_limit = src_table + count;
4650Sstevel@tonic-gate dst_limit = dst_table + 1;
4660Sstevel@tonic-gate for (src_ptr = src_table + 1; src_ptr != src_limit;
4670Sstevel@tonic-gate src_ptr++, dst_limit++) {
4680Sstevel@tonic-gate for (dst_ptr = dst_table; dst_ptr < dst_limit; dst_ptr++) {
4690Sstevel@tonic-gate if (ip_mask_to_plen_v6(&src_ptr->ip6_asp_mask) >
4700Sstevel@tonic-gate ip_mask_to_plen_v6(&dst_ptr->ip6_asp_mask)) {
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate * Make room to insert the source entry
4730Sstevel@tonic-gate * before dst_ptr by shifting entries to
4740Sstevel@tonic-gate * the right.
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate for (dp = dst_limit - 1; dp >= dst_ptr; dp--)
4770Sstevel@tonic-gate *(dp + 1) = *dp;
4780Sstevel@tonic-gate break;
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate }
4810Sstevel@tonic-gate *dst_ptr = *src_ptr;
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate }
4840Sstevel@tonic-gate
4850Sstevel@tonic-gate /*
4860Sstevel@tonic-gate * This function copies as many entries from ip6_asp_table as will fit
4870Sstevel@tonic-gate * into dtable. The dtable_size parameter is the size of dtable
4880Sstevel@tonic-gate * in bytes. This function returns the number of entries in
4890Sstevel@tonic-gate * ip6_asp_table, even if it's not able to fit all of the entries into
4900Sstevel@tonic-gate * dtable.
4910Sstevel@tonic-gate */
4920Sstevel@tonic-gate int
ip6_asp_get(ip6_asp_t * dtable,size_t dtable_size,ip_stack_t * ipst)4933448Sdh155122 ip6_asp_get(ip6_asp_t *dtable, size_t dtable_size, ip_stack_t *ipst)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate uint_t dtable_count;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate if (dtable != NULL) {
4980Sstevel@tonic-gate if (dtable_size < sizeof (ip6_asp_t))
4990Sstevel@tonic-gate return (-1);
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate dtable_count = dtable_size / sizeof (ip6_asp_t);
5023448Sdh155122 bcopy(ipst->ips_ip6_asp_table, dtable,
5033448Sdh155122 MIN(ipst->ips_ip6_asp_table_count, dtable_count) *
5040Sstevel@tonic-gate sizeof (ip6_asp_t));
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5073448Sdh155122 return (ipst->ips_ip6_asp_table_count);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate /*
5110Sstevel@tonic-gate * Compare two labels. Return B_TRUE if they are equal, B_FALSE
5120Sstevel@tonic-gate * otherwise.
5130Sstevel@tonic-gate */
5140Sstevel@tonic-gate boolean_t
ip6_asp_labelcmp(const char * label1,const char * label2)5150Sstevel@tonic-gate ip6_asp_labelcmp(const char *label1, const char *label2)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate int64_t *llptr1, *llptr2;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate /*
5200Sstevel@tonic-gate * The common case, the two labels are actually the same string
5210Sstevel@tonic-gate * from the policy table.
5220Sstevel@tonic-gate */
5230Sstevel@tonic-gate if (label1 == label2)
5240Sstevel@tonic-gate return (B_TRUE);
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate /*
5270Sstevel@tonic-gate * Since we know the labels are at most 16 bytes long, compare
5280Sstevel@tonic-gate * the two strings as two 8-byte long integers. The ip6_asp_t
5290Sstevel@tonic-gate * structure guarantees that the labels are 8 byte alligned.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate llptr1 = (int64_t *)label1;
5320Sstevel@tonic-gate llptr2 = (int64_t *)label2;
5330Sstevel@tonic-gate if (llptr1[0] == llptr2[0] && llptr1[1] == llptr2[1])
5340Sstevel@tonic-gate return (B_TRUE);
5350Sstevel@tonic-gate return (B_FALSE);
5360Sstevel@tonic-gate }
537