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