[PATCH] IPv6: ndisc_rcv() clean-up

From: $B5HF#1QL@(
Date: Thu Oct 24 2002 - 19:44:59 EST


Hi,

This patch just adds new ndisc_recv_ns() and ndisc_recv_na() to
make switch / case in ndisc_rcv() (and ndisc_rcv() itself) small.

This patch is against linux-2.4.20-pre11.

Thanks in advance.

-------------------------------------------------------------------
Patch-Name: ndisc_rcv() clean-up
Patch-Id: FIX_2_4_20_pre11_NDISC_CLEANUP
Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
-------------------------------------------------------------------
Index: net/ipv6/ndisc.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/ndisc.c,v
retrieving revision 1.1.1.2
retrieving revision 1.1.1.2.20.1
diff -u -r1.1.1.2 -r1.1.1.2.20.1
--- net/ipv6/ndisc.c 9 Oct 2002 01:35:53 -0000 1.1.1.2
+++ net/ipv6/ndisc.c 24 Oct 2002 09:50:42 -0000 1.1.1.2.20.1
@@ -583,6 +583,253 @@
         }
 }
 
+void ndisc_recv_ns(struct sk_buff *skb)
+{
+ struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ u8 *lladdr = NULL;
+ int lladdrlen = 0;
+ u32 ndoptlen = skb->tail - msg->opt;
+ struct ndisc_options ndopts;
+ struct net_device *dev = skb->dev;
+ struct inet6_ifaddr *ifp;
+ struct neighbour *neigh;
+
+ if (skb->len < sizeof(struct nd_msg)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NS: packet too short\n");
+ return;
+ }
+
+ if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NS: target address is multicast\n");
+ return;
+ }
+
+ if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+ return;
+ }
+
+ 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(dev->addr_len)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
+ return;
+ }
+ }
+
+ /* XXX: RFC2461 7.1.1:
+ * If the IP source address is the unspecified address, there
+ * MUST NOT be source link-layer address option in the message.
+ *
+ * NOTE! Linux kernel < 2.4.4 broke this rule.
+ */
+
+ /* XXX: RFC2461 7.1.1:
+ * If the IP source address is the unspecified address, the IP
+ * destination address MUST be a solicited-node multicast address.
+ */
+
+ if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
+ int addr_type = ipv6_addr_type(saddr);
+
+ if (ifp->flags & IFA_F_TENTATIVE) {
+ /* Address is tentative. If the source
+ is unspecified address, it is someone
+ does DAD, otherwise we ignore solicitations
+ until DAD timer expires.
+ */
+ if (addr_type == IPV6_ADDR_ANY) {
+ if (dev->type == ARPHRD_IEEE802_TR) {
+ unsigned char *sadr = skb->mac.raw ;
+ if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
+ (sadr[9] != dev->dev_addr[1]) ||
+ (sadr[10] != dev->dev_addr[2]) ||
+ (sadr[11] != dev->dev_addr[3]) ||
+ (sadr[12] != dev->dev_addr[4]) ||
+ (sadr[13] != dev->dev_addr[5]))
+ {
+ addrconf_dad_failure(ifp) ;
+ }
+ } else {
+ addrconf_dad_failure(ifp);
+ }
+ } else
+ in6_ifa_put(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,
+ ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
+ 1);
+ in6_ifa_put(ifp);
+ return;
+ }
+
+ if (addr_type & IPV6_ADDR_UNICAST) {
+ int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+ if (inc)
+ nd_tbl.stats.rcv_probes_mcast++;
+ else
+ nd_tbl.stats.rcv_probes_ucast++;
+
+ /*
+ * update / create cache entry
+ * for the source adddress
+ */
+
+ 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,
+ ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
+ 1);
+ if (neigh)
+ neigh_release(neigh);
+ }
+ }
+ in6_ifa_put(ifp);
+ } else {
+ struct inet6_dev *in6_dev = in6_dev_get(dev);
+ int addr_type = ipv6_addr_type(saddr);
+
+ if (in6_dev && in6_dev->cnf.forwarding &&
+ (addr_type & IPV6_ADDR_UNICAST) &&
+ pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
+ int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
+
+ 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++;
+
+ 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 {
+ 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;
+}
+
+void ndisc_recv_na(struct sk_buff *skb)
+{
+ struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
+ struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
+ struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
+ u8 *lladdr = NULL;
+ int lladdrlen = 0;
+ u32 ndoptlen = skb->tail - msg->opt;
+ struct ndisc_options ndopts;
+ struct net_device *dev = skb->dev;
+ struct inet6_ifaddr *ifp;
+ struct neighbour *neigh;
+
+ if (skb->len < sizeof(struct nd_msg)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NA: packet too short\n");
+ return;
+ }
+
+ if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "NDISC NA: target address is multicast\n");
+ return;
+ }
+
+ if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
+ msg->icmph.icmp6_solicited) {
+ ND_PRINTK0("NDISC: solicited NA is multicasted\n");
+ return;
+ }
+
+ if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
+ return;
+ }
+ if (ndopts.nd_opts_tgt_lladdr) {
+ lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
+ lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
+ if (lladdrlen != NDISC_OPT_SPACE(dev->addr_len)) {
+ if (net_ratelimit())
+ printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
+ return;
+ }
+ }
+ if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
+ if (ifp->flags & IFA_F_TENTATIVE) {
+ addrconf_dad_failure(ifp);
+ return;
+ }
+ /* What should we make now? The advertisement
+ is invalid, but ndisc specs say nothing
+ about it. It could be misconfiguration, or
+ an smart proxy agent tries to help us :-)
+ */
+ ND_PRINTK0("%s: someone advertises our address!\n",
+ ifp->idev->dev->name);
+ in6_ifa_put(ifp);
+ return;
+ }
+ neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
+
+ if (neigh) {
+ if (neigh->flags & NTF_ROUTER) {
+ if (msg->icmph.icmp6_router == 0) {
+ /*
+ * Change: router to host
+ */
+ struct rt6_info *rt;
+ rt = rt6_get_dflt_router(saddr, dev);
+ if (rt) {
+ /* It is safe only because
+ we aer in BH */
+ dst_release(&rt->u.dst);
+ ip6_del_rt(rt);
+ }
+ }
+ } else {
+ if (msg->icmph.icmp6_router)
+ neigh->flags |= NTF_ROUTER;
+ }
+
+ neigh_update(neigh, lladdr,
+ msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
+ msg->icmph.icmp6_override, 1);
+ neigh_release(neigh);
+ }
+}
+
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
@@ -990,12 +1237,7 @@
 
 int ndisc_rcv(struct sk_buff *skb)
 {
- struct net_device *dev = skb->dev;
- struct in6_addr *saddr = &skb->nh.ipv6h->saddr;
- struct in6_addr *daddr = &skb->nh.ipv6h->daddr;
         struct nd_msg *msg = (struct nd_msg *) skb->h.raw;
- struct neighbour *neigh;
- struct inet6_ifaddr *ifp;
 
         __skb_push(skb, skb->data-skb->h.raw);
 
@@ -1015,244 +1257,12 @@
 
         switch (msg->icmph.icmp6_type) {
         case NDISC_NEIGHBOUR_SOLICITATION:
- {
- struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
- u8 *lladdr = NULL;
- int lladdrlen = 0;
- u32 ndoptlen = skb->tail - msg->opt;
- struct ndisc_options ndopts;
-
- if (skb->len < sizeof(struct nd_msg)) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NS: packet too short\n");
- return 0;
- }
-
- if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NS: target address is multicast\n");
- return 0;
- }
-
- if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
- return 0;
- }
-
- 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)) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NS: bad lladdr length.\n");
- return 0;
- }
- }
-
- /* XXX: RFC2461 7.1.1:
- * If the IP source address is the unspecified address, there
- * MUST NOT be source link-layer address option in the message.
- *
- * NOTE! Linux kernel < 2.4.4 broke this rule.
- */
-
- /* XXX: RFC2461 7.1.1:
- * If the IP source address is the unspecified address, the IP
- * destination address MUST be a solicited-node multicast address.
- */
-
- if ((ifp = ipv6_get_ifaddr(&msg->target, dev)) != NULL) {
- int addr_type = ipv6_addr_type(saddr);
-
- if (ifp->flags & IFA_F_TENTATIVE) {
- /* Address is tentative. If the source
- is unspecified address, it is someone
- does DAD, otherwise we ignore solicitations
- until DAD timer expires.
- */
- if (addr_type == IPV6_ADDR_ANY) {
- if (dev->type == ARPHRD_IEEE802_TR) {
- unsigned char *sadr = skb->mac.raw ;
- if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
- (sadr[9] != dev->dev_addr[1]) ||
- (sadr[10] != dev->dev_addr[2]) ||
- (sadr[11] != dev->dev_addr[3]) ||
- (sadr[12] != dev->dev_addr[4]) ||
- (sadr[13] != dev->dev_addr[5]))
- {
- addrconf_dad_failure(ifp) ;
- }
- } else {
- addrconf_dad_failure(ifp);
- }
- } else
- in6_ifa_put(ifp);
- return 0;
- }
-
- 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,
- ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
- 1);
- in6_ifa_put(ifp);
- return 0;
- }
-
- if (addr_type & IPV6_ADDR_UNICAST) {
- int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
-
- if (inc)
- nd_tbl.stats.rcv_probes_mcast++;
- else
- nd_tbl.stats.rcv_probes_ucast++;
-
- /*
- * update / create cache entry
- * for the source adddress
- */
-
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
-
- if (neigh || !dev->hard_header) {
- ndisc_send_na(dev, neigh, saddr, &ifp->addr,
- ifp->idev->cnf.forwarding, 1,
- ipv6_addr_type(&ifp->addr)&IPV6_ADDR_ANYCAST ? 0 : 1,
- 1);
- if (neigh)
- neigh_release(neigh);
- }
- }
- in6_ifa_put(ifp);
- } else {
- struct inet6_dev *in6_dev = in6_dev_get(dev);
- int addr_type = ipv6_addr_type(saddr);
-
- if (in6_dev && in6_dev->cnf.forwarding &&
- (addr_type & IPV6_ADDR_UNICAST) &&
- pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
- int inc = ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST;
-
- 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++;
-
-
- neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev);
-
- if (neigh) {
- ndisc_send_na(dev, neigh, saddr, &msg->target,
- 0, 1, 0, 1);
- neigh_release(neigh);
- }
- } 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 0;
- }
- }
- if (in6_dev)
- in6_dev_put(in6_dev);
-
- }
- return 0;
- }
+ ndisc_recv_ns(skb);
+ break;
 
         case NDISC_NEIGHBOUR_ADVERTISEMENT:
- {
- struct nd_msg *msg = (struct nd_msg *)skb->h.raw;
- u8 *lladdr = NULL;
- int lladdrlen = 0;
- u32 ndoptlen = skb->tail - msg->opt;
- struct ndisc_options ndopts;
-
- if (skb->len < sizeof(struct nd_msg)) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NA: packet too short\n");
- return 0;
- }
-
- if (ipv6_addr_type(&msg->target)&IPV6_ADDR_MULTICAST) {
- if (net_ratelimit())
- printk(KERN_WARNING "NDISC NA: target address is multicast\n");
- return 0;
- }
-
- if ((ipv6_addr_type(daddr)&IPV6_ADDR_MULTICAST) &&
- msg->icmph.icmp6_solicited) {
- ND_PRINTK0("NDISC: solicited NA is multicasted\n");
- return 0;
- }
-
- if (!ndisc_parse_options(msg->opt, ndoptlen, &ndopts)) {
- if (net_ratelimit())
- printk(KERN_WARNING "ICMP NS: invalid ND option, ignored.\n");
- return 0;
- }
- if (ndopts.nd_opts_tgt_lladdr) {
- lladdr = (u8*)(ndopts.nd_opts_tgt_lladdr + 1);
- lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
- if (lladdrlen != NDISC_OPT_SPACE(skb->dev->addr_len)) {
- if (net_ratelimit())
- printk(KERN_WARNING "NDISC NA: invalid lladdr length.\n");
- return 0;
- }
- }
- if ((ifp = ipv6_get_ifaddr(&msg->target, dev))) {
- if (ifp->flags & IFA_F_TENTATIVE) {
- addrconf_dad_failure(ifp);
- return 0;
- }
- /* What should we make now? The advertisement
- is invalid, but ndisc specs say nothing
- about it. It could be misconfiguration, or
- an smart proxy agent tries to help us :-)
- */
- ND_PRINTK0("%s: someone advertises our address!\n",
- ifp->idev->dev->name);
- in6_ifa_put(ifp);
- return 0;
- }
- neigh = neigh_lookup(&nd_tbl, &msg->target, skb->dev);
-
- if (neigh) {
- if (neigh->flags & NTF_ROUTER) {
- if (msg->icmph.icmp6_router == 0) {
- /*
- * Change: router to host
- */
- struct rt6_info *rt;
- rt = rt6_get_dflt_router(saddr, skb->dev);
- if (rt) {
- /* It is safe only because
- we aer in BH */
- dst_release(&rt->u.dst);
- ip6_del_rt(rt);
- }
- }
- } else {
- if (msg->icmph.icmp6_router)
- neigh->flags |= NTF_ROUTER;
- }
-
- neigh_update(neigh, lladdr,
- msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE,
- msg->icmph.icmp6_override, 1);
- neigh_release(neigh);
- }
+ ndisc_recv_na(skb);
                 break;
- }
 
         case NDISC_ROUTER_ADVERTISEMENT:
                 ndisc_router_discovery(skb);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Thu Oct 31 2002 - 22:00:26 EST