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.c77
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 */
372static int
373isatap_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
367static int ipip6_rcv(struct sk_buff *skb) 413static 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