aboutsummaryrefslogtreecommitdiff
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
authorSascha Hlusiak <contact@saschahlusiak.de>2009-05-19 12:56:52 +0000
committerDavid S. Miller <davem@davemloft.net>2009-05-19 16:02:02 -0700
commit645069299a1c7358cf7330afe293f07552f11a5d (patch)
tree889c39a10ef09cd77c5b052ef837bb4b53bddd83 /net/ipv6/sit.c
parent9af28511be10e175eb0cabb2ba5cfafe77408d84 (diff)
sit: stateless autoconf for isatap
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>
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 3fd060076e7..b3a59bd40f0 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -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--;
}