Skip to content

Commit

Permalink
ipv6: Move bulk of redirect handling into rt6_redirect().
Browse files Browse the repository at this point in the history
This sets things up so that we can have the protocol error handlers
call down into the ipv6 route code for redirects just as ipv4 already
does.

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 12, 2012
1 parent 30f2a5f commit e8599ff
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 82 deletions.
7 changes: 1 addition & 6 deletions include/net/ip6_route.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,7 @@ extern int rt6_route_rcv(struct net_device *dev,
u8 *opt, int len,
const struct in6_addr *gwaddr);

extern void rt6_redirect(const struct in6_addr *dest,
const struct in6_addr *src,
const struct in6_addr *saddr,
struct neighbour *neigh,
u8 *lladdr,
int on_link);
extern void rt6_redirect(struct sk_buff *skb);

extern void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu,
int oif, u32 mark);
Expand Down
72 changes: 1 addition & 71 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,6 @@ struct neigh_table nd_tbl = {
.gc_thresh3 = 1024,
};

#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)

static inline int ndisc_opt_addr_space(struct net_device *dev)
{
return NDISC_OPT_SPACE(dev->addr_len + ndisc_addr_option_pad(dev->type));
Expand Down Expand Up @@ -1336,16 +1334,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)

static void ndisc_redirect_rcv(struct sk_buff *skb)
{
struct inet6_dev *in6_dev;
struct icmp6hdr *icmph;
const struct in6_addr *dest;
const struct in6_addr *target; /* new first hop to destination */
struct neighbour *neigh;
int on_link = 0;
struct ndisc_options ndopts;
int optlen;
u8 *lladdr = NULL;

#ifdef CONFIG_IPV6_NDISC_NODETYPE
switch (skb->ndisc_nodetype) {
case NDISC_NODETYPE_HOST:
Expand All @@ -1362,65 +1350,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
return;
}

optlen = skb->tail - skb->transport_header;
optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);

if (optlen < 0) {
ND_PRINTK(2, warn, "Redirect: packet too short\n");
return;
}

icmph = icmp6_hdr(skb);
target = (const struct in6_addr *) (icmph + 1);
dest = target + 1;

if (ipv6_addr_is_multicast(dest)) {
ND_PRINTK(2, warn,
"Redirect: destination address is multicast\n");
return;
}

if (ipv6_addr_equal(dest, target)) {
on_link = 1;
} else if (ipv6_addr_type(target) !=
(IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
ND_PRINTK(2, warn,
"Redirect: target address is not link-local unicast\n");
return;
}

in6_dev = __in6_dev_get(skb->dev);
if (!in6_dev)
return;
if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
return;

/* RFC2461 8.1:
* The IP source address of the Redirect MUST be the same as the current
* first-hop router for the specified ICMP Destination Address.
*/

if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
ND_PRINTK(2, warn, "Redirect: invalid ND options\n");
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
skb->dev);
if (!lladdr) {
ND_PRINTK(2, warn,
"Redirect: invalid link-layer address length\n");
return;
}
}

neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
if (neigh) {
rt6_redirect(dest, &ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr, neigh, lladdr,
on_link);
neigh_release(neigh);
}
rt6_redirect(skb);
}

void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
Expand Down
75 changes: 70 additions & 5 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -1690,14 +1690,78 @@ static struct rt6_info *ip6_route_redirect(const struct in6_addr *dest,
flags, __ip6_route_redirect);
}

void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
const struct in6_addr *saddr,
struct neighbour *neigh, u8 *lladdr, int on_link)
void rt6_redirect(struct sk_buff *skb)
{
struct rt6_info *rt, *nrt = NULL;
struct net *net = dev_net(skb->dev);
struct netevent_redirect netevent;
struct net *net = dev_net(neigh->dev);
struct rt6_info *rt, *nrt = NULL;
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 inet6_dev *in6_dev;
struct neighbour *neigh;
struct icmp6hdr *icmph;
int on_link, optlen;
u8 *lladdr = NULL;

optlen = skb->tail - skb->transport_header;
optlen -= sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr);

if (optlen < 0) {
net_dbg_ratelimited("rt6_redirect: packet too short\n");
return;
}

icmph = icmp6_hdr(skb);
target = (const struct in6_addr *) (icmph + 1);
dest = target + 1;

if (ipv6_addr_is_multicast(dest)) {
net_dbg_ratelimited("rt6_redirect: destination address is multicast\n");
return;
}

if (ipv6_addr_equal(dest, target)) {
on_link = 1;
} else if (ipv6_addr_type(target) !=
(IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) {
net_dbg_ratelimited("rt6_redirect: target address is not link-local unicast\n");
return;
}

in6_dev = __in6_dev_get(skb->dev);
if (!in6_dev)
return;
if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
return;

/* RFC2461 8.1:
* The IP source address of the Redirect MUST be the same as the current
* first-hop router for the specified ICMP Destination Address.
*/

if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
net_dbg_ratelimited("rt6_redirect: invalid ND options\n");
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr,
skb->dev);
if (!lladdr) {
net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n");
return;
}
}

neigh = __neigh_lookup(&nd_tbl, target, skb->dev, 1);
if (!neigh)
return;

src = &ipv6_hdr(skb)->daddr;
saddr = &ipv6_hdr(skb)->saddr;

rt = ip6_route_redirect(dest, src, saddr, neigh->dev);

Expand Down Expand Up @@ -1756,6 +1820,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src,
}

out:
neigh_release(neigh);
dst_release(&rt->dst);
}

Expand Down

0 comments on commit e8599ff

Please sign in to comment.