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