sit: stateless autoconf for isatap
authorSascha Hlusiak <contact@saschahlusiak.de>
Tue, 19 May 2009 12:56:52 +0000 (12:56 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 May 2009 23:02:02 +0000 (16:02 -0700)
be sent periodically. The rs_delay can be speficied when adding the
PRL entry and defaults to 15 minutes.

The RS is sent from every link local adress that's assigned to the
tunnel interface. It's directed to the (guessed) linklocal address
of the router and is sent through the tunnel.

Better: send to ff02::2 encapsuled in unicast directed to router-v4.

Signed-off-by: Sascha Hlusiak <contact@saschahlusiak.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/if_tunnel.h
include/net/ipip.h
net/ipv6/ndisc.c
net/ipv6/sit.c

index 5a9aae4adb444a3c8a63b5b9c5afd2c4456396de..5eb9b0f857e0720569eb04373ef42fb51bb04c9a 100644 (file)
@@ -44,7 +44,7 @@ struct ip_tunnel_prl {
        __u16                   flags;
        __u16                   __reserved;
        __u32                   datalen;
-       __u32                   __reserved2;
+       __u32                   rs_delay;
        /* data follows */
 };
 
index fdf9bd7437057e26b0f9cd3bdadb8c70ed8a09f6..5d3036fa1511695879a18d3adc02f57feef49392 100644 (file)
@@ -28,11 +28,18 @@ struct ip_tunnel
        unsigned int                    prl_count;      /* # of entries in PRL */
 };
 
+/* ISATAP: default interval between RS in secondy */
+#define IPTUNNEL_RS_DEFAULT_DELAY      (900)
+
 struct ip_tunnel_prl_entry
 {
        struct ip_tunnel_prl_entry      *next;
        __be32                          addr;
        u16                             flags;
+       unsigned long                   rs_delay;
+       struct timer_list               rs_timer;
+       struct ip_tunnel                *tunnel;
+       spinlock_t                      lock;
 };
 
 #define IPTUNNEL_XMIT() do {                                           \
index ab65cc51b00e4953687c21497d586eda92eb12ac..e09f12ee57cf956f5f68fb723c9b603954b20fa2 100644 (file)
@@ -658,6 +658,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
                     &icmp6h, NULL,
                     send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
 }
+EXPORT_SYMBOL(ndisc_send_rs);
 
 
 static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb)
index 3fd060076e7a78bad437041f2a5c1cca0322ac86..b3a59bd40f0184a7bad41d6b4320263040086659 100644 (file)
@@ -15,6 +15,7 @@
  * Roger Venning <r.venning@telstra.com>:      6to4 support
  * Nate Thompson <nate@thebog.net>:            6to4 support
  * Fred Templin <fred.l.templin@boeing.com>:   isatap support
+ * Sascha Hlusiak <mail@saschahlusiak.de>:     stateless autoconf for isatap
  */
 
 #include <linux/module.h>
@@ -222,6 +223,44 @@ failed:
        return NULL;
 }
 
+static void ipip6_tunnel_rs_timer(unsigned long data)
+{
+       struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data;
+       struct inet6_dev *ifp;
+       struct inet6_ifaddr *addr;
+
+       spin_lock(&p->lock);
+       ifp = __in6_dev_get(p->tunnel->dev);
+
+       read_lock_bh(&ifp->lock);
+       for (addr = ifp->addr_list; addr; addr = addr->if_next) {
+               struct in6_addr rtr;
+
+               if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL))
+                       continue;
+
+               /* Send RS to guessed linklocal address of router
+                *
+                * Better: send to ff02::2 encapsuled in unicast directly
+                * to router-v4 instead of guessing the v6 address.
+                *
+                * Cisco/Windows seem to not set the u/l bit correctly,
+                * so we won't guess right.
+                */
+               ipv6_addr_set(&rtr,  htonl(0xFE800000), 0, 0, 0);
+               if (!__ipv6_isatap_ifid(rtr.s6_addr + 8,
+                                       p->addr)) {
+                       ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr);
+               }
+       }
+       read_unlock_bh(&ifp->lock);
+
+       mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay);
+       spin_unlock(&p->lock);
+
+       return;
+}
+
 static struct ip_tunnel_prl_entry *
 __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
 {
@@ -280,6 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
                        continue;
                kp[c].addr = prl->addr;
                kp[c].flags = prl->flags;
+               kp[c].rs_delay = prl->rs_delay;
                c++;
                if (kprl.addr != htonl(INADDR_ANY))
                        break;
@@ -329,11 +369,23 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
        }
 
        p->next = t->prl;
+       p->tunnel = t;
        t->prl = p;
        t->prl_count++;
+
+       spin_lock_init(&p->lock);
+       setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p);
 update:
        p->addr = a->addr;
        p->flags = a->flags;
+       p->rs_delay = a->rs_delay;
+       if (p->rs_delay == 0)
+               p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY;
+       spin_lock(&p->lock);
+       del_timer(&p->rs_timer);
+       if (p->flags & PRL_DEFAULT)
+               mod_timer(&p->rs_timer, jiffies + 1);
+       spin_unlock(&p->lock);
 out:
        write_unlock(&ipip6_lock);
        return err;
@@ -352,6 +404,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
                        if ((*p)->addr == a->addr) {
                                x = *p;
                                *p = x->next;
+                               spin_lock(&x->lock);
+                               del_timer(&x->rs_timer);
+                               spin_unlock(&x->lock);
                                kfree(x);
                                t->prl_count--;
                                goto out;
@@ -362,6 +417,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
                while (t->prl) {
                        x = t->prl;
                        t->prl = t->prl->next;
+                       spin_lock(&x->lock);
+                       del_timer(&x->rs_timer);
+                       spin_unlock(&x->lock);
                        kfree(x);
                        t->prl_count--;
                }