diff options
Diffstat (limited to 'net/ipv6/sit.c')
-rw-r--r-- | net/ipv6/sit.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 71433d29d884..b3b8513e9cb7 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -16,6 +16,7 @@ | |||
16 | * Changes: | 16 | * Changes: |
17 | * Roger Venning <r.venning@telstra.com>: 6to4 support | 17 | * Roger Venning <r.venning@telstra.com>: 6to4 support |
18 | * Nate Thompson <nate@thebog.net>: 6to4 support | 18 | * Nate Thompson <nate@thebog.net>: 6to4 support |
19 | * Fred L. Templin <fltemplin@acm.org>: isatap support | ||
19 | */ | 20 | */ |
20 | 21 | ||
21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
@@ -182,6 +183,9 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int | |||
182 | dev->init = ipip6_tunnel_init; | 183 | dev->init = ipip6_tunnel_init; |
183 | nt->parms = *parms; | 184 | nt->parms = *parms; |
184 | 185 | ||
186 | if (parms->i_flags & SIT_ISATAP) | ||
187 | dev->priv_flags |= IFF_ISATAP; | ||
188 | |||
185 | if (register_netdevice(dev) < 0) { | 189 | if (register_netdevice(dev) < 0) { |
186 | free_netdev(dev); | 190 | free_netdev(dev); |
187 | goto failed; | 191 | goto failed; |
@@ -364,6 +368,48 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | |||
364 | IP6_ECN_set_ce(ipv6_hdr(skb)); | 368 | IP6_ECN_set_ce(ipv6_hdr(skb)); |
365 | } | 369 | } |
366 | 370 | ||
371 | /* ISATAP (RFC4214) - check source address */ | ||
372 | static int | ||
373 | isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev) | ||
374 | { | ||
375 | struct neighbour *neigh; | ||
376 | struct dst_entry *dst; | ||
377 | struct rt6_info *rt; | ||
378 | struct flowi fl; | ||
379 | struct in6_addr *addr6; | ||
380 | struct in6_addr rtr; | ||
381 | struct ipv6hdr *iph6; | ||
382 | int ok = 0; | ||
383 | |||
384 | /* from onlink default router */ | ||
385 | ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); | ||
386 | ipv6_isatap_eui64(rtr.s6_addr + 8, iph->saddr); | ||
387 | if ((rt = rt6_get_dflt_router(&rtr, dev))) { | ||
388 | dst_release(&rt->u.dst); | ||
389 | return 1; | ||
390 | } | ||
391 | |||
392 | iph6 = ipv6_hdr(skb); | ||
393 | memset(&fl, 0, sizeof(fl)); | ||
394 | fl.proto = iph6->nexthdr; | ||
395 | ipv6_addr_copy(&fl.fl6_dst, &iph6->saddr); | ||
396 | fl.oif = dev->ifindex; | ||
397 | security_skb_classify_flow(skb, &fl); | ||
398 | |||
399 | dst = ip6_route_output(NULL, &fl); | ||
400 | if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) { | ||
401 | |||
402 | addr6 = (struct in6_addr*)&neigh->primary_key; | ||
403 | |||
404 | /* from correct previous hop */ | ||
405 | if (ipv6_addr_is_isatap(addr6) && | ||
406 | (addr6->s6_addr32[3] == iph->saddr)) | ||
407 | ok = 1; | ||
408 | } | ||
409 | dst_release(dst); | ||
410 | return ok; | ||
411 | } | ||
412 | |||
367 | static int ipip6_rcv(struct sk_buff *skb) | 413 | static int ipip6_rcv(struct sk_buff *skb) |
368 | { | 414 | { |
369 | struct iphdr *iph; | 415 | struct iphdr *iph; |
@@ -382,6 +428,14 @@ static int ipip6_rcv(struct sk_buff *skb) | |||
382 | IPCB(skb)->flags = 0; | 428 | IPCB(skb)->flags = 0; |
383 | skb->protocol = htons(ETH_P_IPV6); | 429 | skb->protocol = htons(ETH_P_IPV6); |
384 | skb->pkt_type = PACKET_HOST; | 430 | skb->pkt_type = PACKET_HOST; |
431 | |||
432 | if ((tunnel->dev->priv_flags & IFF_ISATAP) && | ||
433 | !isatap_srcok(skb, iph, tunnel->dev)) { | ||
434 | tunnel->stat.rx_errors++; | ||
435 | read_unlock(&ipip6_lock); | ||
436 | kfree_skb(skb); | ||
437 | return 0; | ||
438 | } | ||
385 | tunnel->stat.rx_packets++; | 439 | tunnel->stat.rx_packets++; |
386 | tunnel->stat.rx_bytes += skb->len; | 440 | tunnel->stat.rx_bytes += skb->len; |
387 | skb->dev = tunnel->dev; | 441 | skb->dev = tunnel->dev; |
@@ -444,6 +498,29 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) | |||
444 | if (skb->protocol != htons(ETH_P_IPV6)) | 498 | if (skb->protocol != htons(ETH_P_IPV6)) |
445 | goto tx_error; | 499 | goto tx_error; |
446 | 500 | ||
501 | /* ISATAP (RFC4214) - must come before 6to4 */ | ||
502 | if (dev->priv_flags & IFF_ISATAP) { | ||
503 | struct neighbour *neigh = NULL; | ||
504 | |||
505 | if (skb->dst) | ||
506 | neigh = skb->dst->neighbour; | ||
507 | |||
508 | if (neigh == NULL) { | ||
509 | if (net_ratelimit()) | ||
510 | printk(KERN_DEBUG "sit: nexthop == NULL\n"); | ||
511 | goto tx_error; | ||
512 | } | ||
513 | |||
514 | addr6 = (struct in6_addr*)&neigh->primary_key; | ||
515 | addr_type = ipv6_addr_type(addr6); | ||
516 | |||
517 | if ((addr_type & IPV6_ADDR_UNICAST) && | ||
518 | ipv6_addr_is_isatap(addr6)) | ||
519 | dst = addr6->s6_addr32[3]; | ||
520 | else | ||
521 | goto tx_error; | ||
522 | } | ||
523 | |||
447 | if (!dst) | 524 | if (!dst) |
448 | dst = try_6to4(&iph6->daddr); | 525 | dst = try_6to4(&iph6->daddr); |
449 | 526 | ||