xfrm6: Fix xfrm6_policy.c build when SYSCTL disabled.
[safe/jmp/linux-2.6] / net / ipv6 / sit.c
index dfedd56..d335a30 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,13 +417,16 @@ 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--;
                }
        }
 out:
        write_unlock(&ipip6_lock);
-       return 0;
+       return err;
 }
 
 static int
@@ -517,8 +575,7 @@ static int ipip6_rcv(struct sk_buff *skb)
                tunnel->dev->stats.rx_packets++;
                tunnel->dev->stats.rx_bytes += skb->len;
                skb->dev = tunnel->dev;
-               dst_release(skb->dst);
-               skb->dst = NULL;
+               skb_dst_drop(skb);
                nf_reset(skb);
                ipip6_ecn_decapsulate(iph, skb);
                netif_rx(skb);
@@ -580,8 +637,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (dev->priv_flags & IFF_ISATAP) {
                struct neighbour *neigh = NULL;
 
-               if (skb->dst)
-                       neigh = skb->dst->neighbour;
+               if (skb_dst(skb))
+                       neigh = skb_dst(skb)->neighbour;
 
                if (neigh == NULL) {
                        if (net_ratelimit())
@@ -605,8 +662,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (!dst) {
                struct neighbour *neigh = NULL;
 
-               if (skb->dst)
-                       neigh = skb->dst->neighbour;
+               if (skb_dst(skb))
+                       neigh = skb_dst(skb)->neighbour;
 
                if (neigh == NULL) {
                        if (net_ratelimit())
@@ -656,7 +713,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        if (tiph->frag_off)
                mtu = dst_mtu(&rt->u.dst) - sizeof(struct iphdr);
        else
-               mtu = skb->dst ? dst_mtu(skb->dst) : dev->mtu;
+               mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu;
 
        if (mtu < 68) {
                stats->collisions++;
@@ -665,8 +722,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
-       if (tunnel->parms.iph.daddr && skb->dst)
-               skb->dst->ops->update_pmtu(skb->dst, mtu);
+       if (tunnel->parms.iph.daddr && skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
 
        if (skb->len > mtu) {
                icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
@@ -696,7 +753,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
                        stats->tx_dropped++;
                        dev_kfree_skb(skb);
                        tunnel->recursion--;
-                       return 0;
+                       return NETDEV_TX_OK;
                }
                if (skb->sk)
                        skb_set_owner_w(new_skb, skb->sk);
@@ -710,8 +767,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_reset_network_header(skb);
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
        IPCB(skb)->flags = 0;
-       dst_release(skb->dst);
-       skb->dst = &rt->u.dst;
+       skb_dst_drop(skb);
+       skb_dst_set(skb, &rt->u.dst);
 
        /*
         *      Push down and install the IPIP header.
@@ -737,7 +794,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        IPTUNNEL_XMIT();
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 
 tx_error_icmp:
        dst_link_failure(skb);
@@ -745,7 +802,7 @@ tx_error:
        stats->tx_errors++;
        dev_kfree_skb(skb);
        tunnel->recursion--;
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 static void ipip6_tunnel_bind_dev(struct net_device *dev)
@@ -961,6 +1018,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
        dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
        dev->mtu                = ETH_DATA_LEN - sizeof(struct iphdr);
        dev->flags              = IFF_NOARP;
+       dev->priv_flags        &= ~IFF_XMIT_DST_RELEASE;
        dev->iflink             = 0;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_NETNS_LOCAL;