Subject: Re: no v4, slip this time - patches!
To: None <tech-net@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-net
Date: 07/17/2002 16:47:44
Okay, v6 SLIP seems to work (FVO "work" good enough to keep me happy,
at least unless something nasty shows up that I haven't noticed yet).
Here's what I did to if_sl{.c,var.h}. These are relative to if_sl.c
1.55 and if_slvar.h 1.19. They will not apply mechanically to
-current, but based on reading diffs between these versions and
-current, I believe that anyone who cares to bother will probably have
little trouble making "the same" changes to -current.
I suspect, though, that the people who were saying nobody would care
are likely right. I wouldn't even bother sending diffs here except to
get them in the archives against someone's possible future use. If
anyone does go through them or try them, of course, I welcome comments
and such.
Note that if you use these, you will have to go to some lengths
(deleting all v6 addresses, even the link-local one that shows up
automatically) to get the interface's MTU below 576; setting a v6
address raises the MTU if it's below 576, and it rejects attempts to
set it below that if there are any v6 addresses configured.
/~\ The ASCII der Mouse
\ / Ribbon Campaign
X Against HTML mouse@rodents.montreal.qc.ca
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
--- if_sl.c- Sun Sep 17 20:05:01 2000
+++ if_sl.c Wed Jul 17 22:10:46 2002
@@ -95,13 +95,13 @@
#include <net/netisr.h>
#include <net/route.h>
-#ifdef INET
+#if defined(INET) || defined(INET6)
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
#else
-#error Slip without inet?
+#error Slip with neither inet nor inet6?
#endif
#include <net/slcompress.h>
@@ -171,6 +171,8 @@
#define CLISTRESERVE 1024 /* Can't let clists get too low */
#endif /* !__NetBSD__ */
+#define MINV6MTU 576 /* straight from the v6 spec */
+
/*
* SLIP ABORT ESCAPE MECHANISM:
* (inspired by HAYES modem escape arrangement)
@@ -189,6 +191,15 @@
#define FRAME_ESCAPE 0xdb /* Frame Esc */
#define TRANS_FRAME_END 0xdc /* transposed frame end */
#define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */
+/*
+ * The intent is that 0x80-0x8e are the 15 commonest address families
+ * (not counting IPv4, which uses unmarked packets), with 0x8f
+ * indicating a "rare" address family (not yet specified; maybe the
+ * next two bytes will be an Ethernet frame type - anyone for bridging
+ * Ethernet over serial lines?).
+ */
+#define TRANS_PKTTYPE_BASE 0x80 /* packet type base */
+#define PKTTYPE_IPv6 0 /* packet is a v6 packet */
static int slinit __P((struct sl_softc *));
static struct mbuf *sl_btom __P((struct sl_softc *, int));
@@ -218,6 +229,7 @@
#if NBPFILTER > 0
bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
#endif
+ sc->sc_af = AF_INET;
}
}
@@ -385,16 +397,18 @@
register struct ifqueue *ifq;
int s;
- /*
- * `Cannot happen' (see slioctl). Someday we will extend
- * the line protocol to support other address families.
- */
- if (dst->sa_family != AF_INET) {
- printf("%s: af%d not supported\n", sc->sc_if.if_xname,
- dst->sa_family);
- m_freem(m);
- sc->sc_if.if_noproto++;
- return (EAFNOSUPPORT);
+ switch (dst->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ /* "can't happen"; slioctl won't set any others */
+ printf("%s: af%d not supported\n", sc->sc_if.if_xname,
+ dst->sa_family);
+ m_freem(m);
+ sc->sc_if.if_noproto++;
+ return (EAFNOSUPPORT);
+ break;
}
if (sc->sc_ttyp == NULL) {
@@ -408,13 +422,22 @@
return (EHOSTUNREACH);
}
ifq = &sc->sc_if.if_snd;
- ip = mtod(m, struct ip *);
- if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
- m_freem(m);
- return (ENETRESET); /* XXX ? */
+ /* XXX really should do likewise for icmp6! */
+ if (dst->sa_family == AF_INET) {
+ ip = mtod(m, struct ip *);
+ if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) {
+ m_freem(m);
+ return (ENETRESET); /* XXX ? */
+ }
+ if (ip->ip_tos & IPTOS_LOWDELAY)
+ ifq = &sc->sc_fastq;
}
- if (ip->ip_tos & IPTOS_LOWDELAY)
- ifq = &sc->sc_fastq;
+ M_PREPEND(m,dst->sa_len,M_DONTWAIT);
+ if (m == 0) {
+ sc->sc_if.if_oerrors ++;
+ return(ENOBUFS);
+ }
+ bcopy(dst,mtod(m,char *),dst->sa_len);
s = splimp();
if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
struct timeval tv;
@@ -456,6 +479,8 @@
register struct ip *ip;
int s;
struct mbuf *m2;
+ struct sockaddr_storage dst;
+ struct sockaddr *dstp;
#if NBPFILTER > 0
u_char *bpfbuf;
register int len = 0;
@@ -525,6 +550,14 @@
}
/*
+ * We know (because we added it ourselves) that the
+ * destination address is entirely within the first mbuf.
+ */
+ dstp = mtod(m,struct sockaddr *);
+ bcopy(dstp,&dst,dstp->sa_len);
+ m_adj(m,dst.ss_len);
+
+ /*
* We do the header compression here rather than in sloutput
* because the packets will be out of order if we are using TOS
* queueing, and the connection id compression will get
@@ -535,10 +568,10 @@
/*
* We need to save the TCP/IP header before it's
* compressed. To avoid complicated code, we just
- * copy the entire packet into a stack buffer (since
- * this is a serial line, packets should be short
- * and/or the copy should be negligible cost compared
- * to the packet transmission time).
+ * copy the entire packet into a temporary buffer
+ * (since this is a serial line, packets should be
+ * short and/or the copy should be negligible
+ * compared to the packet transmission time).
*/
register struct mbuf *m1 = m;
register u_char *cp = bpfbuf + SLIP_HDRLEN;
@@ -553,7 +586,9 @@
} while ((m1 = m1->m_next) != NULL);
}
#endif
- if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) {
+
+ if ( (dst.ss_family == AF_INET) &&
+ ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) ) {
if (sc->sc_if.if_flags & SC_COMPRESS)
*mtod(m, u_char *) |= sl_compress_tcp(m, ip,
&sc->sc_comp, 1);
@@ -593,6 +628,18 @@
++sc->sc_if.if_obytes;
(void) putc(FRAME_END, &tp->t_outq);
}
+ switch (dst.ss_family) {
+ case AF_INET:
+ break;
+ case AF_INET6:
+ if ( !putc(FRAME_ESCAPE,&tp->t_outq) &&
+ putc(TRANS_PKTTYPE_BASE+PKTTYPE_IPv6,&tp->t_outq) )
+ unputc(&tp->t_outq);
+ break;
+ default:
+ panic("slstart: impossible dst.sa_family");
+ break;
+ }
while (m) {
register u_char *ep;
@@ -731,6 +778,8 @@
#if NBPFILTER > 0
u_char chdr[CHDR_LEN];
#endif
+ struct ifqueue *queue;
+ int isr;
tk_nin++;
sc = (struct sl_softc *)tp->t_sc;
@@ -783,6 +832,14 @@
c = FRAME_END;
break;
+ case TRANS_PKTTYPE_BASE + PKTTYPE_IPv6:
+ if (sc->sc_escape) {
+ sc->sc_af = AF_INET6;
+ sc->sc_escape = 0;
+ return;
+ }
+ break;
+
case FRAME_ESCAPE:
sc->sc_escape = 1;
return;
@@ -811,7 +868,8 @@
}
#endif
- if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
+ if ((sc->sc_af == AF_INET) &&
+ ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4))) {
if (c & 0x80)
c = TYPE_COMPRESSED_TCP;
else if (c == TYPE_UNCOMPRESSED_TCP)
@@ -860,14 +918,36 @@
sc->sc_if.if_ipackets++;
sc->sc_if.if_lastchange = time;
s = splimp();
- if (IF_QFULL(&ipintrq)) {
- IF_DROP(&ipintrq);
+ queue = 0;
+ switch (sc->sc_af) {
+ case AF_INET:
+#ifdef INET
+ queue = &ipintrq;
+ isr = NETISR_IP;
+#endif
+ break;
+ case AF_INET6:
+#ifdef INET6
+ queue = &ip6intrq;
+ isr = NETISR_IPV6;
+#endif
+ break;
+ default:
+ panic("slinput impossible sc_af");
+ break;
+ }
+ if (queue == 0) {
+ /* AF not in this kernel! */
+ sc->sc_if.if_ierrors++;
+ m_freem(m);
+ } else if (IF_QFULL(queue)) {
+ IF_DROP(queue);
sc->sc_if.if_ierrors++;
sc->sc_if.if_iqdrops++;
m_freem(m);
} else {
- IF_ENQUEUE(&ipintrq, m);
- schednetisr(NETISR_IP);
+ IF_ENQUEUE(queue, m);
+ schednetisr(isr)
}
splx(s);
goto newpack;
@@ -886,6 +966,7 @@
newpack:
sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
sc->sc_escape = 0;
+ sc->sc_af = AF_INET;
}
/*
@@ -905,15 +986,30 @@
switch (cmd) {
case SIOCSIFADDR:
- if (ifa->ifa_addr->sa_family == AF_INET)
- ifp->if_flags |= IFF_UP;
- else
- error = EAFNOSUPPORT;
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ ifp->if_flags |= IFF_UP;
+ break;
+ case AF_INET6:
+ ifp->if_flags |= IFF_UP;
+ if (sc->sc_if.if_mtu < MINV6MTU)
+ sc->sc_if.if_mtu = MINV6MTU;
+ break;
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
break;
case SIOCSIFDSTADDR:
- if (ifa->ifa_addr->sa_family != AF_INET)
- error = EAFNOSUPPORT;
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ break;
+ default:
+ error = EAFNOSUPPORT;
+ break;
+ }
break;
case SIOCSIFMTU:
@@ -921,6 +1017,18 @@
error = EINVAL;
break;
}
+ if (ifr->ifr_mtu < MINV6MTU) {
+ /* If we have any v6 address set, reject! */
+ struct ifaddr *ifa;
+ for ( ifa = sc->sc_if.if_addrlist.tqh_first;
+ ifa;
+ ifa = ifa->ifa_list.tqe_next )
+ switch (((struct sockaddr *)ifa->ifa_addr)->sa_family) {
+ case AF_INET6:
+ error = EINVAL;
+ goto done; /* break switch, for, switch */
+ }
+ }
sc->sc_if.if_mtu = ifr->ifr_mtu;
break;
@@ -941,6 +1049,11 @@
break;
#endif
+#ifdef INET6
+ case AF_INET6:
+ break;
+#endif
+
default:
error = EAFNOSUPPORT;
break;
@@ -950,6 +1063,7 @@
default:
error = EINVAL;
}
+done:;
splx(s);
return (error);
}
--- if_slvar.h- Sun Sep 17 20:05:01 2000
+++ if_slvar.h Wed Jul 17 19:02:09 2002
@@ -55,6 +55,7 @@
u_char *sc_xxx; /* XXX don't ask... */
u_int sc_flags; /* see below */
u_int sc_escape; /* =1 if last char input was FRAME_ESCAPE */
+ int sc_af; /* AF_INET, AF_INET6, etc - input */
long sc_lasttime; /* last time a char arrived */
long sc_abortcount; /* number of abort esacpe chars */
long sc_starttime; /* time of first abort in window */