Commit 6e157b6a authored by David S. Miller's avatar David S. Miller

ipv6: Pull main logic of rt6_redirect() into rt6_do_redirect().

Hook it into dst_ops->redirect as well.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e8599ff4
...@@ -79,6 +79,7 @@ static int ip6_pkt_discard(struct sk_buff *skb); ...@@ -79,6 +79,7 @@ static int ip6_pkt_discard(struct sk_buff *skb);
static int ip6_pkt_discard_out(struct sk_buff *skb); static int ip6_pkt_discard_out(struct sk_buff *skb);
static void ip6_link_failure(struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb);
static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu);
static void rt6_do_redirect(struct dst_entry *dst, struct sk_buff *skb);
#ifdef CONFIG_IPV6_ROUTE_INFO #ifdef CONFIG_IPV6_ROUTE_INFO
static struct rt6_info *rt6_add_route_info(struct net *net, static struct rt6_info *rt6_add_route_info(struct net *net,
...@@ -174,6 +175,7 @@ static struct dst_ops ip6_dst_ops_template = { ...@@ -174,6 +175,7 @@ static struct dst_ops ip6_dst_ops_template = {
.negative_advice = ip6_negative_advice, .negative_advice = ip6_negative_advice,
.link_failure = ip6_link_failure, .link_failure = ip6_link_failure,
.update_pmtu = ip6_rt_update_pmtu, .update_pmtu = ip6_rt_update_pmtu,
.redirect = rt6_do_redirect,
.local_out = __ip6_local_out, .local_out = __ip6_local_out,
.neigh_lookup = ip6_neigh_lookup, .neigh_lookup = ip6_neigh_lookup,
}; };
...@@ -1690,28 +1692,26 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest, ...@@ -1690,28 +1692,26 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
flags, __ip6_route_redirect); flags, __ip6_route_redirect);
} }
void rt6_redirect(struct sk_buff *skb) static void rt6_do_redirect(struct dst_entry *dst, struct sk_buff *skb)
{ {
struct net *net = dev_net(skb->dev); struct net *net = dev_net(skb->dev);
struct netevent_redirect netevent; struct netevent_redirect netevent;
struct rt6_info *rt, *nrt = NULL; struct rt6_info *rt, *nrt = NULL;
const struct in6_addr *target; const struct in6_addr *target;
struct neighbour *old_neigh;
const struct in6_addr *dest;
const struct in6_addr *src;
const struct in6_addr *saddr;
struct ndisc_options ndopts; struct ndisc_options ndopts;
const struct in6_addr *dest;
struct neighbour *old_neigh;
struct inet6_dev *in6_dev; struct inet6_dev *in6_dev;
struct neighbour *neigh; struct neighbour *neigh;
struct icmp6hdr *icmph; struct icmp6hdr *icmph;
int on_link, optlen; int optlen, on_link;
u8 *lladdr = NULL; u8 *lladdr;
optlen = skb->tail - skb->transport_header; optlen = skb->tail - skb->transport_header;
optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);
if (optlen < 0) { if (optlen < 0) {
net_dbg_ratelimited("rt6_redirect: packet too short\n"); net_dbg_ratelimited("rt6_do_redirect: packet too short\n");
return; return;
} }
...@@ -1720,15 +1720,16 @@ void rt6_redirect(struct sk_buff *skb) ...@@ -1720,15 +1720,16 @@ void rt6_redirect(struct sk_buff *skb)
dest = target + 1; dest = target + 1;
if (ipv6_addr_is_multicast(dest)) { if (ipv6_addr_is_multicast(dest)) {
net_dbg_ratelimited("rt6_redirect: destination address is multicast\n"); net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n");
return; return;
} }
on_link = 0;
if (ipv6_addr_equal(dest, target)) { if (ipv6_addr_equal(dest, target)) {
on_link = 1; on_link = 1;
} else if (ipv6_addr_type(target) != } else if (ipv6_addr_type(target) !=
(IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
net_dbg_ratelimited("rt6_redirect: target address is not link-local unicast\n"); net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n");
return; return;
} }
...@@ -1747,6 +1748,8 @@ void rt6_redirect(struct sk_buff *skb) ...@@ -1747,6 +1748,8 @@ void rt6_redirect(struct sk_buff *skb)
net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
return; return;
} }
lladdr = NULL;
if (ndopts.nd_opts_tgt_lladdr) { if (ndopts.nd_opts_tgt_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
skb->dev); skb->dev);
...@@ -1756,19 +1759,26 @@ void rt6_redirect(struct sk_buff *skb) ...@@ -1756,19 +1759,26 @@ void rt6_redirect(struct sk_buff *skb)
} }
} }
neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1); rt = (struct rt6_info *) dst;
if (!neigh) if (rt == net->ipv6.ip6_null_entry) {
net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n");
return; return;
}
src = &ipv6_hdr(skb)->daddr; /* Redirect received -> path was valid.
saddr = &ipv6_hdr(skb)->saddr; * Look, redirects are sent only in response to data packets,
* so that this nexthop apparently is reachable. --ANK
*/
dst_confirm(&rt->dst);
rt = ip6_route_redirect(dest, src, saddr, neigh->dev); neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
if (!neigh)
return;
if (rt == net->ipv6.ip6_null_entry) { /* Duplicate redirect: silently ignore. */
net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n"); old_neigh = rt->n;
if (neigh == old_neigh)
goto out; goto out;
}
/* /*
* We have finally decided to accept it. * We have finally decided to accept it.
...@@ -1781,18 +1791,6 @@ void rt6_redirect(struct sk_buff *skb) ...@@ -1781,18 +1791,6 @@ void rt6_redirect(struct sk_buff *skb)
NEIGH_UPDATE_F_ISROUTER)) NEIGH_UPDATE_F_ISROUTER))
); );
/*
* Redirect received -> path was valid.
* Look, redirects are sent only in response to data packets,
* so that this nexthop apparently is reachable. --ANK
*/
dst_confirm(&rt->dst);
/* Duplicate redirect: silently ignore. */
old_neigh = rt->n;
if (neigh == old_neigh)
goto out;
nrt = ip6_rt_copy(rt, dest); nrt = ip6_rt_copy(rt, dest);
if (!nrt) if (!nrt)
goto out; goto out;
...@@ -1815,12 +1813,32 @@ void rt6_redirect(struct sk_buff *skb) ...@@ -1815,12 +1813,32 @@ void rt6_redirect(struct sk_buff *skb)
call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
if (rt->rt6i_flags & RTF_CACHE) { if (rt->rt6i_flags & RTF_CACHE) {
rt = (struct rt6_info *) dst_clone(&rt->dst);
ip6_del_rt(rt); ip6_del_rt(rt);
return;
} }
out: out:
neigh_release(neigh); neigh_release(neigh);
}
void rt6_redirect(struct sk_buff *skb)
{
const struct in6_addr *target;
const struct in6_addr *dest;
const struct in6_addr *src;
const struct in6_addr *saddr;
struct icmp6hdr *icmph;
struct rt6_info *rt;
icmph = icmp6_hdr(skb);
target = (const struct in6_addr *) (icmph + 1);
dest = target + 1;
src = &ipv6_hdr(skb)->daddr;
saddr = &ipv6_hdr(skb)->saddr;
rt = ip6_route_redirect(dest, src, saddr, skb->dev);
rt6_do_redirect(&rt->dst, skb);
dst_release(&rt->dst); dst_release(&rt->dst);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment