|
|
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: * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. ! 28: * ! 29: * Copyright (c) 1989 Carnegie Mellon University. ! 30: * All rights reserved. ! 31: * ! 32: * Redistribution and use in source and binary forms are permitted ! 33: * provided that the above copyright notice and this paragraph are ! 34: * duplicated in all such forms and that any documentation, ! 35: * advertising materials, and other materials related to such ! 36: * distribution and use acknowledge that the software was developed ! 37: * by Carnegie Mellon University. The name of the ! 38: * University may not be used to endorse or promote products derived ! 39: * from this software without specific prior written permission. ! 40: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 41: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 42: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 43: * ! 44: * Drew D. Perkins ! 45: * Carnegie Mellon University ! 46: * 4910 Forbes Ave. ! 47: * Pittsburgh, PA 15213 ! 48: * (412) 268-8576 ! 49: * [email protected] ! 50: * ! 51: * Based on: ! 52: * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 ! 53: * ! 54: * Copyright (c) 1987 Regents of the University of California. ! 55: * All rights reserved. ! 56: * ! 57: * Redistribution and use in source and binary forms are permitted ! 58: * provided that the above copyright notice and this paragraph are ! 59: * duplicated in all such forms and that any documentation, ! 60: * advertising materials, and other materials related to such ! 61: * distribution and use acknowledge that the software was developed ! 62: * by the University of California, Berkeley. The name of the ! 63: * University may not be used to endorse or promote products derived ! 64: * from this software without specific prior written permission. ! 65: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 66: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 67: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 68: * ! 69: * Serial Line interface ! 70: * ! 71: * Rick Adams ! 72: * Center for Seismic Studies ! 73: * 1300 N 17th Street, Suite 1450 ! 74: * Arlington, Virginia 22209 ! 75: * (703)276-7900 ! 76: * [email protected] ! 77: * seismo!rick ! 78: * ! 79: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris). ! 80: * Converted to 4.3BSD Beta by Chris Torek. ! 81: * Other changes made at Berkeley, based in part on code by Kirk Smith. ! 82: * ! 83: * Converted to 4.3BSD+ 386BSD by Brad Parker ([email protected]) ! 84: * Added VJ tcp header compression; more unified ioctls ! 85: * ! 86: * Extensively modified by Paul Mackerras ([email protected]). ! 87: * Cleaned up a lot of the mbuf-related code to fix bugs that ! 88: * caused system crashes and packet corruption. Changed pppstart ! 89: * so that it doesn't just give up with a collision if the whole ! 90: * packet doesn't fit in the output ring buffer. ! 91: * ! 92: * Added priority queueing for interactive IP packets, following ! 93: * the model of if_sl.c, plus hooks for bpf. ! 94: * Paul Mackerras ([email protected]). ! 95: */ ! 96: ! 97: /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ ! 98: ! 99: #include "ppp.h" ! 100: #if NPPP > 0 ! 101: ! 102: #define VJC ! 103: ! 104: #include <sys/param.h> ! 105: #include <sys/proc.h> ! 106: #include <sys/mbuf.h> ! 107: #include <sys/buf.h> ! 108: #include <sys/dkstat.h> ! 109: #include <sys/socket.h> ! 110: #include <sys/ioctl.h> ! 111: #include <sys/file.h> ! 112: #include <sys/tty.h> ! 113: #include <sys/kernel.h> ! 114: #include <sys/conf.h> ! 115: #include <sys/vnode.h> ! 116: ! 117: #include <net/if.h> ! 118: #include <net/if_types.h> ! 119: #include <net/netisr.h> ! 120: #include <net/route.h> ! 121: ! 122: #if INET ! 123: #include <netinet/in.h> ! 124: #include <netinet/in_systm.h> ! 125: #include <netinet/in_var.h> ! 126: #include <netinet/ip.h> ! 127: #endif ! 128: ! 129: #include "bpfilter.h" ! 130: #if NBPFILTER > 0 ! 131: #include <sys/time.h> ! 132: #include <net/bpf.h> ! 133: #endif ! 134: ! 135: #ifdef VJC ! 136: #include <net/slcompress.h> ! 137: #define HDROFF MAX_HDR ! 138: /* HDROFF should really be 128, but other parts of the system will ! 139: panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */ ! 140: ! 141: #else ! 142: #define HDROFF (0) ! 143: #endif ! 144: ! 145: #include <net/if_ppp.h> ! 146: #include <machine/cpu.h> ! 147: ! 148: #define CCOUNT(q) ((q)->c_cc) ! 149: ! 150: #define PPP_HIWAT 400 /* Don't start a new packet if HIWAT on que */ ! 151: ! 152: struct ppp_softc ppp_softc[NPPP]; ! 153: ! 154: void pppattach __P((void)); ! 155: int pppopen __P((dev_t dev, struct tty *tp)); ! 156: void pppclose __P((struct tty *tp, int flag)); ! 157: int pppread __P((struct tty *tp, struct uio *uio, int flag)); ! 158: int pppwrite __P((struct tty *tp, struct uio *uio, int flag)); ! 159: int ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag, ! 160: struct proc *)); ! 161: int pppoutput __P((struct ifnet *ifp, struct mbuf *m0, ! 162: struct sockaddr *dst, struct rtentry *rtp)); ! 163: void pppinput __P((int c, struct tty *tp)); ! 164: int pppioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); ! 165: void pppstart __P((struct tty *tp)); ! 166: ! 167: static int pppasyncstart __P((struct ppp_softc *)); ! 168: static u_int16_t pppfcs __P((u_int fcs, u_char *cp, int len)); ! 169: static int pppgetm __P((struct ppp_softc *sc)); ! 170: static void pppdumpm __P((struct mbuf *m0, int pktlen)); ! 171: static void pppdumpb __P((u_char *b, int l)); ! 172: static void ppplogchar __P((struct ppp_softc *, int)); ! 173: ! 174: /* ! 175: * Some useful mbuf macros not in mbuf.h. ! 176: */ ! 177: #define M_DATASTART(m) \ ! 178: ((m)->m_flags & M_EXT ? (m)->m_ext.ext_buf : \ ! 179: (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) ! 180: ! 181: #define M_DATASIZE(m) \ ! 182: ((m)->m_flags & M_EXT ? (m)->m_ext.ext_size : \ ! 183: (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) ! 184: ! 185: /* ! 186: * The following disgusting hack gets around the problem that IP TOS ! 187: * can't be set yet. We want to put "interactive" traffic on a high ! 188: * priority queue. To decide if traffic is interactive, we check that ! 189: * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control. ! 190: */ ! 191: static u_int16_t interactive_ports[8] = { ! 192: 0, 513, 0, 0, ! 193: 0, 21, 0, 23, ! 194: }; ! 195: #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) ! 196: ! 197: /* ! 198: * Does c need to be escaped? ! 199: */ ! 200: #define ESCAPE_P(c) (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F))) ! 201: ! 202: /* ! 203: * Called from boot code to establish ppp interfaces. ! 204: */ ! 205: void ! 206: pppattach() ! 207: { ! 208: register struct ppp_softc *sc; ! 209: register int i = 0; ! 210: ! 211: for (sc = ppp_softc; i < NPPP; sc++) { ! 212: sc->sc_if.if_name = "ppp"; ! 213: sc->sc_if.if_unit = i++; ! 214: sc->sc_if.if_mtu = PPP_MTU; ! 215: sc->sc_if.if_flags = IFF_POINTOPOINT; ! 216: sc->sc_if.if_type = IFT_PPP; ! 217: sc->sc_if.if_hdrlen = PPP_HDRLEN; ! 218: sc->sc_if.if_ioctl = pppioctl; ! 219: sc->sc_if.if_output = pppoutput; ! 220: sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; ! 221: sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; ! 222: sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; ! 223: if_attach(&sc->sc_if); ! 224: #if NBPFILTER > 0 ! 225: bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN); ! 226: #endif ! 227: } ! 228: } ! 229: ! 230: /* ! 231: * Allocate a ppp interface unit and initialize it. ! 232: */ ! 233: struct ppp_softc * ! 234: pppalloc(pid) ! 235: pid_t pid; ! 236: { ! 237: int nppp; ! 238: struct ppp_softc *sc; ! 239: ! 240: for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) ! 241: if (sc->sc_xfer == pid) { ! 242: sc->sc_xfer = 0; ! 243: break; ! 244: } ! 245: if (nppp >= NPPP) ! 246: for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) ! 247: if (sc->sc_devp == NULL) ! 248: break; ! 249: if (nppp >= NPPP) ! 250: return NULL; ! 251: ! 252: sc->sc_flags = 0; ! 253: sc->sc_mru = PPP_MRU; ! 254: #ifdef VJC ! 255: sl_compress_init(&sc->sc_comp, -1); ! 256: #endif ! 257: sc->sc_if.if_flags |= IFF_RUNNING; ! 258: ! 259: return sc; ! 260: } ! 261: ! 262: /* ! 263: * Deallocate a ppp unit. ! 264: */ ! 265: pppdealloc(sc) ! 266: struct ppp_softc *sc; ! 267: { ! 268: struct mbuf *m; ! 269: ! 270: if_down(&sc->sc_if); ! 271: sc->sc_devp = NULL; ! 272: sc->sc_xfer = 0; ! 273: for (;;) { ! 274: IF_DEQUEUE(&sc->sc_inq, m); ! 275: if (m == NULL) ! 276: break; ! 277: m_freem(m); ! 278: } ! 279: for (;;) { ! 280: IF_DEQUEUE(&sc->sc_fastq, m); ! 281: if (m == NULL) ! 282: break; ! 283: m_freem(m); ! 284: } ! 285: sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); ! 286: } ! 287: ! 288: /* ! 289: * Line specific open routine for async tty devices. ! 290: * Attach the given tty to the first available ppp unit. ! 291: */ ! 292: /* ARGSUSED */ ! 293: int ! 294: pppopen(dev, tp) ! 295: dev_t dev; ! 296: register struct tty *tp; ! 297: { ! 298: struct proc *p = current_proc(); /* XXX */ ! 299: register struct ppp_softc *sc; ! 300: int error, s, i; ! 301: ! 302: if (error = suser(p->p_ucred, &p->p_acflag)) ! 303: return (error); ! 304: ! 305: if (tp->t_line == PPPDISC) { ! 306: sc = (struct ppp_softc *) tp->t_sc; ! 307: if (sc != NULL && sc->sc_devp == (void *) tp) ! 308: return (0); ! 309: } ! 310: ! 311: if ((sc = pppalloc(p->p_pid)) == NULL) ! 312: return ENXIO; ! 313: ! 314: if (sc->sc_outm != NULL) { ! 315: m_freem(sc->sc_outm); ! 316: sc->sc_outm = NULL; ! 317: } ! 318: ! 319: pppgetm(sc); ! 320: ! 321: sc->sc_ilen = 0; ! 322: bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); ! 323: sc->sc_asyncmap[0] = 0xffffffff; ! 324: sc->sc_asyncmap[3] = 0x60000000; ! 325: sc->sc_rasyncmap = 0; ! 326: sc->sc_devp = (void *) tp; ! 327: sc->sc_start = pppasyncstart; ! 328: ! 329: tp->t_sc = (caddr_t) sc; ! 330: ttyflush(tp, FREAD | FWRITE); ! 331: ! 332: return (0); ! 333: } ! 334: ! 335: /* ! 336: * Line specific close routine. ! 337: * Detach the tty from the ppp unit. ! 338: * Mimics part of ttyclose(). ! 339: */ ! 340: void ! 341: pppclose(tp, flag) ! 342: struct tty *tp; ! 343: int flag; ! 344: { ! 345: register struct ppp_softc *sc; ! 346: struct mbuf *m; ! 347: int s; ! 348: ! 349: ttywflush(tp); ! 350: s = splimp(); /* paranoid; splnet probably ok */ ! 351: tp->t_line = 0; ! 352: sc = (struct ppp_softc *)tp->t_sc; ! 353: if (sc != NULL) { ! 354: tp->t_sc = NULL; ! 355: if (tp == (struct tty *) sc->sc_devp) { ! 356: m_freem(sc->sc_outm); ! 357: sc->sc_outm = NULL; ! 358: m_freem(sc->sc_m); ! 359: sc->sc_m = NULL; ! 360: pppdealloc(sc); ! 361: } ! 362: } ! 363: splx(s); ! 364: } ! 365: ! 366: /* ! 367: * Line specific (tty) read routine. ! 368: */ ! 369: int ! 370: pppread(tp, uio, flag) ! 371: register struct tty *tp; ! 372: struct uio *uio; ! 373: int flag; ! 374: { ! 375: register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; ! 376: struct mbuf *m, *m0; ! 377: register int s; ! 378: int error = 0; ! 379: ! 380: if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) ! 381: return 0; /* end of file */ ! 382: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 383: return 0; ! 384: s = splimp(); ! 385: while (sc->sc_inq.ifq_head == NULL && tp->t_line == PPPDISC) { ! 386: if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) { ! 387: splx(s); ! 388: return (EWOULDBLOCK); ! 389: } ! 390: error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0); ! 391: if (error) { ! 392: splx(s); ! 393: return error; ! 394: } ! 395: } ! 396: if (tp->t_line != PPPDISC) { ! 397: splx(s); ! 398: return (-1); ! 399: } ! 400: ! 401: /* Pull place-holder byte out of canonical queue */ ! 402: getc(&tp->t_canq); ! 403: ! 404: /* Get the packet from the input queue */ ! 405: IF_DEQUEUE(&sc->sc_inq, m0); ! 406: splx(s); ! 407: ! 408: for (m = m0; m && uio->uio_resid; m = m->m_next) ! 409: if (error = uiomove(mtod(m, u_char *), m->m_len, uio)) ! 410: break; ! 411: m_freem(m0); ! 412: return (error); ! 413: } ! 414: ! 415: /* ! 416: * Line specific (tty) write routine. ! 417: */ ! 418: int ! 419: pppwrite(tp, uio, flag) ! 420: register struct tty *tp; ! 421: struct uio *uio; ! 422: int flag; ! 423: { ! 424: register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc; ! 425: struct mbuf *m, *m0, **mp; ! 426: struct sockaddr dst; ! 427: struct ppp_header *ph1, *ph2; ! 428: int len, error; ! 429: ! 430: if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 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: for (mp = &m0; uio->uio_resid; mp = &m->m_next) { ! 440: MGET(m, M_WAIT, MT_DATA); ! 441: if ((*mp = m) == NULL) { ! 442: m_freem(m0); ! 443: return (ENOBUFS); ! 444: } ! 445: m->m_len = 0; ! 446: if (uio->uio_resid >= MCLBYTES / 2) ! 447: MCLGET(m, M_DONTWAIT); ! 448: len = M_TRAILINGSPACE(m); ! 449: if (len > uio->uio_resid) ! 450: len = uio->uio_resid; ! 451: if (error = uiomove(mtod(m, u_char *), len, uio)) { ! 452: m_freem(m0); ! 453: return (error); ! 454: } ! 455: m->m_len = len; ! 456: } ! 457: dst.sa_family = AF_UNSPEC; ! 458: ph1 = (struct ppp_header *) &dst.sa_data; ! 459: ph2 = mtod(m0, struct ppp_header *); ! 460: *ph1 = *ph2; ! 461: m0->m_data += PPP_HDRLEN; ! 462: m0->m_len -= PPP_HDRLEN; ! 463: return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0)); ! 464: } ! 465: ! 466: /* ! 467: * Line specific (tty) ioctl routine. ! 468: * Provide a way to get the ppp unit number. ! 469: * This discipline requires that tty device drivers call ! 470: * the line specific l_ioctl routine from their ioctl routines. ! 471: */ ! 472: /* ARGSUSED */ ! 473: int ! 474: ppptioctl(tp, cmd, data, flag, p) ! 475: struct tty *tp; ! 476: u_long cmd; ! 477: caddr_t data; ! 478: int flag; ! 479: struct proc *p; ! 480: { ! 481: register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; ! 482: int s, error, flags, mru; ! 483: ! 484: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 485: return -1; ! 486: ! 487: switch (cmd) { ! 488: case FIONREAD: ! 489: *(int *)data = sc->sc_inq.ifq_len; ! 490: break; ! 491: ! 492: case PPPIOCGUNIT: ! 493: *(int *)data = sc->sc_if.if_unit; ! 494: break; ! 495: ! 496: case PPPIOCGFLAGS: ! 497: *(u_int *)data = sc->sc_flags; ! 498: break; ! 499: ! 500: case PPPIOCSFLAGS: ! 501: if (error = suser(p->p_ucred, &p->p_acflag)) ! 502: return (error); ! 503: flags = *(int *)data & SC_MASK; ! 504: s = splimp(); ! 505: sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; ! 506: splx(s); ! 507: break; ! 508: ! 509: case PPPIOCSASYNCMAP: ! 510: if (error = suser(p->p_ucred, &p->p_acflag)) ! 511: return (error); ! 512: sc->sc_asyncmap[0] = *(u_int32_t *)data; ! 513: break; ! 514: ! 515: case PPPIOCGASYNCMAP: ! 516: *(u_int32_t *)data = sc->sc_asyncmap[0]; ! 517: break; ! 518: ! 519: case PPPIOCSRASYNCMAP: ! 520: if (error = suser(p->p_ucred, &p->p_acflag)) ! 521: return (error); ! 522: sc->sc_rasyncmap = *(u_int32_t *)data; ! 523: break; ! 524: ! 525: case PPPIOCGRASYNCMAP: ! 526: *(u_int32_t *)data = sc->sc_rasyncmap; ! 527: break; ! 528: ! 529: case PPPIOCSXASYNCMAP: ! 530: if (error = suser(p->p_ucred, &p->p_acflag)) ! 531: return (error); ! 532: bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap)); ! 533: sc->sc_asyncmap[1] = 0; /* mustn't escape 0x20 - 0x3f */ ! 534: sc->sc_asyncmap[2] &= ~0x40000000; /* mustn't escape 0x5e */ ! 535: sc->sc_asyncmap[3] |= 0x60000000; /* must escape 0x7d, 0x7e */ ! 536: break; ! 537: ! 538: case PPPIOCGXASYNCMAP: ! 539: bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap)); ! 540: break; ! 541: ! 542: case PPPIOCSMRU: ! 543: if (error = suser(p->p_ucred, &p->p_acflag)) ! 544: return (error); ! 545: mru = *(int *)data; ! 546: if (mru >= PPP_MRU && mru <= PPP_MAXMRU) { ! 547: sc->sc_mru = mru; ! 548: pppgetm(sc); ! 549: } ! 550: break; ! 551: ! 552: case PPPIOCGMRU: ! 553: *(int *)data = sc->sc_mru; ! 554: break; ! 555: ! 556: #ifdef VJC ! 557: case PPPIOCSMAXCID: ! 558: if (error = suser(p->p_ucred, &p->p_acflag)) ! 559: return (error); ! 560: sl_compress_init(&sc->sc_comp, *(int *)data); ! 561: break; ! 562: #endif ! 563: ! 564: case PPPIOCXFERUNIT: ! 565: if (error = suser(p->p_ucred, &p->p_acflag)) ! 566: return (error); ! 567: sc->sc_xfer = p->p_pid; ! 568: break; ! 569: ! 570: default: ! 571: return (-1); ! 572: } ! 573: return (0); ! 574: } ! 575: ! 576: /* ! 577: * FCS lookup table as calculated by genfcstab. ! 578: */ ! 579: static u_int16_t fcstab[256] = { ! 580: 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, ! 581: 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, ! 582: 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, ! 583: 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, ! 584: 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, ! 585: 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, ! 586: 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, ! 587: 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, ! 588: 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, ! 589: 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, ! 590: 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, ! 591: 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, ! 592: 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, ! 593: 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, ! 594: 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, ! 595: 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, ! 596: 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, ! 597: 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, ! 598: 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, ! 599: 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, ! 600: 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, ! 601: 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, ! 602: 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, ! 603: 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, ! 604: 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, ! 605: 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, ! 606: 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, ! 607: 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, ! 608: 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, ! 609: 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, ! 610: 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, ! 611: 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 ! 612: }; ! 613: ! 614: /* ! 615: * Calculate a new FCS given the current FCS and the new data. ! 616: */ ! 617: static u_int16_t ! 618: pppfcs(fcs, cp, len) ! 619: register u_int fcs; ! 620: register u_char *cp; ! 621: register int len; ! 622: { ! 623: while (len--) ! 624: fcs = PPP_FCS(fcs, *cp++); ! 625: return (fcs); ! 626: } ! 627: ! 628: /* ! 629: * Queue a packet. Start transmission if not active. ! 630: * Packet is placed in Information field of PPP frame. ! 631: */ ! 632: int ! 633: pppoutput(ifp, m0, dst, rtp) ! 634: struct ifnet *ifp; ! 635: struct mbuf *m0; ! 636: struct sockaddr *dst; ! 637: struct rtentry *rtp; ! 638: { ! 639: register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; ! 640: struct ppp_header *ph; ! 641: int protocol, address, control; ! 642: u_char *cp; ! 643: int s, error; ! 644: struct ip *ip; ! 645: struct ifqueue *ifq; ! 646: ! 647: if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 ! 648: || (ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC) { ! 649: error = ENETDOWN; /* sort of */ ! 650: goto bad; ! 651: } ! 652: ! 653: /* ! 654: * Compute PPP header. ! 655: */ ! 656: address = PPP_ALLSTATIONS; ! 657: control = PPP_UI; ! 658: ifq = &ifp->if_snd; ! 659: switch (dst->sa_family) { ! 660: #if INET ! 661: case AF_INET: ! 662: protocol = PPP_IP; ! 663: if ((sc->sc_flags & SC_ENABLE_IP) == 0) { ! 664: error = ENETDOWN; ! 665: goto bad; ! 666: } ! 667: ! 668: /* ! 669: * If this is a TCP packet to or from an "interactive" port, ! 670: * put the packet on the fastq instead. ! 671: */ ! 672: if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) { ! 673: register int32_t p = ntohl(((int32_t *)ip)[ip->ip_hl]); ! 674: if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16)) ! 675: ifq = &sc->sc_fastq; ! 676: } ! 677: break; ! 678: #endif ! 679: #if NS ! 680: case AF_NS: ! 681: protocol = PPP_XNS; ! 682: break; ! 683: #endif ! 684: case AF_UNSPEC: ! 685: ph = (struct ppp_header *) dst->sa_data; ! 686: address = ph->ph_address; ! 687: control = ph->ph_control; ! 688: protocol = ntohs(ph->ph_protocol); ! 689: break; ! 690: default: ! 691: printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); ! 692: error = EAFNOSUPPORT; ! 693: goto bad; ! 694: } ! 695: ! 696: /* ! 697: * Add PPP header. If no space in first mbuf, allocate another. ! 698: * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) ! 699: */ ! 700: if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { ! 701: m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); ! 702: if (m0 == 0) { ! 703: error = ENOBUFS; ! 704: goto bad; ! 705: } ! 706: m0->m_len = 0; ! 707: } else ! 708: m0->m_data -= PPP_HDRLEN; ! 709: ! 710: cp = mtod(m0, u_char *); ! 711: *cp++ = address; ! 712: *cp++ = control; ! 713: *cp++ = protocol >> 8; ! 714: *cp++ = protocol & 0xff; ! 715: m0->m_len += PPP_HDRLEN; ! 716: ! 717: if (sc->sc_flags & SC_LOG_OUTPKT) { ! 718: printf("ppp%d output: ", ifp->if_unit); ! 719: pppdumpm(m0, -1); ! 720: } ! 721: ! 722: #if NBPFILTER > 0 ! 723: /* See if bpf wants to look at the packet. */ ! 724: if (sc->sc_bpf) ! 725: BPF_MTAP(sc->sc_bpf, m0); ! 726: #endif ! 727: ! 728: /* ! 729: * Put the packet on the appropriate queue. ! 730: */ ! 731: s = splimp(); ! 732: if (IF_QFULL(ifq)) { ! 733: IF_DROP(ifq); ! 734: splx(s); ! 735: sc->sc_if.if_oerrors++; ! 736: error = ENOBUFS; ! 737: goto bad; ! 738: } ! 739: IF_ENQUEUE(ifq, m0); ! 740: ! 741: /* ! 742: * Tell the device to send it out. ! 743: */ ! 744: (*sc->sc_start)(sc); ! 745: ! 746: splx(s); ! 747: return (0); ! 748: ! 749: bad: ! 750: m_freem(m0); ! 751: return (error); ! 752: } ! 753: ! 754: /* ! 755: * Grab another packet off a queue and apply VJ compression, ! 756: * address/control and/or protocol compression if appropriate. ! 757: */ ! 758: struct mbuf * ! 759: ppp_dequeue(sc) ! 760: struct ppp_softc *sc; ! 761: { ! 762: int s; ! 763: struct mbuf *m, *mp; ! 764: u_char *cp; ! 765: int address, control, protocol; ! 766: ! 767: s = splimp(); ! 768: IF_DEQUEUE(&sc->sc_fastq, m); ! 769: if (m == NULL) ! 770: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 771: splx(s); ! 772: if (m == NULL) ! 773: return NULL; ! 774: ! 775: /* ! 776: * Extract the ppp header of the new packet. ! 777: * The ppp header will be in one mbuf. ! 778: */ ! 779: cp = mtod(m, u_char *); ! 780: address = cp[0]; ! 781: control = cp[1]; ! 782: protocol = (cp[2] << 8) + cp[3]; ! 783: ! 784: switch (protocol) { ! 785: #ifdef VJC ! 786: case PPP_IP: ! 787: /* ! 788: * If the packet is a TCP/IP packet, see if we can compress it. ! 789: */ ! 790: if (sc->sc_flags & SC_COMP_TCP) { ! 791: struct ip *ip; ! 792: int type; ! 793: ! 794: mp = m; ! 795: ip = (struct ip *) (cp + PPP_HDRLEN); ! 796: if (mp->m_len <= PPP_HDRLEN) { ! 797: mp = mp->m_next; ! 798: if (mp == NULL) ! 799: break; ! 800: ip = mtod(mp, struct ip *); ! 801: } ! 802: /* this code assumes the IP/TCP header is in one non-shared mbuf */ ! 803: if (ip->ip_p == IPPROTO_TCP) { ! 804: type = sl_compress_tcp(mp, ip, &sc->sc_comp, ! 805: !(sc->sc_flags & SC_NO_TCP_CCID)); ! 806: switch (type) { ! 807: case TYPE_UNCOMPRESSED_TCP: ! 808: protocol = PPP_VJC_UNCOMP; ! 809: break; ! 810: case TYPE_COMPRESSED_TCP: ! 811: protocol = PPP_VJC_COMP; ! 812: cp = mtod(m, u_char *); ! 813: cp[0] = address; /* header has moved */ ! 814: cp[1] = control; ! 815: cp[2] = 0; ! 816: break; ! 817: } ! 818: cp[3] = protocol; /* update protocol in PPP header */ ! 819: } ! 820: } ! 821: #endif /* VJC */ ! 822: } ! 823: ! 824: /* ! 825: * Compress the address/control and protocol, if possible. ! 826: */ ! 827: if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && ! 828: control == PPP_UI && protocol != PPP_ALLSTATIONS && ! 829: protocol != PPP_LCP) { ! 830: /* can compress address/control */ ! 831: m->m_data += 2; ! 832: m->m_len -= 2; ! 833: } ! 834: if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { ! 835: /* can compress protocol */ ! 836: if (mtod(m, u_char *) == cp) { ! 837: cp[2] = cp[1]; /* move address/control up */ ! 838: cp[1] = cp[0]; ! 839: } ! 840: ++m->m_data; ! 841: --m->m_len; ! 842: } ! 843: ! 844: return m; ! 845: } ! 846: ! 847: /* ! 848: * This gets called from pppoutput when a new packet is ! 849: * put on a queue. ! 850: */ ! 851: static ! 852: pppasyncstart(sc) ! 853: register struct ppp_softc *sc; ! 854: { ! 855: register struct tty *tp = (struct tty *) sc->sc_devp; ! 856: ! 857: pppstart(tp); ! 858: } ! 859: ! 860: /* ! 861: * Start output on async tty interface. Get another datagram ! 862: * to send from the interface queue and start sending it. ! 863: */ ! 864: void ! 865: pppstart(tp) ! 866: register struct tty *tp; ! 867: { ! 868: register struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc; ! 869: register struct mbuf *m; ! 870: register int len; ! 871: register u_char *start, *stop, *cp; ! 872: int n, s, ndone, done; ! 873: struct mbuf *m2; ! 874: ! 875: if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0) { ! 876: /* sorry, I can't talk now */ ! 877: return; ! 878: } ! 879: if (sc == NULL || tp != (struct tty *) sc->sc_devp) { ! 880: (*tp->t_oproc)(tp); ! 881: return; ! 882: } ! 883: ! 884: for (;;) { ! 885: /* ! 886: * If there is more in the output queue, just send it now. ! 887: * We are being called in lieu of ttstart and must do what ! 888: * it would. ! 889: */ ! 890: if (CCOUNT(&tp->t_outq) != 0 && tp->t_oproc != NULL) { ! 891: (*tp->t_oproc)(tp); ! 892: if (CCOUNT(&tp->t_outq) > PPP_HIWAT) ! 893: return; ! 894: } ! 895: ! 896: /* ! 897: * See if we have an existing packet partly sent. ! 898: * If not, get a new packet and start sending it. ! 899: * We take packets on the priority queue ahead of those ! 900: * on the normal queue. ! 901: */ ! 902: m = sc->sc_outm; ! 903: if (m == NULL) { ! 904: /* ! 905: * Get another packet to be sent ! 906: */ ! 907: m = ppp_dequeue(sc); ! 908: if (m == NULL) ! 909: return; ! 910: ! 911: /* ! 912: * The extra PPP_FLAG will start up a new packet, and thus ! 913: * will flush any accumulated garbage. We do this whenever ! 914: * the line may have been idle for some time. ! 915: */ ! 916: if (CCOUNT(&tp->t_outq) == 0) { ! 917: ++sc->sc_bytessent; ! 918: (void) putc(PPP_FLAG, &tp->t_outq); ! 919: } ! 920: ! 921: /* Calculate the FCS for the first mbuf's worth. */ ! 922: sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len); ! 923: } ! 924: ! 925: for (;;) { ! 926: start = mtod(m, u_char *); ! 927: len = m->m_len; ! 928: stop = start + len; ! 929: while (len > 0) { ! 930: /* ! 931: * Find out how many bytes in the string we can ! 932: * handle without doing something special. ! 933: */ ! 934: for (cp = start; cp < stop; cp++) ! 935: if (ESCAPE_P(*cp)) ! 936: break; ! 937: n = cp - start; ! 938: if (n) { ! 939: ndone = n - b_to_q(start, n, &tp->t_outq); ! 940: len -= ndone; ! 941: start += ndone; ! 942: sc->sc_bytessent += ndone; ! 943: ! 944: if (ndone < n) ! 945: break; /* packet doesn't fit */ ! 946: } ! 947: /* ! 948: * If there are characters left in the mbuf, ! 949: * the first one must be special.. ! 950: * Put it out in a different form. ! 951: */ ! 952: if (len) { ! 953: if (putc(PPP_ESCAPE, &tp->t_outq)) ! 954: break; ! 955: if (putc(*start ^ PPP_TRANS, &tp->t_outq)) { ! 956: (void) unputc(&tp->t_outq); ! 957: break; ! 958: } ! 959: sc->sc_bytessent += 2; ! 960: start++; ! 961: len--; ! 962: } ! 963: } ! 964: /* ! 965: * If we didn't empty this mbuf, remember where we're up to. ! 966: * If we emptied the last mbuf, try to add the FCS and closing ! 967: * flag, and if we can't, leave sc_outm pointing to m, but with ! 968: * m->m_len == 0, to remind us to output the FCS and flag later. ! 969: */ ! 970: done = len == 0; ! 971: if (done && m->m_next == NULL) { ! 972: u_char *p, *q; ! 973: int c; ! 974: u_char endseq[8]; ! 975: ! 976: /* ! 977: * We may have to escape the bytes in the FCS. ! 978: */ ! 979: p = endseq; ! 980: c = ~sc->sc_outfcs & 0xFF; ! 981: if (ESCAPE_P(c)) { ! 982: *p++ = PPP_ESCAPE; ! 983: *p++ = c ^ PPP_TRANS; ! 984: } else ! 985: *p++ = c; ! 986: c = (~sc->sc_outfcs >> 8) & 0xFF; ! 987: if (ESCAPE_P(c)) { ! 988: *p++ = PPP_ESCAPE; ! 989: *p++ = c ^ PPP_TRANS; ! 990: } else ! 991: *p++ = c; ! 992: *p++ = PPP_FLAG; ! 993: ! 994: /* ! 995: * Try to output the FCS and flag. If the bytes ! 996: * don't all fit, back out. ! 997: */ ! 998: for (q = endseq; q < p; ++q) ! 999: if (putc(*q, &tp->t_outq)) { ! 1000: done = 0; ! 1001: for (; q > endseq; --q) ! 1002: unputc(&tp->t_outq); ! 1003: break; ! 1004: } ! 1005: } ! 1006: ! 1007: if (!done) { ! 1008: m->m_data = start; ! 1009: m->m_len = len; ! 1010: sc->sc_outm = m; ! 1011: if (tp->t_oproc != NULL) ! 1012: (*tp->t_oproc)(tp); ! 1013: return; /* can't do any more at the moment */ ! 1014: } ! 1015: ! 1016: /* Finished with this mbuf; free it and move on. */ ! 1017: MFREE(m, m2); ! 1018: if (m2 == NULL) ! 1019: break; ! 1020: ! 1021: m = m2; ! 1022: sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len); ! 1023: } ! 1024: ! 1025: /* Finished a packet */ ! 1026: sc->sc_outm = NULL; ! 1027: sc->sc_bytessent++; /* account for closing flag */ ! 1028: sc->sc_if.if_opackets++; ! 1029: sc->sc_if.if_obytes = sc->sc_bytessent; ! 1030: } ! 1031: } ! 1032: ! 1033: /* ! 1034: * Allocate enough mbuf to handle current MRU. ! 1035: */ ! 1036: static int ! 1037: pppgetm(sc) ! 1038: register struct ppp_softc *sc; ! 1039: { ! 1040: struct mbuf *m, **mp; ! 1041: int len; ! 1042: int s; ! 1043: ! 1044: s = splimp(); ! 1045: mp = &sc->sc_m; ! 1046: for (len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){ ! 1047: if ((m = *mp) == NULL) { ! 1048: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 1049: if (m == NULL) ! 1050: break; ! 1051: *mp = m; ! 1052: MCLGET(m, M_DONTWAIT); ! 1053: } ! 1054: len -= M_DATASIZE(m); ! 1055: mp = &m->m_next; ! 1056: } ! 1057: splx(s); ! 1058: return len <= 0; ! 1059: } ! 1060: ! 1061: /* ! 1062: * PPP packet input routine. ! 1063: * The caller has checked and removed the FCS and has inserted ! 1064: * the address/control bytes and the protocol high byte if they ! 1065: * were omitted. The data in the first mbuf should start HDROFF ! 1066: * bytes from the beginning of the mbuf data storage area. ! 1067: * The return value is 1 if the packet was put on sc->sc_inq, ! 1068: * 0 otherwise. ! 1069: */ ! 1070: #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ ! 1071: TYPE_UNCOMPRESSED_TCP) ! 1072: ! 1073: int ! 1074: ppppktin(sc, m) ! 1075: struct ppp_softc *sc; ! 1076: struct mbuf *m; ! 1077: { ! 1078: struct ifqueue *inq; ! 1079: int s, ilen, xlen, proto, rv; ! 1080: u_char *cp, adrs, ctrl; ! 1081: struct mbuf *mp; ! 1082: ! 1083: sc->sc_if.if_ipackets++; ! 1084: rv = 0; ! 1085: ! 1086: cp = mtod(m, u_char *); ! 1087: adrs = cp[0]; ! 1088: ctrl = cp[1]; ! 1089: proto = (cp[2] << 8) + cp[3]; ! 1090: ! 1091: ilen = 0; ! 1092: for (mp = m; mp != NULL; mp = mp->m_next) ! 1093: ilen += mp->m_len; ! 1094: ! 1095: #ifdef VJC ! 1096: /* ! 1097: * See if we have a VJ-compressed packet to uncompress. ! 1098: */ ! 1099: if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) { ! 1100: char *pkttype = proto == PPP_VJC_COMP? "": "un"; ! 1101: ! 1102: if (sc->sc_flags & SC_REJ_COMP_TCP) { ! 1103: if (sc->sc_flags & SC_DEBUG) ! 1104: printf("ppp%d: %scomp pkt w/o compression; flags 0x%x\n", ! 1105: sc->sc_if.if_unit, pkttype, sc->sc_flags); ! 1106: m_freem(m); ! 1107: sc->sc_if.if_ierrors++; ! 1108: return 0; ! 1109: } ! 1110: ! 1111: if (proto == PPP_VJC_COMP && m->m_data - M_DATASTART(m) < MAX_HDR) { ! 1112: /* ! 1113: * We don't have room in the mbuf to decompress this packet. ! 1114: * XXX For now we just drop the packet. ! 1115: */ ! 1116: if (sc->sc_flags & SC_DEBUG) ! 1117: printf("ppp%d: no room to VJ-decompress packet\n", ! 1118: sc->sc_if.if_unit); ! 1119: m_freem(m); ! 1120: sc->sc_if.if_ierrors++; ! 1121: return 0; ! 1122: } ! 1123: ! 1124: m->m_data += PPP_HDRLEN; ! 1125: m->m_len -= PPP_HDRLEN; ! 1126: ilen -= PPP_HDRLEN; ! 1127: xlen = sl_uncompress_tcp_part((u_char **)(&m->m_data), ! 1128: m->m_len, ilen, ! 1129: COMPTYPE(proto), &sc->sc_comp); ! 1130: ! 1131: if (xlen == 0) { ! 1132: if (sc->sc_flags & SC_DEBUG) ! 1133: printf("ppp%d: sl_uncompress failed on type %scomp\n", ! 1134: sc->sc_if.if_unit, pkttype); ! 1135: m_freem(m); ! 1136: sc->sc_if.if_ierrors++; ! 1137: return 0; ! 1138: } ! 1139: ! 1140: /* adjust the first mbuf by the decompressed amt */ ! 1141: xlen += PPP_HDRLEN; ! 1142: m->m_len += xlen - ilen; ! 1143: ilen = xlen; ! 1144: m->m_data -= PPP_HDRLEN; ! 1145: proto = PPP_IP; ! 1146: ! 1147: /* put the ppp header back in place */ ! 1148: if (cp != mtod(m, u_char *)) { ! 1149: cp = mtod(m, u_char *); ! 1150: cp[0] = adrs; ! 1151: cp[1] = ctrl; ! 1152: cp[2] = 0; ! 1153: } ! 1154: cp[3] = PPP_IP; ! 1155: } ! 1156: #endif /* VJC */ ! 1157: ! 1158: /* ! 1159: * If the packet will fit in a header mbuf, don't waste a ! 1160: * whole cluster on it. ! 1161: */ ! 1162: if (ilen <= MHLEN) { ! 1163: MGETHDR(mp, M_DONTWAIT, MT_DATA); ! 1164: if (mp != NULL) { ! 1165: m_copydata(m, 0, ilen, mtod(mp, caddr_t)); ! 1166: m_freem(m); ! 1167: m = mp; ! 1168: m->m_len = ilen; ! 1169: } ! 1170: } ! 1171: m->m_pkthdr.len = ilen; ! 1172: m->m_pkthdr.rcvif = &sc->sc_if; ! 1173: ! 1174: #if NBPFILTER > 0 ! 1175: /* See if bpf wants to look at the packet. */ ! 1176: if (sc->sc_bpf) ! 1177: BPF_MTAP(sc->sc_bpf, m); ! 1178: #endif ! 1179: ! 1180: switch (proto) { ! 1181: #if INET ! 1182: case PPP_IP: ! 1183: /* ! 1184: * IP packet - take off the ppp header and pass it up to IP. ! 1185: */ ! 1186: if ((sc->sc_if.if_flags & IFF_UP) == 0 ! 1187: || (sc->sc_flags & SC_ENABLE_IP) == 0) { ! 1188: /* interface is down - drop the packet. */ ! 1189: m_freem(m); ! 1190: return 0; ! 1191: } ! 1192: m->m_pkthdr.len -= PPP_HDRLEN; ! 1193: m->m_data += PPP_HDRLEN; ! 1194: m->m_len -= PPP_HDRLEN; ! 1195: schednetisr(NETISR_IP); ! 1196: inq = &ipintrq; ! 1197: break; ! 1198: #endif ! 1199: ! 1200: default: ! 1201: /* ! 1202: * Some other protocol - place on input queue for read(). ! 1203: */ ! 1204: inq = &sc->sc_inq; ! 1205: rv = 1; ! 1206: break; ! 1207: } ! 1208: ! 1209: /* ! 1210: * Put the packet on the appropriate input queue. ! 1211: */ ! 1212: s = splimp(); ! 1213: if (IF_QFULL(inq)) { ! 1214: IF_DROP(inq); ! 1215: if (sc->sc_flags & SC_DEBUG) ! 1216: printf("ppp%d: queue full\n", sc->sc_if.if_unit); ! 1217: sc->sc_if.if_ierrors++; ! 1218: sc->sc_if.if_iqdrops++; ! 1219: m_freem(m); ! 1220: rv = 0; ! 1221: } else ! 1222: IF_ENQUEUE(inq, m); ! 1223: ! 1224: splx(s); ! 1225: return rv; ! 1226: } ! 1227: ! 1228: /* ! 1229: * tty interface receiver interrupt. ! 1230: */ ! 1231: static unsigned paritytab[8] = { ! 1232: 0x96696996, 0x69969669, 0x69969669, 0x96696996, ! 1233: 0x69969669, 0x96696996, 0x96696996, 0x69969669 ! 1234: }; ! 1235: ! 1236: void ! 1237: pppinput(c, tp) ! 1238: int c; ! 1239: register struct tty *tp; ! 1240: { ! 1241: register struct ppp_softc *sc; ! 1242: struct mbuf *m; ! 1243: int ilen; ! 1244: ! 1245: tk_nin++; ! 1246: sc = (struct ppp_softc *) tp->t_sc; ! 1247: if (sc == NULL || tp != (struct tty *) sc->sc_devp) ! 1248: return; ! 1249: ! 1250: ++sc->sc_bytesrcvd; ! 1251: ! 1252: if (c & TTY_FE) { ! 1253: /* framing error or overrun on this char - abort packet */ ! 1254: if (sc->sc_flags & SC_DEBUG) ! 1255: printf("ppp%d: bad char %x\n", sc->sc_if.if_unit, c); ! 1256: goto flush; ! 1257: } ! 1258: ! 1259: c &= 0xff; ! 1260: ! 1261: if (c & 0x80) ! 1262: sc->sc_flags |= SC_RCV_B7_1; ! 1263: else ! 1264: sc->sc_flags |= SC_RCV_B7_0; ! 1265: if (paritytab[c >> 5] & (1 << (c & 0x1F))) ! 1266: sc->sc_flags |= SC_RCV_ODDP; ! 1267: else ! 1268: sc->sc_flags |= SC_RCV_EVNP; ! 1269: ! 1270: if (sc->sc_flags & SC_LOG_RAWIN) ! 1271: ppplogchar(sc, c); ! 1272: ! 1273: if (c == PPP_FLAG) { ! 1274: ilen = sc->sc_ilen; ! 1275: sc->sc_ilen = 0; ! 1276: sc->sc_if.if_ibytes = sc->sc_bytesrcvd; ! 1277: ! 1278: if (sc->sc_rawin_count > 0) ! 1279: ppplogchar(sc, -1); ! 1280: ! 1281: /* ! 1282: * If SC_ESCAPED is set, then we've seen the packet ! 1283: * abort sequence "}~". ! 1284: */ ! 1285: if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED) ! 1286: || ilen > 0 && sc->sc_fcs != PPP_GOODFCS) { ! 1287: #ifdef VJC ! 1288: /* ! 1289: * If we've missed a packet, we must toss subsequent compressed ! 1290: * packets which don't have an explicit connection ID. ! 1291: */ ! 1292: sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp); ! 1293: #endif ! 1294: if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){ ! 1295: if (sc->sc_flags & SC_DEBUG) ! 1296: printf("ppp%d: bad fcs %x\n", sc->sc_if.if_unit, ! 1297: sc->sc_fcs); ! 1298: sc->sc_if.if_ierrors++; ! 1299: } else ! 1300: sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED); ! 1301: return; ! 1302: } ! 1303: ! 1304: if (ilen < PPP_HDRLEN + PPP_FCSLEN) { ! 1305: if (ilen) { ! 1306: if (sc->sc_flags & SC_DEBUG) ! 1307: printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen); ! 1308: sc->sc_if.if_ierrors++; ! 1309: } ! 1310: return; ! 1311: } ! 1312: ! 1313: /* ! 1314: * Remove FCS trailer. Somewhat painful... ! 1315: */ ! 1316: ilen -= 2; ! 1317: if (--sc->sc_mc->m_len == 0) { ! 1318: for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next) ! 1319: ; ! 1320: sc->sc_mc = m; ! 1321: } ! 1322: sc->sc_mc->m_len--; ! 1323: ! 1324: /* excise this mbuf chain */ ! 1325: m = sc->sc_m; ! 1326: sc->sc_m = sc->sc_mc->m_next; ! 1327: sc->sc_mc->m_next = NULL; ! 1328: ! 1329: if (sc->sc_flags & SC_LOG_INPKT) { ! 1330: printf("ppp%d: got %d bytes\n", sc->sc_if.if_unit, ilen); ! 1331: pppdumpm(m, ilen); ! 1332: } ! 1333: ! 1334: if (ppppktin(sc, m)) { ! 1335: /* Put a placeholder byte in canq for ttselect()/ttnread(). */ ! 1336: putc(0, &tp->t_canq); ! 1337: ttwakeup(tp); ! 1338: } ! 1339: ! 1340: pppgetm(sc); ! 1341: return; ! 1342: } ! 1343: ! 1344: if (sc->sc_flags & SC_FLUSH) { ! 1345: if (sc->sc_flags & SC_LOG_FLUSH) ! 1346: ppplogchar(sc, c); ! 1347: return; ! 1348: } ! 1349: ! 1350: if (c < 0x20 && (sc->sc_rasyncmap & (1 << c))) ! 1351: return; ! 1352: ! 1353: if (sc->sc_flags & SC_ESCAPED) { ! 1354: sc->sc_flags &= ~SC_ESCAPED; ! 1355: c ^= PPP_TRANS; ! 1356: } else if (c == PPP_ESCAPE) { ! 1357: sc->sc_flags |= SC_ESCAPED; ! 1358: return; ! 1359: } ! 1360: ! 1361: /* ! 1362: * Initialize buffer on first octet received. ! 1363: * First octet could be address or protocol (when compressing ! 1364: * address/control). ! 1365: * Second octet is control. ! 1366: * Third octet is first or second (when compressing protocol) ! 1367: * octet of protocol. ! 1368: * Fourth octet is second octet of protocol. ! 1369: */ ! 1370: if (sc->sc_ilen == 0) { ! 1371: /* reset the first input mbuf */ ! 1372: if (sc->sc_m == NULL) { ! 1373: pppgetm(sc); ! 1374: if (sc->sc_m == NULL) { ! 1375: if (sc->sc_flags & SC_DEBUG) ! 1376: printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit); ! 1377: goto flush; ! 1378: } ! 1379: } ! 1380: m = sc->sc_m; ! 1381: m->m_len = 0; ! 1382: m->m_data = M_DATASTART(sc->sc_m); ! 1383: if (M_DATASIZE(sc->sc_m) >= HDROFF + PPP_HDRLEN) ! 1384: m->m_data += HDROFF; /* allow room for VJ decompression */ ! 1385: sc->sc_mc = m; ! 1386: sc->sc_mp = mtod(m, char *); ! 1387: sc->sc_fcs = PPP_INITFCS; ! 1388: if (c != PPP_ALLSTATIONS) { ! 1389: if (sc->sc_flags & SC_REJ_COMP_AC) { ! 1390: if (sc->sc_flags & SC_DEBUG) ! 1391: printf("ppp%d: garbage received: 0x%x (need 0xFF)\n", ! 1392: sc->sc_if.if_unit, c); ! 1393: goto flush; ! 1394: } ! 1395: *sc->sc_mp++ = PPP_ALLSTATIONS; ! 1396: *sc->sc_mp++ = PPP_UI; ! 1397: sc->sc_ilen += 2; ! 1398: m->m_len += 2; ! 1399: } ! 1400: } ! 1401: if (sc->sc_ilen == 1 && c != PPP_UI) { ! 1402: if (sc->sc_flags & SC_DEBUG) ! 1403: printf("ppp%d: missing UI (0x3), got 0x%x\n", ! 1404: sc->sc_if.if_unit, c); ! 1405: goto flush; ! 1406: } ! 1407: if (sc->sc_ilen == 2 && (c & 1) == 1) { ! 1408: /* a compressed protocol */ ! 1409: *sc->sc_mp++ = 0; ! 1410: sc->sc_ilen++; ! 1411: sc->sc_mc->m_len++; ! 1412: } ! 1413: if (sc->sc_ilen == 3 && (c & 1) == 0) { ! 1414: if (sc->sc_flags & SC_DEBUG) ! 1415: printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit, ! 1416: (sc->sc_mp[-1] << 8) + c); ! 1417: goto flush; ! 1418: } ! 1419: ! 1420: /* packet beyond configured mru? */ ! 1421: if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) { ! 1422: if (sc->sc_flags & SC_DEBUG) ! 1423: printf("ppp%d: packet too big\n", sc->sc_if.if_unit); ! 1424: goto flush; ! 1425: } ! 1426: ! 1427: /* is this mbuf full? */ ! 1428: m = sc->sc_mc; ! 1429: if (M_TRAILINGSPACE(m) <= 0) { ! 1430: if (m->m_next == NULL) { ! 1431: pppgetm(sc); ! 1432: if (m->m_next == NULL) { ! 1433: if (sc->sc_flags & SC_DEBUG) ! 1434: printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit); ! 1435: goto flush; ! 1436: } ! 1437: } ! 1438: sc->sc_mc = m = m->m_next; ! 1439: m->m_len = 0; ! 1440: m->m_data = M_DATASTART(m); ! 1441: sc->sc_mp = mtod(m, char *); ! 1442: } ! 1443: ! 1444: ++m->m_len; ! 1445: *sc->sc_mp++ = c; ! 1446: sc->sc_fcs = PPP_FCS(sc->sc_fcs, c); ! 1447: return; ! 1448: ! 1449: flush: ! 1450: if (!(sc->sc_flags & SC_FLUSH)) { ! 1451: sc->sc_if.if_ierrors++; ! 1452: sc->sc_flags |= SC_FLUSH; ! 1453: if (sc->sc_flags & SC_LOG_FLUSH) ! 1454: ppplogchar(sc, c); ! 1455: } ! 1456: } ! 1457: ! 1458: /* ! 1459: * Process an ioctl request to interface. ! 1460: */ ! 1461: pppioctl(ifp, cmd, data) ! 1462: register struct ifnet *ifp; ! 1463: u_long cmd; ! 1464: caddr_t data; ! 1465: { ! 1466: struct proc *p = current_proc(); /* XXX */ ! 1467: register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; ! 1468: register struct ifaddr *ifa = (struct ifaddr *)data; ! 1469: register struct ifreq *ifr = (struct ifreq *)data; ! 1470: int s = splimp(), error = 0; ! 1471: ! 1472: ! 1473: switch (cmd) { ! 1474: case SIOCSIFFLAGS: ! 1475: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 1476: ifp->if_flags &= ~IFF_UP; ! 1477: break; ! 1478: ! 1479: case SIOCSIFADDR: ! 1480: if (ifa->ifa_addr->sa_family != AF_INET) ! 1481: error = EAFNOSUPPORT; ! 1482: break; ! 1483: ! 1484: case SIOCSIFDSTADDR: ! 1485: if (ifa->ifa_addr->sa_family != AF_INET) ! 1486: error = EAFNOSUPPORT; ! 1487: break; ! 1488: ! 1489: case SIOCSIFMTU: ! 1490: if (error = suser(p->p_ucred, &p->p_acflag)) ! 1491: break; ! 1492: sc->sc_if.if_mtu = ifr->ifr_mtu; ! 1493: break; ! 1494: ! 1495: case SIOCGIFMTU: ! 1496: ifr->ifr_mtu = sc->sc_if.if_mtu; ! 1497: break; ! 1498: ! 1499: default: ! 1500: error = EINVAL; ! 1501: } ! 1502: splx(s); ! 1503: return (error); ! 1504: } ! 1505: ! 1506: #define MAX_DUMP_BYTES 128 ! 1507: ! 1508: static void ! 1509: pppdumpm(m0, pktlen) ! 1510: struct mbuf *m0; ! 1511: int pktlen; ! 1512: { ! 1513: char buf[3*MAX_DUMP_BYTES+4]; ! 1514: char *bp = buf; ! 1515: struct mbuf *m; ! 1516: static char digits[] = "0123456789abcdef"; ! 1517: ! 1518: for (m = m0; m && pktlen; m = m->m_next) { ! 1519: int l = m->m_len; ! 1520: u_char *rptr = (u_char *)m->m_data; ! 1521: ! 1522: if (pktlen > 0) { ! 1523: if (l > pktlen) ! 1524: l = pktlen; ! 1525: pktlen -= l; ! 1526: } ! 1527: while (l--) { ! 1528: if (bp > buf + sizeof(buf) - 4) ! 1529: goto done; ! 1530: *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */ ! 1531: *bp++ = digits[*rptr++ & 0xf]; ! 1532: } ! 1533: ! 1534: if (m->m_next) { ! 1535: if (bp > buf + sizeof(buf) - 3) ! 1536: goto done; ! 1537: *bp++ = '|'; ! 1538: } else ! 1539: *bp++ = ' '; ! 1540: } ! 1541: done: ! 1542: if (m && pktlen) ! 1543: *bp++ = '>'; ! 1544: *bp = 0; ! 1545: printf("%s\n", buf); ! 1546: } ! 1547: ! 1548: static void ! 1549: ppplogchar(sc, c) ! 1550: struct ppp_softc *sc; ! 1551: int c; ! 1552: { ! 1553: if (c >= 0) ! 1554: sc->sc_rawin[sc->sc_rawin_count++] = c; ! 1555: if (sc->sc_rawin_count >= sizeof(sc->sc_rawin) ! 1556: || c < 0 && sc->sc_rawin_count > 0) { ! 1557: printf("ppp%d input: ", sc->sc_if.if_unit); ! 1558: pppdumpb(sc->sc_rawin, sc->sc_rawin_count); ! 1559: sc->sc_rawin_count = 0; ! 1560: } ! 1561: } ! 1562: ! 1563: static void ! 1564: pppdumpb(b, l) ! 1565: u_char *b; ! 1566: int l; ! 1567: { ! 1568: char buf[3*MAX_DUMP_BYTES+4]; ! 1569: char *bp = buf; ! 1570: static char digits[] = "0123456789abcdef"; ! 1571: ! 1572: while (l--) { ! 1573: if (bp >= buf + sizeof(buf) - 3) { ! 1574: *bp++ = '>'; ! 1575: break; ! 1576: } ! 1577: *bp++ = digits[*b >> 4]; /* convert byte to ascii hex */ ! 1578: *bp++ = digits[*b++ & 0xf]; ! 1579: *bp++ = ' '; ! 1580: } ! 1581: ! 1582: *bp = 0; ! 1583: printf("%s\n", buf); ! 1584: } ! 1585: ! 1586: ! 1587: #endif /* NPPP > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.