133183Sbostic /* 2*38378Skarels * 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*38378Skarels * @(#)if_sl.c 7.16 (Berkeley) 06/30/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. 38*38378Skarels * W. Jolitz added slip abort. 39*38378Skarels * 40*38378Skarels * Hacked almost beyond recognition by Van Jacobson (van@helios.ee.lbl.gov). 41*38378Skarels * Added priority queuing for "interactive" traffic; hooks for TCP 42*38378Skarels * header compression; ICMP filtering (at 2400 baud, some cretin 43*38378Skarels * pinging you can use up all your bandwidth). Made low clist behavior 44*38378Skarels * more robust and slightly less likely to hang serial line. 45*38378Skarels * Sped up a bunch of things. 46*38378Skarels * 47*38378Skarels * Note that splimp() is used throughout to block both (tty) input 48*38378Skarels * interrupts and network activity; thus, splimp must be >= spltty. 4926121Skarels */ 5026121Skarels 51*38378Skarels /* $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" 7226378Skarels #include "netisr.h" 7326378Skarels #include "route.h" 7426378Skarels #if INET 7526121Skarels #include "../netinet/in.h" 7626121Skarels #include "../netinet/in_systm.h" 7728986Skarels #include "../netinet/in_var.h" 7826121Skarels #include "../netinet/ip.h" 7926378Skarels #endif 8026121Skarels 8137500Smckusick #include "machine/mtpr.h" 8226121Skarels 83*38378Skarels #include "slcompress.h" 84*38378Skarels #include "if_slvar.h" 85*38378Skarels 8626121Skarels /* 87*38378Skarels * SLMTU is a hard limit on input packet size. To simplify the code 88*38378Skarels * and improve performance, we require that packets fit in an mbuf 89*38378Skarels * cluster, that there be enough extra room for the ifnet pointer that 90*38378Skarels * IP input requires and, if we get a compressed packet, there's 91*38378Skarels * enough extra room to expand the header into a max length tcp/ip 92*38378Skarels * header (128 bytes). So, SLMTU can be at most 93*38378Skarels * MCLBYTES - sizeof(struct ifnet *) - 128 94*38378Skarels * 95*38378Skarels * To insure we get good interactive response, the MTU wants to be 96*38378Skarels * the smallest size that amortizes the header cost. (Remember 97*38378Skarels * that even with type-of-service queuing, we have to wait for any 98*38378Skarels * in-progress packet to finish. I.e., we wait, on the average, 99*38378Skarels * 1/2 * mtu / cps, where cps is the line speed in characters per 100*38378Skarels * second. E.g., 533ms wait for a 1024 byte MTU on a 9600 baud 101*38378Skarels * line. The average compressed header size is 6-8 bytes so any 102*38378Skarels * MTU > 90 bytes will give us 90% of the line bandwidth. A 100ms 103*38378Skarels * wait is tolerable (500ms is not), so want an MTU around 256. 104*38378Skarels * (Since TCP will send 212 byte segments (to allow for 40 byte 105*38378Skarels * headers), the typical packet size on the wire will be around 220 106*38378Skarels * bytes). In 4.3tahoe+ systems, we can set an MTU in a route 107*38378Skarels * so we do that & leave the interface MTU relatively high (so we 108*38378Skarels * don't IP fragment when acting as a gateway to someone using a 109*38378Skarels * stupid MTU). 11026121Skarels */ 111*38378Skarels #define SLMTU 576 112*38378Skarels #define BUFOFFSET (128+sizeof(struct ifnet **)) 113*38378Skarels #define SLIP_HIWAT 1024 /* don't start a new packet if HIWAT on queue */ 114*38378Skarels #define CLISTRESERVE 1024 /* Can't let clists get too low */ 11538365Swilliam /* 11638365Swilliam * SLIP ABORT ESCAPE MECHANISM: 11738365Swilliam * (inspired by HAYES modem escape arrangement) 11838365Swilliam * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } 11938365Swilliam * signals a "soft" exit from slip mode by usermode process 12038365Swilliam */ 12126121Skarels 12238365Swilliam #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ 12338365Swilliam #define ABT_WAIT 1 /* in seconds - idle before an escape & after */ 12438365Swilliam #define ABT_RECYCLE (5*2+2) /* in seconds - time window processing abort */ 12526121Skarels 12638365Swilliam #define ABT_SOFT 3 /* count of escapes */ 12738365Swilliam 12838365Swilliam /* 129*38378Skarels * The following disgusting hack gets around the problem that IP TOS 130*38378Skarels * can't be set in BSD/Sun OS yet. We want to put "interactive" 131*38378Skarels * traffic on a high priority queue. To decide if traffic is 132*38378Skarels * interactive, we check that a) it is TCP and b) one of it's ports 133*38378Skarels * if telnet, rlogin or ftp control. 13438365Swilliam */ 135*38378Skarels static u_short interactive_ports[8] = { 136*38378Skarels 0, 513, 0, 0, 137*38378Skarels 0, 21, 0, 23, 138*38378Skarels }; 139*38378Skarels #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 14038365Swilliam 141*38378Skarels struct sl_softc sl_softc[NSL]; 14238365Swilliam 143*38378Skarels #define FRAME_END 0xc0 /* Frame End */ 144*38378Skarels #define FRAME_ESCAPE 0xdb /* Frame Esc */ 145*38378Skarels #define TRANS_FRAME_END 0xdc /* transposed frame end */ 146*38378Skarels #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ 14738365Swilliam 14826121Skarels #define t_sc T_LINEP 14926121Skarels 15026121Skarels int sloutput(), slioctl(), ttrstrt(); 15126121Skarels 15226121Skarels /* 15326121Skarels * Called from boot code to establish sl interfaces. 15426121Skarels */ 15526121Skarels slattach() 15626121Skarels { 15726121Skarels register struct sl_softc *sc; 15826121Skarels register int i = 0; 15926121Skarels 16026121Skarels for (sc = sl_softc; i < NSL; sc++) { 16126121Skarels sc->sc_if.if_name = "sl"; 16226121Skarels sc->sc_if.if_unit = i++; 16326121Skarels sc->sc_if.if_mtu = SLMTU; 16426121Skarels sc->sc_if.if_flags = IFF_POINTOPOINT; 16526121Skarels sc->sc_if.if_ioctl = slioctl; 16626121Skarels sc->sc_if.if_output = sloutput; 167*38378Skarels sc->sc_if.if_snd.ifq_maxlen = 50; 168*38378Skarels sc->sc_fastq.ifq_maxlen = 32; 16926121Skarels if_attach(&sc->sc_if); 17026121Skarels } 17126121Skarels } 17226121Skarels 173*38378Skarels static int 174*38378Skarels slinit(sc) 175*38378Skarels register struct sl_softc *sc; 176*38378Skarels { 177*38378Skarels register caddr_t p; 178*38378Skarels 179*38378Skarels if (sc->sc_ep == (u_char *) 0) { 180*38378Skarels MCLALLOC(p, M_WAIT); 181*38378Skarels if (p) 182*38378Skarels sc->sc_ep = (u_char *)p + (BUFOFFSET + SLMTU); 183*38378Skarels else { 184*38378Skarels printf("sl%d: can't allocate buffer\n", sc - sl_softc); 185*38378Skarels sc->sc_if.if_flags &= ~IFF_UP; 186*38378Skarels return (0); 187*38378Skarels } 188*38378Skarels } 189*38378Skarels sc->sc_buf = sc->sc_ep - SLMTU; 190*38378Skarels sc->sc_mp = sc->sc_buf; 191*38378Skarels sl_compress_init(&sc->sc_comp); 192*38378Skarels return (1); 193*38378Skarels } 194*38378Skarels 19526121Skarels /* 19626121Skarels * Line specific open routine. 19726121Skarels * Attach the given tty to the first available sl unit. 19826121Skarels */ 19926378Skarels /* ARGSUSED */ 20026121Skarels slopen(dev, tp) 20126121Skarels dev_t dev; 20226121Skarels register struct tty *tp; 20326121Skarels { 20426121Skarels register struct sl_softc *sc; 20526121Skarels register int nsl; 20637549Smckusick int error; 20726121Skarels 20837549Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 20937549Smckusick return (error); 210*38378Skarels 21126378Skarels if (tp->t_line == SLIPDISC) 21226121Skarels return (EBUSY); 21326121Skarels 214*38378Skarels for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) 21526121Skarels if (sc->sc_ttyp == NULL) { 21626378Skarels if (slinit(sc) == 0) 21726378Skarels return (ENOBUFS); 21826121Skarels tp->t_sc = (caddr_t)sc; 21926121Skarels sc->sc_ttyp = tp; 22026378Skarels ttyflush(tp, FREAD | FWRITE); 22126121Skarels return (0); 22226121Skarels } 22326378Skarels return (ENXIO); 22426121Skarels } 22526121Skarels 22626121Skarels /* 22726121Skarels * Line specific close routine. 22826121Skarels * Detach the tty from the sl unit. 22926121Skarels * Mimics part of ttyclose(). 23026121Skarels */ 23126121Skarels slclose(tp) 23226121Skarels struct tty *tp; 23326121Skarels { 23426121Skarels register struct sl_softc *sc; 23526121Skarels int s; 23626121Skarels 23726121Skarels ttywflush(tp); 238*38378Skarels s = splimp(); /* actually, max(spltty, splnet) */ 23926121Skarels tp->t_line = 0; 24026121Skarels sc = (struct sl_softc *)tp->t_sc; 24126121Skarels if (sc != NULL) { 24226121Skarels if_down(&sc->sc_if); 24326121Skarels sc->sc_ttyp = NULL; 24426121Skarels tp->t_sc = NULL; 245*38378Skarels MCLFREE((struct mbuf *)(sc->sc_ep - (SLMTU + BUFOFFSET))); 246*38378Skarels sc->sc_ep = 0; 247*38378Skarels sc->sc_mp = 0; 24826378Skarels sc->sc_buf = 0; 24926121Skarels } 25026121Skarels splx(s); 25126121Skarels } 25226121Skarels 25326121Skarels /* 25426121Skarels * Line specific (tty) ioctl routine. 25526121Skarels * Provide a way to get the sl unit number. 25626121Skarels */ 25726378Skarels /* ARGSUSED */ 25826121Skarels sltioctl(tp, cmd, data, flag) 25926121Skarels struct tty *tp; 26026121Skarels caddr_t data; 26126121Skarels { 26238365Swilliam struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 26338365Swilliam int s; 26426121Skarels 26538365Swilliam switch (cmd) { 266*38378Skarels case TIOCGETD: /* XXX */ 267*38378Skarels case SLIOGUNIT: 26838365Swilliam *(int *)data = sc->sc_if.if_unit; 26938365Swilliam break; 27038365Swilliam 27138365Swilliam case SLIOCGFLAGS: 27238365Swilliam *(int *)data = sc->sc_flags; 27338365Swilliam break; 274*38378Skarels 27538365Swilliam case SLIOCSFLAGS: 27638365Swilliam #define SC_MASK (SC_COMPRESS|SC_NOICMP) 27738365Swilliam s = splimp(); 27838365Swilliam sc->sc_flags = 27938365Swilliam (sc->sc_flags &~ SC_MASK) | ((*(int *)data) & SC_MASK); 28038365Swilliam splx(s); 28138365Swilliam break; 282*38378Skarels 28338365Swilliam default: 28438365Swilliam return (-1); 28538280Swilliam } 28638365Swilliam return (0); 28726121Skarels } 28826121Skarels 28926121Skarels /* 29026121Skarels * Queue a packet. Start transmission if not active. 29126121Skarels */ 29226121Skarels sloutput(ifp, m, dst) 29326121Skarels register struct ifnet *ifp; 29426121Skarels register struct mbuf *m; 29526121Skarels struct sockaddr *dst; 29626121Skarels { 29726121Skarels register struct sl_softc *sc; 298*38378Skarels register struct ip *ip; 299*38378Skarels register struct ifqueue *ifq; 30026121Skarels int s; 30126121Skarels 30226121Skarels /* 30326121Skarels * `Cannot happen' (see slioctl). Someday we will extend 30426121Skarels * the line protocol to support other address families. 30526121Skarels */ 30626121Skarels if (dst->sa_family != AF_INET) { 30726121Skarels printf("sl%d: af%d not supported\n", ifp->if_unit, 30826121Skarels dst->sa_family); 30926121Skarels m_freem(m); 31026121Skarels return (EAFNOSUPPORT); 31126121Skarels } 31226121Skarels 31326121Skarels sc = &sl_softc[ifp->if_unit]; 31426121Skarels if (sc->sc_ttyp == NULL) { 31526121Skarels m_freem(m); 31626121Skarels return (ENETDOWN); /* sort of */ 31726121Skarels } 31826899Skarels if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) { 31926899Skarels m_freem(m); 32026899Skarels return (EHOSTUNREACH); 32126899Skarels } 322*38378Skarels ifq = &ifp->if_snd; 323*38378Skarels if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { 324*38378Skarels register int p = ((int *)ip)[ip->ip_hl]; 325*38378Skarels 326*38378Skarels if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) 327*38378Skarels ifq = &sc->sc_fastq; 328*38378Skarels 329*38378Skarels if (sc->sc_flags & SC_COMPRESS) { 330*38378Skarels /* if two copies of sl_compress_tcp are running 331*38378Skarels * for the same line, the compression state can 332*38378Skarels * get screwed up. We're assuming that sloutput 333*38378Skarels * was invoked at splnet so this isn't possible 334*38378Skarels * (this assumption is correct for 4.xbsd, x<=4). 335*38378Skarels * In a multi-threaded kernel, a lockout might 336*38378Skarels * be needed here. */ 337*38378Skarels p = sl_compress_tcp(m, ip, &sc->sc_comp); 338*38378Skarels *mtod(m, u_char *) |= p; 33938365Swilliam } 340*38378Skarels } else if (sc->sc_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { 341*38378Skarels m_freem(m); 342*38378Skarels return (0); 34338365Swilliam } 344*38378Skarels s = splimp(); 345*38378Skarels if (IF_QFULL(ifq)) { 346*38378Skarels IF_DROP(ifq); 347*38378Skarels m_freem(m); 34826121Skarels splx(s); 34926378Skarels sc->sc_if.if_oerrors++; 35026121Skarels return (ENOBUFS); 35126121Skarels } 352*38378Skarels IF_ENQUEUE(ifq, m); 35333740Skarels if (sc->sc_ttyp->t_outq.c_cc == 0) { 35426121Skarels splx(s); 35526121Skarels slstart(sc->sc_ttyp); 35626121Skarels } else 35726121Skarels splx(s); 35826121Skarels return (0); 35926121Skarels } 36026121Skarels 36126121Skarels /* 36226121Skarels * Start output on interface. Get another datagram 36326121Skarels * to send from the interface queue and map it to 36426121Skarels * the interface before starting output. 36526121Skarels */ 36626121Skarels slstart(tp) 36726121Skarels register struct tty *tp; 36826121Skarels { 36926121Skarels register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; 37026121Skarels register struct mbuf *m; 37126378Skarels register u_char *cp; 372*38378Skarels int s; 37326378Skarels struct mbuf *m2; 37426378Skarels extern int cfreecount; 37526121Skarels 37626378Skarels for (;;) { 37726378Skarels /* 37826378Skarels * If there is more in the output queue, just send it now. 37926378Skarels * We are being called in lieu of ttstart and must do what 38026378Skarels * it would. 38126378Skarels */ 382*38378Skarels if (tp->t_outq.c_cc != 0) { 383*38378Skarels (*tp->t_oproc)(tp); 384*38378Skarels if (tp->t_outq.c_cc > SLIP_HIWAT) 385*38378Skarels return; 386*38378Skarels } 38726378Skarels /* 38826378Skarels * This happens briefly when the line shuts down. 38926378Skarels */ 39026378Skarels if (sc == NULL) 39126378Skarels return; 39226121Skarels 39326378Skarels /* 39426378Skarels * Get a packet and send it to the interface. 39526378Skarels */ 39626378Skarels s = splimp(); 397*38378Skarels IF_DEQUEUE(&sc->sc_fastq, m); 398*38378Skarels if (m == NULL) 399*38378Skarels IF_DEQUEUE(&sc->sc_if.if_snd, m); 40033740Skarels splx(s); 40133740Skarels if (m == NULL) 40226378Skarels return; 403*38378Skarels /* 404*38378Skarels * If system is getting low on clists, just flush our 405*38378Skarels * output queue (if the stuff was important, it'll get 406*38378Skarels * retransmitted). 407*38378Skarels */ 408*38378Skarels if (cfreecount < CLISTRESERVE + SLMTU) { 409*38378Skarels m_freem(m); 410*38378Skarels sc->sc_if.if_collisions++; 411*38378Skarels continue; 412*38378Skarels } 41326121Skarels 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 */ 419*38378Skarels if (tp->t_outq.c_cc == 0) { 420*38378Skarels ++sc->sc_bytessent; 42126378Skarels (void) putc(FRAME_END, &tp->t_outq); 422*38378Skarels } 42326378Skarels 42426378Skarels while (m) { 425*38378Skarels register u_char *ep; 426*38378Skarels 427*38378Skarels cp = mtod(m, u_char *); ep = cp + m->m_len; 428*38378Skarels while (cp < ep) { 42926378Skarels /* 43026378Skarels * Find out how many bytes in the string we can 43126378Skarels * handle without doing something special. 43226378Skarels */ 433*38378Skarels register u_char *bp = cp; 434*38378Skarels 435*38378Skarels while (cp < ep) { 436*38378Skarels switch (*cp++) { 437*38378Skarels case FRAME_ESCAPE: 438*38378Skarels case FRAME_END: 439*38378Skarels --cp; 440*38378Skarels goto out; 441*38378Skarels } 442*38378Skarels } 443*38378Skarels out: 444*38378Skarels if (cp > bp) { 44526378Skarels /* 44626378Skarels * Put n characters at once 44726378Skarels * into the tty output queue. 44826378Skarels */ 449*38378Skarels if (b_to_q((char *)bp, cp - bp, &tp->t_outq)) 45026378Skarels break; 451*38378Skarels sc->sc_bytessent += 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 */ 458*38378Skarels if (cp < ep) { 45926378Skarels if (putc(FRAME_ESCAPE, &tp->t_outq)) 46026378Skarels break; 461*38378Skarels 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 } 467*38378Skarels sc->sc_bytessent += 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++; 485*38378Skarels } else { 486*38378Skarels ++sc->sc_bytessent; 48726378Skarels sc->sc_if.if_opackets++; 48826378Skarels } 48926378Skarels } 49026121Skarels } 49126121Skarels 49226121Skarels /* 493*38378Skarels * Copy data buffer to mbuf chain; add ifnet pointer. 49426121Skarels */ 495*38378Skarels static struct mbuf * 496*38378Skarels sl_btom(sc, len) 497*38378Skarels register struct sl_softc *sc; 49826121Skarels register int len; 49926121Skarels { 500*38378Skarels register u_char *cp; 501*38378Skarels register struct mbuf *m; 50226121Skarels 503*38378Skarels MGETHDR(m, M_DONTWAIT, MT_DATA); 504*38378Skarels if (m == NULL) 505*38378Skarels return (NULL); 506*38378Skarels 507*38378Skarels /* 508*38378Skarels * If we have more than MLEN bytes, it's cheaper to 509*38378Skarels * queue the cluster we just filled & allocate a new one 510*38378Skarels * for the input buffer. Otherwise, fill the mbuf we 511*38378Skarels * allocated above. Note that code in the input routine 512*38378Skarels * guarantees that packet will fit in a cluster. 513*38378Skarels */ 51438280Swilliam cp = sc->sc_buf; 515*38378Skarels if (len >= MHLEN) { 516*38378Skarels MCLGET(m, M_DONTWAIT); 517*38378Skarels if ((m->m_flags & M_EXT) == 0) { 518*38378Skarels /* we couldn't get a cluster - if memory's this 519*38378Skarels * low, it's time to start dropping packets. */ 520*38378Skarels m_freem(m); 52126121Skarels return (NULL); 52226121Skarels } 523*38378Skarels sc->sc_ep = mtod(m, u_char *) + (BUFOFFSET + SLMTU); 524*38378Skarels m->m_data = (caddr_t)cp; 525*38378Skarels } else 526*38378Skarels bcopy((caddr_t)cp, mtod(m, caddr_t), len); 527*38378Skarels 528*38378Skarels m->m_len = len; 529*38378Skarels m->m_pkthdr.len = len; 530*38378Skarels m->m_pkthdr.rcvif = &sc->sc_if; 531*38378Skarels return (m); 53226121Skarels } 53326121Skarels 53426121Skarels /* 53526121Skarels * tty interface receiver interrupt. 53626121Skarels */ 53726121Skarels slinput(c, tp) 53826121Skarels register int c; 53926121Skarels register struct tty *tp; 54026121Skarels { 54126121Skarels register struct sl_softc *sc; 54226121Skarels register struct mbuf *m; 543*38378Skarels register int len; 54426121Skarels int s; 54526121Skarels 54626378Skarels tk_nin++; 54726121Skarels sc = (struct sl_softc *)tp->t_sc; 54826121Skarels if (sc == NULL) 54926121Skarels return; 550*38378Skarels if (!(tp->t_state&TS_CARR_ON)) /* XXX */ 55138365Swilliam return; 55226121Skarels 553*38378Skarels ++sc->sc_bytesrcvd; 554*38378Skarels c &= 0xff; /* XXX */ 55538365Swilliam 556*38378Skarels #ifdef ABT_ESC 557*38378Skarels if (sc->sc_flags & SC_ABORT) { 558*38378Skarels /* if we see an abort after "idle" time, count it */ 559*38378Skarels if (c == ABT_ESC && time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 560*38378Skarels sc->sc_abortcount++; 561*38378Skarels /* record when the first abort escape arrived */ 562*38378Skarels if (sc->sc_abortcount == 1) 563*38378Skarels sc->sc_starttime = time.tv_sec; 564*38378Skarels } 565*38378Skarels /* 566*38378Skarels * if we have an abort, see that we have not run out of time, 567*38378Skarels * or that we have an "idle" time after the complete escape 568*38378Skarels * sequence 569*38378Skarels */ 570*38378Skarels if (sc->sc_abortcount) { 571*38378Skarels if (time.tv_sec >= sc->sc_starttime + ABT_RECYCLE) 572*38378Skarels sc->sc_abortcount = 0; 573*38378Skarels if (sc->sc_abortcount >= ABT_SOFT && 574*38378Skarels time.tv_sec >= sc->sc_lasttime + ABT_WAIT) { 575*38378Skarels slclose(tp); 576*38378Skarels return; 577*38378Skarels } 578*38378Skarels } 579*38378Skarels sc->sc_lasttime = time.tv_sec; 58038365Swilliam } 581*38378Skarels #endif 58238365Swilliam 583*38378Skarels switch (c) { 58438365Swilliam 585*38378Skarels case TRANS_FRAME_ESCAPE: 586*38378Skarels if (sc->sc_escape) 587*38378Skarels c = FRAME_ESCAPE; 588*38378Skarels break; 58938365Swilliam 590*38378Skarels case TRANS_FRAME_END: 591*38378Skarels if (sc->sc_escape) 592*38378Skarels c = FRAME_END; 593*38378Skarels break; 59438365Swilliam 595*38378Skarels case FRAME_ESCAPE: 596*38378Skarels sc->sc_escape = 1; 597*38378Skarels return; 59826121Skarels 599*38378Skarels case FRAME_END: 600*38378Skarels len = sc->sc_mp - sc->sc_buf; 601*38378Skarels if (len < 3) 602*38378Skarels /* less than min length packet - ignore */ 603*38378Skarels goto newpack; 60426121Skarels 605*38378Skarels if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { 606*38378Skarels if (c & 0x80) 607*38378Skarels c = TYPE_COMPRESSED_TCP; 608*38378Skarels else if (c == TYPE_UNCOMPRESSED_TCP) 609*38378Skarels *sc->sc_buf &= 0x4f; /* XXX */ 610*38378Skarels len = sl_uncompress_tcp(&sc->sc_buf, len, (u_int)c, 611*38378Skarels &sc->sc_comp); 612*38378Skarels if (len <= 0) 613*38378Skarels goto error; 614*38378Skarels } 615*38378Skarels m = sl_btom(sc, len); 616*38378Skarels if (m == NULL) 617*38378Skarels goto error; 61826121Skarels 619*38378Skarels sc->sc_if.if_ipackets++; 620*38378Skarels s = splimp(); 621*38378Skarels if (IF_QFULL(&ipintrq)) { 622*38378Skarels IF_DROP(&ipintrq); 62326121Skarels sc->sc_if.if_ierrors++; 624*38378Skarels m_freem(m); 625*38378Skarels } else { 626*38378Skarels IF_ENQUEUE(&ipintrq, m); 627*38378Skarels schednetisr(NETISR_IP); 62826121Skarels } 629*38378Skarels splx(s); 630*38378Skarels goto newpack; 63126121Skarels } 632*38378Skarels if (sc->sc_mp < sc->sc_ep) { 633*38378Skarels *sc->sc_mp++ = c; 634*38378Skarels sc->sc_escape = 0; 63526121Skarels return; 63626121Skarels } 637*38378Skarels error: 638*38378Skarels sc->sc_if.if_ierrors++; 639*38378Skarels newpack: 640*38378Skarels sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMTU; 641*38378Skarels sc->sc_escape = 0; 64226121Skarels } 64326121Skarels 64426121Skarels /* 64526121Skarels * Process an ioctl request. 64626121Skarels */ 64726121Skarels slioctl(ifp, cmd, data) 64826121Skarels register struct ifnet *ifp; 64926121Skarels int cmd; 65026121Skarels caddr_t data; 65126121Skarels { 65226121Skarels register struct ifaddr *ifa = (struct ifaddr *)data; 65326121Skarels int s = splimp(), error = 0; 65426121Skarels 65526121Skarels switch (cmd) { 65626121Skarels 65726121Skarels case SIOCSIFADDR: 65837472Ssklower if (ifa->ifa_addr->sa_family == AF_INET) 65926121Skarels ifp->if_flags |= IFF_UP; 66026121Skarels else 66126121Skarels error = EAFNOSUPPORT; 66226121Skarels break; 66326121Skarels 66426121Skarels case SIOCSIFDSTADDR: 66537472Ssklower if (ifa->ifa_addr->sa_family != AF_INET) 66626121Skarels error = EAFNOSUPPORT; 66726121Skarels break; 66826121Skarels 66926121Skarels default: 67026121Skarels error = EINVAL; 67126121Skarels } 67226121Skarels splx(s); 67326121Skarels return (error); 67426121Skarels } 67526121Skarels #endif 676