summaryrefslogtreecommitdiff
path: root/sys/net/if_strip.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-10-04 01:58:58 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-10-04 01:58:58 +0000
commit3b6a1dc93e56b4cef6f7dd33ce0a275a84be4002 (patch)
treee132f0a52c9f8b8bf29b4899cf40eefa64cc76ac /sys/net/if_strip.c
parent76fdbce809bd30e4cbd790a38bde89c44d70760b (diff)
sync to netbsd 0901
Diffstat (limited to 'sys/net/if_strip.c')
-rw-r--r--sys/net/if_strip.c795
1 files changed, 505 insertions, 290 deletions
diff --git a/sys/net/if_strip.c b/sys/net/if_strip.c
index 846d1689f94..9c8e423fdb9 100644
--- a/sys/net/if_strip.c
+++ b/sys/net/if_strip.c
@@ -1,4 +1,4 @@
-/* $NetBSD: if_strip.c,v 1.2.4.2 1996/06/26 22:37:00 jtc Exp $ */
+/* $NetBSD: if_strip.c,v 1.2.4.3 1996/08/03 00:58:32 jtc Exp $ */
/* from: NetBSD: if_sl.c,v 1.38 1996/02/13 22:00:23 christos Exp $ */
/*
@@ -156,7 +156,7 @@ typedef char ttychar_t;
*
* SLMTU is a hard limit on output packet size. To insure good
* interactive response, SLMTU wants to be the smallest size that
- * amortizes the header cost. (Remember that even with
+ * amortizes the header cost. Remember that even with
* type-of-service queuing, we have to wait for any in-progress
* packet to finish. I.e., we wait, on the average, 1/2 * mtu /
* cps, where cps is the line speed in characters per second.
@@ -193,11 +193,17 @@ typedef char ttychar_t;
#endif
#define SLMAX (MCLBYTES - BUFOFFSET)
#define SLBUFSIZE (SLMAX + BUFOFFSET)
-#define SLMTU 1200 /*XXX*/
+#define SLMTU 1100 /* XXX -- appromaximated. 1024 may be safer. */
#define STRIP_MTU_ONWIRE (SLMTU + 20 + STRIP_HDRLEN) /* (2*SLMTU+2 in sl.c */
+
+
#define SLIP_HIWAT roundup(50,CBSIZE)
+/* This is a NetBSD-1.0 or later kernel. */
+#define CCOUNT(q) ((q)->c_cc)
+
+
#if !(defined(__NetBSD__) || defined(__OpenBSD__)) /* XXX - cgd */
#define CLISTRESERVE 1024 /* Can't let clists get too low */
#endif /* !__NetBSD__ */
@@ -259,26 +265,22 @@ static void RecvErr __P((char *msg, struct st_softc *sc));
static void RecvErr_Message __P((struct st_softc *strip_info,
u_char *sendername, u_char *msg));
void strip_resetradio __P((struct st_softc *sc, struct tty *tp));
+void strip_proberadio __P((struct st_softc *sc, struct tty *tp));
void strip_watchdog __P((struct ifnet *ifp));
-void strip_esc __P((struct st_softc *sc, struct mbuf *m));
+void strip_sendbody __P((struct st_softc *sc, struct mbuf *m));
int strip_newpacket __P((struct st_softc *sc, u_char *ptr, u_char *end));
struct mbuf * strip_send __P((struct st_softc *sc, struct mbuf *m0));
+static void strip_timeout __P((void *x));
+
+
#ifdef DEBUG
-void ipdump __P((const char *msg, u_char *p, int len));
-void stripdump __P((const char *msg, u_char *p, int len));
-void stripdumpm __P((const char *msg, struct mbuf *m, int len));
#define DPRINTF(x) printf x
-#define TXPRINTF(x) printf x/* causes outrageous delays */
-#define RXPRINTF(x) printf x /* causes outrageous delays */
#else
#define DPRINTF(x)
-#define TXPRINTF(x)
-#define RXPRINTF(x)
#endif
-#define XDPRINTF(x) /* really verbose debugging */
/*
@@ -293,18 +295,43 @@ void stripdumpm __P((const char *msg, struct mbuf *m, int len));
* respond with an error, the driver knows to reset the radio.
*/
-#define FORCE_RESET(sc) \
- do {\
- printf("strip: XXX: reset state-machine not yet implemented in *BSD\n"); \
- (sc)->sc_if.if_timer = 0; \
- } while (0)
+/* Radio-reset finite state machine (if_watchdog) callback rate, in seconds */
+#define STRIP_WATCHDOG_INTERVAL 5
+
+/* Period between intrusive radio probes, in seconds */
+#define ST_PROBE_INTERVAL 10
+
+/* Grace period for radio to answer probe, in seconds */
+#define ST_PROBERESPONSE_INTERVAL 2
+
+/* Be less agressive about repeated resetting. */
+#define STRIP_RESET_INTERVAL 5
+/*
+ * We received a response from the radio that indicates it's in
+ * star mode. Clear any pending probe or reset timer.
+ * Don't probe radio again for standard polling interval.
+ */
#define CLEAR_RESET_TIMER(sc) \
do {\
- printf("strip: clearing reset timeout: not yet implemented in *BSD\n"); \
- (sc)->sc_if.if_timer = 0; \
+ (sc)->sc_state = ST_ALIVE; \
+ (sc)->sc_statetimo = time.tv_sec + ST_PROBE_INTERVAL; \
} while (0)
+/*
+ * we received a response from the radio that indicates it's crashed
+ * out of starmode into Hayse mode. Reset it ASAP.
+ */
+#define FORCE_RESET(sc) \
+ do {\
+ (sc)->sc_statetimo = time.tv_sec - 1; \
+ (sc)->sc_state = ST_DEAD; \
+ /*(sc)->sc_if.if_timer = 0;*/ \
+ } while (0)
+
+#define RADIO_PROBE_TIMEOUT(sc) \
+ ((sc)-> sc_statetimo > time.tv_sec)
+
/*
@@ -334,7 +361,7 @@ stripattach(n)
sc->sc_fastq.ifq_maxlen = 32;
sc->sc_if.if_watchdog = strip_watchdog;
- sc->sc_if.if_timer = 15; /* seconds */
+ sc->sc_if.if_timer = STRIP_WATCHDOG_INTERVAL;
if_attach(&sc->sc_if);
#if NBPFILTER > 0
bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN);
@@ -353,31 +380,34 @@ stripinit(sc)
if (p)
sc->sc_ep = (u_char *)p + SLBUFSIZE;
else {
- printf("sl%d: can't allocate buffer\n", sc - st_softc);
+ printf("%s: can't allocate buffer\n",
+ sc->sc_if.if_xname);
sc->sc_if.if_flags &= ~IFF_UP;
return (0);
}
}
- /* get buffer in which to unstuff input */
+ /* Get contiguous buffer in which to de-bytestuff/rll-decode input */
if (sc->sc_rxbuf == (u_char *) 0) {
MCLALLOC(p, M_WAIT);
if (p)
sc->sc_rxbuf = (u_char *)p + SLBUFSIZE - SLMAX;
else {
- printf("sl%d: can't allocate buffer\n", sc - st_softc);
+ printf("%s: can't allocate input buffer\n",
+ sc->sc_if.if_xname);
sc->sc_if.if_flags &= ~IFF_UP;
return (0);
}
}
- /* get buffer in which to stuff output */
+ /* Get contiguous buffer in which to bytestuff/rll-encode output */
if (sc->sc_txbuf == (u_char *) 0) {
MCLALLOC(p, M_WAIT);
if (p)
sc->sc_txbuf = (u_char *)p + SLBUFSIZE - SLMAX;
else {
- printf("sl%d: can't allocate buffer\n", sc - st_softc);
+ printf("%s: can't allocate buffer\n",
+ sc->sc_if.if_xname);
sc->sc_if.if_flags &= ~IFF_UP;
return (0);
@@ -388,6 +418,10 @@ stripinit(sc)
sc->sc_mp = sc->sc_buf;
sl_compress_init(&sc->sc_comp, -1);
+ /* Initialize radio probe/reset state machine */
+ sc->sc_state = ST_DEAD; /* assumet the worst. */
+ sc->sc_statetimo = time.tv_sec; /* do reset immediately */
+
return (1);
}
@@ -458,7 +492,7 @@ stripopen(dev, tp)
/*
* Line specific close routine.
- * Detach the tty from the sl unit.
+ * Detach the tty from the strip unit.
*/
void
stripclose(tp)
@@ -469,7 +503,6 @@ stripclose(tp)
ttywflush(tp);
- DPRINTF(("stripclose: closing\n"));
s = splimp(); /* actually, max(spltty, splsoftnet) */
tp->t_line = 0;
sc = (struct st_softc *)tp->t_sc;
@@ -485,6 +518,11 @@ stripclose(tp)
sc->sc_buf = 0;
sc->sc_rxbuf = 0;
sc->sc_txbuf = 0;
+
+ if (sc->sc_flags & SC_TIMEOUT) {
+ untimeout(strip_timeout, (void *) sc);
+ sc->sc_flags &= ~SC_TIMEOUT;
+ }
}
#if defined(__NetBSD__) || defined(__OpenBSD__)
/* if necessary, install a new outq buffer of the appropriate size */
@@ -526,7 +564,7 @@ striptioctl(tp, cmd, data, flag)
* byte-stuff (escape) it, and enqueue it on the tty send queue.
*/
void
-strip_esc(sc, m)
+strip_sendbody(sc, m)
struct st_softc *sc;
struct mbuf *m;
{
@@ -539,7 +577,9 @@ strip_esc(sc, m)
while (m) {
/*
* Byte-stuff/run-length encode this mbuf's data into the
- * output buffer. XXX note that chained calls to stuffdata()
+ * output buffer.
+ * XXX
+ * Note that chained calls to stuffdata()
* require that the stuffed data be left in the
* output buffer until the entire packet is encoded.
*/
@@ -555,6 +595,9 @@ strip_esc(sc, m)
len = dp - sc->sc_txbuf;
if (b_to_q((ttychar_t *)sc->sc_txbuf,
len, &tp->t_outq)) {
+ if (sc->sc_if.if_flags & IFF_DEBUG)
+ addlog("%s: tty output overflow\n",
+ sc->sc_if.if_xname);
goto bad;
}
sc->sc_if.if_obytes += len;
@@ -571,7 +614,8 @@ bad:
* Prepend a STRIP header to the packet.
* (based on 4.4bsd if_ppp)
*
- * XXX manipulates tty queues with putc
+ * XXX manipulates tty queues with putc.
+ * must be called at spl >= spltty.
*/
struct mbuf *
strip_send(sc, m0)
@@ -586,8 +630,11 @@ strip_send(sc, m0)
*/
hdr = mtod(m0, struct st_header *);
if (b_to_q((ttychar_t *)hdr, STRIP_HDRLEN, &tp->t_outq)) {
- TXPRINTF(("prepend: outq overflow\n"));
+ if (sc->sc_if.if_flags & IFF_DEBUG)
+ addlog("%s: outq overflow writing header\n",
+ sc->sc_if.if_xname);
m_freem(m0);
+ return 0;
}
/* The header has been enqueued in clear; undo the M_PREPEND() of the header. */
@@ -598,10 +645,14 @@ strip_send(sc, m0)
}
#ifdef DIAGNOSTIC
else
- addlog("strip_send: not pkthdr, %d remains\n", m0->m_len); /*XXX*/
+ addlog("%s: strip_send: missing pkthdr, %d remains\n",
+ sc->sc_if.if_xname, m0->m_len); /*XXX*/
#endif
- /* If M_PREPEND() had to prepend a new mbuf, it is now empty. Discard it. */
+ /*
+ * If M_PREPEND() had to prepend a new mbuf, it is now empty.
+ * Discard it.
+ */
if (m0->m_len == 0) {
register struct mbuf *m;
MFREE(m0, m);
@@ -609,7 +660,7 @@ strip_send(sc, m0)
}
/* Byte-stuff and run-length encode the remainder of the packet. */
- strip_esc(sc, m0);
+ strip_sendbody(sc, m0);
if (putc(STRIP_FRAME_END, &tp->t_outq)) {
/*
@@ -626,6 +677,14 @@ strip_send(sc, m0)
++sc->sc_if.if_obytes;
sc->sc_if.if_opackets++;
}
+
+ /*
+ * If a radio probe is due now, append it to this packet rather
+ * than waiting until the watchdog routine next runs.
+ */
+ if (time.tv_sec >= sc->sc_statetimo && sc->sc_state == ST_ALIVE)
+ strip_proberadio(sc, tp);
+
return(m0);
}
@@ -682,7 +741,6 @@ stripoutput(ifp, m, dst, rt)
switch (dst->sa_family) {
case AF_INET:
- /* XXX untested */
if (rt != NULL && rt->rt_gwroute != NULL)
rt = rt->rt_gwroute;
@@ -767,7 +825,6 @@ stripoutput(ifp, m, dst, rt)
bcopy((caddr_t)dldst, (caddr_t)shp->starmode_addr,
sizeof (shp->starmode_addr));
- TXPRINTF(("strip address is %16s\n", (char *)shp));
s = splimp();
if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) {
@@ -776,7 +833,7 @@ stripoutput(ifp, m, dst, rt)
/* if output's been stalled for too long, and restart */
timersub(&time, &sc->sc_if.if_lastchange, &tv);
if (tv.tv_sec > 0) {
- /*XXX*/ DPRINTF(("stripoutput: stalled, resetting\n"));
+ DPRINTF(("stripoutput: stalled, resetting\n"));
sc->sc_otimeout++;
stripstart(sc->sc_ttyp);
}
@@ -786,17 +843,20 @@ stripoutput(ifp, m, dst, rt)
m_freem(m);
splx(s);
sc->sc_if.if_oerrors++;
- /*XXX*/ TXPRINTF(("stripoutput: ifq full\n"));
return (ENOBUFS);
}
IF_ENQUEUE(ifq, m);
sc->sc_if.if_lastchange = time;
if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) {
- /*XXX*/ TXPRINTF(("stripoutput: enqueued pkt, restarting\n"));
stripstart(sc->sc_ttyp);
}
-/* XXX FIXME */
- stripstart(sc->sc_ttyp);
+
+ /*
+ * slip doesn't call its start routine unconditionally (again)
+ * here, but doing so apepars to reduce latency.
+ */
+ stripstart(sc->sc_ttyp);
+
splx(s);
return (0);
}
@@ -823,30 +883,34 @@ stripstart(tp)
#if !(defined(__NetBSD__) || defined(__OpenBSD__)) /* XXX - cgd */
extern int cfreecount;
#endif
- for (;;) {
-/*XXX*/ TXPRINTF(("stripstart\n"));
- /*
- * If there is more in the output queue, just send it now.
- * We are being called in lieu of ttstart and must do what
- * it would.
- */
- if (tp->t_outq.c_cc != 0) {
+
+
+ /*
+ * Ppp checks that strip is still the line discipline,
+ * and if not, calls t_oproc here. sl.c does not.
+ * PPP is newer...
+ */
+
+ if (((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
+ || sc == NULL || tp != (struct tty *) sc->sc_ttyp) {
+ if (tp->t_oproc != NULL)
(*tp->t_oproc)(tp);
- if (tp->t_outq.c_cc > SLIP_HIWAT) {
- TXPRINTF(("stripstart: outq past SLIP_HIWAT\n"));
-#if 0
- /* XXX can't just stop output on
- * framed packet-radio links!
- */
- return;
-#endif
- }
- }
+ if (sc && (sc->sc_if.if_flags & IFF_DEBUG))
+ addlog("%s: late call to stripstart\n ",
+ sc->sc_if.if_xname);
+ }
+
+ /* Start any pending output asap */
+ if (CCOUNT(&tp->t_outq) != 0) {
+ (*tp->t_oproc)(tp);
+ }
+
+ while (CCOUNT(&tp->t_outq) < SLIP_HIWAT) {
+
/*
* This happens briefly when the line shuts down.
*/
if (sc == NULL) {
- TXPRINTF(("(shutdown)\n"));
return;
}
@@ -857,8 +921,10 @@ stripstart(tp)
* current serial output queue, with a packet full of
* escapes this could be as bad as STRIP_MTU_ONWIRE
* (for slip, SLMTU*2+2, for STRIP, header + 20 bytes).
+ * Also allow 4 bytes in case we need to send a probe
+ * to the radio.
*/
- if (tp->t_outq.c_cn - tp->t_outq.c_cc < STRIP_MTU_ONWIRE)
+ if (tp->t_outq.c_cn - tp->t_outq.c_cc < STRIP_MTU_ONWIRE + 4)
return;
#endif /* __NetBSD__ */
/*
@@ -872,7 +938,6 @@ stripstart(tp)
IF_DEQUEUE(&sc->sc_if.if_snd, m);
splx(s);
if (m == NULL) {
-/*XXX*/ TXPRINTF(("(empty q)\n"));
return;
}
/*
@@ -938,11 +1003,43 @@ stripstart(tp)
}
#endif /* !__NetBSD__ */
-
if (strip_send(sc, m) == NULL) {
-/*XXX*/ DPRINTF(("stripsend: failed to send pkt\n"));
+ DPRINTF(("stripsend: failed to send pkt\n")); /*XXX*/
}
}
+
+
+#if 0
+ /* schedule timeout to start output */
+ if ((sc->sc_flags & SC_TIMEOUT) == 0) {
+ timeout(strip_timeout, (void *) sc, HZ);
+ sc->sc_flags |= SC_TIMEOUT;
+ }
+#endif
+
+#if 0
+ /*
+ * This timeout is needed for operation on a pseudo-tty,
+ * because the pty code doesn't call our start routine
+ * after it has drained the t_outq.
+ */
+ if ((sc->sc_flags & SC_TIMEOUT) == 0) {
+ timeout(strip_timeout, (void *) sc, HZ);
+ sc->sc_flags |= SC_TIMEOUT;
+ }
+#endif
+
+ /*
+ * XXX ppp calls oproc at the end of its loop, but slip
+ * does it at the beginning. We do both.
+ */
+
+ /*
+ * If there is stuff in the output queue, send it now.
+ * We are being called in lieu of ttstart and must do what it would.
+ */
+ if (tp->t_oproc != NULL)
+ (*tp->t_oproc)(tp);
}
@@ -981,9 +1078,6 @@ strip_btom(sc, len)
sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE;
m->m_data = (caddr_t)sc->sc_buf;
m->m_ext.ext_buf = (caddr_t)((long)sc->sc_buf &~ MCLOFSET);
- TXPRINTF(("strip_btom: new cluster for sc_buf\n"));
- XDPRINTF(("XXX 1: sc_buf %x end %x hardlim %x\n",
- sc->sc_buf, sc->sc_mp, sc->sc_ep));
} else
bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len);
@@ -1028,141 +1122,149 @@ stripinput(c, tp)
++sc->sc_if.if_ibytes;
+ /*
+ * Accumulate characters until we see a frame terminator (\r).
+ */
switch (c) {
-#ifdef notanymore
- case 0x0a:
- /* (leading newline characters are ignored) */
+ case '\n':
+ /*
+ * Error message strings from the modem are terminated with
+ * \r\n. This driver interprets the \r as a packet terminator.
+ * If the first character in a packet is a \n, drop it.
+ * (it can never be the first char of a vaild frame).
+ */
if (sc->sc_mp - sc->sc_buf == 0)
- return;
-#endif
+ break;
+ /* Fall through to */
+
+ default:
+ if (sc->sc_mp < sc->sc_ep) {
+ *sc->sc_mp++ = c;
+ } else {
+ sc->sc_flags |= SC_ERROR;
+ goto error;
+ }
+ return;
case STRIP_FRAME_END:
- len = sc->sc_mp - sc->sc_buf;
+ break;
+ }
+
+
+ /*
+ * We only reach here if we see a CR delimiting a packet.
+ */
+
+
+ len = sc->sc_mp - sc->sc_buf;
#ifdef XDEBUG
- if (len < 15 || sc->sc_flags & SC_ERROR)
- printf("stripinput: end of pkt, len %d, err %d\n",
- len, sc->sc_flags & SC_ERROR); /*XXX*/
+ if (len < 15 || sc->sc_flags & SC_ERROR)
+ printf("stripinput: end of pkt, len %d, err %d\n",
+ len, sc->sc_flags & SC_ERROR); /*XXX*/
#endif
- if(sc->sc_flags & SC_ERROR) {
- sc->sc_flags &= ~SC_ERROR;
- goto newpack;
- }
-
- /*
- * We have a frame.
- * Process an IP packet, ARP packet, AppleTalk packet,
- * AT command resposne, or Starmode error.
- */
- len = strip_newpacket(sc, sc->sc_buf, sc->sc_mp);
- if (len <= 1)
- /* less than min length packet - ignore */
- goto newpack;
-#if DEBUG > 1
- ipdump("after destuff", sc->sc_buf, len);
-#endif /* DEBUG */
+ if(sc->sc_flags & SC_ERROR) {
+ sc->sc_flags &= ~SC_ERROR;
+ addlog("%s: sc error flag set. terminating packet\n",
+ sc->sc_if.if_xname);
+ goto newpack;
+ }
+ /*
+ * We have a frame.
+ * Process an IP packet, ARP packet, AppleTalk packet,
+ * AT command resposne, or Starmode error.
+ */
+ len = strip_newpacket(sc, sc->sc_buf, sc->sc_mp);
+ if (len <= 1)
+ /* less than min length packet - ignore */
+ goto newpack;
#if NBPFILTER > 0
- if (sc->sc_bpf) {
- /*
- * Save the compressed header, so we
- * can tack it on later. Note that we
- * will end up copying garbage in some
- * cases but this is okay. We remember
- * where the buffer started so we can
- * compute the new header length.
- */
- bcopy(sc->sc_buf, chdr, CHDR_LEN);
- }
+ if (sc->sc_bpf) {
+ /*
+ * Save the compressed header, so we
+ * can tack it on later. Note that we
+ * will end up copying garbage in some
+ * cases but this is okay. We remember
+ * where the buffer started so we can
+ * compute the new header length.
+ */
+ bcopy(sc->sc_buf, chdr, CHDR_LEN);
+ }
#endif
- if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
- if (c & 0x80)
- c = TYPE_COMPRESSED_TCP;
- else if (c == TYPE_UNCOMPRESSED_TCP)
- *sc->sc_buf &= 0x4f; /* XXX */
- /*
- * We've got something that's not an IP packet.
- * If compression is enabled, try to decompress it.
- * Otherwise, if `auto-enable' compression is on and
- * it's a reasonable packet, decompress it and then
- * enable compression. Otherwise, drop it.
- */
- if (sc->sc_if.if_flags & SC_COMPRESS) {
- len = sl_uncompress_tcp(&sc->sc_buf, len,
- (u_int)c, &sc->sc_comp);
- if (len <= 0)
- goto error;
- } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
- c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
- len = sl_uncompress_tcp(&sc->sc_buf, len,
- (u_int)c, &sc->sc_comp);
- if (len <= 0)
- goto error;
- sc->sc_if.if_flags |= SC_COMPRESS;
- } else
+ if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) {
+ if (c & 0x80)
+ c = TYPE_COMPRESSED_TCP;
+ else if (c == TYPE_UNCOMPRESSED_TCP)
+ *sc->sc_buf &= 0x4f; /* XXX */
+ /*
+ * We've got something that's not an IP packet.
+ * If compression is enabled, try to decompress it.
+ * Otherwise, if `auto-enable' compression is on and
+ * it's a reasonable packet, decompress it and then
+ * enable compression. Otherwise, drop it.
+ */
+ if (sc->sc_if.if_flags & SC_COMPRESS) {
+ len = sl_uncompress_tcp(&sc->sc_buf, len,
+ (u_int)c, &sc->sc_comp);
+ if (len <= 0)
goto error;
- }
+ } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) &&
+ c == TYPE_UNCOMPRESSED_TCP && len >= 40) {
+ len = sl_uncompress_tcp(&sc->sc_buf, len,
+ (u_int)c, &sc->sc_comp);
+ if (len <= 0)
+ goto error;
+ sc->sc_if.if_flags |= SC_COMPRESS;
+ } else
+ goto error;
+ }
+
#if NBPFILTER > 0
- if (sc->sc_bpf) {
- /*
- * Put the SLIP pseudo-"link header" in place.
- * We couldn't do this any earlier since
- * decompression probably moved the buffer
- * pointer. Then, invoke BPF.
- */
- register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
+ if (sc->sc_bpf) {
+ /*
+ * Put the SLIP pseudo-"link header" in place.
+ * We couldn't do this any earlier since
+ * decompression probably moved the buffer
+ * pointer. Then, invoke BPF.
+ */
+ register u_char *hp = sc->sc_buf - SLIP_HDRLEN;
- hp[SLX_DIR] = SLIPDIR_IN;
- bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN);
- bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN);
- }
+ hp[SLX_DIR] = SLIPDIR_IN;
+ bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN);
+ bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN);
+ }
#endif
- m = strip_btom(sc, len);
- if (m == NULL)
- goto error;
-
- sc->sc_if.if_ipackets++;
- sc->sc_if.if_lastchange = time;
- s = splimp();
- if (IF_QFULL(&ipintrq)) {
- IF_DROP(&ipintrq);
- DPRINTF(("stripinput: ipintrq full\n"));
- sc->sc_if.if_ierrors++;
- sc->sc_if.if_iqdrops++;
- m_freem(m);
- } else {
- IF_ENQUEUE(&ipintrq, m);
- schednetisr(NETISR_IP);
- }
- splx(s);
- goto newpack;
+ m = strip_btom(sc, len);
+ if (m == NULL) {
+ goto error;
}
- if (sc->sc_mp < sc->sc_ep) {
- *sc->sc_mp++ = c;
- /*sc->sc_escape = 0;*/
- return;
+ sc->sc_if.if_ipackets++;
+ sc->sc_if.if_lastchange = time;
+ s = splimp();
+ if (IF_QFULL(&ipintrq)) {
+ IF_DROP(&ipintrq);
+ sc->sc_if.if_ierrors++;
+ sc->sc_if.if_iqdrops++;
+ m_freem(m);
+ } else {
+ IF_ENQUEUE(&ipintrq, m);
+ schednetisr(NETISR_IP);
}
-
- /* can't put lower; would miss an extra frame */
- sc->sc_flags |= SC_ERROR;
- DPRINTF(("stripinput: overran buf\n"));
- goto quiet_error;
+ splx(s);
+ goto newpack;
error:
- RXPRINTF(("stripinput: error\n"));
-quiet_error:
sc->sc_if.if_ierrors++;
- goto quiet_newpack;
newpack:
- /*DPRINTF(("stripinput: newpack\n"));*/ /* XXX */
-quiet_newpack:
+
sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX;
}
@@ -1223,6 +1325,8 @@ stripioctl(ifp, cmd, data)
splx(s);
return (error);
}
+
+
/*
* Strip subroutines
*/
@@ -1241,28 +1345,28 @@ strip_resetradio(sc, tp)
"\r\n\r\n\r\nat\r\n\r\n\r\nate0dt**starmode\r\n**\r\n";
#else
static ttychar_t InitString[] =
- "\r\rat\r\r\rate0q1dt**starmode\r*\r";
+ "\r\rat\r\r\rate0q1dt**starmode\r**\r";
#endif
register int i;
-
- DPRINTF(("strip: resetting radio\n"));
/*
* XXX Perhaps flush tty output queue?
*/
+
if ((i = b_to_q(InitString, sizeof(InitString) - 1, &tp->t_outq))) {
printf("resetradio: %d chars didn't fit in tty queue\n", i);
return;
}
sc->sc_if.if_obytes += sizeof(InitString) - 1;
-#ifdef linux /*XXX*/
- /* reset the watchdog counter */
- sc->watchdog_doprobe = jiffies + 10 * HZ;
- sc->watchdog_doreset = jiffies + 1 * HZ;
-#endif
-
+ /*
+ * Assume the radio is still dead, so we can detect repeated
+ * resets (perhaps the radio is disconnected, powered off, or
+ * is so badlyhung it needs powercycling.
+ */
+ sc->sc_state = ST_DEAD;
sc->sc_if.if_lastchange = time;
+ sc->sc_statetimo = time.tv_sec + STRIP_RESET_INTERVAL;
/*
* XXX Does calling the tty output routine now help resets?
@@ -1270,34 +1374,175 @@ strip_resetradio(sc, tp)
(*sc->sc_ttyp->t_oproc)(tp);
}
+
+/*
+ * Send an invalid starmode packet to the radio, to induce an error message
+ * indicating the radio is in starmode.
+ * Update the state machine to indicate a response is expected.
+ * Either the radio answers, which will be caught by the parser,
+ * or the watchdog will start resetting.
+ *
+ * NOTE: drops chars directly on the tty output queue.
+ * should be caled at spl >= spltty.
+ */
+void
+strip_proberadio(sc, tp)
+ register struct st_softc *sc;
+ register struct tty *tp;
+{
+
+ int overflow;
+ const char *strip_probestr = "**";
+
+ if (sc->sc_if.if_flags & IFF_DEBUG)
+ addlog("%s: attempting to probe radio\n", sc->sc_if.if_xname);
+
+ overflow = b_to_q((ttychar_t *)strip_probestr, 2, &tp->t_outq);
+ if (overflow == 0) {
+ if (sc->sc_if.if_flags & IFF_DEBUG)
+ addlog("%s:: sent probe to radio\n",
+ sc->sc_if.if_xname);
+ /* Go to probe-sent state, set timeout accordingly. */
+ sc->sc_state = ST_PROBE_SENT;
+ sc->sc_statetimo = time.tv_sec + ST_PROBERESPONSE_INTERVAL;
+ } else {
+ addlog("%s: incomplete probe, tty queue %d bytes overfull\n",
+ sc->sc_if.if_xname, overflow);
+ }
+}
+
+
+#ifdef DEBUG
+static char *strip_statenames[] = {
+ "Alive",
+ "Probe sent, awaiting answer",
+ "Probe not answered, resetting"
+};
+#endif
+
+
+/*
+ * Timeout routine -- try to start more output.
+ * Will be needed to make strip work on ptys.
+ */
+static void
+strip_timeout(x)
+ void *x;
+{
+ struct st_softc *sc = (struct st_softc *) x;
+ struct tty *tp = sc->sc_ttyp;
+ int s;
+
+ s = spltty();
+ sc->sc_flags &= ~SC_TIMEOUT;
+ stripstart(tp);
+ splx(s);
+}
+
+
/*
* Strip watchdog routine.
- * The radio hardware is balky and sometimes crashes doesn't reste properly,
- * or crashes and reboots into Hayes-emulation mode.
- * If we don't hear a starmode-only response from the radio within a
- * given time, reset it.
+ * The radio hardware is balky. When sent long packets or bursts of small
+ * packets, the radios crash and reboots into Hayes-emulation mode.
+ * The transmit-side machinery, the error parser, and strip_watchdog()
+ * implement a simple finite state machine.
+ *
+ * We attempt to send a probe to the radio every ST_PROBE seconds. There
+ * is no direct way to tell if the radio is in starmode, so we send it a
+ * malformed starmode packet -- a frame with no destination address --
+ * and expect to an "name missing" error response from the radio within
+ * 1 second. If we hear such a response, we assume the radio is alive
+ * for the next ST_PROBE seconds.
+ * If we don't hear a starmode-error response from the radio, we reset it.
+ *
+ * Probes, and parsing of error responses, are normally done inside the send
+ * and receive side respectively. This watchdog routine examines the
+ * state-machine variables. If there are no packets to send to the radio
+ * during an entire probe interval, strip_output will not be called,
+ * so we send a probe on its behalf.
*/
void
strip_watchdog(ifp)
struct ifnet *ifp;
{
register struct st_softc *sc = ifp->if_softc;
+ struct tty *tp = sc->sc_ttyp;
+
+#ifdef DEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ addlog("\n%s: in watchdog, state %s timeout %ld\n",
+ ifp->if_xname,
+ ((unsigned) sc->sc_state < 3) ?
+ strip_statenames[sc->sc_state] : "<<illegal state>>",
+ sc->sc_statetimo - time.tv_sec);
+#endif
+
+ /*
+ * If time in this state hasn't yet expired, return.
+ */
+ if ((ifp->if_flags & IFF_UP) == 0 || sc->sc_statetimo > time.tv_sec) {
+ goto done;
+ }
+ /*
+ * The time in the current state has expired.
+ * Take appropriate action and advance FSA to the next state.
+ */
+ switch (sc->sc_state) {
+ case ST_ALIVE:
+ /*
+ * A probe is due but we haven't piggybacked one on a packet.
+ * Send a probe now.
+ */
+ strip_proberadio(sc, sc->sc_ttyp);
+ (*tp->t_oproc)(tp);
+ break;
+
+ case ST_PROBE_SENT:
+ /*
+ * Probe sent but no response within timeout. Reset.
+ */
+ addlog("%s: no answer to probe, resetting radio\n",
+ ifp->if_xname);
+ strip_resetradio(sc, sc->sc_ttyp);
+ ifp->if_oerrors++;
+ break;
+
+ case ST_DEAD:
+ /*
+ * The radio has been sent a reset but didn't respond.
+ * XXX warn user to remove AC adaptor and battery,
+ * wait 5 secs, and replace.
+ */
+ addlog("%s: radio reset but not responding, Trying again\n",
+ ifp->if_xname);
+ strip_resetradio(sc, sc->sc_ttyp);
+ ifp->if_oerrors++;
+ break;
- if (0) {
- addlog("%s: watchdog\n", ifp->if_xname);
+ default:
+ /* Cannot happen. To be safe, do a reset. */
+ addlog("%s: %s %d, resetting\n",
+ sc->sc_if.if_xname,
+ "radio-reset finite-state machine in invalid state",
+ sc->sc_state);
strip_resetradio(sc, sc->sc_ttyp);
- ++ifp->if_oerrors;
+ sc->sc_state = ST_DEAD;
+ break;
}
- sc->sc_if.if_timer = 15; /* seconds */
+ done:
+ ifp->if_timer = STRIP_WATCHDOG_INTERVAL;
return;
}
/*
- * The following is taken, with permission of the author, from
- * the LInux strip driver.
+ * The following bytestuffing and run-length encoding/decoding
+ * fucntions are taken, with permission from Stuart Cheshire,
+ * from the MosquitonNet strip driver for Linux.
+ * XXX Linux style left intact, to ease folding in updates from
+ * the Mosquitonet group.
*/
@@ -1328,11 +1573,11 @@ strip_newpacket(sc, ptr, end)
if (*ptr != '*') {
/* Catch other error messages */
if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_')
- RecvErr_Message(sc, NULL, ptr);
+ RecvErr_Message(sc, NULL, ptr+4);
/* XXX what should the message above be? */
else {
RecvErr("No initial *", sc);
- addlog("(len = %d\n", len);
+ addlog("(len = %d)\n", len);
}
return 0;
}
@@ -1348,8 +1593,6 @@ strip_newpacket(sc, ptr, end)
/* Check for end of address marker, and skip over it */
if (ptr == end) {
RecvErr("No second *", sc);
- XDPRINTF(("XXX 3: sc_buf %x ptr %x end %x mp %x hardlim %x\n",
- sc->sc_buf, ptr, end, sc->sc_mp, sc->sc_ep));
return 0;
}
name_end = ptr++;
@@ -1359,7 +1602,7 @@ strip_newpacket(sc, ptr, end)
if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' &&
ptr[3] == '_') {
*name_end = 0;
- RecvErr_Message(sc, name, ptr);
+ RecvErr_Message(sc, name, ptr+4);
}
else RecvErr("No SRIP key", sc);
return 0;
@@ -1368,12 +1611,16 @@ strip_newpacket(sc, ptr, end)
/* Decode start of the IP packet header */
ptr = UnStuffData(ptr, end, sc->sc_rxbuf, 4);
- if (!ptr) {
+ if (ptr == 0) {
RecvErr("Runt packet (hdr)", sc);
return 0;
}
- /* XXX is this the IP header length, or what? */
+ /*
+ * The STRIP bytestuff/RLL encoding has no explicit length
+ * of the decoded packet. Decode start of IP header, get the
+ * IP header length and decode that many bytes in total.
+ */
packetlen = ((u_short)sc->sc_rxbuf[2] << 8) | sc->sc_rxbuf[3];
#ifdef DIAGNOSTIC
@@ -1385,7 +1632,7 @@ strip_newpacket(sc, ptr, end)
/* Decode remainder of the IP packer */
ptr = UnStuffData(ptr, end, sc->sc_rxbuf+4, packetlen-4);
- if (!ptr) {
+ if (ptr == 0) {
RecvErr("Short packet", sc);
return 0;
}
@@ -1546,35 +1793,36 @@ StuffData(u_char *src, u_long length, u_char *dest, u_char **code_ptr_ptr)
/*
* UnStuffData decodes the data at "src", up to (but not including)
* "end". It writes the decoded data into the buffer pointed to by
- * "dest", up to a maximum of "dest_length", and returns the new
+ * "dst", up to a maximum of "dst_length", and returns the new
* value of "src" so that a follow-on call can read more data,
* continuing from where the first left off.
*
* There are three types of results:
- * 1. The source data runs out before extracting "dest_length" bytes:
+ * 1. The source data runs out before extracting "dst_length" bytes:
* UnStuffData returns NULL to indicate failure.
- * 2. The source data produces exactly "dest_length" bytes:
+ * 2. The source data produces exactly "dst_length" bytes:
* UnStuffData returns new_src = end to indicate that all bytes
* were consumed.
- * 3. "dest_length" bytes are extracted, with more
+ * 3. "dst_length" bytes are extracted, with more
* remaining. UnStuffData returns new_src < end to indicate that
* there are more bytes to be read.
*
- * Note: The decoding may be destructive, in that it may alter the
+ * Note: The decoding may be dstructive, in that it may alter the
* source data in the process of decoding it (this is necessary to
* allow a follow-on call to resume correctly).
*/
static u_char*
-UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
+UnStuffData(u_char *src, u_char *end, u_char *dst, u_long dst_length)
{
- u_char *dest_end = dest + dest_length;
+ u_char *dst_end = dst + dst_length;
/* Sanity check */
- if (!src || !end || !dest || !dest_length)
+ if (!src || !end || !dst || !dst_length)
return(NULL);
- while (src < end && dest < dest_end) {
+ while (src < end && dst < dst_end)
+ {
int count = (*src ^ Stuff_Magic) & Stuff_CountMask;
switch ((*src ^ Stuff_Magic) & Stuff_CodeMask)
{
@@ -1582,11 +1830,14 @@ UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
if (src+1+count >= end)
return(NULL);
do
- *dest++ = *++src ^ Stuff_Magic;
- while(--count >= 0 && dest < dest_end);
+ {
+ *dst++ = *++src ^ Stuff_Magic;
+ }
+ while(--count >= 0 && dst < dst_end);
if (count < 0)
src += 1;
- else if (count == 0)
+ else
+ if (count == 0)
*src = Stuff_Same ^ Stuff_Magic;
else
*src = (Stuff_Diff + count) ^ Stuff_Magic;
@@ -1595,8 +1846,10 @@ UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
if (src+1+count >= end)
return(NULL);
do
- *dest++ = *++src ^ Stuff_Magic;
- while(--count >= 0 && dest < dest_end);
+ {
+ *dst++ = *++src ^ Stuff_Magic;
+ }
+ while(--count >= 0 && dst < dst_end);
if (count < 0)
*src = Stuff_Zero ^ Stuff_Magic;
else
@@ -1606,8 +1859,10 @@ UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
if (src+1 >= end)
return(NULL);
do
- *dest++ = src[1] ^ Stuff_Magic;
- while(--count >= 0 && dest < dest_end);
+ {
+ *dst++ = src[1] ^ Stuff_Magic;
+ }
+ while(--count >= 0 && dst < dst_end);
if (count < 0)
src += 2;
else
@@ -1615,8 +1870,10 @@ UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
break;
case Stuff_Zero:
do
- *dest++ = 0;
- while(--count >= 0 && dest < dest_end);
+ {
+ *dst++ = 0;
+ }
+ while(--count >= 0 && dst < dst_end);
if (count < 0)
src += 1;
else
@@ -1625,7 +1882,7 @@ UnStuffData(u_char *src, u_char *end, u_char *dest, u_long dest_length)
}
}
- if (dest < dest_end)
+ if (dst < dst_end)
return(NULL);
else
return(src);
@@ -1662,12 +1919,15 @@ RecvErr(msg, sc)
if (ptr == end) *p++ = '\"';
*p++ = 0;
- addlog("%13s : %s\n", msg, pkt_text);
+ addlog("%s: %13s : %s\n", sc->sc_if.if_xname, msg, pkt_text);
sc->sc_if.if_ierrors++;
}
+/*
+ * Parse an error message from the radio.
+ */
static void
RecvErr_Message(strip_info, sendername, msg)
struct st_softc *strip_info;
@@ -1690,13 +1950,13 @@ RecvErr_Message(strip_info, sendername, msg)
if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1))
{
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
addlog("%s: Radio %s is not in StarMode\n",
if_name, sendername);
}
else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1))
{
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
#ifdef notyet /*Kernel doesn't have scanf!*/
int handle;
u_char newname[64];
@@ -1707,94 +1967,49 @@ RecvErr_Message(strip_info, sendername, msg)
}
else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1))
{
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
addlog("%s: Destination radio name is unknown\n", if_name);
}
- else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1))
- {
-#ifdef notyet /* FIXME jrs */
- strip_info->watchdog_doreset = jiffies + LONG_TIME;
- if (!strip_info->working)
- {
- strip_info->working = 1;
- addlog("%s: Radio now in starmode\n", if_name);
+ else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) {
+ /*
+ * The radio reports it got a badly-framed starmode packet
+ * from us; so it must me in starmode.
+ */
+ if (strip_info->sc_if.if_flags & IFF_DEBUG)
+ addlog("%s: radio responded to probe\n", if_name);
+ if (strip_info->sc_state == ST_DEAD) {
+ /* A successful reset... */
+ addlog("%s: Radio back in starmode\n", if_name);
}
-#endif
+ CLEAR_RESET_TIMER(strip_info);
}
else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1))
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1))
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1))
{
/*
* Note: This error knocks the radio back into
* command mode.
*/
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
printf("%s: Error! Packet size too big for radio.",
if_name);
-#ifdef FIXME /* FIXME jrs */
- strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */
-#endif
+ FORCE_RESET(strip_info);
}
else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1))
{
- RecvErr("Error Msg:", strip_info);
+ RecvErr("radio error message:", strip_info);
printf("%s: Radio name contains illegal character\n",
if_name);
}
else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1))
- RecvErr("Error Msg:", strip_info);
- else
- RecvErr("Error Msg:", strip_info);
-}
-
-#ifdef DEBUG
-void
-stripdumpm(msg, m, len)
- const char *msg;
- struct mbuf *m;
-{
- stripdump(msg, mtod(m, u_char*), len);
- /*XXX*/
-}
-
-void
-stripdump(msg, p, len)
- const char *msg;
- u_char *p;
- int len;
-{
- register int i;
-
-
- printf(msg);
- for (i = 0; i < STRIP_HDRLEN; i++)
- printf("%c", p[i]);
- printf("\n");
-
- p += STRIP_HDRLEN;
- for (i = 0; i < 32; i++) {
- printf("%02x ", p[i]);
- }
- printf("\n");
-}
-
-void
-ipdump(msg, p, len)
- const char *msg;
- u_char *p;
- int len;
-{
- register int i;
-
- printf(msg);
- for (i = 0; i < 32; i++) {
- printf("%02x ", p[i]);
+ RecvErr("radio error message:", strip_info);
+ else {
+ addlog("failed to parse ]%3s[\n", msg);
+ RecvErr("unparsed radio error message:", strip_info);
}
- printf("\n");
}
-#endif /* DEBUG */
#endif /* NSTRIP > 0 */