diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 5a9aae4adb444a3c8a63b5b9c5afd2c4456396de..5eb9b0f857e0720569eb04373ef42fb51bb04c9a 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -44,7 +44,7 @@ struct ip_tunnel_prl { __u16 flags; __u16 __reserved; __u32 datalen; - __u32 __reserved2; + __u32 rs_delay; /* data follows */ }; diff --git a/include/net/ipip.h b/include/net/ipip.h index fdf9bd7437057e26b0f9cd3bdadb8c70ed8a09f6..5d3036fa1511695879a18d3adc02f57feef49392 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -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 { \ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index ab65cc51b00e4953687c21497d586eda92eb12ac..e09f12ee57cf956f5f68fb723c9b603954b20fa2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -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) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 3fd060076e7a78bad437041f2a5c1cca0322ac86..b3a59bd40f0184a7bad41d6b4320263040086659 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -15,6 +15,7 @@ * Roger Venning : 6to4 support * Nate Thompson : 6to4 support * Fred Templin : isatap support + * Sascha Hlusiak : stateless autoconf for isatap */ #include @@ -222,6 +223,44 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, 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--; }