Subject: tun and ipv6
To: None <tech-net@netbsd.org>
From: None <zul@netbsd-fr.org>
List: tech-net
Date: 02/15/2006 21:47:43
--/04w6evG8XlLl3ft
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Hi list
rpaulo@ added some preliminary code to add ipv6 support to tun. But
currently, it is only possible to have ipv6 support into "tunnel mode".
To solve this issue, I think we can use an implementation like obsd or
fbsd : they preprend the packet with the af_family of the packet, so they
can retrieve the family of the packet.
A patch which implements this idea is attached. I don't have tested it.
Please excuse me if they are some errors, it is my first kernel patch.
Take cares.
--
Degroote Arnaud
--/04w6evG8XlLl3ft
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename=patch_tun
--- if_tun.c.orig 2006-02-13 20:02:49.000000000 +0100
+++ if_tun.c 2006-02-13 19:57:58.000000000 +0100
@@ -345,8 +345,9 @@
/* find internet addresses and delete routes */
struct ifaddr *ifa;
IFADDR_FOREACH(ifa, ifp) {
-#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET) {
+#if defined(INET) || defined(INET6)
+ if (ifa->ifa_addr->sa_family == AF_INET ||
+ ifa->ifa_addr->sa_family == AF_INET6) {
rtinit(ifa, (int)RTM_DELETE,
tp->tun_flags & TUN_DSTADDR
? RTF_HOST
@@ -396,6 +397,24 @@
}
}
#endif
+#ifdef INET6
+ if (ifa->ifa_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin;
+
+ sin = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
+ tp->tun_flags |= TUN_IASET;
+
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+ if (sin &&
+ !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
+ tp->tun_flags |= TUN_DSTADDR;
+ } else
+ tp->tun_flags &= ~TUN_DSTADDR;
+ }
+#endif /* INET6 */
+
}
return;
@@ -474,8 +493,9 @@
struct tun_softc *tp = ifp->if_softc;
int s;
int error;
-#ifdef INET
+#if defined(INET) || defined(INET6)
int mlen;
+ uint32_t * af;
#endif
ALTQ_DECL(struct altq_pktattr pktattr;)
@@ -519,7 +539,18 @@
goto out;
}
bcopy(dst, mtod(m0, char *), dst->sa_len);
- }
+ } else {
+ /* Prepend the adress family */
+ M_PREPEND(m0,sizeof(*af),M_DONTWAIT);
+ if (m0 == NULL) {
+ IF_DROP(&ifp->if_snd);
+ error = ENOBUFS;
+ goto out;
+ }
+ af = mtod(m0,u_int32_t *);
+ *af = htonl(dst->sa_family);
+ }
+
/* FALLTHROUGH */
case AF_UNSPEC:
IFQ_ENQUEUE(&ifp->if_snd, m0, &pktattr, error);
@@ -753,6 +784,7 @@
struct ifqueue *ifq;
struct sockaddr dst;
int isr, error = 0, s, tlen, mlen;
+ uint32_t family;
s = splnet();
tp = tun_find_unit(dev);
@@ -787,9 +819,12 @@
}
}
} else {
-#ifdef INET
- dst.sa_family = AF_INET;
-#endif
+ if (uio->uio_resid < sizeof(family)){
+ error = EIO;
+ goto out0;
+ }
+ error = uiomove((caddr_t)&family,sizeof(family), uio);
+ dst.sa_family = ntohl(family);
}
if (uio->uio_resid > TUNMTU) {
--/04w6evG8XlLl3ft--