📄 nd6_rtr.c
字号:
mtu, ip6_sprintf(&ip6->ip6_src)));
goto skip;
}
/* upper bound */
if (ndi->maxmtu) {
if (mtu <= ndi->maxmtu) {
int change = (ndi->linkmtu != mtu);
ndi->linkmtu = mtu;
if (change) /* in6_maxmtu may change */
in6_setmaxmtu();
} else {
nd6log((LOG_INFO, "nd6_ra_input: bogus mtu "
"mtu=%d sent from %s; "
"exceeds maxmtu %d, ignoring\n",
mtu, ip6_sprintf(&ip6->ip6_src),
ndi->maxmtu));
}
} else {
nd6log((LOG_INFO, "nd6_ra_input: mtu option "
"mtu=%d sent from %s; maxmtu unknown, "
"ignoring\n",
mtu, ip6_sprintf(&ip6->ip6_src)));
}
}
skip:
/*
* Source link layer address
*/
{
char *lladdr = NULL;
int lladdrlen = 0;
if (ndopts.nd_opts_src_lladdr) {
lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
}
if (lladdr && ((ifp->if_addrlen + 2 + 7) & ~7) != lladdrlen) {
nd6log((LOG_INFO,
"nd6_ra_input: lladdrlen mismatch for %s "
"(if %d, RA packet %d)\n",
ip6_sprintf(&saddr6), ifp->if_addrlen, lladdrlen - 2));
goto bad;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen, ND_ROUTER_ADVERT, 0);
/*
* Installing a link-layer address might change the state of the
* router's neighbor cache, which might also affect our on-link
* detection of adveritsed prefixes.
*/
pfxlist_onlink_check();
}
freeit:
m_freem(m);
return;
bad:
icmp6stat.icp6s_badra++;
m_freem(m);
}
/*
* default router list proccessing sub routines
*/
/* tell the change to user processes watching the routing socket. */
static void
nd6_rtmsg(cmd, rt)
int cmd;
struct rtentry *rt;
{
struct rt_addrinfo info;
bzero((caddr_t)&info, sizeof(info));
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802) /* BSDI4 */
/* maybe this is unnecessary */
info.rti_flags = rt->rt_flags;
#endif
info.rti_info[RTAX_DST] = rt_key(rt);
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway;
info.rti_info[RTAX_NETMASK] = rt_mask(rt);
#if defined(__bsdi__) || (defined(__FreeBSD__) && __FreeBSD__ < 3)
info.rti_info[RTAX_IFP] = rt->rt_ifp->if_addrlist->ifa_addr;
#else
info.rti_info[RTAX_IFP] =
(struct sockaddr *)TAILQ_FIRST(&rt->rt_ifp->if_addrlist);
#endif
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
rt_missmsg(cmd, &info, rt->rt_flags, 0);
}
void
defrouter_addreq(new)
struct nd_defrouter *new;
{
struct sockaddr_in6 def, mask, gate;
struct rtentry *newrt = NULL;
int s;
int error;
Bzero(&def, sizeof(def));
Bzero(&mask, sizeof(mask));
Bzero(&gate, sizeof(gate));
def.sin6_len = mask.sin6_len = gate.sin6_len
= sizeof(struct sockaddr_in6);
def.sin6_family = mask.sin6_family = gate.sin6_family = AF_INET6;
gate.sin6_addr = new->rtaddr;
#ifdef __NetBSD__
s = splsoftnet();
#else
s = splnet();
#endif
error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
RTF_GATEWAY, &newrt);
if (newrt) {
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
newrt->rt_refcnt--;
}
if (error == 0)
new->installed = 1;
splx(s);
return;
}
/* Add a route to a given interface as default */
static void
defrouter_addifreq(ifp)
struct ifnet *ifp;
{
struct sockaddr_in6 def, mask;
struct ifaddr *ifa;
struct rtentry *newrt = NULL;
int error, flags;
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
struct rt_addrinfo info;
#endif
/* remove one if we have already installed one */
if (nd6_defif_installed)
defrouter_delifreq();
bzero(&def, sizeof(def));
bzero(&mask, sizeof(mask));
def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
def.sin6_family = mask.sin6_family = AF_INET6;
/*
* Search for an ifaddr beloging to the specified interface.
* XXX: An IPv6 address are required to be assigned on the interface.
*/
if ((ifa = ifaof_ifpforaddr((struct sockaddr *)&def, ifp)) == NULL) {
nd6log((LOG_ERR, /* better error? */
"defrouter_addifreq: failed to find an ifaddr "
"to install a route to interface %s\n",
if_name(ifp)));
return;
}
flags = ifa->ifa_flags;
#if (defined(__bsdi__) && _BSDI_VERSION >= 199802)
bzero(&info, sizeof(info));
info.rti_info[RTAX_DST] = (struct sockaddr *)&def;
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)ifa->ifa_addr;
info.rti_info[RTAX_NETMASK] = (struct sockaddr *)&mask;
info.rti_info[RTAX_IFA] = (struct sockaddr *)ifa->ifa_addr;
info.rti_flags = flags;
error = rtrequest1(RTM_ADD, &info, &newrt);
#else
error = rtrequest(RTM_ADD, (struct sockaddr *)&def, ifa->ifa_addr,
(struct sockaddr *)&mask, flags, &newrt);
#endif
if (error != 0) {
nd6log((LOG_ERR,
"defrouter_addifreq: failed to install a route to "
"interface %s (errno = %d)\n",
if_name(ifp), error));
if (newrt) /* maybe unnecessary, but do it for safety */
newrt->rt_refcnt--;
} else {
if (newrt) {
nd6_rtmsg(RTM_ADD, newrt);
newrt->rt_refcnt--;
}
}
nd6_defif_installed = ifa;
IFAREF(ifa);
}
/* Remove a default route points to interface */
static void
defrouter_delifreq()
{
struct sockaddr_in6 def, mask;
struct rtentry *oldrt = NULL;
if (!nd6_defif_installed)
return;
Bzero(&def, sizeof(def));
Bzero(&mask, sizeof(mask));
def.sin6_len = mask.sin6_len = sizeof(struct sockaddr_in6);
def.sin6_family = mask.sin6_family = AF_INET6;
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
(struct sockaddr *)nd6_defif_installed->ifa_addr,
(struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
if (oldrt) {
nd6_rtmsg(RTM_DELETE, oldrt);
if (oldrt->rt_refcnt <= 0) {
/*
* XXX: borrowed from the RTM_DELETE case of
* rtrequest().
*/
oldrt->rt_refcnt++;
rtfree(oldrt);
}
}
IFAFREE(nd6_defif_installed);
nd6_defif_installed = NULL;
}
struct nd_defrouter *
defrouter_lookup(addr, ifp)
struct in6_addr *addr;
struct ifnet *ifp;
{
struct nd_defrouter *dr;
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
dr = TAILQ_NEXT(dr, dr_entry)) {
if (dr->ifp == ifp && IN6_ARE_ADDR_EQUAL(addr, &dr->rtaddr))
return(dr);
}
return(NULL); /* search failed */
}
void
defrtrlist_del(dr)
struct nd_defrouter *dr;
{
struct nd_defrouter *deldr = NULL;
struct nd_prefix *pr;
/*
* Flush all the routing table entries that use the router
* as a next hop.
*/
if (!ip6_forwarding && ip6_accept_rtadv) {
/* above is a good condition? */
rt6_flush(&dr->rtaddr, dr->ifp);
}
if (dr->installed) {
deldr = dr;
defrouter_delreq(dr);
}
TAILQ_REMOVE(&nd_defrouter, dr, dr_entry);
/*
* Also delete all the pointers to the router in each prefix lists.
*/
for (pr = nd_prefix.lh_first; pr; pr = pr->ndpr_next) {
struct nd_pfxrouter *pfxrtr;
if ((pfxrtr = pfxrtr_lookup(pr, dr)) != NULL)
pfxrtr_del(pfxrtr);
}
pfxlist_onlink_check();
/*
* If the router is the primary one, choose a new one.
* Note that defrouter_select() will remove the current gateway
* from the routing table.
*/
if (deldr)
defrouter_select();
free(dr, M_IP6NDP);
}
/*
* Remove the default route for a given router.
* This is just a subroutine function for defrouter_select(), and should
* not be called from anywhere else.
*/
static void
defrouter_delreq(dr)
struct nd_defrouter *dr;
{
struct sockaddr_in6 def, mask, gw;
struct rtentry *oldrt = NULL;
Bzero(&def, sizeof(def));
Bzero(&mask, sizeof(mask));
Bzero(&gw, sizeof(gw));
def.sin6_len = mask.sin6_len = gw.sin6_len =
sizeof(struct sockaddr_in6);
def.sin6_family = mask.sin6_family = gw.sin6_family = AF_INET6;
if (dr)
gw.sin6_addr = dr->rtaddr;
rtrequest(RTM_DELETE, (struct sockaddr *)&def,
dr ? (struct sockaddr *)&gw : NULL,
(struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
if (oldrt) {
nd6_rtmsg(RTM_DELETE, oldrt);
if (oldrt->rt_refcnt <= 0) {
/*
* XXX: borrowed from the RTM_DELETE case of
* rtrequest().
*/
oldrt->rt_refcnt++;
rtfree(oldrt);
}
}
if (dr)
dr->installed = 0;
}
/*
* remove all default routes from default router list
*/
void
defrouter_reset()
{
struct nd_defrouter *dr;
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
dr = TAILQ_NEXT(dr, dr_entry))
defrouter_delreq(dr);
defrouter_delifreq();
/*
* XXX should we also nuke any default routers in the kernel, by
* going through them by rtalloc1()?
*/
}
/*
* Default Router Selection according to Section 6.3.6 of RFC 2461 and
* draft-ietf-ipngwg-router-selection:
* 1) Routers that are reachable or probably reachable should be preferred.
* If we have more than one (probably) reachable router, prefer ones
* with the highest router preference.
* 2) When no routers on the list are known to be reachable or
* probably reachable, routers SHOULD be selected in a round-robin
* fashion, regardless of router preference values.
* 3) If the Default Router List is empty, assume that all
* destinations are on-link.
*
* We assume nd_defrouter is sorted by router preference value.
* Since the code below covers both with and without router preference cases,
* we do not need to classify the cases by ifdef.
*
* At this moment, we do not try to install more than one default router,
* even when the multipath routing is available, because we're not sure about
* the benefits for stub hosts comparing to the risk of making the code
* complicated and the possibility of introducing bugs.
*/
void
defrouter_select()
{
#ifdef __NetBSD__
int s = splsoftnet();
#else
int s = splnet();
#endif
struct nd_defrouter *dr, *selected_dr = NULL, *installed_dr = NULL;
struct rtentry *rt = NULL;
struct llinfo_nd6 *ln = NULL;
/*
* This function should be called only when acting as an autoconfigured
* host. Although the remaining part of this function is not effective
* if the node is not an autoconfigured host, we explicitly exclude
* such cases here for safety.
*/
if (ip6_forwarding || !ip6_accept_rtadv) {
nd6log((LOG_WARNING,
"defrouter_select: called unexpectedly (forwarding=%d, "
"accept_rtadv=%d)\n", ip6_forwarding, ip6_accept_rtadv));
splx(s);
return;
}
/*
* Let's handle easy case (3) first:
* If default router list is empty, we should probably install
* an interface route and assume that all destinations are on-link.
*/
if (!TAILQ_FIRST(&nd_defrouter)) {
/*
* XXX: The specification does not say this mechanism should
* be restricted to hosts, but this would be not useful
* (even harmful) for routers.
* This test is meaningless due to a test at the beginning of
* the function, but we intentionally keep it to make the note
* clear.
*/
if (!ip6_forwarding) {
if (nd6_defifp) {
/*
* Install a route to the default interface
* as default route.
*/
defrouter_addifreq(nd6_defifp);
} else {
/*
* purge the existing route.
* XXX: is this really correct?
*/
defrouter_delifreq();
nd6log((LOG_INFO, "defrouter_select: "
"there's no default router and no default"
" interface\n"));
}
}
splx(s);
return;
}
/*
* If we have a default route for the default interface, delete it.
* Note that the existence of the route is checked in the delete
* function.
*/
defrouter_delifreq();
/*
* Search for a (probably) reachable router from the list.
* We just pick up the first reachable one (if any), assuming that
* the ordering rule of the list described in defrtrlist_update().
*/
for (dr = TAILQ_FIRST(&nd_defrouter); dr;
dr = TAILQ_NEXT(dr, dr_entry)) {
if (!selected_dr &&
(rt = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -