diff options
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 97 |
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 { | |||
80 | static DEFINE_RWLOCK(ipip6_lock); | 81 | static DEFINE_RWLOCK(ipip6_lock); |
81 | 82 | ||
82 | static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, | 83 | static 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 | ||
226 | static 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 | |||
212 | static struct ip_tunnel_prl_entry * | 264 | static 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); | ||
321 | update: | 378 | update: |
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); | ||
324 | out: | 389 | out: |
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 | } |
356 | out: | 427 | out: |
357 | write_unlock(&ipip6_lock); | 428 | write_unlock(&ipip6_lock); |
358 | return 0; | 429 | return err; |
359 | } | 430 | } |
360 | 431 | ||
361 | static int | 432 | static 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); |