Home | History | Annotate | Download | only in ip
      1      0    stevel /*
      2      0    stevel  * CDDL HEADER START
      3      0    stevel  *
      4      0    stevel  * The contents of this file are subject to the terms of the
      5   3448  dh155122  * Common Development and Distribution License (the "License").
      6   3448  dh155122  * You may not use this file except in compliance with the License.
      7      0    stevel  *
      8      0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0    stevel  * or http://www.opensolaris.org/os/licensing.
     10      0    stevel  * See the License for the specific language governing permissions
     11      0    stevel  * and limitations under the License.
     12      0    stevel  *
     13      0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0    stevel  *
     19      0    stevel  * CDDL HEADER END
     20      0    stevel  */
     21      0    stevel /*
     22  11042      Erik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0    stevel  * Use is subject to license terms.
     24      0    stevel  */
     25      0    stevel 
     26      0    stevel #include <sys/types.h>
     27      0    stevel #include <sys/socket.h>
     28      0    stevel #include <sys/ksynch.h>
     29      0    stevel #include <sys/kmem.h>
     30      0    stevel #include <sys/errno.h>
     31      0    stevel #include <sys/systm.h>
     32      0    stevel #include <sys/sysmacros.h>
     33      0    stevel #include <sys/cmn_err.h>
     34      0    stevel #include <sys/strsun.h>
     35      0    stevel #include <sys/zone.h>
     36      0    stevel #include <netinet/in.h>
     37      0    stevel #include <inet/common.h>
     38      0    stevel #include <inet/ip.h>
     39      0    stevel #include <inet/ip6.h>
     40      0    stevel #include <inet/ip6_asp.h>
     41      0    stevel #include <inet/ip_ire.h>
     42  11042      Erik #include <inet/ip_if.h>
     43   3448  dh155122 #include <inet/ipclassifier.h>
     44      0    stevel 
     45      0    stevel #define	IN6ADDR_MASK128_INIT \
     46      0    stevel 	{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU }
     47      0    stevel #define	IN6ADDR_MASK96_INIT	{ 0xffffffffU, 0xffffffffU, 0xffffffffU, 0 }
     48      0    stevel #ifdef _BIG_ENDIAN
     49      0    stevel #define	IN6ADDR_MASK16_INIT	{ 0xffff0000U, 0, 0, 0 }
     50      0    stevel #else
     51      0    stevel #define	IN6ADDR_MASK16_INIT	{ 0x0000ffffU, 0, 0, 0 }
     52      0    stevel #endif
     53      0    stevel 
     54      0    stevel 
     55      0    stevel /*
     56      0    stevel  * This table is ordered such that longest prefix matches are hit first
     57      0    stevel  * (longer prefix lengths first).  The last entry must be the "default"
     58      0    stevel  * entry (::0/0).
     59      0    stevel  */
     60      0    stevel static ip6_asp_t default_ip6_asp_table[] = {
     61      0    stevel 	{ IN6ADDR_LOOPBACK_INIT,	IN6ADDR_MASK128_INIT,
     62      0    stevel 	    "Loopback", 50 },
     63      0    stevel 	{ IN6ADDR_ANY_INIT,		IN6ADDR_MASK96_INIT,
     64      0    stevel 	    "IPv4_Compatible", 20 },
     65      0    stevel #ifdef _BIG_ENDIAN
     66      0    stevel 	{ { 0, 0, 0x0000ffffU, 0 },	IN6ADDR_MASK96_INIT,
     67      0    stevel 	    "IPv4", 10 },
     68      0    stevel 	{ { 0x20020000U, 0, 0, 0 },	IN6ADDR_MASK16_INIT,
     69      0    stevel 	    "6to4", 30 },
     70      0    stevel #else
     71      0    stevel 	{ { 0, 0, 0xffff0000U, 0 },	IN6ADDR_MASK96_INIT,
     72      0    stevel 	    "IPv4", 10 },
     73      0    stevel 	{ { 0x00000220U, 0, 0, 0 },	IN6ADDR_MASK16_INIT,
     74      0    stevel 	    "6to4", 30 },
     75      0    stevel #endif
     76      0    stevel 	{ IN6ADDR_ANY_INIT,		IN6ADDR_ANY_INIT,
     77      0    stevel 	    "Default", 40 }
     78      0    stevel };
     79      0    stevel 
     80      0    stevel /*
     81      0    stevel  * The IPv6 Default Address Selection policy table.
     82      0    stevel  * Until someone up above reconfigures the policy table, use the global
     83      0    stevel  * default.  The table needs no lock since the only way to alter it is
     84      0    stevel  * through the SIOCSIP6ADDRPOLICY which is exclusive in ip.
     85      0    stevel  */
     86      0    stevel static void ip6_asp_copy(ip6_asp_t *, ip6_asp_t *, uint_t);
     87   3448  dh155122 static void ip6_asp_check_for_updates(ip_stack_t *);
     88      0    stevel 
     89      0    stevel void
     90   3448  dh155122 ip6_asp_init(ip_stack_t *ipst)
     91      0    stevel {
     92      0    stevel 	/* Initialize the table lock */
     93   3448  dh155122 	mutex_init(&ipst->ips_ip6_asp_lock, NULL, MUTEX_DEFAULT, NULL);
     94   3448  dh155122 
     95   3448  dh155122 	ipst->ips_ip6_asp_table = default_ip6_asp_table;
     96   3448  dh155122 
     97   3448  dh155122 	ipst->ips_ip6_asp_table_count =
     98   3448  dh155122 	    sizeof (default_ip6_asp_table) / sizeof (ip6_asp_t);
     99      0    stevel }
    100      0    stevel 
    101      0    stevel void
    102   3448  dh155122 ip6_asp_free(ip_stack_t *ipst)
    103      0    stevel {
    104   3448  dh155122 	if (ipst->ips_ip6_asp_table != default_ip6_asp_table) {
    105   3448  dh155122 		kmem_free(ipst->ips_ip6_asp_table,
    106   3448  dh155122 		    ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
    107   3448  dh155122 		ipst->ips_ip6_asp_table = NULL;
    108      0    stevel 	}
    109   3448  dh155122 	mutex_destroy(&ipst->ips_ip6_asp_lock);
    110      0    stevel }
    111      0    stevel 
    112      0    stevel /*
    113      0    stevel  * Return false if the table is being updated. Else, increment the ref
    114      0    stevel  * count and return true.
    115      0    stevel  */
    116      0    stevel boolean_t
    117   3448  dh155122 ip6_asp_can_lookup(ip_stack_t *ipst)
    118      0    stevel {
    119   3448  dh155122 	mutex_enter(&ipst->ips_ip6_asp_lock);
    120   3448  dh155122 	if (ipst->ips_ip6_asp_uip) {
    121   3448  dh155122 		mutex_exit(&ipst->ips_ip6_asp_lock);
    122      0    stevel 		return (B_FALSE);
    123      0    stevel 	}
    124   3448  dh155122 	IP6_ASP_TABLE_REFHOLD(ipst);
    125   3448  dh155122 	mutex_exit(&ipst->ips_ip6_asp_lock);
    126      0    stevel 	return (B_TRUE);
    127      0    stevel 
    128      0    stevel }
    129      0    stevel 
    130      0    stevel void
    131      0    stevel ip6_asp_pending_op(queue_t *q, mblk_t *mp, aspfunc_t func)
    132      0    stevel {
    133   3448  dh155122 	conn_t	*connp = Q_TO_CONN(q);
    134   3448  dh155122 	ip_stack_t *ipst = connp->conn_netstack->netstack_ip;
    135      0    stevel 
    136      0    stevel 	ASSERT((mp->b_prev == NULL) && (mp->b_queue == NULL) &&
    137      0    stevel 	    (mp->b_next == NULL));
    138      0    stevel 	mp->b_queue = (void *)q;
    139      0    stevel 	mp->b_prev = (void *)func;
    140      0    stevel 	mp->b_next = NULL;
    141      0    stevel 
    142   3448  dh155122 	mutex_enter(&ipst->ips_ip6_asp_lock);
    143   3448  dh155122 	if (ipst->ips_ip6_asp_pending_ops == NULL) {
    144   3448  dh155122 		ASSERT(ipst->ips_ip6_asp_pending_ops_tail == NULL);
    145   3448  dh155122 		ipst->ips_ip6_asp_pending_ops =
    146   3448  dh155122 		    ipst->ips_ip6_asp_pending_ops_tail = mp;
    147      0    stevel 	} else {
    148   3448  dh155122 		ipst->ips_ip6_asp_pending_ops_tail->b_next = mp;
    149   3448  dh155122 		ipst->ips_ip6_asp_pending_ops_tail = mp;
    150      0    stevel 	}
    151   3448  dh155122 	mutex_exit(&ipst->ips_ip6_asp_lock);
    152      0    stevel }
    153      0    stevel 
    154      0    stevel static void
    155   3448  dh155122 ip6_asp_complete_op(ip_stack_t *ipst)
    156      0    stevel {
    157      0    stevel 	mblk_t		*mp;
    158      0    stevel 	queue_t		*q;
    159      0    stevel 	aspfunc_t	func;
    160      0    stevel 
    161   3448  dh155122 	mutex_enter(&ipst->ips_ip6_asp_lock);
    162   3448  dh155122 	while (ipst->ips_ip6_asp_pending_ops != NULL) {
    163   3448  dh155122 		mp = ipst->ips_ip6_asp_pending_ops;
    164   3448  dh155122 		ipst->ips_ip6_asp_pending_ops = mp->b_next;
    165      0    stevel 		mp->b_next = NULL;
    166   3448  dh155122 		if (ipst->ips_ip6_asp_pending_ops == NULL)
    167   3448  dh155122 			ipst->ips_ip6_asp_pending_ops_tail = NULL;
    168   3448  dh155122 		mutex_exit(&ipst->ips_ip6_asp_lock);
    169      0    stevel 
    170      0    stevel 		q = (queue_t *)mp->b_queue;
    171      0    stevel 		func = (aspfunc_t)mp->b_prev;
    172      0    stevel 
    173      0    stevel 		mp->b_prev = NULL;
    174      0    stevel 		mp->b_queue = NULL;
    175      0    stevel 
    176      0    stevel 
    177      0    stevel 		(*func)(NULL, q, mp, NULL);
    178   3448  dh155122 		mutex_enter(&ipst->ips_ip6_asp_lock);
    179      0    stevel 	}
    180   3448  dh155122 	mutex_exit(&ipst->ips_ip6_asp_lock);
    181      0    stevel }
    182      0    stevel 
    183      0    stevel /*
    184      0    stevel  * Decrement reference count. When it gets to 0, we check for (pending)
    185      0    stevel  * saved update to the table, if any.
    186      0    stevel  */
    187      0    stevel void
    188   3448  dh155122 ip6_asp_table_refrele(ip_stack_t *ipst)
    189      0    stevel {
    190   3448  dh155122 	IP6_ASP_TABLE_REFRELE(ipst);
    191      0    stevel }
    192      0    stevel 
    193      0    stevel /*
    194      0    stevel  * This function is guaranteed never to return a NULL pointer.  It
    195      0    stevel  * will always return information from one of the entries in the
    196      0    stevel  * asp_table (which will never be empty).  If a pointer is passed
    197      0    stevel  * in for the precedence, the precedence value will be set; a
    198      0    stevel  * pointer to the label will be returned by the function.
    199      0    stevel  *
    200      0    stevel  * Since the table is only anticipated to have five or six entries
    201      0    stevel  * total, the lookup algorithm hasn't been optimized to anything
    202      0    stevel  * better than O(n).
    203      0    stevel  */
    204      0    stevel char *
    205   3448  dh155122 ip6_asp_lookup(const in6_addr_t *addr, uint32_t *precedence, ip_stack_t *ipst)
    206      0    stevel {
    207      0    stevel 	ip6_asp_t *aspp;
    208      0    stevel 	ip6_asp_t *match = NULL;
    209      0    stevel 	ip6_asp_t *default_policy;
    210      0    stevel 
    211   3448  dh155122 	aspp = ipst->ips_ip6_asp_table;
    212      0    stevel 	/* The default entry must always be the last one */
    213   3448  dh155122 	default_policy = aspp + ipst->ips_ip6_asp_table_count - 1;
    214      0    stevel 
    215      0    stevel 	while (match == NULL) {
    216      0    stevel 		if (aspp == default_policy) {
    217      0    stevel 			match = aspp;
    218      0    stevel 		} else {
    219      0    stevel 			if (V6_MASK_EQ(*addr, aspp->ip6_asp_mask,
    220      0    stevel 			    aspp->ip6_asp_prefix))
    221      0    stevel 				match = aspp;
    222      0    stevel 			else
    223      0    stevel 				aspp++;
    224      0    stevel 		}
    225      0    stevel 	}
    226      0    stevel 
    227      0    stevel 	if (precedence != NULL)
    228      0    stevel 		*precedence = match->ip6_asp_precedence;
    229      0    stevel 	return (match->ip6_asp_label);
    230      0    stevel }
    231      0    stevel 
    232      0    stevel /*
    233      0    stevel  * If we had deferred updating the table because of outstanding references,
    234      0    stevel  * do it now. Note, we don't do error checking on the queued IOCTL mblk, since
    235      0    stevel  * ip_sioctl_ip6addrpolicy() has already done it for us.
    236      0    stevel  */
    237      0    stevel void
    238   3448  dh155122 ip6_asp_check_for_updates(ip_stack_t *ipst)
    239      0    stevel {
    240      0    stevel 	ip6_asp_t *table;
    241      0    stevel 	size_t	table_size;
    242      0    stevel 	mblk_t	*data_mp, *mp;
    243      0    stevel 	struct iocblk *iocp;
    244      0    stevel 
    245   3448  dh155122 	mutex_enter(&ipst->ips_ip6_asp_lock);
    246   3448  dh155122 	if (ipst->ips_ip6_asp_pending_update == NULL ||
    247   3448  dh155122 	    ipst->ips_ip6_asp_refcnt > 0) {
    248   3448  dh155122 		mutex_exit(&ipst->ips_ip6_asp_lock);
    249      0    stevel 		return;
    250      0    stevel 	}
    251      0    stevel 
    252   3448  dh155122 	mp = ipst->ips_ip6_asp_pending_update;
    253   3448  dh155122 	ipst->ips_ip6_asp_pending_update = NULL;
    254      0    stevel 	ASSERT(mp->b_prev != NULL);
    255      0    stevel 
    256   3448  dh155122 	ipst->ips_ip6_asp_uip = B_TRUE;
    257      0    stevel 
    258      0    stevel 	iocp = (struct iocblk *)mp->b_rptr;
    259      0    stevel 	data_mp = mp->b_cont;
    260      0    stevel 	if (data_mp == NULL) {
    261      0    stevel 		table = NULL;
    262      0    stevel 		table_size = iocp->ioc_count;
    263      0    stevel 	} else {
    264      0    stevel 		table = (ip6_asp_t *)data_mp->b_rptr;
    265      0    stevel 		table_size = iocp->ioc_count;
    266      0    stevel 	}
    267      0    stevel 
    268   3448  dh155122 	ip6_asp_replace(mp, table, table_size, B_TRUE, ipst,
    269      0    stevel 	    iocp->ioc_flag & IOC_MODELS);
    270      0    stevel }
    271      0    stevel 
    272      0    stevel /*
    273      0    stevel  * ip6_asp_replace replaces the contents of the IPv6 address selection
    274      0    stevel  * policy table with those specified in new_table.  If new_table is NULL,
    275      0    stevel  * this indicates that the caller wishes ip to use the default policy
    276      0    stevel  * table.  The caller is responsible for making sure that there are exactly
    277      0    stevel  * new_count policy entries in new_table.
    278      0    stevel  */
    279   3448  dh155122 /*ARGSUSED5*/
    280      0    stevel void
    281      0    stevel ip6_asp_replace(mblk_t *mp, ip6_asp_t *new_table, size_t new_size,
    282   3448  dh155122     boolean_t locked, ip_stack_t *ipst, model_t datamodel)
    283      0    stevel {
    284      0    stevel 	int			ret_val = 0;
    285      0    stevel 	ip6_asp_t		*tmp_table;
    286      0    stevel 	uint_t			count;
    287      0    stevel 	queue_t			*q;
    288      0    stevel 	struct iocblk		*iocp;
    289      0    stevel #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
    290      0    stevel 	size_t ip6_asp_size = SIZEOF_STRUCT(ip6_asp, datamodel);
    291      0    stevel #else
    292      0    stevel 	const size_t ip6_asp_size = sizeof (ip6_asp_t);
    293      0    stevel #endif
    294      0    stevel 
    295      0    stevel 	if (new_size % ip6_asp_size != 0) {
    296      0    stevel 		ip1dbg(("ip6_asp_replace: invalid table size\n"));
    297      0    stevel 		ret_val = EINVAL;
    298      0    stevel 		if (locked)
    299      0    stevel 			goto unlock_end;
    300      0    stevel 		goto replace_end;
    301      0    stevel 	} else {
    302      0    stevel 		count = new_size / ip6_asp_size;
    303      0    stevel 	}
    304      0    stevel 
    305      0    stevel 
    306      0    stevel 	if (!locked)
    307   3448  dh155122 		mutex_enter(&ipst->ips_ip6_asp_lock);
    308      0    stevel 	/*
    309      0    stevel 	 * Check if we are in the process of creating any IRE using the
    310      0    stevel 	 * current information. If so, wait till that is done.
    311      0    stevel 	 */
    312   3448  dh155122 	if (!locked && ipst->ips_ip6_asp_refcnt > 0) {
    313      0    stevel 		/* Save this request for later processing */
    314   3448  dh155122 		if (ipst->ips_ip6_asp_pending_update == NULL) {
    315   3448  dh155122 			ipst->ips_ip6_asp_pending_update = mp;
    316      0    stevel 		} else {
    317      0    stevel 			/* Let's not queue multiple requests for now */
    318      0    stevel 			ip1dbg(("ip6_asp_replace: discarding request\n"));
    319   3448  dh155122 			mutex_exit(&ipst->ips_ip6_asp_lock);
    320      0    stevel 			ret_val =  EAGAIN;
    321      0    stevel 			goto replace_end;
    322      0    stevel 		}
    323   3448  dh155122 		mutex_exit(&ipst->ips_ip6_asp_lock);
    324      0    stevel 		return;
    325      0    stevel 	}
    326      0    stevel 
    327      0    stevel 	/* Prevent lookups till the table have been updated */
    328      0    stevel 	if (!locked)
    329   3448  dh155122 		ipst->ips_ip6_asp_uip = B_TRUE;
    330      0    stevel 
    331   3448  dh155122 	ASSERT(ipst->ips_ip6_asp_refcnt == 0);
    332      0    stevel 
    333      0    stevel 	if (new_table == NULL) {
    334      0    stevel 		/*
    335      0    stevel 		 * This is a special case.  The user wants to revert
    336      0    stevel 		 * back to using the default table.
    337      0    stevel 		 */
    338   3448  dh155122 		if (ipst->ips_ip6_asp_table == default_ip6_asp_table)
    339      0    stevel 			goto unlock_end;
    340      0    stevel 
    341   3448  dh155122 		kmem_free(ipst->ips_ip6_asp_table,
    342   3448  dh155122 		    ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
    343   3448  dh155122 		ipst->ips_ip6_asp_table = default_ip6_asp_table;
    344   3448  dh155122 		ipst->ips_ip6_asp_table_count =
    345      0    stevel 		    sizeof (default_ip6_asp_table) / sizeof (ip6_asp_t);
    346      0    stevel 		goto unlock_end;
    347      0    stevel 	}
    348      0    stevel 
    349      0    stevel 	if (count == 0) {
    350      0    stevel 		ret_val = EINVAL;
    351      0    stevel 		ip1dbg(("ip6_asp_replace: empty table\n"));
    352      0    stevel 		goto unlock_end;
    353      0    stevel 	}
    354      0    stevel 
    355      0    stevel 	if ((tmp_table = kmem_alloc(count * sizeof (ip6_asp_t), KM_NOSLEEP)) ==
    356      0    stevel 	    NULL) {
    357      0    stevel 		ret_val = ENOMEM;
    358      0    stevel 		goto unlock_end;
    359      0    stevel 	}
    360      0    stevel 
    361      0    stevel #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
    362      0    stevel 
    363      0    stevel 	/*
    364      0    stevel 	 * If 'new_table' -actually- originates from a 32-bit process
    365      0    stevel 	 * then the nicely aligned ip6_asp_label array will be
    366      0    stevel 	 * subtlely misaligned on this kernel, because the structure
    367      0    stevel 	 * is 8 byte aligned in the kernel, but only 4 byte aligned in
    368      0    stevel 	 * userland.  Fix it up here.
    369      0    stevel 	 *
    370      0    stevel 	 * XX64	See the notes in ip_sioctl_ip6addrpolicy.  Perhaps we could
    371      0    stevel 	 *	do the datamodel transformation (below) there instead of here?
    372      0    stevel 	 */
    373      0    stevel 	if (datamodel == IOC_ILP32) {
    374      0    stevel 		ip6_asp_t *dst;
    375      0    stevel 		ip6_asp32_t *src;
    376      0    stevel 		int i;
    377      0    stevel 
    378      0    stevel 		if ((dst = kmem_zalloc(count * sizeof (*dst),
    379      0    stevel 		    KM_NOSLEEP)) == NULL) {
    380      0    stevel 			kmem_free(tmp_table, count * sizeof (ip6_asp_t));
    381      0    stevel 			ret_val = ENOMEM;
    382      0    stevel 			goto unlock_end;
    383      0    stevel 		}
    384      0    stevel 
    385      0    stevel 		/*
    386      0    stevel 		 * Copy each element of the table from ip6_asp32_t
    387      0    stevel 		 * format into ip6_asp_t format.  Fortunately, since
    388      0    stevel 		 * we're just dealing with a trailing structure pad,
    389      0    stevel 		 * we can do this straightforwardly with a flurry of
    390      0    stevel 		 * bcopying.
    391      0    stevel 		 */
    392      0    stevel 		src = (void *)new_table;
    393      0    stevel 		for (i = 0; i < count; i++)
    394      0    stevel 			bcopy(src + i, dst + i, sizeof (*src));
    395      0    stevel 
    396      0    stevel 		ip6_asp_copy(dst, tmp_table, count);
    397      0    stevel 		kmem_free(dst, count * sizeof (*dst));
    398      0    stevel 	} else
    399      0    stevel #endif
    400      0    stevel 		ip6_asp_copy(new_table, tmp_table, count);
    401      0    stevel 
    402      0    stevel 	/* Make sure the last entry is the default entry */
    403      0    stevel 	if (!IN6_IS_ADDR_UNSPECIFIED(&tmp_table[count - 1].ip6_asp_prefix) ||
    404      0    stevel 	    !IN6_IS_ADDR_UNSPECIFIED(&tmp_table[count - 1].ip6_asp_mask)) {
    405      0    stevel 		ret_val = EINVAL;
    406      0    stevel 		kmem_free(tmp_table, count * sizeof (ip6_asp_t));
    407      0    stevel 		ip1dbg(("ip6_asp_replace: bad table: no default entry\n"));
    408      0    stevel 		goto unlock_end;
    409      0    stevel 	}
    410   3448  dh155122 	if (ipst->ips_ip6_asp_table != default_ip6_asp_table) {
    411   3448  dh155122 		kmem_free(ipst->ips_ip6_asp_table,
    412   3448  dh155122 		    ipst->ips_ip6_asp_table_count * sizeof (ip6_asp_t));
    413      0    stevel 	}
    414   3448  dh155122 	ipst->ips_ip6_asp_table = tmp_table;
    415   3448  dh155122 	ipst->ips_ip6_asp_table_count = count;
    416      0    stevel 
    417      0    stevel unlock_end:
    418   3448  dh155122 	ipst->ips_ip6_asp_uip = B_FALSE;
    419   3448  dh155122 	mutex_exit(&ipst->ips_ip6_asp_lock);
    420  11042      Erik 
    421  11042      Erik 	/* Let conn_ixa caching know that source address selection changed */
    422  11042      Erik 	ip_update_source_selection(ipst);
    423      0    stevel 
    424      0    stevel replace_end:
    425      0    stevel 	/* Reply to the ioctl */
    426      0    stevel 	q = (queue_t *)mp->b_prev;
    427      0    stevel 	mp->b_prev = NULL;
    428      0    stevel 	if (q == NULL) {
    429      0    stevel 		freemsg(mp);
    430      0    stevel 		goto check_binds;
    431      0    stevel 	}
    432      0    stevel 	iocp = (struct iocblk *)mp->b_rptr;
    433      0    stevel 	iocp->ioc_error = ret_val;
    434      0    stevel 	iocp->ioc_count = 0;
    435      0    stevel 	DB_TYPE(mp) = (iocp->ioc_error == 0) ? M_IOCACK : M_IOCNAK;
    436      0    stevel 	qreply(q, mp);
    437      0    stevel check_binds:
    438   3448  dh155122 	ip6_asp_complete_op(ipst);
    439      0    stevel }
    440      0    stevel 
    441      0    stevel /*
    442      0    stevel  * Copies the contents of src_table to dst_table, and sorts the
    443      0    stevel  * entries in decending order of prefix lengths.  It assumes that both
    444      0    stevel  * tables are appropriately sized to contain count entries.
    445      0    stevel  */
    446      0    stevel static void
    447      0    stevel ip6_asp_copy(ip6_asp_t *src_table, ip6_asp_t *dst_table, uint_t count)
    448      0    stevel {
    449      0    stevel 	ip6_asp_t *src_ptr, *src_limit, *dst_ptr, *dst_limit, *dp;
    450      0    stevel 
    451      0    stevel 	dst_table[0] = src_table[0];
    452      0    stevel 	if (count == 1)
    453      0    stevel 		return;
    454      0    stevel 
    455      0    stevel 	/*
    456      0    stevel 	 * Sort the entries in descending order of prefix lengths.
    457      0    stevel 	 *
    458      0    stevel 	 * Note: this should be a small table.  In 99% of cases, we
    459      0    stevel 	 * expect the table to have 5 entries.  In the remaining 1%
    460      0    stevel 	 * of cases, we expect the table to have one or two more
    461      0    stevel 	 * entries.  It would be very rare for the table to have
    462      0    stevel 	 * double-digit entries.
    463      0    stevel 	 */
    464      0    stevel 	src_limit = src_table + count;
    465      0    stevel 	dst_limit = dst_table + 1;
    466      0    stevel 	for (src_ptr = src_table + 1; src_ptr != src_limit;
    467      0    stevel 	    src_ptr++, dst_limit++) {
    468      0    stevel 		for (dst_ptr = dst_table; dst_ptr < dst_limit; dst_ptr++) {
    469      0    stevel 			if (ip_mask_to_plen_v6(&src_ptr->ip6_asp_mask) >
    470      0    stevel 			    ip_mask_to_plen_v6(&dst_ptr->ip6_asp_mask)) {
    471      0    stevel 				/*
    472      0    stevel 				 * Make room to insert the source entry
    473      0    stevel 				 * before dst_ptr by shifting entries to
    474      0    stevel 				 * the right.
    475      0    stevel 				 */
    476      0    stevel 				for (dp = dst_limit - 1; dp >= dst_ptr; dp--)
    477      0    stevel 					*(dp + 1) = *dp;
    478      0    stevel 				break;
    479      0    stevel 			}
    480      0    stevel 		}
    481      0    stevel 		*dst_ptr = *src_ptr;
    482      0    stevel 	}
    483      0    stevel }
    484      0    stevel 
    485      0    stevel /*
    486      0    stevel  * This function copies as many entries from ip6_asp_table as will fit
    487      0    stevel  * into dtable.  The dtable_size parameter is the size of dtable
    488      0    stevel  * in bytes.  This function returns the number of entries in
    489      0    stevel  * ip6_asp_table, even if it's not able to fit all of the entries into
    490      0    stevel  * dtable.
    491      0    stevel  */
    492      0    stevel int
    493   3448  dh155122 ip6_asp_get(ip6_asp_t *dtable, size_t dtable_size, ip_stack_t *ipst)
    494      0    stevel {
    495      0    stevel 	uint_t dtable_count;
    496      0    stevel 
    497      0    stevel 	if (dtable != NULL) {
    498      0    stevel 		if (dtable_size < sizeof (ip6_asp_t))
    499      0    stevel 			return (-1);
    500      0    stevel 
    501      0    stevel 		dtable_count = dtable_size / sizeof (ip6_asp_t);
    502   3448  dh155122 		bcopy(ipst->ips_ip6_asp_table, dtable,
    503   3448  dh155122 		    MIN(ipst->ips_ip6_asp_table_count, dtable_count) *
    504      0    stevel 		    sizeof (ip6_asp_t));
    505      0    stevel 	}
    506      0    stevel 
    507   3448  dh155122 	return (ipst->ips_ip6_asp_table_count);
    508      0    stevel }
    509      0    stevel 
    510      0    stevel /*
    511      0    stevel  * Compare two labels.  Return B_TRUE if they are equal, B_FALSE
    512      0    stevel  * otherwise.
    513      0    stevel  */
    514      0    stevel boolean_t
    515      0    stevel ip6_asp_labelcmp(const char *label1, const char *label2)
    516      0    stevel {
    517      0    stevel 	int64_t *llptr1, *llptr2;
    518      0    stevel 
    519      0    stevel 	/*
    520      0    stevel 	 * The common case, the two labels are actually the same string
    521      0    stevel 	 * from the policy table.
    522      0    stevel 	 */
    523      0    stevel 	if (label1 == label2)
    524      0    stevel 		return (B_TRUE);
    525      0    stevel 
    526      0    stevel 	/*
    527      0    stevel 	 * Since we know the labels are at most 16 bytes long, compare
    528      0    stevel 	 * the two strings as two 8-byte long integers.  The ip6_asp_t
    529      0    stevel 	 * structure guarantees that the labels are 8 byte alligned.
    530      0    stevel 	 */
    531      0    stevel 	llptr1 = (int64_t *)label1;
    532      0    stevel 	llptr2 = (int64_t *)label2;
    533      0    stevel 	if (llptr1[0] == llptr2[0] && llptr1[1] == llptr2[1])
    534      0    stevel 		return (B_TRUE);
    535      0    stevel 	return (B_FALSE);
    536      0    stevel }
    537