133183Sbostic /* 2*63211Sbostic * Copyright (c) 1987, 1989, 1992, 1993 3*63211Sbostic * The Regents of the University of California. All rights reserved. 433183Sbostic * 544464Sbostic * %sccs.include.redist.c% 633183Sbostic * 7*63211Sbostic * @(#)if_sl.c 8.1 (Berkeley) 06/10/93 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 4456529Sbostic #include <sys/param.h> 4556529Sbostic #include <sys/proc.h> 4656529Sbostic #include <sys/mbuf.h> 4756529Sbostic #include <sys/buf.h> 4856529Sbostic #include <sys/dkstat.h> 4956529Sbostic #include <sys/socket.h> 5056529Sbostic #include <sys/ioctl.h> 5156529Sbostic #include <sys/file.h> 5256529Sbostic #include <sys/tty.h> 5356529Sbostic #include <sys/kernel.h> 5456529Sbostic #include <sys/conf.h> 5526121Skarels 5656529Sbostic #include <machine/cpu.h> 5752270Storek 5856529Sbostic #include <net/if.h> 5956529Sbostic #include <net/if_types.h> 6056529Sbostic #include <net/netisr.h> 6156529Sbostic #include <net/route.h> 6256529Sbostic 6326378Skarels #if INET 6456529Sbostic #include <netinet/in.h> 6556529Sbostic #include <netinet/in_systm.h> 6656529Sbostic #include <netinet/in_var.h> 6756529Sbostic #include <netinet/ip.h> 6848454Skarels #else 6948454Skarels Huh? Slip without inet? 7026378Skarels #endif 7126121Skarels 7256529Sbostic #include <net/slcompress.h> 7356529Sbostic #include <net/if_slvar.h> 7438378Skarels 7526121Skarels /* 7639946Ssam * SLMAX is a hard limit on input packet size. To simplify the code 7738378Skarels * and improve performance, we require that packets fit in an mbuf 7839946Ssam * cluster, and if we get a compressed packet, there's enough extra 7939946Ssam * room to expand the header into a max length tcp/ip header (128 8039946Ssam * bytes). So, SLMAX can be at most 8139946Ssam * MCLBYTES - 128 8238378Skarels * 8339946Ssam * SLMTU is a hard limit on output packet size. To insure good 8439946Ssam * interactive response, SLMTU wants to be the smallest size that 8539946Ssam * amortizes the header cost. (Remember that even with 8639946Ssam * type-of-service queuing, we have to wait for any in-progress 8739946Ssam * packet to finish. I.e., we wait, on the average, 1/2 * mtu / 8839946Ssam * cps, where cps is the line speed in characters per second. 8939946Ssam * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The 9039946Ssam * average compressed header size is 6-8 bytes so any MTU > 90 9139946Ssam * bytes will give us 90% of the line bandwidth. A 100ms wait is 9239946Ssam * tolerable (500ms is not), so want an MTU around 296. (Since TCP 9339946Ssam * will send 256 byte segments (to allow for 40 byte headers), the 9439946Ssam * typical packet size on the wire will be around 260 bytes). In 9539946Ssam * 4.3tahoe+ systems, we can set an MTU in a route so we do that & 9639946Ssam * leave the interface MTU relatively high (so we don't IP fragment 9739946Ssam * when acting as a gateway to someone using a stupid MTU). 9839946Ssam * 9939946Ssam * Similar considerations apply to SLIP_HIWAT: It's the amount of 10039946Ssam * data that will be queued 'downstream' of us (i.e., in clists 10139946Ssam * waiting to be picked up by the tty output interrupt). If we 10239946Ssam * queue a lot of data downstream, it's immune to our t.o.s. queuing. 10339946Ssam * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed 10439946Ssam * telnet/ftp will see a 1 sec wait, independent of the mtu (the 10539946Ssam * wait is dependent on the ftp window size but that's typically 10639946Ssam * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize 10739946Ssam * the cost (in idle time on the wire) of the tty driver running 10839946Ssam * off the end of its clists & having to call back slstart for a 10939946Ssam * new packet. For a tty interface with any buffering at all, this 11039946Ssam * cost will be zero. Even with a totally brain dead interface (like 11139946Ssam * the one on a typical workstation), the cost will be <= 1 character 11239946Ssam * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose 11339946Ssam * at most 1% while maintaining good interactive response. 11426121Skarels */ 11538942Skarels #define BUFOFFSET 128 11639946Ssam #define SLMAX (MCLBYTES - BUFOFFSET) 11739946Ssam #define SLBUFSIZE (SLMAX + BUFOFFSET) 11839946Ssam #define SLMTU 296 11939946Ssam #define SLIP_HIWAT roundup(50,CBSIZE) 12038378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 12138942Skarels 12238365Swilliam /* 12338365Swilliam * SLIP ABORT ESCAPE MECHANISM: 12438365Swilliam * (inspired by HAYES modem escape arrangement) 12538365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 12652200Skarels * within window time signals a "soft" exit from slip mode by remote end 12752203Skarels * if the IFF_DEBUG flag is on. 12838365Swilliam */ 12938365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 13052200Skarels #define ABT_IDLE 1 /* in seconds - idle before an escape */ 13152200Skarels #define ABT_COUNT 3 /* count of escapes for abort */ 13252200Skarels #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ 13326121Skarels 13438378Skarels struct sl_softc sl_softc[NSL]; 13538365Swilliam 13638378Skarels #define FRAME_END 0xc0 /* Frame End */ 13738378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 13838378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 13938378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 14038365Swilliam 14126121Skarels #define t_sc T_LINEP 14226121Skarels 14339212Ssklower extern struct timeval time; 14426121Skarels 14561353Sbostic static int slinit __P((struct sl_softc *)); 14661353Sbostic static struct mbuf *sl_btom __P((struct sl_softc *, int)); 14761353Sbostic 14826121Skarels /* 14926121Skarels * Called from boot code to establish sl interfaces. 15026121Skarels */ 15161353Sbostic void 15226121Skarels slattach() 15326121Skarels { 15426121Skarels register struct sl_softc *sc; 15526121Skarels register int i = 0; 15626121Skarels 15726121Skarels for (sc = sl_softc; i < NSL; sc++) { 15826121Skarels sc->sc_if.if_name = "sl"; 15953817Smckusick sc->sc_if.if_next = NULL; 16026121Skarels sc->sc_if.if_unit = i++; 16126121Skarels sc->sc_if.if_mtu = SLMTU; 16254718Ssklower sc->sc_if.if_flags = 16354718Ssklower IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; 16439212Ssklower sc->sc_if.if_type = IFT_SLIP; 16526121Skarels sc->sc_if.if_ioctl = slioctl; 16626121Skarels sc->sc_if.if_output = sloutput; 16738378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 16838378Skarels sc->sc_fastq.ifq_maxlen = 32; 16926121Skarels if_attach(&sc->sc_if); 17026121Skarels } 17126121Skarels } 17226121Skarels 17338378Skarels static int 17438378Skarels slinit(sc) 17538378Skarels register struct sl_softc *sc; 17638378Skarels { 17738378Skarels register caddr_t p; 17838378Skarels 17938378Skarels if (sc->sc_ep == (u_char *) 0) { 18038378Skarels MCLALLOC(p, M_WAIT); 18138378Skarels if (p) 18238942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 18338378Skarels else { 18438378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 18538378Skarels sc->sc_if.if_flags &= ~IFF_UP; 18638378Skarels return (0); 18738378Skarels } 18838378Skarels } 18939946Ssam sc->sc_buf = sc->sc_ep - SLMAX; 19038378Skarels sc->sc_mp = sc->sc_buf; 19138378Skarels sl_compress_init(&sc->sc_comp); 19238378Skarels return (1); 19338378Skarels } 19438378Skarels 19526121Skarels /* 19626121Skarels * Line specific open routine. 19726121Skarels * Attach the given tty to the first available sl unit. 19826121Skarels */ 19926378Skarels /* ARGSUSED */ 20061353Sbostic int 20126121Skarels slopen(dev, tp) 20226121Skarels dev_t dev; 20326121Skarels register struct tty *tp; 20426121Skarels { 20548454Skarels struct proc *p = curproc; /* XXX */ 20626121Skarels register struct sl_softc *sc; 20726121Skarels register int nsl; 20837549Smckusick int error; 20926121Skarels 21048454Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 21137549Smckusick return (error); 21238378Skarels 21326378Skarels if (tp->t_line == SLIPDISC) 21438942Skarels return (0); 21526121Skarels 21638378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 21726121Skarels if (sc->sc_ttyp == NULL) { 21826378Skarels if (slinit(sc) == 0) 21926378Skarels return (ENOBUFS); 22026121Skarels tp->t_sc = (caddr_t)sc; 22126121Skarels sc->sc_ttyp = tp; 22239212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 22326378Skarels ttyflush(tp, FREAD | FWRITE); 22426121Skarels return (0); 22526121Skarels } 22626378Skarels return (ENXIO); 22726121Skarels } 22826121Skarels 22926121Skarels /* 23026121Skarels * Line specific close routine. 23126121Skarels * Detach the tty from the sl unit. 23226121Skarels */ 23361353Sbostic void 23426121Skarels slclose(tp) 23526121Skarels struct tty *tp; 23626121Skarels { 23726121Skarels register struct sl_softc *sc; 23826121Skarels int s; 23926121Skarels 24026121Skarels ttywflush(tp); 24138378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 24226121Skarels tp->t_line = 0; 24326121Skarels sc = (struct sl_softc *)tp->t_sc; 24426121Skarels if (sc != NULL) { 24526121Skarels if_down(&sc->sc_if); 24626121Skarels sc->sc_ttyp = NULL; 24726121Skarels tp->t_sc = NULL; 24838942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 24938378Skarels sc->sc_ep = 0; 25038378Skarels sc->sc_mp = 0; 25126378Skarels sc->sc_buf = 0; 25226121Skarels } 25326121Skarels splx(s); 25426121Skarels } 25526121Skarels 25626121Skarels /* 25726121Skarels * Line specific (tty) ioctl routine. 25826121Skarels * Provide a way to get the sl unit number. 25926121Skarels */ 26026378Skarels /* ARGSUSED */ 26161353Sbostic int 26226121Skarels sltioctl(tp, cmd, data, flag) 26326121Skarels struct tty *tp; 26452946Storek int cmd; 26526121Skarels caddr_t data; 26652946Storek int flag; 26726121Skarels { 26838365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 26938365Swilliam int s; 27026121Skarels 27138365Swilliam switch (cmd) { 27248454Skarels case SLIOCGUNIT: 27338365Swilliam *(int *)data = sc->sc_if.if_unit; 27438365Swilliam break; 27538365Swilliam 27638365Swilliam default: 27738365Swilliam return (-1); 27838280Swilliam } 27938365Swilliam return (0); 28026121Skarels } 28126121Skarels 28226121Skarels /* 28326121Skarels * Queue a packet. Start transmission if not active. 28426121Skarels */ 28561353Sbostic int 28661353Sbostic sloutput(ifp, m, dst, rtp) 28738942Skarels struct ifnet *ifp; 28826121Skarels register struct mbuf *m; 28926121Skarels struct sockaddr *dst; 29061353Sbostic struct rtentry *rtp; 29126121Skarels { 29238942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 29338378Skarels register struct ip *ip; 29438378Skarels register struct ifqueue *ifq; 29552203Skarels register int p; 29626121Skarels int s; 29726121Skarels 29826121Skarels /* 29926121Skarels * `Cannot happen' (see slioctl). Someday we will extend 30026121Skarels * the line protocol to support other address families. 30126121Skarels */ 30226121Skarels if (dst->sa_family != AF_INET) { 30338942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 30426121Skarels dst->sa_family); 30526121Skarels m_freem(m); 30652200Skarels sc->sc_if.if_noproto++; 30726121Skarels return (EAFNOSUPPORT); 30826121Skarels } 30926121Skarels 31026121Skarels if (sc->sc_ttyp == NULL) { 31126121Skarels m_freem(m); 31226121Skarels return (ENETDOWN); /* sort of */ 31326121Skarels } 31426899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 31526899Skarels m_freem(m); 31626899Skarels return (EHOSTUNREACH); 31726899Skarels } 31838942Skarels ifq = &sc->sc_if.if_snd; 31952946Storek ip = mtod(m, struct ip *); 32052203Skarels if (ip->ip_tos & IPTOS_LOWDELAY) { 32152203Skarels ifq = &sc->sc_fastq; 32252203Skarels p = 1; 32352203Skarels } else 32452203Skarels p = 0; 32552946Storek if (ip->ip_p == IPPROTO_TCP) { 32651369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 32739946Ssam /* 32839946Ssam * The last parameter turns off connection id 32939946Ssam * compression for background traffic: Since 33039946Ssam * fastq traffic can jump ahead of the background 33139946Ssam * traffic, we don't know what order packets will 33239946Ssam * go on the line. 33339946Ssam */ 33439946Ssam p = sl_compress_tcp(m, ip, &sc->sc_comp, p); 33538378Skarels *mtod(m, u_char *) |= p; 33638365Swilliam } 33751369Swilliam } else if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 33838378Skarels m_freem(m); 33952200Skarels return (ENETRESET); /* XXX ? */ 34038365Swilliam } 34138378Skarels s = splimp(); 34238378Skarels if (IF_QFULL(ifq)) { 34338378Skarels IF_DROP(ifq); 34438378Skarels m_freem(m); 34526121Skarels splx(s); 34626378Skarels sc->sc_if.if_oerrors++; 34726121Skarels return (ENOBUFS); 34826121Skarels } 34938378Skarels IF_ENQUEUE(ifq, m); 35039212Ssklower sc->sc_if.if_lastchange = time; 35138942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 35226121Skarels slstart(sc->sc_ttyp); 35338942Skarels splx(s); 35426121Skarels return (0); 35526121Skarels } 35626121Skarels 35726121Skarels /* 35826121Skarels * Start output on interface. Get another datagram 35926121Skarels * to send from the interface queue and map it to 36026121Skarels * the interface before starting output. 36126121Skarels */ 36261353Sbostic void 36326121Skarels slstart(tp) 36426121Skarels register struct tty *tp; 36526121Skarels { 36626121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 36726121Skarels register struct mbuf *m; 36826378Skarels register u_char *cp; 36938378Skarels int s; 37026378Skarels struct mbuf *m2; 37126378Skarels extern int cfreecount; 37226121Skarels 37326378Skarels for (;;) { 37426378Skarels /* 37526378Skarels * If there is more in the output queue, just send it now. 37626378Skarels * We are being called in lieu of ttstart and must do what 37726378Skarels * it would. 37826378Skarels */ 37938378Skarels if (tp->t_outq.c_cc != 0) { 38038378Skarels (*tp->t_oproc)(tp); 38138378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 38238378Skarels return; 38338378Skarels } 38426378Skarels /* 38526378Skarels * This happens briefly when the line shuts down. 38626378Skarels */ 38726378Skarels if (sc == NULL) 38826378Skarels return; 38926121Skarels 39026378Skarels /* 39126378Skarels * Get a packet and send it to the interface. 39226378Skarels */ 39326378Skarels s = splimp(); 39438378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 39552200Skarels if (m) 39652200Skarels sc->sc_if.if_omcasts++; /* XXX */ 39752200Skarels else 39838378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 39933740Skarels splx(s); 40033740Skarels if (m == NULL) 40126378Skarels return; 40239212Ssklower sc->sc_if.if_lastchange = time; 40351369Swilliam 40438378Skarels /* 40538378Skarels * If system is getting low on clists, just flush our 40638378Skarels * output queue (if the stuff was important, it'll get 40738378Skarels * retransmitted). 40838378Skarels */ 40938378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 41038378Skarels m_freem(m); 41138378Skarels sc->sc_if.if_collisions++; 41238378Skarels continue; 41338378Skarels } 41426378Skarels /* 41526378Skarels * The extra FRAME_END will start up a new packet, and thus 41626378Skarels * will flush any accumulated garbage. We do this whenever 41726378Skarels * the line may have been idle for some time. 41826378Skarels */ 41938378Skarels if (tp->t_outq.c_cc == 0) { 42052200Skarels ++sc->sc_if.if_obytes; 42126378Skarels (void) putc(FRAME_END, &tp->t_outq); 42238378Skarels } 42326378Skarels 42426378Skarels while (m) { 42538378Skarels register u_char *ep; 42638378Skarels 42738378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 42838378Skarels while (cp < ep) { 42926378Skarels /* 43026378Skarels * Find out how many bytes in the string we can 43126378Skarels * handle without doing something special. 43226378Skarels */ 43338378Skarels register u_char *bp = cp; 43438378Skarels 43538378Skarels while (cp < ep) { 43638378Skarels switch (*cp++) { 43738378Skarels case FRAME_ESCAPE: 43838378Skarels case FRAME_END: 43938378Skarels --cp; 44038378Skarels goto out; 44138378Skarels } 44238378Skarels } 44338378Skarels out: 44438378Skarels if (cp > bp) { 44526378Skarels /* 44626378Skarels * Put n characters at once 44726378Skarels * into the tty output queue. 44826378Skarels */ 44938378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 45026378Skarels break; 45152200Skarels sc->sc_if.if_obytes += cp - bp; 45226121Skarels } 45326378Skarels /* 45426378Skarels * If there are characters left in the mbuf, 45526378Skarels * the first one must be special.. 45626378Skarels * Put it out in a different form. 45726378Skarels */ 45838378Skarels if (cp < ep) { 45926378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 46026378Skarels break; 46138378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 46226378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 46326378Skarels &tp->t_outq)) { 46426378Skarels (void) unputc(&tp->t_outq); 46526378Skarels break; 46626378Skarels } 46752200Skarels sc->sc_if.if_obytes += 2; 46826378Skarels } 46926378Skarels } 47026378Skarels MFREE(m, m2); 47126378Skarels m = m2; 47226121Skarels } 47326378Skarels 47426378Skarels if (putc(FRAME_END, &tp->t_outq)) { 47526378Skarels /* 47626378Skarels * Not enough room. Remove a char to make room 47726378Skarels * and end the packet normally. 47826378Skarels * If you get many collisions (more than one or two 47926378Skarels * a day) you probably do not have enough clists 48026378Skarels * and you should increase "nclist" in param.c. 48126378Skarels */ 48226378Skarels (void) unputc(&tp->t_outq); 48326378Skarels (void) putc(FRAME_END, &tp->t_outq); 48426378Skarels sc->sc_if.if_collisions++; 48538378Skarels } else { 48652200Skarels ++sc->sc_if.if_obytes; 48726378Skarels sc->sc_if.if_opackets++; 48826378Skarels } 48926378Skarels } 49026121Skarels } 49126121Skarels 49226121Skarels /* 49338378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 49426121Skarels */ 49538378Skarels static struct mbuf * 49638378Skarels sl_btom(sc, len) 49738378Skarels register struct sl_softc *sc; 49826121Skarels register int len; 49926121Skarels { 50038378Skarels register struct mbuf *m; 50126121Skarels 50238378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 50338378Skarels if (m == NULL) 50438378Skarels return (NULL); 50538378Skarels 50638378Skarels /* 50738942Skarels * If we have more than MHLEN bytes, it's cheaper to 50838378Skarels * queue the cluster we just filled & allocate a new one 50938378Skarels * for the input buffer. Otherwise, fill the mbuf we 51038378Skarels * allocated above. Note that code in the input routine 51138378Skarels * guarantees that packet will fit in a cluster. 51238378Skarels */ 51338378Skarels if (len >= MHLEN) { 51438378Skarels MCLGET(m, M_DONTWAIT); 51538378Skarels if ((m->m_flags & M_EXT) == 0) { 51638942Skarels /* 51738942Skarels * we couldn't get a cluster - if memory's this 51838942Skarels * low, it's time to start dropping packets. 51938942Skarels */ 52038942Skarels (void) m_free(m); 52126121Skarels return (NULL); 52226121Skarels } 52338942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 52438942Skarels m->m_data = (caddr_t)sc->sc_buf; 52538942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 52638378Skarels } else 52738942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 52838378Skarels 52938378Skarels m->m_len = len; 53038378Skarels m->m_pkthdr.len = len; 53138378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 53238378Skarels return (m); 53326121Skarels } 53426121Skarels 53526121Skarels /* 53626121Skarels * tty interface receiver interrupt. 53726121Skarels */ 53861353Sbostic void 53926121Skarels slinput(c, tp) 54026121Skarels register int c; 54126121Skarels register struct tty *tp; 54226121Skarels { 54326121Skarels register struct sl_softc *sc; 54426121Skarels register struct mbuf *m; 54538378Skarels register int len; 54626121Skarels int s; 54726121Skarels 54826378Skarels tk_nin++; 54926121Skarels sc = (struct sl_softc *)tp->t_sc; 55026121Skarels if (sc == NULL) 55126121Skarels return; 55238378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 55338365Swilliam return; 55426121Skarels 55539212Ssklower ++sc->sc_if.if_ibytes; 55638378Skarels c &= 0xff; /* XXX */ 55738365Swilliam 55838378Skarels #ifdef ABT_ESC 55952200Skarels if (sc->sc_if.if_flags & IFF_DEBUG) { 56052200Skarels if (c == ABT_ESC) { 56152200Skarels /* 56252200Skarels * If we have a previous abort, see whether 56352200Skarels * this one is within the time limit. 56452200Skarels */ 56552200Skarels if (sc->sc_abortcount && 56652200Skarels time.tv_sec >= sc->sc_starttime + ABT_WINDOW) 56738378Skarels sc->sc_abortcount = 0; 56852200Skarels /* 56952200Skarels * If we see an abort after "idle" time, count it; 57052200Skarels * record when the first abort escape arrived. 57152200Skarels */ 57252200Skarels if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { 57352200Skarels if (++sc->sc_abortcount == 1) 57452200Skarels sc->sc_starttime = time.tv_sec; 57552200Skarels if (sc->sc_abortcount >= ABT_COUNT) { 57652200Skarels slclose(tp); 57752200Skarels return; 57852200Skarels } 57938378Skarels } 58052200Skarels } else 58152200Skarels sc->sc_abortcount = 0; 58238378Skarels sc->sc_lasttime = time.tv_sec; 58338365Swilliam } 58438378Skarels #endif 58538365Swilliam 58638378Skarels switch (c) { 58738365Swilliam 58838378Skarels case TRANS_FRAME_ESCAPE: 58938378Skarels if (sc->sc_escape) 59038378Skarels c = FRAME_ESCAPE; 59138378Skarels break; 59238365Swilliam 59338378Skarels case TRANS_FRAME_END: 59438378Skarels if (sc->sc_escape) 59538378Skarels c = FRAME_END; 59638378Skarels break; 59738365Swilliam 59838378Skarels case FRAME_ESCAPE: 59938378Skarels sc->sc_escape = 1; 60038378Skarels return; 60126121Skarels 60238378Skarels case FRAME_END: 60338378Skarels len = sc->sc_mp - sc->sc_buf; 60438378Skarels if (len < 3) 60538378Skarels /* less than min length packet - ignore */ 60638378Skarels goto newpack; 60726121Skarels 60838378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 60938378Skarels if (c & 0x80) 61038378Skarels c = TYPE_COMPRESSED_TCP; 61138378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 61238378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 61339946Ssam /* 61439946Ssam * We've got something that's not an IP packet. 61539946Ssam * If compression is enabled, try to decompress it. 61639946Ssam * Otherwise, if `auto-enable' compression is on and 61739946Ssam * it's a reasonable packet, decompress it and then 61839946Ssam * enable compression. Otherwise, drop it. 61939946Ssam */ 62051369Swilliam if (sc->sc_if.if_flags & SC_COMPRESS) { 62139946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 62239946Ssam (u_int)c, &sc->sc_comp); 62339946Ssam if (len <= 0) 62439946Ssam goto error; 62551369Swilliam } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && 62639946Ssam c == TYPE_UNCOMPRESSED_TCP && len >= 40) { 62739946Ssam len = sl_uncompress_tcp(&sc->sc_buf, len, 62839946Ssam (u_int)c, &sc->sc_comp); 62939946Ssam if (len <= 0) 63039946Ssam goto error; 63151369Swilliam sc->sc_if.if_flags |= SC_COMPRESS; 63239946Ssam } else 63338378Skarels goto error; 63438378Skarels } 63538378Skarels m = sl_btom(sc, len); 63638378Skarels if (m == NULL) 63738378Skarels goto error; 63826121Skarels 63938378Skarels sc->sc_if.if_ipackets++; 64039212Ssklower sc->sc_if.if_lastchange = time; 64138378Skarels s = splimp(); 64238378Skarels if (IF_QFULL(&ipintrq)) { 64338378Skarels IF_DROP(&ipintrq); 64426121Skarels sc->sc_if.if_ierrors++; 64539212Ssklower sc->sc_if.if_iqdrops++; 64638378Skarels m_freem(m); 64738378Skarels } else { 64838378Skarels IF_ENQUEUE(&ipintrq, m); 64938378Skarels schednetisr(NETISR_IP); 65026121Skarels } 65138378Skarels splx(s); 65238378Skarels goto newpack; 65326121Skarels } 65438378Skarels if (sc->sc_mp < sc->sc_ep) { 65538378Skarels *sc->sc_mp++ = c; 65638378Skarels sc->sc_escape = 0; 65726121Skarels return; 65826121Skarels } 65938378Skarels error: 66038378Skarels sc->sc_if.if_ierrors++; 66138378Skarels newpack: 66239946Ssam sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; 66338378Skarels sc->sc_escape = 0; 66426121Skarels } 66526121Skarels 66626121Skarels /* 66726121Skarels * Process an ioctl request. 66826121Skarels */ 66961353Sbostic int 67026121Skarels slioctl(ifp, cmd, data) 67126121Skarels register struct ifnet *ifp; 67226121Skarels int cmd; 67326121Skarels caddr_t data; 67426121Skarels { 67526121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 67654718Ssklower register struct ifreq *ifr; 67754718Ssklower register int s = splimp(), error = 0; 67826121Skarels 67926121Skarels switch (cmd) { 68026121Skarels 68126121Skarels case SIOCSIFADDR: 68237472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 68326121Skarels ifp->if_flags |= IFF_UP; 68426121Skarels else 68526121Skarels error = EAFNOSUPPORT; 68626121Skarels break; 68726121Skarels 68826121Skarels case SIOCSIFDSTADDR: 68937472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 69026121Skarels error = EAFNOSUPPORT; 69126121Skarels break; 69226121Skarels 69354718Ssklower case SIOCADDMULTI: 69454718Ssklower case SIOCDELMULTI: 69554718Ssklower ifr = (struct ifreq *)data; 69654718Ssklower if (ifr == 0) { 69754718Ssklower error = EAFNOSUPPORT; /* XXX */ 69854718Ssklower break; 69954718Ssklower } 70054718Ssklower switch (ifr->ifr_addr.sa_family) { 70154718Ssklower 70254718Ssklower #ifdef INET 70354718Ssklower case AF_INET: 70454718Ssklower break; 70554718Ssklower #endif 70654718Ssklower 70754718Ssklower default: 70854718Ssklower error = EAFNOSUPPORT; 70954718Ssklower break; 71054718Ssklower } 71154718Ssklower break; 71254718Ssklower #endif 71354718Ssklower 71426121Skarels default: 71526121Skarels error = EINVAL; 71626121Skarels } 71726121Skarels splx(s); 71826121Skarels return (error); 71926121Skarels } 720