|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1987, 1989, 1992, 1993 ! 28: * The Regents of the University of California. All rights reserved. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)if_sl.c 8.9 (Berkeley) 1/9/95 ! 59: */ ! 60: ! 61: /* ! 62: * Serial Line interface ! 63: * ! 64: * Rick Adams ! 65: * Center for Seismic Studies ! 66: * 1300 N 17th Street, Suite 1450 ! 67: * Arlington, Virginia 22209 ! 68: * (703)276-7900 ! 69: * [email protected] ! 70: * seismo!rick ! 71: * ! 72: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris). ! 73: * N.B.: this belongs in netinet, not net, the way it stands now. ! 74: * Should have a link-layer type designation, but wouldn't be ! 75: * backwards-compatible. ! 76: * ! 77: * Converted to 4.3BSD Beta by Chris Torek. ! 78: * Other changes made at Berkeley, based in part on code by Kirk Smith. ! 79: * W. Jolitz added slip abort. ! 80: * ! 81: * Hacked almost beyond recognition by Van Jacobson ([email protected]). ! 82: * Added priority queuing for "interactive" traffic; hooks for TCP ! 83: * header compression; ICMP filtering (at 2400 baud, some cretin ! 84: * pinging you can use up all your bandwidth). Made low clist behavior ! 85: * more robust and slightly less likely to hang serial line. ! 86: * Sped up a bunch of things. ! 87: * ! 88: * Note that splimp() is used throughout to block both (tty) input ! 89: * interrupts and network activity; thus, splimp must be >= spltty. ! 90: */ ! 91: ! 92: #include "sl.h" ! 93: #if NSL > 0 ! 94: ! 95: #include "bpfilter.h" ! 96: ! 97: #include <sys/param.h> ! 98: #include <sys/proc.h> ! 99: #include <sys/mbuf.h> ! 100: #include <sys/buf.h> ! 101: #include <sys/dkstat.h> ! 102: #include <sys/socket.h> ! 103: #include <sys/ioctl.h> ! 104: #include <sys/file.h> ! 105: #include <sys/tty.h> ! 106: #include <sys/kernel.h> ! 107: #include <sys/conf.h> ! 108: ! 109: #include <machine/cpu.h> ! 110: ! 111: #include <net/if.h> ! 112: #include <net/if_types.h> ! 113: #include <net/netisr.h> ! 114: #include <net/route.h> ! 115: ! 116: #if INET ! 117: #include <netinet/in.h> ! 118: #include <netinet/in_systm.h> ! 119: #include <netinet/in_var.h> ! 120: #include <netinet/ip.h> ! 121: #else ! 122: Huh? Slip without inet? ! 123: #endif ! 124: ! 125: #include <net/slcompress.h> ! 126: #include <net/if_slvar.h> ! 127: #include <net/slip.h> ! 128: ! 129: #if NBPFILTER > 0 ! 130: #include <sys/time.h> ! 131: #include <net/bpf.h> ! 132: #endif ! 133: ! 134: /* ! 135: * SLMAX is a hard limit on input packet size. To simplify the code ! 136: * and improve performance, we require that packets fit in an mbuf ! 137: * cluster, and if we get a compressed packet, there's enough extra ! 138: * room to expand the header into a max length tcp/ip header (128 ! 139: * bytes). So, SLMAX can be at most ! 140: * MCLBYTES - 128 ! 141: * ! 142: * SLMTU is a hard limit on output packet size. To insure good ! 143: * interactive response, SLMTU wants to be the smallest size that ! 144: * amortizes the header cost. (Remember that even with ! 145: * type-of-service queuing, we have to wait for any in-progress ! 146: * packet to finish. I.e., we wait, on the average, 1/2 * mtu / ! 147: * cps, where cps is the line speed in characters per second. ! 148: * E.g., 533ms wait for a 1024 byte MTU on a 9600 baud line. The ! 149: * average compressed header size is 6-8 bytes so any MTU > 90 ! 150: * bytes will give us 90% of the line bandwidth. A 100ms wait is ! 151: * tolerable (500ms is not), so want an MTU around 296. (Since TCP ! 152: * will send 256 byte segments (to allow for 40 byte headers), the ! 153: * typical packet size on the wire will be around 260 bytes). In ! 154: * 4.3tahoe+ systems, we can set an MTU in a route so we do that & ! 155: * leave the interface MTU relatively high (so we don't IP fragment ! 156: * when acting as a gateway to someone using a stupid MTU). ! 157: * ! 158: * Similar considerations apply to SLIP_HIWAT: It's the amount of ! 159: * data that will be queued 'downstream' of us (i.e., in clists ! 160: * waiting to be picked up by the tty output interrupt). If we ! 161: * queue a lot of data downstream, it's immune to our t.o.s. queuing. ! 162: * E.g., if SLIP_HIWAT is 1024, the interactive traffic in mixed ! 163: * telnet/ftp will see a 1 sec wait, independent of the mtu (the ! 164: * wait is dependent on the ftp window size but that's typically ! 165: * 1k - 4k). So, we want SLIP_HIWAT just big enough to amortize ! 166: * the cost (in idle time on the wire) of the tty driver running ! 167: * off the end of its clists & having to call back slstart for a ! 168: * new packet. For a tty interface with any buffering at all, this ! 169: * cost will be zero. Even with a totally brain dead interface (like ! 170: * the one on a typical workstation), the cost will be <= 1 character ! 171: * time. So, setting SLIP_HIWAT to ~100 guarantees that we'll lose ! 172: * at most 1% while maintaining good interactive response. ! 173: */ ! 174: #if NBPFILTER > 0 ! 175: #define BUFOFFSET (128+sizeof(struct ifnet **)+SLIP_HDRLEN) ! 176: #else ! 177: #define BUFOFFSET (128+sizeof(struct ifnet **)) ! 178: #endif ! 179: #define SLMAX (MCLBYTES - BUFOFFSET) ! 180: #define SLBUFSIZE (SLMAX + BUFOFFSET) ! 181: #define SLMTU 296 ! 182: #define SLIP_HIWAT roundup(50,CBSIZE) ! 183: ! 184: /* ! 185: * SLIP ABORT ESCAPE MECHANISM: ! 186: * (inspired by HAYES modem escape arrangement) ! 187: * 1sec escape 1sec escape 1sec escape { 1sec escape 1sec escape } ! 188: * within window time signals a "soft" exit from slip mode by remote end ! 189: * if the IFF_DEBUG flag is on. ! 190: */ ! 191: #define ABT_ESC '\033' /* can't be t_intr - distant host must know it*/ ! 192: #define ABT_IDLE 1 /* in seconds - idle before an escape */ ! 193: #define ABT_COUNT 3 /* count of escapes for abort */ ! 194: #define ABT_WINDOW (ABT_COUNT*2+2) /* in seconds - time to count */ ! 195: ! 196: struct sl_softc sl_softc[NSL]; ! 197: ! 198: #define FRAME_END 0xc0 /* Frame End */ ! 199: #define FRAME_ESCAPE 0xdb /* Frame Esc */ ! 200: #define TRANS_FRAME_END 0xdc /* transposed frame end */ ! 201: #define TRANS_FRAME_ESCAPE 0xdd /* transposed frame esc */ ! 202: ! 203: static int slinit __P((struct sl_softc *)); ! 204: static struct mbuf *sl_btom __P((struct sl_softc *, int)); ! 205: ! 206: /* ! 207: * Called from boot code to establish sl interfaces. ! 208: */ ! 209: void ! 210: slattach() ! 211: { ! 212: register struct sl_softc *sc; ! 213: register int i = 0; ! 214: ! 215: for (sc = sl_softc; i < NSL; sc++) { ! 216: sc->sc_if.if_name = "sl"; ! 217: sc->sc_if.if_next = NULL; ! 218: sc->sc_if.if_unit = i++; ! 219: sc->sc_if.if_mtu = SLMTU; ! 220: sc->sc_if.if_flags = ! 221: IFF_POINTOPOINT | SC_AUTOCOMP | IFF_MULTICAST; ! 222: sc->sc_if.if_type = IFT_SLIP; ! 223: sc->sc_if.if_ioctl = slioctl; ! 224: sc->sc_if.if_output = sloutput; ! 225: sc->sc_if.if_snd.ifq_maxlen = 50; ! 226: sc->sc_fastq.ifq_maxlen = 32; ! 227: if_attach(&sc->sc_if); ! 228: #if NBPFILTER > 0 ! 229: bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_SLIP, SLIP_HDRLEN); ! 230: #endif ! 231: } ! 232: } ! 233: ! 234: static int ! 235: slinit(sc) ! 236: register struct sl_softc *sc; ! 237: { ! 238: register caddr_t p; ! 239: ! 240: if (sc->sc_ep == (u_char *) 0) { ! 241: MCLALLOC(p, M_WAIT); ! 242: if (p) ! 243: sc->sc_ep = (u_char *)p + SLBUFSIZE; ! 244: else { ! 245: printf("sl%d: can't allocate buffer\n", sc - sl_softc); ! 246: sc->sc_if.if_flags &= ~IFF_UP; ! 247: return (0); ! 248: } ! 249: } ! 250: sc->sc_buf = sc->sc_ep - SLMAX; ! 251: sc->sc_mp = sc->sc_buf; ! 252: sl_compress_init(&sc->sc_comp, -1); ! 253: return (1); ! 254: } ! 255: ! 256: /* ! 257: * Line specific open routine. ! 258: * Attach the given tty to the first available sl unit. ! 259: */ ! 260: /* ARGSUSED */ ! 261: int ! 262: slopen(dev, tp) ! 263: dev_t dev; ! 264: register struct tty *tp; ! 265: { ! 266: struct proc *p = curproc; /* XXX */ ! 267: register struct sl_softc *sc; ! 268: register int nsl; ! 269: int error; ! 270: int s; ! 271: ! 272: if (error = suser(p->p_ucred, &p->p_acflag)) ! 273: return (error); ! 274: ! 275: if (tp->t_line == SLIPDISC) ! 276: return (0); ! 277: ! 278: for (nsl = NSL, sc = sl_softc; --nsl >= 0; sc++) ! 279: if (sc->sc_ttyp == NULL) { ! 280: if (slinit(sc) == 0) ! 281: return (ENOBUFS); ! 282: tp->t_sc = (caddr_t)sc; ! 283: sc->sc_ttyp = tp; ! 284: sc->sc_if.if_baudrate = tp->t_ospeed; ! 285: ttyflush(tp, FREAD | FWRITE); ! 286: ! 287: /* ! 288: * make sure tty output queue is large enough ! 289: * to hold a full-sized packet (including frame ! 290: * end, and a possible extra frame end). full-sized ! 291: * packet occupies a max of 2*SLMTU bytes (because ! 292: * of possible escapes), and add two on for frame ! 293: * ends. ! 294: */ ! 295: s = spltty(); ! 296: if (tp->t_outq.c_cn < 2*SLMTU+2) { ! 297: sc->sc_oldbufsize = tp->t_outq.c_cn; ! 298: sc->sc_oldbufquot = tp->t_outq.c_cq != 0; ! 299: ! 300: clfree(&tp->t_outq); ! 301: error = clalloc(&tp->t_outq, 3*SLMTU, 0); ! 302: if (error) { ! 303: splx(s); ! 304: return(error); ! 305: } ! 306: } else ! 307: sc->sc_oldbufsize = sc->sc_oldbufquot = 0; ! 308: splx(s); ! 309: ! 310: return (0); ! 311: } ! 312: return (ENXIO); ! 313: } ! 314: ! 315: /* ! 316: * Line specific close routine. ! 317: * Detach the tty from the sl unit. ! 318: */ ! 319: void ! 320: slclose(tp) ! 321: struct tty *tp; ! 322: { ! 323: register struct sl_softc *sc; ! 324: int s; ! 325: ! 326: ttywflush(tp); ! 327: s = splimp(); /* actually, max(spltty, splnet) */ ! 328: tp->t_line = 0; ! 329: tp->t_state = 0; ! 330: sc = (struct sl_softc *)tp->t_sc; ! 331: if (sc != NULL) { ! 332: if_down(&sc->sc_if); ! 333: sc->sc_ttyp = NULL; ! 334: tp->t_sc = NULL; ! 335: MCLFREE((caddr_t)(sc->sc_ep - SLBUFSIZE)); ! 336: sc->sc_ep = 0; ! 337: sc->sc_mp = 0; ! 338: sc->sc_buf = 0; ! 339: } ! 340: /* if necessary, install a new outq buffer of the appropriate size */ ! 341: if (sc->sc_oldbufsize != 0) { ! 342: clfree(&tp->t_outq); ! 343: clalloc(&tp->t_outq, sc->sc_oldbufsize, sc->sc_oldbufquot); ! 344: } ! 345: splx(s); ! 346: } ! 347: ! 348: /* ! 349: * Line specific (tty) ioctl routine. ! 350: * Provide a way to get the sl unit number. ! 351: */ ! 352: /* ARGSUSED */ ! 353: int ! 354: sltioctl(tp, cmd, data, flag) ! 355: struct tty *tp; ! 356: u_long cmd; ! 357: caddr_t data; ! 358: int flag; ! 359: { ! 360: struct sl_softc *sc = (struct sl_softc *)tp->t_sc; ! 361: ! 362: switch (cmd) { ! 363: case SLIOCGUNIT: ! 364: *(int *)data = sc->sc_if.if_unit; ! 365: break; ! 366: ! 367: default: ! 368: return (-1); ! 369: } ! 370: return (0); ! 371: } ! 372: ! 373: /* ! 374: * Queue a packet. Start transmission if not active. ! 375: * Compression happens in slstart; if we do it here, IP TOS ! 376: * will cause us to not compress "background" packets, because ! 377: * ordering gets trashed. It can be done for all packets in slstart. ! 378: */ ! 379: int ! 380: sloutput(ifp, m, dst, rtp) ! 381: struct ifnet *ifp; ! 382: register struct mbuf *m; ! 383: struct sockaddr *dst; ! 384: struct rtentry *rtp; ! 385: { ! 386: register struct sl_softc *sc = &sl_softc[ifp->if_unit]; ! 387: register struct ip *ip; ! 388: register struct ifqueue *ifq; ! 389: int s; ! 390: ! 391: /* ! 392: * `Cannot happen' (see slioctl). Someday we will extend ! 393: * the line protocol to support other address families. ! 394: */ ! 395: if (dst->sa_family != AF_INET) { ! 396: printf("sl%d: af%d not supported\n", sc->sc_if.if_unit, ! 397: dst->sa_family); ! 398: m_freem(m); ! 399: sc->sc_if.if_noproto++; ! 400: return (EAFNOSUPPORT); ! 401: } ! 402: ! 403: if (sc->sc_ttyp == NULL) { ! 404: m_freem(m); ! 405: return (ENETDOWN); /* sort of */ ! 406: } ! 407: if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0 && ! 408: (sc->sc_ttyp->t_cflag & CLOCAL) == 0) { ! 409: m_freem(m); ! 410: return (EHOSTUNREACH); ! 411: } ! 412: ifq = &sc->sc_if.if_snd; ! 413: ip = mtod(m, struct ip *); ! 414: if (sc->sc_if.if_flags & SC_NOICMP && ip->ip_p == IPPROTO_ICMP) { ! 415: m_freem(m); ! 416: return (ENETRESET); /* XXX ? */ ! 417: } ! 418: if (ip->ip_tos & IPTOS_LOWDELAY) ! 419: ifq = &sc->sc_fastq; ! 420: s = splimp(); ! 421: if (sc->sc_oqlen && sc->sc_ttyp->t_outq.c_cc == sc->sc_oqlen) { ! 422: /* if output's been stalled for too long, and restart */ ! 423: timersub(&time, &sc->sc_if.if_lastchange, &tv); ! 424: if (tv.tv_sec > 0) { ! 425: sc->sc_otimeout++; ! 426: slstart(sc->sc_ttyp); ! 427: } ! 428: } ! 429: if (IF_QFULL(ifq)) { ! 430: IF_DROP(ifq); ! 431: m_freem(m); ! 432: splx(s); ! 433: sc->sc_if.if_oerrors++; ! 434: return (ENOBUFS); ! 435: } ! 436: IF_ENQUEUE(ifq, m); ! 437: sc->sc_if.if_lastchange = time; ! 438: if ((sc->sc_oqlen = sc->sc_ttyp->t_outq.c_cc) == 0) ! 439: slstart(sc->sc_ttyp); ! 440: splx(s); ! 441: return (0); ! 442: } ! 443: ! 444: /* ! 445: * Start output on interface. Get another datagram ! 446: * to send from the interface queue and map it to ! 447: * the interface before starting output. ! 448: */ ! 449: void ! 450: slstart(tp) ! 451: register struct tty *tp; ! 452: { ! 453: register struct sl_softc *sc = (struct sl_softc *)tp->t_sc; ! 454: register struct mbuf *m; ! 455: register u_char *cp; ! 456: register struct ip *ip; ! 457: int s; ! 458: struct mbuf *m2; ! 459: #if NBPFILTER > 0 ! 460: u_char bpfbuf[SLMTU + SLIP_HDRLEN]; ! 461: register int len; ! 462: #endif ! 463: ! 464: for (;;) { ! 465: /* ! 466: * If there is more in the output queue, just send it now. ! 467: * We are being called in lieu of ttstart and must do what ! 468: * it would. ! 469: */ ! 470: if (tp->t_outq.c_cc != 0) { ! 471: (*tp->t_oproc)(tp); ! 472: if (tp->t_outq.c_cc > SLIP_HIWAT) ! 473: return; ! 474: } ! 475: /* ! 476: * This happens briefly when the line shuts down. ! 477: */ ! 478: if (sc == NULL) ! 479: return; ! 480: ! 481: /* ! 482: * Do not remove the packet from the IP queue if it ! 483: * doesn't look like the packet will fit into the ! 484: * current serial output queue, with a packet full of ! 485: * escapes this could be as bad as SLMTU*2+2. ! 486: */ ! 487: if (tp->t_outq.c_cn - tp->t_outq.c_cc < 2*SLMTU+2) ! 488: return; ! 489: ! 490: /* ! 491: * Get a packet and send it to the interface. ! 492: */ ! 493: s = splimp(); ! 494: IF_DEQUEUE(&sc->sc_fastq, m); ! 495: if (m) ! 496: sc->sc_if.if_omcasts++; /* XXX */ ! 497: else ! 498: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 499: splx(s); ! 500: if (m == NULL) ! 501: return; ! 502: ! 503: /* ! 504: * We do the header compression here rather than in sloutput ! 505: * because the packets will be out of order if we are using TOS ! 506: * queueing, and the connection id compression will get ! 507: * munged when this happens. ! 508: */ ! 509: #if NBPFILTER > 0 ! 510: if (sc->sc_bpf) { ! 511: /* ! 512: * We need to save the TCP/IP header before it's ! 513: * compressed. To avoid complicated code, we just ! 514: * copy the entire packet into a stack buffer (since ! 515: * this is a serial line, packets should be short ! 516: * and/or the copy should be negligible cost compared ! 517: * to the packet transmission time). ! 518: */ ! 519: register struct mbuf *m1 = m; ! 520: register u_char *cp = bpfbuf + SLIP_HDRLEN; ! 521: ! 522: len = 0; ! 523: do { ! 524: register int mlen = m1->m_len; ! 525: ! 526: bcopy(mtod(m1, caddr_t), cp, mlen); ! 527: cp += mlen; ! 528: len += mlen; ! 529: } while (m1 = m1->m_next); ! 530: } ! 531: #endif ! 532: if ((ip = mtod(m, struct ip *))->ip_p == IPPROTO_TCP) { ! 533: if (sc->sc_if.if_flags & SC_COMPRESS) ! 534: *mtod(m, u_char *) |= sl_compress_tcp(m, ip, ! 535: &sc->sc_comp, 1); ! 536: } ! 537: #if NBPFILTER > 0 ! 538: if (sc->sc_bpf) { ! 539: /* ! 540: * Put the SLIP pseudo-"link header" in place. The ! 541: * compressed header is now at the beginning of the ! 542: * mbuf. ! 543: */ ! 544: bpfbuf[SLX_DIR] = SLIPDIR_OUT; ! 545: bcopy(mtod(m, caddr_t), &bpfbuf[SLX_CHDR], CHDR_LEN); ! 546: BPF_TAP(sc->sc_bpf, bpfbuf, len + SLIP_HDRLEN); ! 547: } ! 548: #endif ! 549: sc->sc_if.if_lastchange = time; ! 550: ! 551: /* ! 552: * The extra FRAME_END will start up a new packet, and thus ! 553: * will flush any accumulated garbage. We do this whenever ! 554: * the line may have been idle for some time. ! 555: */ ! 556: if (tp->t_outq.c_cc == 0) { ! 557: ++sc->sc_if.if_obytes; ! 558: (void) putc(FRAME_END, &tp->t_outq); ! 559: } ! 560: ! 561: while (m) { ! 562: register u_char *ep; ! 563: ! 564: cp = mtod(m, u_char *); ep = cp + m->m_len; ! 565: while (cp < ep) { ! 566: /* ! 567: * Find out how many bytes in the string we can ! 568: * handle without doing something special. ! 569: */ ! 570: register u_char *bp = cp; ! 571: ! 572: while (cp < ep) { ! 573: switch (*cp++) { ! 574: case FRAME_ESCAPE: ! 575: case FRAME_END: ! 576: --cp; ! 577: goto out; ! 578: } ! 579: } ! 580: out: ! 581: if (cp > bp) { ! 582: /* ! 583: * Put n characters at once ! 584: * into the tty output queue. ! 585: */ ! 586: if (b_to_q((u_char *)bp, cp - bp, ! 587: &tp->t_outq)) ! 588: break; ! 589: sc->sc_if.if_obytes += cp - bp; ! 590: } ! 591: /* ! 592: * If there are characters left in the mbuf, ! 593: * the first one must be special.. ! 594: * Put it out in a different form. ! 595: */ ! 596: if (cp < ep) { ! 597: if (putc(FRAME_ESCAPE, &tp->t_outq)) ! 598: break; ! 599: if (putc(*cp++ == FRAME_ESCAPE ? ! 600: TRANS_FRAME_ESCAPE : TRANS_FRAME_END, ! 601: &tp->t_outq)) { ! 602: (void) unputc(&tp->t_outq); ! 603: break; ! 604: } ! 605: sc->sc_if.if_obytes += 2; ! 606: } ! 607: } ! 608: MFREE(m, m2); ! 609: m = m2; ! 610: } ! 611: ! 612: if (putc(FRAME_END, &tp->t_outq)) { ! 613: /* ! 614: * Not enough room. Remove a char to make room ! 615: * and end the packet normally. ! 616: * If you get many collisions (more than one or two ! 617: * a day) you probably do not have enough clists ! 618: * and you should increase "nclist" in param.c. ! 619: */ ! 620: (void) unputc(&tp->t_outq); ! 621: (void) putc(FRAME_END, &tp->t_outq); ! 622: sc->sc_if.if_collisions++; ! 623: } else { ! 624: ++sc->sc_if.if_obytes; ! 625: sc->sc_if.if_opackets++; ! 626: } ! 627: } ! 628: } ! 629: ! 630: /* ! 631: * Copy data buffer to mbuf chain; add ifnet pointer. ! 632: */ ! 633: static struct mbuf * ! 634: sl_btom(sc, len) ! 635: register struct sl_softc *sc; ! 636: register int len; ! 637: { ! 638: register struct mbuf *m; ! 639: ! 640: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 641: if (m == NULL) ! 642: return (NULL); ! 643: ! 644: /* ! 645: * If we have more than MHLEN bytes, it's cheaper to ! 646: * queue the cluster we just filled & allocate a new one ! 647: * for the input buffer. Otherwise, fill the mbuf we ! 648: * allocated above. Note that code in the input routine ! 649: * guarantees that packet will fit in a cluster. ! 650: */ ! 651: if (len >= MHLEN) { ! 652: MCLGET(m, M_DONTWAIT); ! 653: if ((m->m_flags & M_EXT) == 0) { ! 654: /* ! 655: * we couldn't get a cluster - if memory's this ! 656: * low, it's time to start dropping packets. ! 657: */ ! 658: (void) m_free(m); ! 659: return (NULL); ! 660: } ! 661: sc->sc_ep = mtod(m, u_char *) + SLBUFSIZE; ! 662: m->m_data = (caddr_t)sc->sc_buf; ! 663: m->m_ext.ext_buf = (caddr_t)((long)sc->sc_buf &~ MCLOFSET); ! 664: } else ! 665: bcopy((caddr_t)sc->sc_buf, mtod(m, caddr_t), len); ! 666: ! 667: m->m_len = len; ! 668: m->m_pkthdr.len = len; ! 669: m->m_pkthdr.rcvif = &sc->sc_if; ! 670: return (m); ! 671: } ! 672: ! 673: /* ! 674: * tty interface receiver interrupt. ! 675: */ ! 676: void ! 677: slinput(c, tp) ! 678: register int c; ! 679: register struct tty *tp; ! 680: { ! 681: register struct sl_softc *sc; ! 682: register struct mbuf *m; ! 683: register int len; ! 684: int s; ! 685: #if NBPFILTER > 0 ! 686: u_char chdr[CHDR_LEN]; ! 687: #endif ! 688: ! 689: tk_nin++; ! 690: sc = (struct sl_softc *)tp->t_sc; ! 691: if (sc == NULL) ! 692: return; ! 693: if (c & TTY_ERRORMASK || ((tp->t_state & TS_CARR_ON) == 0 && ! 694: (tp->t_cflag & CLOCAL) == 0)) { ! 695: sc->sc_flags |= SC_ERROR; ! 696: return; ! 697: } ! 698: c &= TTY_CHARMASK; ! 699: ! 700: ++sc->sc_if.if_ibytes; ! 701: ! 702: if (sc->sc_if.if_flags & IFF_DEBUG) { ! 703: ! 704: if (c == ABT_ESC) { ! 705: /* ! 706: * If we have a previous abort, see whether ! 707: * this one is within the time limit. ! 708: */ ! 709: if (sc->sc_abortcount && ! 710: time.tv_sec >= sc->sc_starttime + ABT_WINDOW) ! 711: sc->sc_abortcount = 0; ! 712: /* ! 713: * If we see an abort after "idle" time, count it; ! 714: * record when the first abort escape arrived. ! 715: */ ! 716: if (time.tv_sec >= sc->sc_lasttime + ABT_IDLE) { ! 717: if (++sc->sc_abortcount == 1) ! 718: sc->sc_starttime = time.tv_sec; ! 719: if (sc->sc_abortcount >= ABT_COUNT) { ! 720: slclose(tp); ! 721: return; ! 722: } ! 723: } ! 724: } else ! 725: sc->sc_abortcount = 0; ! 726: sc->sc_lasttime = time.tv_sec; ! 727: } ! 728: ! 729: switch (c) { ! 730: ! 731: case TRANS_FRAME_ESCAPE: ! 732: if (sc->sc_escape) ! 733: c = FRAME_ESCAPE; ! 734: break; ! 735: ! 736: case TRANS_FRAME_END: ! 737: if (sc->sc_escape) ! 738: c = FRAME_END; ! 739: break; ! 740: ! 741: case FRAME_ESCAPE: ! 742: sc->sc_escape = 1; ! 743: return; ! 744: ! 745: case FRAME_END: ! 746: if(sc->sc_flags & SC_ERROR) { ! 747: sc->sc_flags &= ~SC_ERROR; ! 748: goto newpack; ! 749: } ! 750: len = sc->sc_mp - sc->sc_buf; ! 751: if (len < 3) ! 752: /* less than min length packet - ignore */ ! 753: goto newpack; ! 754: ! 755: #if NBPFILTER > 0 ! 756: if (sc->sc_bpf) { ! 757: /* ! 758: * Save the compressed header, so we ! 759: * can tack it on later. Note that we ! 760: * will end up copying garbage in some ! 761: * cases but this is okay. We remember ! 762: * where the buffer started so we can ! 763: * compute the new header length. ! 764: */ ! 765: bcopy(sc->sc_buf, chdr, CHDR_LEN); ! 766: } ! 767: #endif ! 768: ! 769: if ((c = (*sc->sc_buf & 0xf0)) != (IPVERSION << 4)) { ! 770: if (c & 0x80) ! 771: c = TYPE_COMPRESSED_TCP; ! 772: else if (c == TYPE_UNCOMPRESSED_TCP) ! 773: *sc->sc_buf &= 0x4f; /* XXX */ ! 774: /* ! 775: * We've got something that's not an IP packet. ! 776: * If compression is enabled, try to decompress it. ! 777: * Otherwise, if `auto-enable' compression is on and ! 778: * it's a reasonable packet, decompress it and then ! 779: * enable compression. Otherwise, drop it. ! 780: */ ! 781: if (sc->sc_if.if_flags & SC_COMPRESS) { ! 782: len = sl_uncompress_tcp(&sc->sc_buf, len, ! 783: (u_int)c, &sc->sc_comp); ! 784: if (len <= 0) ! 785: goto error; ! 786: } else if ((sc->sc_if.if_flags & SC_AUTOCOMP) && ! 787: c == TYPE_UNCOMPRESSED_TCP && len >= 40) { ! 788: len = sl_uncompress_tcp(&sc->sc_buf, len, ! 789: (u_int)c, &sc->sc_comp); ! 790: if (len <= 0) ! 791: goto error; ! 792: sc->sc_if.if_flags |= SC_COMPRESS; ! 793: } else ! 794: goto error; ! 795: } ! 796: #if NBPFILTER > 0 ! 797: if (sc->sc_bpf) { ! 798: /* ! 799: * Put the SLIP pseudo-"link header" in place. ! 800: * We couldn't do this any earlier since ! 801: * decompression probably moved the buffer ! 802: * pointer. Then, invoke BPF. ! 803: */ ! 804: register u_char *hp = sc->sc_buf - SLIP_HDRLEN; ! 805: ! 806: hp[SLX_DIR] = SLIPDIR_IN; ! 807: bcopy(chdr, &hp[SLX_CHDR], CHDR_LEN); ! 808: BPF_TAP(sc->sc_bpf, hp, len + SLIP_HDRLEN); ! 809: } ! 810: #endif ! 811: m = sl_btom(sc, len); ! 812: if (m == NULL) ! 813: goto error; ! 814: ! 815: sc->sc_if.if_ipackets++; ! 816: sc->sc_if.if_lastchange = time; ! 817: s = splimp(); ! 818: if (IF_QFULL(&ipintrq)) { ! 819: IF_DROP(&ipintrq); ! 820: sc->sc_if.if_ierrors++; ! 821: sc->sc_if.if_iqdrops++; ! 822: m_freem(m); ! 823: } else { ! 824: IF_ENQUEUE(&ipintrq, m); ! 825: schednetisr(NETISR_IP); ! 826: } ! 827: splx(s); ! 828: goto newpack; ! 829: } ! 830: if (sc->sc_mp < sc->sc_ep) { ! 831: *sc->sc_mp++ = c; ! 832: sc->sc_escape = 0; ! 833: return; ! 834: } ! 835: ! 836: /* can't put lower; would miss an extra frame */ ! 837: sc->sc_flags |= SC_ERROR; ! 838: ! 839: error: ! 840: sc->sc_if.if_ierrors++; ! 841: newpack: ! 842: sc->sc_mp = sc->sc_buf = sc->sc_ep - SLMAX; ! 843: sc->sc_escape = 0; ! 844: } ! 845: ! 846: /* ! 847: * Process an ioctl request. ! 848: */ ! 849: int ! 850: slioctl(ifp, cmd, data) ! 851: register struct ifnet *ifp; ! 852: u_long cmd; ! 853: caddr_t data; ! 854: { ! 855: register struct ifaddr *ifa = (struct ifaddr *)data; ! 856: register struct ifreq *ifr; ! 857: register int s = splimp(), error = 0; ! 858: ! 859: switch (cmd) { ! 860: ! 861: case SIOCSIFADDR: ! 862: if (ifa->ifa_addr->sa_family == AF_INET) ! 863: ifp->if_flags |= IFF_UP; ! 864: else ! 865: error = EAFNOSUPPORT; ! 866: break; ! 867: ! 868: case SIOCSIFDSTADDR: ! 869: if (ifa->ifa_addr->sa_family != AF_INET) ! 870: error = EAFNOSUPPORT; ! 871: break; ! 872: ! 873: case SIOCADDMULTI: ! 874: case SIOCDELMULTI: ! 875: ifr = (struct ifreq *)data; ! 876: if (ifr == 0) { ! 877: error = EAFNOSUPPORT; /* XXX */ ! 878: break; ! 879: } ! 880: switch (ifr->ifr_addr.sa_family) { ! 881: ! 882: #if INET ! 883: case AF_INET: ! 884: break; ! 885: #endif ! 886: ! 887: default: ! 888: error = EAFNOSUPPORT; ! 889: break; ! 890: } ! 891: break; ! 892: ! 893: default: ! 894: error = EINVAL; ! 895: } ! 896: splx(s); ! 897: return (error); ! 898: } ! 899: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.