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