Commit de0b4832 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji

[IPV6] NDISC: update neighbor cache entry by RS.

Signed-off-by: default avatarHideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>
parent 8101cd57
...@@ -45,6 +45,11 @@ struct nd_msg { ...@@ -45,6 +45,11 @@ struct nd_msg {
__u8 opt[0]; __u8 opt[0];
}; };
struct rs_msg {
struct icmp6hdr icmph;
__u8 opt[0];
};
struct ra_msg { struct ra_msg {
struct icmp6hdr icmph; struct icmp6hdr icmph;
__u32 reachable_time; __u32 reachable_time;
......
...@@ -921,6 +921,64 @@ static void ndisc_recv_na(struct sk_buff *skb) ...@@ -921,6 +921,64 @@ static void ndisc_recv_na(struct sk_buff *skb)
} }
} }
static void ndisc_recv_rs(struct sk_buff *skb)
{
struct rs_msg *rs_msg = (struct rs_msg *) skb->h.raw;
unsigned long ndoptlen = skb->len - sizeof(*rs_msg);
struct neighbour *neigh;
struct inet6_dev *idev;
struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
struct ndisc_options ndopts;
u8 *lladdr = NULL;
int lladdrlen = 0;
if (skb->len < sizeof(*rs_msg))
return;
idev = in6_dev_get(skb->dev);
if (!idev) {
if (net_ratelimit())
ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
return;
}
/* Don't accept RS if we're not in router mode */
if (!idev->cnf.forwarding || idev->cnf.accept_ra)
goto out;
/*
* Don't update NCE if src = ::;
* this implies that the source node has no ip address assigned yet.
*/
if (ipv6_addr_any(saddr))
goto out;
/* Parse ND options */
if (!ndisc_parse_options(rs_msg->opt, ndoptlen, &ndopts)) {
if (net_ratelimit())
ND_PRINTK2("ICMP6 NS: invalid ND option, ignored\n");
goto out;
}
if (ndopts.nd_opts_src_lladdr) {
lladdr = (u8 *)(ndopts.nd_opts_src_lladdr + 1);
lladdrlen = ndopts.nd_opts_src_lladdr->nd_opt_len << 3;
if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len))
goto out;
}
neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1);
if (neigh) {
neigh_update(neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_WEAK_OVERRIDE|
NEIGH_UPDATE_F_OVERRIDE|
NEIGH_UPDATE_F_OVERRIDE_ISROUTER);
neigh_release(neigh);
}
out:
in6_dev_put(idev);
}
static void ndisc_router_discovery(struct sk_buff *skb) static void ndisc_router_discovery(struct sk_buff *skb)
{ {
struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw; struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
...@@ -1395,6 +1453,10 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1395,6 +1453,10 @@ int ndisc_rcv(struct sk_buff *skb)
ndisc_recv_na(skb); ndisc_recv_na(skb);
break; break;
case NDISC_ROUTER_SOLICITATION:
ndisc_recv_rs(skb);
break;
case NDISC_ROUTER_ADVERTISEMENT: case NDISC_ROUTER_ADVERTISEMENT:
ndisc_router_discovery(skb); ndisc_router_discovery(skb);
break; break;
......
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