* [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
[not found] <20030424132559.GA15894@morphine.tml.hut.fi>
@ 2003-05-30 14:34 ` Ville Nuorvala
2003-05-30 15:00 ` [patch]: ipv6 tunnel " Ville Nuorvala
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
0 siblings, 2 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-05-30 14:34 UTC (permalink / raw)
To: David S. Miller, kuznet, yoshfuji, netdev
Cc: Antti Tuominen, Lars Henrik Petander, jagana, kumarkr
[-- Attachment #1: Type: TEXT/PLAIN, Size: 565 bytes --]
Hi guys,
here is a patch that fixes CONFIG_IPV6_SUBTREES and allows overriding
normal routes with source address specific ones. This is for example
needed in MIPv6 for handling the traffic to and from a mobile node's home
address correctly.
The patch is sent as an attachment to this mail but is also available at:
http://www.mipl.mediapoli.com/patches/source-routing.patch
Regards,
Ville Nuorvala
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
[-- Attachment #2: Type: TEXT/PLAIN, Size: 18718 bytes --]
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/ipv6.h merge-2.5/include/linux/ipv6.h
--- linux-2.5/include/linux/ipv6.h Wed May 28 20:07:22 2003
+++ merge-2.5/include/linux/ipv6.h Wed May 28 19:51:18 2003
@@ -150,7 +150,9 @@
struct in6_addr rcv_saddr;
struct in6_addr daddr;
struct in6_addr *daddr_cache;
-
+#ifdef CONFIG_IPV6_SUBTREES
+ struct in6_addr *saddr_cache;
+#endif
__u32 flow_label;
__u32 frag_size;
int hop_limit;
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/net/ip6_route.h merge-2.5/include/net/ip6_route.h
--- linux-2.5/include/net/ip6_route.h Wed May 28 20:07:29 2003
+++ merge-2.5/include/net/ip6_route.h Wed May 28 19:51:19 2003
@@ -102,7 +102,8 @@
*/
static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
- struct in6_addr *daddr)
+ struct in6_addr *daddr,
+ struct in6_addr *saddr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
struct rt6_info *rt = (struct rt6_info *) dst;
@@ -110,6 +111,9 @@
write_lock(&sk->dst_lock);
__sk_dst_set(sk, dst);
np->daddr_cache = daddr;
+#ifdef CONFIG_IPV6_SUBTREES
+ np->saddr_cache = saddr;
+#endif
np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
write_unlock(&sk->dst_lock);
}
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Kconfig merge-2.5/net/ipv6/Kconfig
--- linux-2.5/net/ipv6/Kconfig Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/Kconfig Wed May 28 19:51:20 2003
@@ -42,4 +42,12 @@
If unsure, say Y.
+config IPV6_SUBTREES
+ bool "IPv6: Source address routing"
+ depends on IPV6
+ ---help---
+ Support for advanced routing by both source and destination address.
+
+ If unsure, say N.
+
source "net/ipv6/netfilter/Kconfig"
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ip6_fib.c merge-2.5/net/ipv6/ip6_fib.c
--- linux-2.5/net/ipv6/ip6_fib.c Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/ip6_fib.c Wed May 28 19:51:22 2003
@@ -18,6 +18,7 @@
* Yuji SEKIYA @USAGI: Support default route on router node;
* remove ip6_null_entry from the top of
* routing table.
+ * Ville Nuorvala: Fixes to source address based routing
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -40,7 +41,6 @@
#include <net/ip6_route.h>
#define RT6_DEBUG 2
-#undef CONFIG_IPV6_SUBTREES
#if RT6_DEBUG >= 3
#define RT6_TRACE(x...) printk(KERN_DEBUG x)
@@ -84,6 +84,10 @@
static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
+#ifdef CONFIG_IPV6_SUBTREES
+static struct in6_addr fib6_addr_any = IN6ADDR_ANY_INIT;
+#endif
+
/*
* A routing update causes an increase of the serial number on the
* afected subtree. This allows for cached routes to be asynchronously
@@ -497,6 +501,8 @@
mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
}
+static struct rt6_info * fib6_find_prefix(struct fib6_node *fn);
+
/*
* Add routing information to the routing tree.
* <destination addr>/<source addr>
@@ -508,14 +514,16 @@
struct fib6_node *fn;
int err = -ENOMEM;
- fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
- rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
+#ifdef CONFIG_IPV6_SUBTREES
+ struct fib6_node *pn = NULL;
+ fn = fib6_add_1(root, &rt->rt6i_src.addr, sizeof(struct in6_addr),
+ rt->rt6i_src.plen, (u8*) &rt->rt6i_src - (u8*) rt);
+
if (fn == NULL)
goto out;
-#ifdef CONFIG_IPV6_SUBTREES
- if (rt->rt6i_src.plen) {
+ if (rt->rt6i_dst.plen) {
struct fib6_node *sn;
if (fn->subtree == NULL) {
@@ -543,9 +551,9 @@
/* Now add the first leaf node to new subtree */
- sn = fib6_add_1(sfn, &rt->rt6i_src.addr,
- sizeof(struct in6_addr), rt->rt6i_src.plen,
- (u8*) &rt->rt6i_src - (u8*) rt);
+ sn = fib6_add_1(sfn, &rt->rt6i_dst.addr,
+ sizeof(struct in6_addr), rt->rt6i_dst.plen,
+ (u8*) &rt->rt6i_dst - (u8*) rt);
if (sn == NULL) {
/* If it is failed, discard just allocated
@@ -559,21 +567,30 @@
/* Now link new subtree to main tree */
sfn->parent = fn;
fn->subtree = sfn;
- if (fn->leaf == NULL) {
- fn->leaf = rt;
- atomic_inc(&rt->rt6i_ref);
- }
} else {
- sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr,
- sizeof(struct in6_addr), rt->rt6i_src.plen,
- (u8*) &rt->rt6i_src - (u8*) rt);
+ sn = fib6_add_1(fn->subtree, &rt->rt6i_dst.addr,
+ sizeof(struct in6_addr), rt->rt6i_dst.plen,
+ (u8*) &rt->rt6i_dst - (u8*) rt);
if (sn == NULL)
goto st_failure;
}
+ /* fib6_add_1 might have cleared the old leaf pointer */
+ if (fn->leaf == NULL) {
+ fn->leaf = rt;
+ atomic_inc(&rt->rt6i_ref);
+ }
+
+ pn = fn;
fn = sn;
}
+#else
+ fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr),
+ rt->rt6i_dst.plen, (u8*) &rt->rt6i_dst - (u8*) rt);
+
+ if (fn == NULL)
+ goto out;
#endif
err = fib6_add_rt2node(fn, rt, nlh);
@@ -585,8 +602,25 @@
}
out:
- if (err)
+ if (err) {
+#ifdef CONFIG_IPV6_SUBTREES
+
+ /* If fib6_add_1 has cleared the old leaf pointer in the
+ super-tree leaf node we have to find a new one for it. */
+
+ if (pn && !(pn->fn_flags & RTN_RTINFO)) {
+ pn->leaf = fib6_find_prefix(pn);
+#if RT6_DEBUG >= 2
+ if (!pn->leaf) {
+ BUG_TRAP(pn->leaf);
+ pn->leaf = &ip6_null_entry;
+ }
+#endif
+ atomic_inc(&pn->leaf->rt6i_ref);
+ }
+#endif
dst_free(&rt->u.dst);
+ }
return err;
#ifdef CONFIG_IPV6_SUBTREES
@@ -594,8 +628,8 @@
is orphan. If it is, shoot it.
*/
st_failure:
- if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
- fib_repair_tree(fn);
+ if (fn && !(fn->fn_flags &(RTN_RTINFO|RTN_ROOT)))
+ fib6_repair_tree(fn);
dst_free(&rt->u.dst);
return err;
#endif
@@ -638,22 +672,28 @@
break;
}
- while ((fn->fn_flags & RTN_ROOT) == 0) {
+ for (;;) {
#ifdef CONFIG_IPV6_SUBTREES
if (fn->subtree) {
- struct fib6_node *st;
- struct lookup_args *narg;
-
- narg = args + 1;
-
- if (narg->addr) {
- st = fib6_lookup_1(fn->subtree, narg);
+ struct rt6key *key;
- if (st && !(st->fn_flags & RTN_ROOT))
- return st;
+ key = (struct rt6key *) ((u8 *) fn->leaf +
+ args->offset);
+
+ if (addr_match(&key->addr, args->addr, key->plen)) {
+ struct fib6_node *st;
+ struct lookup_args *narg = args + 1;
+ if (!ipv6_addr_any(narg->addr)) {
+ st = fib6_lookup_1(fn->subtree, narg);
+
+ if (st && !(st->fn_flags & RTN_ROOT))
+ return st;
+ }
}
}
#endif
+ if (fn->fn_flags & RTN_ROOT)
+ break;
if (fn->fn_flags & RTN_RTINFO) {
struct rt6key *key;
@@ -677,13 +717,17 @@
struct lookup_args args[2];
struct rt6_info *rt = NULL;
struct fib6_node *fn;
+#ifdef CONFIG_IPV6_SUBTREES
+ if (saddr == NULL)
+ saddr = &fib6_addr_any;
+ args[0].offset = (u8*) &rt->rt6i_src - (u8*) rt;
+ args[0].addr = saddr;
+ args[1].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
+ args[1].addr = daddr;
+#else
args[0].offset = (u8*) &rt->rt6i_dst - (u8*) rt;
args[0].addr = daddr;
-
-#ifdef CONFIG_IPV6_SUBTREES
- args[1].offset = (u8*) &rt->rt6i_src - (u8*) rt;
- args[1].addr = saddr;
#endif
fn = fib6_lookup_1(root, args);
@@ -736,19 +780,22 @@
{
struct rt6_info *rt = NULL;
struct fib6_node *fn;
-
- fn = fib6_locate_1(root, daddr, dst_len,
- (u8*) &rt->rt6i_dst - (u8*) rt);
-
#ifdef CONFIG_IPV6_SUBTREES
- if (src_len) {
- BUG_TRAP(saddr!=NULL);
- if (fn == NULL)
- fn = fn->subtree;
+ if (saddr == NULL)
+ saddr = &fib6_addr_any;
+
+ fn = fib6_locate_1(root, saddr, src_len,
+ (u8*) &rt->rt6i_src - (u8*) rt);
+ if (dst_len) {
if (fn)
- fn = fib6_locate_1(fn, saddr, src_len,
- (u8*) &rt->rt6i_src - (u8*) rt);
+ fn = fib6_locate_1(fn->subtree, daddr, dst_len,
+ (u8*) &rt->rt6i_dst - (u8*) rt);
+ else
+ return NULL;
}
+#else
+ fn = fib6_locate_1(root, daddr, dst_len,
+ (u8*) &rt->rt6i_dst - (u8*) rt);
#endif
if (fn && fn->fn_flags&RTN_RTINFO)
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ip6_output.c merge-2.5/net/ipv6/ip6_output.c
--- linux-2.5/net/ipv6/ip6_output.c Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/ip6_output.c Wed May 28 19:51:23 2003
@@ -527,6 +527,7 @@
struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr final_dst_buf, *final_dst = NULL;
struct dst_entry *dst;
+ struct rt6_info *rt;
int err = 0;
unsigned int pktlength, jumbolen, mtu;
@@ -542,11 +543,11 @@
dst = __sk_dst_check(sk, np->dst_cookie);
if (dst) {
- struct rt6_info *rt = (struct rt6_info*)dst;
+ rt = (struct rt6_info*)dst;
/* Yes, checking route validity in not connected
case is not very simple. Take into account,
- that we do not support routing by source, TOS,
+ that we do not support routing by TOS,
and MSG_DONTROUTE --ANK (980726)
1. If route was host route, check that
@@ -566,6 +567,13 @@
ipv6_addr_cmp(&fl->fl6_dst, &rt->rt6i_dst.addr))
&& (np->daddr_cache == NULL ||
ipv6_addr_cmp(&fl->fl6_dst, np->daddr_cache)))
+#ifdef CONFIG_IPV6_SUBTREES
+ || (!ipv6_addr_any(&fl->fl6_src)
+ && (rt->rt6i_src.plen != 128 ||
+ ipv6_addr_cmp(&fl->fl6_src, &rt->rt6i_src.addr))
+ && (np->saddr_cache == NULL ||
+ ipv6_addr_cmp(&fl->fl6_src, np->saddr_cache)))
+#endif
|| (fl->oif && fl->oif != dst->dev->ifindex)) {
dst = NULL;
} else
@@ -592,6 +600,20 @@
goto out;
}
}
+#ifdef CONFIG_IPV6_SUBTREES
+ rt = (struct rt6_info*)dst;
+ if (ipv6_addr_cmp(&fl->fl6_src, &np->saddr) &&
+ (rt->rt6i_src.plen != 128 ||
+ ipv6_addr_cmp(&fl->fl6_src, &rt->rt6i_src.addr))) {
+ dst_release(dst);
+ dst = ip6_route_output(sk, fl);
+ if (dst->error) {
+ IP6_INC_STATS(Ip6OutNoRoutes);
+ dst_release(dst);
+ return -ENETUNREACH;
+ }
+ }
+#endif
pktlength = length;
if (dst) {
@@ -715,7 +737,9 @@
out:
ip6_dst_store(sk, dst,
!ipv6_addr_cmp(&fl->fl6_dst, &np->daddr) ?
- &np->daddr : NULL);
+ &np->daddr : NULL,
+ !ipv6_addr_cmp(&fl->fl6_src, &np->saddr) ?
+ &np->saddr : NULL);
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
return err;
@@ -1138,15 +1162,16 @@
int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
{
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct rt6_info *rt;
int err = 0;
*dst = __sk_dst_check(sk, np->dst_cookie);
if (*dst) {
- struct rt6_info *rt = (struct rt6_info*)*dst;
+ rt = (struct rt6_info*)*dst;
/* Yes, checking route validity in not connected
case is not very simple. Take into account,
- that we do not support routing by source, TOS,
+ that we do not support routing by TOS,
and MSG_DONTROUTE --ANK (980726)
1. If route was host route, check that
@@ -1166,6 +1191,13 @@
ipv6_addr_cmp(&fl->fl6_dst, &rt->rt6i_dst.addr))
&& (np->daddr_cache == NULL ||
ipv6_addr_cmp(&fl->fl6_dst, np->daddr_cache)))
+#ifdef CONFIG_IPV6_SUBTREES
+ || (!ipv6_addr_any(&fl->fl6_src)
+ && (rt->rt6i_src.plen != 128 ||
+ ipv6_addr_cmp(&fl->fl6_src, &rt->rt6i_src.addr))
+ && (np->saddr_cache == NULL ||
+ ipv6_addr_cmp(&fl->fl6_src, np->saddr_cache)))
+#endif
|| (fl->oif && fl->oif != (*dst)->dev->ifindex)) {
*dst = NULL;
} else
@@ -1192,7 +1224,20 @@
return err;
}
}
-
+#ifdef CONFIG_IPV6_SUBTREES
+ rt = (struct rt6_info*)*dst;
+ if (ipv6_addr_cmp(&fl->fl6_src, &np->saddr) &&
+ (rt->rt6i_src.plen != 128 ||
+ ipv6_addr_cmp(&fl->fl6_src, &rt->rt6i_src.addr))) {
+ dst_release(*dst);
+ *dst = ip6_route_output(sk, fl);
+ if ((*dst)->error) {
+ IP6_INC_STATS(Ip6OutNoRoutes);
+ dst_release(*dst);
+ return -ENETUNREACH;
+ }
+ }
+#endif
if (*dst) {
if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) {
dst_release(*dst);
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/raw.c merge-2.5/net/ipv6/raw.c
--- linux-2.5/net/ipv6/raw.c Wed May 28 20:07:42 2003
+++ merge-2.5/net/ipv6/raw.c Wed May 28 19:51:24 2003
@@ -700,7 +700,9 @@
done:
ip6_dst_store(sk, dst,
!ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ?
- &np->daddr : NULL);
+ &np->daddr : NULL,
+ !ipv6_addr_cmp(&fl.fl6_src, &np->saddr) ?
+ &np->saddr : NULL);
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/route.c merge-2.5/net/ipv6/route.c
--- linux-2.5/net/ipv6/route.c Wed May 28 20:07:42 2003
+++ merge-2.5/net/ipv6/route.c Wed May 28 19:51:25 2003
@@ -361,12 +361,8 @@
rt->u.dst.flags |= DST_HOST;
#ifdef CONFIG_IPV6_SUBTREES
- if (rt->rt6i_src.plen && saddr) {
- ipv6_addr_copy(&rt->rt6i_src.addr, saddr);
- rt->rt6i_src.plen = 128;
- }
+ rt->rt6i_src.plen = ort->rt6i_src.plen;
#endif
-
rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);
dst_hold(&rt->u.dst);
@@ -883,7 +879,7 @@
struct rt6_info *rt, *nrt;
/* Locate old route to this destination. */
- rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);
+ rt = rt6_lookup(dest, saddr, neigh->dev->ifindex, 1);
if (rt == NULL)
return;
@@ -1050,6 +1046,9 @@
nrt = ip6_rt_copy(rt);
if (nrt == NULL)
goto out;
+#ifdef CONFIG_IPV6_SUBTREES
+ nrt->rt6i_src.plen = rt->rt6i_src.plen;
+#endif
ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);
nrt->rt6i_dst.plen = 128;
nrt->u.dst.flags |= DST_HOST;
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/tcp_ipv6.c merge-2.5/net/ipv6/tcp_ipv6.c
--- linux-2.5/net/ipv6/tcp_ipv6.c Wed May 28 20:07:42 2003
+++ merge-2.5/net/ipv6/tcp_ipv6.c Wed May 28 19:51:25 2003
@@ -563,10 +563,10 @@
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_opt *tp = tcp_sk(sk);
struct in6_addr *saddr = NULL;
- struct in6_addr saddr_buf;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
+ int reroute = 0;
int err;
if (addr_len < SIN6_LEN_RFC2133)
@@ -685,24 +685,40 @@
dst = ip6_route_output(sk, &fl);
+#ifdef CONFIG_IPV6_SUBTREES
+ reroute = (saddr == NULL);
+#endif
if ((err = dst->error) != 0) {
dst_release(dst);
goto failure;
}
-
- ip6_dst_store(sk, dst, NULL);
- sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO);
-
+ if (!reroute) {
+ ip6_dst_store(sk, dst, NULL, NULL);
+ sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO);
+ }
if (saddr == NULL) {
- err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf);
+ err = ipv6_get_saddr(dst, &np->daddr, &fl.fl6_src);
+
+ if (reroute)
+ dst_release(dst);
if (err)
goto failure;
- saddr = &saddr_buf;
+#ifdef CONFIG_IPV6_SUBTREES
+ dst = ip6_route_output(sk, &fl);
+
+ if ((err = dst->error) != 0) {
+ dst_release(dst);
+ goto failure;
+ }
+ ip6_dst_store(sk, dst, NULL, NULL);
+ sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO);
+#endif
+ saddr = &fl.fl6_src;
+ ipv6_addr_copy(&np->rcv_saddr, saddr);
}
/* set the source address */
- ipv6_addr_copy(&np->rcv_saddr, saddr);
ipv6_addr_copy(&np->saddr, saddr);
inet->rcv_saddr = LOOPBACK4_IPV6;
@@ -1363,7 +1379,7 @@
atomic_inc(&inet6_sock_nr);
#endif
- ip6_dst_store(newsk, dst, NULL);
+ ip6_dst_store(newsk, dst, NULL, NULL);
sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO);
newtcp6sk = (struct tcp6_sock *)newsk;
@@ -1754,7 +1770,7 @@
return err;
}
- ip6_dst_store(sk, dst, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO);
}
@@ -1795,7 +1811,7 @@
return -sk->err_soft;
}
- ip6_dst_store(sk, dst, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
}
skb->dst = dst_clone(dst);
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/udp.c merge-2.5/net/ipv6/udp.c
--- linux-2.5/net/ipv6/udp.c Wed May 28 20:07:42 2003
+++ merge-2.5/net/ipv6/udp.c Wed May 28 19:54:09 2003
@@ -254,12 +254,12 @@
struct inet_opt *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct in6_addr *daddr;
- struct in6_addr saddr;
struct dst_entry *dst;
struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL;
int addr_type;
int err;
+ int reroute = 0;
if (usin->sin6_family == AF_INET) {
if (__ipv6_only_sock(sk))
@@ -355,7 +355,6 @@
fl.proto = IPPROTO_UDP;
ipv6_addr_copy(&fl.fl6_dst, &np->daddr);
- ipv6_addr_copy(&fl.fl6_src, &saddr);
fl.oif = sk->bound_dev_if;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
@@ -380,21 +379,37 @@
fl6_sock_release(flowlabel);
return err;
}
-
- ip6_dst_store(sk, dst, &fl.fl6_dst);
-
+#if CONFIG_IPV6_SUBTREES
+ reroute = 1;
+#endif
/* get the source address used in the appropriate device */
- err = ipv6_get_saddr(dst, daddr, &saddr);
+ err = ipv6_get_saddr(dst, daddr, &fl.fl6_src);
+
+ if (reroute)
+ dst_release(dst);
if (err == 0) {
+#ifdef CONFIG_IPV6_SUBTREES
+ if (reroute) {
+ dst = ip6_route_output(sk, &fl);
+ if ((err = dst->error) != 0) {
+ dst_release(dst);
+ fl6_sock_release(flowlabel);
+ return err;
+ }
+ }
+#endif
if (ipv6_addr_any(&np->saddr))
- ipv6_addr_copy(&np->saddr, &saddr);
+ ipv6_addr_copy(&np->saddr, &fl.fl6_src);
if (ipv6_addr_any(&np->rcv_saddr)) {
- ipv6_addr_copy(&np->rcv_saddr, &saddr);
+ ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src);
inet->rcv_saddr = LOOPBACK4_IPV6;
}
+ ip6_dst_store(sk, dst, &np->daddr,
+ !ipv6_addr_cmp(&fl.fl6_src, &np->saddr) ?
+ &np->saddr : NULL);
sk->state = TCP_ESTABLISHED;
}
fl6_sock_release(flowlabel);
@@ -1003,7 +1018,9 @@
ip6_dst_store(sk, dst,
!ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ?
- &np->daddr : NULL);
+ &np->daddr : NULL,
+ !ipv6_addr_cmp(&fl.fl6_src, &np->saddr) ?
+ &np->saddr : NULL);
if (err > 0)
err = np->recverr ? net_xmit_errno(err) : 0;
release_sock(sk);
^ permalink raw reply [flat|nested] 37+ messages in thread
* [patch]: ipv6 tunnel for MIPv6
2003-05-30 14:34 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 Ville Nuorvala
@ 2003-05-30 15:00 ` Ville Nuorvala
2003-05-30 15:38 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 4:34 ` David S. Miller
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
1 sibling, 2 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-05-30 15:00 UTC (permalink / raw)
To: David S. Miller, kuznet, yoshfuji, netdev
Cc: Antti Tuominen, Lars Henrik Petander, jagana, kumarkr
[-- Attachment #1: Type: TEXT/PLAIN, Size: 946 bytes --]
Hi again guys,
there was a while ago some talk about an xfrm6_tunnel driver IIRC. I don't
know how far along the project is and what capabilities the xfrm6_tunnels
will have, but in the mean time I have an ipv6-in-ipv6 tunnel driver
specified in RFC 2473 to offer you. If the xfrm6_tunnels are going to
support ipv6-in-ipv6 you also might find the code useful.
The tunnels are needed by MIPv6 for encapsulation and decapsulation of
tunneled packets between the home agent and mobile node. Some proctocols
like DHCP are also run over the virtual link between the MN and the home
network according to the MIPv6 specification.
The patch is sent as an attachment to this mail, but is also available at:
http://www.mipl.mediapoli.com/patches/ip6-tunnel.patch
Regards,
Ville Nuorvala
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
[-- Attachment #2: Type: TEXT/PLAIN, Size: 39847 bytes --]
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/if_arp.h merge-2.5/include/linux/if_arp.h
--- linux-2.5/include/linux/if_arp.h Wed May 28 20:07:22 2003
+++ merge-2.5/include/linux/if_arp.h Wed May 28 21:11:43 2003
@@ -60,7 +60,7 @@
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
-#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
+#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
#define ARPHRD_SKIP 771 /* SKIP vif */
#define ARPHRD_LOOPBACK 772 /* Loopback device */
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/ip6_tunnel.h merge-2.5/include/linux/ip6_tunnel.h
--- linux-2.5/include/linux/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/linux/ip6_tunnel.h Wed May 28 21:11:43 2003
@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ */
+
+#ifndef _IP6_TUNNEL_H
+#define _IP6_TUNNEL_H
+
+#define IPV6_TLV_TNL_ENCAP_LIMIT 4
+#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
+
+/* don't add encapsulation limit if one isn't present in inner packet */
+#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
+/* copy the traffic class field from the inner packet */
+#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
+/* copy the flowlabel from the inner packet */
+#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
+/* being used for Mobile IPv6 */
+#define IP6_TNL_F_MIP6_DEV 0x8
+
+struct ip6_tnl_parm {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __u32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+};
+
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/net/ip6_tunnel.h merge-2.5/include/net/ip6_tunnel.h
--- linux-2.5/include/net/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/net/ip6_tunnel.h Wed May 28 21:11:43 2003
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ */
+
+#ifndef _NET_IP6_TUNNEL_H
+#define _NET_IP6_TUNNEL_H
+
+#include <linux/ipv6.h>
+#include <linux/netdevice.h>
+#include <linux/ip6_tunnel.h>
+
+/* capable of sending packets */
+#define IP6_TNL_F_CAP_XMIT 0x10000
+/* capable of receiving packets */
+#define IP6_TNL_F_CAP_RCV 0x20000
+
+#define IP6_TNL_MAX 128
+
+/* IPv6 tunnel */
+
+struct ip6_tnl {
+ struct ip6_tnl *next; /* next tunnel in list */
+ struct net_device *dev; /* virtual device associated with tunnel */
+ struct net_device_stats stat; /* statistics for tunnel device */
+ int recursion; /* depth of hard_start_xmit recursion */
+ struct ip6_tnl_parm parms; /* tunnel configuration paramters */
+ struct flowi fl; /* flowi template for xmit */
+};
+
+/* Tunnel encapsulation limit destination sub-option */
+
+struct ipv6_tlv_tnl_enc_lim {
+ __u8 type; /* type-code for option */
+ __u8 length; /* option length */
+ __u8 encap_limit; /* tunnel encapsulation limit */
+} __attribute__ ((packed));
+
+#ifdef __KERNEL__
+#ifdef CONFIG_IPV6_TUNNEL
+extern int __init ip6_tunnel_init(void);
+extern void ip6_tunnel_cleanup(void);
+#endif
+#endif
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Kconfig merge-2.5/net/ipv6/Kconfig
--- linux-2.5/net/ipv6/Kconfig Wed May 28 21:11:06 2003
+++ merge-2.5/net/ipv6/Kconfig Wed May 28 21:11:43 2003
@@ -50,4 +50,12 @@
If unsure, say N.
+config IPV6_TUNNEL
+ tristate "IPv6: IPv6-in-IPv6 tunnel"
+ depends on IPV6
+ ---help---
+ Support for IPv6-in-IPv6 tunnels described in RFC 2473.
+
+ If unsure, say N.
+
source "net/ipv6/netfilter/Kconfig"
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Makefile merge-2.5/net/ipv6/Makefile
--- linux-2.5/net/ipv6/Makefile Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/Makefile Wed May 28 21:11:59 2003
@@ -15,3 +15,5 @@
obj-$(CONFIG_INET6_ESP) += esp6.o
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
obj-$(CONFIG_NETFILTER) += netfilter/
+
+obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/af_inet6.c merge-2.5/net/ipv6/af_inet6.c
--- linux-2.5/net/ipv6/af_inet6.c Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/af_inet6.c Wed May 28 21:13:08 2003
@@ -57,6 +57,9 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#if CONFIG_IPV6_TUNNEL
+#include <net/ip6_tunnel.h>
+#endif
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -780,6 +783,11 @@
err = ndisc_init(&inet6_family_ops);
if (err)
goto ndisc_fail;
+#ifdef CONFIG_IPV6_TUNNEL
+ err = ip6_tunnel_init();
+ if (err)
+ goto ip6_tunnel_fail;
+#endif
err = igmp6_init(&inet6_family_ops);
if (err)
goto igmp_fail;
@@ -834,6 +842,10 @@
igmp6_cleanup();
#endif
igmp_fail:
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+ip6_tunnel_fail:
+#endif
ndisc_cleanup();
ndisc_fail:
icmpv6_cleanup();
@@ -869,6 +881,9 @@
ip6_route_cleanup();
ipv6_packet_cleanup();
igmp6_cleanup();
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+#endif
ndisc_cleanup();
icmpv6_cleanup();
#ifdef CONFIG_SYSCTL
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ip6_tunnel.c merge-2.5/net/ipv6/ip6_tunnel.c
--- linux-2.5/net/ipv6/ip6_tunnel.c Thu Jan 1 02:00:00 1970
+++ merge-2.5/net/ipv6/ip6_tunnel.c Wed May 28 21:12:01 2003
@@ -0,0 +1,1268 @@
+/*
+ * IPv6 over IPv6 tunnel device
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Ville Nuorvala <vnuorval@tcs.hut.fi>
+ *
+ * $Id$
+ *
+ * Based on:
+ * linux/net/ipv6/sit.c
+ *
+ * RFC 2473
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/icmpv6.h>
+#include <linux/init.h>
+#include <linux/route.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip6_tunnel.h>
+
+#ifdef CONFIG_IPV6_TUNNEL_MODULE
+MODULE_AUTHOR("Ville Nuorvala");
+MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
+MODULE_LICENSE("GPL");
+#endif
+
+#define IPV6_TLV_TEL_DST_SIZE 8
+
+#ifdef IP6_TNL_DEBUG
+#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
+#else
+#define IP6_TNL_TRACE(x...) do {;} while(0)
+#endif
+
+#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+
+/* socket(s) used by ip6ip6_tnl_xmit() for resending packets */
+static struct socket *__ip6_socket[NR_CPUS];
+#define ip6_socket __ip6_socket[smp_processor_id()]
+
+static void ip6_xmit_lock(void)
+{
+ local_bh_disable();
+ if (unlikely(!spin_trylock(&ip6_socket->sk->lock.slock)))
+ BUG();
+}
+
+static void ip6_xmit_unlock(void)
+{
+ spin_unlock_bh(&ip6_socket->sk->lock.slock);
+}
+
+#define HASH_SIZE 32
+
+#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
+ (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
+ (HASH_SIZE - 1))
+
+static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
+static int ip6ip6_tnl_dev_init(struct net_device *dev);
+
+/* the IPv6 tunnel fallback device */
+static struct net_device ip6ip6_fb_tnl_dev = {
+ .name = "ip6tnl0",
+ .init = ip6ip6_fb_tnl_dev_init
+};
+
+/* the IPv6 fallback tunnel */
+static struct ip6_tnl ip6ip6_fb_tnl = {
+ .dev = &ip6ip6_fb_tnl_dev,
+ .parms ={.name = "ip6tnl0", .proto = IPPROTO_IPV6}
+};
+
+/* lists for storing tunnels in use */
+static struct ip6_tnl *tnls_r_l[HASH_SIZE];
+static struct ip6_tnl *tnls_wc[1];
+static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
+
+/* lock for the tunnel lists */
+static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ * @remote: the address of the tunnel exit-point
+ * @local: the address of the tunnel entry-point
+ *
+ * Return:
+ * tunnel matching given end-points if found,
+ * else fallback tunnel if its device is up,
+ * else %NULL
+ **/
+
+struct ip6_tnl *
+ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
+{
+ unsigned h0 = HASH(remote);
+ unsigned h1 = HASH(local);
+ struct ip6_tnl *t;
+
+ for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+ if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
+ return t;
+
+ return NULL;
+}
+
+/**
+ * ip6ip6_bucket - get head of list matching given tunnel parameters
+ * @p: parameters containing tunnel end-points
+ *
+ * Description:
+ * ip6ip6_bucket() returns the head of the list matching the
+ * &struct in6_addr entries laddr and raddr in @p.
+ *
+ * Return: head of IPv6 tunnel list
+ **/
+
+static struct ip6_tnl **
+ip6ip6_bucket(struct ip6_tnl_parm *p)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ prio = 1;
+ h = HASH(remote) ^ HASH(local);
+ }
+ return &tnls[prio][h];
+}
+
+/**
+ * ip6ip6_tnl_link - add tunnel to hash table
+ * @t: tunnel to be added
+ **/
+
+static void
+ip6ip6_tnl_link(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
+
+ write_lock_bh(&ip6ip6_lock);
+ t->next = *tp;
+ write_unlock_bh(&ip6ip6_lock);
+ *tp = t;
+}
+
+/**
+ * ip6ip6_tnl_unlink - remove tunnel from hash table
+ * @t: tunnel to be removed
+ **/
+
+static void
+ip6ip6_tnl_unlink(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp;
+
+ for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ write_lock_bh(&ip6ip6_lock);
+ *tp = t->next;
+ write_unlock_bh(&ip6ip6_lock);
+ break;
+ }
+ }
+}
+
+/**
+ * ip6_tnl_create() - create a new tunnel
+ * @p: tunnel parameters
+ * @pt: pointer to new tunnel
+ *
+ * Description:
+ * Create tunnel matching given parameters.
+ *
+ * Return:
+ * 0 on success
+ **/
+
+static int
+ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
+{
+ struct net_device *dev;
+ int err = -ENOBUFS;
+ struct ip6_tnl *t;
+
+ dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
+ if (!dev)
+ return err;
+
+ memset(dev, 0, sizeof (*dev) + sizeof (*t));
+ dev->priv = (void *) (dev + 1);
+ t = (struct ip6_tnl *) dev->priv;
+ t->dev = dev;
+ dev->init = ip6ip6_tnl_dev_init;
+ memcpy(&t->parms, p, sizeof (*p));
+ t->parms.name[IFNAMSIZ - 1] = '\0';
+ if (t->parms.hop_limit > 255)
+ t->parms.hop_limit = -1;
+ strcpy(dev->name, t->parms.name);
+ if (!dev->name[0]) {
+ int i = 0;
+ int exists = 0;
+
+ do {
+ sprintf(dev->name, "ip6tnl%d", ++i);
+ exists = (__dev_get_by_name(dev->name) != NULL);
+ } while (i < IP6_TNL_MAX && exists);
+
+ if (i == IP6_TNL_MAX) {
+ goto failed;
+ }
+ memcpy(t->parms.name, dev->name, IFNAMSIZ);
+ }
+ SET_MODULE_OWNER(dev);
+ if ((err = register_netdevice(dev)) < 0) {
+ goto failed;
+ }
+ ip6ip6_tnl_link(t);
+ *pt = t;
+ return 0;
+failed:
+ kfree(dev);
+ return err;
+}
+
+/**
+ * ip6_tnl_destroy() - destroy old tunnel
+ * @t: tunnel to be destroyed
+ *
+ * Return:
+ * whatever unregister_netdevice() returns
+ **/
+
+static inline int
+ip6_tnl_destroy(struct ip6_tnl *t)
+{
+ return unregister_netdevice(t->dev);
+}
+
+/**
+ * ip6ip6_tnl_locate - find or create tunnel matching given parameters
+ * @p: tunnel parameters
+ * @create: != 0 if allowed to create new tunnel if no match found
+ *
+ * Description:
+ * ip6ip6_tnl_locate() first tries to locate an existing tunnel
+ * based on @parms. If this is unsuccessful, but @create is set a new
+ * tunnel device is created and registered for use.
+ *
+ * Return:
+ * 0 if tunnel located or created,
+ * -EINVAL if parameters incorrect,
+ * -ENODEV if no matching tunnel available
+ **/
+
+static int
+ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ struct ip6_tnl *t;
+
+ if (p->proto != IPPROTO_IPV6)
+ return -EINVAL;
+
+ for (t = *ip6ip6_bucket(p); t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr)) {
+ *pt = t;
+ return (create ? -EEXIST : 0);
+ }
+ }
+ if (!create) {
+ return -ENODEV;
+ }
+ return ip6_tnl_create(p, pt);
+}
+
+/**
+ * ip6ip6_tnl_dev_destructor - tunnel device destructor
+ * @dev: the device to be destroyed
+ **/
+
+static void
+ip6ip6_tnl_dev_destructor(struct net_device *dev)
+{
+ kfree(dev);
+}
+
+/**
+ * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
+ * @dev: the device to be destroyed
+ *
+ * Description:
+ * ip6ip6_tnl_dev_uninit() removes tunnel from its list
+ **/
+
+static void
+ip6ip6_tnl_dev_uninit(struct net_device *dev)
+{
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ write_lock_bh(&ip6ip6_lock);
+ tnls_wc[0] = NULL;
+ write_unlock_bh(&ip6ip6_lock);
+ } else {
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_unlink(t);
+ }
+}
+
+/**
+ * parse_tvl_tnl_enc_lim - handle encapsulation limit option
+ * @skb: received socket buffer
+ *
+ * Return:
+ * 0 if none was found,
+ * else index to encapsulation limit
+ **/
+
+static __u16
+parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
+ __u8 nexthdr = ipv6h->nexthdr;
+ __u16 off = sizeof (*ipv6h);
+
+ while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
+ __u16 optlen = 0;
+ struct ipv6_opt_hdr *hdr;
+ if (raw + off + sizeof (*hdr) > skb->data &&
+ !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+ break;
+
+ hdr = (struct ipv6_opt_hdr *) (raw + off);
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
+ if (frag_hdr->frag_off)
+ break;
+ optlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH) {
+ optlen = (hdr->hdrlen + 2) << 2;
+ } else {
+ optlen = ipv6_optlen(hdr);
+ }
+ if (nexthdr == NEXTHDR_DEST) {
+ __u16 i = off + 2;
+ while (1) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+
+ /* No more room for encapsulation limit */
+ if (i + sizeof (*tel) > off + optlen)
+ break;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+ /* return index of option if found and valid */
+ if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
+ tel->length == 1)
+ return i;
+ /* else jump to next option */
+ if (tel->type)
+ i += tel->length + 2;
+ else
+ i++;
+ }
+ }
+ nexthdr = hdr->nexthdr;
+ off += optlen;
+ }
+ return 0;
+}
+
+/**
+ * ip6ip6_err - tunnel error handler
+ *
+ * Description:
+ * ip6ip6_err() should handle errors in the tunnel according
+ * to the specifications in RFC 2473.
+ **/
+
+void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
+ struct ip6_tnl *t;
+ int rel_msg = 0;
+ int rel_type = ICMPV6_DEST_UNREACH;
+ int rel_code = ICMPV6_ADDR_UNREACH;
+ __u32 rel_info = 0;
+ __u16 len;
+
+ /* If the packet doesn't contain the original IPv6 header we are
+ in trouble since we might need the source address for furter
+ processing of the error. */
+
+ read_lock(&ip6ip6_lock);
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
+ goto out;
+
+ switch (type) {
+ __u32 teli;
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ __u32 mtu;
+ case ICMPV6_DEST_UNREACH:
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Path to destination invalid "
+ "or inactive!\n", t->parms.name);
+ rel_msg = 1;
+ break;
+ case ICMPV6_TIME_EXCEED:
+ if (code == ICMPV6_EXC_HOPLIMIT) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small hop limit or "
+ "routing loop in tunnel!\n",
+ t->parms.name);
+ rel_msg = 1;
+ }
+ break;
+ case ICMPV6_PARAMPROB:
+ /* ignore if parameter problem not caused by a tunnel
+ encapsulation limit sub-option */
+ if (code != ICMPV6_HDR_FIELD) {
+ break;
+ }
+ teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+
+ if (teli && teli == info - 2) {
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
+ if (tel->encap_limit <= 1) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small encapsulation "
+ "limit or routing loop in "
+ "tunnel!\n", t->parms.name);
+ rel_msg = 1;
+ }
+ }
+ break;
+ case ICMPV6_PKT_TOOBIG:
+ mtu = info - offset;
+ if (mtu <= IPV6_MIN_MTU) {
+ mtu = IPV6_MIN_MTU;
+ }
+ t->dev->mtu = mtu;
+
+ if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
+ rel_type = ICMPV6_PKT_TOOBIG;
+ rel_code = 0;
+ rel_info = mtu;
+ rel_msg = 1;
+ }
+ break;
+ }
+ if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
+ struct rt6_info *rt;
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2)
+ goto out;
+
+ dst_release(skb2->dst);
+ skb2->dst = NULL;
+ skb_pull(skb2, offset);
+ skb2->nh.raw = skb2->data;
+
+ /* Try to guess incoming interface */
+ rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
+
+ if (rt && rt->rt6i_dev)
+ skb2->dev = rt->rt6i_dev;
+
+ icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
+
+ if (rt)
+ dst_free(&rt->u.dst);
+
+ kfree_skb(skb2);
+ }
+out:
+ read_unlock(&ip6ip6_lock);
+}
+
+/**
+ * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
+ * @skb: received socket buffer
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+ struct sk_buff *skb = *pskb;
+ struct ipv6hdr *ipv6h;
+ struct ip6_tnl *t;
+
+ if (!pskb_may_pull(skb, sizeof (*ipv6h)))
+ goto discard;
+
+ ipv6h = skb->nh.ipv6h;
+
+ read_lock(&ip6ip6_lock);
+
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
+ if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
+ t->stat.rx_dropped++;
+ read_unlock(&ip6ip6_lock);
+ goto discard;
+ }
+ skb->mac.raw = skb->nh.raw;
+ skb->nh.raw = skb->data;
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->pkt_type = PACKET_HOST;
+ memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+ skb->dev = t->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ t->stat.rx_packets++;
+ t->stat.rx_bytes += skb->len;
+ netif_rx(skb);
+ read_unlock(&ip6ip6_lock);
+ return 0;
+ }
+ read_unlock(&ip6ip6_lock);
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+discard:
+ kfree_skb(skb);
+ return 0;
+}
+
+/**
+ * txopt_len - get necessary size for new &struct ipv6_txoptions
+ * @orig_opt: old options
+ *
+ * Return:
+ * Size of old one plus size of tunnel encapsulation limit option
+ **/
+
+static inline int
+txopt_len(struct ipv6_txoptions *orig_opt)
+{
+ int len = sizeof (*orig_opt) + 8;
+
+ if (orig_opt && orig_opt->dst0opt)
+ len += ipv6_optlen(orig_opt->dst0opt);
+ return len;
+}
+
+/**
+ * merge_options - add encapsulation limit to original options
+ * @encap_limit: number of allowed encapsulation limits
+ * @orig_opt: original options
+ *
+ * Return:
+ * Pointer to new &struct ipv6_txoptions containing the tunnel
+ * encapsulation limit
+ **/
+
+static struct ipv6_txoptions *
+merge_options(struct sock *sk, __u8 encap_limit,
+ struct ipv6_txoptions *orig_opt)
+{
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ struct ipv6_txoptions *opt;
+ __u8 *raw;
+ __u8 pad_to = 8;
+ int opt_len = txopt_len(orig_opt);
+
+ if (!(opt = sock_kmalloc(sk, opt_len, GFP_ATOMIC))) {
+ return NULL;
+ }
+
+ memset(opt, 0, opt_len);
+ opt->tot_len = opt_len;
+ opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
+ opt->opt_nflen = 8;
+
+ raw = (__u8 *) opt->dst0opt;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
+ tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
+ tel->length = 1;
+ tel->encap_limit = encap_limit;
+
+ if (orig_opt) {
+ __u8 *orig_raw;
+
+ opt->hopopt = orig_opt->hopopt;
+
+ /* Keep the original destination options properly
+ aligned and merge possible old paddings to the
+ new padding option */
+ if ((orig_raw = (__u8 *) orig_opt->dst0opt) != NULL) {
+ __u8 type;
+ int i = sizeof (struct ipv6_opt_hdr);
+ pad_to += sizeof (struct ipv6_opt_hdr);
+ while (i < ipv6_optlen(orig_opt->dst0opt)) {
+ type = orig_raw[i++];
+ if (type == IPV6_TLV_PAD0)
+ pad_to++;
+ else if (type == IPV6_TLV_PADN) {
+ int len = orig_raw[i++];
+ i += len;
+ pad_to += len + 2;
+ } else {
+ break;
+ }
+ }
+ opt->dst0opt->hdrlen = orig_opt->dst0opt->hdrlen + 1;
+ memcpy(raw + pad_to, orig_raw + pad_to - 8,
+ opt_len - sizeof (*opt) - pad_to);
+ }
+ opt->srcrt = orig_opt->srcrt;
+ opt->opt_nflen += orig_opt->opt_nflen;
+
+ opt->dst1opt = orig_opt->dst1opt;
+ opt->auth = orig_opt->auth;
+ opt->opt_flen = orig_opt->opt_flen;
+ }
+ raw[5] = IPV6_TLV_PADN;
+
+ /* subtract lengths of destination suboption header,
+ tunnel encapsulation limit and pad N header */
+ raw[6] = pad_to - 7;
+
+ return opt;
+}
+
+/**
+ * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ * @t: the outgoing tunnel device
+ * @hdr: IPv6 header from the incoming packet
+ *
+ * Description:
+ * Avoid trivial tunneling loop by checking that tunnel exit-point
+ * doesn't match source of incoming packet.
+ *
+ * Return:
+ * 1 if conflict,
+ * 0 else
+ **/
+
+static inline int
+ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+{
+ return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
+}
+
+/**
+ * ip6ip6_tnl_xmit - encapsulate packet and send
+ * @skb: the outgoing socket buffer
+ * @dev: the outgoing tunnel device
+ *
+ * Description:
+ * Build new header and do some sanity checks on the packet before sending
+ * it to ip6_build_xmit().
+ *
+ * Return:
+ * 0
+ **/
+
+int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct net_device_stats *stats = &t->stat;
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ipv6_txoptions *orig_opt = NULL;
+ struct ipv6_txoptions *opt = NULL;
+ __u8 encap_limit = 0;
+ __u16 offset;
+ struct flowi fl;
+ struct ip6_flowlabel *fl_lbl = NULL;
+ int err = 0;
+ struct dst_entry *dst;
+ int link_failure = 0;
+ struct sock *sk = ip6_socket->sk;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ int mtu;
+
+ if (t->recursion++) {
+ stats->collisions++;
+ goto tx_err;
+ }
+ if (skb->protocol != htons(ETH_P_IPV6) ||
+ !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
+ ip6ip6_tnl_addr_conflict(t, ipv6h)) {
+ goto tx_err;
+ }
+ if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
+ if (tel->encap_limit <= 1) {
+ icmpv6_send(skb, ICMPV6_PARAMPROB,
+ ICMPV6_HDR_FIELD, offset + 2, skb->dev);
+ goto tx_err;
+ }
+ encap_limit = tel->encap_limit - 1;
+ } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
+ encap_limit = t->parms.encap_limit;
+ }
+ ip6_xmit_lock();
+
+ memcpy(&fl, &t->fl, sizeof (fl));
+
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+
+ if (fl.fl6_flowlabel) {
+ fl_lbl = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (fl_lbl)
+ orig_opt = fl_lbl->opt;
+ }
+ if (encap_limit > 0) {
+ if (!(opt = merge_options(sk, encap_limit, orig_opt))) {
+ goto tx_err_free_fl_lbl;
+ }
+ } else {
+ opt = orig_opt;
+ }
+ dst = __sk_dst_check(sk, np->dst_cookie);
+
+ if (dst) {
+ if (np->daddr_cache == NULL ||
+ ipv6_addr_cmp(&fl.fl6_dst, np->daddr_cache) ||
+#ifdef CONFIG_IPV6_SUBTREES
+ np->saddr_cache == NULL ||
+ ipv6_addr_cmp(&fl.fl6_src, np->saddr_cache) ||
+#endif
+ (fl.oif && fl.oif != dst->dev->ifindex)) {
+ dst = NULL;
+ }
+ }
+ if (dst == NULL) {
+ dst = ip6_route_output(sk, &fl);
+ if (dst->error) {
+ stats->tx_carrier_errors++;
+ link_failure = 1;
+ goto tx_err_dst_release;
+ }
+ /* local routing loop */
+ if (dst->dev == dev) {
+ stats->collisions++;
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Local routing loop detected!\n",
+ t->parms.name);
+ goto tx_err_dst_release;
+ }
+ ipv6_addr_copy(&np->daddr, &fl.fl6_dst);
+ ipv6_addr_copy(&np->saddr, &fl.fl6_src);
+ }
+ mtu = dst_pmtu(dst) - sizeof (*ipv6h);
+ if (opt) {
+ mtu -= (opt->opt_nflen + opt->opt_flen);
+ }
+ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
+ if (skb->dst && mtu < dst_pmtu(skb->dst)) {
+ struct rt6_info *rt = (struct rt6_info *) skb->dst;
+ rt->rt6i_flags |= RTF_MODIFIED;
+ rt->u.dst.metrics[RTAX_MTU-1] = mtu;
+ }
+ if (skb->len > mtu) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+ goto tx_err_opt_release;
+ }
+ err = ip6_append_data(sk, ip_generic_getfrag, skb->nh.raw, skb->len, 0,
+ t->parms.hop_limit, opt, &fl,
+ (struct rt6_info *)dst, MSG_DONTWAIT);
+
+ if (err) {
+ ip6_flush_pending_frames(sk);
+ } else {
+ err = ip6_push_pending_frames(sk);
+ err = (err < 0 ? err : 0);
+ }
+ if (!err) {
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ } else {
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+ }
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+
+ fl6_sock_release(fl_lbl);
+ ip6_dst_store(sk, dst, &np->daddr, &np->saddr);
+ ip6_xmit_unlock();
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+tx_err_dst_release:
+ dst_release(dst);
+tx_err_opt_release:
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+tx_err_free_fl_lbl:
+ fl6_sock_release(fl_lbl);
+ ip6_xmit_unlock();
+ if (link_failure)
+ dst_link_failure(skb);
+tx_err:
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+}
+
+static void ip6_tnl_set_cap(struct ip6_tnl *t)
+{
+ struct ip6_tnl_parm *p = &t->parms;
+ struct in6_addr *laddr = &p->laddr;
+ struct in6_addr *raddr = &p->raddr;
+ int ltype = ipv6_addr_type(laddr);
+ int rtype = ipv6_addr_type(raddr);
+
+ p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
+
+ if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
+ ((ltype|rtype) &
+ (IPV6_ADDR_UNICAST|
+ IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
+ IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
+ struct net_device *ldev = NULL;
+ int l_ok = 1;
+ int r_ok = 1;
+
+ if (p->link)
+ ldev = dev_get_by_index(p->link);
+
+ if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
+ l_ok = 0;
+
+ if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
+ r_ok = 0;
+
+ if (l_ok && r_ok) {
+ if (ltype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_XMIT;
+ if (rtype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_RCV;
+ }
+ if (ldev)
+ dev_put(ldev);
+ }
+}
+
+
+static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
+{
+ struct net_device *dev = t->dev;
+ struct ip6_tnl_parm *p = &t->parms;
+ struct flowi *fl;
+ /* Set up flowi template */
+ fl = &t->fl;
+ ipv6_addr_copy(&fl->fl6_src, &p->laddr);
+ ipv6_addr_copy(&fl->fl6_dst, &p->raddr);
+ fl->oif = p->link;
+ fl->fl6_flowlabel = 0;
+
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
+ fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
+
+ ip6_tnl_set_cap(t);
+
+ if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
+ dev->flags |= IFF_POINTOPOINT;
+ else
+ dev->flags &= ~IFF_POINTOPOINT;
+
+ if (p->flags & IP6_TNL_F_CAP_XMIT) {
+ struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
+ p->link, 0);
+ if (rt) {
+ struct net_device *rtdev;
+ if (!(rtdev = rt->rt6i_dev) ||
+ rtdev->type == ARPHRD_TUNNEL6) {
+ /* as long as tunnels use the same socket
+ for transmission, locally nested tunnels
+ won't work */
+ dst_release(&rt->u.dst);
+ goto no_link;
+ } else {
+ dev->iflink = rtdev->ifindex;
+ dev->hard_header_len = rtdev->hard_header_len +
+ sizeof (struct ipv6hdr);
+ dev->mtu = rtdev->mtu - sizeof (struct ipv6hdr);
+ if (dev->mtu < IPV6_MIN_MTU)
+ dev->mtu = IPV6_MIN_MTU;
+
+ dst_release(&rt->u.dst);
+ }
+ }
+ } else {
+ no_link:
+ dev->iflink = 0;
+ dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
+ dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+ }
+}
+
+/**
+ * ip6ip6_tnl_change - update the tunnel parameters
+ * @t: tunnel to be changed
+ * @p: tunnel configuration parameters
+ * @active: != 0 if tunnel is ready for use
+ *
+ * Description:
+ * ip6ip6_tnl_change() updates the tunnel parameters
+ **/
+
+static int
+ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+{
+ ipv6_addr_copy(&t->parms.laddr, &p->laddr);
+ ipv6_addr_copy(&t->parms.raddr, &p->raddr);
+ t->parms.flags = p->flags;
+ t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1);
+ t->parms.encap_limit = p->encap_limit;
+ t->parms.flowinfo = p->flowinfo;
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ * @dev: virtual device associated with tunnel
+ * @ifr: parameters passed from userspace
+ * @cmd: command to be performed
+ *
+ * Description:
+ * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
+ * from userspace.
+ *
+ * The possible commands are the following:
+ * %SIOCGETTUNNEL: get tunnel parameters for device
+ * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
+ * %SIOCCHGTUNNEL: change tunnel parameters to those given
+ * %SIOCDELTUNNEL: delete tunnel
+ *
+ * The fallback device "ip6tnl0", created during module
+ * initialization, can be used for creating other tunnel devices.
+ *
+ * Return:
+ * 0 on success,
+ * %-EFAULT if unable to copy data to or from userspace,
+ * %-EPERM if current process hasn't %CAP_NET_ADMIN set
+ * %-EINVAL if passed tunnel parameters are invalid,
+ * %-EEXIST if changing a tunnel's parameters would cause a conflict
+ * %-ENODEV if attempting to change or delete a nonexisting device
+ **/
+
+static int
+ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ int create;
+ struct ip6_tnl_parm p;
+ struct ip6_tnl *t = NULL;
+
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p,
+ ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
+ t = (struct ip6_tnl *) dev->priv;
+ else if (err)
+ break;
+ } else
+ t = (struct ip6_tnl *) dev->priv;
+
+ memcpy(&p, &t->parms, sizeof (p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+ err = -EFAULT;
+ }
+ break;
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ create = (cmd == SIOCADDTUNNEL);
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if (!create && dev != &ip6ip6_fb_tnl_dev) {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
+ break;
+ }
+ if (cmd == SIOCCHGTUNNEL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ ip6ip6_tnl_unlink(t);
+ err = ip6ip6_tnl_change(t, &p);
+ ip6ip6_tnl_link(t);
+ netdev_state_change(dev);
+ }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data,
+ &t->parms, sizeof (p))) {
+ err = -EFAULT;
+ } else {
+ err = 0;
+ }
+ break;
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ err = ip6ip6_tnl_locate(&p, &t, 0);
+ if (err)
+ break;
+ if (t == &ip6ip6_fb_tnl) {
+ err = -EPERM;
+ break;
+ }
+ } else {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ err = ip6_tnl_destroy(t);
+ break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/**
+ * ip6ip6_tnl_get_stats - return the stats for tunnel device
+ * @dev: virtual device associated with tunnel
+ *
+ * Return: stats for device
+ **/
+
+static struct net_device_stats *
+ip6ip6_tnl_get_stats(struct net_device *dev)
+{
+ return &(((struct ip6_tnl *) dev->priv)->stat);
+}
+
+/**
+ * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
+ * @dev: virtual device associated with tunnel
+ * @new_mtu: the new mtu
+ *
+ * Return:
+ * 0 on success,
+ * %-EINVAL if mtu too small
+ **/
+
+static int
+ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < IPV6_MIN_MTU) {
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
+ * @dev: virtual device associated with tunnel
+ *
+ * Description:
+ * Set function pointers and initialize the &struct flowi template used
+ * by the tunnel.
+ **/
+
+static void
+ip6ip6_tnl_dev_init_gen(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct flowi *fl = &t->fl;
+
+ memset(fl, 0, sizeof (*fl));
+ fl->proto = IPPROTO_IPV6;
+
+ dev->destructor = ip6ip6_tnl_dev_destructor;
+ dev->uninit = ip6ip6_tnl_dev_uninit;
+ dev->hard_start_xmit = ip6ip6_tnl_xmit;
+ dev->get_stats = ip6ip6_tnl_get_stats;
+ dev->do_ioctl = ip6ip6_tnl_ioctl;
+ dev->change_mtu = ip6ip6_tnl_change_mtu;
+ dev->type = ARPHRD_TUNNEL6;
+ dev->flags |= IFF_NOARP;
+ if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST &&
+ ipv6_addr_type(&t->parms.laddr) & IPV6_ADDR_UNICAST)
+ dev->flags |= IFF_POINTOPOINT;
+ /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be
+ copied to dev->dev_addr and dev->broadcast, like the ipv4
+ addresses were in ipip.c, ip_gre.c and sit.c. */
+ dev->addr_len = 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
+ * @dev: virtual device associated with tunnel
+ **/
+
+static int
+ip6ip6_tnl_dev_init(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_dev_init_gen(dev);
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
+ * @dev: fallback device
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_fb_tnl_dev_init(struct net_device *dev)
+{
+ ip6ip6_tnl_dev_init_gen(dev);
+ tnls_wc[0] = &ip6ip6_fb_tnl;
+ return 0;
+}
+
+static struct inet6_protocol ip6ip6_protocol = {
+ .handler = ip6ip6_rcv,
+ .err_handler = ip6ip6_err,
+ .flags = INET6_PROTO_FINAL
+};
+
+/**
+ * ip6_tunnel_init - register protocol and reserve needed resources
+ *
+ * Return: 0 on success
+ **/
+
+int __init ip6_tunnel_init(void)
+{
+ int i, j, err;
+ struct sock *sk;
+ struct ipv6_pinfo *np;
+
+ ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+
+ err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6,
+ &__ip6_socket[i]);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Failed to create the IPv6 tunnel socket "
+ "(err %d).\n",
+ err);
+ goto fail;
+ }
+ sk = __ip6_socket[i]->sk;
+ sk->allocation = GFP_ATOMIC;
+
+ np = inet6_sk(sk);
+ np->hop_limit = 255;
+ np->mc_loop = 0;
+
+ sk->prot->unhash(sk);
+ }
+ if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) {
+ printk(KERN_ERR "Failed to register IPv6 protocol\n");
+ goto fail;
+ }
+
+ SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev);
+ register_netdev(&ip6ip6_fb_tnl_dev);
+
+ return 0;
+fail:
+ for (j = 0; j < i; j++) {
+ if (!cpu_possible(j))
+ continue;
+ sock_release(__ip6_socket[j]);
+ __ip6_socket[j] = NULL;
+ }
+ return err;
+}
+
+/**
+ * ip6_tunnel_cleanup - free resources and unregister protocol
+ **/
+
+void ip6_tunnel_cleanup(void)
+{
+ int i;
+
+ unregister_netdev(&ip6ip6_fb_tnl_dev);
+
+ inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+ sock_release(__ip6_socket[i]);
+ __ip6_socket[i] = NULL;
+ }
+}
+
+#ifdef CONFIG_IPV6_TUNNEL_MODULE
+module_init(ip6_tunnel_init);
+module_exit(ip6_tunnel_cleanup);
+#endif
+
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ipv6_syms.c merge-2.5/net/ipv6/ipv6_syms.c
--- linux-2.5/net/ipv6/ipv6_syms.c Wed May 28 20:07:41 2003
+++ merge-2.5/net/ipv6/ipv6_syms.c Wed May 28 21:12:02 2003
@@ -38,3 +38,11 @@
EXPORT_SYMBOL(ip6_found_nexthdr);
EXPORT_SYMBOL(xfrm6_rcv);
EXPORT_SYMBOL(xfrm6_clear_mutable_options);
+#ifdef CONFIG_IPV6_TUNNEL_MODULE
+EXPORT_SYMBOL(rt6_lookup);
+EXPORT_SYMBOL(fl6_sock_lookup);
+EXPORT_SYMBOL(ipv6_ext_hdr);
+EXPORT_SYMBOL(ip6_append_data);
+EXPORT_SYMBOL(ip6_flush_pending_frames);
+EXPORT_SYMBOL(ip6_push_pending_frames);
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/netsyms.c merge-2.5/net/netsyms.c
--- linux-2.5/net/netsyms.c Wed May 28 20:07:35 2003
+++ merge-2.5/net/netsyms.c Wed May 28 21:12:02 2003
@@ -477,8 +477,10 @@
EXPORT_SYMBOL(sysctl_max_syn_backlog);
#endif
-EXPORT_SYMBOL(ip_generic_getfrag);
+#endif
+#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) || defined (CONFIG_IPV6_TUNNEL_MODULE)
+EXPORT_SYMBOL(ip_generic_getfrag);
#endif
EXPORT_SYMBOL(tcp_read_sock);
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-05-30 14:34 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 Ville Nuorvala
2003-05-30 15:00 ` [patch]: ipv6 tunnel " Ville Nuorvala
@ 2003-05-30 15:03 ` YOSHIFUJI Hideaki / 吉藤英明
2003-05-30 20:38 ` Venkata Jagana
` (2 more replies)
1 sibling, 3 replies; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-05-30 15:03 UTC (permalink / raw)
To: vnuorval
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr,
yoshfuji
In article <Pine.LNX.4.44.0305301712300.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 17:34:40 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
> here is a patch that fixes CONFIG_IPV6_SUBTREES and allows overriding
> normal routes with source address specific ones. This is for example
> needed in MIPv6 for handling the traffic to and from a mobile node's home
> address correctly.
Let us test the patch. It seemed buggy when USAGI tested before.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-05-30 15:00 ` [patch]: ipv6 tunnel " Ville Nuorvala
@ 2003-05-30 15:38 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 4:38 ` David S. Miller
2003-06-04 4:34 ` David S. Miller
1 sibling, 1 reply; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-05-30 15:38 UTC (permalink / raw)
To: vnuorval
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr,
yoshfuji
In article <Pine.LNX.4.44.0305301735340.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 18:00:55 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
> there was a while ago some talk about an xfrm6_tunnel driver IIRC. I don't
> know how far along the project is and what capabilities the xfrm6_tunnels
> will have, but in the mean time I have an ipv6-in-ipv6 tunnel driver
> specified in RFC 2473 to offer you. If the xfrm6_tunnels are going to
> support ipv6-in-ipv6 you also might find the code useful.
The code exists in our repository.
Kanda-san is preparing patch for xfrm6_tunnel;
patch will soon be available.
> The tunnels are needed by MIPv6 for encapsulation and decapsulation of
> tunneled packets between the home agent and mobile node. Some proctocols
> like DHCP are also run over the virtual link between the MN and the home
> network according to the MIPv6 specification.
I'm not sure if MIP6 will use this tunnel driver.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
@ 2003-05-30 20:38 ` Venkata Jagana
2003-06-03 6:35 ` Ville Nuorvala
2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
2 siblings, 0 replies; 37+ messages in thread
From: Venkata Jagana @ 2003-05-30 20:38 UTC (permalink / raw)
To: yoshfuji
Cc: vnuorval, davem, kuznet, netdev, ajtuomin, lpetande, jagana,
kumarkr
When we have tested this recently (just two months ago), we found only
two bugs but MIPL has already fixed those in their development version.
How long before have you tested this and what problems have you
encountered in your test?
Thanks,
Venkat
YOSHIFUJI Hideaki / wrote:
>In article <Pine.LNX.4.44.0305301712300.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 17:34:40 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
>
>
>
>>here is a patch that fixes CONFIG_IPV6_SUBTREES and allows overriding
>>normal routes with source address specific ones. This is for example
>>needed in MIPv6 for handling the traffic to and from a mobile node's home
>>address correctly.
>>
>>
>
>Let us test the patch. It seemed buggy when USAGI tested before.
>
>
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
2003-05-30 20:38 ` Venkata Jagana
@ 2003-06-03 6:35 ` Ville Nuorvala
2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
2 siblings, 0 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-03 6:35 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr
On Sat, 31 May 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> Let us test the patch. It seemed buggy when USAGI tested before.
Any feedback would have been (and still is) of course welcome. The bugs
are much easier to locate and fix if people report about them :-)
-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-05-30 15:00 ` [patch]: ipv6 tunnel " Ville Nuorvala
2003-05-30 15:38 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-04 4:34 ` David S. Miller
2003-06-04 12:40 ` Ville Nuorvala
1 sibling, 1 reply; 37+ messages in thread
From: David S. Miller @ 2003-06-04 4:34 UTC (permalink / raw)
To: vnuorval; +Cc: kuznet, yoshfuji, netdev, ajtuomin, lpetande, jagana, kumarkr
From: Ville Nuorvala <vnuorval@tcs.hut.fi>
Date: Fri, 30 May 2003 18:00:55 +0300 (EEST)
The patch is sent as an attachment to this mail, but is also available at:
You need to fix some things before I will apply this:
1) Bogus #ifdef CONFIG_IPV6_TUNNEL_MODULE. You need not this test
around things like MODULE_AUTHOR() and stuff like that,
linux/module.h does that for you.
2) Dependency upon subtrees patch, please remove it. There is no
agreement on that semantic change to how subtrees work.
Thanks.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-05-30 15:38 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-04 4:38 ` David S. Miller
2003-06-04 14:30 ` Henrik Petander
0 siblings, 1 reply; 37+ messages in thread
From: David S. Miller @ 2003-06-04 4:38 UTC (permalink / raw)
To: yoshfuji; +Cc: vnuorval, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr
From: YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>
Date: Sat, 31 May 2003 00:38:58 +0900 (JST)
In article <Pine.LNX.4.44.0305301735340.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 18:00:55 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
> The tunnels are needed by MIPv6 for encapsulation and decapsulation of
> tunneled packets between the home agent and mobile node. Some proctocols
> like DHCP are also run over the virtual link between the MN and the home
> network according to the MIPv6 specification.
I'm not sure if MIP6 will use this tunnel driver.
Yes, it is an important issue.
I am VERY UPSET that there appears to be NO dialogue between USAGI and
MIPV6 folks to discuss design of MIPV6. If you do not talk together,
how can you guys possibly coordinate efforts and not avoid duplicated
work?
And, it is very clear from my perspective that it is the MIPV6
developers who are not communicating. USAGI are making an effort
to discuss the issues, but MIPV6 coders disappear for weeks at a time
not answering queries made to them or comments made about their
patch submissions.
That is unacceptable. And this makes me less likely to apply any
patches from MIPV6 project, here is why. If some bug shows in some
patch I apply from MIPV6 project, can I expect them to act similarly
and not respond for weeks at a time? That's intolerable. If you add
some bug to the tree, you are responsible to be responsive and fix
the problem in a reasonable amount of time.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 4:34 ` David S. Miller
@ 2003-06-04 12:40 ` Ville Nuorvala
2003-06-07 10:30 ` David S. Miller
0 siblings, 1 reply; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-04 12:40 UTC (permalink / raw)
To: David S. Miller
Cc: kuznet, yoshfuji, netdev, ajtuomin, lpetande, jagana, kumarkr
[-- Attachment #1: Type: TEXT/PLAIN, Size: 780 bytes --]
On Tue, 3 Jun 2003, David S. Miller wrote:
> You need to fix some things before I will apply this:
>
> 1) Bogus #ifdef CONFIG_IPV6_TUNNEL_MODULE. You need not this test
> around things like MODULE_AUTHOR() and stuff like that,
> linux/module.h does that for you.
>
Fixed.
> 2) Dependency upon subtrees patch, please remove it. There is no
> agreement on that semantic change to how subtrees work.
>
Done. I'll send a separate patch for the subtrees stuff if needed.
The revised version is attached to this mail, but also available at:
http://www.mipl.mediapoli.com/patches/ip6-tunnel-r2.patch
-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
[-- Attachment #2: Type: TEXT/PLAIN, Size: 39640 bytes --]
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/if_arp.h merge-2.5/include/linux/if_arp.h
--- linux-2.5/include/linux/if_arp.h Wed Jun 4 13:43:03 2003
+++ merge-2.5/include/linux/if_arp.h Wed May 28 21:11:43 2003
@@ -60,7 +60,7 @@
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
-#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
+#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
#define ARPHRD_SKIP 771 /* SKIP vif */
#define ARPHRD_LOOPBACK 772 /* Loopback device */
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/ip6_tunnel.h merge-2.5/include/linux/ip6_tunnel.h
--- linux-2.5/include/linux/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/linux/ip6_tunnel.h Wed May 28 21:11:43 2003
@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ */
+
+#ifndef _IP6_TUNNEL_H
+#define _IP6_TUNNEL_H
+
+#define IPV6_TLV_TNL_ENCAP_LIMIT 4
+#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
+
+/* don't add encapsulation limit if one isn't present in inner packet */
+#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
+/* copy the traffic class field from the inner packet */
+#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
+/* copy the flowlabel from the inner packet */
+#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
+/* being used for Mobile IPv6 */
+#define IP6_TNL_F_MIP6_DEV 0x8
+
+struct ip6_tnl_parm {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __u32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+};
+
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/net/ip6_tunnel.h merge-2.5/include/net/ip6_tunnel.h
--- linux-2.5/include/net/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/net/ip6_tunnel.h Wed May 28 21:11:43 2003
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ */
+
+#ifndef _NET_IP6_TUNNEL_H
+#define _NET_IP6_TUNNEL_H
+
+#include <linux/ipv6.h>
+#include <linux/netdevice.h>
+#include <linux/ip6_tunnel.h>
+
+/* capable of sending packets */
+#define IP6_TNL_F_CAP_XMIT 0x10000
+/* capable of receiving packets */
+#define IP6_TNL_F_CAP_RCV 0x20000
+
+#define IP6_TNL_MAX 128
+
+/* IPv6 tunnel */
+
+struct ip6_tnl {
+ struct ip6_tnl *next; /* next tunnel in list */
+ struct net_device *dev; /* virtual device associated with tunnel */
+ struct net_device_stats stat; /* statistics for tunnel device */
+ int recursion; /* depth of hard_start_xmit recursion */
+ struct ip6_tnl_parm parms; /* tunnel configuration paramters */
+ struct flowi fl; /* flowi template for xmit */
+};
+
+/* Tunnel encapsulation limit destination sub-option */
+
+struct ipv6_tlv_tnl_enc_lim {
+ __u8 type; /* type-code for option */
+ __u8 length; /* option length */
+ __u8 encap_limit; /* tunnel encapsulation limit */
+} __attribute__ ((packed));
+
+#ifdef __KERNEL__
+#ifdef CONFIG_IPV6_TUNNEL
+extern int __init ip6_tunnel_init(void);
+extern void ip6_tunnel_cleanup(void);
+#endif
+#endif
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Kconfig merge-2.5/net/ipv6/Kconfig
--- linux-2.5/net/ipv6/Kconfig Wed Jun 4 13:43:44 2003
+++ merge-2.5/net/ipv6/Kconfig Wed Jun 4 12:20:33 2003
@@ -42,4 +42,12 @@
If unsure, say Y.
+config IPV6_TUNNEL
+ tristate "IPv6: IPv6-in-IPv6 tunnel"
+ depends on IPV6
+ ---help---
+ Support for IPv6-in-IPv6 tunnels described in RFC 2473.
+
+ If unsure, say N.
+
source "net/ipv6/netfilter/Kconfig"
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Makefile merge-2.5/net/ipv6/Makefile
--- linux-2.5/net/ipv6/Makefile Wed Jun 4 13:43:06 2003
+++ merge-2.5/net/ipv6/Makefile Wed May 28 21:11:59 2003
@@ -15,3 +15,5 @@
obj-$(CONFIG_INET6_ESP) += esp6.o
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
obj-$(CONFIG_NETFILTER) += netfilter/
+
+obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/af_inet6.c merge-2.5/net/ipv6/af_inet6.c
--- linux-2.5/net/ipv6/af_inet6.c Wed Jun 4 13:43:07 2003
+++ merge-2.5/net/ipv6/af_inet6.c Wed May 28 21:13:08 2003
@@ -57,6 +57,9 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#if CONFIG_IPV6_TUNNEL
+#include <net/ip6_tunnel.h>
+#endif
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -780,6 +783,11 @@
err = ndisc_init(&inet6_family_ops);
if (err)
goto ndisc_fail;
+#ifdef CONFIG_IPV6_TUNNEL
+ err = ip6_tunnel_init();
+ if (err)
+ goto ip6_tunnel_fail;
+#endif
err = igmp6_init(&inet6_family_ops);
if (err)
goto igmp_fail;
@@ -834,6 +842,10 @@
igmp6_cleanup();
#endif
igmp_fail:
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+ip6_tunnel_fail:
+#endif
ndisc_cleanup();
ndisc_fail:
icmpv6_cleanup();
@@ -869,6 +881,9 @@
ip6_route_cleanup();
ipv6_packet_cleanup();
igmp6_cleanup();
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+#endif
ndisc_cleanup();
icmpv6_cleanup();
#ifdef CONFIG_SYSCTL
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ip6_tunnel.c merge-2.5/net/ipv6/ip6_tunnel.c
--- linux-2.5/net/ipv6/ip6_tunnel.c Thu Jan 1 02:00:00 1970
+++ merge-2.5/net/ipv6/ip6_tunnel.c Wed Jun 4 13:44:50 2003
@@ -0,0 +1,1261 @@
+/*
+ * IPv6 over IPv6 tunnel device
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Ville Nuorvala <vnuorval@tcs.hut.fi>
+ *
+ * $Id$
+ *
+ * Based on:
+ * linux/net/ipv6/sit.c
+ *
+ * RFC 2473
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/icmpv6.h>
+#include <linux/init.h>
+#include <linux/route.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip6_tunnel.h>
+
+MODULE_AUTHOR("Ville Nuorvala");
+MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
+MODULE_LICENSE("GPL");
+
+#define IPV6_TLV_TEL_DST_SIZE 8
+
+#ifdef IP6_TNL_DEBUG
+#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
+#else
+#define IP6_TNL_TRACE(x...) do {;} while(0)
+#endif
+
+#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+
+/* socket(s) used by ip6ip6_tnl_xmit() for resending packets */
+static struct socket *__ip6_socket[NR_CPUS];
+#define ip6_socket __ip6_socket[smp_processor_id()]
+
+static void ip6_xmit_lock(void)
+{
+ local_bh_disable();
+ if (unlikely(!spin_trylock(&ip6_socket->sk->lock.slock)))
+ BUG();
+}
+
+static void ip6_xmit_unlock(void)
+{
+ spin_unlock_bh(&ip6_socket->sk->lock.slock);
+}
+
+#define HASH_SIZE 32
+
+#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
+ (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
+ (HASH_SIZE - 1))
+
+static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
+static int ip6ip6_tnl_dev_init(struct net_device *dev);
+
+/* the IPv6 tunnel fallback device */
+static struct net_device ip6ip6_fb_tnl_dev = {
+ .name = "ip6tnl0",
+ .init = ip6ip6_fb_tnl_dev_init
+};
+
+/* the IPv6 fallback tunnel */
+static struct ip6_tnl ip6ip6_fb_tnl = {
+ .dev = &ip6ip6_fb_tnl_dev,
+ .parms ={.name = "ip6tnl0", .proto = IPPROTO_IPV6}
+};
+
+/* lists for storing tunnels in use */
+static struct ip6_tnl *tnls_r_l[HASH_SIZE];
+static struct ip6_tnl *tnls_wc[1];
+static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
+
+/* lock for the tunnel lists */
+static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ * @remote: the address of the tunnel exit-point
+ * @local: the address of the tunnel entry-point
+ *
+ * Return:
+ * tunnel matching given end-points if found,
+ * else fallback tunnel if its device is up,
+ * else %NULL
+ **/
+
+struct ip6_tnl *
+ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
+{
+ unsigned h0 = HASH(remote);
+ unsigned h1 = HASH(local);
+ struct ip6_tnl *t;
+
+ for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+ if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
+ return t;
+
+ return NULL;
+}
+
+/**
+ * ip6ip6_bucket - get head of list matching given tunnel parameters
+ * @p: parameters containing tunnel end-points
+ *
+ * Description:
+ * ip6ip6_bucket() returns the head of the list matching the
+ * &struct in6_addr entries laddr and raddr in @p.
+ *
+ * Return: head of IPv6 tunnel list
+ **/
+
+static struct ip6_tnl **
+ip6ip6_bucket(struct ip6_tnl_parm *p)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ prio = 1;
+ h = HASH(remote) ^ HASH(local);
+ }
+ return &tnls[prio][h];
+}
+
+/**
+ * ip6ip6_tnl_link - add tunnel to hash table
+ * @t: tunnel to be added
+ **/
+
+static void
+ip6ip6_tnl_link(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
+
+ write_lock_bh(&ip6ip6_lock);
+ t->next = *tp;
+ write_unlock_bh(&ip6ip6_lock);
+ *tp = t;
+}
+
+/**
+ * ip6ip6_tnl_unlink - remove tunnel from hash table
+ * @t: tunnel to be removed
+ **/
+
+static void
+ip6ip6_tnl_unlink(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp;
+
+ for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ write_lock_bh(&ip6ip6_lock);
+ *tp = t->next;
+ write_unlock_bh(&ip6ip6_lock);
+ break;
+ }
+ }
+}
+
+/**
+ * ip6_tnl_create() - create a new tunnel
+ * @p: tunnel parameters
+ * @pt: pointer to new tunnel
+ *
+ * Description:
+ * Create tunnel matching given parameters.
+ *
+ * Return:
+ * 0 on success
+ **/
+
+static int
+ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
+{
+ struct net_device *dev;
+ int err = -ENOBUFS;
+ struct ip6_tnl *t;
+
+ dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
+ if (!dev)
+ return err;
+
+ memset(dev, 0, sizeof (*dev) + sizeof (*t));
+ dev->priv = (void *) (dev + 1);
+ t = (struct ip6_tnl *) dev->priv;
+ t->dev = dev;
+ dev->init = ip6ip6_tnl_dev_init;
+ memcpy(&t->parms, p, sizeof (*p));
+ t->parms.name[IFNAMSIZ - 1] = '\0';
+ if (t->parms.hop_limit > 255)
+ t->parms.hop_limit = -1;
+ strcpy(dev->name, t->parms.name);
+ if (!dev->name[0]) {
+ int i = 0;
+ int exists = 0;
+
+ do {
+ sprintf(dev->name, "ip6tnl%d", ++i);
+ exists = (__dev_get_by_name(dev->name) != NULL);
+ } while (i < IP6_TNL_MAX && exists);
+
+ if (i == IP6_TNL_MAX) {
+ goto failed;
+ }
+ memcpy(t->parms.name, dev->name, IFNAMSIZ);
+ }
+ SET_MODULE_OWNER(dev);
+ if ((err = register_netdevice(dev)) < 0) {
+ goto failed;
+ }
+ ip6ip6_tnl_link(t);
+ *pt = t;
+ return 0;
+failed:
+ kfree(dev);
+ return err;
+}
+
+/**
+ * ip6_tnl_destroy() - destroy old tunnel
+ * @t: tunnel to be destroyed
+ *
+ * Return:
+ * whatever unregister_netdevice() returns
+ **/
+
+static inline int
+ip6_tnl_destroy(struct ip6_tnl *t)
+{
+ return unregister_netdevice(t->dev);
+}
+
+/**
+ * ip6ip6_tnl_locate - find or create tunnel matching given parameters
+ * @p: tunnel parameters
+ * @create: != 0 if allowed to create new tunnel if no match found
+ *
+ * Description:
+ * ip6ip6_tnl_locate() first tries to locate an existing tunnel
+ * based on @parms. If this is unsuccessful, but @create is set a new
+ * tunnel device is created and registered for use.
+ *
+ * Return:
+ * 0 if tunnel located or created,
+ * -EINVAL if parameters incorrect,
+ * -ENODEV if no matching tunnel available
+ **/
+
+static int
+ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ struct ip6_tnl *t;
+
+ if (p->proto != IPPROTO_IPV6)
+ return -EINVAL;
+
+ for (t = *ip6ip6_bucket(p); t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr)) {
+ *pt = t;
+ return (create ? -EEXIST : 0);
+ }
+ }
+ if (!create) {
+ return -ENODEV;
+ }
+ return ip6_tnl_create(p, pt);
+}
+
+/**
+ * ip6ip6_tnl_dev_destructor - tunnel device destructor
+ * @dev: the device to be destroyed
+ **/
+
+static void
+ip6ip6_tnl_dev_destructor(struct net_device *dev)
+{
+ kfree(dev);
+}
+
+/**
+ * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
+ * @dev: the device to be destroyed
+ *
+ * Description:
+ * ip6ip6_tnl_dev_uninit() removes tunnel from its list
+ **/
+
+static void
+ip6ip6_tnl_dev_uninit(struct net_device *dev)
+{
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ write_lock_bh(&ip6ip6_lock);
+ tnls_wc[0] = NULL;
+ write_unlock_bh(&ip6ip6_lock);
+ } else {
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_unlink(t);
+ }
+}
+
+/**
+ * parse_tvl_tnl_enc_lim - handle encapsulation limit option
+ * @skb: received socket buffer
+ *
+ * Return:
+ * 0 if none was found,
+ * else index to encapsulation limit
+ **/
+
+static __u16
+parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
+ __u8 nexthdr = ipv6h->nexthdr;
+ __u16 off = sizeof (*ipv6h);
+
+ while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
+ __u16 optlen = 0;
+ struct ipv6_opt_hdr *hdr;
+ if (raw + off + sizeof (*hdr) > skb->data &&
+ !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+ break;
+
+ hdr = (struct ipv6_opt_hdr *) (raw + off);
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
+ if (frag_hdr->frag_off)
+ break;
+ optlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH) {
+ optlen = (hdr->hdrlen + 2) << 2;
+ } else {
+ optlen = ipv6_optlen(hdr);
+ }
+ if (nexthdr == NEXTHDR_DEST) {
+ __u16 i = off + 2;
+ while (1) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+
+ /* No more room for encapsulation limit */
+ if (i + sizeof (*tel) > off + optlen)
+ break;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+ /* return index of option if found and valid */
+ if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
+ tel->length == 1)
+ return i;
+ /* else jump to next option */
+ if (tel->type)
+ i += tel->length + 2;
+ else
+ i++;
+ }
+ }
+ nexthdr = hdr->nexthdr;
+ off += optlen;
+ }
+ return 0;
+}
+
+/**
+ * ip6ip6_err - tunnel error handler
+ *
+ * Description:
+ * ip6ip6_err() should handle errors in the tunnel according
+ * to the specifications in RFC 2473.
+ **/
+
+void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
+ struct ip6_tnl *t;
+ int rel_msg = 0;
+ int rel_type = ICMPV6_DEST_UNREACH;
+ int rel_code = ICMPV6_ADDR_UNREACH;
+ __u32 rel_info = 0;
+ __u16 len;
+
+ /* If the packet doesn't contain the original IPv6 header we are
+ in trouble since we might need the source address for furter
+ processing of the error. */
+
+ read_lock(&ip6ip6_lock);
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
+ goto out;
+
+ switch (type) {
+ __u32 teli;
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ __u32 mtu;
+ case ICMPV6_DEST_UNREACH:
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Path to destination invalid "
+ "or inactive!\n", t->parms.name);
+ rel_msg = 1;
+ break;
+ case ICMPV6_TIME_EXCEED:
+ if (code == ICMPV6_EXC_HOPLIMIT) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small hop limit or "
+ "routing loop in tunnel!\n",
+ t->parms.name);
+ rel_msg = 1;
+ }
+ break;
+ case ICMPV6_PARAMPROB:
+ /* ignore if parameter problem not caused by a tunnel
+ encapsulation limit sub-option */
+ if (code != ICMPV6_HDR_FIELD) {
+ break;
+ }
+ teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+
+ if (teli && teli == info - 2) {
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
+ if (tel->encap_limit <= 1) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small encapsulation "
+ "limit or routing loop in "
+ "tunnel!\n", t->parms.name);
+ rel_msg = 1;
+ }
+ }
+ break;
+ case ICMPV6_PKT_TOOBIG:
+ mtu = info - offset;
+ if (mtu <= IPV6_MIN_MTU) {
+ mtu = IPV6_MIN_MTU;
+ }
+ t->dev->mtu = mtu;
+
+ if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
+ rel_type = ICMPV6_PKT_TOOBIG;
+ rel_code = 0;
+ rel_info = mtu;
+ rel_msg = 1;
+ }
+ break;
+ }
+ if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
+ struct rt6_info *rt;
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2)
+ goto out;
+
+ dst_release(skb2->dst);
+ skb2->dst = NULL;
+ skb_pull(skb2, offset);
+ skb2->nh.raw = skb2->data;
+
+ /* Try to guess incoming interface */
+ rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
+
+ if (rt && rt->rt6i_dev)
+ skb2->dev = rt->rt6i_dev;
+
+ icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
+
+ if (rt)
+ dst_free(&rt->u.dst);
+
+ kfree_skb(skb2);
+ }
+out:
+ read_unlock(&ip6ip6_lock);
+}
+
+/**
+ * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
+ * @skb: received socket buffer
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+ struct sk_buff *skb = *pskb;
+ struct ipv6hdr *ipv6h;
+ struct ip6_tnl *t;
+
+ if (!pskb_may_pull(skb, sizeof (*ipv6h)))
+ goto discard;
+
+ ipv6h = skb->nh.ipv6h;
+
+ read_lock(&ip6ip6_lock);
+
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
+ if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
+ t->stat.rx_dropped++;
+ read_unlock(&ip6ip6_lock);
+ goto discard;
+ }
+ skb->mac.raw = skb->nh.raw;
+ skb->nh.raw = skb->data;
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->pkt_type = PACKET_HOST;
+ memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+ skb->dev = t->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ t->stat.rx_packets++;
+ t->stat.rx_bytes += skb->len;
+ netif_rx(skb);
+ read_unlock(&ip6ip6_lock);
+ return 0;
+ }
+ read_unlock(&ip6ip6_lock);
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+discard:
+ kfree_skb(skb);
+ return 0;
+}
+
+/**
+ * txopt_len - get necessary size for new &struct ipv6_txoptions
+ * @orig_opt: old options
+ *
+ * Return:
+ * Size of old one plus size of tunnel encapsulation limit option
+ **/
+
+static inline int
+txopt_len(struct ipv6_txoptions *orig_opt)
+{
+ int len = sizeof (*orig_opt) + 8;
+
+ if (orig_opt && orig_opt->dst0opt)
+ len += ipv6_optlen(orig_opt->dst0opt);
+ return len;
+}
+
+/**
+ * merge_options - add encapsulation limit to original options
+ * @encap_limit: number of allowed encapsulation limits
+ * @orig_opt: original options
+ *
+ * Return:
+ * Pointer to new &struct ipv6_txoptions containing the tunnel
+ * encapsulation limit
+ **/
+
+static struct ipv6_txoptions *
+merge_options(struct sock *sk, __u8 encap_limit,
+ struct ipv6_txoptions *orig_opt)
+{
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ struct ipv6_txoptions *opt;
+ __u8 *raw;
+ __u8 pad_to = 8;
+ int opt_len = txopt_len(orig_opt);
+
+ if (!(opt = sock_kmalloc(sk, opt_len, GFP_ATOMIC))) {
+ return NULL;
+ }
+
+ memset(opt, 0, opt_len);
+ opt->tot_len = opt_len;
+ opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
+ opt->opt_nflen = 8;
+
+ raw = (__u8 *) opt->dst0opt;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
+ tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
+ tel->length = 1;
+ tel->encap_limit = encap_limit;
+
+ if (orig_opt) {
+ __u8 *orig_raw;
+
+ opt->hopopt = orig_opt->hopopt;
+
+ /* Keep the original destination options properly
+ aligned and merge possible old paddings to the
+ new padding option */
+ if ((orig_raw = (__u8 *) orig_opt->dst0opt) != NULL) {
+ __u8 type;
+ int i = sizeof (struct ipv6_opt_hdr);
+ pad_to += sizeof (struct ipv6_opt_hdr);
+ while (i < ipv6_optlen(orig_opt->dst0opt)) {
+ type = orig_raw[i++];
+ if (type == IPV6_TLV_PAD0)
+ pad_to++;
+ else if (type == IPV6_TLV_PADN) {
+ int len = orig_raw[i++];
+ i += len;
+ pad_to += len + 2;
+ } else {
+ break;
+ }
+ }
+ opt->dst0opt->hdrlen = orig_opt->dst0opt->hdrlen + 1;
+ memcpy(raw + pad_to, orig_raw + pad_to - 8,
+ opt_len - sizeof (*opt) - pad_to);
+ }
+ opt->srcrt = orig_opt->srcrt;
+ opt->opt_nflen += orig_opt->opt_nflen;
+
+ opt->dst1opt = orig_opt->dst1opt;
+ opt->auth = orig_opt->auth;
+ opt->opt_flen = orig_opt->opt_flen;
+ }
+ raw[5] = IPV6_TLV_PADN;
+
+ /* subtract lengths of destination suboption header,
+ tunnel encapsulation limit and pad N header */
+ raw[6] = pad_to - 7;
+
+ return opt;
+}
+
+/**
+ * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ * @t: the outgoing tunnel device
+ * @hdr: IPv6 header from the incoming packet
+ *
+ * Description:
+ * Avoid trivial tunneling loop by checking that tunnel exit-point
+ * doesn't match source of incoming packet.
+ *
+ * Return:
+ * 1 if conflict,
+ * 0 else
+ **/
+
+static inline int
+ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+{
+ return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
+}
+
+/**
+ * ip6ip6_tnl_xmit - encapsulate packet and send
+ * @skb: the outgoing socket buffer
+ * @dev: the outgoing tunnel device
+ *
+ * Description:
+ * Build new header and do some sanity checks on the packet before sending
+ * it to ip6_build_xmit().
+ *
+ * Return:
+ * 0
+ **/
+
+int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct net_device_stats *stats = &t->stat;
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ipv6_txoptions *orig_opt = NULL;
+ struct ipv6_txoptions *opt = NULL;
+ __u8 encap_limit = 0;
+ __u16 offset;
+ struct flowi fl;
+ struct ip6_flowlabel *fl_lbl = NULL;
+ int err = 0;
+ struct dst_entry *dst;
+ int link_failure = 0;
+ struct sock *sk = ip6_socket->sk;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ int mtu;
+
+ if (t->recursion++) {
+ stats->collisions++;
+ goto tx_err;
+ }
+ if (skb->protocol != htons(ETH_P_IPV6) ||
+ !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
+ ip6ip6_tnl_addr_conflict(t, ipv6h)) {
+ goto tx_err;
+ }
+ if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
+ if (tel->encap_limit <= 1) {
+ icmpv6_send(skb, ICMPV6_PARAMPROB,
+ ICMPV6_HDR_FIELD, offset + 2, skb->dev);
+ goto tx_err;
+ }
+ encap_limit = tel->encap_limit - 1;
+ } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
+ encap_limit = t->parms.encap_limit;
+ }
+ ip6_xmit_lock();
+
+ memcpy(&fl, &t->fl, sizeof (fl));
+
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+
+ if (fl.fl6_flowlabel) {
+ fl_lbl = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (fl_lbl)
+ orig_opt = fl_lbl->opt;
+ }
+ if (encap_limit > 0) {
+ if (!(opt = merge_options(sk, encap_limit, orig_opt))) {
+ goto tx_err_free_fl_lbl;
+ }
+ } else {
+ opt = orig_opt;
+ }
+ dst = __sk_dst_check(sk, np->dst_cookie);
+
+ if (dst) {
+ if (np->daddr_cache == NULL ||
+ ipv6_addr_cmp(&fl.fl6_dst, np->daddr_cache) ||
+ (fl.oif && fl.oif != dst->dev->ifindex)) {
+ dst = NULL;
+ }
+ }
+ if (dst == NULL) {
+ dst = ip6_route_output(sk, &fl);
+ if (dst->error) {
+ stats->tx_carrier_errors++;
+ link_failure = 1;
+ goto tx_err_dst_release;
+ }
+ /* local routing loop */
+ if (dst->dev == dev) {
+ stats->collisions++;
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Local routing loop detected!\n",
+ t->parms.name);
+ goto tx_err_dst_release;
+ }
+ ipv6_addr_copy(&np->daddr, &fl.fl6_dst);
+ ipv6_addr_copy(&np->saddr, &fl.fl6_src);
+ }
+ mtu = dst_pmtu(dst) - sizeof (*ipv6h);
+ if (opt) {
+ mtu -= (opt->opt_nflen + opt->opt_flen);
+ }
+ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
+ if (skb->dst && mtu < dst_pmtu(skb->dst)) {
+ struct rt6_info *rt = (struct rt6_info *) skb->dst;
+ rt->rt6i_flags |= RTF_MODIFIED;
+ rt->u.dst.metrics[RTAX_MTU-1] = mtu;
+ }
+ if (skb->len > mtu) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+ goto tx_err_opt_release;
+ }
+ err = ip6_append_data(sk, ip_generic_getfrag, skb->nh.raw, skb->len, 0,
+ t->parms.hop_limit, opt, &fl,
+ (struct rt6_info *)dst, MSG_DONTWAIT);
+
+ if (err) {
+ ip6_flush_pending_frames(sk);
+ } else {
+ err = ip6_push_pending_frames(sk);
+ err = (err < 0 ? err : 0);
+ }
+ if (!err) {
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ } else {
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+ }
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+
+ fl6_sock_release(fl_lbl);
+ ip6_dst_store(sk, dst, &np->daddr);
+ ip6_xmit_unlock();
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+tx_err_dst_release:
+ dst_release(dst);
+tx_err_opt_release:
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+tx_err_free_fl_lbl:
+ fl6_sock_release(fl_lbl);
+ ip6_xmit_unlock();
+ if (link_failure)
+ dst_link_failure(skb);
+tx_err:
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+}
+
+static void ip6_tnl_set_cap(struct ip6_tnl *t)
+{
+ struct ip6_tnl_parm *p = &t->parms;
+ struct in6_addr *laddr = &p->laddr;
+ struct in6_addr *raddr = &p->raddr;
+ int ltype = ipv6_addr_type(laddr);
+ int rtype = ipv6_addr_type(raddr);
+
+ p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
+
+ if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
+ ((ltype|rtype) &
+ (IPV6_ADDR_UNICAST|
+ IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
+ IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
+ struct net_device *ldev = NULL;
+ int l_ok = 1;
+ int r_ok = 1;
+
+ if (p->link)
+ ldev = dev_get_by_index(p->link);
+
+ if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
+ l_ok = 0;
+
+ if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
+ r_ok = 0;
+
+ if (l_ok && r_ok) {
+ if (ltype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_XMIT;
+ if (rtype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_RCV;
+ }
+ if (ldev)
+ dev_put(ldev);
+ }
+}
+
+
+static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
+{
+ struct net_device *dev = t->dev;
+ struct ip6_tnl_parm *p = &t->parms;
+ struct flowi *fl;
+ /* Set up flowi template */
+ fl = &t->fl;
+ ipv6_addr_copy(&fl->fl6_src, &p->laddr);
+ ipv6_addr_copy(&fl->fl6_dst, &p->raddr);
+ fl->oif = p->link;
+ fl->fl6_flowlabel = 0;
+
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
+ fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
+
+ ip6_tnl_set_cap(t);
+
+ if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
+ dev->flags |= IFF_POINTOPOINT;
+ else
+ dev->flags &= ~IFF_POINTOPOINT;
+
+ if (p->flags & IP6_TNL_F_CAP_XMIT) {
+ struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
+ p->link, 0);
+ if (rt) {
+ struct net_device *rtdev;
+ if (!(rtdev = rt->rt6i_dev) ||
+ rtdev->type == ARPHRD_TUNNEL6) {
+ /* as long as tunnels use the same socket
+ for transmission, locally nested tunnels
+ won't work */
+ dst_release(&rt->u.dst);
+ goto no_link;
+ } else {
+ dev->iflink = rtdev->ifindex;
+ dev->hard_header_len = rtdev->hard_header_len +
+ sizeof (struct ipv6hdr);
+ dev->mtu = rtdev->mtu - sizeof (struct ipv6hdr);
+ if (dev->mtu < IPV6_MIN_MTU)
+ dev->mtu = IPV6_MIN_MTU;
+
+ dst_release(&rt->u.dst);
+ }
+ }
+ } else {
+ no_link:
+ dev->iflink = 0;
+ dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
+ dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+ }
+}
+
+/**
+ * ip6ip6_tnl_change - update the tunnel parameters
+ * @t: tunnel to be changed
+ * @p: tunnel configuration parameters
+ * @active: != 0 if tunnel is ready for use
+ *
+ * Description:
+ * ip6ip6_tnl_change() updates the tunnel parameters
+ **/
+
+static int
+ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+{
+ ipv6_addr_copy(&t->parms.laddr, &p->laddr);
+ ipv6_addr_copy(&t->parms.raddr, &p->raddr);
+ t->parms.flags = p->flags;
+ t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1);
+ t->parms.encap_limit = p->encap_limit;
+ t->parms.flowinfo = p->flowinfo;
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ * @dev: virtual device associated with tunnel
+ * @ifr: parameters passed from userspace
+ * @cmd: command to be performed
+ *
+ * Description:
+ * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
+ * from userspace.
+ *
+ * The possible commands are the following:
+ * %SIOCGETTUNNEL: get tunnel parameters for device
+ * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
+ * %SIOCCHGTUNNEL: change tunnel parameters to those given
+ * %SIOCDELTUNNEL: delete tunnel
+ *
+ * The fallback device "ip6tnl0", created during module
+ * initialization, can be used for creating other tunnel devices.
+ *
+ * Return:
+ * 0 on success,
+ * %-EFAULT if unable to copy data to or from userspace,
+ * %-EPERM if current process hasn't %CAP_NET_ADMIN set
+ * %-EINVAL if passed tunnel parameters are invalid,
+ * %-EEXIST if changing a tunnel's parameters would cause a conflict
+ * %-ENODEV if attempting to change or delete a nonexisting device
+ **/
+
+static int
+ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ int create;
+ struct ip6_tnl_parm p;
+ struct ip6_tnl *t = NULL;
+
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p,
+ ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
+ t = (struct ip6_tnl *) dev->priv;
+ else if (err)
+ break;
+ } else
+ t = (struct ip6_tnl *) dev->priv;
+
+ memcpy(&p, &t->parms, sizeof (p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+ err = -EFAULT;
+ }
+ break;
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ create = (cmd == SIOCADDTUNNEL);
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if (!create && dev != &ip6ip6_fb_tnl_dev) {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
+ break;
+ }
+ if (cmd == SIOCCHGTUNNEL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ ip6ip6_tnl_unlink(t);
+ err = ip6ip6_tnl_change(t, &p);
+ ip6ip6_tnl_link(t);
+ netdev_state_change(dev);
+ }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data,
+ &t->parms, sizeof (p))) {
+ err = -EFAULT;
+ } else {
+ err = 0;
+ }
+ break;
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ err = ip6ip6_tnl_locate(&p, &t, 0);
+ if (err)
+ break;
+ if (t == &ip6ip6_fb_tnl) {
+ err = -EPERM;
+ break;
+ }
+ } else {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ err = ip6_tnl_destroy(t);
+ break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/**
+ * ip6ip6_tnl_get_stats - return the stats for tunnel device
+ * @dev: virtual device associated with tunnel
+ *
+ * Return: stats for device
+ **/
+
+static struct net_device_stats *
+ip6ip6_tnl_get_stats(struct net_device *dev)
+{
+ return &(((struct ip6_tnl *) dev->priv)->stat);
+}
+
+/**
+ * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
+ * @dev: virtual device associated with tunnel
+ * @new_mtu: the new mtu
+ *
+ * Return:
+ * 0 on success,
+ * %-EINVAL if mtu too small
+ **/
+
+static int
+ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < IPV6_MIN_MTU) {
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
+ * @dev: virtual device associated with tunnel
+ *
+ * Description:
+ * Set function pointers and initialize the &struct flowi template used
+ * by the tunnel.
+ **/
+
+static void
+ip6ip6_tnl_dev_init_gen(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct flowi *fl = &t->fl;
+
+ memset(fl, 0, sizeof (*fl));
+ fl->proto = IPPROTO_IPV6;
+
+ dev->destructor = ip6ip6_tnl_dev_destructor;
+ dev->uninit = ip6ip6_tnl_dev_uninit;
+ dev->hard_start_xmit = ip6ip6_tnl_xmit;
+ dev->get_stats = ip6ip6_tnl_get_stats;
+ dev->do_ioctl = ip6ip6_tnl_ioctl;
+ dev->change_mtu = ip6ip6_tnl_change_mtu;
+ dev->type = ARPHRD_TUNNEL6;
+ dev->flags |= IFF_NOARP;
+ if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST &&
+ ipv6_addr_type(&t->parms.laddr) & IPV6_ADDR_UNICAST)
+ dev->flags |= IFF_POINTOPOINT;
+ /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be
+ copied to dev->dev_addr and dev->broadcast, like the ipv4
+ addresses were in ipip.c, ip_gre.c and sit.c. */
+ dev->addr_len = 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
+ * @dev: virtual device associated with tunnel
+ **/
+
+static int
+ip6ip6_tnl_dev_init(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_dev_init_gen(dev);
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
+ * @dev: fallback device
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_fb_tnl_dev_init(struct net_device *dev)
+{
+ ip6ip6_tnl_dev_init_gen(dev);
+ tnls_wc[0] = &ip6ip6_fb_tnl;
+ return 0;
+}
+
+static struct inet6_protocol ip6ip6_protocol = {
+ .handler = ip6ip6_rcv,
+ .err_handler = ip6ip6_err,
+ .flags = INET6_PROTO_FINAL
+};
+
+/**
+ * ip6_tunnel_init - register protocol and reserve needed resources
+ *
+ * Return: 0 on success
+ **/
+
+int __init ip6_tunnel_init(void)
+{
+ int i, j, err;
+ struct sock *sk;
+ struct ipv6_pinfo *np;
+
+ ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+
+ err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6,
+ &__ip6_socket[i]);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Failed to create the IPv6 tunnel socket "
+ "(err %d).\n",
+ err);
+ goto fail;
+ }
+ sk = __ip6_socket[i]->sk;
+ sk->allocation = GFP_ATOMIC;
+
+ np = inet6_sk(sk);
+ np->hop_limit = 255;
+ np->mc_loop = 0;
+
+ sk->prot->unhash(sk);
+ }
+ if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) {
+ printk(KERN_ERR "Failed to register IPv6 protocol\n");
+ goto fail;
+ }
+
+ SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev);
+ register_netdev(&ip6ip6_fb_tnl_dev);
+
+ return 0;
+fail:
+ for (j = 0; j < i; j++) {
+ if (!cpu_possible(j))
+ continue;
+ sock_release(__ip6_socket[j]);
+ __ip6_socket[j] = NULL;
+ }
+ return err;
+}
+
+/**
+ * ip6_tunnel_cleanup - free resources and unregister protocol
+ **/
+
+void ip6_tunnel_cleanup(void)
+{
+ int i;
+
+ unregister_netdev(&ip6ip6_fb_tnl_dev);
+
+ inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+ sock_release(__ip6_socket[i]);
+ __ip6_socket[i] = NULL;
+ }
+}
+
+#ifdef MODULE
+module_init(ip6_tunnel_init);
+module_exit(ip6_tunnel_cleanup);
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ipv6_syms.c merge-2.5/net/ipv6/ipv6_syms.c
--- linux-2.5/net/ipv6/ipv6_syms.c Wed Jun 4 13:43:09 2003
+++ merge-2.5/net/ipv6/ipv6_syms.c Wed May 28 21:12:02 2003
@@ -38,3 +38,11 @@
EXPORT_SYMBOL(ip6_found_nexthdr);
EXPORT_SYMBOL(xfrm6_rcv);
EXPORT_SYMBOL(xfrm6_clear_mutable_options);
+#ifdef CONFIG_IPV6_TUNNEL_MODULE
+EXPORT_SYMBOL(rt6_lookup);
+EXPORT_SYMBOL(fl6_sock_lookup);
+EXPORT_SYMBOL(ipv6_ext_hdr);
+EXPORT_SYMBOL(ip6_append_data);
+EXPORT_SYMBOL(ip6_flush_pending_frames);
+EXPORT_SYMBOL(ip6_push_pending_frames);
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/netsyms.c merge-2.5/net/netsyms.c
--- linux-2.5/net/netsyms.c Wed Jun 4 13:43:10 2003
+++ merge-2.5/net/netsyms.c Wed May 28 21:12:02 2003
@@ -477,8 +477,10 @@
EXPORT_SYMBOL(sysctl_max_syn_backlog);
#endif
-EXPORT_SYMBOL(ip_generic_getfrag);
+#endif
+#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) || defined (CONFIG_IPV6_TUNNEL_MODULE)
+EXPORT_SYMBOL(ip_generic_getfrag);
#endif
EXPORT_SYMBOL(tcp_read_sock);
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 4:38 ` David S. Miller
@ 2003-06-04 14:30 ` Henrik Petander
2003-06-04 15:49 ` YOSHIFUJI Hideaki / 吉藤英明
0 siblings, 1 reply; 37+ messages in thread
From: Henrik Petander @ 2003-06-04 14:30 UTC (permalink / raw)
To: David S. Miller
Cc: yoshfuji, vnuorval, kuznet, netdev, ajtuomin, lpetande, jagana,
kumarkr
David S. Miller wrote:
> I am VERY UPSET that there appears to be NO dialogue between USAGI and
> MIPV6 folks to discuss design of MIPV6. If you do not talk together,
> how can you guys possibly coordinate efforts and not avoid duplicated
> work?
I am sorry about the long delay in the extension header addition
mechanism discussion. The issues involved with interactions between xfrm
stacked destinations and mipv6 were at least to me somewhat fuzzy. To
understand them better we developed a prototype of the mipv6 extension
header addition and processing. This unfortunately took too long, due to
other work.
In any case, I hope we can all work better together from now on. In
hopes of starting a working dialogue, I'll try to summarize the current
situation on our side.
1. Tunnel
The tunneling code should be ready, Ville just sent a patch without
dependancies on source address based routing. All received and future
comments about that are highly appreciated.
2. Source address based routing
Ville sent the patch. The semantical changes to the original code were
in our opinion necessary to get source address based routing working
more as IPv4 policy routing. Let's discuss this more.
3. API
We've added kernel support for the API to accept routing header type 2
and to do the additional checks necessary. Also home address option
API support has been written. In fact, you can add any destination
option to the new DO position with this.
There is a (sub)group working on MIPv6 extensions to the Advanced Socket
API for IPv6. To me it seems pointless to add anything other to the
spec than a way to insert a destination option header to the third
possible DO position (i.e. between routing header and fragmentation
header). This could be done just by adding new type, let's call it
IPV6_NOFRAGDSTOPTS. Everything else should be doable with the
existing ASA. We would like to hear comments on this.
Is a rtnetlink extension enough for adding mobility routes or do
we need to support ioctl too?
4. Source address selection
We think adding new home address flag to addresses is the best and
easiest way making the source address selection to work with MIPv6.
I'm sure USAGI will add the relevant checks to their source address
selection code for that. Dave, Antti already brought this up some weeks
ago, but got no answer. Is the home address bit OK with you?
5. MIPv6 extension header adding
We have been also testing how the mipv6 extension header adding would
work in practice through the development of a prototype for the purpose.
Based on the work it seems (to me) that the use of xfrm for storing the
mipv6 stuff conflicts with its primary use, especially if there are
overlapping entries for IPSec and MIPv6.
Storing of the mipv6 information would in our opinion be achieved more
cleanly by using cached routes which included the mipv6 information (two
extra addresses and flags). The routes would contain modified nexthop
information and mip6_output as the rt->u.dst.output function.
Mip6_output would add the extension headers based on the information
stored in the route. The routes would have a stacked dst entry, which
would be used for actual output.
Our prototype currently works with tcp, tcp + ipsec and raw sockets,
but has only a hackish interface through route ioctl for testing. I can
send a preview patch of the code for discussion, if the general approach
makes sense to you. I would like to hear your opinions on this and also
if you (USAGI) have planned something else for storing the mipv6 state.
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 14:30 ` Henrik Petander
@ 2003-06-04 15:49 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 17:31 ` Henrik Petander
2003-06-05 12:40 ` Ville Nuorvala
0 siblings, 2 replies; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-04 15:49 UTC (permalink / raw)
To: lpetande
Cc: davem, vnuorval, kuznet, netdev, ajtuomin, lpetande, jagana,
kumarkr
Hello.
In article <3EDE0286.4000304@tml.hut.fi> (at Wed, 04 Jun 2003 17:30:30 +0300), Henrik Petander <lpetande@tml.hut.fi> says:
> 2. Source address based routing
>
> Ville sent the patch. The semantical changes to the original code were
> in our opinion necessary to get source address based routing working
> more as IPv4 policy routing. Let's discuss this more.
I'm not sure why you need this (and tunnel) for MIP...
Would you clearify for me?
(IMHO, I believe we don't need this change if we use XFRM engine.)
BTW, source based routing (source address is major, destination is minor)
is done by policy routing; It is NOT the task of CONFIG_IPV6_SUBTREE, IMHO.
Yes, poeple want to have policy routing, but it is NOT (only) for MIP6.
> 3. API
:
> There is a (sub)group working on MIPv6 extensions to the Advanced Socket
> API for IPv6. To me it seems pointless to add anything other to the
> spec than a way to insert a destination option header to the third
> possible DO position (i.e. between routing header and fragmentation
> header). This could be done just by adding new type, let's call it
> IPV6_NOFRAGDSTOPTS. Everything else should be doable with the
> existing ASA. We would like to hear comments on this.
No, user daemon adds a XFRM policy for adding destination option
(and/or routing header). Stackable destination will do the real work.
(So, we don't need socket options.)
> 4. Source address selection
>
> We think adding new home address flag to addresses is the best and
> easiest way making the source address selection to work with MIPv6.
> I'm sure USAGI will add the relevant checks to their source address
> selection code for that. Dave, Antti already brought this up some weeks
> ago, but got no answer. Is the home address bit OK with you?
"Yes," is my answer for now.
> 5. MIPv6 extension header adding
:
> Storing of the mipv6 information would in our opinion be achieved more
> cleanly by using cached routes which included the mipv6 information (two
> extra addresses and flags). The routes would contain modified nexthop
> information and mip6_output as the rt->u.dst.output function.
> Mip6_output would add the extension headers based on the information
> stored in the route. The routes would have a stacked dst entry, which
> would be used for actual output.
I still belive it is very natural to use XFRM to manage stackable
destination.
> Our prototype currently works with tcp, tcp + ipsec and raw sockets,
> but has only a hackish interface through route ioctl for testing. I can
> send a preview patch of the code for discussion, if the general approach
> makes sense to you. I would like to hear your opinions on this and also
> if you (USAGI) have planned something else for storing the mipv6 state.
Okay, anyway, please sent it to David, Alexey and me (at least).
We can learn more from the code than documentation. ;-)
Thank you.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 15:49 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-04 17:31 ` Henrik Petander
2003-06-05 8:36 ` Ville Nuorvala
2003-06-05 12:40 ` Ville Nuorvala
1 sibling, 1 reply; 37+ messages in thread
From: Henrik Petander @ 2003-06-04 17:31 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明
Cc: davem, vnuorval, kuznet, netdev@oss.sgi.com, ajtuomin,
Venkata Jagana, kumarkr
Hello Yoshifuji,
On Thu, 5 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> In article <3EDE0286.4000304@tml.hut.fi> (at Wed, 04 Jun 2003 17:30:30 +0300), Henrik Petander <lpetande@tml.hut.fi> says:
>
> > 2. Source address based routing
>
> I'm not sure why you need this (and tunnel) for MIP...
> Would you clearify for me?
> (IMHO, I believe we don't need this change if we use XFRM engine.)
As far as I remember there are three main reasons for this: (Ville
correct me if forgot something)
1. Mobile node sends packets to correspondent node through the tunnel, if
they have home address as the IPv6 source address (not in home address
option). MIPv6 signalling packets are sent at the same time with the home
address option (i.e. care-of address as the source address in IPv6 header)
to the same destination, but they must not be sent through the tunnel.
If the xfrm engine works correctly (for IPSec) and does the lookup using
the home address as the source address, the flows appear the same based on
the addresses.
2. Home Agent delivers packets with its own address as source address to
mobile node using route optimization, i.e. routing header type 2, but
tunnels other traffic to MN. Again behaviour depends on the source
address.
3. Multihomed mobile hosts: Mobile nodes can have a cellular and WLAN
interface. Packets with address from one interface can be sent only
through that interface to avoid RPF dropping the traffic. With routing
based primarily on source addresses this is easy to achieve. Actually this
is more general than MIPv6, but multihoming is essential for
real-life mobility.
>
> BTW, source based routing (source address is major, destination is minor)
> is done by policy routing; It is NOT the task of CONFIG_IPV6_SUBTREE, IMHO.
> Yes, poeple want to have policy routing, but it is NOT (only) for MIP6.
IMO source address subtrees were useless as they were at least for doing
mobility and multihoming, whereas with source address as primary selector
routing for mobile and multihomed hosts is straightforward. Of course I
may miss something of the larger picture ;-) But so far I have heard of no
one using them for anything else. As long as Linux lacks "real" IPv6
policy routing, source based routing is the best we have got and works
both for mobility and multihoming. The main problem with it is IMO
the source address selection using the route as a selection basis. Just my
thoughts, though.
>
> > 3. API
>
> No, user daemon adds a XFRM policy for adding destination option
> (and/or routing header). Stackable destination will do the real work.
> (So, we don't need socket options.)
Actually we do... Due to some interesting requirements in the MIPv6 spec.
the signalling packets are treated differently from data packets: home
address option is always present in binding update messages, but it can be
used with data packets only after sending a binding update. Routing
header type 2 is used in negative binding acks sometimes with addresses
which differ from the ones used with data packets.
The signalling packets need IPSec protection with final addresses as
selectors, so the MIPv6 extension headers can't be added to packets
created by a raw socket as the final addresses would be hidden in the
extension headers.
>
> > 5. MIPv6 extension header adding
> I still belive it is very natural to use XFRM to manage stackable
> destination.
If you have a concrete proposal how to do it, I would be eager to hear it
;-)
> Okay, anyway, please sent it to David, Alexey and me (at least).
> We can learn more from the code than documentation. ;-)
Sure, I'll send it tomorrow when i get back to work.
Regards,
Henrik
----------------------------------
Henrik Petander
Helsinki University of Technology,
GO/Core Project
Henrik.Petander@hut.fi
Office: +358 (0)9 451 5846
GSM: +358 (0)40 741 5248
----------------------------------
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 17:31 ` Henrik Petander
@ 2003-06-05 8:36 ` Ville Nuorvala
0 siblings, 0 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-05 8:36 UTC (permalink / raw)
To: Henrik Petander
Cc: YOSHIFUJI Hideaki / 吉藤英明, davem,
kuznet, netdev@oss.sgi.com, ajtuomin, Venkata Jagana, kumarkr
On Wed, 4 Jun 2003, Henrik Petander wrote:
> Hello Yoshifuji,
>
> On Thu, 5 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> > In article <3EDE0286.4000304@tml.hut.fi> (at Wed, 04 Jun 2003 17:30:30 +0300), Henrik Petander <lpetande@tml.hut.fi> says:
> >
> > > 2. Source address based routing
> >
> > I'm not sure why you need this (and tunnel) for MIP...
> > Would you clearify for me?
> > (IMHO, I believe we don't need this change if we use XFRM engine.)
>
> As far as I remember there are three main reasons for this: (Ville
> correct me if forgot something)
I think you've got all the main reasons. I'll get back to this issue
if I suddenly remember something you forgot. :)
-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
2003-05-30 20:38 ` Venkata Jagana
2003-06-03 6:35 ` Ville Nuorvala
@ 2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-06 5:38 ` Masahide NAKAMURA
2003-06-06 8:48 ` Ville Nuorvala
2 siblings, 2 replies; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-05 10:12 UTC (permalink / raw)
To: vnuorval
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr,
yoshfuji, nakam, usagi-core
In article <20030531.000319.114704530.yoshfuji@linux-ipv6.org> (at Sat, 31 May 2003 00:03:19 +0900 (JST)), YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> says:
> In article <Pine.LNX.4.44.0305301712300.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 17:34:40 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
>
> > here is a patch that fixes CONFIG_IPV6_SUBTREES and allows overriding
> > normal routes with source address specific ones. This is for example
> > needed in MIPv6 for handling the traffic to and from a mobile node's home
> > address correctly.
>
> Let us test the patch. It seemed buggy when USAGI tested before.
I've re-tested your latest CONFIG_IPV6_SUBTREE patch.
The results of the restesting seems fine.
However, I won't accept your patch as-is for now.
The patch consists of several parts:
1. fixing bugs in IPv6 code
2. fixing bugs in CONFIG_IPV6_SUBTREE code
3. changing majority of keys of routing table.
There's no problems with 1 and 2.
However, We need to discuss on 3.
As I said in other thread, the policy routing should be done in the
other way. And, it is not good to change the semantics of
CONFIG_IPV6_SUBTREE.
In original, routing is looked up by destination address, and then,
looked up by the source address; destination takes precedence over source.
Your patch changes this. Source address takes precedence over destination
address.
>From the point of the policy routing, both (and other attributes) should be
considered equally, and this is what IPv4 routing table does.
Well, I won't hurry intorducing IPv6 policy routing just because of MIP6.
The reason why I won't hurry is because I still believe it is not
required for MIP6. Nakamura, one of our member, will describe the details.
It takes precedence over "limited" policy(?) routing to introcuce generic
policy routing.
Anyway, will you split up your patch (into 1-3 above) first, please?
Thanks.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 15:49 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 17:31 ` Henrik Petander
@ 2003-06-05 12:40 ` Ville Nuorvala
1 sibling, 0 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-05 12:40 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明
Cc: lpetande, davem, kuznet, netdev, ajtuomin, lpetande, jagana,
kumarkr
On Thu, 5 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> In article <3EDE0286.4000304@tml.hut.fi> (at Wed, 04 Jun 2003 17:30:30 +0300), Henrik Petander <lpetande@tml.hut.fi> says:
>
> > 2. Source address based routing
>
> I'm not sure why you need this (and tunnel) for MIP...
> Would you clearify for me?
> (IMHO, I believe we don't need this change if we use XFRM engine.)
>
A few comments about the tunnels:
Can you run link-scope protocols over an XFRM tunnel? The MIPv6 spec more
or less requires this feature if you are to support protocols like DHCPv6
and MLD. (See eg. sections 8.5, 10.4.3 and 10.4.4 in the MIPv6 draft 22).
The only way to get them to work is AFAICS that there is a virtual
net_device associated with every tunnel. Are XFRM tunnels like this?
At least they didn't seem to be, based on the xfrm6_tunnel patch sent to
netdev last week...
If the tunnels aren't separate devices I can straight away think of one
scenario where we run into trouble.
1. MN receives RA with M or O flags set from a router on the foreign
link.
2. MN receives a MPA with M or O flags set from HA.
In the first case the DHCP queries should be sent to the current link the
MN is attached to, in the latter to the HA.
I dont see any way for the MN to separate these two cases while sending
the DHCP queries, _unless_ they are sent through different interfaces
(i.e. the physical vs the virtual tunnel interface).
On a more general note, the driver I sent aims to provide provide a
completely RFC 2473 compliant tunnel interface. :)
Things (at the moment) missing from the xfrm6_tunnel are at least:
- tunnel encapsulation limit destination sub-option support
- forwarding of ICMP errors to the original source of the packet
- transparent fragmentation of packets if MTU minus size of tunnel
headers less than IPV6_MIN_MTU
- ability to configure things like traffic class and flowlabel of
encapsulating ipv6 header
Perhaps we could make feature complete ip6ip6 tunnels if we combined
xfrm6_tunnel and ip6_tunnel? :)
Regards,
Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-06 5:38 ` Masahide NAKAMURA
2003-06-06 11:14 ` Henrik Petander
2003-06-06 8:48 ` Ville Nuorvala
1 sibling, 1 reply; 37+ messages in thread
From: Masahide NAKAMURA @ 2003-06-06 5:38 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明, vnuorval,
davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr
Cc: usagi-core
Hello,
I'm Nakamura, a member of USAGI.
On Thu, 05 Jun 2003 19:12:24 +0900 (JST)
YOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org> wrote:
> Well, I won't hurry intorducing IPv6 policy routing just because of MIP6.
> The reason why I won't hurry is because I still believe it is not
> required for MIP6. Nakamura, one of our member, will describe the details.
> It takes precedence over "limited" policy(?) routing to introcuce generic
> policy routing.
As you know, we've been planning the MIPv6 design to use XFRM.
If we use MIPv6, we need some fix and extension to XFRM and it results to make XFRM
more generic.
On output processing, our design is like below:
Through netlink/xfrm from userland, we have to set xfrm_policy and xfrm_state with
something like ip command(or extended ip command).
The xfrm_policy has two templates now:
- template handling Routing Header type 2(RT2) ...(a)
- template handling Destination Options Header(DST) ...(b)
And we have to add one address field(c) in xfrm_state for MIPv6.
(Currently it is named mip6_state.addr.)
Template-(a) finds a xfrm_state that points function like mip6_rthdr_output()
to insert RT2 and replace dst address of IP header with specified address-(c).
Also, template-(b) finds a xfrm_state that points function like mip6_destopt_output()
to insert DST and replace src address of IP header with specified address-(c).
Of course, both mip6_rthdr_output() and mip6_destopt_output() are callled as dst_output
in XFRM world internally.
For example, if two state is found, the packet will be append both RT2 and DST.
We have tested that on our tree.
In case of tunneling, We think we also make it to add a template and
prepare a function for dst_output on XFRM world like above.
(Maybe xfrm6_tunnel needs some fix to use MIPv6, as Henrik said.)
Could you give us comments?
BTW, I have read Henrik's patch(mip6-exthdr.patch) sent to netdev in other thread and I
feel that is simple code to implement MIPv6 and is clean one. Thanks, Henrik.
As he said, it is similar one to use XFRM like ours.
We know that the big difference between yours and ours is to modify either routing table or
XFRM.
Anyway, we'll show you our patch later.
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-06 5:38 ` Masahide NAKAMURA
@ 2003-06-06 8:48 ` Ville Nuorvala
2003-06-06 10:32 ` CONFIG_IPV6_SUBTREES (was [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6) YOSHIFUJI Hideaki / 吉藤英明
1 sibling, 1 reply; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-06 8:48 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr, nakam,
usagi-core
On Thu, 5 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> In article <20030531.000319.114704530.yoshfuji@linux-ipv6.org> (at Sat, 31 May 2003 00:03:19 +0900 (JST)), YOSHIFUJI Hideaki / ^[$B5HF#1QL@^[(B <yoshfuji@linux-ipv6.org> says:
>
> > In article <Pine.LNX.4.44.0305301712300.3584-200000@rhea.tcs.hut.fi> (at Fri, 30 May 2003 17:34:40 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
> >
> > > here is a patch that fixes CONFIG_IPV6_SUBTREES and allows overriding
> > > normal routes with source address specific ones. This is for example
> > > needed in MIPv6 for handling the traffic to and from a mobile node's home
> > > address correctly.
> >
> > Let us test the patch. It seemed buggy when USAGI tested before.
>
> I've re-tested your latest CONFIG_IPV6_SUBTREE patch.
> The results of the restesting seems fine.
Great! :)
> However, I won't accept your patch as-is for now.
>
> The patch consists of several parts:
>
> 1. fixing bugs in IPv6 code
> 2. fixing bugs in CONFIG_IPV6_SUBTREE code
> 3. changing majority of keys of routing table.
>
> There's no problems with 1 and 2.
> However, We need to discuss on 3.
I have of course no objections against 1. :)
However 2 and 3 are in my view quite interrelated.
> As I said in other thread, the policy routing should be done in the
> other way. And, it is not good to change the semantics of
> CONFIG_IPV6_SUBTREE.
Even if the semantics are flawed? I'll try to explain my reasoning below.
> In original, routing is looked up by destination address, and then,
> looked up by the source address; destination takes precedence over source.
> Your patch changes this. Source address takes precedence over destination
> address.
The main problem with the original destination,source lookup are the
cached host routes created by ip6_route_{input,output} (or actually
rt6_cow).
Since these routes have destination prefix length 128, they will override
all source routes, unless they also are host routes.
This happens because the (non-host) source route ends up in the subtree of
a node higher up in the destination tree, which will never be reached
because the cached host route already matches the destination address.
Since the initial mode of communication between a mobile node (using its
home address) and any correspondent node is reverse tunneling we at least
need something like a default (i.e. a non-host) route through the tunnel
for the MN's home address.
Not until route optimization is set up between the MN and the CN do we
actually get host routes for the traffic between the two.
If we switch the order of keys to source,destination we don't get this
problem since the cached host routes end up at the bottom of the subtrees
and wont interfere with the normal routing.
Prefix routes also cause problems with the destination,source key order,
since we must create a duplicate route for each prefix and home address.
Hope I explained it clearly enough :)
> From the point of the policy routing, both (and other attributes) should be
> considered equally, and this is what IPv4 routing table does.
This of course seems like the optimal solution.
> Well, I won't hurry intorducing IPv6 policy routing just because of MIP6.
> The reason why I won't hurry is because I still believe it is not
> required for MIP6. Nakamura, one of our member, will describe the details.
> It takes precedence over "limited" policy(?) routing to introcuce generic
> policy routing.
I still think _some_ routing changes are necessary, but I guess we need to
discuss what the changes are. I'm btw willing to help with the IPv6 policy
routing if that helps getting it into the kernel sooner.
> Anyway, will you split up your patch (into 1-3 above) first, please?
I'll check if there still is anything to do in 1 after the patch you
already submitted, but let's please discuss 3 before I split it into 2 and
3.
Thanks,
Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: CONFIG_IPV6_SUBTREES (was [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6)
2003-06-06 8:48 ` Ville Nuorvala
@ 2003-06-06 10:32 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-06 11:16 ` Ville Nuorvala
0 siblings, 1 reply; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-06 10:32 UTC (permalink / raw)
To: vnuorval
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr, nakam,
usagi-core
In article <Pine.LNX.4.44.0306052009580.32033-100000@rhea.tcs.hut.fi> (at Fri, 6 Jun 2003 11:48:36 +0300 (EEST)), Ville Nuorvala <vnuorval@tcs.hut.fi> says:
> Since the initial mode of communication between a mobile node (using its
> home address) and any correspondent node is reverse tunneling we at least
> need something like a default (i.e. a non-host) route through the tunnel
> for the MN's home address.
Excuse me, please forget anything related to "Mobile IP" during this
discussion; do not assume that Mobile IP is the only user of
CONFIG_IPV6_SUBTREES.
Thank you.
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-06 5:38 ` Masahide NAKAMURA
@ 2003-06-06 11:14 ` Henrik Petander
2003-06-06 13:31 ` Masahide NAKAMURA
0 siblings, 1 reply; 37+ messages in thread
From: Henrik Petander @ 2003-06-06 11:14 UTC (permalink / raw)
To: Masahide NAKAMURA
Cc: YOSHIFUJI Hideaki / 吉藤英明, vnuorval,
davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr,
usagi-core
Hello Nakamura,
Masahide NAKAMURA wrote:
> Hello,
> I'm Nakamura, a member of USAGI.
>
>
> As you know, we've been planning the MIPv6 design to use XFRM.
> If we use MIPv6, we need some fix and extension to XFRM and it results to make XFRM
> more generic.
I like your idea, as it allows a high level of flexibility in use of
mipv6 with flows through the definition of policies. This is the way I
would also do mipv6 extension header addition with xfrm.
However, if you insert mipv6 policies into xfrm, you need to take care
of the interactions between ipsec and mipv6 policies. The system needs
to cope with data flows to which both ipsec and mipv6 should be applied.
As a result of this the logic of the xfrm lookups probably needs some
changes to return both the matching ipsec and mipv6 policies. How have
you planned to solve this problem?
BTW, feel free to use relevant parts of my code for the output
functionality to speed up the work. After your code is ready we can look
at which approach is better suited for implementing the kernel support
and get a working kernel infrastructure for mipv6 into 2.6 kernels.
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: CONFIG_IPV6_SUBTREES (was [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6)
2003-06-06 10:32 ` CONFIG_IPV6_SUBTREES (was [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6) YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-06 11:16 ` Ville Nuorvala
0 siblings, 0 replies; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-06 11:16 UTC (permalink / raw)
To: YOSHIFUJI Hideaki / 吉藤英明
Cc: davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr, nakam,
usagi-core
On Fri, 6 Jun 2003, YOSHIFUJI Hideaki / [iso-2022-jp] ^[$B5HF#1QL@^[(B wrote:
> Excuse me, please forget anything related to "Mobile IP" during this
> discussion; do not assume that Mobile IP is the only user of
> CONFIG_IPV6_SUBTREES.
At the moment it is :)
I was just making a point about the IMHO flawed semantics of
CONFIG_IPV6_SUBTREES.
If you keep the original (first dest, then src) key ordering you
basically can't use the subtrees for anything else but storing source
address specific host routes.
With the reversed order you can do a lot more...
-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-06 11:14 ` Henrik Petander
@ 2003-06-06 13:31 ` Masahide NAKAMURA
2003-06-09 9:06 ` Henrik Petander
0 siblings, 1 reply; 37+ messages in thread
From: Masahide NAKAMURA @ 2003-06-06 13:31 UTC (permalink / raw)
To: Henrik Petander
Cc: YOSHIFUJI Hideaki / 吉藤英明, vnuorval,
davem, kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr,
usagi-core
Hello Henrik,
On Fri, 06 Jun 2003 14:14:35 +0300
Henrik Petander <lpetande@tml.hut.fi> wrote:
> I like your idea, as it allows a high level of flexibility in use of
> mipv6 with flows through the definition of policies. This is the way I
> would also do mipv6 extension header addition with xfrm.
Thanks.
> However, if you insert mipv6 policies into xfrm, you need to take care
> of the interactions between ipsec and mipv6 policies. The system needs
> to cope with data flows to which both ipsec and mipv6 should be applied.
> As a result of this the logic of the xfrm lookups probably needs some
> changes to return both the matching ipsec and mipv6 policies. How have
> you planned to solve this problem?
We don't think we have to change the logic handling policy with
the reason because we can treat MIPv6 policy just like IPsec.
When we want to apply both MIPv6 and IPsec to the same target,
we need one policy that has two or more of templates(e.g. one is
MIPv6's template and the other is IPsec's).
Regarding above case, however, we have a problem like below:
draft(9.3.1 in draft-ietf-mobileip-ipv6-22) says,
When attempting to verify AH authentication data in a packet that
contains a Home Address option, the receiving node MUST calculate
the AH authentication data as if the following were true: The Home
Address option contains the care-of address, and the source IPv6
address field of the IPv6 header contains the home address.
Because xfrm decides to call dst_output in the order of templates,
at first we had no idea which is the former template, MIPv6 or IPsec(Home
Address Option or AH).
Then we discussed about that with our IPsec guys and now we guess we have
an idea to use xfrm6_clear_mutable_options() to re-replace address for
calculating for AH when calling ah6_output().
Anyway, I think this is not specialized matter of xfrm. (Did you also point
this, Henrik?) Or, could you have any idea?
> BTW, feel free to use relevant parts of my code for the output
> functionality to speed up the work. After your code is ready we can look
> at which approach is better suited for implementing the kernel support
> and get a working kernel infrastructure for mipv6 into 2.6 kernels.
Thank you for your kindness. Of course I agree with you.
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-04 12:40 ` Ville Nuorvala
@ 2003-06-07 10:30 ` David S. Miller
2003-06-07 10:41 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-09 11:43 ` ipv6 tunnel patch (was: Re: [patch]: ipv6 tunnel for MIPv6) Ville Nuorvala
0 siblings, 2 replies; 37+ messages in thread
From: David S. Miller @ 2003-06-07 10:30 UTC (permalink / raw)
To: vnuorval; +Cc: kuznet, yoshfuji, netdev, ajtuomin, lpetande, jagana, kumarkr
From: Ville Nuorvala <vnuorval@tcs.hut.fi>
Date: Wed, 4 Jun 2003 15:40:02 +0300 (EEST)
The revised version is attached to this mail,
Looks ok, but sorry two things need to be fixed up first:
1) Doesn't apply anymore, I think it's because of the
struct sock member renames, just replace sk->foo
with sk->sk_foo
2) Just export all those routines from net/ipv6/ipv6_syms.c
always, remove the ifdefs.
I promise to apply it after you fix this stuff up :)))
Thank you.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: ipv6 tunnel for MIPv6
2003-06-07 10:30 ` David S. Miller
@ 2003-06-07 10:41 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-09 11:43 ` ipv6 tunnel patch (was: Re: [patch]: ipv6 tunnel for MIPv6) Ville Nuorvala
1 sibling, 0 replies; 37+ messages in thread
From: YOSHIFUJI Hideaki / 吉藤英明 @ 2003-06-07 10:41 UTC (permalink / raw)
To: davem, vnuorval; +Cc: kuznet, netdev, ajtuomin, lpetande, jagana, kumarkr
In article <20030607.033059.48393210.davem@redhat.com> (at Sat, 07 Jun 2003 03:30:59 -0700 (PDT)), "David S. Miller" <davem@redhat.com> says:
> I promise to apply it after you fix this stuff up :)))
Please be sure not to include "for MIPv6" from the changeset. :-)
--
Hideaki YOSHIFUJI @ USAGI Project <yoshfuji@linux-ipv6.org>
GPG FP: 9022 65EB 1ECF 3AD1 0BDF 80D8 4807 F894 E062 0EEA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-06 13:31 ` Masahide NAKAMURA
@ 2003-06-09 9:06 ` Henrik Petander
2003-06-09 11:37 ` Masahide NAKAMURA
0 siblings, 1 reply; 37+ messages in thread
From: Henrik Petander @ 2003-06-09 9:06 UTC (permalink / raw)
To: Masahide NAKAMURA
Cc: YOSHIFUJI Hideaki / 吉藤英明, vnuorval,
davem, kuznet, netdev, ajtuomin, jagana, kumarkr, usagi-core
On Fri, 6 Jun 2003, Masahide NAKAMURA wrote:
>
> We don't think we have to change the logic handling policy with
> the reason because we can treat MIPv6 policy just like IPsec.
>
> When we want to apply both MIPv6 and IPsec to the same target,
> we need one policy that has two or more of templates(e.g. one is
> MIPv6's template and the other is IPsec's).
Does this also mean that the IPSec and MIPv6 policies and SAs need to be
configured at the same time or is it possible to add templates to an
existing policy?
>
> Regarding above case, however, we have a problem like below:
>
> draft(9.3.1 in draft-ietf-mobileip-ipv6-22) says,
>
> When attempting to verify AH authentication data in a packet that
> contains a Home Address option, the receiving node MUST calculate
> the AH authentication data as if the following were true: The Home
> Address option contains the care-of address, and the source IPv6
> address field of the IPv6 header contains the home address.
Yes, and this also applies to routing header types 0 and 2. They also need
to be processed by AH so that the addresses are as the receiver sees them
after processing the headers: home address in destination address and
care-of address in the routing header. This is just not said in the mipv6
spec as the routing header IPSec interactions are not specified by it.
>
> Because xfrm decides to call dst_output in the order of templates,
> at first we had no idea which is the former template, MIPv6 or IPsec(Home
> Address Option or AH).
MIPv6 headers should be added first for AH to work.
A different issue related to the different addresses is that the SPD
lookup should be done with the original source address, i.e. home address,
if home address option is used and with the final destination address, if
routing header is used. SPD lookup works now for TCP (with RT header), but
not for raw sockets, which the mipv6 daemon will use. We will provide a
patch for fixing the SPD lookups with raw sockets, which add routing
header and home address option from socket options.
Henrik
----------------------------------
Henrik Petander
Helsinki University of Technology,
GO/Core Project
Henrik.Petander@hut.fi
Office: +358 (0)9 451 5846
GSM: +358 (0)40 741 5248
----------------------------------
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-09 9:06 ` Henrik Petander
@ 2003-06-09 11:37 ` Masahide NAKAMURA
2003-06-10 15:25 ` Henrik Petander
0 siblings, 1 reply; 37+ messages in thread
From: Masahide NAKAMURA @ 2003-06-09 11:37 UTC (permalink / raw)
To: Henrik Petander
Cc: YOSHIFUJI Hideaki / 吉藤英明, vnuorval,
davem, kuznet, netdev, ajtuomin, jagana, kumarkr, usagi-core
On Mon, 9 Jun 2003 12:06:35 +0300 (EEST)
Henrik Petander <lpetande@morphine.tml.hut.fi> wrote:
> On Fri, 6 Jun 2003, Masahide NAKAMURA wrote:
> >
> > We don't think we have to change the logic handling policy with
> > the reason because we can treat MIPv6 policy just like IPsec.
> >
> > When we want to apply both MIPv6 and IPsec to the same target,
> > we need one policy that has two or more of templates(e.g. one is
> > MIPv6's template and the other is IPsec's).
>
> Does this also mean that the IPSec and MIPv6 policies and SAs need to be
> configured at the same time or is it possible to add templates to an
> existing policy?
Currently no interface to add templates directly to it.
:
> A different issue related to the different addresses is that the SPD
> lookup should be done with the original source address, i.e. home address,
> if home address option is used and with the final destination address, if
> routing header is used. SPD lookup works now for TCP (with RT header), but
> not for raw sockets, which the mipv6 daemon will use. We will provide a
> patch for fixing the SPD lookups with raw sockets, which add routing
> header and home address option from socket options.
>
Ok, I want to see your patch when it is provided because now I'm not so clear
about using socket option in the above case.
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 37+ messages in thread
* ipv6 tunnel patch (was: Re: [patch]: ipv6 tunnel for MIPv6)
2003-06-07 10:30 ` David S. Miller
2003-06-07 10:41 ` YOSHIFUJI Hideaki / 吉藤英明
@ 2003-06-09 11:43 ` Ville Nuorvala
2003-06-09 14:55 ` ipv6 tunnel patch David S. Miller
1 sibling, 1 reply; 37+ messages in thread
From: Ville Nuorvala @ 2003-06-09 11:43 UTC (permalink / raw)
To: David S. Miller
Cc: kuznet, yoshfuji, netdev, ajtuomin, lpetande, jagana, kumarkr
[-- Attachment #1: Type: TEXT/PLAIN, Size: 757 bytes --]
On Sat, 7 Jun 2003, David S. Miller wrote:
> Looks ok, but sorry two things need to be fixed up first:
>
> 1) Doesn't apply anymore, I think it's because of the
> struct sock member renames, just replace sk->foo
> with sk->sk_foo
>
Done...
> 2) Just export all those routines from net/ipv6/ipv6_syms.c
> always, remove the ifdefs.
...and done!
>
> I promise to apply it after you fix this stuff up :)))
Ok here's the last revision of the patch :)
It's done against ChangeSet 1.1308.
Also available at:
http://www.mipl.mediapoli.com/patches/ip6-tunnel-r3.patch
Thanks!
-Ville
--
Ville Nuorvala
Research Assistant, Institute of Digital Communications,
Helsinki University of Technology
email: vnuorval@tcs.hut.fi, phone: +358 (0)9 451 5257
[-- Attachment #2: Type: TEXT/PLAIN, Size: 39609 bytes --]
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/if_arp.h merge-2.5/include/linux/if_arp.h
--- linux-2.5/include/linux/if_arp.h Wed Jun 4 13:43:03 2003
+++ merge-2.5/include/linux/if_arp.h Mon Jun 9 10:14:24 2003
@@ -60,7 +60,7 @@
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
-#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */
+#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
#define ARPHRD_SKIP 771 /* SKIP vif */
#define ARPHRD_LOOPBACK 772 /* Loopback device */
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/linux/ip6_tunnel.h merge-2.5/include/linux/ip6_tunnel.h
--- linux-2.5/include/linux/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/linux/ip6_tunnel.h Mon Jun 9 10:14:24 2003
@@ -0,0 +1,32 @@
+/*
+ * $Id$
+ */
+
+#ifndef _IP6_TUNNEL_H
+#define _IP6_TUNNEL_H
+
+#define IPV6_TLV_TNL_ENCAP_LIMIT 4
+#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4
+
+/* don't add encapsulation limit if one isn't present in inner packet */
+#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1
+/* copy the traffic class field from the inner packet */
+#define IP6_TNL_F_USE_ORIG_TCLASS 0x2
+/* copy the flowlabel from the inner packet */
+#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4
+/* being used for Mobile IPv6 */
+#define IP6_TNL_F_MIP6_DEV 0x8
+
+struct ip6_tnl_parm {
+ char name[IFNAMSIZ]; /* name of tunnel device */
+ int link; /* ifindex of underlying L2 interface */
+ __u8 proto; /* tunnel protocol */
+ __u8 encap_limit; /* encapsulation limit for tunnel */
+ __u8 hop_limit; /* hop limit for tunnel */
+ __u32 flowinfo; /* traffic class and flowlabel for tunnel */
+ __u32 flags; /* tunnel flags */
+ struct in6_addr laddr; /* local tunnel end-point address */
+ struct in6_addr raddr; /* remote tunnel end-point address */
+};
+
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/include/net/ip6_tunnel.h merge-2.5/include/net/ip6_tunnel.h
--- linux-2.5/include/net/ip6_tunnel.h Thu Jan 1 02:00:00 1970
+++ merge-2.5/include/net/ip6_tunnel.h Mon Jun 9 10:14:24 2003
@@ -0,0 +1,44 @@
+/*
+ * $Id$
+ */
+
+#ifndef _NET_IP6_TUNNEL_H
+#define _NET_IP6_TUNNEL_H
+
+#include <linux/ipv6.h>
+#include <linux/netdevice.h>
+#include <linux/ip6_tunnel.h>
+
+/* capable of sending packets */
+#define IP6_TNL_F_CAP_XMIT 0x10000
+/* capable of receiving packets */
+#define IP6_TNL_F_CAP_RCV 0x20000
+
+#define IP6_TNL_MAX 128
+
+/* IPv6 tunnel */
+
+struct ip6_tnl {
+ struct ip6_tnl *next; /* next tunnel in list */
+ struct net_device *dev; /* virtual device associated with tunnel */
+ struct net_device_stats stat; /* statistics for tunnel device */
+ int recursion; /* depth of hard_start_xmit recursion */
+ struct ip6_tnl_parm parms; /* tunnel configuration paramters */
+ struct flowi fl; /* flowi template for xmit */
+};
+
+/* Tunnel encapsulation limit destination sub-option */
+
+struct ipv6_tlv_tnl_enc_lim {
+ __u8 type; /* type-code for option */
+ __u8 length; /* option length */
+ __u8 encap_limit; /* tunnel encapsulation limit */
+} __attribute__ ((packed));
+
+#ifdef __KERNEL__
+#ifdef CONFIG_IPV6_TUNNEL
+extern int __init ip6_tunnel_init(void);
+extern void ip6_tunnel_cleanup(void);
+#endif
+#endif
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Kconfig merge-2.5/net/ipv6/Kconfig
--- linux-2.5/net/ipv6/Kconfig Mon Jun 9 09:11:24 2003
+++ merge-2.5/net/ipv6/Kconfig Mon Jun 9 10:14:27 2003
@@ -55,4 +55,12 @@
If unsure, say Y.
+config IPV6_TUNNEL
+ tristate "IPv6: IPv6-in-IPv6 tunnel"
+ depends on IPV6
+ ---help---
+ Support for IPv6-in-IPv6 tunnels described in RFC 2473.
+
+ If unsure, say N.
+
source "net/ipv6/netfilter/Kconfig"
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/Makefile merge-2.5/net/ipv6/Makefile
--- linux-2.5/net/ipv6/Makefile Wed Jun 4 13:43:06 2003
+++ merge-2.5/net/ipv6/Makefile Mon Jun 9 10:14:27 2003
@@ -15,3 +15,5 @@
obj-$(CONFIG_INET6_ESP) += esp6.o
obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
obj-$(CONFIG_NETFILTER) += netfilter/
+
+obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/af_inet6.c merge-2.5/net/ipv6/af_inet6.c
--- linux-2.5/net/ipv6/af_inet6.c Mon Jun 9 09:11:24 2003
+++ merge-2.5/net/ipv6/af_inet6.c Mon Jun 9 10:14:36 2003
@@ -57,6 +57,9 @@
#include <net/transp_v6.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
+#if CONFIG_IPV6_TUNNEL
+#include <net/ip6_tunnel.h>
+#endif
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -776,6 +779,11 @@
err = ndisc_init(&inet6_family_ops);
if (err)
goto ndisc_fail;
+#ifdef CONFIG_IPV6_TUNNEL
+ err = ip6_tunnel_init();
+ if (err)
+ goto ip6_tunnel_fail;
+#endif
err = igmp6_init(&inet6_family_ops);
if (err)
goto igmp_fail;
@@ -830,6 +838,10 @@
igmp6_cleanup();
#endif
igmp_fail:
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+ip6_tunnel_fail:
+#endif
ndisc_cleanup();
ndisc_fail:
icmpv6_cleanup();
@@ -865,6 +877,9 @@
ip6_route_cleanup();
ipv6_packet_cleanup();
igmp6_cleanup();
+#ifdef CONFIG_IPV6_TUNNEL
+ ip6_tunnel_cleanup();
+#endif
ndisc_cleanup();
icmpv6_cleanup();
#ifdef CONFIG_SYSCTL
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ip6_tunnel.c merge-2.5/net/ipv6/ip6_tunnel.c
--- linux-2.5/net/ipv6/ip6_tunnel.c Thu Jan 1 02:00:00 1970
+++ merge-2.5/net/ipv6/ip6_tunnel.c Mon Jun 9 10:39:50 2003
@@ -0,0 +1,1261 @@
+/*
+ * IPv6 over IPv6 tunnel device
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Ville Nuorvala <vnuorval@tcs.hut.fi>
+ *
+ * $Id$
+ *
+ * Based on:
+ * linux/net/ipv6/sit.c
+ *
+ * RFC 2473
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/if.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/if_tunnel.h>
+#include <linux/net.h>
+#include <linux/in6.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/icmpv6.h>
+#include <linux/init.h>
+#include <linux/route.h>
+#include <linux/rtnetlink.h>
+
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <net/ip.h>
+#include <net/sock.h>
+#include <net/ipv6.h>
+#include <net/protocol.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+#include <net/ip6_tunnel.h>
+
+MODULE_AUTHOR("Ville Nuorvala");
+MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel");
+MODULE_LICENSE("GPL");
+
+#define IPV6_TLV_TEL_DST_SIZE 8
+
+#ifdef IP6_TNL_DEBUG
+#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__)
+#else
+#define IP6_TNL_TRACE(x...) do {;} while(0)
+#endif
+
+#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+
+/* socket(s) used by ip6ip6_tnl_xmit() for resending packets */
+static struct socket *__ip6_socket[NR_CPUS];
+#define ip6_socket __ip6_socket[smp_processor_id()]
+
+static void ip6_xmit_lock(void)
+{
+ local_bh_disable();
+ if (unlikely(!spin_trylock(&ip6_socket->sk->sk_lock.slock)))
+ BUG();
+}
+
+static void ip6_xmit_unlock(void)
+{
+ spin_unlock_bh(&ip6_socket->sk->sk_lock.slock);
+}
+
+#define HASH_SIZE 32
+
+#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
+ (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
+ (HASH_SIZE - 1))
+
+static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
+static int ip6ip6_tnl_dev_init(struct net_device *dev);
+
+/* the IPv6 tunnel fallback device */
+static struct net_device ip6ip6_fb_tnl_dev = {
+ .name = "ip6tnl0",
+ .init = ip6ip6_fb_tnl_dev_init
+};
+
+/* the IPv6 fallback tunnel */
+static struct ip6_tnl ip6ip6_fb_tnl = {
+ .dev = &ip6ip6_fb_tnl_dev,
+ .parms ={.name = "ip6tnl0", .proto = IPPROTO_IPV6}
+};
+
+/* lists for storing tunnels in use */
+static struct ip6_tnl *tnls_r_l[HASH_SIZE];
+static struct ip6_tnl *tnls_wc[1];
+static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l };
+
+/* lock for the tunnel lists */
+static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED;
+
+/**
+ * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
+ * @remote: the address of the tunnel exit-point
+ * @local: the address of the tunnel entry-point
+ *
+ * Return:
+ * tunnel matching given end-points if found,
+ * else fallback tunnel if its device is up,
+ * else %NULL
+ **/
+
+struct ip6_tnl *
+ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local)
+{
+ unsigned h0 = HASH(remote);
+ unsigned h1 = HASH(local);
+ struct ip6_tnl *t;
+
+ for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr) &&
+ (t->dev->flags & IFF_UP))
+ return t;
+ }
+ if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP))
+ return t;
+
+ return NULL;
+}
+
+/**
+ * ip6ip6_bucket - get head of list matching given tunnel parameters
+ * @p: parameters containing tunnel end-points
+ *
+ * Description:
+ * ip6ip6_bucket() returns the head of the list matching the
+ * &struct in6_addr entries laddr and raddr in @p.
+ *
+ * Return: head of IPv6 tunnel list
+ **/
+
+static struct ip6_tnl **
+ip6ip6_bucket(struct ip6_tnl_parm *p)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ unsigned h = 0;
+ int prio = 0;
+
+ if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
+ prio = 1;
+ h = HASH(remote) ^ HASH(local);
+ }
+ return &tnls[prio][h];
+}
+
+/**
+ * ip6ip6_tnl_link - add tunnel to hash table
+ * @t: tunnel to be added
+ **/
+
+static void
+ip6ip6_tnl_link(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp = ip6ip6_bucket(&t->parms);
+
+ write_lock_bh(&ip6ip6_lock);
+ t->next = *tp;
+ write_unlock_bh(&ip6ip6_lock);
+ *tp = t;
+}
+
+/**
+ * ip6ip6_tnl_unlink - remove tunnel from hash table
+ * @t: tunnel to be removed
+ **/
+
+static void
+ip6ip6_tnl_unlink(struct ip6_tnl *t)
+{
+ struct ip6_tnl **tp;
+
+ for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) {
+ if (t == *tp) {
+ write_lock_bh(&ip6ip6_lock);
+ *tp = t->next;
+ write_unlock_bh(&ip6ip6_lock);
+ break;
+ }
+ }
+}
+
+/**
+ * ip6_tnl_create() - create a new tunnel
+ * @p: tunnel parameters
+ * @pt: pointer to new tunnel
+ *
+ * Description:
+ * Create tunnel matching given parameters.
+ *
+ * Return:
+ * 0 on success
+ **/
+
+static int
+ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt)
+{
+ struct net_device *dev;
+ int err = -ENOBUFS;
+ struct ip6_tnl *t;
+
+ dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL);
+ if (!dev)
+ return err;
+
+ memset(dev, 0, sizeof (*dev) + sizeof (*t));
+ dev->priv = (void *) (dev + 1);
+ t = (struct ip6_tnl *) dev->priv;
+ t->dev = dev;
+ dev->init = ip6ip6_tnl_dev_init;
+ memcpy(&t->parms, p, sizeof (*p));
+ t->parms.name[IFNAMSIZ - 1] = '\0';
+ if (t->parms.hop_limit > 255)
+ t->parms.hop_limit = -1;
+ strcpy(dev->name, t->parms.name);
+ if (!dev->name[0]) {
+ int i = 0;
+ int exists = 0;
+
+ do {
+ sprintf(dev->name, "ip6tnl%d", ++i);
+ exists = (__dev_get_by_name(dev->name) != NULL);
+ } while (i < IP6_TNL_MAX && exists);
+
+ if (i == IP6_TNL_MAX) {
+ goto failed;
+ }
+ memcpy(t->parms.name, dev->name, IFNAMSIZ);
+ }
+ SET_MODULE_OWNER(dev);
+ if ((err = register_netdevice(dev)) < 0) {
+ goto failed;
+ }
+ ip6ip6_tnl_link(t);
+ *pt = t;
+ return 0;
+failed:
+ kfree(dev);
+ return err;
+}
+
+/**
+ * ip6_tnl_destroy() - destroy old tunnel
+ * @t: tunnel to be destroyed
+ *
+ * Return:
+ * whatever unregister_netdevice() returns
+ **/
+
+static inline int
+ip6_tnl_destroy(struct ip6_tnl *t)
+{
+ return unregister_netdevice(t->dev);
+}
+
+/**
+ * ip6ip6_tnl_locate - find or create tunnel matching given parameters
+ * @p: tunnel parameters
+ * @create: != 0 if allowed to create new tunnel if no match found
+ *
+ * Description:
+ * ip6ip6_tnl_locate() first tries to locate an existing tunnel
+ * based on @parms. If this is unsuccessful, but @create is set a new
+ * tunnel device is created and registered for use.
+ *
+ * Return:
+ * 0 if tunnel located or created,
+ * -EINVAL if parameters incorrect,
+ * -ENODEV if no matching tunnel available
+ **/
+
+static int
+ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create)
+{
+ struct in6_addr *remote = &p->raddr;
+ struct in6_addr *local = &p->laddr;
+ struct ip6_tnl *t;
+
+ if (p->proto != IPPROTO_IPV6)
+ return -EINVAL;
+
+ for (t = *ip6ip6_bucket(p); t; t = t->next) {
+ if (!ipv6_addr_cmp(local, &t->parms.laddr) &&
+ !ipv6_addr_cmp(remote, &t->parms.raddr)) {
+ *pt = t;
+ return (create ? -EEXIST : 0);
+ }
+ }
+ if (!create) {
+ return -ENODEV;
+ }
+ return ip6_tnl_create(p, pt);
+}
+
+/**
+ * ip6ip6_tnl_dev_destructor - tunnel device destructor
+ * @dev: the device to be destroyed
+ **/
+
+static void
+ip6ip6_tnl_dev_destructor(struct net_device *dev)
+{
+ kfree(dev);
+}
+
+/**
+ * ip6ip6_tnl_dev_uninit - tunnel device uninitializer
+ * @dev: the device to be destroyed
+ *
+ * Description:
+ * ip6ip6_tnl_dev_uninit() removes tunnel from its list
+ **/
+
+static void
+ip6ip6_tnl_dev_uninit(struct net_device *dev)
+{
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ write_lock_bh(&ip6ip6_lock);
+ tnls_wc[0] = NULL;
+ write_unlock_bh(&ip6ip6_lock);
+ } else {
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_unlink(t);
+ }
+}
+
+/**
+ * parse_tvl_tnl_enc_lim - handle encapsulation limit option
+ * @skb: received socket buffer
+ *
+ * Return:
+ * 0 if none was found,
+ * else index to encapsulation limit
+ **/
+
+static __u16
+parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw;
+ __u8 nexthdr = ipv6h->nexthdr;
+ __u16 off = sizeof (*ipv6h);
+
+ while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
+ __u16 optlen = 0;
+ struct ipv6_opt_hdr *hdr;
+ if (raw + off + sizeof (*hdr) > skb->data &&
+ !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+ break;
+
+ hdr = (struct ipv6_opt_hdr *) (raw + off);
+ if (nexthdr == NEXTHDR_FRAGMENT) {
+ struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
+ if (frag_hdr->frag_off)
+ break;
+ optlen = 8;
+ } else if (nexthdr == NEXTHDR_AUTH) {
+ optlen = (hdr->hdrlen + 2) << 2;
+ } else {
+ optlen = ipv6_optlen(hdr);
+ }
+ if (nexthdr == NEXTHDR_DEST) {
+ __u16 i = off + 2;
+ while (1) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+
+ /* No more room for encapsulation limit */
+ if (i + sizeof (*tel) > off + optlen)
+ break;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+ /* return index of option if found and valid */
+ if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
+ tel->length == 1)
+ return i;
+ /* else jump to next option */
+ if (tel->type)
+ i += tel->length + 2;
+ else
+ i++;
+ }
+ }
+ nexthdr = hdr->nexthdr;
+ off += optlen;
+ }
+ return 0;
+}
+
+/**
+ * ip6ip6_err - tunnel error handler
+ *
+ * Description:
+ * ip6ip6_err() should handle errors in the tunnel according
+ * to the specifications in RFC 2473.
+ **/
+
+void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
+{
+ struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
+ struct ip6_tnl *t;
+ int rel_msg = 0;
+ int rel_type = ICMPV6_DEST_UNREACH;
+ int rel_code = ICMPV6_ADDR_UNREACH;
+ __u32 rel_info = 0;
+ __u16 len;
+
+ /* If the packet doesn't contain the original IPv6 header we are
+ in trouble since we might need the source address for furter
+ processing of the error. */
+
+ read_lock(&ip6ip6_lock);
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL)
+ goto out;
+
+ switch (type) {
+ __u32 teli;
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ __u32 mtu;
+ case ICMPV6_DEST_UNREACH:
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Path to destination invalid "
+ "or inactive!\n", t->parms.name);
+ rel_msg = 1;
+ break;
+ case ICMPV6_TIME_EXCEED:
+ if (code == ICMPV6_EXC_HOPLIMIT) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small hop limit or "
+ "routing loop in tunnel!\n",
+ t->parms.name);
+ rel_msg = 1;
+ }
+ break;
+ case ICMPV6_PARAMPROB:
+ /* ignore if parameter problem not caused by a tunnel
+ encapsulation limit sub-option */
+ if (code != ICMPV6_HDR_FIELD) {
+ break;
+ }
+ teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+
+ if (teli && teli == info - 2) {
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
+ if (tel->encap_limit <= 1) {
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Too small encapsulation "
+ "limit or routing loop in "
+ "tunnel!\n", t->parms.name);
+ rel_msg = 1;
+ }
+ }
+ break;
+ case ICMPV6_PKT_TOOBIG:
+ mtu = info - offset;
+ if (mtu <= IPV6_MIN_MTU) {
+ mtu = IPV6_MIN_MTU;
+ }
+ t->dev->mtu = mtu;
+
+ if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) {
+ rel_type = ICMPV6_PKT_TOOBIG;
+ rel_code = 0;
+ rel_info = mtu;
+ rel_msg = 1;
+ }
+ break;
+ }
+ if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
+ struct rt6_info *rt;
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb2)
+ goto out;
+
+ dst_release(skb2->dst);
+ skb2->dst = NULL;
+ skb_pull(skb2, offset);
+ skb2->nh.raw = skb2->data;
+
+ /* Try to guess incoming interface */
+ rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0);
+
+ if (rt && rt->rt6i_dev)
+ skb2->dev = rt->rt6i_dev;
+
+ icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev);
+
+ if (rt)
+ dst_free(&rt->u.dst);
+
+ kfree_skb(skb2);
+ }
+out:
+ read_unlock(&ip6ip6_lock);
+}
+
+/**
+ * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally
+ * @skb: received socket buffer
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp)
+{
+ struct sk_buff *skb = *pskb;
+ struct ipv6hdr *ipv6h;
+ struct ip6_tnl *t;
+
+ if (!pskb_may_pull(skb, sizeof (*ipv6h)))
+ goto discard;
+
+ ipv6h = skb->nh.ipv6h;
+
+ read_lock(&ip6ip6_lock);
+
+ if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) {
+ if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) {
+ t->stat.rx_dropped++;
+ read_unlock(&ip6ip6_lock);
+ goto discard;
+ }
+ skb->mac.raw = skb->nh.raw;
+ skb->nh.raw = skb->data;
+ skb->protocol = htons(ETH_P_IPV6);
+ skb->pkt_type = PACKET_HOST;
+ memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+ skb->dev = t->dev;
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ t->stat.rx_packets++;
+ t->stat.rx_bytes += skb->len;
+ netif_rx(skb);
+ read_unlock(&ip6ip6_lock);
+ return 0;
+ }
+ read_unlock(&ip6ip6_lock);
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+discard:
+ kfree_skb(skb);
+ return 0;
+}
+
+/**
+ * txopt_len - get necessary size for new &struct ipv6_txoptions
+ * @orig_opt: old options
+ *
+ * Return:
+ * Size of old one plus size of tunnel encapsulation limit option
+ **/
+
+static inline int
+txopt_len(struct ipv6_txoptions *orig_opt)
+{
+ int len = sizeof (*orig_opt) + 8;
+
+ if (orig_opt && orig_opt->dst0opt)
+ len += ipv6_optlen(orig_opt->dst0opt);
+ return len;
+}
+
+/**
+ * merge_options - add encapsulation limit to original options
+ * @encap_limit: number of allowed encapsulation limits
+ * @orig_opt: original options
+ *
+ * Return:
+ * Pointer to new &struct ipv6_txoptions containing the tunnel
+ * encapsulation limit
+ **/
+
+static struct ipv6_txoptions *
+merge_options(struct sock *sk, __u8 encap_limit,
+ struct ipv6_txoptions *orig_opt)
+{
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ struct ipv6_txoptions *opt;
+ __u8 *raw;
+ __u8 pad_to = 8;
+ int opt_len = txopt_len(orig_opt);
+
+ if (!(opt = sock_kmalloc(sk, opt_len, GFP_ATOMIC))) {
+ return NULL;
+ }
+
+ memset(opt, 0, opt_len);
+ opt->tot_len = opt_len;
+ opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1);
+ opt->opt_nflen = 8;
+
+ raw = (__u8 *) opt->dst0opt;
+
+ tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1);
+ tel->type = IPV6_TLV_TNL_ENCAP_LIMIT;
+ tel->length = 1;
+ tel->encap_limit = encap_limit;
+
+ if (orig_opt) {
+ __u8 *orig_raw;
+
+ opt->hopopt = orig_opt->hopopt;
+
+ /* Keep the original destination options properly
+ aligned and merge possible old paddings to the
+ new padding option */
+ if ((orig_raw = (__u8 *) orig_opt->dst0opt) != NULL) {
+ __u8 type;
+ int i = sizeof (struct ipv6_opt_hdr);
+ pad_to += sizeof (struct ipv6_opt_hdr);
+ while (i < ipv6_optlen(orig_opt->dst0opt)) {
+ type = orig_raw[i++];
+ if (type == IPV6_TLV_PAD0)
+ pad_to++;
+ else if (type == IPV6_TLV_PADN) {
+ int len = orig_raw[i++];
+ i += len;
+ pad_to += len + 2;
+ } else {
+ break;
+ }
+ }
+ opt->dst0opt->hdrlen = orig_opt->dst0opt->hdrlen + 1;
+ memcpy(raw + pad_to, orig_raw + pad_to - 8,
+ opt_len - sizeof (*opt) - pad_to);
+ }
+ opt->srcrt = orig_opt->srcrt;
+ opt->opt_nflen += orig_opt->opt_nflen;
+
+ opt->dst1opt = orig_opt->dst1opt;
+ opt->auth = orig_opt->auth;
+ opt->opt_flen = orig_opt->opt_flen;
+ }
+ raw[5] = IPV6_TLV_PADN;
+
+ /* subtract lengths of destination suboption header,
+ tunnel encapsulation limit and pad N header */
+ raw[6] = pad_to - 7;
+
+ return opt;
+}
+
+/**
+ * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ * @t: the outgoing tunnel device
+ * @hdr: IPv6 header from the incoming packet
+ *
+ * Description:
+ * Avoid trivial tunneling loop by checking that tunnel exit-point
+ * doesn't match source of incoming packet.
+ *
+ * Return:
+ * 1 if conflict,
+ * 0 else
+ **/
+
+static inline int
+ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr)
+{
+ return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr);
+}
+
+/**
+ * ip6ip6_tnl_xmit - encapsulate packet and send
+ * @skb: the outgoing socket buffer
+ * @dev: the outgoing tunnel device
+ *
+ * Description:
+ * Build new header and do some sanity checks on the packet before sending
+ * it to ip6_build_xmit().
+ *
+ * Return:
+ * 0
+ **/
+
+int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct net_device_stats *stats = &t->stat;
+ struct ipv6hdr *ipv6h = skb->nh.ipv6h;
+ struct ipv6_txoptions *orig_opt = NULL;
+ struct ipv6_txoptions *opt = NULL;
+ __u8 encap_limit = 0;
+ __u16 offset;
+ struct flowi fl;
+ struct ip6_flowlabel *fl_lbl = NULL;
+ int err = 0;
+ struct dst_entry *dst;
+ int link_failure = 0;
+ struct sock *sk = ip6_socket->sk;
+ struct ipv6_pinfo *np = inet6_sk(sk);
+ int mtu;
+
+ if (t->recursion++) {
+ stats->collisions++;
+ goto tx_err;
+ }
+ if (skb->protocol != htons(ETH_P_IPV6) ||
+ !(t->parms.flags & IP6_TNL_F_CAP_XMIT) ||
+ ip6ip6_tnl_addr_conflict(t, ipv6h)) {
+ goto tx_err;
+ }
+ if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) {
+ struct ipv6_tlv_tnl_enc_lim *tel;
+ tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset];
+ if (tel->encap_limit <= 1) {
+ icmpv6_send(skb, ICMPV6_PARAMPROB,
+ ICMPV6_HDR_FIELD, offset + 2, skb->dev);
+ goto tx_err;
+ }
+ encap_limit = tel->encap_limit - 1;
+ } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) {
+ encap_limit = t->parms.encap_limit;
+ }
+ ip6_xmit_lock();
+
+ memcpy(&fl, &t->fl, sizeof (fl));
+
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK);
+ if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+
+ if (fl.fl6_flowlabel) {
+ fl_lbl = fl6_sock_lookup(sk, fl.fl6_flowlabel);
+ if (fl_lbl)
+ orig_opt = fl_lbl->opt;
+ }
+ if (encap_limit > 0) {
+ if (!(opt = merge_options(sk, encap_limit, orig_opt))) {
+ goto tx_err_free_fl_lbl;
+ }
+ } else {
+ opt = orig_opt;
+ }
+ dst = __sk_dst_check(sk, np->dst_cookie);
+
+ if (dst) {
+ if (np->daddr_cache == NULL ||
+ ipv6_addr_cmp(&fl.fl6_dst, np->daddr_cache) ||
+ (fl.oif && fl.oif != dst->dev->ifindex)) {
+ dst = NULL;
+ }
+ }
+ if (dst == NULL) {
+ dst = ip6_route_output(sk, &fl);
+ if (dst->error) {
+ stats->tx_carrier_errors++;
+ link_failure = 1;
+ goto tx_err_dst_release;
+ }
+ /* local routing loop */
+ if (dst->dev == dev) {
+ stats->collisions++;
+ if (net_ratelimit())
+ printk(KERN_WARNING
+ "%s: Local routing loop detected!\n",
+ t->parms.name);
+ goto tx_err_dst_release;
+ }
+ ipv6_addr_copy(&np->daddr, &fl.fl6_dst);
+ ipv6_addr_copy(&np->saddr, &fl.fl6_src);
+ }
+ mtu = dst_pmtu(dst) - sizeof (*ipv6h);
+ if (opt) {
+ mtu -= (opt->opt_nflen + opt->opt_flen);
+ }
+ if (mtu < IPV6_MIN_MTU)
+ mtu = IPV6_MIN_MTU;
+ if (skb->dst && mtu < dst_pmtu(skb->dst)) {
+ struct rt6_info *rt = (struct rt6_info *) skb->dst;
+ rt->rt6i_flags |= RTF_MODIFIED;
+ rt->u.dst.metrics[RTAX_MTU-1] = mtu;
+ }
+ if (skb->len > mtu) {
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
+ goto tx_err_opt_release;
+ }
+ err = ip6_append_data(sk, ip_generic_getfrag, skb->nh.raw, skb->len, 0,
+ t->parms.hop_limit, opt, &fl,
+ (struct rt6_info *)dst, MSG_DONTWAIT);
+
+ if (err) {
+ ip6_flush_pending_frames(sk);
+ } else {
+ err = ip6_push_pending_frames(sk);
+ err = (err < 0 ? err : 0);
+ }
+ if (!err) {
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+ } else {
+ stats->tx_errors++;
+ stats->tx_aborted_errors++;
+ }
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+
+ fl6_sock_release(fl_lbl);
+ ip6_dst_store(sk, dst, &np->daddr);
+ ip6_xmit_unlock();
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+tx_err_dst_release:
+ dst_release(dst);
+tx_err_opt_release:
+ if (opt && opt != orig_opt)
+ sock_kfree_s(sk, opt, opt->tot_len);
+tx_err_free_fl_lbl:
+ fl6_sock_release(fl_lbl);
+ ip6_xmit_unlock();
+ if (link_failure)
+ dst_link_failure(skb);
+tx_err:
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ kfree_skb(skb);
+ t->recursion--;
+ return 0;
+}
+
+static void ip6_tnl_set_cap(struct ip6_tnl *t)
+{
+ struct ip6_tnl_parm *p = &t->parms;
+ struct in6_addr *laddr = &p->laddr;
+ struct in6_addr *raddr = &p->raddr;
+ int ltype = ipv6_addr_type(laddr);
+ int rtype = ipv6_addr_type(raddr);
+
+ p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV);
+
+ if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY &&
+ ((ltype|rtype) &
+ (IPV6_ADDR_UNICAST|
+ IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL|
+ IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) {
+ struct net_device *ldev = NULL;
+ int l_ok = 1;
+ int r_ok = 1;
+
+ if (p->link)
+ ldev = dev_get_by_index(p->link);
+
+ if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev))
+ l_ok = 0;
+
+ if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL))
+ r_ok = 0;
+
+ if (l_ok && r_ok) {
+ if (ltype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_XMIT;
+ if (rtype&IPV6_ADDR_UNICAST)
+ p->flags |= IP6_TNL_F_CAP_RCV;
+ }
+ if (ldev)
+ dev_put(ldev);
+ }
+}
+
+
+static void ip6ip6_tnl_link_config(struct ip6_tnl *t)
+{
+ struct net_device *dev = t->dev;
+ struct ip6_tnl_parm *p = &t->parms;
+ struct flowi *fl;
+ /* Set up flowi template */
+ fl = &t->fl;
+ ipv6_addr_copy(&fl->fl6_src, &p->laddr);
+ ipv6_addr_copy(&fl->fl6_dst, &p->raddr);
+ fl->oif = p->link;
+ fl->fl6_flowlabel = 0;
+
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
+ fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo);
+ if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
+ fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo);
+
+ ip6_tnl_set_cap(t);
+
+ if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV)
+ dev->flags |= IFF_POINTOPOINT;
+ else
+ dev->flags &= ~IFF_POINTOPOINT;
+
+ if (p->flags & IP6_TNL_F_CAP_XMIT) {
+ struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr,
+ p->link, 0);
+ if (rt) {
+ struct net_device *rtdev;
+ if (!(rtdev = rt->rt6i_dev) ||
+ rtdev->type == ARPHRD_TUNNEL6) {
+ /* as long as tunnels use the same socket
+ for transmission, locally nested tunnels
+ won't work */
+ dst_release(&rt->u.dst);
+ goto no_link;
+ } else {
+ dev->iflink = rtdev->ifindex;
+ dev->hard_header_len = rtdev->hard_header_len +
+ sizeof (struct ipv6hdr);
+ dev->mtu = rtdev->mtu - sizeof (struct ipv6hdr);
+ if (dev->mtu < IPV6_MIN_MTU)
+ dev->mtu = IPV6_MIN_MTU;
+
+ dst_release(&rt->u.dst);
+ }
+ }
+ } else {
+ no_link:
+ dev->iflink = 0;
+ dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
+ dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+ }
+}
+
+/**
+ * ip6ip6_tnl_change - update the tunnel parameters
+ * @t: tunnel to be changed
+ * @p: tunnel configuration parameters
+ * @active: != 0 if tunnel is ready for use
+ *
+ * Description:
+ * ip6ip6_tnl_change() updates the tunnel parameters
+ **/
+
+static int
+ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+{
+ ipv6_addr_copy(&t->parms.laddr, &p->laddr);
+ ipv6_addr_copy(&t->parms.raddr, &p->raddr);
+ t->parms.flags = p->flags;
+ t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1);
+ t->parms.encap_limit = p->encap_limit;
+ t->parms.flowinfo = p->flowinfo;
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ * @dev: virtual device associated with tunnel
+ * @ifr: parameters passed from userspace
+ * @cmd: command to be performed
+ *
+ * Description:
+ * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
+ * from userspace.
+ *
+ * The possible commands are the following:
+ * %SIOCGETTUNNEL: get tunnel parameters for device
+ * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters
+ * %SIOCCHGTUNNEL: change tunnel parameters to those given
+ * %SIOCDELTUNNEL: delete tunnel
+ *
+ * The fallback device "ip6tnl0", created during module
+ * initialization, can be used for creating other tunnel devices.
+ *
+ * Return:
+ * 0 on success,
+ * %-EFAULT if unable to copy data to or from userspace,
+ * %-EPERM if current process hasn't %CAP_NET_ADMIN set
+ * %-EINVAL if passed tunnel parameters are invalid,
+ * %-EEXIST if changing a tunnel's parameters would cause a conflict
+ * %-ENODEV if attempting to change or delete a nonexisting device
+ **/
+
+static int
+ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ int create;
+ struct ip6_tnl_parm p;
+ struct ip6_tnl *t = NULL;
+
+ switch (cmd) {
+ case SIOCGETTUNNEL:
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p,
+ ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV)
+ t = (struct ip6_tnl *) dev->priv;
+ else if (err)
+ break;
+ } else
+ t = (struct ip6_tnl *) dev->priv;
+
+ memcpy(&p, &t->parms, sizeof (p));
+ if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
+ err = -EFAULT;
+ }
+ break;
+ case SIOCADDTUNNEL:
+ case SIOCCHGTUNNEL:
+ err = -EPERM;
+ create = (cmd == SIOCADDTUNNEL);
+ if (!capable(CAP_NET_ADMIN))
+ break;
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ if (!create && dev != &ip6ip6_fb_tnl_dev) {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) {
+ break;
+ }
+ if (cmd == SIOCCHGTUNNEL) {
+ if (t->dev != dev) {
+ err = -EEXIST;
+ break;
+ }
+ ip6ip6_tnl_unlink(t);
+ err = ip6ip6_tnl_change(t, &p);
+ ip6ip6_tnl_link(t);
+ netdev_state_change(dev);
+ }
+ if (copy_to_user(ifr->ifr_ifru.ifru_data,
+ &t->parms, sizeof (p))) {
+ err = -EFAULT;
+ } else {
+ err = 0;
+ }
+ break;
+ case SIOCDELTUNNEL:
+ err = -EPERM;
+ if (!capable(CAP_NET_ADMIN))
+ break;
+
+ if (dev == &ip6ip6_fb_tnl_dev) {
+ if (copy_from_user(&p, ifr->ifr_ifru.ifru_data,
+ sizeof (p))) {
+ err = -EFAULT;
+ break;
+ }
+ err = ip6ip6_tnl_locate(&p, &t, 0);
+ if (err)
+ break;
+ if (t == &ip6ip6_fb_tnl) {
+ err = -EPERM;
+ break;
+ }
+ } else {
+ t = (struct ip6_tnl *) dev->priv;
+ }
+ err = ip6_tnl_destroy(t);
+ break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+/**
+ * ip6ip6_tnl_get_stats - return the stats for tunnel device
+ * @dev: virtual device associated with tunnel
+ *
+ * Return: stats for device
+ **/
+
+static struct net_device_stats *
+ip6ip6_tnl_get_stats(struct net_device *dev)
+{
+ return &(((struct ip6_tnl *) dev->priv)->stat);
+}
+
+/**
+ * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device
+ * @dev: virtual device associated with tunnel
+ * @new_mtu: the new mtu
+ *
+ * Return:
+ * 0 on success,
+ * %-EINVAL if mtu too small
+ **/
+
+static int
+ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if (new_mtu < IPV6_MIN_MTU) {
+ return -EINVAL;
+ }
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices
+ * @dev: virtual device associated with tunnel
+ *
+ * Description:
+ * Set function pointers and initialize the &struct flowi template used
+ * by the tunnel.
+ **/
+
+static void
+ip6ip6_tnl_dev_init_gen(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ struct flowi *fl = &t->fl;
+
+ memset(fl, 0, sizeof (*fl));
+ fl->proto = IPPROTO_IPV6;
+
+ dev->destructor = ip6ip6_tnl_dev_destructor;
+ dev->uninit = ip6ip6_tnl_dev_uninit;
+ dev->hard_start_xmit = ip6ip6_tnl_xmit;
+ dev->get_stats = ip6ip6_tnl_get_stats;
+ dev->do_ioctl = ip6ip6_tnl_ioctl;
+ dev->change_mtu = ip6ip6_tnl_change_mtu;
+ dev->type = ARPHRD_TUNNEL6;
+ dev->flags |= IFF_NOARP;
+ if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST &&
+ ipv6_addr_type(&t->parms.laddr) & IPV6_ADDR_UNICAST)
+ dev->flags |= IFF_POINTOPOINT;
+ /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be
+ copied to dev->dev_addr and dev->broadcast, like the ipv4
+ addresses were in ipip.c, ip_gre.c and sit.c. */
+ dev->addr_len = 0;
+}
+
+/**
+ * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices
+ * @dev: virtual device associated with tunnel
+ **/
+
+static int
+ip6ip6_tnl_dev_init(struct net_device *dev)
+{
+ struct ip6_tnl *t = (struct ip6_tnl *) dev->priv;
+ ip6ip6_tnl_dev_init_gen(dev);
+ ip6ip6_tnl_link_config(t);
+ return 0;
+}
+
+/**
+ * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device
+ * @dev: fallback device
+ *
+ * Return: 0
+ **/
+
+int ip6ip6_fb_tnl_dev_init(struct net_device *dev)
+{
+ ip6ip6_tnl_dev_init_gen(dev);
+ tnls_wc[0] = &ip6ip6_fb_tnl;
+ return 0;
+}
+
+static struct inet6_protocol ip6ip6_protocol = {
+ .handler = ip6ip6_rcv,
+ .err_handler = ip6ip6_err,
+ .flags = INET6_PROTO_FINAL
+};
+
+/**
+ * ip6_tunnel_init - register protocol and reserve needed resources
+ *
+ * Return: 0 on success
+ **/
+
+int __init ip6_tunnel_init(void)
+{
+ int i, j, err;
+ struct sock *sk;
+ struct ipv6_pinfo *np;
+
+ ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+
+ err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6,
+ &__ip6_socket[i]);
+ if (err < 0) {
+ printk(KERN_ERR
+ "Failed to create the IPv6 tunnel socket "
+ "(err %d).\n",
+ err);
+ goto fail;
+ }
+ sk = __ip6_socket[i]->sk;
+ sk->sk_allocation = GFP_ATOMIC;
+
+ np = inet6_sk(sk);
+ np->hop_limit = 255;
+ np->mc_loop = 0;
+
+ sk->sk_prot->unhash(sk);
+ }
+ if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) {
+ printk(KERN_ERR "Failed to register IPv6 protocol\n");
+ goto fail;
+ }
+
+ SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev);
+ register_netdev(&ip6ip6_fb_tnl_dev);
+
+ return 0;
+fail:
+ for (j = 0; j < i; j++) {
+ if (!cpu_possible(j))
+ continue;
+ sock_release(__ip6_socket[j]);
+ __ip6_socket[j] = NULL;
+ }
+ return err;
+}
+
+/**
+ * ip6_tunnel_cleanup - free resources and unregister protocol
+ **/
+
+void ip6_tunnel_cleanup(void)
+{
+ int i;
+
+ unregister_netdev(&ip6ip6_fb_tnl_dev);
+
+ inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_possible(i))
+ continue;
+ sock_release(__ip6_socket[i]);
+ __ip6_socket[i] = NULL;
+ }
+}
+
+#ifdef MODULE
+module_init(ip6_tunnel_init);
+module_exit(ip6_tunnel_cleanup);
+#endif
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/ipv6/ipv6_syms.c merge-2.5/net/ipv6/ipv6_syms.c
--- linux-2.5/net/ipv6/ipv6_syms.c Mon Jun 9 09:11:25 2003
+++ merge-2.5/net/ipv6/ipv6_syms.c Mon Jun 9 10:36:46 2003
@@ -38,3 +38,9 @@
EXPORT_SYMBOL(ip6_find_1stfragopt);
EXPORT_SYMBOL(xfrm6_rcv);
EXPORT_SYMBOL(xfrm6_clear_mutable_options);
+EXPORT_SYMBOL(rt6_lookup);
+EXPORT_SYMBOL(fl6_sock_lookup);
+EXPORT_SYMBOL(ipv6_ext_hdr);
+EXPORT_SYMBOL(ip6_append_data);
+EXPORT_SYMBOL(ip6_flush_pending_frames);
+EXPORT_SYMBOL(ip6_push_pending_frames);
diff -Nur --exclude=SCCS --exclude=BitKeeper --exclude=ChangeSet linux-2.5/net/netsyms.c merge-2.5/net/netsyms.c
--- linux-2.5/net/netsyms.c Mon Jun 9 08:45:57 2003
+++ merge-2.5/net/netsyms.c Mon Jun 9 10:38:16 2003
@@ -477,8 +477,10 @@
EXPORT_SYMBOL(sysctl_max_syn_backlog);
#endif
-EXPORT_SYMBOL(ip_generic_getfrag);
+#endif
+#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) || defined (CONFIG_IPV6_TUNNEL_MODULE)
+EXPORT_SYMBOL(ip_generic_getfrag);
#endif
EXPORT_SYMBOL(tcp_read_sock);
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: ipv6 tunnel patch
2003-06-09 11:43 ` ipv6 tunnel patch (was: Re: [patch]: ipv6 tunnel for MIPv6) Ville Nuorvala
@ 2003-06-09 14:55 ` David S. Miller
0 siblings, 0 replies; 37+ messages in thread
From: David S. Miller @ 2003-06-09 14:55 UTC (permalink / raw)
To: vnuorval; +Cc: kuznet, yoshfuji, netdev, ajtuomin, lpetande, jagana, kumarkr
From: Ville Nuorvala <vnuorval@tcs.hut.fi>
Date: Mon, 9 Jun 2003 14:43:11 +0300 (EEST)
Ok here's the last revision of the patch :)
It's done against ChangeSet 1.1308.
Applied, thank you.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-09 11:37 ` Masahide NAKAMURA
@ 2003-06-10 15:25 ` Henrik Petander
2003-06-10 15:40 ` Masahide NAKAMURA
2003-06-10 16:51 ` David S. Miller
0 siblings, 2 replies; 37+ messages in thread
From: Henrik Petander @ 2003-06-10 15:25 UTC (permalink / raw)
To: Masahide NAKAMURA
Cc: Henrik Petander, YOSHIFUJI Hideaki, vnuorval, davem, kuznet,
netdev, ajtuomin, jagana, kumarkr, usagi-core
Masahide NAKAMURA wrote:
> On Mon, 9 Jun 2003 12:06:35 +0300 (EEST)
> Henrik Petander <lpetande@morphine.tml.hut.fi> wrote:
>
>
>>On Fri, 6 Jun 2003, Masahide NAKAMURA wrote:
>>
>>>We don't think we have to change the logic handling policy with
>>>the reason because we can treat MIPv6 policy just like IPsec.
>>>
>>>When we want to apply both MIPv6 and IPsec to the same target,
>>>we need one policy that has two or more of templates(e.g. one is
>>>MIPv6's template and the other is IPsec's).
>>
>>Does this also mean that the IPSec and MIPv6 policies and SAs need to be
>>configured at the same time or is it possible to add templates to an
>>existing policy?
>
>
> Currently no interface to add templates directly to it.
Then the policies for mipv6 would need to be specified at the same time
as the ipsec policies. This is not a problem as long as the policies are
loaded at start up. However, this could lead to problems with
applications which specify their own policies, e.g. racoon.
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-10 15:25 ` Henrik Petander
@ 2003-06-10 15:40 ` Masahide NAKAMURA
2003-06-10 16:56 ` David S. Miller
2003-06-10 16:51 ` David S. Miller
1 sibling, 1 reply; 37+ messages in thread
From: Masahide NAKAMURA @ 2003-06-10 15:40 UTC (permalink / raw)
To: Henrik Petander
Cc: YOSHIFUJI Hideaki, vnuorval, davem, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
On Tue, 10 Jun 2003 18:25:18 +0300
Henrik Petander <lpetande@tml.hut.fi> wrote:
> Then the policies for mipv6 would need to be specified at the same time
> as the ipsec policies. This is not a problem as long as the policies are
> loaded at start up. However, this could lead to problems with
> applications which specify their own policies, e.g. racoon.
How about providing interface of handling templates to update
existing policy in kernel?
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-10 15:25 ` Henrik Petander
2003-06-10 15:40 ` Masahide NAKAMURA
@ 2003-06-10 16:51 ` David S. Miller
2003-06-11 8:48 ` Henrik Petander
1 sibling, 1 reply; 37+ messages in thread
From: David S. Miller @ 2003-06-10 16:51 UTC (permalink / raw)
To: lpetande
Cc: nakam, lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
From: Henrik Petander <lpetande@tml.hut.fi>
Date: Tue, 10 Jun 2003 18:25:18 +0300
Then the policies for mipv6 would need to be specified at the same time
as the ipsec policies. This is not a problem as long as the policies are
loaded at start up. However, this could lead to problems with
applications which specify their own policies, e.g. racoon.
It is an important point.
Ask yourself this, why do we have tunnel devices and don't implement
them with cool routing or XFRM rules? We don't do this because as
soon as you type "zebra" all your by-hand routes are gone, and as soon
as you type "racoon" al your by-hand xfrm rules are gone.
If you want to do these things using routes or xfrm rules, you must
integrate the creation of them into either zebra or racoon. You
cannot have a setup where mipv6d and racoon/zebra fight each other
flushing each other's settings. It doesn't work.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-10 15:40 ` Masahide NAKAMURA
@ 2003-06-10 16:56 ` David S. Miller
0 siblings, 0 replies; 37+ messages in thread
From: David S. Miller @ 2003-06-10 16:56 UTC (permalink / raw)
To: nakam
Cc: lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin, jagana,
kumarkr, usagi-core
From: Masahide NAKAMURA <nakam@linux-ipv6.org>
Date: Wed, 11 Jun 2003 00:40:44 +0900
How about providing interface of handling templates to update
existing policy in kernel?
Who will manage mipv6 policies? racoon? See my other email
on why any other setup simply will not work.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-10 16:51 ` David S. Miller
@ 2003-06-11 8:48 ` Henrik Petander
2003-06-12 3:20 ` David S. Miller
0 siblings, 1 reply; 37+ messages in thread
From: Henrik Petander @ 2003-06-11 8:48 UTC (permalink / raw)
To: David S. Miller
Cc: nakam, lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
David S. Miller wrote:
>
> If you want to do these things using routes or xfrm rules, you must
> integrate the creation of them into either zebra or racoon. You
> cannot have a setup where mipv6d and racoon/zebra fight each other
> flushing each other's settings. It doesn't work.
>
In the routing based approach there should not be any conflicts between
mipv6 and zebra: We would create cached host routes based on the
existing routes. Thus if zebra was running, the mipv6 daemon would not
change the routes created by zebra, but only cached host routes. If
zebra changed any routes, it would cause the deletion of any invalid
cached routes. The mipv6 daemon would listen to netlink messages for
route deletion and would then reinsert the mipv6 state into a new cached
route.
Does this make sense to you?
Thanks,
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-11 8:48 ` Henrik Petander
@ 2003-06-12 3:20 ` David S. Miller
2003-06-12 8:44 ` Henrik Petander
0 siblings, 1 reply; 37+ messages in thread
From: David S. Miller @ 2003-06-12 3:20 UTC (permalink / raw)
To: lpetande
Cc: nakam, lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
From: Henrik Petander <lpetande@tml.hut.fi>
Date: Wed, 11 Jun 2003 11:48:19 +0300
Does this make sense to you?
No it doesn't. When you startup zebra, it may flush the entire
routing table.
You must make zebra aware of any static or dynamic routes you care
about. It manages entire routing table and that is the end of
the story.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-12 3:20 ` David S. Miller
@ 2003-06-12 8:44 ` Henrik Petander
2003-06-12 8:49 ` David S. Miller
2003-06-13 11:26 ` Masahide NAKAMURA
0 siblings, 2 replies; 37+ messages in thread
From: Henrik Petander @ 2003-06-12 8:44 UTC (permalink / raw)
To: David S. Miller
Cc: nakam, lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
David S. Miller wrote:
> From: Henrik Petander <lpetande@tml.hut.fi>
> Date: Wed, 11 Jun 2003 11:48:19 +0300
>
> Does this make sense to you?
>
> No it doesn't. When you startup zebra, it may flush the entire
> routing table.
I don't see a problem in that. It would only result in a short period of
missing mipv6 route optimization information, until MIPv6 daemon
reinserted the mipv6 information. MIPv6 daemon would do this after
getting a notification of the deletion of the old mipv6 related cached
routes. This would relate to zebra in the same way as pmtu discovery.
Regards,
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-12 8:44 ` Henrik Petander
@ 2003-06-12 8:49 ` David S. Miller
2003-06-13 11:26 ` Masahide NAKAMURA
1 sibling, 0 replies; 37+ messages in thread
From: David S. Miller @ 2003-06-12 8:49 UTC (permalink / raw)
To: lpetande
Cc: nakam, lpetande, yoshfuji, vnuorval, kuznet, netdev, ajtuomin,
jagana, kumarkr, usagi-core
From: Henrik Petander <lpetande@tml.hut.fi>
Date: Thu, 12 Jun 2003 11:44:49 +0300
MIPv6 daemon would do this after getting a notification of the
deletion of the old mipv6 related cached routes.
Ok.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-12 8:44 ` Henrik Petander
2003-06-12 8:49 ` David S. Miller
@ 2003-06-13 11:26 ` Masahide NAKAMURA
2003-06-13 14:27 ` Henrik Petander
1 sibling, 1 reply; 37+ messages in thread
From: Masahide NAKAMURA @ 2003-06-13 11:26 UTC (permalink / raw)
To: Henrik Petander
Cc: David S. Miller, lpetande, yoshfuji, vnuorval, kuznet, netdev,
ajtuomin, jagana, kumarkr, usagi-core
On Thu, 12 Jun 2003 11:44:49 +0300
Henrik Petander <lpetande@tml.hut.fi> wrote:
> > No it doesn't. When you startup zebra, it may flush the entire
> > routing table.
>
>
> I don't see a problem in that. It would only result in a short period of
> missing mipv6 route optimization information, until MIPv6 daemon
> reinserted the mipv6 information. MIPv6 daemon would do this after
> getting a notification of the deletion of the old mipv6 related cached
> routes. This would relate to zebra in the same way as pmtu discovery.
When routing information is deleted by zebra, the packets from user
application will be sent incorrectly until MIPv6 daemon re-inserts
the special host route.
Anyway, in the xfrm based approach,
I suggested that MIPv6 should use the same policy as IPsec(racoon),
however, it causes problems as David and Henrik said.
So, I suggest a little other plan like below:
How about making new policy(MIPv6 policy) in the similar way of IPsec?
MIPv6 and IPsec policy are managed by separated list.
In that way we have to notice about both of policies and state order
in looking xfrm up or creating bundle.
I think there is not period issue like above.
I think, in networking operation, it seems natural way to use stackable
destination, and Henrik's patch(mip6-exthdr.patch;maybe sent to netdev at 5 Jun)
is almost the same one.
The first step is we should have two kinds of policy, IPsec and MIP6.
In this step, we make MIP6 stack to use stackable destination and some XFRM
with MIP6 policy.
Probably the second step will be to modify xfrm_policy is not a IPsec's SPD but
generic one.
How about you?
Regards,
--
Masahide NAKAMURA
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6
2003-06-13 11:26 ` Masahide NAKAMURA
@ 2003-06-13 14:27 ` Henrik Petander
0 siblings, 0 replies; 37+ messages in thread
From: Henrik Petander @ 2003-06-13 14:27 UTC (permalink / raw)
To: Masahide NAKAMURA
Cc: David S. Miller, lpetande, yoshfuji, vnuorval, kuznet, netdev,
ajtuomin, jagana, kumarkr, usagi-core
Masahide NAKAMURA wrote:
> On Thu, 12 Jun 2003 11:44:49 +0300
> Henrik Petander <lpetande@tml.hut.fi> wrote:
>>
>>I don't see a problem in that. It would only result in a short period of
>>missing mipv6 route optimization information, until MIPv6 daemon
>>reinserted the mipv6 information. MIPv6 daemon would do this after
>>getting a notification of the deletion of the old mipv6 related cached
>>routes. This would relate to zebra in the same way as pmtu discovery.
>
>
> When routing information is deleted by zebra, the packets from user
> application will be sent incorrectly until MIPv6 daemon re-inserts
> the special host route.
The packets between Mobile Node and Correspondent Node would be just
sent through the tunnel via Home Agent. Only parts of the direct traffic
between MN and HA would be temporarily lost. Since HA is conceptually a
router, the traffic between MN and HA should be very limited and Mobile
IP / IPSec signaling would not be affected. This is why IMO the use of
soft state is acceptable.
> How about making new policy(MIPv6 policy) in the similar way of IPsec?
> MIPv6 and IPsec policy are managed by separated list.
It would be a good solution from our POV, since it should work well with
IPSec.
Regards,
Henrik
^ permalink raw reply [flat|nested] 37+ messages in thread
end of thread, other threads:[~2003-06-13 14:27 UTC | newest]
Thread overview: 37+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20030424132559.GA15894@morphine.tml.hut.fi>
2003-05-30 14:34 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 Ville Nuorvala
2003-05-30 15:00 ` [patch]: ipv6 tunnel " Ville Nuorvala
2003-05-30 15:38 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 4:38 ` David S. Miller
2003-06-04 14:30 ` Henrik Petander
2003-06-04 15:49 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-04 17:31 ` Henrik Petander
2003-06-05 8:36 ` Ville Nuorvala
2003-06-05 12:40 ` Ville Nuorvala
2003-06-04 4:34 ` David S. Miller
2003-06-04 12:40 ` Ville Nuorvala
2003-06-07 10:30 ` David S. Miller
2003-06-07 10:41 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-09 11:43 ` ipv6 tunnel patch (was: Re: [patch]: ipv6 tunnel for MIPv6) Ville Nuorvala
2003-06-09 14:55 ` ipv6 tunnel patch David S. Miller
2003-05-30 15:03 ` [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6 YOSHIFUJI Hideaki / 吉藤英明
2003-05-30 20:38 ` Venkata Jagana
2003-06-03 6:35 ` Ville Nuorvala
2003-06-05 10:12 ` YOSHIFUJI Hideaki / 吉藤英明
2003-06-06 5:38 ` Masahide NAKAMURA
2003-06-06 11:14 ` Henrik Petander
2003-06-06 13:31 ` Masahide NAKAMURA
2003-06-09 9:06 ` Henrik Petander
2003-06-09 11:37 ` Masahide NAKAMURA
2003-06-10 15:25 ` Henrik Petander
2003-06-10 15:40 ` Masahide NAKAMURA
2003-06-10 16:56 ` David S. Miller
2003-06-10 16:51 ` David S. Miller
2003-06-11 8:48 ` Henrik Petander
2003-06-12 3:20 ` David S. Miller
2003-06-12 8:44 ` Henrik Petander
2003-06-12 8:49 ` David S. Miller
2003-06-13 11:26 ` Masahide NAKAMURA
2003-06-13 14:27 ` Henrik Petander
2003-06-06 8:48 ` Ville Nuorvala
2003-06-06 10:32 ` CONFIG_IPV6_SUBTREES (was [patch]: CONFIG_IPV6_SUBTREES fix for MIPv6) YOSHIFUJI Hideaki / 吉藤英明
2003-06-06 11:16 ` Ville Nuorvala
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).