133183Sbostic /* 263211Sbostic * Copyright (c) 1987, 1989, 1992, 1993 363211Sbostic * The Regents of the University of California. All rights reserved. 433183Sbostic * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*65578Scgd * @(#)if_sl.c 8.4 (Berkeley) 01/07/94 833183Sbostic */ 926122Skarels 1026121Skarels /* 1126121Skarels * Serial Line interface 1226121Skarels * 1326121Skarels * Rick Adams 1426121Skarels * Center for Seismic Studies 1526121Skarels * 1300 N 17th Street, Suite 1450 1626121Skarels * Arlington, Virginia 22209 1726121Skarels * (703)276-7900 1826121Skarels * rick@seismo.ARPA 1926121Skarels * seismo!rick 2026121Skarels * 2126121Skarels * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 2226378Skarels * N.B.: this belongs in netinet, not net, the way it stands now. 2326122Skarels * Should have a link-layer type designation, but wouldn't be 2426122Skarels * backwards-compatible. 2526121Skarels * 2626121Skarels * Converted to 4.3BSD Beta by Chris Torek. 2726378Skarels * Other changes made at Berkeley, based in part on code by Kirk Smith. 2838378Skarels * W. Jolitz added slip abort. 2938378Skarels * 3038378Skarels * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). 3138378Skarels * Added priority queuing for "interactive" traffic; hooks for TCP 3238378Skarels * header compression; ICMP filtering (at 2400 baud, some cretin 3338378Skarels * pinging you can use up all your bandwidth). Made low clist behavior 3438378Skarels * more robust and slightly less likely to hang serial line. 3538378Skarels * Sped up a bunch of things. 3638378Skarels * 3738378Skarels * Note that splimp() is used throughout to block both (tty) input 3838378Skarels * interrupts and network activity; thus, splimp must be >= spltty. 3926121Skarels */ 4026121Skarels 4126121Skarels #include "sl.h" 4226121Skarels #if NSL > 0 4326121Skarels 44*65578Scgd #include "bpfilter.h" 45*65578Scgd 4656529Sbostic #include <sys/param.h> 4756529Sbostic #include <sys/proc.h> 4856529Sbostic #include <sys/mbuf.h> 4956529Sbostic #include <sys/buf.h> 5056529Sbostic #include <sys/dkstat.h> 5156529Sbostic #include <sys/socket.h> 5256529Sbostic #include <sys/ioctl.h> 5356529Sbostic #include <sys/file.h> 5456529Sbostic #include <sys/tty.h> 5556529Sbostic #include <sys/kernel.h> 5656529Sbostic #include <sys/conf.h> 5726121Skarels 5856529Sbostic #include <machine/cpu.h> 5952270Storek 6056529Sbostic #include <net/if.h> 6156529Sbostic #include <net/if_types.h> 6256529Sbostic #include <net/netisr.h> 6356529Sbostic #include <net/route.h> 6456529Sbostic 6526378Skarels #if INET 6656529Sbostic #include <netinet/in.h> 6756529Sbostic #include <netinet/in_systm.h> 6856529Sbostic #include <netinet/in_var.h> 6956529Sbostic #include <netinet/ip.h> 7048454Skarels #else 7148454Skarels Huh? Slip without inet? 7226378Skarels #endif 7326121Skarels 7456529Sbostic #include <net/slcompress.h> 7556529Sbostic #include <net/if_slvar.h> 7638378Skarels 77*65578Scgd #if NBPFILTER > 0 78*65578Scgd #include <sys/time.h> 79*65578Scgd #include <net/bpf.h> 80*65578Scgd #endif 81*65578Scgd 8226121Skarels /* 8339946Ssam * SLMAX is a hard limit on input packet size. To simplify the code 8438378Skarels * and improve performance, we require that packets fit in an mbuf 8539946Ssam * cluster, and if we get a compressed packet, there's enough extra 8639946Ssam * room to expand the header into a max length tcp/ip header (128 8739946Ssam * bytes). So, SLMAX can be at most 8839946Ssam * MCLBYTES - 128 8938378Skarels * 9039946Ssam * SLMTU is a hard limit on output packet size. To insure good 9139946Ssam * interactive response, SLMTU wants to be the smallest size that 9239946Ssam * amortizes the header cost. (Remember that even with 9339946Ssam * type-of-service queuing, we have to wait for any in-progress 9439946Ssam * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 9539946Ssam * cps, where cps is the line speed in characters per second. 9639946Ssam * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 9739946Ssam * average compressed header size is 6-8 bytes so any MTU > 90 9839946Ssam * bytes will give us 90% of the line bandwidth. A 100ms wait is 9939946Ssam * tolerable (500ms is not), so want an MTU around 296. (Since TCP 10039946Ssam * will send 256 byte segments (to allow for 40 byte headers), the 10139946Ssam * typical packet size on the wire will be around 260 bytes). In 10239946Ssam * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 10339946Ssam * leave the interface MTU relatively high (so we don't IP fragment 10439946Ssam * when acting as a gateway to someone using a stupid MTU). 10539946Ssam * 10639946Ssam * Similar considerations apply to SLIP_HIWAT: It's the amount of 10739946Ssam * data that will be queued 'downstream' of us (i.e., in clists 10839946Ssam * waiting to be picked up by the tty output interrupt). If we 10939946Ssam * queue a lot of data downstream, it's immune to our t.o.s. queuing. 11039946Ssam * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 11139946Ssam * telnet/ftp will see a 1 sec wait, independent of the mtu (the 11239946Ssam * wait is dependent on the ftp window size but that's typically 11339946Ssam * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 11439946Ssam * the cost (in idle time on the wire) of the tty driver running 11539946Ssam * off the end of its clists & having to call back slstart for a 11639946Ssam * new packet. For a tty interface with any buffering at all, this 11739946Ssam * cost will be zero. Even with a totally brain dead interface (like 11839946Ssam * the one on a typical workstation), the cost will be <= 1 character 11939946Ssam * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 12039946Ssam * at most 1% while maintaining good interactive response. 12126121Skarels */ 122*65578Scgd #if NBPFILTER > 0 123*65578Scgd #define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN) 124*65578Scgd #else 125*65578Scgd #define BUFOFFSET (128+sizeof(struct ifnet **)) 126*65578Scgd #endif 12739946Ssam #define SLMAX (MCLBYTES - BUFOFFSET) 12839946Ssam #define SLBUFSIZE (SLMAX + BUFOFFSET) 12939946Ssam #define SLMTU 296 13039946Ssam #define SLIP_HIWAT roundup(50,CBSIZE) 13138378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 13238942Skarels 13338365Swilliam /* 13438365Swilliam * SLIP ABORT ESCAPE MECHANISM: 13538365Swilliam * (inspired by HAYES modem escape arrangement) 13638365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 13752200Skarels * within window time signals a "soft" exit from slip mode by remote end 13852203Skarels * if the IFF_DEBUG flag is on. 13938365Swilliam */ 14038365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 141*65578Scgd #define ABT_IDLE 1 /* in seconds - idle before an escape */ 142*65578Scgd #define ABT_COUNT 3 /* count of escapes for abort */ 143*65578Scgd #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 14426121Skarels 14538378Skarels struct sl_softc sl_softc[NSL]; 14638365Swilliam 14738378Skarels #define FRAME_END 0xc0 /* Frame End */ 14838378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 14938378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 15038378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 15138365Swilliam 15239212Ssklower extern struct timeval time; 15326121Skarels 15461353Sbostic static int slinit __P((struct sl_softc *)); 15561353Sbostic static struct mbuf *sl_btom __P((struct sl_softc *, int)); 15661353Sbostic 15726121Skarels /* 15826121Skarels * Called from boot code to establish sl interfaces. 15926121Skarels */ 16061353Sbostic void 16126121Skarels slattach() 16226121Skarels { 16326121Skarels register struct sl_softc *sc; 16426121Skarels register int i = 0; 16526121Skarels 16626121Skarels for (sc = sl_softc; i < NSL; sc++) { 16726121Skarels sc->sc_if.if_name = "sl"; 16853817Smckusick sc->sc_if.if_next = NULL; 16926121Skarels sc->sc_if.if_unit = i++; 17026121Skarels sc->sc_if.if_mtu = SLMTU; 17154718Ssklower sc->sc_if.if_flags = 17254718Ssklower IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; 17339212Ssklower sc->sc_if.if_type = IFT_SLIP; 17426121Skarels sc->sc_if.if_ioctl = slioctl; 17526121Skarels sc->sc_if.if_output = sloutput; 17638378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 17738378Skarels sc->sc_fastq.ifq_maxlen = 32; 17826121Skarels if_attach(&sc->sc_if); 179*65578Scgd #if NBPFILTER > 0 180*65578Scgd bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN); 181*65578Scgd #endif 18226121Skarels } 18326121Skarels } 18426121Skarels 18538378Skarels static int 18638378Skarels slinit(sc) 18738378Skarels register struct sl_softc *sc; 18838378Skarels { 18938378Skarels register caddr_t p; 19038378Skarels 19138378Skarels if (sc->sc_ep == (u_char *) 0) { 19238378Skarels MCLALLOC(p, M_WAIT); 19338378Skarels if (p) 19438942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 19538378Skarels else { 19638378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 19738378Skarels sc->sc_if.if_flags &= ~IFF_UP; 19838378Skarels return (0); 19938378Skarels } 20038378Skarels } 20139946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 20238378Skarels sc->sc_mp = sc->sc_buf; 20338378Skarels sl_compress_init(&sc->sc_comp); 20438378Skarels return (1); 20538378Skarels } 20638378Skarels 20726121Skarels /* 20826121Skarels * Line specific open routine. 20926121Skarels * Attach the given tty to the first available sl unit. 21026121Skarels */ 21126378Skarels /* ARGSUSED */ 21261353Sbostic int 21326121Skarels slopen(dev, tp) 21426121Skarels dev_t dev; 21526121Skarels register struct tty *tp; 21626121Skarels { 21748454Skarels struct proc *p = curproc; /* XXX */ 21826121Skarels register struct sl_softc *sc; 21926121Skarels register int nsl; 22037549Smckusick int error; 22126121Skarels 22248454Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 22337549Smckusick return (error); 22438378Skarels 22526378Skarels if (tp->t_line == SLIPDISC) 22638942Skarels return (0); 22726121Skarels 22838378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 22926121Skarels if (sc->sc_ttyp == NULL) { 23026378Skarels if (slinit(sc) == 0) 23126378Skarels return (ENOBUFS); 23226121Skarels tp->t_sc = (caddr_t)sc; 23326121Skarels sc->sc_ttyp = tp; 23439212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 23526378Skarels ttyflush(tp, FREAD | FWRITE); 23626121Skarels return (0); 23726121Skarels } 23826378Skarels return (ENXIO); 23926121Skarels } 24026121Skarels 24126121Skarels /* 24226121Skarels * Line specific close routine. 24326121Skarels * Detach the tty from the sl unit. 24426121Skarels */ 24561353Sbostic void 24626121Skarels slclose(tp) 24726121Skarels struct tty *tp; 24826121Skarels { 24926121Skarels register struct sl_softc *sc; 25026121Skarels int s; 25126121Skarels 25226121Skarels ttywflush(tp); 25338378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 25426121Skarels tp->t_line = 0; 25526121Skarels sc = (struct sl_softc *)tp->t_sc; 25626121Skarels if (sc != NULL) { 25726121Skarels if_down(&sc->sc_if); 25826121Skarels sc->sc_ttyp = NULL; 25926121Skarels tp->t_sc = NULL; 26038942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 26138378Skarels sc->sc_ep = 0; 26238378Skarels sc->sc_mp = 0; 26326378Skarels sc->sc_buf = 0; 26426121Skarels } 26526121Skarels splx(s); 26626121Skarels } 26726121Skarels 26826121Skarels /* 26926121Skarels * Line specific (tty) ioctl routine. 27026121Skarels * Provide a way to get the sl unit number. 27126121Skarels */ 27226378Skarels /* ARGSUSED */ 27361353Sbostic int 27426121Skarels sltioctl(tp, cmd, data, flag) 27526121Skarels struct tty *tp; 27652946Storek int cmd; 27726121Skarels caddr_t data; 27852946Storek int flag; 27926121Skarels { 28038365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 281*65578Scgd int s; 28226121Skarels 28338365Swilliam switch (cmd) { 28448454Skarels case SLIOCGUNIT: 28538365Swilliam *(int *)data = sc->sc_if.if_unit; 28638365Swilliam break; 28738365Swilliam 28838365Swilliam default: 28938365Swilliam return (-1); 29038280Swilliam } 29138365Swilliam return (0); 29226121Skarels } 29326121Skarels 29426121Skarels /* 29526121Skarels * Queue a packet. Start transmission if not active. 296*65578Scgd * Compression happens in slstart; if we do it here, IP TOS 297*65578Scgd * will cause us to not compress "background" packets, because 298*65578Scgd * ordering gets trashed. It can be done for all packets in slstart. 29926121Skarels */ 30061353Sbostic int 30161353Sbostic sloutput(ifp, m, dst, rtp) 30238942Skarels struct ifnet *ifp; 30326121Skarels register struct mbuf *m; 30426121Skarels struct sockaddr *dst; 30561353Sbostic struct rtentry *rtp; 30626121Skarels { 30738942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 30838378Skarels register struct ip *ip; 30938378Skarels register struct ifqueue *ifq; 31026121Skarels int s; 31126121Skarels 31226121Skarels /* 31326121Skarels * `Cannot happen' (see slioctl). Someday we will extend 31426121Skarels * the line protocol to support other address families. 31526121Skarels */ 31626121Skarels if (dst->sa_family != AF_INET) { 31738942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 31826121Skarels dst->sa_family); 31926121Skarels m_freem(m); 32052200Skarels sc->sc_if.if_noproto++; 32126121Skarels return (EAFNOSUPPORT); 32226121Skarels } 32326121Skarels 32426121Skarels if (sc->sc_ttyp == NULL) { 32526121Skarels m_freem(m); 32626121Skarels return (ENETDOWN); /* sort of */ 32726121Skarels } 328*65578Scgd if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && 329*65578Scgd (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { 33026899Skarels m_freem(m); 33126899Skarels return (EHOSTUNREACH); 33226899Skarels } 33338942Skarels ifq = &sc->sc_if.if_snd; 33452946Storek ip = mtod(m, struct ip *); 335*65578Scgd if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 33638378Skarels m_freem(m); 33752200Skarels return (ENETRESET); /* XXX ? */ 33838365Swilliam } 339*65578Scgd if (ip->ip_tos & IPTOS_LOWDELAY) 340*65578Scgd ifq = &sc->sc_fastq; 34138378Skarels s = splimp(); 34238378Skarels if (IF_QFULL(ifq)) { 34338378Skarels IF_DROP(ifq); 34438378Skarels m_freem(m); 34526121Skarels splx(s); 34626378Skarels sc->sc_if.if_oerrors++; 34726121Skarels return (ENOBUFS); 34826121Skarels } 34938378Skarels IF_ENQUEUE(ifq, m); 35039212Ssklower sc->sc_if.if_lastchange = time; 35138942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 35226121Skarels slstart(sc->sc_ttyp); 35338942Skarels splx(s); 35426121Skarels return (0); 35526121Skarels } 35626121Skarels 35726121Skarels /* 35826121Skarels * Start output on interface. Get another datagram 35926121Skarels * to send from the interface queue and map it to 36026121Skarels * the interface before starting output. 36126121Skarels */ 36261353Sbostic void 36326121Skarels slstart(tp) 36426121Skarels register struct tty *tp; 36526121Skarels { 36626121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 36726121Skarels register struct mbuf *m; 36826378Skarels register u_char *cp; 369*65578Scgd register struct ip *ip; 37038378Skarels int s; 37126378Skarels struct mbuf *m2; 372*65578Scgd #if NBPFILTER > 0 373*65578Scgd u_char bpfbuf[SLMTU + SLIP_HDRLEN]; 374*65578Scgd register int len; 375*65578Scgd #endif 37626378Skarels extern int cfreecount; 37726121Skarels 37826378Skarels for (;;) { 37926378Skarels /* 38026378Skarels * If there is more in the output queue, just send it now. 38126378Skarels * We are being called in lieu of ttstart and must do what 38226378Skarels * it would. 38326378Skarels */ 38438378Skarels if (tp->t_outq.c_cc != 0) { 38538378Skarels (*tp->t_oproc)(tp); 38638378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 38738378Skarels return; 38838378Skarels } 38926378Skarels /* 39026378Skarels * This happens briefly when the line shuts down. 39126378Skarels */ 39226378Skarels if (sc == NULL) 39326378Skarels return; 39426121Skarels 39526378Skarels /* 39626378Skarels * Get a packet and send it to the interface. 39726378Skarels */ 39826378Skarels s = splimp(); 39938378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 40052200Skarels if (m) 40152200Skarels sc->sc_if.if_omcasts++; /* XXX */ 40252200Skarels else 40338378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 40433740Skarels splx(s); 40533740Skarels if (m == NULL) 40626378Skarels return; 407*65578Scgd 408*65578Scgd /* 409*65578Scgd * We do the header compression here rather than in sloutput 410*65578Scgd * because the packets will be out of order if we are using TOS 411*65578Scgd * queueing, and the connection id compression will get 412*65578Scgd * munged when this happens. 413*65578Scgd */ 414*65578Scgd #if NBPFILTER > 0 415*65578Scgd if (sc->sc_bpf) { 416*65578Scgd /* 417*65578Scgd * We need to save the TCP/IP header before it's 418*65578Scgd * compressed. To avoid complicated code, we just 419*65578Scgd * copy the entire packet into a stack buffer (since 420*65578Scgd * this is a serial line, packets should be short 421*65578Scgd * and/or the copy should be negligible cost compared 422*65578Scgd * to the packet transmission time). 423*65578Scgd */ 424*65578Scgd register struct mbuf *m1 = m; 425*65578Scgd register u_char *cp = bpfbuf + SLIP_HDRLEN; 426*65578Scgd 427*65578Scgd len = 0; 428*65578Scgd do { 429*65578Scgd register int mlen = m1->m_len; 430*65578Scgd 431*65578Scgd bcopy(mtod(m1, caddr_t), cp, mlen); 432*65578Scgd cp += mlen; 433*65578Scgd len += mlen; 434*65578Scgd } while (m1 = m1->m_next); 435*65578Scgd } 436*65578Scgd #endif 437*65578Scgd if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 438*65578Scgd if (sc->sc_if.if_flags & SC_COMPRESS) 439*65578Scgd *mtod(m, u_char *) |= sl_compress_tcp(m, ip, 440*65578Scgd &sc->sc_comp, 1); 441*65578Scgd } 442*65578Scgd #if NBPFILTER > 0 443*65578Scgd if (sc->sc_bpf) { 444*65578Scgd /* 445*65578Scgd * Put the SLIP pseudo-"link header" in place. The 446*65578Scgd * compressed header is now at the beginning of the 447*65578Scgd * mbuf. 448*65578Scgd */ 449*65578Scgd bpfbuf[SLX_DIR] = SLIPDIR_OUT; 450*65578Scgd bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN); 451*65578Scgd bpf_tap(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN); 452*65578Scgd } 453*65578Scgd #endif 45439212Ssklower sc->sc_if.if_lastchange = time; 45551369Swilliam 45638378Skarels /* 45738378Skarels * If system is getting low on clists, just flush our 45838378Skarels * output queue (if the stuff was important, it'll get 45938378Skarels * retransmitted). 46038378Skarels */ 46138378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 46238378Skarels m_freem(m); 46338378Skarels sc->sc_if.if_collisions++; 46438378Skarels continue; 46538378Skarels } 46626378Skarels /* 46726378Skarels * The extra FRAME_END will start up a new packet, and thus 46826378Skarels * will flush any accumulated garbage. We do this whenever 46926378Skarels * the line may have been idle for some time. 47026378Skarels */ 47138378Skarels if (tp->t_outq.c_cc == 0) { 47252200Skarels ++sc->sc_if.if_obytes; 47326378Skarels (void) putc(FRAME_END, &tp->t_outq); 47438378Skarels } 47526378Skarels 47626378Skarels while (m) { 47738378Skarels register u_char *ep; 47838378Skarels 47938378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 48038378Skarels while (cp < ep) { 48126378Skarels /* 48226378Skarels * Find out how many bytes in the string we can 48326378Skarels * handle without doing something special. 48426378Skarels */ 48538378Skarels register u_char *bp = cp; 48638378Skarels 48738378Skarels while (cp < ep) { 48838378Skarels switch (*cp++) { 48938378Skarels case FRAME_ESCAPE: 49038378Skarels case FRAME_END: 49138378Skarels --cp; 49238378Skarels goto out; 49338378Skarels } 49438378Skarels } 49538378Skarels out: 49638378Skarels if (cp > bp) { 49726378Skarels /* 49826378Skarels * Put n characters at once 49926378Skarels * into the tty output queue. 50026378Skarels */ 501*65578Scgd if (b_to_q((char *)bp, cp - bp, 502*65578Scgd &tp->t_outq)) 50326378Skarels break; 50452200Skarels sc->sc_if.if_obytes += cp - bp; 50526121Skarels } 50626378Skarels /* 50726378Skarels * If there are characters left in the mbuf, 50826378Skarels * the first one must be special.. 50926378Skarels * Put it out in a different form. 51026378Skarels */ 51138378Skarels if (cp < ep) { 51226378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 51326378Skarels break; 51438378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 51526378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 51626378Skarels &tp->t_outq)) { 51726378Skarels (void) unputc(&tp->t_outq); 51826378Skarels break; 51926378Skarels } 52052200Skarels sc->sc_if.if_obytes += 2; 52126378Skarels } 52226378Skarels } 52326378Skarels MFREE(m, m2); 52426378Skarels m = m2; 52526121Skarels } 52626378Skarels 52726378Skarels if (putc(FRAME_END, &tp->t_outq)) { 52826378Skarels /* 52926378Skarels * Not enough room. Remove a char to make room 53026378Skarels * and end the packet normally. 53126378Skarels * If you get many collisions (more than one or two 53226378Skarels * a day) you probably do not have enough clists 53326378Skarels * and you should increase "nclist" in param.c. 53426378Skarels */ 53526378Skarels (void) unputc(&tp->t_outq); 53626378Skarels (void) putc(FRAME_END, &tp->t_outq); 53726378Skarels sc->sc_if.if_collisions++; 53838378Skarels } else { 53952200Skarels ++sc->sc_if.if_obytes; 54026378Skarels sc->sc_if.if_opackets++; 54126378Skarels } 54226378Skarels } 54326121Skarels } 54426121Skarels 54526121Skarels /* 54638378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 54726121Skarels */ 54838378Skarels static struct mbuf * 54938378Skarels sl_btom(sc, len) 55038378Skarels register struct sl_softc *sc; 55126121Skarels register int len; 55226121Skarels { 55338378Skarels register struct mbuf *m; 55426121Skarels 55538378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 55638378Skarels if (m == NULL) 55738378Skarels return (NULL); 55838378Skarels 55938378Skarels /* 56038942Skarels * If we have more than MHLEN bytes, it's cheaper to 56138378Skarels * queue the cluster we just filled & allocate a new one 56238378Skarels * for the input buffer. Otherwise, fill the mbuf we 56338378Skarels * allocated above. Note that code in the input routine 56438378Skarels * guarantees that packet will fit in a cluster. 56538378Skarels */ 56638378Skarels if (len >= MHLEN) { 56738378Skarels MCLGET(m, M_DONTWAIT); 56838378Skarels if ((m->m_flags & M_EXT) == 0) { 56938942Skarels /* 57038942Skarels * we couldn't get a cluster - if memory's this 57138942Skarels * low, it's time to start dropping packets. 57238942Skarels */ 57338942Skarels (void) m_free(m); 57426121Skarels return (NULL); 57526121Skarels } 57638942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 57738942Skarels m->m_data = (caddr_t)sc->sc_buf; 57838942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 57938378Skarels } else 58038942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 58138378Skarels 58238378Skarels m->m_len = len; 58338378Skarels m->m_pkthdr.len = len; 58438378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 58538378Skarels return (m); 58626121Skarels } 58726121Skarels 58826121Skarels /* 58926121Skarels * tty interface receiver interrupt. 59026121Skarels */ 59161353Sbostic void 59226121Skarels slinput(c, tp) 59326121Skarels register int c; 59426121Skarels register struct tty *tp; 59526121Skarels { 59626121Skarels register struct sl_softc *sc; 59726121Skarels register struct mbuf *m; 59838378Skarels register int len; 59926121Skarels int s; 600*65578Scgd #if NBPFILTER > 0 601*65578Scgd u_char chdr[CHDR_LEN]; 602*65578Scgd #endif 60326121Skarels 60426378Skarels tk_nin++; 60526121Skarels sc = (struct sl_softc *)tp->t_sc; 60626121Skarels if (sc == NULL) 60726121Skarels return; 608*65578Scgd if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 && 609*65578Scgd (tp->t_cflag & CLOCAL) == 0)) { 610*65578Scgd sc->sc_flags |= SC_ERROR; 61138365Swilliam return; 612*65578Scgd } 613*65578Scgd c &= TTY_CHARMASK; 61426121Skarels 61539212Ssklower ++sc->sc_if.if_ibytes; 61638365Swilliam 61752200Skarels if (sc->sc_if.if_flags & IFF_DEBUG) { 61852200Skarels if (c == ABT_ESC) { 61952200Skarels /* 62052200Skarels * If we have a previous abort, see whether 62152200Skarels * this one is within the time limit. 62252200Skarels */ 62352200Skarels if (sc->sc_abortcount && 62452200Skarels time.tv_sec >= sc->sc_starttime + ABT_WINDOW) 62538378Skarels sc->sc_abortcount = 0; 62652200Skarels /* 62752200Skarels * If we see an abort after "idle" time, count it; 62852200Skarels * record when the first abort escape arrived. 62952200Skarels */ 63052200Skarels if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { 63152200Skarels if (++sc->sc_abortcount == 1) 63252200Skarels sc->sc_starttime = time.tv_sec; 63352200Skarels if (sc->sc_abortcount >= ABT_COUNT) { 63452200Skarels slclose(tp); 63552200Skarels return; 63652200Skarels } 63738378Skarels } 63852200Skarels } else 63952200Skarels sc->sc_abortcount = 0; 64038378Skarels sc->sc_lasttime = time.tv_sec; 64138365Swilliam } 64238365Swilliam 64338378Skarels switch (c) { 64438365Swilliam 64538378Skarels case TRANS_FRAME_ESCAPE: 64638378Skarels if (sc->sc_escape) 64738378Skarels c = FRAME_ESCAPE; 64838378Skarels break; 64938365Swilliam 65038378Skarels case TRANS_FRAME_END: 65138378Skarels if (sc->sc_escape) 65238378Skarels c = FRAME_END; 65338378Skarels break; 65438365Swilliam 65538378Skarels case FRAME_ESCAPE: 65638378Skarels sc->sc_escape = 1; 65738378Skarels return; 65826121Skarels 65938378Skarels case FRAME_END: 660*65578Scgd if(sc->sc_flags & SC_ERROR) { 661*65578Scgd sc->sc_flags &= ~SC_ERROR; 662*65578Scgd goto newpack; 663*65578Scgd } 66438378Skarels len = sc->sc_mp - sc->sc_buf; 66538378Skarels if (len < 3) 66638378Skarels /* less than min length packet - ignore */ 66738378Skarels goto newpack; 66826121Skarels 669*65578Scgd #if NBPFILTER > 0 670*65578Scgd if (sc->sc_bpf) { 671*65578Scgd /* 672*65578Scgd * Save the compressed header, so we 673*65578Scgd * can tack it on later. Note that we 674*65578Scgd * will end up copying garbage in some 675*65578Scgd * cases but this is okay. We remember 676*65578Scgd * where the buffer started so we can 677*65578Scgd * compute the new header length. 678*65578Scgd */ 679*65578Scgd bcopy(sc->sc_buf, chdr, CHDR_LEN); 680*65578Scgd } 681*65578Scgd #endif 682*65578Scgd 68338378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 68438378Skarels if (c & 0x80) 68538378Skarels c = TYPE_COMPRESSED_TCP; 68638378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 68738378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 68839946Ssam /* 68939946Ssam * We've got something that's not an IP packet. 69039946Ssam * If compression is enabled, try to decompress it. 69139946Ssam * Otherwise, if `auto-enable' compression is on and 69239946Ssam * it's a reasonable packet, decompress it and then 69339946Ssam * enable compression. Otherwise, drop it. 69439946Ssam */ 69551369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 69639946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 69739946Ssam (u_int)c, &sc->sc_comp); 69839946Ssam if (len <= 0) 69939946Ssam goto error; 70051369Swilliam } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 70139946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 70239946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 70339946Ssam (u_int)c, &sc->sc_comp); 70439946Ssam if (len <= 0) 70539946Ssam goto error; 70651369Swilliam sc->sc_if.if_flags |= SC_COMPRESS; 70739946Ssam } else 70838378Skarels goto error; 70938378Skarels } 710*65578Scgd #if NBPFILTER > 0 711*65578Scgd if (sc->sc_bpf) { 712*65578Scgd /* 713*65578Scgd * Put the SLIP pseudo-"link header" in place. 714*65578Scgd * We couldn't do this any earlier since 715*65578Scgd * decompression probably moved the buffer 716*65578Scgd * pointer. Then, invoke BPF. 717*65578Scgd */ 718*65578Scgd register u_char *hp = sc->sc_buf - SLIP_HDRLEN; 719*65578Scgd 720*65578Scgd hp[SLX_DIR] = SLIPDIR_IN; 721*65578Scgd bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN); 722*65578Scgd bpf_tap(sc->sc_bpf, hp, len + SLIP_HDRLEN); 723*65578Scgd } 724*65578Scgd #endif 72538378Skarels m = sl_btom(sc, len); 72638378Skarels if (m == NULL) 72738378Skarels goto error; 72826121Skarels 72938378Skarels sc->sc_if.if_ipackets++; 73039212Ssklower sc->sc_if.if_lastchange = time; 73138378Skarels s = splimp(); 73238378Skarels if (IF_QFULL(&ipintrq)) { 73338378Skarels IF_DROP(&ipintrq); 73426121Skarels sc->sc_if.if_ierrors++; 73539212Ssklower sc->sc_if.if_iqdrops++; 73638378Skarels m_freem(m); 73738378Skarels } else { 73838378Skarels IF_ENQUEUE(&ipintrq, m); 73938378Skarels schednetisr(NETISR_IP); 74026121Skarels } 74138378Skarels splx(s); 74238378Skarels goto newpack; 74326121Skarels } 74438378Skarels if (sc->sc_mp < sc->sc_ep) { 74538378Skarels *sc->sc_mp++ = c; 74638378Skarels sc->sc_escape = 0; 74726121Skarels return; 74826121Skarels } 749*65578Scgd 750*65578Scgd /* can't put lower; would miss an extra frame */ 751*65578Scgd sc->sc_flags |= SC_ERROR; 752*65578Scgd 75338378Skarels error: 75438378Skarels sc->sc_if.if_ierrors++; 75538378Skarels newpack: 75639946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 75738378Skarels sc->sc_escape = 0; 75826121Skarels } 75926121Skarels 76026121Skarels /* 76126121Skarels * Process an ioctl request. 76226121Skarels */ 76361353Sbostic int 76426121Skarels slioctl(ifp, cmd, data) 76526121Skarels register struct ifnet *ifp; 76626121Skarels int cmd; 76726121Skarels caddr_t data; 76826121Skarels { 76926121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 77054718Ssklower register struct ifreq *ifr; 77154718Ssklower register int s = splimp(), error = 0; 77226121Skarels 77326121Skarels switch (cmd) { 77426121Skarels 77526121Skarels case SIOCSIFADDR: 77637472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 77726121Skarels ifp->if_flags |= IFF_UP; 77826121Skarels else 77926121Skarels error = EAFNOSUPPORT; 78026121Skarels break; 78126121Skarels 78226121Skarels case SIOCSIFDSTADDR: 78337472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 78426121Skarels error = EAFNOSUPPORT; 78526121Skarels break; 78626121Skarels 78754718Ssklower case SIOCADDMULTI: 78854718Ssklower case SIOCDELMULTI: 78954718Ssklower ifr = (struct ifreq *)data; 79054718Ssklower if (ifr == 0) { 79154718Ssklower error = EAFNOSUPPORT; /* XXX */ 79254718Ssklower break; 79354718Ssklower } 79454718Ssklower switch (ifr->ifr_addr.sa_family) { 79554718Ssklower 79654718Ssklower #ifdef INET 79754718Ssklower case AF_INET: 79854718Ssklower break; 79954718Ssklower #endif 80054718Ssklower 80154718Ssklower default: 80254718Ssklower error = EAFNOSUPPORT; 80354718Ssklower break; 80454718Ssklower } 80554718Ssklower break; 80654718Ssklower 80726121Skarels default: 80826121Skarels error = EINVAL; 80926121Skarels } 81026121Skarels splx(s); 81126121Skarels return (error); 81226121Skarels } 813*65578Scgd #endif 814