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 */