[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

(usagi-users 02704) insufficient process when receiving IPv6 Router Solicitation



Hello,

I think that the processing which receives Router Solicitation
Message is insufficient in the USAGI snap kernel-2.6-s20031208.

 1. (RFC2461 6.1.1)
    Hosts MUST silently discard any received Router Solicitation
    Messages.

 2. (RFC2461 6.1.1)
       .....
      A router MUST silently discard any received Router Solicitation
      messages that do not satisfy all of the following validity checks:
       .....
      - ICMP Code is 0.
       .....
      - All included options have a length that is greater than zero.
      - If the IP source address is the unspecified address, there is no
        source link-layer address option in the message.
       .....

 3. (RFC2461 6.2.6)
       .....
      Router Solicitations in which the Source Address is the unspecified
      address MUST NOT update the router's Neighbor Cache;

 4. (RFC2461 6.2.6)
       .....
      solicitations
      with a proper source address update the Neighbor Cache as follows. If
      the router already has a Neighbor Cache entry for the solicitation's
      sender, the solicitation contains a Source Link-Layer Address option,
      and the received link-layer address differs from that already in the
      cache, the link-layer address SHOULD be updated in the appropriate
      Neighbor Cache entry, and its reachability state MUST also be set to
      STALE. If there is no existing Neighbor Cache entry for the
      solicitation's sender, the router creates one, installs the link-
      layer address and sets its reachability state to STALE as specified
      in Section 7.3.3. Whether or not a Source Link-Layer Address option
      is provided, if a Neighbor Cache entry for the solicitation's sender
      exists (or is created) the entry's IsRouter flag MUST be set to
      FALSE.

I made a patch and fixed the problem. This patch referred
to the USAGI snap kernel-2.4-s20031208.

------------------------------------------------------------------------
--- net/ipv6/ndisc.c.orig       2003-10-30 14:49:30.000000000 +0900
+++ net/ipv6/ndisc.c    2003-12-10 08:58:49.000000000 +0900
@@ -999,6 +999,67 @@
        }
 }

+static void ndisc_recv_rs(struct sk_buff *skb)
+{
+       struct icmp6hdr *rs_msg = (struct icmp6hdr *) 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;
+
+       ND_PRINTK2(KERN_DEBUG "ndisc_recv_rs()\n");
+
+       idev = in6_dev_get(skb->dev);
+       if (!idev) {
+               ND_PRINTK1(KERN_WARNING "ndisc_recv_rs: can't find in6 device\n");
+               return;
+       }
+
+       /* Ignore if I'm not a router */
+       if (!idev->cnf.forwarding || idev->cnf.accept_ra)
+               goto out;
+
+       if (!ndisc_parse_options((u8*)(rs_msg+1), ndoptlen, &ndopts)){
+               if (net_ratelimit())
+                       ND_PRINTK2(KERN_WARNING "ICMP6 NS: invalid ND option, ignored\n");
+               goto out;
+       }
+
+       /* Don't update NCE if src = :: */
+       if (ipv6_addr_any(saddr)) {
+               /*
+                * this is ok but ignore because this indicates that
+                * source has no ip address assigned yet.
+                */
+               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) {
+               int notify;
+               write_lock(&neigh->lock);
+               neigh_update(neigh, lladdr, NUD_STALE, 1, NEIGH_UPDATE_TYPE_IP6RS);
+               write_unlock(&neigh->lock);
+#ifdef CONFIG_ARPD
+               if (notify > 0)
+                       neigh_app_notify(neigh);
+#endif
+               neigh_release(neigh);
+       }
+out:
+       in6_dev_put(idev);
+}
+
 static void ndisc_router_discovery(struct sk_buff *skb)
 {
         struct ra_msg *ra_msg = (struct ra_msg *) skb->h.raw;
@@ -1480,6 +1541,10 @@
                ndisc_router_discovery(skb);
                break;

+       case NDISC_ROUTER_SOLICITATION:
+               ndisc_recv_rs(skb);
+               break;
+
        case NDISC_REDIRECT:
                ndisc_redirect_rcv(skb);
                break;
------------------------------------------------------------------------

Regards,
Hiroaki Kago