in6_src.c revision 185088
1251881Speter/*- 2251881Speter * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 1. Redistributions of source code must retain the above copyright 9251881Speter * notice, this list of conditions and the following disclaimer. 10251881Speter * 2. Redistributions in binary form must reproduce the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer in the 12251881Speter * documentation and/or other materials provided with the distribution. 13251881Speter * 3. Neither the name of the project nor the names of its contributors 14251881Speter * may be used to endorse or promote products derived from this software 15251881Speter * without specific prior written permission. 16251881Speter * 17251881Speter * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27251881Speter * SUCH DAMAGE. 28251881Speter * 29251881Speter * $KAME: in6_src.c,v 1.132 2003/08/26 04:42:27 keiichi Exp $ 30251881Speter */ 31251881Speter 32251881Speter/*- 33251881Speter * Copyright (c) 1982, 1986, 1991, 1993 34251881Speter * The Regents of the University of California. All rights reserved. 35251881Speter * 36251881Speter * Redistribution and use in source and binary forms, with or without 37251881Speter * modification, are permitted provided that the following conditions 38251881Speter * are met: 39251881Speter * 1. Redistributions of source code must retain the above copyright 40251881Speter * notice, this list of conditions and the following disclaimer. 41269847Speter * 2. Redistributions in binary form must reproduce the above copyright 42251881Speter * notice, this list of conditions and the following disclaimer in the 43251881Speter * documentation and/or other materials provided with the distribution. 44251881Speter * 4. Neither the name of the University nor the names of its contributors 45251881Speter * may be used to endorse or promote products derived from this software 46251881Speter * without specific prior written permission. 47251881Speter * 48251881Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58251881Speter * SUCH DAMAGE. 59251881Speter * 60251881Speter * @(#)in_pcb.c 8.2 (Berkeley) 1/4/94 61251881Speter */ 62251881Speter 63251881Speter#include <sys/cdefs.h> 64251881Speter__FBSDID("$FreeBSD: head/sys/netinet6/in6_src.c 185088 2008-11-19 09:39:34Z zec $"); 65251881Speter 66251881Speter#include "opt_inet.h" 67251881Speter#include "opt_inet6.h" 68251881Speter#include "opt_mpath.h" 69251881Speter 70251881Speter#include <sys/param.h> 71251881Speter#include <sys/systm.h> 72251881Speter#include <sys/lock.h> 73251881Speter#include <sys/malloc.h> 74251881Speter#include <sys/mbuf.h> 75251881Speter#include <sys/priv.h> 76251881Speter#include <sys/protosw.h> 77251881Speter#include <sys/socket.h> 78251881Speter#include <sys/socketvar.h> 79251881Speter#include <sys/sockio.h> 80251881Speter#include <sys/sysctl.h> 81251881Speter#include <sys/errno.h> 82251881Speter#include <sys/time.h> 83251881Speter#include <sys/kernel.h> 84251881Speter#include <sys/sx.h> 85251881Speter#include <sys/vimage.h> 86251881Speter 87251881Speter#include <net/if.h> 88251881Speter#include <net/route.h> 89251881Speter#ifdef RADIX_MPATH 90251881Speter#include <net/radix_mpath.h> 91251881Speter#endif 92251881Speter 93251881Speter#include <netinet/in.h> 94251881Speter#include <netinet/in_var.h> 95251881Speter#include <netinet/in_systm.h> 96251881Speter#include <netinet/ip.h> 97251881Speter#include <netinet/in_pcb.h> 98251881Speter#include <netinet/ip_var.h> 99251881Speter#include <netinet/udp.h> 100251881Speter#include <netinet/udp_var.h> 101251881Speter#include <netinet6/in6_var.h> 102251881Speter#include <netinet/ip6.h> 103251881Speter#include <netinet6/in6_pcb.h> 104251881Speter#include <netinet6/ip6_var.h> 105251881Speter#include <netinet6/scope6_var.h> 106251881Speter#include <netinet6/nd6.h> 107251881Speter 108251881Speterstatic struct mtx addrsel_lock; 109251881Speter#define ADDRSEL_LOCK_INIT() mtx_init(&addrsel_lock, "addrsel_lock", NULL, MTX_DEF) 110251881Speter#define ADDRSEL_LOCK() mtx_lock(&addrsel_lock) 111251881Speter#define ADDRSEL_UNLOCK() mtx_unlock(&addrsel_lock) 112251881Speter#define ADDRSEL_LOCK_ASSERT() mtx_assert(&addrsel_lock, MA_OWNED) 113251881Speter 114251881Speterstatic struct sx addrsel_sxlock; 115251881Speter#define ADDRSEL_SXLOCK_INIT() sx_init(&addrsel_sxlock, "addrsel_sxlock") 116251881Speter#define ADDRSEL_SLOCK() sx_slock(&addrsel_sxlock) 117251881Speter#define ADDRSEL_SUNLOCK() sx_sunlock(&addrsel_sxlock) 118251881Speter#define ADDRSEL_XLOCK() sx_xlock(&addrsel_sxlock) 119251881Speter#define ADDRSEL_XUNLOCK() sx_xunlock(&addrsel_sxlock) 120251881Speter 121251881Speter#define ADDR_LABEL_NOTAPP (-1) 122251881Speter 123251881Speter#ifdef VIMAGE_GLOBALS 124251881Speterstruct in6_addrpolicy defaultaddrpolicy; 125251881Speterint ip6_prefer_tempaddr; 126251881Speter#endif 127251881Speter 128251881Speterstatic int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *, 129251881Speter struct ip6_moptions *, struct route_in6 *, struct ifnet **, 130251881Speter struct rtentry **, int, int)); 131251881Speterstatic int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *, 132251881Speter struct ip6_moptions *, struct route_in6 *ro, struct ifnet **)); 133251881Speter 134251881Speterstatic struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *); 135251881Speter 136251881Speterstatic void init_policy_queue(void); 137251881Speterstatic int add_addrsel_policyent(struct in6_addrpolicy *); 138251881Speterstatic int delete_addrsel_policyent(struct in6_addrpolicy *); 139251881Speterstatic int walk_addrsel_policy __P((int (*)(struct in6_addrpolicy *, void *), 140251881Speter void *)); 141251881Speterstatic int dump_addrsel_policyent(struct in6_addrpolicy *, void *); 142251881Speterstatic struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *); 143251881Speter 144251881Speter/* 145251881Speter * Return an IPv6 address, which is the most appropriate for a given 146251881Speter * destination and user specified options. 147251881Speter * If necessary, this function lookups the routing table and returns 148251881Speter * an entry to the caller for later use. 149251881Speter */ 150251881Speter#define REPLACE(r) do {\ 151251881Speter if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \ 152251881Speter sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ 153251881Speter V_ip6stat.ip6s_sources_rule[(r)]++; \ 154251881Speter /* { \ 155251881Speter char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \ 156251881Speter printf("in6_selectsrc: replace %s with %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \ 157251881Speter } */ \ 158251881Speter goto replace; \ 159251881Speter} while(0) 160251881Speter#define NEXT(r) do {\ 161251881Speter if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \ 162251881Speter sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ 163251881Speter V_ip6stat.ip6s_sources_rule[(r)]++; \ 164251881Speter /* { \ 165251881Speter char ip6buf[INET6_ADDRSTRLEN], ip6b[INET6_ADDRSTRLEN]; \ 166251881Speter printf("in6_selectsrc: keep %s against %s by %d\n", ia_best ? ip6_sprintf(ip6buf, &ia_best->ia_addr.sin6_addr) : "none", ip6_sprintf(ip6b, &ia->ia_addr.sin6_addr), (r)); \ 167251881Speter } */ \ 168251881Speter goto next; /* XXX: we can't use 'continue' here */ \ 169251881Speter} while(0) 170251881Speter#define BREAK(r) do { \ 171251881Speter if ((r) < sizeof(V_ip6stat.ip6s_sources_rule) / \ 172251881Speter sizeof(V_ip6stat.ip6s_sources_rule[0])) /* check for safety */ \ 173251881Speter V_ip6stat.ip6s_sources_rule[(r)]++; \ 174251881Speter goto out; /* XXX: we can't use 'break' here */ \ 175251881Speter} while(0) 176251881Speter 177251881Speterstruct in6_addr * 178251881Speterin6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 179251881Speter struct inpcb *inp, struct route_in6 *ro, struct ucred *cred, 180251881Speter struct ifnet **ifpp, int *errorp) 181251881Speter{ 182251881Speter INIT_VNET_INET6(curvnet); 183251881Speter struct in6_addr dst; 184251881Speter struct ifnet *ifp = NULL; 185251881Speter struct in6_ifaddr *ia = NULL, *ia_best = NULL; 186251881Speter struct in6_pktinfo *pi = NULL; 187251881Speter int dst_scope = -1, best_scope = -1, best_matchlen = -1; 188251881Speter struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL; 189251881Speter u_int32_t odstzone; 190251881Speter int prefer_tempaddr; 191251881Speter struct ip6_moptions *mopts; 192251881Speter 193251881Speter dst = dstsock->sin6_addr; /* make a copy for local operation */ 194251881Speter *errorp = 0; 195251881Speter if (ifpp) 196251881Speter *ifpp = NULL; 197251881Speter 198251881Speter if (inp != NULL) { 199251881Speter INP_LOCK_ASSERT(inp); 200251881Speter mopts = inp->in6p_moptions; 201251881Speter } else { 202251881Speter mopts = NULL; 203251881Speter } 204251881Speter 205251881Speter /* 206251881Speter * If the source address is explicitly specified by the caller, 207251881Speter * check if the requested source address is indeed a unicast address 208251881Speter * assigned to the node, and can be used as the packet's source 209251881Speter * address. If everything is okay, use the address as source. 210251881Speter */ 211251881Speter if (opts && (pi = opts->ip6po_pktinfo) && 212251881Speter !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) { 213251881Speter struct sockaddr_in6 srcsock; 214251881Speter struct in6_ifaddr *ia6; 215251881Speter 216251881Speter /* get the outgoing interface */ 217251881Speter if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) 218251881Speter != 0) { 219251881Speter return (NULL); 220251881Speter } 221251881Speter 222251881Speter /* 223251881Speter * determine the appropriate zone id of the source based on 224251881Speter * the zone of the destination and the outgoing interface. 225251881Speter * If the specified address is ambiguous wrt the scope zone, 226251881Speter * the interface must be specified; otherwise, ifa_ifwithaddr() 227251881Speter * will fail matching the address. 228251881Speter */ 229251881Speter bzero(&srcsock, sizeof(srcsock)); 230251881Speter srcsock.sin6_family = AF_INET6; 231251881Speter srcsock.sin6_len = sizeof(srcsock); 232251881Speter srcsock.sin6_addr = pi->ipi6_addr; 233251881Speter if (ifp) { 234251881Speter *errorp = in6_setscope(&srcsock.sin6_addr, ifp, NULL); 235251881Speter if (*errorp != 0) 236251881Speter return (NULL); 237251881Speter } 238251881Speter 239251881Speter ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock)); 240251881Speter if (ia6 == NULL || 241251881Speter (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) { 242251881Speter *errorp = EADDRNOTAVAIL; 243251881Speter return (NULL); 244251881Speter } 245251881Speter pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */ 246251881Speter if (ifpp) 247251881Speter *ifpp = ifp; 248251881Speter return (&ia6->ia_addr.sin6_addr); 249251881Speter } 250251881Speter 251251881Speter /* 252251881Speter * Otherwise, if the socket has already bound the source, just use it. 253251881Speter */ 254251881Speter if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) { 255251881Speter return (&inp->in6p_laddr); 256251881Speter } 257251881Speter 258251881Speter /* 259251881Speter * If the address is not specified, choose the best one based on 260251881Speter * the outgoing interface and the destination address. 261251881Speter */ 262251881Speter /* get the outgoing interface */ 263251881Speter if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0) 264251881Speter return (NULL); 265251881Speter 266251881Speter#ifdef DIAGNOSTIC 267251881Speter if (ifp == NULL) /* this should not happen */ 268251881Speter panic("in6_selectsrc: NULL ifp"); 269251881Speter#endif 270251881Speter *errorp = in6_setscope(&dst, ifp, &odstzone); 271251881Speter if (*errorp != 0) 272251881Speter return (NULL); 273251881Speter 274251881Speter for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) { 275251881Speter int new_scope = -1, new_matchlen = -1; 276251881Speter struct in6_addrpolicy *new_policy = NULL; 277251881Speter u_int32_t srczone, osrczone, dstzone; 278251881Speter struct in6_addr src; 279251881Speter struct ifnet *ifp1 = ia->ia_ifp; 280251881Speter 281251881Speter /* 282251881Speter * We'll never take an address that breaks the scope zone 283251881Speter * of the destination. We also skip an address if its zone 284251881Speter * does not contain the outgoing interface. 285251881Speter * XXX: we should probably use sin6_scope_id here. 286251881Speter */ 287251881Speter if (in6_setscope(&dst, ifp1, &dstzone) || 288251881Speter odstzone != dstzone) { 289251881Speter continue; 290251881Speter } 291251881Speter src = ia->ia_addr.sin6_addr; 292251881Speter if (in6_setscope(&src, ifp, &osrczone) || 293251881Speter in6_setscope(&src, ifp1, &srczone) || 294251881Speter osrczone != srczone) { 295251881Speter continue; 296251881Speter } 297251881Speter 298251881Speter /* avoid unusable addresses */ 299251881Speter if ((ia->ia6_flags & 300251881Speter (IN6_IFF_NOTREADY | IN6_IFF_ANYCAST | IN6_IFF_DETACHED))) { 301251881Speter continue; 302251881Speter } 303251881Speter if (!V_ip6_use_deprecated && IFA6_IS_DEPRECATED(ia)) 304251881Speter continue; 305251881Speter 306251881Speter /* Rule 1: Prefer same address */ 307251881Speter if (IN6_ARE_ADDR_EQUAL(&dst, &ia->ia_addr.sin6_addr)) { 308251881Speter ia_best = ia; 309251881Speter BREAK(1); /* there should be no better candidate */ 310251881Speter } 311251881Speter 312251881Speter if (ia_best == NULL) 313251881Speter REPLACE(0); 314251881Speter 315251881Speter /* Rule 2: Prefer appropriate scope */ 316251881Speter if (dst_scope < 0) 317251881Speter dst_scope = in6_addrscope(&dst); 318251881Speter new_scope = in6_addrscope(&ia->ia_addr.sin6_addr); 319251881Speter if (IN6_ARE_SCOPE_CMP(best_scope, new_scope) < 0) { 320251881Speter if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0) 321251881Speter REPLACE(2); 322251881Speter NEXT(2); 323251881Speter } else if (IN6_ARE_SCOPE_CMP(new_scope, best_scope) < 0) { 324251881Speter if (IN6_ARE_SCOPE_CMP(new_scope, dst_scope) < 0) 325251881Speter NEXT(2); 326251881Speter REPLACE(2); 327251881Speter } 328251881Speter 329251881Speter /* 330251881Speter * Rule 3: Avoid deprecated addresses. Note that the case of 331251881Speter * !ip6_use_deprecated is already rejected above. 332251881Speter */ 333251881Speter if (!IFA6_IS_DEPRECATED(ia_best) && IFA6_IS_DEPRECATED(ia)) 334251881Speter NEXT(3); 335251881Speter if (IFA6_IS_DEPRECATED(ia_best) && !IFA6_IS_DEPRECATED(ia)) 336251881Speter REPLACE(3); 337251881Speter 338251881Speter /* Rule 4: Prefer home addresses */ 339251881Speter /* 340251881Speter * XXX: This is a TODO. We should probably merge the MIP6 341251881Speter * case above. 342251881Speter */ 343251881Speter 344251881Speter /* Rule 5: Prefer outgoing interface */ 345251881Speter if (ia_best->ia_ifp == ifp && ia->ia_ifp != ifp) 346251881Speter NEXT(5); 347251881Speter if (ia_best->ia_ifp != ifp && ia->ia_ifp == ifp) 348251881Speter REPLACE(5); 349251881Speter 350251881Speter /* 351251881Speter * Rule 6: Prefer matching label 352251881Speter * Note that best_policy should be non-NULL here. 353251881Speter */ 354251881Speter if (dst_policy == NULL) 355251881Speter dst_policy = lookup_addrsel_policy(dstsock); 356251881Speter if (dst_policy->label != ADDR_LABEL_NOTAPP) { 357251881Speter new_policy = lookup_addrsel_policy(&ia->ia_addr); 358251881Speter if (dst_policy->label == best_policy->label && 359251881Speter dst_policy->label != new_policy->label) 360251881Speter NEXT(6); 361251881Speter if (dst_policy->label != best_policy->label && 362251881Speter dst_policy->label == new_policy->label) 363251881Speter REPLACE(6); 364251881Speter } 365251881Speter 366251881Speter /* 367251881Speter * Rule 7: Prefer public addresses. 368251881Speter * We allow users to reverse the logic by configuring 369251881Speter * a sysctl variable, so that privacy conscious users can 370251881Speter * always prefer temporary addresses. 371251881Speter */ 372251881Speter if (opts == NULL || 373251881Speter opts->ip6po_prefer_tempaddr == IP6PO_TEMPADDR_SYSTEM) { 374251881Speter prefer_tempaddr = V_ip6_prefer_tempaddr; 375251881Speter } else if (opts->ip6po_prefer_tempaddr == 376251881Speter IP6PO_TEMPADDR_NOTPREFER) { 377251881Speter prefer_tempaddr = 0; 378251881Speter } else 379251881Speter prefer_tempaddr = 1; 380251881Speter if (!(ia_best->ia6_flags & IN6_IFF_TEMPORARY) && 381251881Speter (ia->ia6_flags & IN6_IFF_TEMPORARY)) { 382251881Speter if (prefer_tempaddr) 383251881Speter REPLACE(7); 384251881Speter else 385251881Speter NEXT(7); 386251881Speter } 387251881Speter if ((ia_best->ia6_flags & IN6_IFF_TEMPORARY) && 388251881Speter !(ia->ia6_flags & IN6_IFF_TEMPORARY)) { 389251881Speter if (prefer_tempaddr) 390251881Speter NEXT(7); 391251881Speter else 392251881Speter REPLACE(7); 393251881Speter } 394251881Speter 395251881Speter /* 396251881Speter * Rule 8: prefer addresses on alive interfaces. 397251881Speter * This is a KAME specific rule. 398251881Speter */ 399251881Speter if ((ia_best->ia_ifp->if_flags & IFF_UP) && 400251881Speter !(ia->ia_ifp->if_flags & IFF_UP)) 401251881Speter NEXT(8); 402251881Speter if (!(ia_best->ia_ifp->if_flags & IFF_UP) && 403251881Speter (ia->ia_ifp->if_flags & IFF_UP)) 404251881Speter REPLACE(8); 405251881Speter 406251881Speter /* 407251881Speter * Rule 14: Use longest matching prefix. 408251881Speter * Note: in the address selection draft, this rule is 409251881Speter * documented as "Rule 8". However, since it is also 410251881Speter * documented that this rule can be overridden, we assign 411251881Speter * a large number so that it is easy to assign smaller numbers 412251881Speter * to more preferred rules. 413251881Speter */ 414251881Speter new_matchlen = in6_matchlen(&ia->ia_addr.sin6_addr, &dst); 415251881Speter if (best_matchlen < new_matchlen) 416251881Speter REPLACE(14); 417251881Speter if (new_matchlen < best_matchlen) 418251881Speter NEXT(14); 419251881Speter 420251881Speter /* Rule 15 is reserved. */ 421251881Speter 422251881Speter /* 423251881Speter * Last resort: just keep the current candidate. 424251881Speter * Or, do we need more rules? 425251881Speter */ 426251881Speter continue; 427251881Speter 428251881Speter replace: 429251881Speter ia_best = ia; 430251881Speter best_scope = (new_scope >= 0 ? new_scope : 431251881Speter in6_addrscope(&ia_best->ia_addr.sin6_addr)); 432251881Speter best_policy = (new_policy ? new_policy : 433251881Speter lookup_addrsel_policy(&ia_best->ia_addr)); 434251881Speter best_matchlen = (new_matchlen >= 0 ? new_matchlen : 435251881Speter in6_matchlen(&ia_best->ia_addr.sin6_addr, 436251881Speter &dst)); 437251881Speter 438251881Speter next: 439251881Speter continue; 440251881Speter 441251881Speter out: 442251881Speter break; 443251881Speter } 444251881Speter 445251881Speter if ((ia = ia_best) == NULL) { 446251881Speter *errorp = EADDRNOTAVAIL; 447251881Speter return (NULL); 448251881Speter } 449251881Speter 450251881Speter if (ifpp) 451251881Speter *ifpp = ifp; 452251881Speter 453251881Speter return (&ia->ia_addr.sin6_addr); 454251881Speter} 455251881Speter 456251881Speter/* 457251881Speter * clone - meaningful only for bsdi and freebsd 458251881Speter */ 459251881Speterstatic int 460251881Speterselectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 461251881Speter struct ip6_moptions *mopts, struct route_in6 *ro, 462251881Speter struct ifnet **retifp, struct rtentry **retrt, int clone, 463251881Speter int norouteok) 464251881Speter{ 465251881Speter INIT_VNET_NET(curvnet); 466251881Speter INIT_VNET_INET6(curvnet); 467251881Speter int error = 0; 468251881Speter struct ifnet *ifp = NULL; 469251881Speter struct rtentry *rt = NULL; 470251881Speter struct sockaddr_in6 *sin6_next; 471251881Speter struct in6_pktinfo *pi = NULL; 472251881Speter struct in6_addr *dst = &dstsock->sin6_addr; 473251881Speter#if 0 474251881Speter char ip6buf[INET6_ADDRSTRLEN]; 475251881Speter 476251881Speter if (dstsock->sin6_addr.s6_addr32[0] == 0 && 477251881Speter dstsock->sin6_addr.s6_addr32[1] == 0 && 478251881Speter !IN6_IS_ADDR_LOOPBACK(&dstsock->sin6_addr)) { 479251881Speter printf("in6_selectroute: strange destination %s\n", 480251881Speter ip6_sprintf(ip6buf, &dstsock->sin6_addr)); 481251881Speter } else { 482251881Speter printf("in6_selectroute: destination = %s%%%d\n", 483251881Speter ip6_sprintf(ip6buf, &dstsock->sin6_addr), 484251881Speter dstsock->sin6_scope_id); /* for debug */ 485251881Speter } 486251881Speter#endif 487251881Speter 488251881Speter /* If the caller specify the outgoing interface explicitly, use it. */ 489251881Speter if (opts && (pi = opts->ip6po_pktinfo) != NULL && pi->ipi6_ifindex) { 490251881Speter /* XXX boundary check is assumed to be already done. */ 491251881Speter ifp = ifnet_byindex(pi->ipi6_ifindex); 492251881Speter if (ifp != NULL && 493251881Speter (norouteok || retrt == NULL || 494251881Speter IN6_IS_ADDR_MULTICAST(dst))) { 495251881Speter /* 496251881Speter * we do not have to check or get the route for 497251881Speter * multicast. 498251881Speter */ 499251881Speter goto done; 500251881Speter } else 501251881Speter goto getroute; 502251881Speter } 503251881Speter 504251881Speter /* 505251881Speter * If the destination address is a multicast address and the outgoing 506251881Speter * interface for the address is specified by the caller, use it. 507251881Speter */ 508251881Speter if (IN6_IS_ADDR_MULTICAST(dst) && 509251881Speter mopts != NULL && (ifp = mopts->im6o_multicast_ifp) != NULL) { 510251881Speter goto done; /* we do not need a route for multicast. */ 511251881Speter } 512251881Speter 513251881Speter getroute: 514251881Speter /* 515251881Speter * If the next hop address for the packet is specified by the caller, 516251881Speter * use it as the gateway. 517251881Speter */ 518251881Speter if (opts && opts->ip6po_nexthop) { 519251881Speter struct route_in6 *ron; 520251881Speter 521251881Speter sin6_next = satosin6(opts->ip6po_nexthop); 522251881Speter 523251881Speter /* at this moment, we only support AF_INET6 next hops */ 524251881Speter if (sin6_next->sin6_family != AF_INET6) { 525251881Speter error = EAFNOSUPPORT; /* or should we proceed? */ 526251881Speter goto done; 527251881Speter } 528251881Speter 529251881Speter /* 530251881Speter * If the next hop is an IPv6 address, then the node identified 531251881Speter * by that address must be a neighbor of the sending host. 532251881Speter */ 533251881Speter ron = &opts->ip6po_nextroute; 534251881Speter if ((ron->ro_rt && 535251881Speter (ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) != 536251881Speter (RTF_UP | RTF_LLINFO)) || 537251881Speter !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr, 538251881Speter &sin6_next->sin6_addr)) { 539251881Speter if (ron->ro_rt) { 540251881Speter RTFREE(ron->ro_rt); 541251881Speter ron->ro_rt = NULL; 542251881Speter } 543251881Speter *satosin6(&ron->ro_dst) = *sin6_next; 544251881Speter } 545251881Speter if (ron->ro_rt == NULL) { 546251881Speter rtalloc((struct route *)ron); /* multi path case? */ 547251881Speter if (ron->ro_rt == NULL || 548251881Speter !(ron->ro_rt->rt_flags & RTF_LLINFO)) { 549251881Speter if (ron->ro_rt) { 550251881Speter RTFREE(ron->ro_rt); 551251881Speter ron->ro_rt = NULL; 552251881Speter } 553251881Speter error = EHOSTUNREACH; 554251881Speter goto done; 555251881Speter } 556251881Speter } 557251881Speter rt = ron->ro_rt; 558251881Speter ifp = rt->rt_ifp; 559251881Speter 560251881Speter /* 561251881Speter * When cloning is required, try to allocate a route to the 562251881Speter * destination so that the caller can store path MTU 563251881Speter * information. 564251881Speter */ 565251881Speter if (!clone) 566251881Speter goto done; 567251881Speter } 568251881Speter 569251881Speter /* 570251881Speter * Use a cached route if it exists and is valid, else try to allocate 571251881Speter * a new one. Note that we should check the address family of the 572251881Speter * cached destination, in case of sharing the cache with IPv4. 573251881Speter */ 574251881Speter if (ro) { 575251881Speter if (ro->ro_rt && 576251881Speter (!(ro->ro_rt->rt_flags & RTF_UP) || 577251881Speter ((struct sockaddr *)(&ro->ro_dst))->sa_family != AF_INET6 || 578251881Speter !IN6_ARE_ADDR_EQUAL(&satosin6(&ro->ro_dst)->sin6_addr, 579251881Speter dst))) { 580251881Speter RTFREE(ro->ro_rt); 581251881Speter ro->ro_rt = (struct rtentry *)NULL; 582251881Speter } 583251881Speter if (ro->ro_rt == (struct rtentry *)NULL) { 584251881Speter struct sockaddr_in6 *sa6; 585251881Speter 586251881Speter /* No route yet, so try to acquire one */ 587251881Speter bzero(&ro->ro_dst, sizeof(struct sockaddr_in6)); 588251881Speter sa6 = (struct sockaddr_in6 *)&ro->ro_dst; 589251881Speter *sa6 = *dstsock; 590251881Speter sa6->sin6_scope_id = 0; 591251881Speter 592251881Speter if (clone) { 593251881Speter#ifdef RADIX_MPATH 594251881Speter rtalloc_mpath((struct route *)ro, 595251881Speter ntohl(sa6->sin6_addr.s6_addr32[3])); 596251881Speter#else 597251881Speter rtalloc((struct route *)ro); 598251881Speter#endif 599251881Speter } else { 600251881Speter ro->ro_rt = rtalloc1(&((struct route *)ro) 601251881Speter ->ro_dst, 0, 0UL); 602251881Speter if (ro->ro_rt) 603251881Speter RT_UNLOCK(ro->ro_rt); 604251881Speter } 605251881Speter } 606251881Speter 607251881Speter /* 608251881Speter * do not care about the result if we have the nexthop 609251881Speter * explicitly specified. 610251881Speter */ 611251881Speter if (opts && opts->ip6po_nexthop) 612251881Speter goto done; 613251881Speter 614251881Speter if (ro->ro_rt) { 615251881Speter ifp = ro->ro_rt->rt_ifp; 616251881Speter 617251881Speter if (ifp == NULL) { /* can this really happen? */ 618251881Speter RTFREE(ro->ro_rt); 619251881Speter ro->ro_rt = NULL; 620251881Speter } 621251881Speter } 622251881Speter if (ro->ro_rt == NULL) 623251881Speter error = EHOSTUNREACH; 624251881Speter rt = ro->ro_rt; 625251881Speter 626251881Speter /* 627251881Speter * Check if the outgoing interface conflicts with 628251881Speter * the interface specified by ipi6_ifindex (if specified). 629251881Speter * Note that loopback interface is always okay. 630251881Speter * (this may happen when we are sending a packet to one of 631251881Speter * our own addresses.) 632251881Speter */ 633251881Speter if (ifp && opts && opts->ip6po_pktinfo && 634251881Speter opts->ip6po_pktinfo->ipi6_ifindex) { 635251881Speter if (!(ifp->if_flags & IFF_LOOPBACK) && 636251881Speter ifp->if_index != 637251881Speter opts->ip6po_pktinfo->ipi6_ifindex) { 638251881Speter error = EHOSTUNREACH; 639251881Speter goto done; 640251881Speter } 641251881Speter } 642251881Speter } 643251881Speter 644251881Speter done: 645251881Speter if (ifp == NULL && rt == NULL) { 646251881Speter /* 647251881Speter * This can happen if the caller did not pass a cached route 648251881Speter * nor any other hints. We treat this case an error. 649251881Speter */ 650251881Speter error = EHOSTUNREACH; 651251881Speter } 652251881Speter if (error == EHOSTUNREACH) 653251881Speter V_ip6stat.ip6s_noroute++; 654251881Speter 655251881Speter if (retifp != NULL) 656251881Speter *retifp = ifp; 657251881Speter if (retrt != NULL) 658251881Speter *retrt = rt; /* rt may be NULL */ 659251881Speter 660251881Speter return (error); 661251881Speter} 662251881Speter 663251881Speterstatic int 664251881Speterin6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 665251881Speter struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp) 666251881Speter{ 667251881Speter int error; 668251881Speter struct route_in6 sro; 669251881Speter struct rtentry *rt = NULL; 670251881Speter 671251881Speter if (ro == NULL) { 672251881Speter bzero(&sro, sizeof(sro)); 673251881Speter ro = &sro; 674251881Speter } 675251881Speter 676251881Speter if ((error = selectroute(dstsock, opts, mopts, ro, retifp, 677251881Speter &rt, 0, 1)) != 0) { 678251881Speter if (ro == &sro && rt && rt == sro.ro_rt) 679251881Speter RTFREE(rt); 680251881Speter return (error); 681251881Speter } 682251881Speter 683251881Speter /* 684251881Speter * do not use a rejected or black hole route. 685251881Speter * XXX: this check should be done in the L2 output routine. 686251881Speter * However, if we skipped this check here, we'd see the following 687251881Speter * scenario: 688251881Speter * - install a rejected route for a scoped address prefix 689251881Speter * (like fe80::/10) 690251881Speter * - send a packet to a destination that matches the scoped prefix, 691251881Speter * with ambiguity about the scope zone. 692251881Speter * - pick the outgoing interface from the route, and disambiguate the 693251881Speter * scope zone with the interface. 694251881Speter * - ip6_output() would try to get another route with the "new" 695251881Speter * destination, which may be valid. 696251881Speter * - we'd see no error on output. 697251881Speter * Although this may not be very harmful, it should still be confusing. 698251881Speter * We thus reject the case here. 699251881Speter */ 700251881Speter if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE))) { 701251881Speter int flags = (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); 702251881Speter 703251881Speter if (ro == &sro && rt && rt == sro.ro_rt) 704251881Speter RTFREE(rt); 705251881Speter return (flags); 706251881Speter } 707251881Speter 708251881Speter /* 709251881Speter * Adjust the "outgoing" interface. If we're going to loop the packet 710251881Speter * back to ourselves, the ifp would be the loopback interface. 711251881Speter * However, we'd rather know the interface associated to the 712251881Speter * destination address (which should probably be one of our own 713251881Speter * addresses.) 714251881Speter */ 715251881Speter if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp) 716251881Speter *retifp = rt->rt_ifa->ifa_ifp; 717251881Speter 718251881Speter if (ro == &sro && rt && rt == sro.ro_rt) 719251881Speter RTFREE(rt); 720251881Speter return (0); 721251881Speter} 722251881Speter 723251881Speter/* 724251881Speter * clone - meaningful only for bsdi and freebsd 725251881Speter */ 726251881Speterint 727251881Speterin6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 728251881Speter struct ip6_moptions *mopts, struct route_in6 *ro, 729251881Speter struct ifnet **retifp, struct rtentry **retrt, int clone) 730251881Speter{ 731251881Speter 732251881Speter return (selectroute(dstsock, opts, mopts, ro, retifp, 733251881Speter retrt, clone, 0)); 734251881Speter} 735251881Speter 736251881Speter/* 737251881Speter * Default hop limit selection. The precedence is as follows: 738251881Speter * 1. Hoplimit value specified via ioctl. 739251881Speter * 2. (If the outgoing interface is detected) the current 740251881Speter * hop limit of the interface specified by router advertisement. 741251881Speter * 3. The system default hoplimit. 742251881Speter */ 743251881Speterint 744251881Speterin6_selecthlim(struct in6pcb *in6p, struct ifnet *ifp) 745251881Speter{ 746251881Speter INIT_VNET_INET6(curvnet); 747251881Speter 748251881Speter if (in6p && in6p->in6p_hops >= 0) 749251881Speter return (in6p->in6p_hops); 750251881Speter else if (ifp) 751251881Speter return (ND_IFINFO(ifp)->chlim); 752251881Speter else if (in6p && !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { 753251881Speter struct route_in6 ro6; 754251881Speter struct ifnet *lifp; 755251881Speter 756251881Speter bzero(&ro6, sizeof(ro6)); 757251881Speter ro6.ro_dst.sin6_family = AF_INET6; 758251881Speter ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); 759251881Speter ro6.ro_dst.sin6_addr = in6p->in6p_faddr; 760251881Speter rtalloc((struct route *)&ro6); 761251881Speter if (ro6.ro_rt) { 762251881Speter lifp = ro6.ro_rt->rt_ifp; 763251881Speter RTFREE(ro6.ro_rt); 764251881Speter if (lifp) 765251881Speter return (ND_IFINFO(lifp)->chlim); 766251881Speter } else 767251881Speter return (V_ip6_defhlim); 768251881Speter } 769251881Speter return (V_ip6_defhlim); 770251881Speter} 771251881Speter 772251881Speter/* 773251881Speter * XXX: this is borrowed from in6_pcbbind(). If possible, we should 774251881Speter * share this function by all *bsd*... 775251881Speter */ 776251881Speterint 777251881Speterin6_pcbsetport(struct in6_addr *laddr, struct inpcb *inp, struct ucred *cred) 778251881Speter{ 779251881Speter INIT_VNET_INET(curvnet); 780251881Speter struct socket *so = inp->inp_socket; 781251881Speter u_int16_t lport = 0, first, last, *lastport; 782251881Speter int count, error = 0, wild = 0, dorandom; 783251881Speter struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; 784251881Speter 785251881Speter INP_INFO_WLOCK_ASSERT(pcbinfo); 786251881Speter INP_WLOCK_ASSERT(inp); 787251881Speter 788251881Speter /* XXX: this is redundant when called from in6_pcbbind */ 789251881Speter if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) 790251881Speter wild = INPLOOKUP_WILDCARD; 791251881Speter 792251881Speter inp->inp_flags |= INP_ANONPORT; 793251881Speter 794251881Speter if (inp->inp_flags & INP_HIGHPORT) { 795251881Speter first = V_ipport_hifirstauto; /* sysctl */ 796251881Speter last = V_ipport_hilastauto; 797251881Speter lastport = &pcbinfo->ipi_lasthi; 798251881Speter } else if (inp->inp_flags & INP_LOWPORT) { 799251881Speter error = priv_check_cred(cred, PRIV_NETINET_RESERVEDPORT, 0); 800251881Speter if (error) 801251881Speter return error; 802251881Speter first = V_ipport_lowfirstauto; /* 1023 */ 803251881Speter last = V_ipport_lowlastauto; /* 600 */ 804251881Speter lastport = &pcbinfo->ipi_lastlow; 805251881Speter } else { 806251881Speter first = V_ipport_firstauto; /* sysctl */ 807251881Speter last = V_ipport_lastauto; 808251881Speter lastport = &pcbinfo->ipi_lastport; 809251881Speter } 810251881Speter 811251881Speter /* 812251881Speter * For UDP, use random port allocation as long as the user 813251881Speter * allows it. For TCP (and as of yet unknown) connections, 814251881Speter * use random port allocation only if the user allows it AND 815251881Speter * ipport_tick() allows it. 816251881Speter */ 817251881Speter if (V_ipport_randomized && 818251881Speter (!V_ipport_stoprandom || pcbinfo == &V_udbinfo)) 819251881Speter dorandom = 1; 820251881Speter else 821251881Speter dorandom = 0; 822251881Speter /* 823251881Speter * It makes no sense to do random port allocation if 824251881Speter * we have the only port available. 825251881Speter */ 826251881Speter if (first == last) 827251881Speter dorandom = 0; 828251881Speter /* Make sure to not include UDP packets in the count. */ 829251881Speter if (pcbinfo != &V_udbinfo) 830251881Speter V_ipport_tcpallocs++; 831251881Speter 832251881Speter /* 833251881Speter * Instead of having two loops further down counting up or down 834251881Speter * make sure that first is always <= last and go with only one 835251881Speter * code path implementing all logic. 836251881Speter */ 837251881Speter if (first > last) { 838251881Speter u_int16_t aux; 839251881Speter 840251881Speter aux = first; 841251881Speter first = last; 842251881Speter last = aux; 843251881Speter } 844251881Speter 845251881Speter if (dorandom) 846251881Speter *lastport = first + (arc4random() % (last - first)); 847251881Speter 848251881Speter count = last - first; 849251881Speter 850251881Speter do { 851251881Speter if (count-- < 0) { /* completely used? */ 852251881Speter /* Undo an address bind that may have occurred. */ 853251881Speter inp->in6p_laddr = in6addr_any; 854251881Speter return (EADDRNOTAVAIL); 855251881Speter } 856251881Speter ++*lastport; 857251881Speter if (*lastport < first || *lastport > last) 858251881Speter *lastport = first; 859251881Speter lport = htons(*lastport); 860251881Speter } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr, 861251881Speter lport, wild, cred)); 862251881Speter 863251881Speter inp->inp_lport = lport; 864251881Speter if (in_pcbinshash(inp) != 0) { 865251881Speter inp->in6p_laddr = in6addr_any; 866251881Speter inp->inp_lport = 0; 867251881Speter return (EAGAIN); 868251881Speter } 869251881Speter 870251881Speter return (0); 871251881Speter} 872251881Speter 873251881Spetervoid 874251881Speteraddrsel_policy_init(void) 875251881Speter{ 876251881Speter ADDRSEL_LOCK_INIT(); 877251881Speter ADDRSEL_SXLOCK_INIT(); 878251881Speter INIT_VNET_INET6(curvnet); 879251881Speter 880251881Speter V_ip6_prefer_tempaddr = 0; 881251881Speter 882251881Speter init_policy_queue(); 883251881Speter 884251881Speter /* initialize the "last resort" policy */ 885251881Speter bzero(&V_defaultaddrpolicy, sizeof(V_defaultaddrpolicy)); 886251881Speter V_defaultaddrpolicy.label = ADDR_LABEL_NOTAPP; 887251881Speter} 888251881Speter 889251881Speterstatic struct in6_addrpolicy * 890251881Speterlookup_addrsel_policy(struct sockaddr_in6 *key) 891251881Speter{ 892251881Speter INIT_VNET_INET6(curvnet); 893251881Speter struct in6_addrpolicy *match = NULL; 894251881Speter 895251881Speter ADDRSEL_LOCK(); 896251881Speter match = match_addrsel_policy(key); 897251881Speter 898251881Speter if (match == NULL) 899251881Speter match = &V_defaultaddrpolicy; 900251881Speter else 901251881Speter match->use++; 902251881Speter ADDRSEL_UNLOCK(); 903251881Speter 904251881Speter return (match); 905251881Speter} 906251881Speter 907251881Speter/* 908251881Speter * Subroutines to manage the address selection policy table via sysctl. 909251881Speter */ 910251881Speterstruct walkarg { 911251881Speter struct sysctl_req *w_req; 912251881Speter}; 913251881Speter 914251881Speterstatic int in6_src_sysctl(SYSCTL_HANDLER_ARGS); 915251881SpeterSYSCTL_DECL(_net_inet6_ip6); 916251881SpeterSYSCTL_NODE(_net_inet6_ip6, IPV6CTL_ADDRCTLPOLICY, addrctlpolicy, 917251881Speter CTLFLAG_RD, in6_src_sysctl, ""); 918251881Speter 919251881Speterstatic int 920251881Speterin6_src_sysctl(SYSCTL_HANDLER_ARGS) 921251881Speter{ 922251881Speter struct walkarg w; 923251881Speter 924251881Speter if (req->newptr) 925251881Speter return EPERM; 926251881Speter 927251881Speter bzero(&w, sizeof(w)); 928251881Speter w.w_req = req; 929251881Speter 930251881Speter return (walk_addrsel_policy(dump_addrsel_policyent, &w)); 931251881Speter} 932251881Speter 933251881Speterint 934251881Speterin6_src_ioctl(u_long cmd, caddr_t data) 935251881Speter{ 936251881Speter int i; 937251881Speter struct in6_addrpolicy ent0; 938251881Speter 939251881Speter if (cmd != SIOCAADDRCTL_POLICY && cmd != SIOCDADDRCTL_POLICY) 940251881Speter return (EOPNOTSUPP); /* check for safety */ 941251881Speter 942251881Speter ent0 = *(struct in6_addrpolicy *)data; 943251881Speter 944251881Speter if (ent0.label == ADDR_LABEL_NOTAPP) 945251881Speter return (EINVAL); 946251881Speter /* check if the prefix mask is consecutive. */ 947251881Speter if (in6_mask2len(&ent0.addrmask.sin6_addr, NULL) < 0) 948251881Speter return (EINVAL); 949251881Speter /* clear trailing garbages (if any) of the prefix address. */ 950251881Speter for (i = 0; i < 4; i++) { 951251881Speter ent0.addr.sin6_addr.s6_addr32[i] &= 952251881Speter ent0.addrmask.sin6_addr.s6_addr32[i]; 953251881Speter } 954251881Speter ent0.use = 0; 955251881Speter 956251881Speter switch (cmd) { 957251881Speter case SIOCAADDRCTL_POLICY: 958251881Speter return (add_addrsel_policyent(&ent0)); 959251881Speter case SIOCDADDRCTL_POLICY: 960251881Speter return (delete_addrsel_policyent(&ent0)); 961251881Speter } 962251881Speter 963251881Speter return (0); /* XXX: compromise compilers */ 964251881Speter} 965251881Speter 966251881Speter/* 967251881Speter * The followings are implementation of the policy table using a 968251881Speter * simple tail queue. 969251881Speter * XXX such details should be hidden. 970251881Speter * XXX implementation using binary tree should be more efficient. 971251881Speter */ 972251881Speterstruct addrsel_policyent { 973251881Speter TAILQ_ENTRY(addrsel_policyent) ape_entry; 974251881Speter struct in6_addrpolicy ape_policy; 975251881Speter}; 976251881Speter 977251881SpeterTAILQ_HEAD(addrsel_policyhead, addrsel_policyent); 978251881Speter 979251881Speter#ifdef VIMAGE_GLOBALS 980251881Speterstruct addrsel_policyhead addrsel_policytab; 981251881Speter#endif 982251881Speter 983251881Speterstatic void 984251881Speterinit_policy_queue(void) 985251881Speter{ 986251881Speter INIT_VNET_INET6(curvnet); 987251881Speter 988251881Speter TAILQ_INIT(&V_addrsel_policytab); 989251881Speter} 990251881Speter 991251881Speterstatic int 992251881Speteradd_addrsel_policyent(struct in6_addrpolicy *newpolicy) 993251881Speter{ 994251881Speter INIT_VNET_INET6(curvnet); 995251881Speter struct addrsel_policyent *new, *pol; 996251881Speter 997251881Speter new = malloc(sizeof(*new), M_IFADDR, 998251881Speter M_WAITOK); 999251881Speter ADDRSEL_XLOCK(); 1000251881Speter ADDRSEL_LOCK(); 1001251881Speter 1002251881Speter /* duplication check */ 1003251881Speter TAILQ_FOREACH(pol, &V_addrsel_policytab, ape_entry) { 1004251881Speter if (IN6_ARE_ADDR_EQUAL(&newpolicy->addr.sin6_addr, 1005251881Speter &pol->ape_policy.addr.sin6_addr) && 1006251881Speter IN6_ARE_ADDR_EQUAL(&newpolicy->addrmask.sin6_addr, 1007251881Speter &pol->ape_policy.addrmask.sin6_addr)) { 1008251881Speter ADDRSEL_UNLOCK(); 1009251881Speter ADDRSEL_XUNLOCK(); 1010251881Speter free(new, M_IFADDR); 1011251881Speter return (EEXIST); /* or override it? */ 1012251881Speter } 1013251881Speter } 1014251881Speter 1015251881Speter bzero(new, sizeof(*new)); 1016251881Speter 1017251881Speter /* XXX: should validate entry */ 1018251881Speter new->ape_policy = *newpolicy; 1019251881Speter 1020251881Speter TAILQ_INSERT_TAIL(&V_addrsel_policytab, new, ape_entry); 1021251881Speter ADDRSEL_UNLOCK(); 1022251881Speter ADDRSEL_XUNLOCK(); 1023251881Speter 1024251881Speter return (0); 1025251881Speter} 1026251881Speter 1027251881Speterstatic int 1028251881Speterdelete_addrsel_policyent(struct in6_addrpolicy *key) 1029251881Speter{ 1030251881Speter INIT_VNET_INET6(curvnet); 1031251881Speter struct addrsel_policyent *pol; 1032251881Speter 1033251881Speter ADDRSEL_XLOCK(); 1034251881Speter ADDRSEL_LOCK(); 1035251881Speter 1036251881Speter /* search for the entry in the table */ 1037251881Speter TAILQ_FOREACH(pol, &V_addrsel_policytab, ape_entry) { 1038251881Speter if (IN6_ARE_ADDR_EQUAL(&key->addr.sin6_addr, 1039251881Speter &pol->ape_policy.addr.sin6_addr) && 1040251881Speter IN6_ARE_ADDR_EQUAL(&key->addrmask.sin6_addr, 1041251881Speter &pol->ape_policy.addrmask.sin6_addr)) { 1042251881Speter break; 1043251881Speter } 1044251881Speter } 1045251881Speter if (pol == NULL) { 1046251881Speter ADDRSEL_UNLOCK(); 1047251881Speter ADDRSEL_XUNLOCK(); 1048251881Speter return (ESRCH); 1049251881Speter } 1050251881Speter 1051251881Speter TAILQ_REMOVE(&V_addrsel_policytab, pol, ape_entry); 1052251881Speter ADDRSEL_UNLOCK(); 1053251881Speter ADDRSEL_XUNLOCK(); 1054251881Speter 1055251881Speter return (0); 1056251881Speter} 1057251881Speter 1058251881Speterstatic int 1059251881Speterwalk_addrsel_policy(int (*callback)(struct in6_addrpolicy *, void *), 1060251881Speter void *w) 1061251881Speter{ 1062251881Speter INIT_VNET_INET6(curvnet); 1063251881Speter struct addrsel_policyent *pol; 1064251881Speter int error = 0; 1065251881Speter 1066251881Speter ADDRSEL_SLOCK(); 1067251881Speter TAILQ_FOREACH(pol, &V_addrsel_policytab, ape_entry) { 1068251881Speter if ((error = (*callback)(&pol->ape_policy, w)) != 0) { 1069251881Speter ADDRSEL_SUNLOCK(); 1070251881Speter return (error); 1071251881Speter } 1072251881Speter } 1073251881Speter ADDRSEL_SUNLOCK(); 1074251881Speter return (error); 1075251881Speter} 1076251881Speter 1077251881Speterstatic int 1078251881Speterdump_addrsel_policyent(struct in6_addrpolicy *pol, void *arg) 1079251881Speter{ 1080251881Speter int error = 0; 1081251881Speter struct walkarg *w = arg; 1082251881Speter 1083251881Speter error = SYSCTL_OUT(w->w_req, pol, sizeof(*pol)); 1084251881Speter 1085251881Speter return (error); 1086251881Speter} 1087251881Speter 1088251881Speterstatic struct in6_addrpolicy * 1089251881Spetermatch_addrsel_policy(struct sockaddr_in6 *key) 1090251881Speter{ 1091251881Speter INIT_VNET_INET6(curvnet); 1092251881Speter struct addrsel_policyent *pent; 1093251881Speter struct in6_addrpolicy *bestpol = NULL, *pol; 1094251881Speter int matchlen, bestmatchlen = -1; 1095251881Speter u_char *mp, *ep, *k, *p, m; 1096251881Speter 1097251881Speter TAILQ_FOREACH(pent, &V_addrsel_policytab, ape_entry) { 1098251881Speter matchlen = 0; 1099251881Speter 1100251881Speter pol = &pent->ape_policy; 1101251881Speter mp = (u_char *)&pol->addrmask.sin6_addr; 1102251881Speter ep = mp + 16; /* XXX: scope field? */ 1103251881Speter k = (u_char *)&key->sin6_addr; 1104251881Speter p = (u_char *)&pol->addr.sin6_addr; 1105251881Speter for (; mp < ep && *mp; mp++, k++, p++) { 1106251881Speter m = *mp; 1107251881Speter if ((*k & m) != *p) 1108251881Speter goto next; /* not match */ 1109251881Speter if (m == 0xff) /* short cut for a typical case */ 1110251881Speter matchlen += 8; 1111251881Speter else { 1112251881Speter while (m >= 0x80) { 1113251881Speter matchlen++; 1114251881Speter m <<= 1; 1115251881Speter } 1116251881Speter } 1117251881Speter } 1118251881Speter 1119251881Speter /* matched. check if this is better than the current best. */ 1120251881Speter if (bestpol == NULL || 1121251881Speter matchlen > bestmatchlen) { 1122251881Speter bestpol = pol; 1123251881Speter bestmatchlen = matchlen; 1124251881Speter } 1125251881Speter 1126251881Speter next: 1127251881Speter continue; 1128251881Speter } 1129251881Speter 1130251881Speter return (bestpol); 1131251881Speter} 1132251881Speter