133183Sbostic /* 238378Skarels * Copyright (c) 1987, 1989 Regents of the University of California. 333183Sbostic * All rights reserved. 433183Sbostic * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*51369Swilliam * @(#)if_sl.c 7.23 (Berkeley) 10/16/91 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 41*51369Swilliam /* $Header: /usr/src/sys/net/RCS/if_sl.c,v 1.1 91/08/30 11:14:57 william Exp Locker: william $ */ 4226121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 4326121Skarels 4426121Skarels #include "sl.h" 4526121Skarels #if NSL > 0 4626121Skarels 4726121Skarels #include "param.h" 4848454Skarels #include "proc.h" 4926121Skarels #include "mbuf.h" 5026121Skarels #include "buf.h" 5137472Ssklower #include "dkstat.h" 5226121Skarels #include "socket.h" 5326121Skarels #include "ioctl.h" 5426378Skarels #include "file.h" 5526121Skarels #include "tty.h" 5638365Swilliam #include "kernel.h" 5738365Swilliam #include "conf.h" 5826121Skarels 5926378Skarels #include "if.h" 6039212Ssklower #include "if_types.h" 6126378Skarels #include "netisr.h" 6226378Skarels #include "route.h" 6326378Skarels #if INET 6448454Skarels #include "netinet/in.h" 6548454Skarels #include "netinet/in_systm.h" 6648454Skarels #include "netinet/in_var.h" 6748454Skarels #include "netinet/ip.h" 6848454Skarels #else 6948454Skarels Huh? Slip without inet? 7026378Skarels #endif 7126121Skarels 7237500Smckusick #include "machine/mtpr.h" 7326121Skarels 7438378Skarels #include "slcompress.h" 7538378Skarels #include "if_slvar.h" 7638378Skarels 7726121Skarels /* 7839946Ssam * SLMAX is a hard limit on input packet size. To simplify the code 7938378Skarels * and improve performance, we require that packets fit in an mbuf 8039946Ssam * cluster, and if we get a compressed packet, there's enough extra 8139946Ssam * room to expand the header into a max length tcp/ip header (128 8239946Ssam * bytes). So, SLMAX can be at most 8339946Ssam * MCLBYTES - 128 8438378Skarels * 8539946Ssam * SLMTU is a hard limit on output packet size. To insure good 8639946Ssam * interactive response, SLMTU wants to be the smallest size that 8739946Ssam * amortizes the header cost. (Remember that even with 8839946Ssam * type-of-service queuing, we have to wait for any in-progress 8939946Ssam * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 9039946Ssam * cps, where cps is the line speed in characters per second. 9139946Ssam * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 9239946Ssam * average compressed header size is 6-8 bytes so any MTU > 90 9339946Ssam * bytes will give us 90% of the line bandwidth. A 100ms wait is 9439946Ssam * tolerable (500ms is not), so want an MTU around 296. (Since TCP 9539946Ssam * will send 256 byte segments (to allow for 40 byte headers), the 9639946Ssam * typical packet size on the wire will be around 260 bytes). In 9739946Ssam * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 9839946Ssam * leave the interface MTU relatively high (so we don't IP fragment 9939946Ssam * when acting as a gateway to someone using a stupid MTU). 10039946Ssam * 10139946Ssam * Similar considerations apply to SLIP_HIWAT: It's the amount of 10239946Ssam * data that will be queued 'downstream' of us (i.e., in clists 10339946Ssam * waiting to be picked up by the tty output interrupt). If we 10439946Ssam * queue a lot of data downstream, it's immune to our t.o.s. queuing. 10539946Ssam * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 10639946Ssam * telnet/ftp will see a 1 sec wait, independent of the mtu (the 10739946Ssam * wait is dependent on the ftp window size but that's typically 10839946Ssam * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 10939946Ssam * the cost (in idle time on the wire) of the tty driver running 11039946Ssam * off the end of its clists & having to call back slstart for a 11139946Ssam * new packet. For a tty interface with any buffering at all, this 11239946Ssam * cost will be zero. Even with a totally brain dead interface (like 11339946Ssam * the one on a typical workstation), the cost will be <= 1 character 11439946Ssam * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 11539946Ssam * at most 1% while maintaining good interactive response. 11626121Skarels */ 11738942Skarels #define BUFOFFSET 128 11839946Ssam #define SLMAX (MCLBYTES - BUFOFFSET) 11939946Ssam #define SLBUFSIZE (SLMAX + BUFOFFSET) 12039946Ssam #define SLMTU 296 12139946Ssam #define SLIP_HIWAT roundup(50,CBSIZE) 12238378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 12338942Skarels 12438365Swilliam /* 12538365Swilliam * SLIP ABORT ESCAPE MECHANISM: 12638365Swilliam * (inspired by HAYES modem escape arrangement) 12738365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 12838365Swilliam * signals a "soft" exit from slip mode by usermode process 12938365Swilliam */ 13026121Skarels 13138365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 13238365Swilliam #define ABT_WAIT 1 /* in seconds - idle before an escape & after */ 13338365Swilliam #define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */ 13426121Skarels 13538365Swilliam #define ABT_SOFT 3 /* count of escapes */ 13638365Swilliam 13738365Swilliam /* 13838378Skarels * The following disgusting hack gets around the problem that IP TOS 13938942Skarels * can't be set yet. We want to put "interactive" traffic on a high 14038942Skarels * priority queue. To decide if traffic is interactive, we check that 14138942Skarels * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 14238365Swilliam */ 14338378Skarels static u_short interactive_ports[8] = { 14438378Skarels 0, 513, 0, 0, 14538378Skarels 0, 21, 0, 23, 14638378Skarels }; 14738378Skarels #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 14838365Swilliam 14938378Skarels struct sl_softc sl_softc[NSL]; 15038365Swilliam 15138378Skarels #define FRAME_END 0xc0 /* Frame End */ 15238378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 15338378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 15438378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 15538365Swilliam 15626121Skarels #define t_sc T_LINEP 15726121Skarels 15826121Skarels int sloutput(), slioctl(), ttrstrt(); 15939212Ssklower extern struct timeval time; 16026121Skarels 16126121Skarels /* 16226121Skarels * Called from boot code to establish sl interfaces. 16326121Skarels */ 16426121Skarels slattach() 16526121Skarels { 16626121Skarels register struct sl_softc *sc; 16726121Skarels register int i = 0; 16826121Skarels 16926121Skarels for (sc = sl_softc; i < NSL; sc++) { 17026121Skarels sc->sc_if.if_name = "sl"; 17126121Skarels sc->sc_if.if_unit = i++; 17226121Skarels sc->sc_if.if_mtu = SLMTU; 17326121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 17439212Ssklower sc->sc_if.if_type = IFT_SLIP; 17526121Skarels sc->sc_if.if_ioctl = slioctl; 17626121Skarels sc->sc_if.if_output = sloutput; 17738378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 17838378Skarels sc->sc_fastq.ifq_maxlen = 32; 17926121Skarels if_attach(&sc->sc_if); 18026121Skarels } 18126121Skarels } 18226121Skarels 18338378Skarels static int 18438378Skarels slinit(sc) 18538378Skarels register struct sl_softc *sc; 18638378Skarels { 18738378Skarels register caddr_t p; 18838378Skarels 18938378Skarels if (sc->sc_ep == (u_char *) 0) { 19038378Skarels MCLALLOC(p, M_WAIT); 19138378Skarels if (p) 19238942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 19338378Skarels else { 19438378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 19538378Skarels sc->sc_if.if_flags &= ~IFF_UP; 19638378Skarels return (0); 19738378Skarels } 19838378Skarels } 19939946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 20038378Skarels sc->sc_mp = sc->sc_buf; 20138378Skarels sl_compress_init(&sc->sc_comp); 20238378Skarels return (1); 20338378Skarels } 20438378Skarels 20526121Skarels /* 20626121Skarels * Line specific open routine. 20726121Skarels * Attach the given tty to the first available sl unit. 20826121Skarels */ 20926378Skarels /* ARGSUSED */ 21026121Skarels slopen(dev, tp) 21126121Skarels dev_t dev; 21226121Skarels register struct tty *tp; 21326121Skarels { 21448454Skarels struct proc *p = curproc; /* XXX */ 21526121Skarels register struct sl_softc *sc; 21626121Skarels register int nsl; 21737549Smckusick int error; 21826121Skarels 21948454Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 22037549Smckusick return (error); 22138378Skarels 22226378Skarels if (tp->t_line == SLIPDISC) 22338942Skarels return (0); 22426121Skarels 22538378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 22626121Skarels if (sc->sc_ttyp == NULL) { 22726378Skarels if (slinit(sc) == 0) 22826378Skarels return (ENOBUFS); 22926121Skarels tp->t_sc = (caddr_t)sc; 23026121Skarels sc->sc_ttyp = tp; 23139212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 23226378Skarels ttyflush(tp, FREAD | FWRITE); 23326121Skarels return (0); 23426121Skarels } 23526378Skarels return (ENXIO); 23626121Skarels } 23726121Skarels 23826121Skarels /* 23926121Skarels * Line specific close routine. 24026121Skarels * Detach the tty from the sl unit. 24126121Skarels * Mimics part of ttyclose(). 24226121Skarels */ 24326121Skarels slclose(tp) 24426121Skarels struct tty *tp; 24526121Skarels { 24626121Skarels register struct sl_softc *sc; 24726121Skarels int s; 24826121Skarels 24926121Skarels ttywflush(tp); 25038378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 25126121Skarels tp->t_line = 0; 25226121Skarels sc = (struct sl_softc *)tp->t_sc; 25326121Skarels if (sc != NULL) { 25426121Skarels if_down(&sc->sc_if); 25526121Skarels sc->sc_ttyp = NULL; 25626121Skarels tp->t_sc = NULL; 25738942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 25838378Skarels sc->sc_ep = 0; 25938378Skarels sc->sc_mp = 0; 26026378Skarels sc->sc_buf = 0; 26126121Skarels } 26226121Skarels splx(s); 26326121Skarels } 26426121Skarels 26526121Skarels /* 26626121Skarels * Line specific (tty) ioctl routine. 26726121Skarels * Provide a way to get the sl unit number. 26826121Skarels */ 26926378Skarels /* ARGSUSED */ 27026121Skarels sltioctl(tp, cmd, data, flag) 27126121Skarels struct tty *tp; 27226121Skarels caddr_t data; 27326121Skarels { 27438365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 27538365Swilliam int s; 27626121Skarels 27738365Swilliam switch (cmd) { 27848454Skarels case SLIOCGUNIT: 27938365Swilliam *(int *)data = sc->sc_if.if_unit; 28038365Swilliam break; 28138365Swilliam 28238365Swilliam case SLIOCGFLAGS: 283*51369Swilliam *(int *)data = sc->sc_if.if_flags; 28438365Swilliam break; 28538378Skarels 28638365Swilliam case SLIOCSFLAGS: 287*51369Swilliam #define LLC_MASK (IFF_LLC0|IFF_LLC1|IFF_LLC2) 28838365Swilliam s = splimp(); 289*51369Swilliam sc->sc_if.if_flags = 290*51369Swilliam (sc->sc_if.if_flags &~ LLC_MASK) 291*51369Swilliam | ((*(int *)data) & LLC_MASK); 29238365Swilliam splx(s); 29338365Swilliam break; 29438378Skarels 29538365Swilliam default: 29638365Swilliam return (-1); 29738280Swilliam } 29838365Swilliam return (0); 29926121Skarels } 30026121Skarels 30126121Skarels /* 30226121Skarels * Queue a packet. Start transmission if not active. 30326121Skarels */ 30426121Skarels sloutput(ifp, m, dst) 30538942Skarels struct ifnet *ifp; 30626121Skarels register struct mbuf *m; 30726121Skarels struct sockaddr *dst; 30826121Skarels { 30938942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 31038378Skarels register struct ip *ip; 31138378Skarels register struct ifqueue *ifq; 31226121Skarels int s; 31326121Skarels 31426121Skarels /* 31526121Skarels * `Cannot happen' (see slioctl). Someday we will extend 31626121Skarels * the line protocol to support other address families. 31726121Skarels */ 31826121Skarels if (dst->sa_family != AF_INET) { 31938942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 32026121Skarels dst->sa_family); 32126121Skarels m_freem(m); 32226121Skarels return (EAFNOSUPPORT); 32326121Skarels } 32426121Skarels 32526121Skarels if (sc->sc_ttyp == NULL) { 32626121Skarels m_freem(m); 32726121Skarels return (ENETDOWN); /* sort of */ 32826121Skarels } 32926899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 33026899Skarels m_freem(m); 33126899Skarels return (EHOSTUNREACH); 33226899Skarels } 33338942Skarels ifq = &sc->sc_if.if_snd; 33438378Skarels if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 33538378Skarels register int p = ((int *)ip)[ip->ip_hl]; 33638378Skarels 33739946Ssam if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) { 33838378Skarels ifq = &sc->sc_fastq; 33939946Ssam p = 1; 34039946Ssam } else 34139946Ssam p = 0; 34238378Skarels 343*51369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 34439946Ssam /* 34539946Ssam * The last parameter turns off connection id 34639946Ssam * compression for background traffic: Since 34739946Ssam * fastq traffic can jump ahead of the background 34839946Ssam * traffic, we don't know what order packets will 34939946Ssam * go on the line. 35039946Ssam */ 35139946Ssam p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 35238378Skarels *mtod(m, u_char *) |= p; 35338365Swilliam } 354*51369Swilliam } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 35538378Skarels m_freem(m); 35638378Skarels return (0); 35738365Swilliam } 35838378Skarels s = splimp(); 35938378Skarels if (IF_QFULL(ifq)) { 36038378Skarels IF_DROP(ifq); 36138378Skarels m_freem(m); 36226121Skarels splx(s); 36326378Skarels sc->sc_if.if_oerrors++; 36426121Skarels return (ENOBUFS); 36526121Skarels } 36638378Skarels IF_ENQUEUE(ifq, m); 36739212Ssklower sc->sc_if.if_lastchange = time; 36838942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 36926121Skarels slstart(sc->sc_ttyp); 37038942Skarels splx(s); 37126121Skarels return (0); 37226121Skarels } 37326121Skarels 37426121Skarels /* 37526121Skarels * Start output on interface. Get another datagram 37626121Skarels * to send from the interface queue and map it to 37726121Skarels * the interface before starting output. 37826121Skarels */ 37926121Skarels slstart(tp) 38026121Skarels register struct tty *tp; 38126121Skarels { 38226121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 38326121Skarels register struct mbuf *m; 38426378Skarels register u_char *cp; 38538378Skarels int s; 38626378Skarels struct mbuf *m2; 38726378Skarels extern int cfreecount; 38826121Skarels 38926378Skarels for (;;) { 39026378Skarels /* 39126378Skarels * If there is more in the output queue, just send it now. 39226378Skarels * We are being called in lieu of ttstart and must do what 39326378Skarels * it would. 39426378Skarels */ 39538378Skarels if (tp->t_outq.c_cc != 0) { 39638378Skarels (*tp->t_oproc)(tp); 39738378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 39838378Skarels return; 39938378Skarels } 40026378Skarels /* 40126378Skarels * This happens briefly when the line shuts down. 40226378Skarels */ 40326378Skarels if (sc == NULL) 40426378Skarels return; 40526121Skarels 40626378Skarels /* 40726378Skarels * Get a packet and send it to the interface. 40826378Skarels */ 40926378Skarels s = splimp(); 41038378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 41138378Skarels if (m == NULL) 41238378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 41333740Skarels splx(s); 41433740Skarels if (m == NULL) 41526378Skarels return; 41639212Ssklower sc->sc_if.if_lastchange = time; 417*51369Swilliam 41838378Skarels /* 41938378Skarels * If system is getting low on clists, just flush our 42038378Skarels * output queue (if the stuff was important, it'll get 42138378Skarels * retransmitted). 42238378Skarels */ 42338378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 42438378Skarels m_freem(m); 42538378Skarels sc->sc_if.if_collisions++; 42638378Skarels continue; 42738378Skarels } 42826378Skarels /* 42926378Skarels * The extra FRAME_END will start up a new packet, and thus 43026378Skarels * will flush any accumulated garbage. We do this whenever 43126378Skarels * the line may have been idle for some time. 43226378Skarels */ 43338378Skarels if (tp->t_outq.c_cc == 0) { 43438378Skarels ++sc->sc_bytessent; 43526378Skarels (void) putc(FRAME_END, &tp->t_outq); 43638378Skarels } 43726378Skarels 43826378Skarels while (m) { 43938378Skarels register u_char *ep; 44038378Skarels 44138378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 44238378Skarels while (cp < ep) { 44326378Skarels /* 44426378Skarels * Find out how many bytes in the string we can 44526378Skarels * handle without doing something special. 44626378Skarels */ 44738378Skarels register u_char *bp = cp; 44838378Skarels 44938378Skarels while (cp < ep) { 45038378Skarels switch (*cp++) { 45138378Skarels case FRAME_ESCAPE: 45238378Skarels case FRAME_END: 45338378Skarels --cp; 45438378Skarels goto out; 45538378Skarels } 45638378Skarels } 45738378Skarels out: 45838378Skarels if (cp > bp) { 45926378Skarels /* 46026378Skarels * Put n characters at once 46126378Skarels * into the tty output queue. 46226378Skarels */ 46338378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 46426378Skarels break; 46538378Skarels sc->sc_bytessent += cp - bp; 46626121Skarels } 46726378Skarels /* 46826378Skarels * If there are characters left in the mbuf, 46926378Skarels * the first one must be special.. 47026378Skarels * Put it out in a different form. 47126378Skarels */ 47238378Skarels if (cp < ep) { 47326378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 47426378Skarels break; 47538378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 47626378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 47726378Skarels &tp->t_outq)) { 47826378Skarels (void) unputc(&tp->t_outq); 47926378Skarels break; 48026378Skarels } 48138378Skarels sc->sc_bytessent += 2; 48226378Skarels } 48326378Skarels } 48426378Skarels MFREE(m, m2); 48526378Skarels m = m2; 48626121Skarels } 48726378Skarels 48826378Skarels if (putc(FRAME_END, &tp->t_outq)) { 48926378Skarels /* 49026378Skarels * Not enough room. Remove a char to make room 49126378Skarels * and end the packet normally. 49226378Skarels * If you get many collisions (more than one or two 49326378Skarels * a day) you probably do not have enough clists 49426378Skarels * and you should increase "nclist" in param.c. 49526378Skarels */ 49626378Skarels (void) unputc(&tp->t_outq); 49726378Skarels (void) putc(FRAME_END, &tp->t_outq); 49826378Skarels sc->sc_if.if_collisions++; 49938378Skarels } else { 50038378Skarels ++sc->sc_bytessent; 50126378Skarels sc->sc_if.if_opackets++; 50226378Skarels } 50339212Ssklower sc->sc_if.if_obytes = sc->sc_bytessent; 50426378Skarels } 50526121Skarels } 50626121Skarels 50726121Skarels /* 50838378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 50926121Skarels */ 51038378Skarels static struct mbuf * 51138378Skarels sl_btom(sc, len) 51238378Skarels register struct sl_softc *sc; 51326121Skarels register int len; 51426121Skarels { 51538378Skarels register struct mbuf *m; 51626121Skarels 51738378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 51838378Skarels if (m == NULL) 51938378Skarels return (NULL); 52038378Skarels 52138378Skarels /* 52238942Skarels * If we have more than MHLEN bytes, it's cheaper to 52338378Skarels * queue the cluster we just filled & allocate a new one 52438378Skarels * for the input buffer. Otherwise, fill the mbuf we 52538378Skarels * allocated above. Note that code in the input routine 52638378Skarels * guarantees that packet will fit in a cluster. 52738378Skarels */ 52838378Skarels if (len >= MHLEN) { 52938378Skarels MCLGET(m, M_DONTWAIT); 53038378Skarels if ((m->m_flags & M_EXT) == 0) { 53138942Skarels /* 53238942Skarels * we couldn't get a cluster - if memory's this 53338942Skarels * low, it's time to start dropping packets. 53438942Skarels */ 53538942Skarels (void) m_free(m); 53626121Skarels return (NULL); 53726121Skarels } 53838942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 53938942Skarels m->m_data = (caddr_t)sc->sc_buf; 54038942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 54138378Skarels } else 54238942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 54338378Skarels 54438378Skarels m->m_len = len; 54538378Skarels m->m_pkthdr.len = len; 54638378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 54738378Skarels return (m); 54826121Skarels } 54926121Skarels 55026121Skarels /* 55126121Skarels * tty interface receiver interrupt. 55226121Skarels */ 55326121Skarels slinput(c, tp) 55426121Skarels register int c; 55526121Skarels register struct tty *tp; 55626121Skarels { 55726121Skarels register struct sl_softc *sc; 55826121Skarels register struct mbuf *m; 55938378Skarels register int len; 56026121Skarels int s; 56126121Skarels 56226378Skarels tk_nin++; 56326121Skarels sc = (struct sl_softc *)tp->t_sc; 56426121Skarels if (sc == NULL) 56526121Skarels return; 56638378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 56738365Swilliam return; 56826121Skarels 56938378Skarels ++sc->sc_bytesrcvd; 57039212Ssklower ++sc->sc_if.if_ibytes; 57138378Skarels c &= 0xff; /* XXX */ 57238365Swilliam 57338378Skarels #ifdef ABT_ESC 574*51369Swilliam { 57538378Skarels /* if we see an abort after "idle" time, count it */ 57638378Skarels if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 57738378Skarels sc->sc_abortcount++; 57838378Skarels /* record when the first abort escape arrived */ 57938378Skarels if (sc->sc_abortcount == 1) 58038378Skarels sc->sc_starttime = time.tv_sec; 58138378Skarels } 58238378Skarels /* 58338378Skarels * if we have an abort, see that we have not run out of time, 58438378Skarels * or that we have an "idle" time after the complete escape 58538378Skarels * sequence 58638378Skarels */ 58738378Skarels if (sc->sc_abortcount) { 58838378Skarels if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE) 58938378Skarels sc->sc_abortcount = 0; 59038378Skarels if (sc->sc_abortcount >= ABT_SOFT && 59138378Skarels time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 59238378Skarels slclose(tp); 59338378Skarels return; 59438378Skarels } 59538378Skarels } 59638378Skarels sc->sc_lasttime = time.tv_sec; 59738365Swilliam } 59838378Skarels #endif 59938365Swilliam 60038378Skarels switch (c) { 60138365Swilliam 60238378Skarels case TRANS_FRAME_ESCAPE: 60338378Skarels if (sc->sc_escape) 60438378Skarels c = FRAME_ESCAPE; 60538378Skarels break; 60638365Swilliam 60738378Skarels case TRANS_FRAME_END: 60838378Skarels if (sc->sc_escape) 60938378Skarels c = FRAME_END; 61038378Skarels break; 61138365Swilliam 61238378Skarels case FRAME_ESCAPE: 61338378Skarels sc->sc_escape = 1; 61438378Skarels return; 61526121Skarels 61638378Skarels case FRAME_END: 61738378Skarels len = sc->sc_mp - sc->sc_buf; 61838378Skarels if (len < 3) 61938378Skarels /* less than min length packet - ignore */ 62038378Skarels goto newpack; 62126121Skarels 62238378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 62338378Skarels if (c & 0x80) 62438378Skarels c = TYPE_COMPRESSED_TCP; 62538378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 62638378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 62739946Ssam /* 62839946Ssam * We've got something that's not an IP packet. 62939946Ssam * If compression is enabled, try to decompress it. 63039946Ssam * Otherwise, if `auto-enable' compression is on and 63139946Ssam * it's a reasonable packet, decompress it and then 63239946Ssam * enable compression. Otherwise, drop it. 63339946Ssam */ 634*51369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 63539946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 63639946Ssam (u_int)c, &sc->sc_comp); 63739946Ssam if (len <= 0) 63839946Ssam goto error; 639*51369Swilliam } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 64039946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 64139946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 64239946Ssam (u_int)c, &sc->sc_comp); 64339946Ssam if (len <= 0) 64439946Ssam goto error; 645*51369Swilliam sc->sc_if.if_flags |= SC_COMPRESS; 64639946Ssam } else 64738378Skarels goto error; 64838378Skarels } 64938378Skarels m = sl_btom(sc, len); 65038378Skarels if (m == NULL) 65138378Skarels goto error; 65226121Skarels 65338378Skarels sc->sc_if.if_ipackets++; 65439212Ssklower sc->sc_if.if_lastchange = time; 65538378Skarels s = splimp(); 65638378Skarels if (IF_QFULL(&ipintrq)) { 65738378Skarels IF_DROP(&ipintrq); 65826121Skarels sc->sc_if.if_ierrors++; 65939212Ssklower sc->sc_if.if_iqdrops++; 66038378Skarels m_freem(m); 66138378Skarels } else { 66238378Skarels IF_ENQUEUE(&ipintrq, m); 66338378Skarels schednetisr(NETISR_IP); 66426121Skarels } 66538378Skarels splx(s); 66638378Skarels goto newpack; 66726121Skarels } 66838378Skarels if (sc->sc_mp < sc->sc_ep) { 66938378Skarels *sc->sc_mp++ = c; 67038378Skarels sc->sc_escape = 0; 67126121Skarels return; 67226121Skarels } 67338378Skarels error: 67438378Skarels sc->sc_if.if_ierrors++; 67538378Skarels newpack: 67639946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 67738378Skarels sc->sc_escape = 0; 67826121Skarels } 67926121Skarels 68026121Skarels /* 68126121Skarels * Process an ioctl request. 68226121Skarels */ 68326121Skarels slioctl(ifp, cmd, data) 68426121Skarels register struct ifnet *ifp; 68526121Skarels int cmd; 68626121Skarels caddr_t data; 68726121Skarels { 68826121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 68926121Skarels int s = splimp(), error = 0; 69026121Skarels 69126121Skarels switch (cmd) { 69226121Skarels 69326121Skarels case SIOCSIFADDR: 69437472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 69526121Skarels ifp->if_flags |= IFF_UP; 69626121Skarels else 69726121Skarels error = EAFNOSUPPORT; 69826121Skarels break; 69926121Skarels 70026121Skarels case SIOCSIFDSTADDR: 70137472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 70226121Skarels error = EAFNOSUPPORT; 70326121Skarels break; 70426121Skarels 70526121Skarels default: 70626121Skarels error = EINVAL; 70726121Skarels } 70826121Skarels splx(s); 70926121Skarels return (error); 71026121Skarels } 71126121Skarels #endif 712