133183Sbostic /* 252203Skarels * Copyright (c) 1987, 1989, 1992 Regents of the University of California. 333183Sbostic * All rights reserved. 433183Sbostic * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*52946Storek * @(#)if_sl.c 7.27 (Berkeley) 03/15/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" 5552270Storek #include "machine/cpu.h" 5626121Skarels 5726378Skarels #include "if.h" 5839212Ssklower #include "if_types.h" 5926378Skarels #include "netisr.h" 6026378Skarels #include "route.h" 6152270Storek 6226378Skarels #if INET 6348454Skarels #include "netinet/in.h" 6448454Skarels #include "netinet/in_systm.h" 6548454Skarels #include "netinet/in_var.h" 6648454Skarels #include "netinet/ip.h" 6748454Skarels #else 6848454Skarels Huh? Slip without inet? 6926378Skarels #endif 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 } 12552200Skarels * within window time signals a "soft" exit from slip mode by remote end 12652203Skarels * if the IFF_DEBUG flag is on. 12738365Swilliam */ 12838365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 12952200Skarels #define ABT_IDLE 1 /* in seconds - idle before an escape */ 13052200Skarels #define ABT_COUNT 3 /* count of escapes for abort */ 13152200Skarels #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 13226121Skarels 13338378Skarels struct sl_softc sl_softc[NSL]; 13438365Swilliam 13538378Skarels #define FRAME_END 0xc0 /* Frame End */ 13638378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 13738378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 13838378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 13938365Swilliam 14026121Skarels #define t_sc T_LINEP 14126121Skarels 14226121Skarels int sloutput(), slioctl(), ttrstrt(); 14339212Ssklower extern struct timeval time; 14426121Skarels 14526121Skarels /* 14626121Skarels * Called from boot code to establish sl interfaces. 14726121Skarels */ 14826121Skarels slattach() 14926121Skarels { 15026121Skarels register struct sl_softc *sc; 15126121Skarels register int i = 0; 15226121Skarels 15326121Skarels for (sc = sl_softc; i < NSL; sc++) { 15426121Skarels sc->sc_if.if_name = "sl"; 15526121Skarels sc->sc_if.if_unit = i++; 15626121Skarels sc->sc_if.if_mtu = SLMTU; 15752203Skarels sc->sc_if.if_flags = IFF_POINTOPOINT | SC_AUTOCOMP; 15839212Ssklower sc->sc_if.if_type = IFT_SLIP; 15926121Skarels sc->sc_if.if_ioctl = slioctl; 16026121Skarels sc->sc_if.if_output = sloutput; 16138378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 16238378Skarels sc->sc_fastq.ifq_maxlen = 32; 16326121Skarels if_attach(&sc->sc_if); 16426121Skarels } 16526121Skarels } 16626121Skarels 16738378Skarels static int 16838378Skarels slinit(sc) 16938378Skarels register struct sl_softc *sc; 17038378Skarels { 17138378Skarels register caddr_t p; 17238378Skarels 17338378Skarels if (sc->sc_ep == (u_char *) 0) { 17438378Skarels MCLALLOC(p, M_WAIT); 17538378Skarels if (p) 17638942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 17738378Skarels else { 17838378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 17938378Skarels sc->sc_if.if_flags &= ~IFF_UP; 18038378Skarels return (0); 18138378Skarels } 18238378Skarels } 18339946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 18438378Skarels sc->sc_mp = sc->sc_buf; 18538378Skarels sl_compress_init(&sc->sc_comp); 18638378Skarels return (1); 18738378Skarels } 18838378Skarels 18926121Skarels /* 19026121Skarels * Line specific open routine. 19126121Skarels * Attach the given tty to the first available sl unit. 19226121Skarels */ 19326378Skarels /* ARGSUSED */ 19426121Skarels slopen(dev, tp) 19526121Skarels dev_t dev; 19626121Skarels register struct tty *tp; 19726121Skarels { 19848454Skarels struct proc *p = curproc; /* XXX */ 19926121Skarels register struct sl_softc *sc; 20026121Skarels register int nsl; 20137549Smckusick int error; 20226121Skarels 20348454Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 20437549Smckusick return (error); 20538378Skarels 20626378Skarels if (tp->t_line == SLIPDISC) 20738942Skarels return (0); 20826121Skarels 20938378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 21026121Skarels if (sc->sc_ttyp == NULL) { 21126378Skarels if (slinit(sc) == 0) 21226378Skarels return (ENOBUFS); 21326121Skarels tp->t_sc = (caddr_t)sc; 21426121Skarels sc->sc_ttyp = tp; 21539212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 21626378Skarels ttyflush(tp, FREAD | FWRITE); 21726121Skarels return (0); 21826121Skarels } 21926378Skarels return (ENXIO); 22026121Skarels } 22126121Skarels 22226121Skarels /* 22326121Skarels * Line specific close routine. 22426121Skarels * Detach the tty from the sl unit. 22526121Skarels * Mimics part of ttyclose(). 22626121Skarels */ 22726121Skarels slclose(tp) 22826121Skarels struct tty *tp; 22926121Skarels { 23026121Skarels register struct sl_softc *sc; 23126121Skarels int s; 23226121Skarels 23326121Skarels ttywflush(tp); 23438378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 23526121Skarels tp->t_line = 0; 23626121Skarels sc = (struct sl_softc *)tp->t_sc; 23726121Skarels if (sc != NULL) { 23826121Skarels if_down(&sc->sc_if); 23926121Skarels sc->sc_ttyp = NULL; 24026121Skarels tp->t_sc = NULL; 24138942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 24238378Skarels sc->sc_ep = 0; 24338378Skarels sc->sc_mp = 0; 24426378Skarels sc->sc_buf = 0; 24526121Skarels } 24626121Skarels splx(s); 24726121Skarels } 24826121Skarels 24926121Skarels /* 25026121Skarels * Line specific (tty) ioctl routine. 25126121Skarels * Provide a way to get the sl unit number. 25226121Skarels */ 25326378Skarels /* ARGSUSED */ 25426121Skarels sltioctl(tp, cmd, data, flag) 25526121Skarels struct tty *tp; 256*52946Storek int cmd; 25726121Skarels caddr_t data; 258*52946Storek int flag; 25926121Skarels { 26038365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 26138365Swilliam int s; 26226121Skarels 26338365Swilliam switch (cmd) { 26448454Skarels case SLIOCGUNIT: 26538365Swilliam *(int *)data = sc->sc_if.if_unit; 26638365Swilliam break; 26738365Swilliam 26838365Swilliam default: 26938365Swilliam return (-1); 27038280Swilliam } 27138365Swilliam return (0); 27226121Skarels } 27326121Skarels 27426121Skarels /* 27526121Skarels * Queue a packet. Start transmission if not active. 27626121Skarels */ 27726121Skarels sloutput(ifp, m, dst) 27838942Skarels struct ifnet *ifp; 27926121Skarels register struct mbuf *m; 28026121Skarels struct sockaddr *dst; 28126121Skarels { 28238942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 28338378Skarels register struct ip *ip; 28438378Skarels register struct ifqueue *ifq; 28552203Skarels register int p; 28626121Skarels int s; 28726121Skarels 28826121Skarels /* 28926121Skarels * `Cannot happen' (see slioctl). Someday we will extend 29026121Skarels * the line protocol to support other address families. 29126121Skarels */ 29226121Skarels if (dst->sa_family != AF_INET) { 29338942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 29426121Skarels dst->sa_family); 29526121Skarels m_freem(m); 29652200Skarels sc->sc_if.if_noproto++; 29726121Skarels return (EAFNOSUPPORT); 29826121Skarels } 29926121Skarels 30026121Skarels if (sc->sc_ttyp == NULL) { 30126121Skarels m_freem(m); 30226121Skarels return (ENETDOWN); /* sort of */ 30326121Skarels } 30426899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 30526899Skarels m_freem(m); 30626899Skarels return (EHOSTUNREACH); 30726899Skarels } 30838942Skarels ifq = &sc->sc_if.if_snd; 309*52946Storek ip = mtod(m, struct ip *); 31052203Skarels if (ip->ip_tos & IPTOS_LOWDELAY) { 31152203Skarels ifq = &sc->sc_fastq; 31252203Skarels p = 1; 31352203Skarels } else 31452203Skarels p = 0; 315*52946Storek if (ip->ip_p == IPPROTO_TCP) { 31651369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 31739946Ssam /* 31839946Ssam * The last parameter turns off connection id 31939946Ssam * compression for background traffic: Since 32039946Ssam * fastq traffic can jump ahead of the background 32139946Ssam * traffic, we don't know what order packets will 32239946Ssam * go on the line. 32339946Ssam */ 32439946Ssam p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 32538378Skarels *mtod(m, u_char *) |= p; 32638365Swilliam } 32751369Swilliam } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 32838378Skarels m_freem(m); 32952200Skarels return (ENETRESET); /* XXX ? */ 33038365Swilliam } 33138378Skarels s = splimp(); 33238378Skarels if (IF_QFULL(ifq)) { 33338378Skarels IF_DROP(ifq); 33438378Skarels m_freem(m); 33526121Skarels splx(s); 33626378Skarels sc->sc_if.if_oerrors++; 33726121Skarels return (ENOBUFS); 33826121Skarels } 33938378Skarels IF_ENQUEUE(ifq, m); 34039212Ssklower sc->sc_if.if_lastchange = time; 34138942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 34226121Skarels slstart(sc->sc_ttyp); 34338942Skarels splx(s); 34426121Skarels return (0); 34526121Skarels } 34626121Skarels 34726121Skarels /* 34826121Skarels * Start output on interface. Get another datagram 34926121Skarels * to send from the interface queue and map it to 35026121Skarels * the interface before starting output. 35126121Skarels */ 35226121Skarels slstart(tp) 35326121Skarels register struct tty *tp; 35426121Skarels { 35526121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 35626121Skarels register struct mbuf *m; 35726378Skarels register u_char *cp; 35838378Skarels int s; 35926378Skarels struct mbuf *m2; 36026378Skarels extern int cfreecount; 36126121Skarels 36226378Skarels for (;;) { 36326378Skarels /* 36426378Skarels * If there is more in the output queue, just send it now. 36526378Skarels * We are being called in lieu of ttstart and must do what 36626378Skarels * it would. 36726378Skarels */ 36838378Skarels if (tp->t_outq.c_cc != 0) { 36938378Skarels (*tp->t_oproc)(tp); 37038378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 37138378Skarels return; 37238378Skarels } 37326378Skarels /* 37426378Skarels * This happens briefly when the line shuts down. 37526378Skarels */ 37626378Skarels if (sc == NULL) 37726378Skarels return; 37826121Skarels 37926378Skarels /* 38026378Skarels * Get a packet and send it to the interface. 38126378Skarels */ 38226378Skarels s = splimp(); 38338378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 38452200Skarels if (m) 38552200Skarels sc->sc_if.if_omcasts++; /* XXX */ 38652200Skarels else 38738378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 38833740Skarels splx(s); 38933740Skarels if (m == NULL) 39026378Skarels return; 39139212Ssklower sc->sc_if.if_lastchange = time; 39251369Swilliam 39338378Skarels /* 39438378Skarels * If system is getting low on clists, just flush our 39538378Skarels * output queue (if the stuff was important, it'll get 39638378Skarels * retransmitted). 39738378Skarels */ 39838378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 39938378Skarels m_freem(m); 40038378Skarels sc->sc_if.if_collisions++; 40138378Skarels continue; 40238378Skarels } 40326378Skarels /* 40426378Skarels * The extra FRAME_END will start up a new packet, and thus 40526378Skarels * will flush any accumulated garbage. We do this whenever 40626378Skarels * the line may have been idle for some time. 40726378Skarels */ 40838378Skarels if (tp->t_outq.c_cc == 0) { 40952200Skarels ++sc->sc_if.if_obytes; 41026378Skarels (void) putc(FRAME_END, &tp->t_outq); 41138378Skarels } 41226378Skarels 41326378Skarels while (m) { 41438378Skarels register u_char *ep; 41538378Skarels 41638378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 41738378Skarels while (cp < ep) { 41826378Skarels /* 41926378Skarels * Find out how many bytes in the string we can 42026378Skarels * handle without doing something special. 42126378Skarels */ 42238378Skarels register u_char *bp = cp; 42338378Skarels 42438378Skarels while (cp < ep) { 42538378Skarels switch (*cp++) { 42638378Skarels case FRAME_ESCAPE: 42738378Skarels case FRAME_END: 42838378Skarels --cp; 42938378Skarels goto out; 43038378Skarels } 43138378Skarels } 43238378Skarels out: 43338378Skarels if (cp > bp) { 43426378Skarels /* 43526378Skarels * Put n characters at once 43626378Skarels * into the tty output queue. 43726378Skarels */ 43838378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 43926378Skarels break; 44052200Skarels sc->sc_if.if_obytes += cp - bp; 44126121Skarels } 44226378Skarels /* 44326378Skarels * If there are characters left in the mbuf, 44426378Skarels * the first one must be special.. 44526378Skarels * Put it out in a different form. 44626378Skarels */ 44738378Skarels if (cp < ep) { 44826378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 44926378Skarels break; 45038378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 45126378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 45226378Skarels &tp->t_outq)) { 45326378Skarels (void) unputc(&tp->t_outq); 45426378Skarels break; 45526378Skarels } 45652200Skarels sc->sc_if.if_obytes += 2; 45726378Skarels } 45826378Skarels } 45926378Skarels MFREE(m, m2); 46026378Skarels m = m2; 46126121Skarels } 46226378Skarels 46326378Skarels if (putc(FRAME_END, &tp->t_outq)) { 46426378Skarels /* 46526378Skarels * Not enough room. Remove a char to make room 46626378Skarels * and end the packet normally. 46726378Skarels * If you get many collisions (more than one or two 46826378Skarels * a day) you probably do not have enough clists 46926378Skarels * and you should increase "nclist" in param.c. 47026378Skarels */ 47126378Skarels (void) unputc(&tp->t_outq); 47226378Skarels (void) putc(FRAME_END, &tp->t_outq); 47326378Skarels sc->sc_if.if_collisions++; 47438378Skarels } else { 47552200Skarels ++sc->sc_if.if_obytes; 47626378Skarels sc->sc_if.if_opackets++; 47726378Skarels } 47826378Skarels } 47926121Skarels } 48026121Skarels 48126121Skarels /* 48238378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 48326121Skarels */ 48438378Skarels static struct mbuf * 48538378Skarels sl_btom(sc, len) 48638378Skarels register struct sl_softc *sc; 48726121Skarels register int len; 48826121Skarels { 48938378Skarels register struct mbuf *m; 49026121Skarels 49138378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 49238378Skarels if (m == NULL) 49338378Skarels return (NULL); 49438378Skarels 49538378Skarels /* 49638942Skarels * If we have more than MHLEN bytes, it's cheaper to 49738378Skarels * queue the cluster we just filled & allocate a new one 49838378Skarels * for the input buffer. Otherwise, fill the mbuf we 49938378Skarels * allocated above. Note that code in the input routine 50038378Skarels * guarantees that packet will fit in a cluster. 50138378Skarels */ 50238378Skarels if (len >= MHLEN) { 50338378Skarels MCLGET(m, M_DONTWAIT); 50438378Skarels if ((m->m_flags & M_EXT) == 0) { 50538942Skarels /* 50638942Skarels * we couldn't get a cluster - if memory's this 50738942Skarels * low, it's time to start dropping packets. 50838942Skarels */ 50938942Skarels (void) m_free(m); 51026121Skarels return (NULL); 51126121Skarels } 51238942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 51338942Skarels m->m_data = (caddr_t)sc->sc_buf; 51438942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 51538378Skarels } else 51638942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 51738378Skarels 51838378Skarels m->m_len = len; 51938378Skarels m->m_pkthdr.len = len; 52038378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 52138378Skarels return (m); 52226121Skarels } 52326121Skarels 52426121Skarels /* 52526121Skarels * tty interface receiver interrupt. 52626121Skarels */ 52726121Skarels slinput(c, tp) 52826121Skarels register int c; 52926121Skarels register struct tty *tp; 53026121Skarels { 53126121Skarels register struct sl_softc *sc; 53226121Skarels register struct mbuf *m; 53338378Skarels register int len; 53426121Skarels int s; 53526121Skarels 53626378Skarels tk_nin++; 53726121Skarels sc = (struct sl_softc *)tp->t_sc; 53826121Skarels if (sc == NULL) 53926121Skarels return; 54038378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 54138365Swilliam return; 54226121Skarels 54339212Ssklower ++sc->sc_if.if_ibytes; 54438378Skarels c &= 0xff; /* XXX */ 54538365Swilliam 54638378Skarels #ifdef ABT_ESC 54752200Skarels if (sc->sc_if.if_flags & IFF_DEBUG) { 54852200Skarels if (c == ABT_ESC) { 54952200Skarels /* 55052200Skarels * If we have a previous abort, see whether 55152200Skarels * this one is within the time limit. 55252200Skarels */ 55352200Skarels if (sc->sc_abortcount && 55452200Skarels time.tv_sec >= sc->sc_starttime + ABT_WINDOW) 55538378Skarels sc->sc_abortcount = 0; 55652200Skarels /* 55752200Skarels * If we see an abort after "idle" time, count it; 55852200Skarels * record when the first abort escape arrived. 55952200Skarels */ 56052200Skarels if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { 56152200Skarels if (++sc->sc_abortcount == 1) 56252200Skarels sc->sc_starttime = time.tv_sec; 56352200Skarels if (sc->sc_abortcount >= ABT_COUNT) { 56452200Skarels slclose(tp); 56552200Skarels return; 56652200Skarels } 56738378Skarels } 56852200Skarels } else 56952200Skarels sc->sc_abortcount = 0; 57038378Skarels sc->sc_lasttime = time.tv_sec; 57138365Swilliam } 57238378Skarels #endif 57338365Swilliam 57438378Skarels switch (c) { 57538365Swilliam 57638378Skarels case TRANS_FRAME_ESCAPE: 57738378Skarels if (sc->sc_escape) 57838378Skarels c = FRAME_ESCAPE; 57938378Skarels break; 58038365Swilliam 58138378Skarels case TRANS_FRAME_END: 58238378Skarels if (sc->sc_escape) 58338378Skarels c = FRAME_END; 58438378Skarels break; 58538365Swilliam 58638378Skarels case FRAME_ESCAPE: 58738378Skarels sc->sc_escape = 1; 58838378Skarels return; 58926121Skarels 59038378Skarels case FRAME_END: 59138378Skarels len = sc->sc_mp - sc->sc_buf; 59238378Skarels if (len < 3) 59338378Skarels /* less than min length packet - ignore */ 59438378Skarels goto newpack; 59526121Skarels 59638378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 59738378Skarels if (c & 0x80) 59838378Skarels c = TYPE_COMPRESSED_TCP; 59938378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 60038378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 60139946Ssam /* 60239946Ssam * We've got something that's not an IP packet. 60339946Ssam * If compression is enabled, try to decompress it. 60439946Ssam * Otherwise, if `auto-enable' compression is on and 60539946Ssam * it's a reasonable packet, decompress it and then 60639946Ssam * enable compression. Otherwise, drop it. 60739946Ssam */ 60851369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 60939946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 61039946Ssam (u_int)c, &sc->sc_comp); 61139946Ssam if (len <= 0) 61239946Ssam goto error; 61351369Swilliam } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 61439946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 61539946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 61639946Ssam (u_int)c, &sc->sc_comp); 61739946Ssam if (len <= 0) 61839946Ssam goto error; 61951369Swilliam sc->sc_if.if_flags |= SC_COMPRESS; 62039946Ssam } else 62138378Skarels goto error; 62238378Skarels } 62338378Skarels m = sl_btom(sc, len); 62438378Skarels if (m == NULL) 62538378Skarels goto error; 62626121Skarels 62738378Skarels sc->sc_if.if_ipackets++; 62839212Ssklower sc->sc_if.if_lastchange = time; 62938378Skarels s = splimp(); 63038378Skarels if (IF_QFULL(&ipintrq)) { 63138378Skarels IF_DROP(&ipintrq); 63226121Skarels sc->sc_if.if_ierrors++; 63339212Ssklower sc->sc_if.if_iqdrops++; 63438378Skarels m_freem(m); 63538378Skarels } else { 63638378Skarels IF_ENQUEUE(&ipintrq, m); 63738378Skarels schednetisr(NETISR_IP); 63826121Skarels } 63938378Skarels splx(s); 64038378Skarels goto newpack; 64126121Skarels } 64238378Skarels if (sc->sc_mp < sc->sc_ep) { 64338378Skarels *sc->sc_mp++ = c; 64438378Skarels sc->sc_escape = 0; 64526121Skarels return; 64626121Skarels } 64738378Skarels error: 64838378Skarels sc->sc_if.if_ierrors++; 64938378Skarels newpack: 65039946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 65138378Skarels sc->sc_escape = 0; 65226121Skarels } 65326121Skarels 65426121Skarels /* 65526121Skarels * Process an ioctl request. 65626121Skarels */ 65726121Skarels slioctl(ifp, cmd, data) 65826121Skarels register struct ifnet *ifp; 65926121Skarels int cmd; 66026121Skarels caddr_t data; 66126121Skarels { 66226121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 66326121Skarels int s = splimp(), error = 0; 66426121Skarels 66526121Skarels switch (cmd) { 66626121Skarels 66726121Skarels case SIOCSIFADDR: 66837472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 66926121Skarels ifp->if_flags |= IFF_UP; 67026121Skarels else 67126121Skarels error = EAFNOSUPPORT; 67226121Skarels break; 67326121Skarels 67426121Skarels case SIOCSIFDSTADDR: 67537472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 67626121Skarels error = EAFNOSUPPORT; 67726121Skarels break; 67826121Skarels 67926121Skarels default: 68026121Skarels error = EINVAL; 68126121Skarels } 68226121Skarels splx(s); 68326121Skarels return (error); 68426121Skarels } 68526121Skarels #endif 686