133183Sbostic /* 238378Skarels * Copyright (c) 1987, 1989 Regents of the University of California. 333183Sbostic * All rights reserved. 433183Sbostic * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*52200Skarels * @(#)if_sl.c 7.24 (Berkeley) 01/14/92 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 4426121Skarels #include "param.h" 4548454Skarels #include "proc.h" 4626121Skarels #include "mbuf.h" 4726121Skarels #include "buf.h" 4837472Ssklower #include "dkstat.h" 4926121Skarels #include "socket.h" 5026121Skarels #include "ioctl.h" 5126378Skarels #include "file.h" 5226121Skarels #include "tty.h" 5338365Swilliam #include "kernel.h" 5438365Swilliam #include "conf.h" 5526121Skarels 5626378Skarels #include "if.h" 5739212Ssklower #include "if_types.h" 5826378Skarels #include "netisr.h" 5926378Skarels #include "route.h" 6026378Skarels #if INET 6148454Skarels #include "netinet/in.h" 6248454Skarels #include "netinet/in_systm.h" 6348454Skarels #include "netinet/in_var.h" 6448454Skarels #include "netinet/ip.h" 6548454Skarels #else 6648454Skarels Huh? Slip without inet? 6726378Skarels #endif 6826121Skarels 6937500Smckusick #include "machine/mtpr.h" 7026121Skarels 7138378Skarels #include "slcompress.h" 7238378Skarels #include "if_slvar.h" 7338378Skarels 7426121Skarels /* 7539946Ssam * SLMAX is a hard limit on input packet size. To simplify the code 7638378Skarels * and improve performance, we require that packets fit in an mbuf 7739946Ssam * cluster, and if we get a compressed packet, there's enough extra 7839946Ssam * room to expand the header into a max length tcp/ip header (128 7939946Ssam * bytes). So, SLMAX can be at most 8039946Ssam * MCLBYTES - 128 8138378Skarels * 8239946Ssam * SLMTU is a hard limit on output packet size. To insure good 8339946Ssam * interactive response, SLMTU wants to be the smallest size that 8439946Ssam * amortizes the header cost. (Remember that even with 8539946Ssam * type-of-service queuing, we have to wait for any in-progress 8639946Ssam * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 8739946Ssam * cps, where cps is the line speed in characters per second. 8839946Ssam * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 8939946Ssam * average compressed header size is 6-8 bytes so any MTU > 90 9039946Ssam * bytes will give us 90% of the line bandwidth. A 100ms wait is 9139946Ssam * tolerable (500ms is not), so want an MTU around 296. (Since TCP 9239946Ssam * will send 256 byte segments (to allow for 40 byte headers), the 9339946Ssam * typical packet size on the wire will be around 260 bytes). In 9439946Ssam * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 9539946Ssam * leave the interface MTU relatively high (so we don't IP fragment 9639946Ssam * when acting as a gateway to someone using a stupid MTU). 9739946Ssam * 9839946Ssam * Similar considerations apply to SLIP_HIWAT: It's the amount of 9939946Ssam * data that will be queued 'downstream' of us (i.e., in clists 10039946Ssam * waiting to be picked up by the tty output interrupt). If we 10139946Ssam * queue a lot of data downstream, it's immune to our t.o.s. queuing. 10239946Ssam * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 10339946Ssam * telnet/ftp will see a 1 sec wait, independent of the mtu (the 10439946Ssam * wait is dependent on the ftp window size but that's typically 10539946Ssam * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 10639946Ssam * the cost (in idle time on the wire) of the tty driver running 10739946Ssam * off the end of its clists & having to call back slstart for a 10839946Ssam * new packet. For a tty interface with any buffering at all, this 10939946Ssam * cost will be zero. Even with a totally brain dead interface (like 11039946Ssam * the one on a typical workstation), the cost will be <= 1 character 11139946Ssam * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 11239946Ssam * at most 1% while maintaining good interactive response. 11326121Skarels */ 11438942Skarels #define BUFOFFSET 128 11539946Ssam #define SLMAX (MCLBYTES - BUFOFFSET) 11639946Ssam #define SLBUFSIZE (SLMAX + BUFOFFSET) 11739946Ssam #define SLMTU 296 11839946Ssam #define SLIP_HIWAT roundup(50,CBSIZE) 11938378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 12038942Skarels 12138365Swilliam /* 12238365Swilliam * SLIP ABORT ESCAPE MECHANISM: 12338365Swilliam * (inspired by HAYES modem escape arrangement) 12438365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 125*52200Skarels * within window time signals a "soft" exit from slip mode by remote end 12638365Swilliam */ 12726121Skarels 12838365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 129*52200Skarels #define ABT_IDLE 1 /* in seconds - idle before an escape */ 130*52200Skarels #define ABT_COUNT 3 /* count of escapes for abort */ 131*52200Skarels #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 13226121Skarels 13338365Swilliam 134*52200Skarels #ifdef nomore 13538365Swilliam /* 13638378Skarels * The following disgusting hack gets around the problem that IP TOS 13738942Skarels * can't be set yet. We want to put "interactive" traffic on a high 13838942Skarels * priority queue. To decide if traffic is interactive, we check that 13938942Skarels * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 14038365Swilliam */ 14138378Skarels static u_short interactive_ports[8] = { 14238378Skarels 0, 513, 0, 0, 14338378Skarels 0, 21, 0, 23, 14438378Skarels }; 14538378Skarels #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 146*52200Skarels #endif 14738365Swilliam 14838378Skarels struct sl_softc sl_softc[NSL]; 14938365Swilliam 15038378Skarels #define FRAME_END 0xc0 /* Frame End */ 15138378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 15238378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 15338378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 15438365Swilliam 15526121Skarels #define t_sc T_LINEP 15626121Skarels 15726121Skarels int sloutput(), slioctl(), ttrstrt(); 15839212Ssklower extern struct timeval time; 15926121Skarels 16026121Skarels /* 16126121Skarels * Called from boot code to establish sl interfaces. 16226121Skarels */ 16326121Skarels slattach() 16426121Skarels { 16526121Skarels register struct sl_softc *sc; 16626121Skarels register int i = 0; 16726121Skarels 16826121Skarels for (sc = sl_softc; i < NSL; sc++) { 16926121Skarels sc->sc_if.if_name = "sl"; 17026121Skarels sc->sc_if.if_unit = i++; 17126121Skarels sc->sc_if.if_mtu = SLMTU; 17226121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 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); 17926121Skarels } 18026121Skarels } 18126121Skarels 18238378Skarels static int 18338378Skarels slinit(sc) 18438378Skarels register struct sl_softc *sc; 18538378Skarels { 18638378Skarels register caddr_t p; 18738378Skarels 18838378Skarels if (sc->sc_ep == (u_char *) 0) { 18938378Skarels MCLALLOC(p, M_WAIT); 19038378Skarels if (p) 19138942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 19238378Skarels else { 19338378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 19438378Skarels sc->sc_if.if_flags &= ~IFF_UP; 19538378Skarels return (0); 19638378Skarels } 19738378Skarels } 19839946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 19938378Skarels sc->sc_mp = sc->sc_buf; 20038378Skarels sl_compress_init(&sc->sc_comp); 20138378Skarels return (1); 20238378Skarels } 20338378Skarels 20426121Skarels /* 20526121Skarels * Line specific open routine. 20626121Skarels * Attach the given tty to the first available sl unit. 20726121Skarels */ 20826378Skarels /* ARGSUSED */ 20926121Skarels slopen(dev, tp) 21026121Skarels dev_t dev; 21126121Skarels register struct tty *tp; 21226121Skarels { 21348454Skarels struct proc *p = curproc; /* XXX */ 21426121Skarels register struct sl_softc *sc; 21526121Skarels register int nsl; 21637549Smckusick int error; 21726121Skarels 21848454Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 21937549Smckusick return (error); 22038378Skarels 22126378Skarels if (tp->t_line == SLIPDISC) 22238942Skarels return (0); 22326121Skarels 22438378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 22526121Skarels if (sc->sc_ttyp == NULL) { 22626378Skarels if (slinit(sc) == 0) 22726378Skarels return (ENOBUFS); 22826121Skarels tp->t_sc = (caddr_t)sc; 22926121Skarels sc->sc_ttyp = tp; 23039212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 23126378Skarels ttyflush(tp, FREAD | FWRITE); 23226121Skarels return (0); 23326121Skarels } 23426378Skarels return (ENXIO); 23526121Skarels } 23626121Skarels 23726121Skarels /* 23826121Skarels * Line specific close routine. 23926121Skarels * Detach the tty from the sl unit. 24026121Skarels * Mimics part of ttyclose(). 24126121Skarels */ 24226121Skarels slclose(tp) 24326121Skarels struct tty *tp; 24426121Skarels { 24526121Skarels register struct sl_softc *sc; 24626121Skarels int s; 24726121Skarels 24826121Skarels ttywflush(tp); 24938378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 25026121Skarels tp->t_line = 0; 25126121Skarels sc = (struct sl_softc *)tp->t_sc; 25226121Skarels if (sc != NULL) { 25326121Skarels if_down(&sc->sc_if); 25426121Skarels sc->sc_ttyp = NULL; 25526121Skarels tp->t_sc = NULL; 25638942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 25738378Skarels sc->sc_ep = 0; 25838378Skarels sc->sc_mp = 0; 25926378Skarels sc->sc_buf = 0; 26026121Skarels } 26126121Skarels splx(s); 26226121Skarels } 26326121Skarels 26426121Skarels /* 26526121Skarels * Line specific (tty) ioctl routine. 26626121Skarels * Provide a way to get the sl unit number. 26726121Skarels */ 26826378Skarels /* ARGSUSED */ 26926121Skarels sltioctl(tp, cmd, data, flag) 27026121Skarels struct tty *tp; 27126121Skarels caddr_t data; 27226121Skarels { 27338365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 27438365Swilliam int s; 27526121Skarels 27638365Swilliam switch (cmd) { 27748454Skarels case SLIOCGUNIT: 27838365Swilliam *(int *)data = sc->sc_if.if_unit; 27938365Swilliam break; 28038365Swilliam 281*52200Skarels #ifdef notdef 28238365Swilliam case SLIOCGFLAGS: 28351369Swilliam *(int *)data = sc->sc_if.if_flags; 28438365Swilliam break; 285*52200Skarels #endif 28638378Skarels 28738365Swilliam case SLIOCSFLAGS: 28838365Swilliam s = splimp(); 289*52200Skarels /* temp compat */ 290*52200Skarels sc->sc_if.if_flags &= ~(SC_COMPRESS | SC_NOICMP | SC_AUTOCOMP); 291*52200Skarels if (*(int *)data & 0x2) 292*52200Skarels sc->sc_if.if_flags |= SC_COMPRESS; 293*52200Skarels if (*(int *)data & 0x4) 294*52200Skarels sc->sc_if.if_flags |= SC_NOICMP; 295*52200Skarels if (*(int *)data & 0x8) 296*52200Skarels sc->sc_if.if_flags |= SC_AUTOCOMP; 29738365Swilliam splx(s); 29838365Swilliam break; 29938378Skarels 30038365Swilliam default: 30138365Swilliam return (-1); 30238280Swilliam } 30338365Swilliam return (0); 30426121Skarels } 30526121Skarels 30626121Skarels /* 30726121Skarels * Queue a packet. Start transmission if not active. 30826121Skarels */ 30926121Skarels sloutput(ifp, m, dst) 31038942Skarels struct ifnet *ifp; 31126121Skarels register struct mbuf *m; 31226121Skarels struct sockaddr *dst; 31326121Skarels { 31438942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 31538378Skarels register struct ip *ip; 31638378Skarels register struct ifqueue *ifq; 31726121Skarels int s; 31826121Skarels 31926121Skarels /* 32026121Skarels * `Cannot happen' (see slioctl). Someday we will extend 32126121Skarels * the line protocol to support other address families. 32226121Skarels */ 32326121Skarels if (dst->sa_family != AF_INET) { 32438942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 32526121Skarels dst->sa_family); 32626121Skarels m_freem(m); 327*52200Skarels sc->sc_if.if_noproto++; 32826121Skarels return (EAFNOSUPPORT); 32926121Skarels } 33026121Skarels 33126121Skarels if (sc->sc_ttyp == NULL) { 33226121Skarels m_freem(m); 33326121Skarels return (ENETDOWN); /* sort of */ 33426121Skarels } 33526899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 33626899Skarels m_freem(m); 33726899Skarels return (EHOSTUNREACH); 33826899Skarels } 33938942Skarels ifq = &sc->sc_if.if_snd; 34038378Skarels if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 341*52200Skarels #ifdef nomore 34238378Skarels register int p = ((int *)ip)[ip->ip_hl]; 34338378Skarels 34439946Ssam if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) { 34538378Skarels ifq = &sc->sc_fastq; 34639946Ssam p = 1; 34739946Ssam } else 34839946Ssam p = 0; 349*52200Skarels #else 350*52200Skarels register int p; 35138378Skarels 352*52200Skarels if (ip->ip_tos & IPTOS_LOWDELAY) { 353*52200Skarels ifq = &sc->sc_fastq; 354*52200Skarels p = 1; 355*52200Skarels } else 356*52200Skarels p = 0; 357*52200Skarels #endif 358*52200Skarels 35951369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 36039946Ssam /* 36139946Ssam * The last parameter turns off connection id 36239946Ssam * compression for background traffic: Since 36339946Ssam * fastq traffic can jump ahead of the background 36439946Ssam * traffic, we don't know what order packets will 36539946Ssam * go on the line. 36639946Ssam */ 36739946Ssam p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 36838378Skarels *mtod(m, u_char *) |= p; 36938365Swilliam } 37051369Swilliam } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 37138378Skarels m_freem(m); 372*52200Skarels return (ENETRESET); /* XXX ? */ 37338365Swilliam } 37438378Skarels s = splimp(); 37538378Skarels if (IF_QFULL(ifq)) { 37638378Skarels IF_DROP(ifq); 37738378Skarels m_freem(m); 37826121Skarels splx(s); 37926378Skarels sc->sc_if.if_oerrors++; 38026121Skarels return (ENOBUFS); 38126121Skarels } 38238378Skarels IF_ENQUEUE(ifq, m); 38339212Ssklower sc->sc_if.if_lastchange = time; 38438942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 38526121Skarels slstart(sc->sc_ttyp); 38638942Skarels splx(s); 38726121Skarels return (0); 38826121Skarels } 38926121Skarels 39026121Skarels /* 39126121Skarels * Start output on interface. Get another datagram 39226121Skarels * to send from the interface queue and map it to 39326121Skarels * the interface before starting output. 39426121Skarels */ 39526121Skarels slstart(tp) 39626121Skarels register struct tty *tp; 39726121Skarels { 39826121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 39926121Skarels register struct mbuf *m; 40026378Skarels register u_char *cp; 40138378Skarels int s; 40226378Skarels struct mbuf *m2; 40326378Skarels extern int cfreecount; 40426121Skarels 40526378Skarels for (;;) { 40626378Skarels /* 40726378Skarels * If there is more in the output queue, just send it now. 40826378Skarels * We are being called in lieu of ttstart and must do what 40926378Skarels * it would. 41026378Skarels */ 41138378Skarels if (tp->t_outq.c_cc != 0) { 41238378Skarels (*tp->t_oproc)(tp); 41338378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 41438378Skarels return; 41538378Skarels } 41626378Skarels /* 41726378Skarels * This happens briefly when the line shuts down. 41826378Skarels */ 41926378Skarels if (sc == NULL) 42026378Skarels return; 42126121Skarels 42226378Skarels /* 42326378Skarels * Get a packet and send it to the interface. 42426378Skarels */ 42526378Skarels s = splimp(); 42638378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 427*52200Skarels if (m) 428*52200Skarels sc->sc_if.if_omcasts++; /* XXX */ 429*52200Skarels else 43038378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 43133740Skarels splx(s); 43233740Skarels if (m == NULL) 43326378Skarels return; 43439212Ssklower sc->sc_if.if_lastchange = time; 43551369Swilliam 43638378Skarels /* 43738378Skarels * If system is getting low on clists, just flush our 43838378Skarels * output queue (if the stuff was important, it'll get 43938378Skarels * retransmitted). 44038378Skarels */ 44138378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 44238378Skarels m_freem(m); 44338378Skarels sc->sc_if.if_collisions++; 44438378Skarels continue; 44538378Skarels } 44626378Skarels /* 44726378Skarels * The extra FRAME_END will start up a new packet, and thus 44826378Skarels * will flush any accumulated garbage. We do this whenever 44926378Skarels * the line may have been idle for some time. 45026378Skarels */ 45138378Skarels if (tp->t_outq.c_cc == 0) { 452*52200Skarels ++sc->sc_if.if_obytes; 45326378Skarels (void) putc(FRAME_END, &tp->t_outq); 45438378Skarels } 45526378Skarels 45626378Skarels while (m) { 45738378Skarels register u_char *ep; 45838378Skarels 45938378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 46038378Skarels while (cp < ep) { 46126378Skarels /* 46226378Skarels * Find out how many bytes in the string we can 46326378Skarels * handle without doing something special. 46426378Skarels */ 46538378Skarels register u_char *bp = cp; 46638378Skarels 46738378Skarels while (cp < ep) { 46838378Skarels switch (*cp++) { 46938378Skarels case FRAME_ESCAPE: 47038378Skarels case FRAME_END: 47138378Skarels --cp; 47238378Skarels goto out; 47338378Skarels } 47438378Skarels } 47538378Skarels out: 47638378Skarels if (cp > bp) { 47726378Skarels /* 47826378Skarels * Put n characters at once 47926378Skarels * into the tty output queue. 48026378Skarels */ 48138378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 48226378Skarels break; 483*52200Skarels sc->sc_if.if_obytes += cp - bp; 48426121Skarels } 48526378Skarels /* 48626378Skarels * If there are characters left in the mbuf, 48726378Skarels * the first one must be special.. 48826378Skarels * Put it out in a different form. 48926378Skarels */ 49038378Skarels if (cp < ep) { 49126378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 49226378Skarels break; 49338378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 49426378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 49526378Skarels &tp->t_outq)) { 49626378Skarels (void) unputc(&tp->t_outq); 49726378Skarels break; 49826378Skarels } 499*52200Skarels sc->sc_if.if_obytes += 2; 50026378Skarels } 50126378Skarels } 50226378Skarels MFREE(m, m2); 50326378Skarels m = m2; 50426121Skarels } 50526378Skarels 50626378Skarels if (putc(FRAME_END, &tp->t_outq)) { 50726378Skarels /* 50826378Skarels * Not enough room. Remove a char to make room 50926378Skarels * and end the packet normally. 51026378Skarels * If you get many collisions (more than one or two 51126378Skarels * a day) you probably do not have enough clists 51226378Skarels * and you should increase "nclist" in param.c. 51326378Skarels */ 51426378Skarels (void) unputc(&tp->t_outq); 51526378Skarels (void) putc(FRAME_END, &tp->t_outq); 51626378Skarels sc->sc_if.if_collisions++; 51738378Skarels } else { 518*52200Skarels ++sc->sc_if.if_obytes; 51926378Skarels sc->sc_if.if_opackets++; 52026378Skarels } 52126378Skarels } 52226121Skarels } 52326121Skarels 52426121Skarels /* 52538378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 52626121Skarels */ 52738378Skarels static struct mbuf * 52838378Skarels sl_btom(sc, len) 52938378Skarels register struct sl_softc *sc; 53026121Skarels register int len; 53126121Skarels { 53238378Skarels register struct mbuf *m; 53326121Skarels 53438378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 53538378Skarels if (m == NULL) 53638378Skarels return (NULL); 53738378Skarels 53838378Skarels /* 53938942Skarels * If we have more than MHLEN bytes, it's cheaper to 54038378Skarels * queue the cluster we just filled & allocate a new one 54138378Skarels * for the input buffer. Otherwise, fill the mbuf we 54238378Skarels * allocated above. Note that code in the input routine 54338378Skarels * guarantees that packet will fit in a cluster. 54438378Skarels */ 54538378Skarels if (len >= MHLEN) { 54638378Skarels MCLGET(m, M_DONTWAIT); 54738378Skarels if ((m->m_flags & M_EXT) == 0) { 54838942Skarels /* 54938942Skarels * we couldn't get a cluster - if memory's this 55038942Skarels * low, it's time to start dropping packets. 55138942Skarels */ 55238942Skarels (void) m_free(m); 55326121Skarels return (NULL); 55426121Skarels } 55538942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 55638942Skarels m->m_data = (caddr_t)sc->sc_buf; 55738942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 55838378Skarels } else 55938942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 56038378Skarels 56138378Skarels m->m_len = len; 56238378Skarels m->m_pkthdr.len = len; 56338378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 56438378Skarels return (m); 56526121Skarels } 56626121Skarels 56726121Skarels /* 56826121Skarels * tty interface receiver interrupt. 56926121Skarels */ 57026121Skarels slinput(c, tp) 57126121Skarels register int c; 57226121Skarels register struct tty *tp; 57326121Skarels { 57426121Skarels register struct sl_softc *sc; 57526121Skarels register struct mbuf *m; 57638378Skarels register int len; 57726121Skarels int s; 57826121Skarels 57926378Skarels tk_nin++; 58026121Skarels sc = (struct sl_softc *)tp->t_sc; 58126121Skarels if (sc == NULL) 58226121Skarels return; 58338378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 58438365Swilliam return; 58526121Skarels 58639212Ssklower ++sc->sc_if.if_ibytes; 58738378Skarels c &= 0xff; /* XXX */ 58838365Swilliam 58938378Skarels #ifdef ABT_ESC 590*52200Skarels if (sc->sc_if.if_flags & IFF_DEBUG) { 591*52200Skarels if (c == ABT_ESC) { 592*52200Skarels /* 593*52200Skarels * If we have a previous abort, see whether 594*52200Skarels * this one is within the time limit. 595*52200Skarels */ 596*52200Skarels if (sc->sc_abortcount && 597*52200Skarels time.tv_sec >= sc->sc_starttime + ABT_WINDOW) 59838378Skarels sc->sc_abortcount = 0; 599*52200Skarels /* 600*52200Skarels * If we see an abort after "idle" time, count it; 601*52200Skarels * record when the first abort escape arrived. 602*52200Skarels */ 603*52200Skarels if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { 604*52200Skarels if (++sc->sc_abortcount == 1) 605*52200Skarels sc->sc_starttime = time.tv_sec; 606*52200Skarels if (sc->sc_abortcount >= ABT_COUNT) { 607*52200Skarels slclose(tp); 608*52200Skarels return; 609*52200Skarels } 61038378Skarels } 611*52200Skarels } else 612*52200Skarels sc->sc_abortcount = 0; 61338378Skarels sc->sc_lasttime = time.tv_sec; 61438365Swilliam } 61538378Skarels #endif 61638365Swilliam 61738378Skarels switch (c) { 61838365Swilliam 61938378Skarels case TRANS_FRAME_ESCAPE: 62038378Skarels if (sc->sc_escape) 62138378Skarels c = FRAME_ESCAPE; 62238378Skarels break; 62338365Swilliam 62438378Skarels case TRANS_FRAME_END: 62538378Skarels if (sc->sc_escape) 62638378Skarels c = FRAME_END; 62738378Skarels break; 62838365Swilliam 62938378Skarels case FRAME_ESCAPE: 63038378Skarels sc->sc_escape = 1; 63138378Skarels return; 63226121Skarels 63338378Skarels case FRAME_END: 63438378Skarels len = sc->sc_mp - sc->sc_buf; 63538378Skarels if (len < 3) 63638378Skarels /* less than min length packet - ignore */ 63738378Skarels goto newpack; 63826121Skarels 63938378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 64038378Skarels if (c & 0x80) 64138378Skarels c = TYPE_COMPRESSED_TCP; 64238378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 64338378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 64439946Ssam /* 64539946Ssam * We've got something that's not an IP packet. 64639946Ssam * If compression is enabled, try to decompress it. 64739946Ssam * Otherwise, if `auto-enable' compression is on and 64839946Ssam * it's a reasonable packet, decompress it and then 64939946Ssam * enable compression. Otherwise, drop it. 65039946Ssam */ 65151369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 65239946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 65339946Ssam (u_int)c, &sc->sc_comp); 65439946Ssam if (len <= 0) 65539946Ssam goto error; 65651369Swilliam } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 65739946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 65839946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 65939946Ssam (u_int)c, &sc->sc_comp); 66039946Ssam if (len <= 0) 66139946Ssam goto error; 66251369Swilliam sc->sc_if.if_flags |= SC_COMPRESS; 66339946Ssam } else 66438378Skarels goto error; 66538378Skarels } 66638378Skarels m = sl_btom(sc, len); 66738378Skarels if (m == NULL) 66838378Skarels goto error; 66926121Skarels 67038378Skarels sc->sc_if.if_ipackets++; 67139212Ssklower sc->sc_if.if_lastchange = time; 67238378Skarels s = splimp(); 67338378Skarels if (IF_QFULL(&ipintrq)) { 67438378Skarels IF_DROP(&ipintrq); 67526121Skarels sc->sc_if.if_ierrors++; 67639212Ssklower sc->sc_if.if_iqdrops++; 67738378Skarels m_freem(m); 67838378Skarels } else { 67938378Skarels IF_ENQUEUE(&ipintrq, m); 68038378Skarels schednetisr(NETISR_IP); 68126121Skarels } 68238378Skarels splx(s); 68338378Skarels goto newpack; 68426121Skarels } 68538378Skarels if (sc->sc_mp < sc->sc_ep) { 68638378Skarels *sc->sc_mp++ = c; 68738378Skarels sc->sc_escape = 0; 68826121Skarels return; 68926121Skarels } 69038378Skarels error: 69138378Skarels sc->sc_if.if_ierrors++; 69238378Skarels newpack: 69339946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 69438378Skarels sc->sc_escape = 0; 69526121Skarels } 69626121Skarels 69726121Skarels /* 69826121Skarels * Process an ioctl request. 69926121Skarels */ 70026121Skarels slioctl(ifp, cmd, data) 70126121Skarels register struct ifnet *ifp; 70226121Skarels int cmd; 70326121Skarels caddr_t data; 70426121Skarels { 70526121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 70626121Skarels int s = splimp(), error = 0; 70726121Skarels 70826121Skarels switch (cmd) { 70926121Skarels 71026121Skarels case SIOCSIFADDR: 71137472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 71226121Skarels ifp->if_flags |= IFF_UP; 71326121Skarels else 71426121Skarels error = EAFNOSUPPORT; 71526121Skarels break; 71626121Skarels 71726121Skarels case SIOCSIFDSTADDR: 71837472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 71926121Skarels error = EAFNOSUPPORT; 72026121Skarels break; 72126121Skarels 72226121Skarels default: 72326121Skarels error = EINVAL; 72426121Skarels } 72526121Skarels splx(s); 72626121Skarels return (error); 72726121Skarels } 72826121Skarels #endif 729