diff options
author | Fred L. Templin <fred.l.templin@boeing.com> | 2007-11-29 06:11:40 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:55:09 -0500 |
commit | c7dc89c0ac8e7c3796bff91becf58ccdbcaf9f18 (patch) | |
tree | e876ccadf29a90b7a211522aeccfd42255dab586 | |
parent | df97c708d5e6eebdd9ded1fa588eae09acf53793 (diff) |
[IPV6]: Add RFC4214 support
This patch includes support for the Intra-Site Automatic Tunnel
Addressing Protocol (ISATAP) per RFC4214. It uses the SIT
module, and is configured using extensions to the "iproute2"
utility. The diffs are specific to the Linux 2.6.24-rc2 kernel
distribution.
This version includes the diff for ./include/linux/if.h which was
missing in the v2.4 submission and is needed to make the
patch compile. The patch has been installed, compiled and
tested in a clean 2.6.24-rc2 kernel build area.
Signed-off-by: Fred L. Templin <fred.l.templin@boeing.com>
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/if.h | 1 | ||||
-rw-r--r-- | include/linux/if_tunnel.h | 3 | ||||
-rw-r--r-- | include/linux/in.h | 8 | ||||
-rw-r--r-- | include/net/addrconf.h | 19 | ||||
-rw-r--r-- | net/ipv6/addrconf.c | 22 | ||||
-rw-r--r-- | net/ipv6/route.c | 2 | ||||
-rw-r--r-- | net/ipv6/sit.c | 77 |
7 files changed, 131 insertions, 1 deletions
diff --git a/include/linux/if.h b/include/linux/if.h index 186070d5c544..5c9d1fa93fef 100644 --- a/include/linux/if.h +++ b/include/linux/if.h | |||
@@ -63,6 +63,7 @@ | |||
63 | #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ | 63 | #define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */ |
64 | #define IFF_BONDING 0x20 /* bonding master or slave */ | 64 | #define IFF_BONDING 0x20 /* bonding master or slave */ |
65 | #define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ | 65 | #define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ |
66 | #define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */ | ||
66 | 67 | ||
67 | #define IF_GET_IFACE 0x0001 /* for querying only */ | 68 | #define IF_GET_IFACE 0x0001 /* for querying only */ |
68 | #define IF_GET_PROTO 0x0002 | 69 | #define IF_GET_PROTO 0x0002 |
diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 660b5010c2d9..228eb4eb3129 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h | |||
@@ -17,6 +17,9 @@ | |||
17 | #define GRE_FLAGS __constant_htons(0x00F8) | 17 | #define GRE_FLAGS __constant_htons(0x00F8) |
18 | #define GRE_VERSION __constant_htons(0x0007) | 18 | #define GRE_VERSION __constant_htons(0x0007) |
19 | 19 | ||
20 | /* i_flags values for SIT mode */ | ||
21 | #define SIT_ISATAP 0x0001 | ||
22 | |||
20 | struct ip_tunnel_parm | 23 | struct ip_tunnel_parm |
21 | { | 24 | { |
22 | char name[IFNAMSIZ]; | 25 | char name[IFNAMSIZ]; |
diff --git a/include/linux/in.h b/include/linux/in.h index 3975cbf52f20..a8f00cac8f79 100644 --- a/include/linux/in.h +++ b/include/linux/in.h | |||
@@ -253,6 +253,14 @@ struct sockaddr_in { | |||
253 | #define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000)) | 253 | #define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000)) |
254 | #define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000)) | 254 | #define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000)) |
255 | 255 | ||
256 | /* Special-Use IPv4 Addresses (RFC3330) */ | ||
257 | #define PRIVATE_10(x) (((x) & htonl(0xff000000)) == htonl(0x0A000000)) | ||
258 | #define LINKLOCAL_169(x) (((x) & htonl(0xffff0000)) == htonl(0xA9FE0000)) | ||
259 | #define PRIVATE_172(x) (((x) & htonl(0xfff00000)) == htonl(0xAC100000)) | ||
260 | #define TEST_192(x) (((x) & htonl(0xffffff00)) == htonl(0xC0000200)) | ||
261 | #define ANYCAST_6TO4(x) (((x) & htonl(0xffffff00)) == htonl(0xC0586300)) | ||
262 | #define PRIVATE_192(x) (((x) & htonl(0xffff0000)) == htonl(0xC0A80000)) | ||
263 | #define TEST_198(x) (((x) & htonl(0xfffe0000)) == htonl(0xC6120000)) | ||
256 | #endif | 264 | #endif |
257 | 265 | ||
258 | #endif /* _LINUX_IN_H */ | 266 | #endif /* _LINUX_IN_H */ |
diff --git a/include/net/addrconf.h b/include/net/addrconf.h index bccc2feb99da..c56827da0dee 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #define IPV6_MAX_ADDRESSES 16 | 18 | #define IPV6_MAX_ADDRESSES 16 |
19 | 19 | ||
20 | #include <linux/in.h> | ||
20 | #include <linux/in6.h> | 21 | #include <linux/in6.h> |
21 | 22 | ||
22 | struct prefix_info { | 23 | struct prefix_info { |
@@ -249,6 +250,24 @@ static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr) | |||
249 | addr->s6_addr32[3] == htonl(0x00000002)); | 250 | addr->s6_addr32[3] == htonl(0x00000002)); |
250 | } | 251 | } |
251 | 252 | ||
253 | static inline int ipv6_isatap_eui64(u8 *eui, __be32 addr) | ||
254 | { | ||
255 | eui[0] = (ZERONET(addr) || PRIVATE_10(addr) || LOOPBACK(addr) || | ||
256 | LINKLOCAL_169(addr) || PRIVATE_172(addr) || TEST_192(addr) || | ||
257 | ANYCAST_6TO4(addr) || PRIVATE_192(addr) || TEST_198(addr) || | ||
258 | MULTICAST(addr) || BADCLASS(addr)) ? 0x00 : 0x02; | ||
259 | eui[1] = 0; | ||
260 | eui[2] = 0x5E; | ||
261 | eui[3] = 0xFE; | ||
262 | memcpy (eui+4, &addr, 4); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static inline int ipv6_addr_is_isatap(const struct in6_addr *addr) | ||
267 | { | ||
268 | return ((addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE)); | ||
269 | } | ||
270 | |||
252 | #ifdef CONFIG_PROC_FS | 271 | #ifdef CONFIG_PROC_FS |
253 | extern int if6_proc_init(void); | 272 | extern int if6_proc_init(void); |
254 | extern void if6_proc_exit(void); | 273 | extern void if6_proc_exit(void); |
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6c8b193474ba..f177424c186f 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
@@ -377,6 +377,13 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) | |||
377 | "%s: Disabled Privacy Extensions\n", | 377 | "%s: Disabled Privacy Extensions\n", |
378 | dev->name); | 378 | dev->name); |
379 | ndev->cnf.use_tempaddr = -1; | 379 | ndev->cnf.use_tempaddr = -1; |
380 | |||
381 | if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { | ||
382 | printk(KERN_INFO | ||
383 | "%s: Disabled Multicast RS\n", | ||
384 | dev->name); | ||
385 | ndev->cnf.rtr_solicits = 0; | ||
386 | } | ||
380 | } else { | 387 | } else { |
381 | in6_dev_hold(ndev); | 388 | in6_dev_hold(ndev); |
382 | ipv6_regen_rndid((unsigned long) ndev); | 389 | ipv6_regen_rndid((unsigned long) ndev); |
@@ -1409,6 +1416,9 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) | |||
1409 | return addrconf_ifid_arcnet(eui, dev); | 1416 | return addrconf_ifid_arcnet(eui, dev); |
1410 | case ARPHRD_INFINIBAND: | 1417 | case ARPHRD_INFINIBAND: |
1411 | return addrconf_ifid_infiniband(eui, dev); | 1418 | return addrconf_ifid_infiniband(eui, dev); |
1419 | case ARPHRD_SIT: | ||
1420 | if (dev->priv_flags & IFF_ISATAP) | ||
1421 | return ipv6_isatap_eui64(eui, *(__be32 *)dev->dev_addr); | ||
1412 | } | 1422 | } |
1413 | return -1; | 1423 | return -1; |
1414 | } | 1424 | } |
@@ -1444,7 +1454,7 @@ regen: | |||
1444 | * | 1454 | * |
1445 | * - Reserved subnet anycast (RFC 2526) | 1455 | * - Reserved subnet anycast (RFC 2526) |
1446 | * 11111101 11....11 1xxxxxxx | 1456 | * 11111101 11....11 1xxxxxxx |
1447 | * - ISATAP (draft-ietf-ngtrans-isatap-13.txt) 5.1 | 1457 | * - ISATAP (RFC4214) 6.1 |
1448 | * 00-00-5E-FE-xx-xx-xx-xx | 1458 | * 00-00-5E-FE-xx-xx-xx-xx |
1449 | * - value 0 | 1459 | * - value 0 |
1450 | * - XXX: already assigned to an address on the device | 1460 | * - XXX: already assigned to an address on the device |
@@ -2175,6 +2185,16 @@ static void addrconf_sit_config(struct net_device *dev) | |||
2175 | return; | 2185 | return; |
2176 | } | 2186 | } |
2177 | 2187 | ||
2188 | if (dev->priv_flags & IFF_ISATAP) { | ||
2189 | struct in6_addr addr; | ||
2190 | |||
2191 | ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); | ||
2192 | addrconf_prefix_route(&addr, 64, dev, 0, 0); | ||
2193 | if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) | ||
2194 | addrconf_add_linklocal(idev, &addr); | ||
2195 | return; | ||
2196 | } | ||
2197 | |||
2178 | sit_add_v4_addrs(idev); | 2198 | sit_add_v4_addrs(idev); |
2179 | 2199 | ||
2180 | if (dev->flags&IFF_POINTOPOINT) { | 2200 | if (dev->flags&IFF_POINTOPOINT) { |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d7ec4c9ffc4b..e2c980dbe52d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1659,6 +1659,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d | |||
1659 | return rt; | 1659 | return rt; |
1660 | } | 1660 | } |
1661 | 1661 | ||
1662 | EXPORT_SYMBOL(rt6_get_dflt_router); | ||
1663 | |||
1662 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, | 1664 | struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, |
1663 | struct net_device *dev, | 1665 | struct net_device *dev, |
1664 | unsigned int pref) | 1666 | unsigned int pref) |
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 | ||