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*39212Ssklower * @(#)if_sl.c 7.18 (Berkeley) 09/25/89 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" 72*39212Ssklower #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 /* 8838378Skarels * SLMTU is a hard limit on input packet size. To simplify the code 8938378Skarels * and improve performance, we require that packets fit in an mbuf 9038378Skarels * cluster, that there be enough extra room for the ifnet pointer that 9138378Skarels * IP input requires and, if we get a compressed packet, there's 9238378Skarels * enough extra room to expand the header into a max length tcp/ip 9338378Skarels * header (128 bytes). So, SLMTU can be at most 9438942Skarels * MCLBYTES - 128 9538378Skarels * 9638378Skarels * To insure we get good interactive response, the MTU wants to be 9738378Skarels * the smallest size that amortizes the header cost. (Remember 9838378Skarels * that even with type-of-service queuing, we have to wait for any 9938378Skarels * in-progress packet to finish. I.e., we wait, on the average, 10038378Skarels * 1/2 * mtu / cps, where cps is the line speed in characters per 10138378Skarels * second. E.g., 533ms wait for a 1024 byte MTU on a 9600 baud 10238378Skarels * line. The average compressed header size is 6-8 bytes so any 10338378Skarels * MTU > 90 bytes will give us 90% of the line bandwidth. A 100ms 10438378Skarels * wait is tolerable (500ms is not), so want an MTU around 256. 10538378Skarels * (Since TCP will send 212 byte segments (to allow for 40 byte 10638378Skarels * headers), the typical packet size on the wire will be around 220 10738378Skarels * bytes). In 4.3tahoe+ systems, we can set an MTU in a route 10838378Skarels * so we do that & leave the interface MTU relatively high (so we 10938378Skarels * don't IP fragment when acting as a gateway to someone using a 11038378Skarels * stupid MTU). 11126121Skarels */ 11238942Skarels #define SLMTU 576 11338942Skarels #define BUFOFFSET 128 11438942Skarels #define SLBUFSIZE (SLMTU + BUFOFFSET) 11538378Skarels #define SLIP_HIWAT 1024 /* don't start a new packet if HIWAT on queue */ 11638378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 11738942Skarels 11838365Swilliam /* 11938365Swilliam * SLIP ABORT ESCAPE MECHANISM: 12038365Swilliam * (inspired by HAYES modem escape arrangement) 12138365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 12238365Swilliam * signals a "soft" exit from slip mode by usermode process 12338365Swilliam */ 12426121Skarels 12538365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 12638365Swilliam #define ABT_WAIT 1 /* in seconds - idle before an escape & after */ 12738365Swilliam #define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */ 12826121Skarels 12938365Swilliam #define ABT_SOFT 3 /* count of escapes */ 13038365Swilliam 13138365Swilliam /* 13238378Skarels * The following disgusting hack gets around the problem that IP TOS 13338942Skarels * can't be set yet. We want to put "interactive" traffic on a high 13438942Skarels * priority queue. To decide if traffic is interactive, we check that 13538942Skarels * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. 13638365Swilliam */ 13738378Skarels static u_short interactive_ports[8] = { 13838378Skarels 0, 513, 0, 0, 13938378Skarels 0, 21, 0, 23, 14038378Skarels }; 14138378Skarels #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 14238365Swilliam 14338378Skarels struct sl_softc sl_softc[NSL]; 14438365Swilliam 14538378Skarels #define FRAME_END 0xc0 /* Frame End */ 14638378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 14738378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 14838378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 14938365Swilliam 15026121Skarels #define t_sc T_LINEP 15126121Skarels 15226121Skarels int sloutput(), slioctl(), ttrstrt(); 153*39212Ssklower extern struct timeval time; 15426121Skarels 15526121Skarels /* 15626121Skarels * Called from boot code to establish sl interfaces. 15726121Skarels */ 15826121Skarels slattach() 15926121Skarels { 16026121Skarels register struct sl_softc *sc; 16126121Skarels register int i = 0; 16226121Skarels 16326121Skarels for (sc = sl_softc; i < NSL; sc++) { 16426121Skarels sc->sc_if.if_name = "sl"; 16526121Skarels sc->sc_if.if_unit = i++; 16626121Skarels sc->sc_if.if_mtu = SLMTU; 16726121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 168*39212Ssklower sc->sc_if.if_type = IFT_SLIP; 16926121Skarels sc->sc_if.if_ioctl = slioctl; 17026121Skarels sc->sc_if.if_output = sloutput; 17138378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 17238378Skarels sc->sc_fastq.ifq_maxlen = 32; 17326121Skarels if_attach(&sc->sc_if); 17426121Skarels } 17526121Skarels } 17626121Skarels 17738378Skarels static int 17838378Skarels slinit(sc) 17938378Skarels register struct sl_softc *sc; 18038378Skarels { 18138378Skarels register caddr_t p; 18238378Skarels 18338378Skarels if (sc->sc_ep == (u_char *) 0) { 18438378Skarels MCLALLOC(p, M_WAIT); 18538378Skarels if (p) 18638942Skarels sc->sc_ep = (u_char *)p + SLBUFSIZE; 18738378Skarels else { 18838378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 18938378Skarels sc->sc_if.if_flags &= ~IFF_UP; 19038378Skarels return (0); 19138378Skarels } 19238378Skarels } 19338378Skarels sc->sc_buf = sc->sc_ep - SLMTU; 19438378Skarels sc->sc_mp = sc->sc_buf; 19538378Skarels sl_compress_init(&sc->sc_comp); 19638378Skarels return (1); 19738378Skarels } 19838378Skarels 19926121Skarels /* 20026121Skarels * Line specific open routine. 20126121Skarels * Attach the given tty to the first available sl unit. 20226121Skarels */ 20326378Skarels /* ARGSUSED */ 20426121Skarels slopen(dev, tp) 20526121Skarels dev_t dev; 20626121Skarels register struct tty *tp; 20726121Skarels { 20826121Skarels register struct sl_softc *sc; 20926121Skarels register int nsl; 21037549Smckusick int error; 21126121Skarels 21237549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 21337549Smckusick return (error); 21438378Skarels 21526378Skarels if (tp->t_line == SLIPDISC) 21638942Skarels return (0); 21726121Skarels 21838378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 21926121Skarels if (sc->sc_ttyp == NULL) { 22026378Skarels if (slinit(sc) == 0) 22126378Skarels return (ENOBUFS); 22226121Skarels tp->t_sc = (caddr_t)sc; 22326121Skarels sc->sc_ttyp = tp; 224*39212Ssklower sc->sc_if.if_baudrate = tp->t_ospeed; 22526378Skarels ttyflush(tp, FREAD | FWRITE); 22626121Skarels return (0); 22726121Skarels } 22826378Skarels return (ENXIO); 22926121Skarels } 23026121Skarels 23126121Skarels /* 23226121Skarels * Line specific close routine. 23326121Skarels * Detach the tty from the sl unit. 23426121Skarels * Mimics part of ttyclose(). 23526121Skarels */ 23626121Skarels slclose(tp) 23726121Skarels struct tty *tp; 23826121Skarels { 23926121Skarels register struct sl_softc *sc; 24026121Skarels int s; 24126121Skarels 24226121Skarels ttywflush(tp); 24338378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 24426121Skarels tp->t_line = 0; 24526121Skarels sc = (struct sl_softc *)tp->t_sc; 24626121Skarels if (sc != NULL) { 24726121Skarels if_down(&sc->sc_if); 24826121Skarels sc->sc_ttyp = NULL; 24926121Skarels tp->t_sc = NULL; 25038942Skarels MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); 25138378Skarels sc->sc_ep = 0; 25238378Skarels sc->sc_mp = 0; 25326378Skarels sc->sc_buf = 0; 25426121Skarels } 25526121Skarels splx(s); 25626121Skarels } 25726121Skarels 25826121Skarels /* 25926121Skarels * Line specific (tty) ioctl routine. 26026121Skarels * Provide a way to get the sl unit number. 26126121Skarels */ 26226378Skarels /* ARGSUSED */ 26326121Skarels sltioctl(tp, cmd, data, flag) 26426121Skarels struct tty *tp; 26526121Skarels caddr_t data; 26626121Skarels { 26738365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 26838365Swilliam int s; 26926121Skarels 27038365Swilliam switch (cmd) { 27138378Skarels case TIOCGETD: /* XXX */ 27238378Skarels case SLIOGUNIT: 27338365Swilliam *(int *)data = sc->sc_if.if_unit; 27438365Swilliam break; 27538365Swilliam 27638365Swilliam case SLIOCGFLAGS: 27738365Swilliam *(int *)data = sc->sc_flags; 27838365Swilliam break; 27938378Skarels 28038365Swilliam case SLIOCSFLAGS: 28138365Swilliam #define SC_MASK (SC_COMPRESS|SC_NOICMP) 28238365Swilliam s = splimp(); 28338365Swilliam sc->sc_flags = 28438365Swilliam (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK); 28538365Swilliam splx(s); 28638365Swilliam break; 28738378Skarels 28838365Swilliam default: 28938365Swilliam return (-1); 29038280Swilliam } 29138365Swilliam return (0); 29226121Skarels } 29326121Skarels 29426121Skarels /* 29526121Skarels * Queue a packet. Start transmission if not active. 29626121Skarels */ 29726121Skarels sloutput(ifp, m, dst) 29838942Skarels struct ifnet *ifp; 29926121Skarels register struct mbuf *m; 30026121Skarels struct sockaddr *dst; 30126121Skarels { 30238942Skarels register struct sl_softc *sc = &sl_softc[ifp->if_unit]; 30338378Skarels register struct ip *ip; 30438378Skarels register struct ifqueue *ifq; 30526121Skarels int s; 30626121Skarels 30726121Skarels /* 30826121Skarels * `Cannot happen' (see slioctl). Someday we will extend 30926121Skarels * the line protocol to support other address families. 31026121Skarels */ 31126121Skarels if (dst->sa_family != AF_INET) { 31238942Skarels printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, 31326121Skarels dst->sa_family); 31426121Skarels m_freem(m); 31526121Skarels return (EAFNOSUPPORT); 31626121Skarels } 31726121Skarels 31826121Skarels if (sc->sc_ttyp == NULL) { 31926121Skarels m_freem(m); 32026121Skarels return (ENETDOWN); /* sort of */ 32126121Skarels } 32226899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 32326899Skarels m_freem(m); 32426899Skarels return (EHOSTUNREACH); 32526899Skarels } 32638942Skarels ifq = &sc->sc_if.if_snd; 32738378Skarels if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 32838378Skarels register int p = ((int *)ip)[ip->ip_hl]; 32938378Skarels 33038378Skarels if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) 33138378Skarels ifq = &sc->sc_fastq; 33238378Skarels 33338378Skarels if (sc->sc_flags & SC_COMPRESS) { 33438378Skarels /* if two copies of sl_compress_tcp are running 33538378Skarels * for the same line, the compression state can 33638378Skarels * get screwed up. We're assuming that sloutput 33738378Skarels * was invoked at splnet so this isn't possible 33838378Skarels * (this assumption is correct for 4.xbsd, x<=4). 33938378Skarels * In a multi-threaded kernel, a lockout might 34038378Skarels * be needed here. */ 34138378Skarels p = sl_compress_tcp(m, ip, &sc->sc_comp); 34238378Skarels *mtod(m, u_char *) |= p; 34338365Swilliam } 34438378Skarels } else if (sc->sc_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 34538378Skarels m_freem(m); 34638378Skarels return (0); 34738365Swilliam } 34838378Skarels s = splimp(); 34938378Skarels if (IF_QFULL(ifq)) { 35038378Skarels IF_DROP(ifq); 35138378Skarels m_freem(m); 35226121Skarels splx(s); 35326378Skarels sc->sc_if.if_oerrors++; 35426121Skarels return (ENOBUFS); 35526121Skarels } 35638378Skarels IF_ENQUEUE(ifq, m); 357*39212Ssklower sc->sc_if.if_lastchange = time; 35838942Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) 35926121Skarels slstart(sc->sc_ttyp); 36038942Skarels splx(s); 36126121Skarels return (0); 36226121Skarels } 36326121Skarels 36426121Skarels /* 36526121Skarels * Start output on interface. Get another datagram 36626121Skarels * to send from the interface queue and map it to 36726121Skarels * the interface before starting output. 36826121Skarels */ 36926121Skarels slstart(tp) 37026121Skarels register struct tty *tp; 37126121Skarels { 37226121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 37326121Skarels register struct mbuf *m; 37426378Skarels register u_char *cp; 37538378Skarels int s; 37626378Skarels struct mbuf *m2; 37726378Skarels extern int cfreecount; 37826121Skarels 37926378Skarels for (;;) { 38026378Skarels /* 38126378Skarels * If there is more in the output queue, just send it now. 38226378Skarels * We are being called in lieu of ttstart and must do what 38326378Skarels * it would. 38426378Skarels */ 38538378Skarels if (tp->t_outq.c_cc != 0) { 38638378Skarels (*tp->t_oproc)(tp); 38738378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 38838378Skarels return; 38938378Skarels } 39026378Skarels /* 39126378Skarels * This happens briefly when the line shuts down. 39226378Skarels */ 39326378Skarels if (sc == NULL) 39426378Skarels return; 39526121Skarels 39626378Skarels /* 39726378Skarels * Get a packet and send it to the interface. 39826378Skarels */ 39926378Skarels s = splimp(); 40038378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 40138378Skarels if (m == NULL) 40238378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 40333740Skarels splx(s); 40433740Skarels if (m == NULL) 40526378Skarels return; 406*39212Ssklower sc->sc_if.if_lastchange = time; 40738378Skarels /* 40838378Skarels * If system is getting low on clists, just flush our 40938378Skarels * output queue (if the stuff was important, it'll get 41038378Skarels * retransmitted). 41138378Skarels */ 41238378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 41338378Skarels m_freem(m); 41438378Skarels sc->sc_if.if_collisions++; 41538378Skarels continue; 41638378Skarels } 41726121Skarels 41826378Skarels /* 41926378Skarels * The extra FRAME_END will start up a new packet, and thus 42026378Skarels * will flush any accumulated garbage. We do this whenever 42126378Skarels * the line may have been idle for some time. 42226378Skarels */ 42338378Skarels if (tp->t_outq.c_cc == 0) { 42438378Skarels ++sc->sc_bytessent; 42526378Skarels (void) putc(FRAME_END, &tp->t_outq); 42638378Skarels } 42726378Skarels 42826378Skarels while (m) { 42938378Skarels register u_char *ep; 43038378Skarels 43138378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 43238378Skarels while (cp < ep) { 43326378Skarels /* 43426378Skarels * Find out how many bytes in the string we can 43526378Skarels * handle without doing something special. 43626378Skarels */ 43738378Skarels register u_char *bp = cp; 43838378Skarels 43938378Skarels while (cp < ep) { 44038378Skarels switch (*cp++) { 44138378Skarels case FRAME_ESCAPE: 44238378Skarels case FRAME_END: 44338378Skarels --cp; 44438378Skarels goto out; 44538378Skarels } 44638378Skarels } 44738378Skarels out: 44838378Skarels if (cp > bp) { 44926378Skarels /* 45026378Skarels * Put n characters at once 45126378Skarels * into the tty output queue. 45226378Skarels */ 45338378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 45426378Skarels break; 45538378Skarels sc->sc_bytessent += cp - bp; 45626121Skarels } 45726378Skarels /* 45826378Skarels * If there are characters left in the mbuf, 45926378Skarels * the first one must be special.. 46026378Skarels * Put it out in a different form. 46126378Skarels */ 46238378Skarels if (cp < ep) { 46326378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 46426378Skarels break; 46538378Skarels if (putc(*cp++ == FRAME_ESCAPE ? 46626378Skarels TRANS_FRAME_ESCAPE : TRANS_FRAME_END, 46726378Skarels &tp->t_outq)) { 46826378Skarels (void) unputc(&tp->t_outq); 46926378Skarels break; 47026378Skarels } 47138378Skarels sc->sc_bytessent += 2; 47226378Skarels } 47326378Skarels } 47426378Skarels MFREE(m, m2); 47526378Skarels m = m2; 47626121Skarels } 47726378Skarels 47826378Skarels if (putc(FRAME_END, &tp->t_outq)) { 47926378Skarels /* 48026378Skarels * Not enough room. Remove a char to make room 48126378Skarels * and end the packet normally. 48226378Skarels * If you get many collisions (more than one or two 48326378Skarels * a day) you probably do not have enough clists 48426378Skarels * and you should increase "nclist" in param.c. 48526378Skarels */ 48626378Skarels (void) unputc(&tp->t_outq); 48726378Skarels (void) putc(FRAME_END, &tp->t_outq); 48826378Skarels sc->sc_if.if_collisions++; 48938378Skarels } else { 49038378Skarels ++sc->sc_bytessent; 49126378Skarels sc->sc_if.if_opackets++; 49226378Skarels } 493*39212Ssklower sc->sc_if.if_obytes = sc->sc_bytessent; 49426378Skarels } 49526121Skarels } 49626121Skarels 49726121Skarels /* 49838378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 49926121Skarels */ 50038378Skarels static struct mbuf * 50138378Skarels sl_btom(sc, len) 50238378Skarels register struct sl_softc *sc; 50326121Skarels register int len; 50426121Skarels { 50538378Skarels register struct mbuf *m; 50626121Skarels 50738378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 50838378Skarels if (m == NULL) 50938378Skarels return (NULL); 51038378Skarels 51138378Skarels /* 51238942Skarels * If we have more than MHLEN bytes, it's cheaper to 51338378Skarels * queue the cluster we just filled & allocate a new one 51438378Skarels * for the input buffer. Otherwise, fill the mbuf we 51538378Skarels * allocated above. Note that code in the input routine 51638378Skarels * guarantees that packet will fit in a cluster. 51738378Skarels */ 51838378Skarels if (len >= MHLEN) { 51938378Skarels MCLGET(m, M_DONTWAIT); 52038378Skarels if ((m->m_flags & M_EXT) == 0) { 52138942Skarels /* 52238942Skarels * we couldn't get a cluster - if memory's this 52338942Skarels * low, it's time to start dropping packets. 52438942Skarels */ 52538942Skarels (void) m_free(m); 52626121Skarels return (NULL); 52726121Skarels } 52838942Skarels sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; 52938942Skarels m->m_data = (caddr_t)sc->sc_buf; 53038942Skarels m->m_ext.ext_buf = (caddr_t)((int)sc->sc_buf &~ MCLOFSET); 53138378Skarels } else 53238942Skarels bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); 53338378Skarels 53438378Skarels m->m_len = len; 53538378Skarels m->m_pkthdr.len = len; 53638378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 53738378Skarels return (m); 53826121Skarels } 53926121Skarels 54026121Skarels /* 54126121Skarels * tty interface receiver interrupt. 54226121Skarels */ 54326121Skarels slinput(c, tp) 54426121Skarels register int c; 54526121Skarels register struct tty *tp; 54626121Skarels { 54726121Skarels register struct sl_softc *sc; 54826121Skarels register struct mbuf *m; 54938378Skarels register int len; 55026121Skarels int s; 55126121Skarels 55226378Skarels tk_nin++; 55326121Skarels sc = (struct sl_softc *)tp->t_sc; 55426121Skarels if (sc == NULL) 55526121Skarels return; 55638378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 55738365Swilliam return; 55826121Skarels 55938378Skarels ++sc->sc_bytesrcvd; 560*39212Ssklower ++sc->sc_if.if_ibytes; 56138378Skarels c &= 0xff; /* XXX */ 56238365Swilliam 56338378Skarels #ifdef ABT_ESC 56438378Skarels if (sc->sc_flags & SC_ABORT) { 56538378Skarels /* if we see an abort after "idle" time, count it */ 56638378Skarels if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 56738378Skarels sc->sc_abortcount++; 56838378Skarels /* record when the first abort escape arrived */ 56938378Skarels if (sc->sc_abortcount == 1) 57038378Skarels sc->sc_starttime = time.tv_sec; 57138378Skarels } 57238378Skarels /* 57338378Skarels * if we have an abort, see that we have not run out of time, 57438378Skarels * or that we have an "idle" time after the complete escape 57538378Skarels * sequence 57638378Skarels */ 57738378Skarels if (sc->sc_abortcount) { 57838378Skarels if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE) 57938378Skarels sc->sc_abortcount = 0; 58038378Skarels if (sc->sc_abortcount >= ABT_SOFT && 58138378Skarels time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 58238378Skarels slclose(tp); 58338378Skarels return; 58438378Skarels } 58538378Skarels } 58638378Skarels sc->sc_lasttime = time.tv_sec; 58738365Swilliam } 58838378Skarels #endif 58938365Swilliam 59038378Skarels switch (c) { 59138365Swilliam 59238378Skarels case TRANS_FRAME_ESCAPE: 59338378Skarels if (sc->sc_escape) 59438378Skarels c = FRAME_ESCAPE; 59538378Skarels break; 59638365Swilliam 59738378Skarels case TRANS_FRAME_END: 59838378Skarels if (sc->sc_escape) 59938378Skarels c = FRAME_END; 60038378Skarels break; 60138365Swilliam 60238378Skarels case FRAME_ESCAPE: 60338378Skarels sc->sc_escape = 1; 60438378Skarels return; 60526121Skarels 60638378Skarels case FRAME_END: 60738378Skarels len = sc->sc_mp - sc->sc_buf; 60838378Skarels if (len < 3) 60938378Skarels /* less than min length packet - ignore */ 61038378Skarels goto newpack; 61126121Skarels 61238378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 61338378Skarels if (c & 0x80) 61438378Skarels c = TYPE_COMPRESSED_TCP; 61538378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 61638378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 61738378Skarels len = sl_uncompress_tcp(&sc->sc_buf, len, (u_int)c, 61838378Skarels &sc->sc_comp); 61938378Skarels if (len <= 0) 62038378Skarels goto error; 62138378Skarels } 62238378Skarels m = sl_btom(sc, len); 62338378Skarels if (m == NULL) 62438378Skarels goto error; 62526121Skarels 62638378Skarels sc->sc_if.if_ipackets++; 627*39212Ssklower sc->sc_if.if_lastchange = time; 62838378Skarels s = splimp(); 62938378Skarels if (IF_QFULL(&ipintrq)) { 63038378Skarels IF_DROP(&ipintrq); 63126121Skarels sc->sc_if.if_ierrors++; 632*39212Ssklower sc->sc_if.if_iqdrops++; 63338378Skarels m_freem(m); 63438378Skarels } else { 63538378Skarels IF_ENQUEUE(&ipintrq, m); 63638378Skarels schednetisr(NETISR_IP); 63726121Skarels } 63838378Skarels splx(s); 63938378Skarels goto newpack; 64026121Skarels } 64138378Skarels if (sc->sc_mp < sc->sc_ep) { 64238378Skarels *sc->sc_mp++ = c; 64338378Skarels sc->sc_escape = 0; 64426121Skarels return; 64526121Skarels } 64638378Skarels error: 64738378Skarels sc->sc_if.if_ierrors++; 64838378Skarels newpack: 64938378Skarels sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMTU; 65038378Skarels sc->sc_escape = 0; 65126121Skarels } 65226121Skarels 65326121Skarels /* 65426121Skarels * Process an ioctl request. 65526121Skarels */ 65626121Skarels slioctl(ifp, cmd, data) 65726121Skarels register struct ifnet *ifp; 65826121Skarels int cmd; 65926121Skarels caddr_t data; 66026121Skarels { 66126121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 66226121Skarels int s = splimp(), error = 0; 66326121Skarels 66426121Skarels switch (cmd) { 66526121Skarels 66626121Skarels case SIOCSIFADDR: 66737472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 66826121Skarels ifp->if_flags |= IFF_UP; 66926121Skarels else 67026121Skarels error = EAFNOSUPPORT; 67126121Skarels break; 67226121Skarels 67326121Skarels case SIOCSIFDSTADDR: 67437472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 67526121Skarels error = EAFNOSUPPORT; 67626121Skarels break; 67726121Skarels 67826121Skarels default: 67926121Skarels error = EINVAL; 68026121Skarels } 68126121Skarels splx(s); 68226121Skarels return (error); 68326121Skarels } 68426121Skarels #endif 685