133183Sbostic /* 238378Skarels * Copyright (c) 1987, 1989 Regents of the University of California. 333183Sbostic * All rights reserved. 433183Sbostic * 533183Sbostic * Redistribution and use in source and binary forms are permitted 634844Sbostic * provided that the above copyright notice and this paragraph are 734844Sbostic * duplicated in all such forms and that any documentation, 834844Sbostic * advertising materials, and other materials related to such 934844Sbostic * distribution and use acknowledge that the software was developed 1034844Sbostic * by the University of California, Berkeley. The name of the 1134844Sbostic * University may not be used to endorse or promote products derived 1234844Sbostic * from this software without specific prior written permission. 1334844Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434844Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534844Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1633183Sbostic * 17*39946Ssam * @(#)if_sl.c 7.19 (Berkeley) 01/20/90 1833183Sbostic */ 1926122Skarels 2026121Skarels /* 2126121Skarels * Serial Line interface 2226121Skarels * 2326121Skarels * Rick Adams 2426121Skarels * Center for Seismic Studies 2526121Skarels * 1300 N 17th Street, Suite 1450 2626121Skarels * Arlington, Virginia 22209 2726121Skarels * (703)276-7900 2826121Skarels * rick@seismo.ARPA 2926121Skarels * seismo!rick 3026121Skarels * 3126121Skarels * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris). 3226378Skarels * N.B.: this belongs in netinet, not net, the way it stands now. 3326122Skarels * Should have a link-layer type designation, but wouldn't be 3426122Skarels * backwards-compatible. 3526121Skarels * 3626121Skarels * Converted to 4.3BSD Beta by Chris Torek. 3726378Skarels * Other changes made at Berkeley, based in part on code by Kirk Smith. 3838378Skarels * W. Jolitz added slip abort. 3938378Skarels * 4038378Skarels * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). 4138378Skarels * Added priority queuing for "interactive" traffic; hooks for TCP 4238378Skarels * header compression; ICMP filtering (at 2400 baud, some cretin 4338378Skarels * pinging you can use up all your bandwidth). Made low clist behavior 4438378Skarels * more robust and slightly less likely to hang serial line. 4538378Skarels * Sped up a bunch of things. 4638378Skarels * 4738378Skarels * Note that splimp() is used throughout to block both (tty) input 4838378Skarels * interrupts and network activity; thus, splimp must be >= spltty. 4926121Skarels */ 5026121Skarels 5138378Skarels /* $Header: if_sl.c,v 1.7 89/05/31 02:24:52 van Exp $ */ 5226121Skarels /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ 5326121Skarels 5426121Skarels #include "sl.h" 5526121Skarels #if NSL > 0 5626121Skarels 5726121Skarels #include "param.h" 5838365Swilliam #include "dir.h" 5938280Swilliam #include "user.h" 6026121Skarels #include "mbuf.h" 6126121Skarels #include "buf.h" 6237472Ssklower #include "dkstat.h" 6326121Skarels #include "socket.h" 6426121Skarels #include "ioctl.h" 6526378Skarels #include "file.h" 6626121Skarels #include "tty.h" 6738365Swilliam #include "kernel.h" 6838365Swilliam #include "conf.h" 6926121Skarels #include "errno.h" 7026121Skarels 7126378Skarels #include "if.h" 7239212Ssklower #include "if_types.h" 7326378Skarels #include "netisr.h" 7426378Skarels #include "route.h" 7526378Skarels #if INET 7626121Skarels #include "../netinet/in.h" 7726121Skarels #include "../netinet/in_systm.h" 7828986Skarels #include "../netinet/in_var.h" 7926121Skarels #include "../netinet/ip.h" 8026378Skarels #endif 8126121Skarels 8237500Smckusick #include "machine/mtpr.h" 8326121Skarels 8438378Skarels #include "slcompress.h" 8538378Skarels #include "if_slvar.h" 8638378Skarels 8726121Skarels /* 88*39946Ssam * SLMAX is a hard limit on input packet size. To simplify the code 8938378Skarels * and improve performance, we require that packets fit in an mbuf 90*39946Ssam * cluster, and if we get a compressed packet, there's enough extra 91*39946Ssam * room to expand the header into a max length tcp/ip header (128 92*39946Ssam * bytes). So, SLMAX can be at most 93*39946Ssam * MCLBYTES - 128 9438378Skarels * 95*39946Ssam * SLMTU is a hard limit on output packet size. To insure good 96*39946Ssam * interactive response, SLMTU wants to be the smallest size that 97*39946Ssam * amortizes the header cost. (Remember that even with 98*39946Ssam * type-of-service queuing, we have to wait for any in-progress 99*39946Ssam * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 100*39946Ssam * cps, where cps is the line speed in characters per second. 101*39946Ssam * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 102*39946Ssam * average compressed header size is 6-8 bytes so any MTU > 90 103*39946Ssam * bytes will give us 90% of the line bandwidth. A 100ms wait is 104*39946Ssam * tolerable (500ms is not), so want an MTU around 296. (Since TCP 105*39946Ssam * will send 256 byte segments (to allow for 40 byte headers), the 106*39946Ssam * typical packet size on the wire will be around 260 bytes). In 107*39946Ssam * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 108*39946Ssam * leave the interface MTU relatively high (so we don't IP fragment 109*39946Ssam * when acting as a gateway to someone using a stupid MTU). 110*39946Ssam * 111*39946Ssam * Similar considerations apply to SLIP_HIWAT: It's the amount of 112*39946Ssam * data that will be queued 'downstream' of us (i.e., in clists 113*39946Ssam * waiting to be picked up by the tty output interrupt). If we 114*39946Ssam * queue a lot of data downstream, it's immune to our t.o.s. queuing. 115*39946Ssam * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 116*39946Ssam * telnet/ftp will see a 1 sec wait, independent of the mtu (the 117*39946Ssam * wait is dependent on the ftp window size but that's typically 118*39946Ssam * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 119*39946Ssam * the cost (in idle time on the wire) of the tty driver running 120*39946Ssam * off the end of its clists & having to call back slstart for a 121*39946Ssam * new packet. For a tty interface with any buffering at all, this 122*39946Ssam * cost will be zero. Even with a totally brain dead interface (like 123*39946Ssam * the one on a typical workstation), the cost will be <= 1 character 124*39946Ssam * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 125*39946Ssam * at most 1% while maintaining good interactive response. 12626121Skarels */ 12738942Skarels #define BUFOFFSET 128 128*39946Ssam #define SLMAX (MCLBYTES - BUFOFFSET) 129*39946Ssam #define SLBUFSIZE (SLMAX + BUFOFFSET) 130*39946Ssam #define SLMTU 296 131*39946Ssam #define SLIP_HIWAT roundup(50,CBSIZE) 13238378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 13338942Skarels 13438365Swilliam /* 13538365Swilliam * SLIP ABORT ESCAPE MECHANISM: 13638365Swilliam * (inspired by HAYES modem escape arrangement) 13738365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 13838365Swilliam * signals a "soft" exit from slip mode by usermode process 13938365Swilliam */ 14026121Skarels 14138365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 14238365Swilliam #define ABT_WAIT 1 /* in seconds - idle before an escape & after */ 14338365Swilliam #define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */ 14426121Skarels 14538365Swilliam #define ABT_SOFT 3 /* count of escapes */ 14638365Swilliam 14738365Swilliam /* 14838378Skarels * The following disgusting hack gets around the problem that IP TOS 14938942Skarels * can't be set yet. We want to put "interactive" traffic on a high 15038942Skarels * priority queue. To decide if traffic is interactive, we check that 15138942Skarels * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 15238365Swilliam */ 15338378Skarels static u_short interactive_ports[8] = { 15438378Skarels 0, 513, 0, 0, 15538378Skarels 0, 21, 0, 23, 15638378Skarels }; 15738378Skarels #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 15838365Swilliam 15938378Skarels struct sl_softc sl_softc[NSL]; 16038365Swilliam 16138378Skarels #define FRAME_END 0xc0 /* Frame End */ 16238378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 16338378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 16438378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 16538365Swilliam 16626121Skarels #define t_sc T_LINEP 16726121Skarels 16826121Skarels int sloutput(), slioctl(), ttrstrt(); 16939212Ssklower extern struct timeval time; 17026121Skarels 17126121Skarels /* 17226121Skarels * Called from boot code to establish sl interfaces. 17326121Skarels */ 17426121Skarels slattach() 17526121Skarels { 17626121Skarels register struct sl_softc *sc; 17726121Skarels register int i = 0; 17826121Skarels 17926121Skarels for (sc = sl_softc; i < NSL; sc++) { 18026121Skarels sc->sc_if.if_name = "sl"; 18126121Skarels sc->sc_if.if_unit = i++; 18226121Skarels sc->sc_if.if_mtu = SLMTU; 18326121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 18439212Ssklower sc->sc_if.if_type = IFT_SLIP; 18526121Skarels sc->sc_if.if_ioctl = slioctl; 18626121Skarels sc->sc_if.if_output = sloutput; 18738378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 18838378Skarels sc->sc_fastq.ifq_maxlen = 32; 18926121Skarels if_attach(&sc->sc_if); 19026121Skarels } 19126121Skarels } 19226121Skarels 19338378Skarels static int 19438378Skarels slinit(sc) 19538378Skarels register struct sl_softc *sc; 19638378Skarels { 19738378Skarels register caddr_t p; 19838378Skarels 19938378Skarels if (sc->sc_ep == (u_char *) 0) { 20038378Skarels MCLALLOC(p, M_WAIT); 20138378Skarels if (p) 20238942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 20338378Skarels else { 20438378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 20538378Skarels sc->sc_if.if_flags &= ~IFF_UP; 20638378Skarels return (0); 20738378Skarels } 20838378Skarels } 209*39946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 21038378Skarels sc->sc_mp = sc->sc_buf; 21138378Skarels sl_compress_init(&sc->sc_comp); 21238378Skarels return (1); 21338378Skarels } 21438378Skarels 21526121Skarels /* 21626121Skarels * Line specific open routine. 21726121Skarels * Attach the given tty to the first available sl unit. 21826121Skarels */ 21926378Skarels /* ARGSUSED */ 22026121Skarels slopen(dev, tp) 22126121Skarels dev_t dev; 22226121Skarels register struct tty *tp; 22326121Skarels { 22426121Skarels register struct sl_softc *sc; 22526121Skarels register int nsl; 22637549Smckusick int error; 22726121Skarels 22837549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 22937549Smckusick return (error); 23038378Skarels 23126378Skarels if (tp->t_line == SLIPDISC) 23238942Skarels return (0); 23326121Skarels 23438378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 23526121Skarels if (sc->sc_ttyp == NULL) { 23626378Skarels if (slinit(sc) == 0) 23726378Skarels return (ENOBUFS); 23826121Skarels tp->t_sc = (caddr_t)sc; 23926121Skarels sc->sc_ttyp = tp; 24039212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 24126378Skarels ttyflush(tp, FREAD | FWRITE); 24226121Skarels return (0); 24326121Skarels } 24426378Skarels return (ENXIO); 24526121Skarels } 24626121Skarels 24726121Skarels /* 24826121Skarels * Line specific close routine. 24926121Skarels * Detach the tty from the sl unit. 25026121Skarels * Mimics part of ttyclose(). 25126121Skarels */ 25226121Skarels slclose(tp) 25326121Skarels struct tty *tp; 25426121Skarels { 25526121Skarels register struct sl_softc *sc; 25626121Skarels int s; 25726121Skarels 25826121Skarels ttywflush(tp); 25938378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 26026121Skarels tp->t_line = 0; 26126121Skarels sc = (struct sl_softc *)tp->t_sc; 26226121Skarels if (sc != NULL) { 26326121Skarels if_down(&sc->sc_if); 26426121Skarels sc->sc_ttyp = NULL; 26526121Skarels tp->t_sc = NULL; 26638942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 26738378Skarels sc->sc_ep = 0; 26838378Skarels sc->sc_mp = 0; 26926378Skarels sc->sc_buf = 0; 27026121Skarels } 27126121Skarels splx(s); 27226121Skarels } 27326121Skarels 27426121Skarels /* 27526121Skarels * Line specific (tty) ioctl routine. 27626121Skarels * Provide a way to get the sl unit number. 27726121Skarels */ 27826378Skarels /* ARGSUSED */ 27926121Skarels sltioctl(tp, cmd, data, flag) 28026121Skarels struct tty *tp; 28126121Skarels caddr_t data; 28226121Skarels { 28338365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 28438365Swilliam int s; 28526121Skarels 28638365Swilliam switch (cmd) { 28738378Skarels case TIOCGETD: /* XXX */ 28838378Skarels case SLIOGUNIT: 28938365Swilliam *(int *)data = sc->sc_if.if_unit; 29038365Swilliam break; 29138365Swilliam 29238365Swilliam case SLIOCGFLAGS: 29338365Swilliam *(int *)data = sc->sc_flags; 29438365Swilliam break; 29538378Skarels 29638365Swilliam case SLIOCSFLAGS: 297*39946Ssam #define SC_MASK 0xffff 29838365Swilliam s = splimp(); 29938365Swilliam sc->sc_flags = 30038365Swilliam (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK); 30138365Swilliam splx(s); 30238365Swilliam break; 30338378Skarels 30438365Swilliam default: 30538365Swilliam return (-1); 30638280Swilliam } 30738365Swilliam return (0); 30826121Skarels } 30926121Skarels 31026121Skarels /* 31126121Skarels * Queue a packet. Start transmission if not active. 31226121Skarels */ 31326121Skarels sloutput(ifp, m, dst) 31438942Skarels struct ifnet *ifp; 31526121Skarels register struct mbuf *m; 31626121Skarels struct sockaddr *dst; 31726121Skarels { 31838942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 31938378Skarels register struct ip *ip; 32038378Skarels register struct ifqueue *ifq; 32126121Skarels int s; 32226121Skarels 32326121Skarels /* 32426121Skarels * `Cannot happen' (see slioctl). Someday we will extend 32526121Skarels * the line protocol to support other address families. 32626121Skarels */ 32726121Skarels if (dst->sa_family != AF_INET) { 32838942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 32926121Skarels dst->sa_family); 33026121Skarels m_freem(m); 33126121Skarels return (EAFNOSUPPORT); 33226121Skarels } 33326121Skarels 33426121Skarels if (sc->sc_ttyp == NULL) { 33526121Skarels m_freem(m); 33626121Skarels return (ENETDOWN); /* sort of */ 33726121Skarels } 33826899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 33926899Skarels m_freem(m); 34026899Skarels return (EHOSTUNREACH); 34126899Skarels } 34238942Skarels ifq = &sc->sc_if.if_snd; 34338378Skarels if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 34438378Skarels register int p = ((int *)ip)[ip->ip_hl]; 34538378Skarels 346*39946Ssam if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) { 34738378Skarels ifq = &sc->sc_fastq; 348*39946Ssam p = 1; 349*39946Ssam } else 350*39946Ssam p = 0; 35138378Skarels 35238378Skarels if (sc->sc_flags & SC_COMPRESS) { 353*39946Ssam /* 354*39946Ssam * The last parameter turns off connection id 355*39946Ssam * compression for background traffic: Since 356*39946Ssam * fastq traffic can jump ahead of the background 357*39946Ssam * traffic, we don't know what order packets will 358*39946Ssam * go on the line. 359*39946Ssam */ 360*39946Ssam p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 36138378Skarels *mtod(m, u_char *) |= p; 36238365Swilliam } 36338378Skarels } else if (sc->sc_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 36438378Skarels m_freem(m); 36538378Skarels return (0); 36638365Swilliam } 36738378Skarels s = splimp(); 36838378Skarels if (IF_QFULL(ifq)) { 36938378Skarels IF_DROP(ifq); 37038378Skarels m_freem(m); 37126121Skarels splx(s); 37226378Skarels sc->sc_if.if_oerrors++; 37326121Skarels return (ENOBUFS); 37426121Skarels } 37538378Skarels IF_ENQUEUE(ifq, m); 37639212Ssklower sc->sc_if.if_lastchange = time; 37738942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 37826121Skarels slstart(sc->sc_ttyp); 37938942Skarels splx(s); 38026121Skarels return (0); 38126121Skarels } 38226121Skarels 38326121Skarels /* 38426121Skarels * Start output on interface. Get another datagram 38526121Skarels * to send from the interface queue and map it to 38626121Skarels * the interface before starting output. 38726121Skarels */ 38826121Skarels slstart(tp) 38926121Skarels register struct tty *tp; 39026121Skarels { 39126121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 39226121Skarels register struct mbuf *m; 39326378Skarels register u_char *cp; 39438378Skarels int s; 39526378Skarels struct mbuf *m2; 39626378Skarels extern int cfreecount; 39726121Skarels 39826378Skarels for (;;) { 39926378Skarels /* 40026378Skarels * If there is more in the output queue, just send it now. 40126378Skarels * We are being called in lieu of ttstart and must do what 40226378Skarels * it would. 40326378Skarels */ 40438378Skarels if (tp->t_outq.c_cc != 0) { 40538378Skarels (*tp->t_oproc)(tp); 40638378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 40738378Skarels return; 40838378Skarels } 40926378Skarels /* 41026378Skarels * This happens briefly when the line shuts down. 41126378Skarels */ 41226378Skarels if (sc == NULL) 41326378Skarels return; 41426121Skarels 41526378Skarels /* 41626378Skarels * Get a packet and send it to the interface. 41726378Skarels */ 41826378Skarels s = splimp(); 41938378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 42038378Skarels if (m == NULL) 42138378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 42233740Skarels splx(s); 42333740Skarels if (m == NULL) 42426378Skarels return; 42539212Ssklower sc->sc_if.if_lastchange = time; 42638378Skarels /* 42738378Skarels * If system is getting low on clists, just flush our 42838378Skarels * output queue (if the stuff was important, it'll get 42938378Skarels * retransmitted). 43038378Skarels */ 43138378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 43238378Skarels m_freem(m); 43338378Skarels sc->sc_if.if_collisions++; 43438378Skarels continue; 43538378Skarels } 43626121Skarels 43726378Skarels /* 43826378Skarels * The extra FRAME_END will start up a new packet, and thus 43926378Skarels * will flush any accumulated garbage. We do this whenever 44026378Skarels * the line may have been idle for some time. 44126378Skarels */ 44238378Skarels if (tp->t_outq.c_cc == 0) { 44338378Skarels ++sc->sc_bytessent; 44426378Skarels (void) putc(FRAME_END, &tp->t_outq); 44538378Skarels } 44626378Skarels 44726378Skarels while (m) { 44838378Skarels register u_char *ep; 44938378Skarels 45038378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 45138378Skarels while (cp < ep) { 45226378Skarels /* 45326378Skarels * Find out how many bytes in the string we can 45426378Skarels * handle without doing something special. 45526378Skarels */ 45638378Skarels register u_char *bp = cp; 45738378Skarels 45838378Skarels while (cp < ep) { 45938378Skarels switch (*cp++) { 46038378Skarels case FRAME_ESCAPE: 46138378Skarels case FRAME_END: 46238378Skarels --cp; 46338378Skarels goto out; 46438378Skarels } 46538378Skarels } 46638378Skarels out: 46738378Skarels if (cp > bp) { 46826378Skarels /* 46926378Skarels * Put n characters at once 47026378Skarels * into the tty output queue. 47126378Skarels */ 47238378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 47326378Skarels break; 47438378Skarels sc->sc_bytessent += cp - bp; 47526121Skarels } 47626378Skarels /* 47726378Skarels * If there are characters left in the mbuf, 47826378Skarels * the first one must be special.. 47926378Skarels * Put it out in a different form. 48026378Skarels */ 48138378Skarels if (cp < ep) { 48226378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 48326378Skarels break; 48438378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 48526378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 48626378Skarels &tp->t_outq)) { 48726378Skarels (void) unputc(&tp->t_outq); 48826378Skarels break; 48926378Skarels } 49038378Skarels sc->sc_bytessent += 2; 49126378Skarels } 49226378Skarels } 49326378Skarels MFREE(m, m2); 49426378Skarels m = m2; 49526121Skarels } 49626378Skarels 49726378Skarels if (putc(FRAME_END, &tp->t_outq)) { 49826378Skarels /* 49926378Skarels * Not enough room. Remove a char to make room 50026378Skarels * and end the packet normally. 50126378Skarels * If you get many collisions (more than one or two 50226378Skarels * a day) you probably do not have enough clists 50326378Skarels * and you should increase "nclist" in param.c. 50426378Skarels */ 50526378Skarels (void) unputc(&tp->t_outq); 50626378Skarels (void) putc(FRAME_END, &tp->t_outq); 50726378Skarels sc->sc_if.if_collisions++; 50838378Skarels } else { 50938378Skarels ++sc->sc_bytessent; 51026378Skarels sc->sc_if.if_opackets++; 51126378Skarels } 51239212Ssklower sc->sc_if.if_obytes = sc->sc_bytessent; 51326378Skarels } 51426121Skarels } 51526121Skarels 51626121Skarels /* 51738378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 51826121Skarels */ 51938378Skarels static struct mbuf * 52038378Skarels sl_btom(sc, len) 52138378Skarels register struct sl_softc *sc; 52226121Skarels register int len; 52326121Skarels { 52438378Skarels register struct mbuf *m; 52526121Skarels 52638378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 52738378Skarels if (m == NULL) 52838378Skarels return (NULL); 52938378Skarels 53038378Skarels /* 53138942Skarels * If we have more than MHLEN bytes, it's cheaper to 53238378Skarels * queue the cluster we just filled & allocate a new one 53338378Skarels * for the input buffer. Otherwise, fill the mbuf we 53438378Skarels * allocated above. Note that code in the input routine 53538378Skarels * guarantees that packet will fit in a cluster. 53638378Skarels */ 53738378Skarels if (len >= MHLEN) { 53838378Skarels MCLGET(m, M_DONTWAIT); 53938378Skarels if ((m->m_flags & M_EXT) == 0) { 54038942Skarels /* 54138942Skarels * we couldn't get a cluster - if memory's this 54238942Skarels * low, it's time to start dropping packets. 54338942Skarels */ 54438942Skarels (void) m_free(m); 54526121Skarels return (NULL); 54626121Skarels } 54738942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 54838942Skarels m->m_data = (caddr_t)sc->sc_buf; 54938942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 55038378Skarels } else 55138942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 55238378Skarels 55338378Skarels m->m_len = len; 55438378Skarels m->m_pkthdr.len = len; 55538378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 55638378Skarels return (m); 55726121Skarels } 55826121Skarels 55926121Skarels /* 56026121Skarels * tty interface receiver interrupt. 56126121Skarels */ 56226121Skarels slinput(c, tp) 56326121Skarels register int c; 56426121Skarels register struct tty *tp; 56526121Skarels { 56626121Skarels register struct sl_softc *sc; 56726121Skarels register struct mbuf *m; 56838378Skarels register int len; 56926121Skarels int s; 57026121Skarels 57126378Skarels tk_nin++; 57226121Skarels sc = (struct sl_softc *)tp->t_sc; 57326121Skarels if (sc == NULL) 57426121Skarels return; 57538378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 57638365Swilliam return; 57726121Skarels 57838378Skarels ++sc->sc_bytesrcvd; 57939212Ssklower ++sc->sc_if.if_ibytes; 58038378Skarels c &= 0xff; /* XXX */ 58138365Swilliam 58238378Skarels #ifdef ABT_ESC 58338378Skarels if (sc->sc_flags & SC_ABORT) { 58438378Skarels /* if we see an abort after "idle" time, count it */ 58538378Skarels if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 58638378Skarels sc->sc_abortcount++; 58738378Skarels /* record when the first abort escape arrived */ 58838378Skarels if (sc->sc_abortcount == 1) 58938378Skarels sc->sc_starttime = time.tv_sec; 59038378Skarels } 59138378Skarels /* 59238378Skarels * if we have an abort, see that we have not run out of time, 59338378Skarels * or that we have an "idle" time after the complete escape 59438378Skarels * sequence 59538378Skarels */ 59638378Skarels if (sc->sc_abortcount) { 59738378Skarels if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE) 59838378Skarels sc->sc_abortcount = 0; 59938378Skarels if (sc->sc_abortcount >= ABT_SOFT && 60038378Skarels time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 60138378Skarels slclose(tp); 60238378Skarels return; 60338378Skarels } 60438378Skarels } 60538378Skarels sc->sc_lasttime = time.tv_sec; 60638365Swilliam } 60738378Skarels #endif 60838365Swilliam 60938378Skarels switch (c) { 61038365Swilliam 61138378Skarels case TRANS_FRAME_ESCAPE: 61238378Skarels if (sc->sc_escape) 61338378Skarels c = FRAME_ESCAPE; 61438378Skarels break; 61538365Swilliam 61638378Skarels case TRANS_FRAME_END: 61738378Skarels if (sc->sc_escape) 61838378Skarels c = FRAME_END; 61938378Skarels break; 62038365Swilliam 62138378Skarels case FRAME_ESCAPE: 62238378Skarels sc->sc_escape = 1; 62338378Skarels return; 62426121Skarels 62538378Skarels case FRAME_END: 62638378Skarels len = sc->sc_mp - sc->sc_buf; 62738378Skarels if (len < 3) 62838378Skarels /* less than min length packet - ignore */ 62938378Skarels goto newpack; 63026121Skarels 63138378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 63238378Skarels if (c & 0x80) 63338378Skarels c = TYPE_COMPRESSED_TCP; 63438378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 63538378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 636*39946Ssam /* 637*39946Ssam * We've got something that's not an IP packet. 638*39946Ssam * If compression is enabled, try to decompress it. 639*39946Ssam * Otherwise, if `auto-enable' compression is on and 640*39946Ssam * it's a reasonable packet, decompress it and then 641*39946Ssam * enable compression. Otherwise, drop it. 642*39946Ssam */ 643*39946Ssam if (sc->sc_flags & SC_COMPRESS) { 644*39946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 645*39946Ssam (u_int)c, &sc->sc_comp); 646*39946Ssam if (len <= 0) 647*39946Ssam goto error; 648*39946Ssam } else if ((sc->sc_flags & SC_AUTOCOMP) && 649*39946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 650*39946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 651*39946Ssam (u_int)c, &sc->sc_comp); 652*39946Ssam if (len <= 0) 653*39946Ssam goto error; 654*39946Ssam sc->sc_flags |= SC_COMPRESS; 655*39946Ssam } else 65638378Skarels goto error; 65738378Skarels } 65838378Skarels m = sl_btom(sc, len); 65938378Skarels if (m == NULL) 66038378Skarels goto error; 66126121Skarels 66238378Skarels sc->sc_if.if_ipackets++; 66339212Ssklower sc->sc_if.if_lastchange = time; 66438378Skarels s = splimp(); 66538378Skarels if (IF_QFULL(&ipintrq)) { 66638378Skarels IF_DROP(&ipintrq); 66726121Skarels sc->sc_if.if_ierrors++; 66839212Ssklower sc->sc_if.if_iqdrops++; 66938378Skarels m_freem(m); 67038378Skarels } else { 67138378Skarels IF_ENQUEUE(&ipintrq, m); 67238378Skarels schednetisr(NETISR_IP); 67326121Skarels } 67438378Skarels splx(s); 67538378Skarels goto newpack; 67626121Skarels } 67738378Skarels if (sc->sc_mp < sc->sc_ep) { 67838378Skarels *sc->sc_mp++ = c; 67938378Skarels sc->sc_escape = 0; 68026121Skarels return; 68126121Skarels } 68238378Skarels error: 68338378Skarels sc->sc_if.if_ierrors++; 68438378Skarels newpack: 685*39946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 68638378Skarels sc->sc_escape = 0; 68726121Skarels } 68826121Skarels 68926121Skarels /* 69026121Skarels * Process an ioctl request. 69126121Skarels */ 69226121Skarels slioctl(ifp, cmd, data) 69326121Skarels register struct ifnet *ifp; 69426121Skarels int cmd; 69526121Skarels caddr_t data; 69626121Skarels { 69726121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 69826121Skarels int s = splimp(), error = 0; 69926121Skarels 70026121Skarels switch (cmd) { 70126121Skarels 70226121Skarels case SIOCSIFADDR: 70337472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 70426121Skarels ifp->if_flags |= IFF_UP; 70526121Skarels else 70626121Skarels error = EAFNOSUPPORT; 70726121Skarels break; 70826121Skarels 70926121Skarels case SIOCSIFDSTADDR: 71037472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 71126121Skarels error = EAFNOSUPPORT; 71226121Skarels break; 71326121Skarels 71426121Skarels default: 71526121Skarels error = EINVAL; 71626121Skarels } 71726121Skarels splx(s); 71826121Skarels return (error); 71926121Skarels } 72026121Skarels #endif 721