|
|
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: /* ! 23: * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous ! 24: * tty devices. ! 25: * ! 26: * Copyright (c) 1989 Carnegie Mellon University. ! 27: * All rights reserved. ! 28: * ! 29: * Redistribution and use in source and binary forms are permitted ! 30: * provided that the above copyright notice and this paragraph are ! 31: * duplicated in all such forms and that any documentation, ! 32: * advertising materials, and other materials related to such ! 33: * distribution and use acknowledge that the software was developed ! 34: * by Carnegie Mellon University. The name of the ! 35: * University may not be used to endorse or promote products derived ! 36: * from this software without specific prior written permission. ! 37: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 38: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 39: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 40: * ! 41: * Drew D. Perkins ! 42: * Carnegie Mellon University ! 43: * 4910 Forbes Ave. ! 44: * Pittsburgh, PA 15213 ! 45: * (412) 268-8576 ! 46: * [email protected] ! 47: * ! 48: * Based on: ! 49: * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 ! 50: * ! 51: * Copyright (c) 1987 Regents of the University of California. ! 52: * All rights reserved. ! 53: * ! 54: * Redistribution and use in source and binary forms are permitted ! 55: * provided that the above copyright notice and this paragraph are ! 56: * duplicated in all such forms and that any documentation, ! 57: * advertising materials, and other materials related to such ! 58: * distribution and use acknowledge that the software was developed ! 59: * by the University of California, Berkeley. The name of the ! 60: * University may not be used to endorse or promote products derived ! 61: * from this software without specific prior written permission. ! 62: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 63: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 64: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 65: * ! 66: * Serial Line interface ! 67: * ! 68: * Rick Adams ! 69: * Center for Seismic Studies ! 70: * 1300 N 17th Street, Suite 1450 ! 71: * Arlington, Virginia 22209 ! 72: * (703)276-7900 ! 73: * [email protected] ! 74: * seismo!rick ! 75: * ! 76: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris). ! 77: * Converted to 4.3BSD Beta by Chris Torek. ! 78: * Other changes made at Berkeley, based in part on code by Kirk Smith. ! 79: * ! 80: * Converted to 4.3BSD+ 386BSD by Brad Parker ([email protected]) ! 81: * Added VJ tcp header compression; more unified ioctls ! 82: * ! 83: * Extensively modified by Paul Mackerras ([email protected]). ! 84: * Cleaned up a lot of the mbuf-related code to fix bugs that ! 85: * caused system crashes and packet corruption. Changed pppstart ! 86: * so that it doesn't just give up with a "collision" if the whole ! 87: * packet doesn't fit in the output ring buffer. ! 88: * ! 89: * Added priority queueing for interactive IP packets, following ! 90: * the model of if_sl.c, plus hooks for bpf. ! 91: * Paul Mackerras ([email protected]). ! 92: */ ! 93: ! 94: ! 95: #include "ppp.h" ! 96: #if NPPP > 0 ! 97: ! 98: #include "opt_ppp.h" /* XXX for ppp_defs.h */ ! 99: ! 100: #define VJC /* XXX for ppp_defs.h */ ! 101: ! 102: #include <sys/param.h> ! 103: #include <sys/systm.h> ! 104: #include <sys/proc.h> ! 105: #include <sys/mbuf.h> ! 106: #include <sys/dkstat.h> ! 107: #include <sys/socket.h> ! 108: #include <sys/fcntl.h> ! 109: #include <sys/tty.h> ! 110: #include <sys/conf.h> ! 111: #include <sys/uio.h> ! 112: #include <sys/vnode.h> ! 113: ! 114: #ifdef __i386__ ! 115: #include <i386/isa/intr_machdep.h> ! 116: #endif ! 117: ! 118: #if PPP_FILTER ! 119: #include <net/bpf.h> ! 120: #endif ! 121: #include <net/if_ppp.h> ! 122: #include <net/if_pppvar.h> ! 123: ! 124: static int pppopen __P((dev_t dev, struct tty *tp)); ! 125: static int pppclose __P((struct tty *tp, int flag)); ! 126: static int pppread __P((struct tty *tp, struct uio *uio, int flag)); ! 127: static int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); ! 128: static int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag, ! 129: struct proc *)); ! 130: static int pppinput __P((int c, struct tty *tp)); ! 131: static int pppstart __P((struct tty *tp)); ! 132: ! 133: static u_short pppfcs __P((u_short fcs, u_char *cp, int len)); ! 134: static void pppasyncstart __P((struct ppp_softc *)); ! 135: static void pppasyncctlp __P((struct ppp_softc *)); ! 136: static void pppasyncrelinq __P((struct ppp_softc *)); ! 137: static void pppasyncsetmtu __P((struct ppp_softc *)); ! 138: static void ppp_timeout __P((void *)); ! 139: static void pppgetm __P((struct ppp_softc *sc)); ! 140: static void ppplogchar __P((struct ppp_softc *, int)); ! 141: ! 142: /* XXX called from if_ppp.c - layering violation */ ! 143: void pppasyncattach __P((void *)); ! 144: ! 145: /* ! 146: * Some useful mbuf macros not in mbuf.h. ! 147: */ ! 148: #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) ! 149: ! 150: #define M_DATASTART(m) \ ! 151: (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ ! 152: (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) ! 153: ! 154: #define M_DATASIZE(m) \ ! 155: (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ ! 156: (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) ! 157: ! 158: /* ! 159: * Does c need to be escaped? ! 160: */ ! 161: #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) ! 162: ! 163: /* ! 164: * Procedures for using an async tty interface for PPP. ! 165: */ ! 166: ! 167: /* This is a FreeBSD-2.X kernel. */ ! 168: #define CCOUNT(q) ((q)->c_cc) ! 169: #define PPP_LOWAT 100 /* Process more output when < LOWAT on queue */ ! 170: #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ ! 171: ! 172: /* ! 173: * Define the PPP line discipline. ! 174: */ ! 175: ! 176: static struct linesw pppdisc = { ! 177: pppopen, pppclose, pppread, pppwrite, ! 178: ppptioctl, pppinput, pppstart, ttymodem, ! 179: PPP_FLAG ! 180: }; ! 181: ! 182: void ! 183: pppasyncattach(dummy) ! 184: void *dummy; ! 185: { ! 186: #ifdef __i386__ ! 187: int s; ! 188: ! 189: s = splhigh(); ! 190: ! 191: /* ! 192: * Make sure that the soft net "engine" cannot run while spltty code is ! 193: * active. The if_ppp.c code can walk down into b_to_q etc, and it is ! 194: * bad if the tty system was in the middle of another b_to_q... ! 195: */ ! 196: tty_imask |= softnet_imask; /* spltty() block spl[soft]net() */ ! 197: net_imask |= softtty_imask; /* splimp() block splsofttty() */ ! 198: net_imask |= tty_imask; /* splimp() block spltty() */ ! 199: update_intr_masks(); ! 200: ! 201: splx(s); ! 202: if ( bootverbose ) ! 203: printf("new masks: bio %x, tty %x, net %x\n", ! 204: bio_imask, tty_imask, net_imask); ! 205: #endif ! 206: ! 207: /* register line discipline */ ! 208: linesw[PPPDISC] = pppdisc; ! 209: } ! 210: ! 211: /* ! 212: * Line specific open routine for async tty devices. ! 213: * Attach the given tty to the first available ppp unit. ! 214: * Called from device open routine or ttioctl() at >= splsofttty() ! 215: */ ! 216: /* ARGSUSED */ ! 217: static int ! 218: pppopen(dev, tp) ! 219: dev_t dev; ! 220: register struct tty *tp; ! 221: { ! 222: struct proc *p = current_proc(); /* XXX */ ! 223: register struct ppp_softc *sc; ! 224: int error, s; ! 225: ! 226: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 227: return (error); ! 228: ! 229: s = spltty(); ! 230: ! 231: if (tp->t_line == PPPDISC) { ! 232: sc = (struct ppp_softc *) tp->t_sc; ! 233: if (sc != NULL && sc->sc_devp == (void *) tp) { ! 234: splx(s); ! 235: return (0); ! 236: } ! 237: } ! 238: ! 239: if ((sc = pppalloc(p->p_pid)) == NULL) { ! 240: splx(s); ! 241: return ENXIO; ! 242: } ! 243: ! 244: if (sc->sc_relinq) ! 245: (*sc->sc_relinq)(sc); /* get previous owner to relinquish the unit */ ! 246: ! 247: sc->sc_ilen = 0; ! 248: sc->sc_m = NULL; ! 249: bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); ! 250: sc->sc_asyncmap[0] = 0xffffffff; ! 251: sc->sc_asyncmap[3] = 0x60000000; ! 252: sc->sc_rasyncmap = 0; ! 253: sc->sc_devp = (void *) tp; ! 254: sc->sc_start = pppasyncstart; ! 255: sc->sc_ctlp = pppasyncctlp; ! 256: sc->sc_relinq = pppasyncrelinq; ! 257: sc->sc_setmtu = pppasyncsetmtu; ! 258: sc->sc_outm = NULL; ! 259: pppgetm(sc); ! 260: sc->sc_if.if_flags |= IFF_RUNNING; ! 261: getmicrotime(&sc->sc_if.if_lastchange); ! 262: sc->sc_if.if_baudrate = tp->t_ospeed; ! 263: ! 264: tp->t_sc = (caddr_t) sc; ! 265: ttyflush(tp, FREAD | FWRITE); ! 266: ! 267: /* ! 268: * Pre-allocate cblocks to the "just right" amount. The 1 byte t_canq ! 269: * allocation helps avoid the need for select and/or FIONREAD. ! 270: * We also pass 1 byte tokens through t_canq... ! 271: */ ! 272: clist_alloc_cblocks(&tp->t_canq, 1, 1); ! 273: clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT, ! 274: sc->sc_if.if_mtu + PPP_HIWAT); ! 275: clist_alloc_cblocks(&tp->t_rawq, 0, 0); ! 276: ! 277: splx(s); ! 278: ! 279: return (0); ! 280: } ! 281: ! 282: /* ! 283: * Line specific close routine, called from device close routine ! 284: * and from ttioctl at >= splsofttty(). ! 285: * Detach the tty from the ppp unit. ! 286: * Mimics part of ttyclose(). ! 287: */ ! 288: static int ! 289: pppclose(tp, flag) ! 290: struct tty *tp; ! 291: int flag; ! 292: { ! 293: register struct ppp_softc *sc; ! 294: int s; ! 295: ! 296: s = spltty(); ! 297: ttyflush(tp, FREAD | FWRITE); ! 298: clist_free_cblocks(&tp->t_canq); ! 299: clist_free_cblocks(&tp->t_outq); ! 300: tp->t_line = 0; ! 301: sc = (struct ppp_softc *) tp->t_sc; ! 302: if (sc != NULL) { ! 303: tp->t_sc = NULL; ! 304: if (tp == (struct tty *) sc->sc_devp) { ! 305: pppasyncrelinq(sc); ! 306: pppdealloc(sc); ! 307: } ! 308: } ! 309: splx(s); ! 310: return 0; ! 311: } ! 312: ! 313: /* ! 314: * Relinquish the interface unit to another device. ! 315: */ ! 316: static void ! 317: pppasyncrelinq(sc) ! 318: struct ppp_softc *sc; ! 319: { ! 320: int s; ! 321: ! 322: s = spltty(); ! 323: if (sc->sc_outm) { ! 324: m_freem(sc->sc_outm); ! 325: sc->sc_outm = NULL; ! 326: } ! 327: if (sc->sc_m) { ! 328: m_freem(sc->sc_m); ! 329: sc->sc_m = NULL; ! 330: } ! 331: if (sc->sc_flags & SC_TIMEOUT) { ! 332: untimeout(ppp_timeout, (void *) sc, sc->sc_ch); ! 333: sc->sc_flags &= ~SC_TIMEOUT; ! 334: } ! 335: splx(s); ! 336: } ! 337: ! 338: /* ! 339: * This gets called from the upper layer to notify a mtu change ! 340: */ ! 341: static void ! 342: pppasyncsetmtu(sc) ! 343: register struct ppp_softc *sc; ! 344: { ! 345: register struct tty *tp = (struct tty *) sc->sc_devp; ! 346: int s; ! 347: ! 348: s = spltty(); ! 349: if (tp != NULL) ! 350: clist_alloc_cblocks(&tp->t_outq, sc->sc_if.if_mtu + PPP_HIWAT, ! 351: sc->sc_if.if_mtu + PPP_HIWAT); ! 352: splx(s); ! 353: } ! 354: ! 355: /* ! 356: * Line specific (tty) read routine. ! 357: * called at zero spl from the device driver in the response to user-level ! 358: * reads on the tty file descriptor (ie: pppd). ! 359: */ ! 360: static int ! 361: pppread(tp, uio, flag) ! 362: register struct tty *tp; ! 363: struct uio *uio; ! 364: int flag; ! 365: { ! 366: register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; ! 367: struct mbuf *m, *m0; ! 368: register int s; ! 369: int error = 0; ! 370: ! 371: if (sc == NULL) ! 372: return 0; ! 373: /* ! 374: * Loop waiting for input, checking that nothing disasterous ! 375: * happens in the meantime. ! 376: */ ! 377: s = spltty(); ! 378: for (;;) { ! 379: if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) { ! 380: splx(s); ! 381: return 0; ! 382: } ! 383: if (sc->sc_inq.ifq_head != NULL) ! 384: break; ! 385: if ((tp->t_state & TS_CONNECTED) == 0) { ! 386: splx(s); ! 387: return 0; /* end of file */ ! 388: } ! 389: if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { ! 390: splx(s); ! 391: return (EWOULDBLOCK); ! 392: } ! 393: error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0); ! 394: if (error) { ! 395: splx(s); ! 396: return error; ! 397: } ! 398: } ! 399: ! 400: /* Pull place-holder byte out of canonical queue */ ! 401: getc(&tp->t_canq); ! 402: ! 403: /* Get the packet from the input queue */ ! 404: IF_DEQUEUE(&sc->sc_inq, m0); ! 405: splx(s); ! 406: ! 407: for (m = m0; m && uio->uio_resid; m = m->m_next) ! 408: if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0) ! 409: break; ! 410: m_freem(m0); ! 411: return (error); ! 412: } ! 413: ! 414: /* ! 415: * Line specific (tty) write routine. ! 416: * called at zero spl from the device driver in the response to user-level ! 417: * writes on the tty file descriptor (ie: pppd). ! 418: */ ! 419: static int ! 420: pppwrite(tp, uio, flag) ! 421: register struct tty *tp; ! 422: struct uio *uio; ! 423: int flag; ! 424: { ! 425: register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; ! 426: struct mbuf *m, *m0, **mp; ! 427: struct sockaddr dst; ! 428: int len, error, s; ! 429: ! 430: if ((tp->t_state & TS_CONNECTED) == 0) ! 431: return 0; /* wrote 0 bytes */ ! 432: if (tp->t_line != PPPDISC) ! 433: return (EINVAL); ! 434: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 435: return EIO; ! 436: if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN || ! 437: uio->uio_resid < PPP_HDRLEN) ! 438: return (EMSGSIZE); ! 439: ! 440: s = spltty(); ! 441: for (mp = &m0; uio->uio_resid; mp = &m->m_next) { ! 442: MGET(m, M_WAIT, MT_DATA); ! 443: if ((*mp = m) == NULL) { ! 444: m_freem(m0); ! 445: splx(s); ! 446: return (ENOBUFS); ! 447: } ! 448: m->m_len = 0; ! 449: if (uio->uio_resid >= MCLBYTES / 2) ! 450: MCLGET(m, M_DONTWAIT); ! 451: len = M_TRAILINGSPACE(m); ! 452: if (len > uio->uio_resid) ! 453: len = uio->uio_resid; ! 454: if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) { ! 455: m_freem(m0); ! 456: splx(s); ! 457: return (error); ! 458: } ! 459: m->m_len = len; ! 460: } ! 461: dst.sa_family = AF_UNSPEC; ! 462: bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN); ! 463: m0->m_data += PPP_HDRLEN; ! 464: m0->m_len -= PPP_HDRLEN; ! 465: ! 466: /* call the upper layer to "transmit" it... */ ! 467: error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0); ! 468: splx(s); ! 469: return (error); ! 470: } ! 471: ! 472: /* ! 473: * Line specific (tty) ioctl routine. ! 474: * This discipline requires that tty device drivers call ! 475: * the line specific l_ioctl routine from their ioctl routines. ! 476: */ ! 477: /* ARGSUSED */ ! 478: static int ! 479: ppptioctl(tp, cmd, data, flag, p) ! 480: struct tty *tp; ! 481: u_long cmd; ! 482: caddr_t data; ! 483: int flag; ! 484: struct proc *p; ! 485: { ! 486: struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; ! 487: int error, s; ! 488: ! 489: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 490: return (ENOIOCTL); ! 491: ! 492: error = 0; ! 493: switch (cmd) { ! 494: case PPPIOCSASYNCMAP: ! 495: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 496: break; ! 497: sc->sc_asyncmap[0] = *(u_int *)data; ! 498: break; ! 499: ! 500: case PPPIOCGASYNCMAP: ! 501: *(u_int *)data = sc->sc_asyncmap[0]; ! 502: break; ! 503: ! 504: case PPPIOCSRASYNCMAP: ! 505: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 506: break; ! 507: sc->sc_rasyncmap = *(u_int *)data; ! 508: break; ! 509: ! 510: case PPPIOCGRASYNCMAP: ! 511: *(u_int *)data = sc->sc_rasyncmap; ! 512: break; ! 513: ! 514: case PPPIOCSXASYNCMAP: ! 515: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 516: break; ! 517: s = spltty(); ! 518: bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); ! 519: sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ ! 520: sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ ! 521: sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ ! 522: splx(s); ! 523: break; ! 524: ! 525: case PPPIOCGXASYNCMAP: ! 526: bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); ! 527: break; ! 528: ! 529: default: ! 530: error = pppioctl(sc, cmd, data, flag, p); ! 531: if (error == 0 && cmd == PPPIOCSMRU) ! 532: pppgetm(sc); ! 533: } ! 534: ! 535: return error; ! 536: } ! 537: ! 538: /* ! 539: * FCS lookup table as calculated by genfcstab. ! 540: */ ! 541: static u_short fcstab[256] = { ! 542: 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, ! 543: 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, ! 544: 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, ! 545: 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, ! 546: 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, ! 547: 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, ! 548: 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, ! 549: 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, ! 550: 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, ! 551: 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, ! 552: 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, ! 553: 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, ! 554: 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, ! 555: 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, ! 556: 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, ! 557: 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, ! 558: 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, ! 559: 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, ! 560: 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, ! 561: 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, ! 562: 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, ! 563: 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, ! 564: 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, ! 565: 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, ! 566: 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, ! 567: 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, ! 568: 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, ! 569: 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, ! 570: 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, ! 571: 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, ! 572: 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, ! 573: 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 ! 574: }; ! 575: ! 576: /* ! 577: * Calculate a new FCS given the current FCS and the new data. ! 578: */ ! 579: static u_short ! 580: pppfcs(u_short fcs, u_char *cp, int len) ! 581: { ! 582: while (len--) ! 583: fcs = PPP_FCS(fcs, *cp++); ! 584: return (fcs); ! 585: } ! 586: ! 587: /* ! 588: * This gets called at splsoftnet from if_ppp.c at various times ! 589: * when there is data ready to be sent. ! 590: */ ! 591: static void ! 592: pppasyncstart(sc) ! 593: register struct ppp_softc *sc; ! 594: { ! 595: register struct tty *tp = (struct tty *) sc->sc_devp; ! 596: register struct mbuf *m; ! 597: register int len; ! 598: register u_char *start, *stop, *cp; ! 599: int n, ndone, done, idle; ! 600: struct mbuf *m2; ! 601: int s; ! 602: ! 603: idle = 0; ! 604: /* XXX assumes atomic access to *tp although we're not at spltty(). */ ! 605: while (CCOUNT(&tp->t_outq) < PPP_HIWAT) { ! 606: /* ! 607: * See if we have an existing packet partly sent. ! 608: * If not, get a new packet and start sending it. ! 609: */ ! 610: m = sc->sc_outm; ! 611: if (m == NULL) { ! 612: /* ! 613: * Get another packet to be sent. ! 614: */ ! 615: m = ppp_dequeue(sc); ! 616: if (m == NULL) { ! 617: idle = 1; ! 618: break; ! 619: } ! 620: ! 621: /* ! 622: * The extra PPP_FLAG will start up a new packet, and thus ! 623: * will flush any accumulated garbage. We do this whenever ! 624: * the line may have been idle for some time. ! 625: */ ! 626: /* XXX as above. */ ! 627: if (CCOUNT(&tp->t_outq) == 0) { ! 628: ++sc->sc_stats.ppp_obytes; ! 629: (void) putc(PPP_FLAG, &tp->t_outq); ! 630: } ! 631: ! 632: /* Calculate the FCS for the first mbuf's worth. */ ! 633: sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); ! 634: getmicrotime(&sc->sc_if.if_lastchange); ! 635: } ! 636: ! 637: for (;;) { ! 638: start = mtod(m, u_char *); ! 639: len = m->m_len; ! 640: stop = start + len; ! 641: while (len > 0) { ! 642: /* ! 643: * Find out how many bytes in the string we can ! 644: * handle without doing something special. ! 645: */ ! 646: for (cp = start; cp < stop; cp++) ! 647: if (ESCAPE_P(*cp)) ! 648: break; ! 649: n = cp - start; ! 650: if (n) { ! 651: /* NetBSD (0.9 or later), 4.3-Reno or similar. */ ! 652: ndone = n - b_to_q(start, n, &tp->t_outq); ! 653: len -= ndone; ! 654: start += ndone; ! 655: sc->sc_stats.ppp_obytes += ndone; ! 656: ! 657: if (ndone < n) ! 658: break; /* packet doesn't fit */ ! 659: } ! 660: /* ! 661: * If there are characters left in the mbuf, ! 662: * the first one must be special. ! 663: * Put it out in a different form. ! 664: */ ! 665: if (len) { ! 666: s = spltty(); ! 667: if (putc(PPP_ESCAPE, &tp->t_outq)) { ! 668: splx(s); ! 669: break; ! 670: } ! 671: if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { ! 672: (void) unputc(&tp->t_outq); ! 673: splx(s); ! 674: break; ! 675: } ! 676: splx(s); ! 677: sc->sc_stats.ppp_obytes += 2; ! 678: start++; ! 679: len--; ! 680: } ! 681: } ! 682: ! 683: /* ! 684: * If we didn't empty this mbuf, remember where we're up to. ! 685: * If we emptied the last mbuf, try to add the FCS and closing ! 686: * flag, and if we can't, leave sc_outm pointing to m, but with ! 687: * m->m_len == 0, to remind us to output the FCS and flag later. ! 688: */ ! 689: done = len == 0; ! 690: if (done && m->m_next == NULL) { ! 691: u_char *p, *q; ! 692: int c; ! 693: u_char endseq[8]; ! 694: ! 695: /* ! 696: * We may have to escape the bytes in the FCS. ! 697: */ ! 698: p = endseq; ! 699: c = ~sc->sc_outfcs & 0xFF; ! 700: if (ESCAPE_P(c)) { ! 701: *p++ = PPP_ESCAPE; ! 702: *p++ = c ^ PPP_TRANS; ! 703: } else ! 704: *p++ = c; ! 705: c = (~sc->sc_outfcs >> 8) & 0xFF; ! 706: if (ESCAPE_P(c)) { ! 707: *p++ = PPP_ESCAPE; ! 708: *p++ = c ^ PPP_TRANS; ! 709: } else ! 710: *p++ = c; ! 711: *p++ = PPP_FLAG; ! 712: ! 713: /* ! 714: * Try to output the FCS and flag. If the bytes ! 715: * don't all fit, back out. ! 716: */ ! 717: s = spltty(); ! 718: for (q = endseq; q < p; ++q) ! 719: if (putc(*q, &tp->t_outq)) { ! 720: done = 0; ! 721: for (; q > endseq; --q) ! 722: unputc(&tp->t_outq); ! 723: break; ! 724: } ! 725: splx(s); ! 726: if (done) ! 727: sc->sc_stats.ppp_obytes += q - endseq; ! 728: } ! 729: ! 730: if (!done) { ! 731: /* remember where we got to */ ! 732: m->m_data = start; ! 733: m->m_len = len; ! 734: break; ! 735: } ! 736: ! 737: /* Finished with this mbuf; free it and move on. */ ! 738: MFREE(m, m2); ! 739: m = m2; ! 740: if (m == NULL) { ! 741: /* Finished a packet */ ! 742: break; ! 743: } ! 744: sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); ! 745: } ! 746: ! 747: /* ! 748: * If m == NULL, we have finished a packet. ! 749: * If m != NULL, we've either done as much work this time ! 750: * as we need to, or else we've filled up the output queue. ! 751: */ ! 752: sc->sc_outm = m; ! 753: if (m) ! 754: break; ! 755: } ! 756: ! 757: /* Call pppstart to start output again if necessary. */ ! 758: s = spltty(); ! 759: pppstart(tp); ! 760: ! 761: /* ! 762: * This timeout is needed for operation on a pseudo-tty, ! 763: * because the pty code doesn't call pppstart after it has ! 764: * drained the t_outq. ! 765: */ ! 766: if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) { ! 767: sc->sc_ch = timeout(ppp_timeout, (void *) sc, 1); ! 768: sc->sc_flags |= SC_TIMEOUT; ! 769: } ! 770: ! 771: splx(s); ! 772: } ! 773: ! 774: /* ! 775: * This gets called when a received packet is placed on ! 776: * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read(). ! 777: */ ! 778: static void ! 779: pppasyncctlp(sc) ! 780: struct ppp_softc *sc; ! 781: { ! 782: struct tty *tp; ! 783: int s; ! 784: ! 785: /* Put a placeholder byte in canq for ttselect()/ttnread(). */ ! 786: s = spltty(); ! 787: tp = (struct tty *) sc->sc_devp; ! 788: putc(0, &tp->t_canq); ! 789: ttwakeup(tp); ! 790: splx(s); ! 791: } ! 792: ! 793: /* ! 794: * Start output on async tty interface. If the transmit queue ! 795: * has drained sufficiently, arrange for pppasyncstart to be ! 796: * called later at splsoftnet. ! 797: * Called at spltty or higher. ! 798: */ ! 799: int ! 800: pppstart(tp) ! 801: register struct tty *tp; ! 802: { ! 803: register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; ! 804: ! 805: /* ! 806: * Call output process whether or not there is any output. ! 807: * We are being called in lieu of ttstart and must do what it would. ! 808: */ ! 809: if (tp->t_oproc != NULL) ! 810: (*tp->t_oproc)(tp); ! 811: ! 812: /* ! 813: * If the transmit queue has drained and the tty has not hung up ! 814: * or been disconnected from the ppp unit, then tell if_ppp.c that ! 815: * we need more output. ! 816: */ ! 817: if (CCOUNT(&tp->t_outq) < PPP_LOWAT ! 818: && !((tp->t_state & TS_CONNECTED) == 0) ! 819: && sc != NULL && tp == (struct tty *) sc->sc_devp) { ! 820: ppp_restart(sc); ! 821: } ! 822: ! 823: return 0; ! 824: } ! 825: ! 826: /* ! 827: * Timeout routine - try to start some more output. ! 828: */ ! 829: static void ! 830: ppp_timeout(x) ! 831: void *x; ! 832: { ! 833: struct ppp_softc *sc = (struct ppp_softc *) x; ! 834: struct tty *tp = (struct tty *) sc->sc_devp; ! 835: int s; ! 836: ! 837: s = spltty(); ! 838: sc->sc_flags &= ~SC_TIMEOUT; ! 839: pppstart(tp); ! 840: splx(s); ! 841: } ! 842: ! 843: /* ! 844: * Allocate enough mbuf to handle current MRU. ! 845: */ ! 846: static void ! 847: pppgetm(sc) ! 848: register struct ppp_softc *sc; ! 849: { ! 850: struct mbuf *m, **mp; ! 851: int len; ! 852: ! 853: mp = &sc->sc_m; ! 854: for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ ! 855: if ((m = *mp) == NULL) { ! 856: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 857: if (m == NULL) ! 858: break; ! 859: *mp = m; ! 860: MCLGET(m, M_DONTWAIT); ! 861: } ! 862: len -= M_DATASIZE(m); ! 863: mp = &m->m_next; ! 864: } ! 865: } ! 866: ! 867: /* ! 868: * tty interface receiver interrupt. ! 869: */ ! 870: static unsigned paritytab[8] = { ! 871: 0x96696996, 0x69969669, 0x69969669, 0x96696996, ! 872: 0x69969669, 0x96696996, 0x96696996, 0x69969669 ! 873: }; ! 874: ! 875: /* ! 876: * Called when character is available from device driver. ! 877: * Only guaranteed to be at splsofttty() or spltty() ! 878: * This is safe to be called while the upper half's netisr is preempted. ! 879: */ ! 880: static int ! 881: pppinput(c, tp) ! 882: int c; ! 883: register struct tty *tp; ! 884: { ! 885: register struct ppp_softc *sc; ! 886: struct mbuf *m; ! 887: int ilen, s; ! 888: ! 889: sc = (struct ppp_softc *) tp->t_sc; ! 890: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 891: return 0; ! 892: ! 893: ++tk_nin; ! 894: ++sc->sc_stats.ppp_ibytes; ! 895: ! 896: if ((tp->t_state & TS_CONNECTED) == 0) { ! 897: if (sc->sc_flags & SC_DEBUG) ! 898: printf("ppp%d: no carrier\n", sc->sc_if.if_unit); ! 899: goto flush; ! 900: } ! 901: ! 902: if (c & TTY_ERRORMASK) { ! 903: /* framing error or overrun on this char - abort packet */ ! 904: if (sc->sc_flags & SC_DEBUG) ! 905: printf("ppp%d: line error %x\n", sc->sc_if.if_unit, ! 906: c & TTY_ERRORMASK); ! 907: goto flush; ! 908: } ! 909: ! 910: c &= TTY_CHARMASK; ! 911: ! 912: /* ! 913: * Handle software flow control of output. ! 914: */ ! 915: if (tp->t_iflag & IXON) { ! 916: if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) { ! 917: if ((tp->t_state & TS_TTSTOP) == 0) { ! 918: tp->t_state |= TS_TTSTOP; ! 919: (*cdevsw[major(tp->t_dev)]->d_stop)(tp, 0); ! 920: } ! 921: return 0; ! 922: } ! 923: if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) { ! 924: tp->t_state &= ~TS_TTSTOP; ! 925: if (tp->t_oproc != NULL) ! 926: (*tp->t_oproc)(tp); ! 927: return 0; ! 928: } ! 929: } ! 930: ! 931: s = spltty(); ! 932: if (c & 0x80) ! 933: sc->sc_flags |= SC_RCV_B7_1; ! 934: else ! 935: sc->sc_flags |= SC_RCV_B7_0; ! 936: if (paritytab[c >> 5] & (1 << (c & 0x1F))) ! 937: sc->sc_flags |= SC_RCV_ODDP; ! 938: else ! 939: sc->sc_flags |= SC_RCV_EVNP; ! 940: splx(s); ! 941: ! 942: if (sc->sc_flags & SC_LOG_RAWIN) ! 943: ppplogchar(sc, c); ! 944: ! 945: if (c == PPP_FLAG) { ! 946: ilen = sc->sc_ilen; ! 947: sc->sc_ilen = 0; ! 948: ! 949: if (sc->sc_rawin_count > 0) ! 950: ppplogchar(sc, -1); ! 951: ! 952: /* ! 953: * If SC_ESCAPED is set, then we've seen the packet ! 954: * abort sequence "}~". ! 955: */ ! 956: if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) ! 957: || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) { ! 958: s = spltty(); ! 959: sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */ ! 960: if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ ! 961: if (sc->sc_flags & SC_DEBUG) ! 962: printf("ppp%d: bad fcs %x, pkt len %d\n", ! 963: sc->sc_if.if_unit, sc->sc_fcs, ilen); ! 964: sc->sc_if.if_ierrors++; ! 965: sc->sc_stats.ppp_ierrors++; ! 966: } else ! 967: sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); ! 968: splx(s); ! 969: return 0; ! 970: } ! 971: ! 972: if (ilen < PPP_HDRLEN + PPP_FCSLEN) { ! 973: if (ilen) { ! 974: if (sc->sc_flags & SC_DEBUG) ! 975: printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); ! 976: s = spltty(); ! 977: sc->sc_if.if_ierrors++; ! 978: sc->sc_stats.ppp_ierrors++; ! 979: sc->sc_flags |= SC_PKTLOST; ! 980: splx(s); ! 981: } ! 982: return 0; ! 983: } ! 984: ! 985: /* ! 986: * Remove FCS trailer. Somewhat painful... ! 987: */ ! 988: ilen -= 2; ! 989: if (--sc->sc_mc->m_len == 0) { ! 990: for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) ! 991: ; ! 992: sc->sc_mc = m; ! 993: } ! 994: sc->sc_mc->m_len--; ! 995: ! 996: /* excise this mbuf chain */ ! 997: m = sc->sc_m; ! 998: sc->sc_m = sc->sc_mc->m_next; ! 999: sc->sc_mc->m_next = NULL; ! 1000: ! 1001: ppppktin(sc, m, sc->sc_flags & SC_PKTLOST); ! 1002: if (sc->sc_flags & SC_PKTLOST) { ! 1003: s = spltty(); ! 1004: sc->sc_flags &= ~SC_PKTLOST; ! 1005: splx(s); ! 1006: } ! 1007: ! 1008: pppgetm(sc); ! 1009: return 0; ! 1010: } ! 1011: ! 1012: if (sc->sc_flags & SC_FLUSH) { ! 1013: if (sc->sc_flags & SC_LOG_FLUSH) ! 1014: ppplogchar(sc, c); ! 1015: return 0; ! 1016: } ! 1017: ! 1018: if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) ! 1019: return 0; ! 1020: ! 1021: s = spltty(); ! 1022: if (sc->sc_flags & SC_ESCAPED) { ! 1023: sc->sc_flags &= ~SC_ESCAPED; ! 1024: c ^= PPP_TRANS; ! 1025: } else if (c == PPP_ESCAPE) { ! 1026: sc->sc_flags |= SC_ESCAPED; ! 1027: splx(s); ! 1028: return 0; ! 1029: } ! 1030: splx(s); ! 1031: ! 1032: /* ! 1033: * Initialize buffer on first octet received. ! 1034: * First octet could be address or protocol (when compressing ! 1035: * address/control). ! 1036: * Second octet is control. ! 1037: * Third octet is first or second (when compressing protocol) ! 1038: * octet of protocol. ! 1039: * Fourth octet is second octet of protocol. ! 1040: */ ! 1041: if (sc->sc_ilen == 0) { ! 1042: /* reset the first input mbuf */ ! 1043: if (sc->sc_m == NULL) { ! 1044: pppgetm(sc); ! 1045: if (sc->sc_m == NULL) { ! 1046: if (sc->sc_flags & SC_DEBUG) ! 1047: printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit); ! 1048: goto flush; ! 1049: } ! 1050: } ! 1051: m = sc->sc_m; ! 1052: m->m_len = 0; ! 1053: m->m_data = M_DATASTART(sc->sc_m); ! 1054: sc->sc_mc = m; ! 1055: sc->sc_mp = mtod(m, char *); ! 1056: sc->sc_fcs = PPP_INITFCS; ! 1057: if (c != PPP_ALLSTATIONS) { ! 1058: if (sc->sc_flags & SC_REJ_COMP_AC) { ! 1059: if (sc->sc_flags & SC_DEBUG) ! 1060: printf("ppp%d: garbage received: 0x%x (need 0xFF)\n", ! 1061: sc->sc_if.if_unit, c); ! 1062: goto flush; ! 1063: } ! 1064: *sc->sc_mp++ = PPP_ALLSTATIONS; ! 1065: *sc->sc_mp++ = PPP_UI; ! 1066: sc->sc_ilen += 2; ! 1067: m->m_len += 2; ! 1068: } ! 1069: } ! 1070: if (sc->sc_ilen == 1 && c != PPP_UI) { ! 1071: if (sc->sc_flags & SC_DEBUG) ! 1072: printf("ppp%d: missing UI (0x3), got 0x%x\n", ! 1073: sc->sc_if.if_unit, c); ! 1074: goto flush; ! 1075: } ! 1076: if (sc->sc_ilen == 2 && (c & 1) == 1) { ! 1077: /* a compressed protocol */ ! 1078: *sc->sc_mp++ = 0; ! 1079: sc->sc_ilen++; ! 1080: sc->sc_mc->m_len++; ! 1081: } ! 1082: if (sc->sc_ilen == 3 && (c & 1) == 0) { ! 1083: if (sc->sc_flags & SC_DEBUG) ! 1084: printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, ! 1085: (sc->sc_mp[-1] << 8) + c); ! 1086: goto flush; ! 1087: } ! 1088: ! 1089: /* packet beyond configured mru? */ ! 1090: if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { ! 1091: if (sc->sc_flags & SC_DEBUG) ! 1092: printf("ppp%d: packet too big\n", sc->sc_if.if_unit); ! 1093: goto flush; ! 1094: } ! 1095: ! 1096: /* is this mbuf full? */ ! 1097: m = sc->sc_mc; ! 1098: if (M_TRAILINGSPACE(m) <= 0) { ! 1099: if (m->m_next == NULL) { ! 1100: pppgetm(sc); ! 1101: if (m->m_next == NULL) { ! 1102: if (sc->sc_flags & SC_DEBUG) ! 1103: printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); ! 1104: goto flush; ! 1105: } ! 1106: } ! 1107: sc->sc_mc = m = m->m_next; ! 1108: m->m_len = 0; ! 1109: m->m_data = M_DATASTART(m); ! 1110: sc->sc_mp = mtod(m, char *); ! 1111: } ! 1112: ! 1113: ++m->m_len; ! 1114: *sc->sc_mp++ = c; ! 1115: sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); ! 1116: return 0; ! 1117: ! 1118: flush: ! 1119: if (!(sc->sc_flags & SC_FLUSH)) { ! 1120: s = spltty(); ! 1121: sc->sc_if.if_ierrors++; ! 1122: sc->sc_stats.ppp_ierrors++; ! 1123: sc->sc_flags |= SC_FLUSH; ! 1124: splx(s); ! 1125: if (sc->sc_flags & SC_LOG_FLUSH) ! 1126: ppplogchar(sc, c); ! 1127: } ! 1128: return 0; ! 1129: } ! 1130: ! 1131: #define MAX_DUMP_BYTES 128 ! 1132: ! 1133: static void ! 1134: ppplogchar(sc, c) ! 1135: struct ppp_softc *sc; ! 1136: int c; ! 1137: { ! 1138: if (c >= 0) ! 1139: sc->sc_rawin[sc->sc_rawin_count++] = c; ! 1140: if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) ! 1141: || (c < 0 && sc->sc_rawin_count > 0)) { ! 1142: printf("ppp%d input: %*D", sc->sc_if.if_unit, ! 1143: sc->sc_rawin_count, sc->sc_rawin, " "); ! 1144: sc->sc_rawin_count = 0; ! 1145: } ! 1146: } ! 1147: ! 1148: #endif /* NPPP > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.