Commit 13ef52ad authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji

[IPV6]: Unify 3 similar code paths in ndisc_recv_ns().

parent b1e63f72
...@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
struct ndisc_options ndopts; struct ndisc_options ndopts;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
struct inet6_dev *idev = NULL;
struct neighbour *neigh; struct neighbour *neigh;
int addr_type = ipv6_addr_type(saddr); int addr_type = ipv6_addr_type(saddr);
int inc;
if (ipv6_addr_is_multicast(&msg->target)) { if (ipv6_addr_is_multicast(&msg->target)) {
if (net_ratelimit()) if (net_ratelimit())
...@@ -757,6 +759,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -757,6 +759,8 @@ static void ndisc_recv_ns(struct sk_buff *skb)
} }
} }
inc = ipv6_addr_is_multicast(daddr);
if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
if (ifp->flags & IFA_F_TENTATIVE) { if (ifp->flags & IFA_F_TENTATIVE) {
/* Address is tentative. If the source /* Address is tentative. If the source
...@@ -785,47 +789,35 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -785,47 +789,35 @@ static void ndisc_recv_ns(struct sk_buff *skb)
return; return;
} }
if (addr_type == IPV6_ADDR_ANY) { idev = ifp->idev;
struct in6_addr maddr; } else {
idev = in6_dev_get(dev);
ipv6_addr_all_nodes(&maddr); if (!idev) {
ndisc_send_na(dev, NULL, &maddr, &ifp->addr, /* XXX: count this drop? */
ifp->idev->cnf.forwarding, 0,
1, 1);
in6_ifa_put(ifp);
return; return;
} }
if (addr_type & IPV6_ADDR_UNICAST) { if (ipv6_chk_acast_addr(dev, &msg->target) ||
if (ipv6_addr_is_multicast(daddr)) (idev->cnf.forwarding &&
nd_tbl.stats.rcv_probes_mcast++; pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
else if (skb->stamp.tv_sec != 0 &&
nd_tbl.stats.rcv_probes_ucast++; skb->pkt_type != PACKET_HOST &&
inc != 0 &&
idev->nd_parms->proxy_delay != 0) {
/* /*
* update / create cache entry * for anycast or proxy,
* for the source address * sender should delay its response
* by a random time between 0 and
* MAX_ANYCAST_DELAY_TIME seconds.
* (RFC2461) -- yoshfuji
*/ */
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev); if (n)
pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
if (neigh || !dev->hard_header) { goto out;
ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1,
1, 1);
if (neigh)
neigh_release(neigh);
}
} }
in6_ifa_put(ifp); } else
} else if (ipv6_chk_acast_addr(dev, &msg->target)) { goto out;
struct inet6_dev *idev = in6_dev_get(dev);
/* anycast */
if (!idev) {
/* XXX: count this drop? */
return;
} }
if (addr_type == IPV6_ADDR_ANY) { if (addr_type == IPV6_ADDR_ANY) {
...@@ -833,13 +825,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -833,13 +825,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
ipv6_addr_all_nodes(&maddr); ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target, ndisc_send_na(dev, NULL, &maddr, &msg->target,
idev->cnf.forwarding, 0, 0, 1); idev->cnf.forwarding, 0, (ifp != NULL), 1);
in6_dev_put(idev); goto out;
return;
} }
if (addr_type & IPV6_ADDR_UNICAST) {
int inc = ipv6_addr_is_multicast(daddr);
if (inc) if (inc)
nd_tbl.stats.rcv_probes_mcast++; nd_tbl.stats.rcv_probes_mcast++;
else else
...@@ -849,62 +838,22 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -849,62 +838,22 @@ static void ndisc_recv_ns(struct sk_buff *skb)
* update / create cache entry * update / create cache entry
* for the source address * for the source address
*/ */
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
if (neigh || !dev->hard_header) { if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, ndisc_send_na(dev, neigh, saddr, &msg->target,
&msg->target, idev->cnf.forwarding,
idev->cnf.forwarding, 1, 0, inc); 1, (ifp != NULL && inc), inc);
if (neigh) if (neigh)
neigh_release(neigh); neigh_release(neigh);
} }
}
in6_dev_put(idev);
} else {
struct inet6_dev *in6_dev = in6_dev_get(dev);
if (in6_dev && in6_dev->cnf.forwarding && out:
(addr_type & IPV6_ADDR_UNICAST || if (ifp)
addr_type == IPV6_ADDR_ANY) && in6_ifa_put(ifp);
pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
int inc = ipv6_addr_is_multicast(daddr);
if (skb->stamp.tv_sec == 0 ||
skb->pkt_type == PACKET_HOST ||
inc == 0 ||
in6_dev->nd_parms->proxy_delay == 0) {
if (inc)
nd_tbl.stats.rcv_probes_mcast++;
else else
nd_tbl.stats.rcv_probes_ucast++; in6_dev_put(idev);
if (addr_type & IPV6_ADDR_UNICAST) {
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
if (neigh) {
ndisc_send_na(dev, neigh, saddr, &msg->target,
0, 1, 0, 1);
neigh_release(neigh);
}
} else {
/* proxy should also protect against DAD */
struct in6_addr maddr;
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target,
0, 0, 0, 1);
}
} else {
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
if (n)
pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
in6_dev_put(in6_dev);
return;
}
}
if (in6_dev)
in6_dev_put(in6_dev);
}
return; return;
} }
......
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