aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFred L. Templin <fred.l.templin@boeing.com>2007-11-29 06:11:40 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:09 -0500
commitc7dc89c0ac8e7c3796bff91becf58ccdbcaf9f18 (patch)
treee876ccadf29a90b7a211522aeccfd42255dab586
parentdf97c708d5e6eebdd9ded1fa588eae09acf53793 (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.h1
-rw-r--r--include/linux/if_tunnel.h3
-rw-r--r--include/linux/in.h8
-rw-r--r--include/net/addrconf.h19
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/sit.c77
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
20struct ip_tunnel_parm 23struct 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
22struct prefix_info { 23struct 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
253static 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
266static 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
253extern int if6_proc_init(void); 272extern int if6_proc_init(void);
254extern void if6_proc_exit(void); 273extern 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
1662EXPORT_SYMBOL(rt6_get_dflt_router);
1663
1662struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, 1664struct 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 */
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