[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>
This commit is contained in:
parent
df97c708d5
commit
c7dc89c0ac
|
@ -63,6 +63,7 @@
|
||||||
#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
|
#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
|
||||||
#define IFF_BONDING 0x20 /* bonding master or slave */
|
#define IFF_BONDING 0x20 /* bonding master or slave */
|
||||||
#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
|
#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
|
||||||
|
#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */
|
||||||
|
|
||||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||||
#define IF_GET_PROTO 0x0002
|
#define IF_GET_PROTO 0x0002
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
#define GRE_FLAGS __constant_htons(0x00F8)
|
#define GRE_FLAGS __constant_htons(0x00F8)
|
||||||
#define GRE_VERSION __constant_htons(0x0007)
|
#define GRE_VERSION __constant_htons(0x0007)
|
||||||
|
|
||||||
|
/* i_flags values for SIT mode */
|
||||||
|
#define SIT_ISATAP 0x0001
|
||||||
|
|
||||||
struct ip_tunnel_parm
|
struct ip_tunnel_parm
|
||||||
{
|
{
|
||||||
char name[IFNAMSIZ];
|
char name[IFNAMSIZ];
|
||||||
|
|
|
@ -253,6 +253,14 @@ struct sockaddr_in {
|
||||||
#define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000))
|
#define ZERONET(x) (((x) & htonl(0xff000000)) == htonl(0x00000000))
|
||||||
#define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000))
|
#define LOCAL_MCAST(x) (((x) & htonl(0xFFFFFF00)) == htonl(0xE0000000))
|
||||||
|
|
||||||
|
/* Special-Use IPv4 Addresses (RFC3330) */
|
||||||
|
#define PRIVATE_10(x) (((x) & htonl(0xff000000)) == htonl(0x0A000000))
|
||||||
|
#define LINKLOCAL_169(x) (((x) & htonl(0xffff0000)) == htonl(0xA9FE0000))
|
||||||
|
#define PRIVATE_172(x) (((x) & htonl(0xfff00000)) == htonl(0xAC100000))
|
||||||
|
#define TEST_192(x) (((x) & htonl(0xffffff00)) == htonl(0xC0000200))
|
||||||
|
#define ANYCAST_6TO4(x) (((x) & htonl(0xffffff00)) == htonl(0xC0586300))
|
||||||
|
#define PRIVATE_192(x) (((x) & htonl(0xffff0000)) == htonl(0xC0A80000))
|
||||||
|
#define TEST_198(x) (((x) & htonl(0xfffe0000)) == htonl(0xC6120000))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _LINUX_IN_H */
|
#endif /* _LINUX_IN_H */
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#define IPV6_MAX_ADDRESSES 16
|
#define IPV6_MAX_ADDRESSES 16
|
||||||
|
|
||||||
|
#include <linux/in.h>
|
||||||
#include <linux/in6.h>
|
#include <linux/in6.h>
|
||||||
|
|
||||||
struct prefix_info {
|
struct prefix_info {
|
||||||
|
@ -249,6 +250,24 @@ static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr)
|
||||||
addr->s6_addr32[3] == htonl(0x00000002));
|
addr->s6_addr32[3] == htonl(0x00000002));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int ipv6_isatap_eui64(u8 *eui, __be32 addr)
|
||||||
|
{
|
||||||
|
eui[0] = (ZERONET(addr) || PRIVATE_10(addr) || LOOPBACK(addr) ||
|
||||||
|
LINKLOCAL_169(addr) || PRIVATE_172(addr) || TEST_192(addr) ||
|
||||||
|
ANYCAST_6TO4(addr) || PRIVATE_192(addr) || TEST_198(addr) ||
|
||||||
|
MULTICAST(addr) || BADCLASS(addr)) ? 0x00 : 0x02;
|
||||||
|
eui[1] = 0;
|
||||||
|
eui[2] = 0x5E;
|
||||||
|
eui[3] = 0xFE;
|
||||||
|
memcpy (eui+4, &addr, 4);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ipv6_addr_is_isatap(const struct in6_addr *addr)
|
||||||
|
{
|
||||||
|
return ((addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
extern int if6_proc_init(void);
|
extern int if6_proc_init(void);
|
||||||
extern void if6_proc_exit(void);
|
extern void if6_proc_exit(void);
|
||||||
|
|
|
@ -377,6 +377,13 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
|
||||||
"%s: Disabled Privacy Extensions\n",
|
"%s: Disabled Privacy Extensions\n",
|
||||||
dev->name);
|
dev->name);
|
||||||
ndev->cnf.use_tempaddr = -1;
|
ndev->cnf.use_tempaddr = -1;
|
||||||
|
|
||||||
|
if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) {
|
||||||
|
printk(KERN_INFO
|
||||||
|
"%s: Disabled Multicast RS\n",
|
||||||
|
dev->name);
|
||||||
|
ndev->cnf.rtr_solicits = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
in6_dev_hold(ndev);
|
in6_dev_hold(ndev);
|
||||||
ipv6_regen_rndid((unsigned long) ndev);
|
ipv6_regen_rndid((unsigned long) ndev);
|
||||||
|
@ -1409,6 +1416,9 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
|
||||||
return addrconf_ifid_arcnet(eui, dev);
|
return addrconf_ifid_arcnet(eui, dev);
|
||||||
case ARPHRD_INFINIBAND:
|
case ARPHRD_INFINIBAND:
|
||||||
return addrconf_ifid_infiniband(eui, dev);
|
return addrconf_ifid_infiniband(eui, dev);
|
||||||
|
case ARPHRD_SIT:
|
||||||
|
if (dev->priv_flags & IFF_ISATAP)
|
||||||
|
return ipv6_isatap_eui64(eui, *(__be32 *)dev->dev_addr);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1444,7 +1454,7 @@ regen:
|
||||||
*
|
*
|
||||||
* - Reserved subnet anycast (RFC 2526)
|
* - Reserved subnet anycast (RFC 2526)
|
||||||
* 11111101 11....11 1xxxxxxx
|
* 11111101 11....11 1xxxxxxx
|
||||||
* - ISATAP (draft-ietf-ngtrans-isatap-13.txt) 5.1
|
* - ISATAP (RFC4214) 6.1
|
||||||
* 00-00-5E-FE-xx-xx-xx-xx
|
* 00-00-5E-FE-xx-xx-xx-xx
|
||||||
* - value 0
|
* - value 0
|
||||||
* - XXX: already assigned to an address on the device
|
* - XXX: already assigned to an address on the device
|
||||||
|
@ -2175,6 +2185,16 @@ static void addrconf_sit_config(struct net_device *dev)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->priv_flags & IFF_ISATAP) {
|
||||||
|
struct in6_addr addr;
|
||||||
|
|
||||||
|
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
|
||||||
|
addrconf_prefix_route(&addr, 64, dev, 0, 0);
|
||||||
|
if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
|
||||||
|
addrconf_add_linklocal(idev, &addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
sit_add_v4_addrs(idev);
|
sit_add_v4_addrs(idev);
|
||||||
|
|
||||||
if (dev->flags&IFF_POINTOPOINT) {
|
if (dev->flags&IFF_POINTOPOINT) {
|
||||||
|
|
|
@ -1659,6 +1659,8 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EXPORT_SYMBOL(rt6_get_dflt_router);
|
||||||
|
|
||||||
struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
|
struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,
|
||||||
struct net_device *dev,
|
struct net_device *dev,
|
||||||
unsigned int pref)
|
unsigned int pref)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* Changes:
|
* Changes:
|
||||||
* Roger Venning <r.venning@telstra.com>: 6to4 support
|
* Roger Venning <r.venning@telstra.com>: 6to4 support
|
||||||
* Nate Thompson <nate@thebog.net>: 6to4 support
|
* Nate Thompson <nate@thebog.net>: 6to4 support
|
||||||
|
* Fred L. Templin <fltemplin@acm.org>: isatap support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
|
@ -182,6 +183,9 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int
|
||||||
dev->init = ipip6_tunnel_init;
|
dev->init = ipip6_tunnel_init;
|
||||||
nt->parms = *parms;
|
nt->parms = *parms;
|
||||||
|
|
||||||
|
if (parms->i_flags & SIT_ISATAP)
|
||||||
|
dev->priv_flags |= IFF_ISATAP;
|
||||||
|
|
||||||
if (register_netdevice(dev) < 0) {
|
if (register_netdevice(dev) < 0) {
|
||||||
free_netdev(dev);
|
free_netdev(dev);
|
||||||
goto failed;
|
goto failed;
|
||||||
|
@ -364,6 +368,48 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb)
|
||||||
IP6_ECN_set_ce(ipv6_hdr(skb));
|
IP6_ECN_set_ce(ipv6_hdr(skb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ISATAP (RFC4214) - check source address */
|
||||||
|
static int
|
||||||
|
isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct neighbour *neigh;
|
||||||
|
struct dst_entry *dst;
|
||||||
|
struct rt6_info *rt;
|
||||||
|
struct flowi fl;
|
||||||
|
struct in6_addr *addr6;
|
||||||
|
struct in6_addr rtr;
|
||||||
|
struct ipv6hdr *iph6;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
/* from onlink default router */
|
||||||
|
ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0);
|
||||||
|
ipv6_isatap_eui64(rtr.s6_addr + 8, iph->saddr);
|
||||||
|
if ((rt = rt6_get_dflt_router(&rtr, dev))) {
|
||||||
|
dst_release(&rt->u.dst);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
iph6 = ipv6_hdr(skb);
|
||||||
|
memset(&fl, 0, sizeof(fl));
|
||||||
|
fl.proto = iph6->nexthdr;
|
||||||
|
ipv6_addr_copy(&fl.fl6_dst, &iph6->saddr);
|
||||||
|
fl.oif = dev->ifindex;
|
||||||
|
security_skb_classify_flow(skb, &fl);
|
||||||
|
|
||||||
|
dst = ip6_route_output(NULL, &fl);
|
||||||
|
if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) {
|
||||||
|
|
||||||
|
addr6 = (struct in6_addr*)&neigh->primary_key;
|
||||||
|
|
||||||
|
/* from correct previous hop */
|
||||||
|
if (ipv6_addr_is_isatap(addr6) &&
|
||||||
|
(addr6->s6_addr32[3] == iph->saddr))
|
||||||
|
ok = 1;
|
||||||
|
}
|
||||||
|
dst_release(dst);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
static int ipip6_rcv(struct sk_buff *skb)
|
static int ipip6_rcv(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct iphdr *iph;
|
struct iphdr *iph;
|
||||||
|
@ -382,6 +428,14 @@ static int ipip6_rcv(struct sk_buff *skb)
|
||||||
IPCB(skb)->flags = 0;
|
IPCB(skb)->flags = 0;
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
skb->protocol = htons(ETH_P_IPV6);
|
||||||
skb->pkt_type = PACKET_HOST;
|
skb->pkt_type = PACKET_HOST;
|
||||||
|
|
||||||
|
if ((tunnel->dev->priv_flags & IFF_ISATAP) &&
|
||||||
|
!isatap_srcok(skb, iph, tunnel->dev)) {
|
||||||
|
tunnel->stat.rx_errors++;
|
||||||
|
read_unlock(&ipip6_lock);
|
||||||
|
kfree_skb(skb);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
tunnel->stat.rx_packets++;
|
tunnel->stat.rx_packets++;
|
||||||
tunnel->stat.rx_bytes += skb->len;
|
tunnel->stat.rx_bytes += skb->len;
|
||||||
skb->dev = tunnel->dev;
|
skb->dev = tunnel->dev;
|
||||||
|
@ -444,6 +498,29 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||||
if (skb->protocol != htons(ETH_P_IPV6))
|
if (skb->protocol != htons(ETH_P_IPV6))
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
|
|
||||||
|
/* ISATAP (RFC4214) - must come before 6to4 */
|
||||||
|
if (dev->priv_flags & IFF_ISATAP) {
|
||||||
|
struct neighbour *neigh = NULL;
|
||||||
|
|
||||||
|
if (skb->dst)
|
||||||
|
neigh = skb->dst->neighbour;
|
||||||
|
|
||||||
|
if (neigh == NULL) {
|
||||||
|
if (net_ratelimit())
|
||||||
|
printk(KERN_DEBUG "sit: nexthop == NULL\n");
|
||||||
|
goto tx_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr6 = (struct in6_addr*)&neigh->primary_key;
|
||||||
|
addr_type = ipv6_addr_type(addr6);
|
||||||
|
|
||||||
|
if ((addr_type & IPV6_ADDR_UNICAST) &&
|
||||||
|
ipv6_addr_is_isatap(addr6))
|
||||||
|
dst = addr6->s6_addr32[3];
|
||||||
|
else
|
||||||
|
goto tx_error;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dst)
|
if (!dst)
|
||||||
dst = try_6to4(&iph6->daddr);
|
dst = try_6to4(&iph6->daddr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue