aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/sit.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r--net/ipv6/sit.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 664ab82e03b2..b3a59bd40f01 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -15,6 +15,7 @@
15 * Roger Venning <r.venning@telstra.com>: 6to4 support 15 * Roger Venning <r.venning@telstra.com>: 6to4 support
16 * Nate Thompson <nate@thebog.net>: 6to4 support 16 * Nate Thompson <nate@thebog.net>: 6to4 support
17 * Fred Templin <fred.l.templin@boeing.com>: isatap support 17 * Fred Templin <fred.l.templin@boeing.com>: isatap support
18 * Sascha Hlusiak <mail@saschahlusiak.de>: stateless autoconf for isatap
18 */ 19 */
19 20
20#include <linux/module.h> 21#include <linux/module.h>
@@ -80,7 +81,7 @@ struct sit_net {
80static DEFINE_RWLOCK(ipip6_lock); 81static DEFINE_RWLOCK(ipip6_lock);
81 82
82static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, 83static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
83 __be32 remote, __be32 local) 84 struct net_device *dev, __be32 remote, __be32 local)
84{ 85{
85 unsigned h0 = HASH(remote); 86 unsigned h0 = HASH(remote);
86 unsigned h1 = HASH(local); 87 unsigned h1 = HASH(local);
@@ -89,18 +90,25 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
89 90
90 for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { 91 for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) {
91 if (local == t->parms.iph.saddr && 92 if (local == t->parms.iph.saddr &&
92 remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 93 remote == t->parms.iph.daddr &&
94 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
95 (t->dev->flags & IFF_UP))
93 return t; 96 return t;
94 } 97 }
95 for (t = sitn->tunnels_r[h0]; t; t = t->next) { 98 for (t = sitn->tunnels_r[h0]; t; t = t->next) {
96 if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) 99 if (remote == t->parms.iph.daddr &&
100 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
101 (t->dev->flags & IFF_UP))
97 return t; 102 return t;
98 } 103 }
99 for (t = sitn->tunnels_l[h1]; t; t = t->next) { 104 for (t = sitn->tunnels_l[h1]; t; t = t->next) {
100 if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) 105 if (local == t->parms.iph.saddr &&
106 (!dev || !t->parms.link || dev->iflink == t->parms.link) &&
107 (t->dev->flags & IFF_UP))
101 return t; 108 return t;
102 } 109 }
103 if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) 110 t = sitn->tunnels_wc[0];
111 if ((t != NULL) && (t->dev->flags & IFF_UP))
104 return t; 112 return t;
105 return NULL; 113 return NULL;
106} 114}
@@ -165,8 +173,14 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
165 struct sit_net *sitn = net_generic(net, sit_net_id); 173 struct sit_net *sitn = net_generic(net, sit_net_id);
166 174
167 for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { 175 for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) {
168 if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) 176 if (local == t->parms.iph.saddr &&
169 return t; 177 remote == t->parms.iph.daddr &&
178 parms->link == t->parms.link) {
179 if (create)
180 return NULL;
181 else
182 return t;
183 }
170 } 184 }
171 if (!create) 185 if (!create)
172 goto failed; 186 goto failed;
@@ -209,6 +223,44 @@ failed:
209 return NULL; 223 return NULL;
210} 224}
211 225
226static void ipip6_tunnel_rs_timer(unsigned long data)
227{
228 struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *) data;
229 struct inet6_dev *ifp;
230 struct inet6_ifaddr *addr;
231
232 spin_lock(&p->lock);
233 ifp = __in6_dev_get(p->tunnel->dev);
234
235 read_lock_bh(&ifp->lock);
236 for (addr = ifp->addr_list; addr; addr = addr->if_next) {
237 struct in6_addr rtr;
238
239 if (!(ipv6_addr_type(&addr->addr) & IPV6_ADDR_LINKLOCAL))
240 continue;
241
242 /* Send RS to guessed linklocal address of router
243 *
244 * Better: send to ff02::2 encapsuled in unicast directly
245 * to router-v4 instead of guessing the v6 address.
246 *
247 * Cisco/Windows seem to not set the u/l bit correctly,
248 * so we won't guess right.
249 */
250 ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0);
251 if (!__ipv6_isatap_ifid(rtr.s6_addr + 8,
252 p->addr)) {
253 ndisc_send_rs(p->tunnel->dev, &addr->addr, &rtr);
254 }
255 }
256 read_unlock_bh(&ifp->lock);
257
258 mod_timer(&p->rs_timer, jiffies + HZ * p->rs_delay);
259 spin_unlock(&p->lock);
260
261 return;
262}
263
212static struct ip_tunnel_prl_entry * 264static struct ip_tunnel_prl_entry *
213__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) 265__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr)
214{ 266{
@@ -267,6 +319,7 @@ static int ipip6_tunnel_get_prl(struct ip_tunnel *t,
267 continue; 319 continue;
268 kp[c].addr = prl->addr; 320 kp[c].addr = prl->addr;
269 kp[c].flags = prl->flags; 321 kp[c].flags = prl->flags;
322 kp[c].rs_delay = prl->rs_delay;
270 c++; 323 c++;
271 if (kprl.addr != htonl(INADDR_ANY)) 324 if (kprl.addr != htonl(INADDR_ANY))
272 break; 325 break;
@@ -316,11 +369,23 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
316 } 369 }
317 370
318 p->next = t->prl; 371 p->next = t->prl;
372 p->tunnel = t;
319 t->prl = p; 373 t->prl = p;
320 t->prl_count++; 374 t->prl_count++;
375
376 spin_lock_init(&p->lock);
377 setup_timer(&p->rs_timer, ipip6_tunnel_rs_timer, (unsigned long) p);
321update: 378update:
322 p->addr = a->addr; 379 p->addr = a->addr;
323 p->flags = a->flags; 380 p->flags = a->flags;
381 p->rs_delay = a->rs_delay;
382 if (p->rs_delay == 0)
383 p->rs_delay = IPTUNNEL_RS_DEFAULT_DELAY;
384 spin_lock(&p->lock);
385 del_timer(&p->rs_timer);
386 if (p->flags & PRL_DEFAULT)
387 mod_timer(&p->rs_timer, jiffies + 1);
388 spin_unlock(&p->lock);
324out: 389out:
325 write_unlock(&ipip6_lock); 390 write_unlock(&ipip6_lock);
326 return err; 391 return err;
@@ -339,6 +404,9 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
339 if ((*p)->addr == a->addr) { 404 if ((*p)->addr == a->addr) {
340 x = *p; 405 x = *p;
341 *p = x->next; 406 *p = x->next;
407 spin_lock(&x->lock);
408 del_timer(&x->rs_timer);
409 spin_unlock(&x->lock);
342 kfree(x); 410 kfree(x);
343 t->prl_count--; 411 t->prl_count--;
344 goto out; 412 goto out;
@@ -349,13 +417,16 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
349 while (t->prl) { 417 while (t->prl) {
350 x = t->prl; 418 x = t->prl;
351 t->prl = t->prl->next; 419 t->prl = t->prl->next;
420 spin_lock(&x->lock);
421 del_timer(&x->rs_timer);
422 spin_unlock(&x->lock);
352 kfree(x); 423 kfree(x);
353 t->prl_count--; 424 t->prl_count--;
354 } 425 }
355 } 426 }
356out: 427out:
357 write_unlock(&ipip6_lock); 428 write_unlock(&ipip6_lock);
358 return 0; 429 return err;
359} 430}
360 431
361static int 432static int
@@ -446,7 +517,10 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
446 err = -ENOENT; 517 err = -ENOENT;
447 518
448 read_lock(&ipip6_lock); 519 read_lock(&ipip6_lock);
449 t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); 520 t = ipip6_tunnel_lookup(dev_net(skb->dev),
521 skb->dev,
522 iph->daddr,
523 iph->saddr);
450 if (t == NULL || t->parms.iph.daddr == 0) 524 if (t == NULL || t->parms.iph.daddr == 0)
451 goto out; 525 goto out;
452 526
@@ -481,8 +555,9 @@ static int ipip6_rcv(struct sk_buff *skb)
481 iph = ip_hdr(skb); 555 iph = ip_hdr(skb);
482 556
483 read_lock(&ipip6_lock); 557 read_lock(&ipip6_lock);
484 if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), 558 tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev,
485 iph->saddr, iph->daddr)) != NULL) { 559 iph->saddr, iph->daddr);
560 if (tunnel != NULL) {
486 secpath_reset(skb); 561 secpath_reset(skb);
487 skb->mac_header = skb->network_header; 562 skb->mac_header = skb->network_header;
488 skb_reset_network_header(skb); 563 skb_reset_network_header(skb);