in6_src.c revision 122058
1/* $FreeBSD: head/sys/netinet6/in6_src.c 122058 2003-11-04 14:08:31Z ume $ */ 2/* $KAME: in6_src.c,v 1.37 2001/03/29 05:34:31 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33/* 34 * Copyright (c) 1982, 1986, 1991, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. All advertising materials mentioning features or use of this software 46 * must display the following acknowledgement: 47 * This product includes software developed by the University of 48 * California, Berkeley and its contributors. 49 * 4. Neither the name of the University nor the names of its contributors 50 * may be used to endorse or promote products derived from this software 51 * without specific prior written permission. 52 * 53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63 * SUCH DAMAGE. 64 * 65 * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 66 */ 67 68#include "opt_inet.h" 69#include "opt_inet6.h" 70 71#include <sys/param.h> 72#include <sys/systm.h> 73#include <sys/malloc.h> 74#include <sys/mbuf.h> 75#include <sys/protosw.h> 76#include <sys/socket.h> 77#include <sys/socketvar.h> 78#include <sys/sockio.h> 79#include <sys/sysctl.h> 80#include <sys/errno.h> 81#include <sys/time.h> 82#include <sys/kernel.h> 83 84#include <net/if.h> 85#include <net/route.h> 86 87#include <netinet/in.h> 88#include <netinet/in_var.h> 89#include <netinet/in_systm.h> 90#include <netinet/ip.h> 91#include <netinet/in_pcb.h> 92#include <netinet6/in6_var.h> 93#include <netinet/ip6.h> 94#include <netinet6/in6_pcb.h> 95#include <netinet6/ip6_var.h> 96#include <netinet6/nd6.h> 97#ifdef ENABLE_DEFAULT_SCOPE 98#include <netinet6/scope6_var.h> 99#endif 100 101#include <net/net_osdep.h> 102 103static struct mtx addrsel_lock; 104#define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF) 105#define ADDRSEL_LOCK() mtx_lock(&addrsel_lock) 106#define ADDRSEL_UNLOCK() mtx_unlock(&addrsel_lock) 107#define ADDRSEL_LOCK_ASSERT() mtx_assert(&addrsel_lock, MA_OWNED) 108 109#define ADDR_LABEL_NOTAPP (-1) 110struct in6_addrpolicy defaultaddrpolicy; 111 112static void init_policy_queue __P((void)); 113static int add_addrsel_policyent __P((struct in6_addrpolicy *)); 114static int delete_addrsel_policyent __P((struct in6_addrpolicy *)); 115static int walk_addrsel_policy __P((int (*)(struct in6_addrpolicy *, void *), 116 void *)); 117static int dump_addrsel_policyent __P((struct in6_addrpolicy *, void *)); 118 119/* 120 * Return an IPv6 address, which is the most appropriate for a given 121 * destination and user specified options. 122 * If necessary, this function lookups the routing table and returns 123 * an entry to the caller for later use. 124 */ 125struct in6_addr * 126in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) 127 struct sockaddr_in6 *dstsock; 128 struct ip6_pktopts *opts; 129 struct ip6_moptions *mopts; 130 struct route_in6 *ro; 131 struct in6_addr *laddr; 132 int *errorp; 133{ 134 struct in6_addr *dst; 135 struct in6_ifaddr *ia6 = 0; 136 struct in6_pktinfo *pi = NULL; 137 138 dst = &dstsock->sin6_addr; 139 *errorp = 0; 140 141 /* 142 * If the source address is explicitly specified by the caller, 143 * use it. 144 */ 145 if (opts && (pi = opts->ip6po_pktinfo) && 146 !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) 147 return (&pi->ipi6_addr); 148 149 /* 150 * If the source address is not specified but the socket(if any) 151 * is already bound, use the bound address. 152 */ 153 if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) 154 return (laddr); 155 156 /* 157 * If the caller doesn't specify the source address but 158 * the outgoing interface, use an address associated with 159 * the interface. 160 */ 161 if (pi && pi->ipi6_ifindex) { 162 /* XXX boundary check is assumed to be already done. */ 163 ia6 = in6_ifawithscope(ifnet_byindex(pi->ipi6_ifindex), dst); 164 if (ia6 == 0) { 165 *errorp = EADDRNOTAVAIL; 166 return (0); 167 } 168 return (&satosin6(&ia6->ia_addr)->sin6_addr); 169 } 170 171 /* 172 * If the destination address is a link-local unicast address or 173 * a multicast address, and if the outgoing interface is specified 174 * by the sin6_scope_id filed, use an address associated with the 175 * interface. 176 * XXX: We're now trying to define more specific semantics of 177 * sin6_scope_id field, so this part will be rewritten in 178 * the near future. 179 */ 180 if ((IN6_IS_ADDR_LINKLOCAL(dst) || IN6_IS_ADDR_MULTICAST(dst)) && 181 dstsock->sin6_scope_id) { 182 /* 183 * I'm not sure if boundary check for scope_id is done 184 * somewhere... 185 */ 186 if (dstsock->sin6_scope_id < 0 || 187 if_index < dstsock->sin6_scope_id) { 188 *errorp = ENXIO; /* XXX: better error? */ 189 return (0); 190 } 191 ia6 = in6_ifawithscope(ifnet_byindex(dstsock->sin6_scope_id), 192 dst); 193 if (ia6 == 0) { 194 *errorp = EADDRNOTAVAIL; 195 return (0); 196 } 197 return (&satosin6(&ia6->ia_addr)->sin6_addr); 198 } 199 200 /* 201 * If the destination address is a multicast address and 202 * the outgoing interface for the address is specified 203 * by the caller, use an address associated with the interface. 204 * There is a sanity check here; if the destination has node-local 205 * scope, the outgoing interfacde should be a loopback address. 206 * Even if the outgoing interface is not specified, we also 207 * choose a loopback interface as the outgoing interface. 208 */ 209 if (IN6_IS_ADDR_MULTICAST(dst)) { 210 struct ifnet *ifp = mopts ? mopts->im6o_multicast_ifp : NULL; 211 212 if (ifp == NULL && IN6_IS_ADDR_MC_INTFACELOCAL(dst)) { 213 ifp = &loif[0]; 214 } 215 216 if (ifp) { 217 ia6 = in6_ifawithscope(ifp, dst); 218 if (ia6 == 0) { 219 *errorp = EADDRNOTAVAIL; 220 return (0); 221 } 222 return (&satosin6(&ia6->ia_addr)->sin6_addr); 223 } 224 } 225 226 /* 227 * If the next hop address for the packet is specified 228 * by caller, use an address associated with the route 229 * to the next hop. 230 */ 231 { 232 struct sockaddr_in6 *sin6_next; 233 struct rtentry *rt; 234 235 if (opts && opts->ip6po_nexthop) { 236 sin6_next = satosin6(opts->ip6po_nexthop); 237 rt = nd6_lookup(&sin6_next->sin6_addr, 1, NULL); 238 if (rt) { 239 ia6 = in6_ifawithscope(rt->rt_ifp, dst); 240 if (ia6 == 0) 241 ia6 = ifatoia6(rt->rt_ifa); 242 } 243 if (ia6 == 0) { 244 *errorp = EADDRNOTAVAIL; 245 return (0); 246 } 247 return (&satosin6(&ia6->ia_addr)->sin6_addr); 248 } 249 } 250 251 /* 252 * If route is known or can be allocated now, 253 * our src addr is taken from the i/f, else punt. 254 */ 255 if (ro) { 256 if (ro->ro_rt && 257 (!(ro->ro_rt->rt_flags & RTF_UP) || 258 satosin6(&ro->ro_dst)->sin6_family != AF_INET6 || 259 !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, 260 dst))) { 261 RTFREE(ro->ro_rt); 262 ro->ro_rt = (struct rtentry *)0; 263 } 264 if (ro->ro_rt == (struct rtentry *)0 || 265 ro->ro_rt->rt_ifp == (struct ifnet *)0) { 266 struct sockaddr_in6 *sa6; 267 268 /* No route yet, so try to acquire one */ 269 bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); 270 sa6 = (struct sockaddr_in6 *)&ro->ro_dst; 271 sa6->sin6_family = AF_INET6; 272 sa6->sin6_len = sizeof(struct sockaddr_in6); 273 sa6->sin6_addr = *dst; 274 sa6->sin6_scope_id = dstsock->sin6_scope_id; 275 if (IN6_IS_ADDR_MULTICAST(dst)) { 276 ro->ro_rt = rtalloc1(&((struct route *)ro) 277 ->ro_dst, 0, 0UL); 278 if (ro->ro_rt) 279 RT_UNLOCK(ro->ro_rt); 280 } else { 281 rtalloc((struct route *)ro); 282 } 283 } 284 285 /* 286 * in_pcbconnect() checks out IFF_LOOPBACK to skip using 287 * the address. But we don't know why it does so. 288 * It is necessary to ensure the scope even for lo0 289 * so doesn't check out IFF_LOOPBACK. 290 */ 291 292 if (ro->ro_rt) { 293 ia6 = in6_ifawithscope(ro->ro_rt->rt_ifa->ifa_ifp, dst); 294 if (ia6 == 0) /* xxx scope error ?*/ 295 ia6 = ifatoia6(ro->ro_rt->rt_ifa); 296 } 297 if (ia6 == 0) { 298 *errorp = EHOSTUNREACH; /* no route */ 299 return (0); 300 } 301 return (&satosin6(&ia6->ia_addr)->sin6_addr); 302 } 303 304 *errorp = EADDRNOTAVAIL; 305 return (0); 306} 307 308/* 309 * Default hop limit selection. The precedence is as follows: 310 * 1. Hoplimit value specified via ioctl. 311 * 2. (If the outgoing interface is detected) the current 312 * hop limit of the interface specified by router advertisement. 313 * 3. The system default hoplimit. 314*/ 315int 316in6_selecthlim(in6p, ifp) 317 struct in6pcb *in6p; 318 struct ifnet *ifp; 319{ 320 if (in6p && in6p->in6p_hops >= 0) 321 return (in6p->in6p_hops); 322 else if (ifp) 323 return (ND_IFINFO(ifp)->chlim); 324 else 325 return (ip6_defhlim); 326} 327 328/* 329 * XXX: this is borrowed from in6_pcbbind(). If possible, we should 330 * share this function by all *bsd*... 331 */ 332int 333in6_pcbsetport(laddr, inp, td) 334 struct in6_addr *laddr; 335 struct inpcb *inp; 336 struct thread *td; 337{ 338 struct socket *so = inp->inp_socket; 339 u_int16_t lport = 0, first, last, *lastport; 340 int count, error = 0, wild = 0; 341 struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 342 343 /* XXX: this is redundant when called from in6_pcbbind */ 344 if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 345 wild = INPLOOKUP_WILDCARD; 346 347 inp->inp_flags |= INP_ANONPORT; 348 349 if (inp->inp_flags & INP_HIGHPORT) { 350 first = ipport_hifirstauto; /* sysctl */ 351 last = ipport_hilastauto; 352 lastport = &pcbinfo->lasthi; 353 } else if (inp->inp_flags & INP_LOWPORT) { 354 if (td && (error = suser(td))) 355 return error; 356 first = ipport_lowfirstauto; /* 1023 */ 357 last = ipport_lowlastauto; /* 600 */ 358 lastport = &pcbinfo->lastlow; 359 } else { 360 first = ipport_firstauto; /* sysctl */ 361 last = ipport_lastauto; 362 lastport = &pcbinfo->lastport; 363 } 364 /* 365 * Simple check to ensure all ports are not used up causing 366 * a deadlock here. 367 * 368 * We split the two cases (up and down) so that the direction 369 * is not being tested on each round of the loop. 370 */ 371 if (first > last) { 372 /* 373 * counting down 374 */ 375 count = first - last; 376 377 do { 378 if (count-- < 0) { /* completely used? */ 379 /* 380 * Undo any address bind that may have 381 * occurred above. 382 */ 383 inp->in6p_laddr = in6addr_any; 384 return (EAGAIN); 385 } 386 --*lastport; 387 if (*lastport > first || *lastport < last) 388 *lastport = first; 389 lport = htons(*lastport); 390 } while (in6_pcblookup_local(pcbinfo, 391 &inp->in6p_laddr, lport, wild)); 392 } else { 393 /* 394 * counting up 395 */ 396 count = last - first; 397 398 do { 399 if (count-- < 0) { /* completely used? */ 400 /* 401 * Undo any address bind that may have 402 * occurred above. 403 */ 404 inp->in6p_laddr = in6addr_any; 405 return (EAGAIN); 406 } 407 ++*lastport; 408 if (*lastport < first || *lastport > last) 409 *lastport = first; 410 lport = htons(*lastport); 411 } while (in6_pcblookup_local(pcbinfo, 412 &inp->in6p_laddr, lport, wild)); 413 } 414 415 inp->inp_lport = lport; 416 if (in_pcbinshash(inp) != 0) { 417 inp->in6p_laddr = in6addr_any; 418 inp->inp_lport = 0; 419 return (EAGAIN); 420 } 421 422 return (0); 423} 424 425/* 426 * Generate kernel-internal form (scopeid embedded into s6_addr16[1]). 427 * If the address scope of is link-local, embed the interface index in the 428 * address. The routine determines our precedence 429 * between advanced API scope/interface specification and basic API 430 * specification. 431 * 432 * This function should be nuked in the future, when we get rid of embedded 433 * scopeid thing. 434 * 435 * XXX actually, it is over-specification to return ifp against sin6_scope_id. 436 * there can be multiple interfaces that belong to a particular scope zone 437 * (in specification, we have 1:N mapping between a scope zone and interfaces). 438 * we may want to change the function to return something other than ifp. 439 */ 440int 441in6_embedscope(in6, sin6, in6p, ifpp) 442 struct in6_addr *in6; 443 const struct sockaddr_in6 *sin6; 444 struct in6pcb *in6p; 445 struct ifnet **ifpp; 446{ 447 struct ifnet *ifp = NULL; 448 u_int32_t scopeid; 449 450 *in6 = sin6->sin6_addr; 451 scopeid = sin6->sin6_scope_id; 452 if (ifpp) 453 *ifpp = NULL; 454 455 /* 456 * don't try to read sin6->sin6_addr beyond here, since the caller may 457 * ask us to overwrite existing sockaddr_in6 458 */ 459 460#ifdef ENABLE_DEFAULT_SCOPE 461 if (scopeid == 0) 462 scopeid = scope6_addr2default(in6); 463#endif 464 465 if (IN6_IS_SCOPE_LINKLOCAL(in6)) { 466 struct in6_pktinfo *pi; 467 468 /* 469 * KAME assumption: link id == interface id 470 */ 471 472 if (in6p && in6p->in6p_outputopts && 473 (pi = in6p->in6p_outputopts->ip6po_pktinfo) && 474 pi->ipi6_ifindex) { 475 ifp = ifnet_byindex(pi->ipi6_ifindex); 476 in6->s6_addr16[1] = htons(pi->ipi6_ifindex); 477 } else if (in6p && IN6_IS_ADDR_MULTICAST(in6) && 478 in6p->in6p_moptions && 479 in6p->in6p_moptions->im6o_multicast_ifp) { 480 ifp = in6p->in6p_moptions->im6o_multicast_ifp; 481 in6->s6_addr16[1] = htons(ifp->if_index); 482 } else if (scopeid) { 483 /* boundary check */ 484 if (scopeid < 0 || if_index < scopeid) 485 return ENXIO; /* XXX EINVAL? */ 486 ifp = ifnet_byindex(scopeid); 487 /* XXX assignment to 16bit from 32bit variable */ 488 in6->s6_addr16[1] = htons(scopeid & 0xffff); 489 } 490 491 if (ifpp) 492 *ifpp = ifp; 493 } 494 495 return 0; 496} 497 498/* 499 * generate standard sockaddr_in6 from embedded form. 500 * touches sin6_addr and sin6_scope_id only. 501 * 502 * this function should be nuked in the future, when we get rid of 503 * embedded scopeid thing. 504 */ 505int 506in6_recoverscope(sin6, in6, ifp) 507 struct sockaddr_in6 *sin6; 508 const struct in6_addr *in6; 509 struct ifnet *ifp; 510{ 511 u_int32_t zoneid; 512 513 sin6->sin6_addr = *in6; 514 515 /* 516 * don't try to read *in6 beyond here, since the caller may 517 * ask us to overwrite existing sockaddr_in6 518 */ 519 520 sin6->sin6_scope_id = 0; 521 if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) { 522 /* 523 * KAME assumption: link id == interface id 524 */ 525 zoneid = ntohs(sin6->sin6_addr.s6_addr16[1]); 526 if (zoneid) { 527 /* sanity check */ 528 if (zoneid < 0 || if_index < zoneid) 529 return ENXIO; 530 if (ifp && ifp->if_index != zoneid) 531 return ENXIO; 532 sin6->sin6_addr.s6_addr16[1] = 0; 533 sin6->sin6_scope_id = zoneid; 534 } 535 } 536 537 return 0; 538} 539 540/* 541 * just clear the embedded scope identifier. 542 */ 543void 544in6_clearscope(addr) 545 struct in6_addr *addr; 546{ 547 if (IN6_IS_SCOPE_LINKLOCAL(addr) || IN6_IS_ADDR_MC_INTFACELOCAL(addr)) 548 addr->s6_addr16[1] = 0; 549} 550 551void 552addrsel_policy_init() 553{ 554 ADDRSEL_LOCK_INIT(); 555 556 init_policy_queue(); 557 558 /* initialize the "last resort" policy */ 559 bzero(&defaultaddrpolicy, sizeof(defaultaddrpolicy)); 560 defaultaddrpolicy.label = ADDR_LABEL_NOTAPP; 561} 562 563/* 564 * Subroutines to manage the address selection policy table via sysctl. 565 */ 566struct walkarg { 567 struct sysctl_req *w_req; 568}; 569 570static int in6_src_sysctl(SYSCTL_HANDLER_ARGS); 571SYSCTL_DECL(_net_inet6_ip6); 572SYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy, 573 CTLFLAG_RD, in6_src_sysctl, ""); 574 575static int 576in6_src_sysctl(SYSCTL_HANDLER_ARGS) 577{ 578 struct walkarg w; 579 580 if (req->newptr) 581 return EPERM; 582 583 bzero(&w, sizeof(w)); 584 w.w_req = req; 585 586 return (walk_addrsel_policy(dump_addrsel_policyent, &w)); 587} 588 589int 590in6_src_ioctl(cmd, data) 591 u_long cmd; 592 caddr_t data; 593{ 594 int i; 595 struct in6_addrpolicy ent0; 596 597 if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY) 598 return (EOPNOTSUPP); /* check for safety */ 599 600 ent0 = *(struct in6_addrpolicy *)data; 601 602 if (ent0.label == ADDR_LABEL_NOTAPP) 603 return (EINVAL); 604 /* check if the prefix mask is consecutive. */ 605 if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0) 606 return (EINVAL); 607 /* clear trailing garbages (if any) of the prefix address. */ 608 for (i = 0; i < 4; i++) { 609 ent0.addr.sin6_addr.s6_addr32[i] &= 610 ent0.addrmask.sin6_addr.s6_addr32[i]; 611 } 612 ent0.use = 0; 613 614 switch (cmd) { 615 case SIOCAADDRCTL_POLICY: 616 return (add_addrsel_policyent(&ent0)); 617 case SIOCDADDRCTL_POLICY: 618 return (delete_addrsel_policyent(&ent0)); 619 } 620 621 return (0); /* XXX: compromise compilers */ 622} 623 624/* 625 * The followings are implementation of the policy table using a 626 * simple tail queue. 627 * XXX such details should be hidden. 628 * XXX implementation using binary tree should be more efficient. 629 */ 630struct addrsel_policyent { 631 TAILQ_ENTRY(addrsel_policyent) ape_entry; 632 struct in6_addrpolicy ape_policy; 633}; 634 635TAILQ_HEAD(addrsel_policyhead, addrsel_policyent); 636 637struct addrsel_policyhead addrsel_policytab; 638 639static void 640init_policy_queue() 641{ 642 TAILQ_INIT(&addrsel_policytab); 643} 644 645static int 646add_addrsel_policyent(newpolicy) 647 struct in6_addrpolicy *newpolicy; 648{ 649 struct addrsel_policyent *new, *pol; 650 651 MALLOC(new, struct addrsel_policyent *, sizeof(*new), M_IFADDR, 652 M_WAITOK); 653 ADDRSEL_LOCK(); 654 655 /* duplication check */ 656 for (pol = TAILQ_FIRST(&addrsel_policytab); pol; 657 pol = TAILQ_NEXT(pol, ape_entry)) { 658 if (SA6_ARE_ADDR_EQUAL(&newpolicy->addr, 659 &pol->ape_policy.addr) && 660 SA6_ARE_ADDR_EQUAL(&newpolicy->addrmask, 661 &pol->ape_policy.addrmask)) { 662 ADDRSEL_UNLOCK(); 663 FREE(new, M_IFADDR); 664 return (EEXIST); /* or override it? */ 665 } 666 } 667 668 bzero(new, sizeof(*new)); 669 670 /* XXX: should validate entry */ 671 new->ape_policy = *newpolicy; 672 673 TAILQ_INSERT_TAIL(&addrsel_policytab, new, ape_entry); 674 ADDRSEL_UNLOCK(); 675 676 return (0); 677} 678 679static int 680delete_addrsel_policyent(key) 681 struct in6_addrpolicy *key; 682{ 683 struct addrsel_policyent *pol; 684 685 ADDRSEL_LOCK(); 686 687 /* search for the entry in the table */ 688 for (pol = TAILQ_FIRST(&addrsel_policytab); pol; 689 pol = TAILQ_NEXT(pol, ape_entry)) { 690 if (SA6_ARE_ADDR_EQUAL(&key->addr, &pol->ape_policy.addr) && 691 SA6_ARE_ADDR_EQUAL(&key->addrmask, 692 &pol->ape_policy.addrmask)) { 693 break; 694 } 695 } 696 if (pol == NULL) { 697 ADDRSEL_UNLOCK(); 698 return (ESRCH); 699 } 700 701 TAILQ_REMOVE(&addrsel_policytab, pol, ape_entry); 702 ADDRSEL_UNLOCK(); 703 704 return (0); 705} 706 707static int 708walk_addrsel_policy(callback, w) 709 int (*callback) __P((struct in6_addrpolicy *, void *)); 710 void *w; 711{ 712 struct addrsel_policyent *pol; 713 int error = 0; 714 715 ADDRSEL_LOCK(); 716 for (pol = TAILQ_FIRST(&addrsel_policytab); pol; 717 pol = TAILQ_NEXT(pol, ape_entry)) { 718 if ((error = (*callback)(&pol->ape_policy, w)) != 0) { 719 ADDRSEL_UNLOCK(); 720 return (error); 721 } 722 } 723 ADDRSEL_UNLOCK(); 724 725 return (error); 726} 727 728static int 729dump_addrsel_policyent(pol, arg) 730 struct in6_addrpolicy *pol; 731 void *arg; 732{ 733 int error = 0; 734 struct walkarg *w = arg; 735 736 error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol)); 737 738 return (error); 739} 740