summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>2004-02-05 23:27:38 -0800
committerHideaki Yoshifuji <yoshfuji@linux-ipv6.org>2004-02-05 23:27:38 -0800
commit13ef52adea98ef92fa0d4b8dbc055ffd28452265 (patch)
tree24b9209a7cead58d22a66069f72f8948b70ac48a
parentb1e63f72029af02a4f1b66e08652ec249c338552 (diff)
[IPV6]: Unify 3 similar code paths in ndisc_recv_ns().
-rw-r--r--net/ipv6/ndisc.c171
1 files changed, 60 insertions, 111 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index d0b59590b252..dd2cb637da34 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
struct ndisc_options ndopts;
struct net_device *dev = skb->dev;
struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev = NULL;
struct neighbour *neigh;
int addr_type = ipv6_addr_type(saddr);
+ int inc;
if (ipv6_addr_is_multicast(&msg->target)) {
if (net_ratelimit())
@@ -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->flags & IFA_F_TENTATIVE) {
/* Address is tentative. If the source
@@ -784,127 +788,72 @@ static void ndisc_recv_ns(struct sk_buff *skb)
addrconf_dad_failure(ifp);
return;
}
-
- if (addr_type == IPV6_ADDR_ANY) {
- struct in6_addr maddr;
-
- ipv6_addr_all_nodes(&maddr);
- ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
- ifp->idev->cnf.forwarding, 0,
- 1, 1);
- in6_ifa_put(ifp);
- return;
- }
-
- if (addr_type & IPV6_ADDR_UNICAST) {
- if (ipv6_addr_is_multicast(daddr))
- nd_tbl.stats.rcv_probes_mcast++;
- else
- nd_tbl.stats.rcv_probes_ucast++;
- /*
- * update / create cache entry
- * for the source address
- */
-
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
-
- if (neigh || !dev->hard_header) {
- 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 if (ipv6_chk_acast_addr(dev, &msg->target)) {
- struct inet6_dev *idev = in6_dev_get(dev);
-
- /* anycast */
-
+ idev = ifp->idev;
+ } else {
+ idev = in6_dev_get(dev);
if (!idev) {
/* XXX: count this drop? */
return;
}
-
- if (addr_type == IPV6_ADDR_ANY) {
- struct in6_addr maddr;
-
- ipv6_addr_all_nodes(&maddr);
- ndisc_send_na(dev, NULL, &maddr, &msg->target,
- idev->cnf.forwarding, 0, 0, 1);
- in6_dev_put(idev);
- return;
- }
-
- if (addr_type & IPV6_ADDR_UNICAST) {
- int inc = ipv6_addr_is_multicast(daddr);
- if (inc)
- nd_tbl.stats.rcv_probes_mcast++;
- else
- nd_tbl.stats.rcv_probes_ucast++;
-
- /*
- * update / create cache entry
- * for the source address
- */
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
-
- if (neigh || !dev->hard_header) {
- ndisc_send_na(dev, neigh, saddr,
- &msg->target,
- idev->cnf.forwarding, 1, 0, inc);
- if (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 &&
- (addr_type & IPV6_ADDR_UNICAST ||
- addr_type == IPV6_ADDR_ANY) &&
- 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
- nd_tbl.stats.rcv_probes_ucast++;
-
- 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 {
+ if (ipv6_chk_acast_addr(dev, &msg->target) ||
+ (idev->cnf.forwarding &&
+ pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
+ if (skb->stamp.tv_sec != 0 &&
+ skb->pkt_type != PACKET_HOST &&
+ inc != 0 &&
+ idev->nd_parms->proxy_delay != 0) {
+ /*
+ * for anycast or proxy,
+ * 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);
if (n)
- pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
- in6_dev_put(in6_dev);
- return;
+ pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
+ goto out;
}
- }
- if (in6_dev)
- in6_dev_put(in6_dev);
+ } else
+ goto out;
}
+
+ if (addr_type == IPV6_ADDR_ANY) {
+ struct in6_addr maddr;
+
+ ipv6_addr_all_nodes(&maddr);
+ ndisc_send_na(dev, NULL, &maddr, &msg->target,
+ idev->cnf.forwarding, 0, (ifp != NULL), 1);
+ goto out;
+ }
+
+ if (inc)
+ nd_tbl.stats.rcv_probes_mcast++;
+ else
+ nd_tbl.stats.rcv_probes_ucast++;
+
+ /*
+ * update / create cache entry
+ * for the source address
+ */
+ neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
+
+ if (neigh || !dev->hard_header) {
+ ndisc_send_na(dev, neigh, saddr, &msg->target,
+ idev->cnf.forwarding,
+ 1, (ifp != NULL && inc), inc);
+ if (neigh)
+ neigh_release(neigh);
+ }
+
+out:
+ if (ifp)
+ in6_ifa_put(ifp);
+ else
+ in6_dev_put(idev);
+
return;
}