|
|
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: * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver. ! 24: * ! 25: * Copyright (c) 1989 Carnegie Mellon University. ! 26: * All rights reserved. ! 27: * ! 28: * Redistribution and use in source and binary forms are permitted ! 29: * provided that the above copyright notice and this paragraph are ! 30: * duplicated in all such forms and that any documentation, ! 31: * advertising materials, and other materials related to such ! 32: * distribution and use acknowledge that the software was developed ! 33: * by Carnegie Mellon University. The name of the ! 34: * University may not be used to endorse or promote products derived ! 35: * from this software without specific prior written permission. ! 36: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 37: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 38: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 39: * ! 40: * Drew D. Perkins ! 41: * Carnegie Mellon University ! 42: * 4910 Forbes Ave. ! 43: * Pittsburgh, PA 15213 ! 44: * (412) 268-8576 ! 45: * [email protected] ! 46: * ! 47: * Based on: ! 48: * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89 ! 49: * ! 50: * Copyright (c) 1987 Regents of the University of California. ! 51: * All rights reserved. ! 52: * ! 53: * Redistribution and use in source and binary forms are permitted ! 54: * provided that the above copyright notice and this paragraph are ! 55: * duplicated in all such forms and that any documentation, ! 56: * advertising materials, and other materials related to such ! 57: * distribution and use acknowledge that the software was developed ! 58: * by the University of California, Berkeley. The name of the ! 59: * University may not be used to endorse or promote products derived ! 60: * from this software without specific prior written permission. ! 61: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 62: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 63: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 64: * ! 65: * Serial Line interface ! 66: * ! 67: * Rick Adams ! 68: * Center for Seismic Studies ! 69: * 1300 N 17th Street, Suite 1450 ! 70: * Arlington, Virginia 22209 ! 71: * (703)276-7900 ! 72: * [email protected] ! 73: * seismo!rick ! 74: * ! 75: * Pounded on heavily by Chris Torek ([email protected], umcp-cs!chris). ! 76: * Converted to 4.3BSD Beta by Chris Torek. ! 77: * Other changes made at Berkeley, based in part on code by Kirk Smith. ! 78: * ! 79: * Converted to 4.3BSD+ 386BSD by Brad Parker ([email protected]) ! 80: * Added VJ tcp header compression; more unified ioctls ! 81: * ! 82: * Extensively modified by Paul Mackerras ([email protected]). ! 83: * Cleaned up a lot of the mbuf-related code to fix bugs that ! 84: * caused system crashes and packet corruption. Changed pppstart ! 85: * so that it doesn't just give up with a collision if the whole ! 86: * packet doesn't fit in the output ring buffer. ! 87: * ! 88: * Added priority queueing for interactive IP packets, following ! 89: * the model of if_sl.c, plus hooks for bpf. ! 90: * Paul Mackerras ([email protected]). ! 91: */ ! 92: ! 93: /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */ ! 94: /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */ ! 95: ! 96: #include "ppp.h" ! 97: #if NPPP > 0 ! 98: ! 99: #include "opt_inet.h" ! 100: #include "opt_ipx.h" ! 101: #include "opt_ppp.h" ! 102: ! 103: #if INET ! 104: #define VJC ! 105: #endif ! 106: #define PPP_COMPRESS ! 107: ! 108: #include <sys/param.h> ! 109: #include <sys/systm.h> ! 110: #include <sys/proc.h> ! 111: #include <sys/mbuf.h> ! 112: #include <sys/socket.h> ! 113: #include <sys/filio.h> ! 114: #include <sys/sockio.h> ! 115: #include <sys/kernel.h> ! 116: #include <sys/time.h> ! 117: #include <sys/malloc.h> ! 118: ! 119: #include <net/if.h> ! 120: #include <net/if_types.h> ! 121: #include <net/netisr.h> ! 122: ! 123: #include <libkern/libkern.h> ! 124: ! 125: #if INET ! 126: #include <netinet/in.h> ! 127: #include <netinet/in_systm.h> ! 128: #include <netinet/in_var.h> ! 129: #include <netinet/ip.h> ! 130: #endif ! 131: ! 132: #if IPX ! 133: #include <netipx/ipx.h> ! 134: #include <netipx/ipx_if.h> ! 135: #endif ! 136: ! 137: #include "bpfilter.h" ! 138: #if NBPFILTER > 0 ! 139: #include <net/bpf.h> ! 140: #endif ! 141: ! 142: #if defined(PPP_FILTER) && NBPFILTER == 0 ! 143: #error "PPP_FILTER requires bpf" ! 144: #endif ! 145: ! 146: #if VJC ! 147: #include <net/slcompress.h> ! 148: #endif ! 149: ! 150: #include <net/if_ppp.h> ! 151: #include <net/if_pppvar.h> ! 152: ! 153: /* minimise diffs */ ! 154: #ifndef splsoftnet ! 155: #define splsoftnet splnet ! 156: #endif ! 157: ! 158: #if PPP_COMPRESS ! 159: #define PACKETPTR struct mbuf * ! 160: #include <net/ppp_comp.h> ! 161: #endif ! 162: ! 163: struct ppp_softc ppp_softc[NPPP]; ! 164: ! 165: /* XXX layering violation */ ! 166: extern void pppasyncattach __P((void *)); ! 167: ! 168: static void pppattach __P((void *)); ! 169: PSEUDO_SET(pppattach, if_ppp); ! 170: ! 171: static int pppsioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data)); ! 172: static void pppintr __P((void)); ! 173: ! 174: static void ppp_requeue __P((struct ppp_softc *)); ! 175: static void ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd)); ! 176: static void ppp_ccp_closed __P((struct ppp_softc *)); ! 177: static void ppp_inproc __P((struct ppp_softc *, struct mbuf *)); ! 178: static void pppdumpm __P((struct mbuf *m0)); ! 179: ! 180: /* ! 181: * Some useful mbuf macros not in mbuf.h. ! 182: */ ! 183: #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT) ! 184: ! 185: #define M_DATASTART(m) \ ! 186: (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \ ! 187: (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat) ! 188: ! 189: #define M_DATASIZE(m) \ ! 190: (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \ ! 191: (m)->m_flags & M_PKTHDR ? MHLEN: MLEN) ! 192: ! 193: /* ! 194: * We steal two bits in the mbuf m_flags, to mark high-priority packets ! 195: * for output, and received packets following lost/corrupted packets. ! 196: */ ! 197: #define M_HIGHPRI 0x2000 /* output packet for sc_fastq */ ! 198: #define M_ERRMARK 0x4000 /* steal a bit in mbuf m_flags */ ! 199: ! 200: ! 201: #if PPP_COMPRESS ! 202: /* ! 203: * List of compressors we know about. ! 204: * We leave some space so maybe we can modload compressors. ! 205: */ ! 206: ! 207: extern struct compressor ppp_bsd_compress; ! 208: extern struct compressor ppp_deflate, ppp_deflate_draft; ! 209: ! 210: static struct compressor *ppp_compressors[8] = { ! 211: #if DO_BSD_COMPRESS && defined(PPP_BSDCOMP) ! 212: &ppp_bsd_compress, ! 213: #endif ! 214: #if DO_DEFLATE && defined(PPP_DEFLATE) ! 215: &ppp_deflate, ! 216: &ppp_deflate_draft, ! 217: #endif ! 218: NULL ! 219: }; ! 220: #endif /* PPP_COMPRESS */ ! 221: ! 222: /* ! 223: * Called from boot code to establish ppp interfaces. ! 224: */ ! 225: static void ! 226: pppattach(dummy) ! 227: void *dummy; ! 228: { ! 229: register struct ppp_softc *sc; ! 230: register int i = 0; ! 231: ! 232: for (sc = ppp_softc; i < NPPP; sc++) { ! 233: sc->sc_if.if_name = "ppp"; ! 234: sc->sc_if.if_family = APPLE_IF_FAM_PPP; ! 235: sc->sc_if.if_unit = i++; ! 236: sc->sc_if.if_mtu = PPP_MTU; ! 237: sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST; ! 238: sc->sc_if.if_type = IFT_PPP; ! 239: sc->sc_if.if_hdrlen = PPP_HDRLEN; ! 240: sc->sc_if.if_ioctl = pppsioctl; ! 241: sc->sc_if.if_output = pppoutput; ! 242: sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN; ! 243: sc->sc_inq.ifq_maxlen = IFQ_MAXLEN; ! 244: sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN; ! 245: sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN; ! 246: if_attach(&sc->sc_if); ! 247: #if NBPFILTER > 0 ! 248: bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN); ! 249: #endif ! 250: } ! 251: register_netisr(NETISR_PPP, pppintr); ! 252: /* ! 253: * XXX layering violation - if_ppp can work over any lower level ! 254: * transport that cares to attach to it. ! 255: */ ! 256: pppasyncattach(dummy); ! 257: } ! 258: ! 259: /* ! 260: * Allocate a ppp interface unit and initialize it. ! 261: */ ! 262: struct ppp_softc * ! 263: pppalloc(pid) ! 264: pid_t pid; ! 265: { ! 266: int nppp, i; ! 267: struct ppp_softc *sc; ! 268: ! 269: for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) ! 270: if (sc->sc_xfer == pid) { ! 271: sc->sc_xfer = 0; ! 272: return sc; ! 273: } ! 274: for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++) ! 275: if (sc->sc_devp == NULL) ! 276: break; ! 277: if (nppp >= NPPP) ! 278: return NULL; ! 279: ! 280: sc->sc_flags = 0; ! 281: sc->sc_mru = PPP_MRU; ! 282: sc->sc_relinq = NULL; ! 283: bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats)); ! 284: #if VJC ! 285: MALLOC(sc->sc_comp, struct slcompress *, sizeof(struct slcompress), ! 286: M_DEVBUF, M_NOWAIT); ! 287: if (sc->sc_comp) ! 288: sl_compress_init(sc->sc_comp, -1); ! 289: #endif ! 290: #if PPP_COMPRESS ! 291: sc->sc_xc_state = NULL; ! 292: sc->sc_rc_state = NULL; ! 293: #endif /* PPP_COMPRESS */ ! 294: for (i = 0; i < NUM_NP; ++i) ! 295: sc->sc_npmode[i] = NPMODE_ERROR; ! 296: sc->sc_npqueue = NULL; ! 297: sc->sc_npqtail = &sc->sc_npqueue; ! 298: sc->sc_last_sent = sc->sc_last_recv = time_second; ! 299: ! 300: return sc; ! 301: } ! 302: ! 303: /* ! 304: * Deallocate a ppp unit. Must be called at splsoftnet or higher. ! 305: */ ! 306: void ! 307: pppdealloc(sc) ! 308: struct ppp_softc *sc; ! 309: { ! 310: struct mbuf *m; ! 311: ! 312: if_down(&sc->sc_if); ! 313: sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING); ! 314: getmicrotime(&sc->sc_if.if_lastchange); ! 315: sc->sc_devp = NULL; ! 316: sc->sc_xfer = 0; ! 317: for (;;) { ! 318: IF_DEQUEUE(&sc->sc_rawq, m); ! 319: if (m == NULL) ! 320: break; ! 321: m_freem(m); ! 322: } ! 323: for (;;) { ! 324: IF_DEQUEUE(&sc->sc_inq, m); ! 325: if (m == NULL) ! 326: break; ! 327: m_freem(m); ! 328: } ! 329: for (;;) { ! 330: IF_DEQUEUE(&sc->sc_fastq, m); ! 331: if (m == NULL) ! 332: break; ! 333: m_freem(m); ! 334: } ! 335: while ((m = sc->sc_npqueue) != NULL) { ! 336: sc->sc_npqueue = m->m_nextpkt; ! 337: m_freem(m); ! 338: } ! 339: #if PPP_COMPRESS ! 340: ppp_ccp_closed(sc); ! 341: sc->sc_xc_state = NULL; ! 342: sc->sc_rc_state = NULL; ! 343: #endif /* PPP_COMPRESS */ ! 344: #if PPP_FILTER ! 345: if (sc->sc_pass_filt.bf_insns != 0) { ! 346: FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF); ! 347: sc->sc_pass_filt.bf_insns = 0; ! 348: sc->sc_pass_filt.bf_len = 0; ! 349: } ! 350: if (sc->sc_active_filt.bf_insns != 0) { ! 351: FREE(sc->sc_active_filt.bf_insns, M_DEVBUF); ! 352: sc->sc_active_filt.bf_insns = 0; ! 353: sc->sc_active_filt.bf_len = 0; ! 354: } ! 355: #endif /* PPP_FILTER */ ! 356: #if VJC ! 357: if (sc->sc_comp != 0) { ! 358: FREE(sc->sc_comp, M_DEVBUF); ! 359: sc->sc_comp = 0; ! 360: } ! 361: #endif ! 362: } ! 363: ! 364: /* ! 365: * Ioctl routine for generic ppp devices. ! 366: */ ! 367: int ! 368: pppioctl(sc, cmd, data, flag, p) ! 369: struct ppp_softc *sc; ! 370: u_long cmd; ! 371: caddr_t data; ! 372: int flag; ! 373: struct proc *p; ! 374: { ! 375: int s, error, flags, mru, nb, npx; ! 376: struct ppp_option_data *odp; ! 377: struct compressor **cp; ! 378: struct npioctl *npi; ! 379: time_t t; ! 380: #if PPP_FILTER ! 381: struct bpf_program *bp, *nbp; ! 382: struct bpf_insn *newcode, *oldcode; ! 383: int newcodelen; ! 384: #endif /* PPP_FILTER */ ! 385: #if PPP_COMPRESS ! 386: u_char ccp_option[CCP_MAX_OPTION_LENGTH]; ! 387: #endif ! 388: ! 389: switch (cmd) { ! 390: case FIONREAD: ! 391: *(int *)data = sc->sc_inq.ifq_len; ! 392: break; ! 393: ! 394: case PPPIOCGUNIT: ! 395: *(int *)data = sc->sc_if.if_unit; ! 396: break; ! 397: ! 398: case PPPIOCGFLAGS: ! 399: *(u_int *)data = sc->sc_flags; ! 400: break; ! 401: ! 402: case PPPIOCSFLAGS: ! 403: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 404: return (error); ! 405: flags = *(int *)data & SC_MASK; ! 406: s = splsoftnet(); ! 407: #if PPP_COMPRESS ! 408: if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN)) ! 409: ppp_ccp_closed(sc); ! 410: #endif ! 411: splimp(); ! 412: sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags; ! 413: splx(s); ! 414: break; ! 415: ! 416: case PPPIOCSMRU: ! 417: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 418: return (error); ! 419: mru = *(int *)data; ! 420: if (mru >= PPP_MRU && mru <= PPP_MAXMRU) ! 421: sc->sc_mru = mru; ! 422: break; ! 423: ! 424: case PPPIOCGMRU: ! 425: *(int *)data = sc->sc_mru; ! 426: break; ! 427: ! 428: #if VJC ! 429: case PPPIOCSMAXCID: ! 430: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 431: return (error); ! 432: if (sc->sc_comp) { ! 433: s = splsoftnet(); ! 434: sl_compress_init(sc->sc_comp, *(int *)data); ! 435: splx(s); ! 436: } ! 437: break; ! 438: #endif ! 439: ! 440: case PPPIOCXFERUNIT: ! 441: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 442: return (error); ! 443: sc->sc_xfer = p->p_pid; ! 444: break; ! 445: ! 446: #if PPP_COMPRESS ! 447: case PPPIOCSCOMPRESS: ! 448: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 449: return (error); ! 450: odp = (struct ppp_option_data *) data; ! 451: nb = odp->length; ! 452: if (nb > sizeof(ccp_option)) ! 453: nb = sizeof(ccp_option); ! 454: if ((error = copyin(odp->ptr, ccp_option, nb)) != 0) ! 455: return (error); ! 456: if (ccp_option[1] < 2) /* preliminary check on the length byte */ ! 457: return (EINVAL); ! 458: for (cp = ppp_compressors; *cp != NULL; ++cp) ! 459: if ((*cp)->compress_proto == ccp_option[0]) { ! 460: /* ! 461: * Found a handler for the protocol - try to allocate ! 462: * a compressor or decompressor. ! 463: */ ! 464: error = 0; ! 465: if (odp->transmit) { ! 466: s = splsoftnet(); ! 467: if (sc->sc_xc_state != NULL) ! 468: (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); ! 469: sc->sc_xcomp = *cp; ! 470: sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb); ! 471: if (sc->sc_xc_state == NULL) { ! 472: if (sc->sc_flags & SC_DEBUG) ! 473: printf("ppp%d: comp_alloc failed\n", ! 474: sc->sc_if.if_unit); ! 475: error = ENOBUFS; ! 476: } ! 477: splimp(); ! 478: sc->sc_flags &= ~SC_COMP_RUN; ! 479: splx(s); ! 480: } else { ! 481: s = splsoftnet(); ! 482: if (sc->sc_rc_state != NULL) ! 483: (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); ! 484: sc->sc_rcomp = *cp; ! 485: sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb); ! 486: if (sc->sc_rc_state == NULL) { ! 487: if (sc->sc_flags & SC_DEBUG) ! 488: printf("ppp%d: decomp_alloc failed\n", ! 489: sc->sc_if.if_unit); ! 490: error = ENOBUFS; ! 491: } ! 492: splimp(); ! 493: sc->sc_flags &= ~SC_DECOMP_RUN; ! 494: splx(s); ! 495: } ! 496: return (error); ! 497: } ! 498: if (sc->sc_flags & SC_DEBUG) ! 499: printf("ppp%d: no compressor for [%x %x %x], %x\n", ! 500: sc->sc_if.if_unit, ccp_option[0], ccp_option[1], ! 501: ccp_option[2], nb); ! 502: return (EINVAL); /* no handler found */ ! 503: #endif /* PPP_COMPRESS */ ! 504: ! 505: case PPPIOCGNPMODE: ! 506: case PPPIOCSNPMODE: ! 507: npi = (struct npioctl *) data; ! 508: switch (npi->protocol) { ! 509: case PPP_IP: ! 510: npx = NP_IP; ! 511: break; ! 512: default: ! 513: return EINVAL; ! 514: } ! 515: if (cmd == PPPIOCGNPMODE) { ! 516: npi->mode = sc->sc_npmode[npx]; ! 517: } else { ! 518: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 519: return (error); ! 520: if (npi->mode != sc->sc_npmode[npx]) { ! 521: s = splsoftnet(); ! 522: sc->sc_npmode[npx] = npi->mode; ! 523: if (npi->mode != NPMODE_QUEUE) { ! 524: ppp_requeue(sc); ! 525: (*sc->sc_start)(sc); ! 526: } ! 527: splx(s); ! 528: } ! 529: } ! 530: break; ! 531: ! 532: case PPPIOCGIDLE: ! 533: s = splsoftnet(); ! 534: t = time_second; ! 535: ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent; ! 536: ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv; ! 537: splx(s); ! 538: break; ! 539: ! 540: #if PPP_FILTER ! 541: case PPPIOCSPASS: ! 542: case PPPIOCSACTIVE: ! 543: nbp = (struct bpf_program *) data; ! 544: if ((unsigned) nbp->bf_len > BPF_MAXINSNS) ! 545: return EINVAL; ! 546: newcodelen = nbp->bf_len * sizeof(struct bpf_insn); ! 547: if (newcodelen != 0) { ! 548: MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK); ! 549: if (newcode == 0) { ! 550: return EINVAL; /* or sumpin */ ! 551: } ! 552: if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode, ! 553: newcodelen)) != 0) { ! 554: FREE(newcode, M_DEVBUF); ! 555: return error; ! 556: } ! 557: if (!bpf_validate(newcode, nbp->bf_len)) { ! 558: FREE(newcode, M_DEVBUF); ! 559: return EINVAL; ! 560: } ! 561: } else ! 562: newcode = 0; ! 563: bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt; ! 564: oldcode = bp->bf_insns; ! 565: s = splimp(); ! 566: bp->bf_len = nbp->bf_len; ! 567: bp->bf_insns = newcode; ! 568: splx(s); ! 569: if (oldcode != 0) ! 570: FREE(oldcode, M_DEVBUF); ! 571: break; ! 572: #endif ! 573: ! 574: default: ! 575: return (ENOIOCTL); ! 576: } ! 577: return (0); ! 578: } ! 579: ! 580: /* ! 581: * Process an ioctl request to the ppp network interface. ! 582: */ ! 583: static int ! 584: pppsioctl(ifp, cmd, data) ! 585: register struct ifnet *ifp; ! 586: u_long cmd; ! 587: caddr_t data; ! 588: { ! 589: struct proc *p = current_proc(); /* XXX */ ! 590: register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; ! 591: register struct ifaddr *ifa = (struct ifaddr *)data; ! 592: register struct ifreq *ifr = (struct ifreq *)data; ! 593: struct ppp_stats *psp; ! 594: #if PPP_COMPRESS ! 595: struct ppp_comp_stats *pcp; ! 596: #endif ! 597: int s = splimp(), error = 0; ! 598: ! 599: switch (cmd) { ! 600: case SIOCSIFFLAGS: ! 601: if ((ifp->if_flags & IFF_RUNNING) == 0) ! 602: ifp->if_flags &= ~IFF_UP; ! 603: break; ! 604: ! 605: case SIOCSIFADDR: ! 606: case SIOCAIFADDR: ! 607: switch(ifa->ifa_addr->sa_family) { ! 608: #if INET ! 609: case AF_INET: ! 610: break; ! 611: #endif ! 612: #if IPX ! 613: case AF_IPX: ! 614: break; ! 615: #endif ! 616: default: ! 617: error = EAFNOSUPPORT; ! 618: break; ! 619: } ! 620: break; ! 621: ! 622: case SIOCSIFDSTADDR: ! 623: switch(ifa->ifa_addr->sa_family) { ! 624: #if INET ! 625: case AF_INET: ! 626: break; ! 627: #endif ! 628: #if IPX ! 629: case AF_IPX: ! 630: break; ! 631: #endif ! 632: default: ! 633: error = EAFNOSUPPORT; ! 634: break; ! 635: } ! 636: break; ! 637: ! 638: case SIOCSIFMTU: ! 639: if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 640: break; ! 641: if (ifr->ifr_mtu > PPP_MAXMTU) ! 642: error = EINVAL; ! 643: else { ! 644: sc->sc_if.if_mtu = ifr->ifr_mtu; ! 645: if (sc->sc_setmtu) ! 646: (*sc->sc_setmtu)(sc); ! 647: } ! 648: break; ! 649: ! 650: case SIOCGIFMTU: ! 651: ifr->ifr_mtu = sc->sc_if.if_mtu; ! 652: break; ! 653: ! 654: case SIOCADDMULTI: ! 655: case SIOCDELMULTI: ! 656: if (ifr == 0) { ! 657: error = EAFNOSUPPORT; ! 658: break; ! 659: } ! 660: switch(ifr->ifr_addr.sa_family) { ! 661: #if INET ! 662: case AF_INET: ! 663: break; ! 664: #endif ! 665: default: ! 666: error = EAFNOSUPPORT; ! 667: break; ! 668: } ! 669: break; ! 670: ! 671: case SIOCGPPPSTATS: ! 672: psp = &((struct ifpppstatsreq *) data)->stats; ! 673: bzero(psp, sizeof(*psp)); ! 674: psp->p = sc->sc_stats; ! 675: #if defined(VJC) && !defined(SL_NO_STATS) ! 676: if (sc->sc_comp) { ! 677: psp->vj.vjs_packets = sc->sc_comp->sls_packets; ! 678: psp->vj.vjs_compressed = sc->sc_comp->sls_compressed; ! 679: psp->vj.vjs_searches = sc->sc_comp->sls_searches; ! 680: psp->vj.vjs_misses = sc->sc_comp->sls_misses; ! 681: psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin; ! 682: psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin; ! 683: psp->vj.vjs_errorin = sc->sc_comp->sls_errorin; ! 684: psp->vj.vjs_tossed = sc->sc_comp->sls_tossed; ! 685: } ! 686: #endif /* VJC */ ! 687: break; ! 688: ! 689: #if PPP_COMPRESS ! 690: case SIOCGPPPCSTATS: ! 691: pcp = &((struct ifpppcstatsreq *) data)->stats; ! 692: bzero(pcp, sizeof(*pcp)); ! 693: if (sc->sc_xc_state != NULL) ! 694: (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c); ! 695: if (sc->sc_rc_state != NULL) ! 696: (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d); ! 697: break; ! 698: #endif /* PPP_COMPRESS */ ! 699: ! 700: default: ! 701: error = ENOTTY; ! 702: } ! 703: splx(s); ! 704: return (error); ! 705: } ! 706: ! 707: /* ! 708: * Queue a packet. Start transmission if not active. ! 709: * Packet is placed in Information field of PPP frame. ! 710: * Called at splnet as the if->if_output handler. ! 711: * Called at splnet from pppwrite(). ! 712: */ ! 713: int ! 714: pppoutput(ifp, m0, dst, rtp) ! 715: struct ifnet *ifp; ! 716: struct mbuf *m0; ! 717: struct sockaddr *dst; ! 718: struct rtentry *rtp; ! 719: { ! 720: register struct ppp_softc *sc = &ppp_softc[ifp->if_unit]; ! 721: int protocol, address, control; ! 722: u_char *cp; ! 723: int s, error; ! 724: struct ip *ip; ! 725: struct ifqueue *ifq; ! 726: enum NPmode mode; ! 727: int len; ! 728: struct mbuf *m; ! 729: ! 730: if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0 ! 731: || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) { ! 732: error = ENETDOWN; /* sort of */ ! 733: goto bad; ! 734: } ! 735: ! 736: /* ! 737: * Compute PPP header. ! 738: */ ! 739: m0->m_flags &= ~M_HIGHPRI; ! 740: switch (dst->sa_family) { ! 741: #if INET ! 742: case AF_INET: ! 743: address = PPP_ALLSTATIONS; ! 744: control = PPP_UI; ! 745: protocol = PPP_IP; ! 746: mode = sc->sc_npmode[NP_IP]; ! 747: ! 748: /* ! 749: * If this packet has the "low delay" bit set in the IP header, ! 750: * put it on the fastq instead. ! 751: */ ! 752: ip = mtod(m0, struct ip *); ! 753: if (ip->ip_tos & IPTOS_LOWDELAY) ! 754: m0->m_flags |= M_HIGHPRI; ! 755: break; ! 756: #endif ! 757: #if IPX ! 758: case AF_IPX: ! 759: /* ! 760: * This is pretty bogus.. We dont have an ipxcp module in pppd ! 761: * yet to configure the link parameters. Sigh. I guess a ! 762: * manual ifconfig would do.... -Peter ! 763: */ ! 764: address = PPP_ALLSTATIONS; ! 765: control = PPP_UI; ! 766: protocol = PPP_IPX; ! 767: mode = NPMODE_PASS; ! 768: break; ! 769: #endif ! 770: case AF_UNSPEC: ! 771: address = PPP_ADDRESS(dst->sa_data); ! 772: control = PPP_CONTROL(dst->sa_data); ! 773: protocol = PPP_PROTOCOL(dst->sa_data); ! 774: mode = NPMODE_PASS; ! 775: break; ! 776: default: ! 777: printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family); ! 778: error = EAFNOSUPPORT; ! 779: goto bad; ! 780: } ! 781: ! 782: /* ! 783: * Drop this packet, or return an error, if necessary. ! 784: */ ! 785: if (mode == NPMODE_ERROR) { ! 786: error = ENETDOWN; ! 787: goto bad; ! 788: } ! 789: if (mode == NPMODE_DROP) { ! 790: error = 0; ! 791: goto bad; ! 792: } ! 793: ! 794: /* ! 795: * Add PPP header. If no space in first mbuf, allocate another. ! 796: * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.) ! 797: */ ! 798: if (M_LEADINGSPACE(m0) < PPP_HDRLEN) { ! 799: m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT); ! 800: if (m0 == 0) { ! 801: error = ENOBUFS; ! 802: goto bad; ! 803: } ! 804: m0->m_len = 0; ! 805: } else ! 806: m0->m_data -= PPP_HDRLEN; ! 807: ! 808: cp = mtod(m0, u_char *); ! 809: *cp++ = address; ! 810: *cp++ = control; ! 811: *cp++ = protocol >> 8; ! 812: *cp++ = protocol & 0xff; ! 813: m0->m_len += PPP_HDRLEN; ! 814: ! 815: len = 0; ! 816: for (m = m0; m != 0; m = m->m_next) ! 817: len += m->m_len; ! 818: ! 819: if (sc->sc_flags & SC_LOG_OUTPKT) { ! 820: printf("ppp%d output: ", ifp->if_unit); ! 821: pppdumpm(m0); ! 822: } ! 823: ! 824: if ((protocol & 0x8000) == 0) { ! 825: #if PPP_FILTER ! 826: /* ! 827: * Apply the pass and active filters to the packet, ! 828: * but only if it is a data packet. ! 829: */ ! 830: *mtod(m0, u_char *) = 1; /* indicates outbound */ ! 831: if (sc->sc_pass_filt.bf_insns != 0 ! 832: && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0, ! 833: len, 0) == 0) { ! 834: error = 0; /* drop this packet */ ! 835: goto bad; ! 836: } ! 837: ! 838: /* ! 839: * Update the time we sent the most recent packet. ! 840: */ ! 841: if (sc->sc_active_filt.bf_insns == 0 ! 842: || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0)) ! 843: sc->sc_last_sent = time_second; ! 844: ! 845: *mtod(m0, u_char *) = address; ! 846: #else ! 847: /* ! 848: * Update the time we sent the most recent data packet. ! 849: */ ! 850: sc->sc_last_sent = time_second; ! 851: #endif /* PPP_FILTER */ ! 852: } ! 853: ! 854: #if NBPFILTER > 0 ! 855: /* ! 856: * See if bpf wants to look at the packet. ! 857: */ ! 858: if (ifp->if_bpf) ! 859: bpf_mtap(ifp, m0); ! 860: #endif ! 861: ! 862: /* ! 863: * Put the packet on the appropriate queue. ! 864: */ ! 865: s = splsoftnet(); /* redundant */ ! 866: if (mode == NPMODE_QUEUE) { ! 867: /* XXX we should limit the number of packets on this queue */ ! 868: *sc->sc_npqtail = m0; ! 869: m0->m_nextpkt = NULL; ! 870: sc->sc_npqtail = &m0->m_nextpkt; ! 871: } else { ! 872: /* fastq and if_snd are emptied at spl[soft]net now */ ! 873: ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd; ! 874: if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) { ! 875: IF_DROP(ifq); ! 876: splx(s); ! 877: sc->sc_if.if_oerrors++; ! 878: sc->sc_stats.ppp_oerrors++; ! 879: error = ENOBUFS; ! 880: goto bad; ! 881: } ! 882: IF_ENQUEUE(ifq, m0); ! 883: (*sc->sc_start)(sc); ! 884: } ! 885: getmicrotime(&ifp->if_lastchange); ! 886: ifp->if_opackets++; ! 887: ifp->if_obytes += len; ! 888: ! 889: splx(s); ! 890: return (0); ! 891: ! 892: bad: ! 893: m_freem(m0); ! 894: return (error); ! 895: } ! 896: ! 897: /* ! 898: * After a change in the NPmode for some NP, move packets from the ! 899: * npqueue to the send queue or the fast queue as appropriate. ! 900: * Should be called at spl[soft]net. ! 901: */ ! 902: static void ! 903: ppp_requeue(sc) ! 904: struct ppp_softc *sc; ! 905: { ! 906: struct mbuf *m, **mpp; ! 907: struct ifqueue *ifq; ! 908: enum NPmode mode; ! 909: ! 910: for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) { ! 911: switch (PPP_PROTOCOL(mtod(m, u_char *))) { ! 912: case PPP_IP: ! 913: mode = sc->sc_npmode[NP_IP]; ! 914: break; ! 915: default: ! 916: mode = NPMODE_PASS; ! 917: } ! 918: ! 919: switch (mode) { ! 920: case NPMODE_PASS: ! 921: /* ! 922: * This packet can now go on one of the queues to be sent. ! 923: */ ! 924: *mpp = m->m_nextpkt; ! 925: m->m_nextpkt = NULL; ! 926: ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd; ! 927: if (IF_QFULL(ifq)) { ! 928: IF_DROP(ifq); ! 929: sc->sc_if.if_oerrors++; ! 930: sc->sc_stats.ppp_oerrors++; ! 931: } else ! 932: IF_ENQUEUE(ifq, m); ! 933: break; ! 934: ! 935: case NPMODE_DROP: ! 936: case NPMODE_ERROR: ! 937: *mpp = m->m_nextpkt; ! 938: m_freem(m); ! 939: break; ! 940: ! 941: case NPMODE_QUEUE: ! 942: mpp = &m->m_nextpkt; ! 943: break; ! 944: } ! 945: } ! 946: sc->sc_npqtail = mpp; ! 947: } ! 948: ! 949: /* ! 950: * Transmitter has finished outputting some stuff; ! 951: * remember to call sc->sc_start later at splsoftnet. ! 952: */ ! 953: void ! 954: ppp_restart(sc) ! 955: struct ppp_softc *sc; ! 956: { ! 957: int s = splimp(); ! 958: ! 959: sc->sc_flags &= ~SC_TBUSY; ! 960: schednetisr(NETISR_PPP); ! 961: splx(s); ! 962: } ! 963: ! 964: ! 965: /* ! 966: * Get a packet to send. This procedure is intended to be called at ! 967: * splsoftnet, since it may involve time-consuming operations such as ! 968: * applying VJ compression, packet compression, address/control and/or ! 969: * protocol field compression to the packet. ! 970: */ ! 971: struct mbuf * ! 972: ppp_dequeue(sc) ! 973: struct ppp_softc *sc; ! 974: { ! 975: struct mbuf *m, *mp; ! 976: u_char *cp; ! 977: int address, control, protocol; ! 978: ! 979: /* ! 980: * Grab a packet to send: first try the fast queue, then the ! 981: * normal queue. ! 982: */ ! 983: IF_DEQUEUE(&sc->sc_fastq, m); ! 984: if (m == NULL) ! 985: IF_DEQUEUE(&sc->sc_if.if_snd, m); ! 986: if (m == NULL) ! 987: return NULL; ! 988: ! 989: ++sc->sc_stats.ppp_opackets; ! 990: ! 991: /* ! 992: * Extract the ppp header of the new packet. ! 993: * The ppp header will be in one mbuf. ! 994: */ ! 995: cp = mtod(m, u_char *); ! 996: address = PPP_ADDRESS(cp); ! 997: control = PPP_CONTROL(cp); ! 998: protocol = PPP_PROTOCOL(cp); ! 999: ! 1000: switch (protocol) { ! 1001: case PPP_IP: ! 1002: #if VJC ! 1003: /* ! 1004: * If the packet is a TCP/IP packet, see if we can compress it. ! 1005: */ ! 1006: if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) { ! 1007: struct ip *ip; ! 1008: int type; ! 1009: ! 1010: mp = m; ! 1011: ip = (struct ip *) (cp + PPP_HDRLEN); ! 1012: if (mp->m_len <= PPP_HDRLEN) { ! 1013: mp = mp->m_next; ! 1014: if (mp == NULL) ! 1015: break; ! 1016: ip = mtod(mp, struct ip *); ! 1017: } ! 1018: /* this code assumes the IP/TCP header is in one non-shared mbuf */ ! 1019: if (ip->ip_p == IPPROTO_TCP) { ! 1020: type = sl_compress_tcp(mp, ip, sc->sc_comp, ! 1021: !(sc->sc_flags & SC_NO_TCP_CCID)); ! 1022: switch (type) { ! 1023: case TYPE_UNCOMPRESSED_TCP: ! 1024: protocol = PPP_VJC_UNCOMP; ! 1025: break; ! 1026: case TYPE_COMPRESSED_TCP: ! 1027: protocol = PPP_VJC_COMP; ! 1028: cp = mtod(m, u_char *); ! 1029: cp[0] = address; /* header has moved */ ! 1030: cp[1] = control; ! 1031: cp[2] = 0; ! 1032: break; ! 1033: } ! 1034: cp[3] = protocol; /* update protocol in PPP header */ ! 1035: } ! 1036: } ! 1037: #endif /* VJC */ ! 1038: break; ! 1039: ! 1040: #if PPP_COMPRESS ! 1041: case PPP_CCP: ! 1042: ppp_ccp(sc, m, 0); ! 1043: break; ! 1044: #endif /* PPP_COMPRESS */ ! 1045: } ! 1046: ! 1047: #if PPP_COMPRESS ! 1048: if (protocol != PPP_LCP && protocol != PPP_CCP ! 1049: && sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) { ! 1050: struct mbuf *mcomp = NULL; ! 1051: int slen, clen; ! 1052: ! 1053: slen = 0; ! 1054: for (mp = m; mp != NULL; mp = mp->m_next) ! 1055: slen += mp->m_len; ! 1056: clen = (*sc->sc_xcomp->compress) ! 1057: (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN); ! 1058: if (mcomp != NULL) { ! 1059: if (sc->sc_flags & SC_CCP_UP) { ! 1060: /* Send the compressed packet instead of the original. */ ! 1061: m_freem(m); ! 1062: m = mcomp; ! 1063: cp = mtod(m, u_char *); ! 1064: protocol = cp[3]; ! 1065: } else { ! 1066: /* Can't transmit compressed packets until CCP is up. */ ! 1067: m_freem(mcomp); ! 1068: } ! 1069: } ! 1070: } ! 1071: #endif /* PPP_COMPRESS */ ! 1072: ! 1073: /* ! 1074: * Compress the address/control and protocol, if possible. ! 1075: */ ! 1076: if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS && ! 1077: control == PPP_UI && protocol != PPP_ALLSTATIONS && ! 1078: protocol != PPP_LCP) { ! 1079: /* can compress address/control */ ! 1080: m->m_data += 2; ! 1081: m->m_len -= 2; ! 1082: } ! 1083: if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) { ! 1084: /* can compress protocol */ ! 1085: if (mtod(m, u_char *) == cp) { ! 1086: cp[2] = cp[1]; /* move address/control up */ ! 1087: cp[1] = cp[0]; ! 1088: } ! 1089: ++m->m_data; ! 1090: --m->m_len; ! 1091: } ! 1092: ! 1093: return m; ! 1094: } ! 1095: ! 1096: /* ! 1097: * Software interrupt routine, called at spl[soft]net. ! 1098: */ ! 1099: static void ! 1100: pppintr() ! 1101: { ! 1102: struct ppp_softc *sc; ! 1103: int i, s; ! 1104: struct mbuf *m; ! 1105: ! 1106: sc = ppp_softc; ! 1107: for (i = 0; i < NPPP; ++i, ++sc) { ! 1108: s = splimp(); ! 1109: if (!(sc->sc_flags & SC_TBUSY) ! 1110: && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) { ! 1111: sc->sc_flags |= SC_TBUSY; ! 1112: splx(s); ! 1113: (*sc->sc_start)(sc); ! 1114: } else ! 1115: splx(s); ! 1116: for (;;) { ! 1117: s = splimp(); ! 1118: IF_DEQUEUE(&sc->sc_rawq, m); ! 1119: splx(s); ! 1120: if (m == NULL) ! 1121: break; ! 1122: ppp_inproc(sc, m); ! 1123: } ! 1124: } ! 1125: } ! 1126: ! 1127: #if PPP_COMPRESS ! 1128: /* ! 1129: * Handle a CCP packet. `rcvd' is 1 if the packet was received, ! 1130: * 0 if it is about to be transmitted. ! 1131: */ ! 1132: static void ! 1133: ppp_ccp(sc, m, rcvd) ! 1134: struct ppp_softc *sc; ! 1135: struct mbuf *m; ! 1136: int rcvd; ! 1137: { ! 1138: u_char *dp, *ep; ! 1139: struct mbuf *mp; ! 1140: int slen, s; ! 1141: ! 1142: /* ! 1143: * Get a pointer to the data after the PPP header. ! 1144: */ ! 1145: if (m->m_len <= PPP_HDRLEN) { ! 1146: mp = m->m_next; ! 1147: if (mp == NULL) ! 1148: return; ! 1149: dp = (mp != NULL)? mtod(mp, u_char *): NULL; ! 1150: } else { ! 1151: mp = m; ! 1152: dp = mtod(mp, u_char *) + PPP_HDRLEN; ! 1153: } ! 1154: ! 1155: ep = mtod(mp, u_char *) + mp->m_len; ! 1156: if (dp + CCP_HDRLEN > ep) ! 1157: return; ! 1158: slen = CCP_LENGTH(dp); ! 1159: if (dp + slen > ep) { ! 1160: if (sc->sc_flags & SC_DEBUG) ! 1161: printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n", ! 1162: dp, slen, mtod(mp, u_char *), mp->m_len); ! 1163: return; ! 1164: } ! 1165: ! 1166: switch (CCP_CODE(dp)) { ! 1167: case CCP_CONFREQ: ! 1168: case CCP_TERMREQ: ! 1169: case CCP_TERMACK: ! 1170: /* CCP must be going down - disable compression */ ! 1171: if (sc->sc_flags & SC_CCP_UP) { ! 1172: s = splimp(); ! 1173: sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN); ! 1174: splx(s); ! 1175: } ! 1176: break; ! 1177: ! 1178: case CCP_CONFACK: ! 1179: if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP) ! 1180: && slen >= CCP_HDRLEN + CCP_OPT_MINLEN ! 1181: && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) { ! 1182: if (!rcvd) { ! 1183: /* we're agreeing to send compressed packets. */ ! 1184: if (sc->sc_xc_state != NULL ! 1185: && (*sc->sc_xcomp->comp_init) ! 1186: (sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, ! 1187: sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) { ! 1188: s = splimp(); ! 1189: sc->sc_flags |= SC_COMP_RUN; ! 1190: splx(s); ! 1191: } ! 1192: } else { ! 1193: /* peer is agreeing to send compressed packets. */ ! 1194: if (sc->sc_rc_state != NULL ! 1195: && (*sc->sc_rcomp->decomp_init) ! 1196: (sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN, ! 1197: sc->sc_if.if_unit, 0, sc->sc_mru, ! 1198: sc->sc_flags & SC_DEBUG)) { ! 1199: s = splimp(); ! 1200: sc->sc_flags |= SC_DECOMP_RUN; ! 1201: sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR); ! 1202: splx(s); ! 1203: } ! 1204: } ! 1205: } ! 1206: break; ! 1207: ! 1208: case CCP_RESETACK: ! 1209: if (sc->sc_flags & SC_CCP_UP) { ! 1210: if (!rcvd) { ! 1211: if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) ! 1212: (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state); ! 1213: } else { ! 1214: if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { ! 1215: (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state); ! 1216: s = splimp(); ! 1217: sc->sc_flags &= ~SC_DC_ERROR; ! 1218: splx(s); ! 1219: } ! 1220: } ! 1221: } ! 1222: break; ! 1223: } ! 1224: } ! 1225: ! 1226: /* ! 1227: * CCP is down; free (de)compressor state if necessary. ! 1228: */ ! 1229: static void ! 1230: ppp_ccp_closed(sc) ! 1231: struct ppp_softc *sc; ! 1232: { ! 1233: if (sc->sc_xc_state) { ! 1234: (*sc->sc_xcomp->comp_free)(sc->sc_xc_state); ! 1235: sc->sc_xc_state = NULL; ! 1236: } ! 1237: if (sc->sc_rc_state) { ! 1238: (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state); ! 1239: sc->sc_rc_state = NULL; ! 1240: } ! 1241: } ! 1242: #endif /* PPP_COMPRESS */ ! 1243: ! 1244: /* ! 1245: * PPP packet input routine. ! 1246: * The caller has checked and removed the FCS and has inserted ! 1247: * the address/control bytes and the protocol high byte if they ! 1248: * were omitted. ! 1249: */ ! 1250: void ! 1251: ppppktin(sc, m, lost) ! 1252: struct ppp_softc *sc; ! 1253: struct mbuf *m; ! 1254: int lost; ! 1255: { ! 1256: int s = splimp(); ! 1257: ! 1258: if (lost) ! 1259: m->m_flags |= M_ERRMARK; ! 1260: IF_ENQUEUE(&sc->sc_rawq, m); ! 1261: schednetisr(NETISR_PPP); ! 1262: splx(s); ! 1263: } ! 1264: ! 1265: /* ! 1266: * Process a received PPP packet, doing decompression as necessary. ! 1267: * Should be called at splsoftnet. ! 1268: */ ! 1269: #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \ ! 1270: TYPE_UNCOMPRESSED_TCP) ! 1271: ! 1272: static void ! 1273: ppp_inproc(sc, m) ! 1274: struct ppp_softc *sc; ! 1275: struct mbuf *m; ! 1276: { ! 1277: struct ifnet *ifp = &sc->sc_if; ! 1278: struct ifqueue *inq; ! 1279: int s, ilen = 0, xlen, proto, rv; ! 1280: u_char *cp, adrs, ctrl; ! 1281: struct mbuf *mp, *dmp = NULL; ! 1282: u_char *iphdr; ! 1283: u_int hlen; ! 1284: ! 1285: sc->sc_stats.ppp_ipackets++; ! 1286: ! 1287: if (sc->sc_flags & SC_LOG_INPKT) { ! 1288: ilen = 0; ! 1289: for (mp = m; mp != NULL; mp = mp->m_next) ! 1290: ilen += mp->m_len; ! 1291: printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen); ! 1292: pppdumpm(m); ! 1293: } ! 1294: ! 1295: cp = mtod(m, u_char *); ! 1296: adrs = PPP_ADDRESS(cp); ! 1297: ctrl = PPP_CONTROL(cp); ! 1298: proto = PPP_PROTOCOL(cp); ! 1299: ! 1300: if (m->m_flags & M_ERRMARK) { ! 1301: m->m_flags &= ~M_ERRMARK; ! 1302: s = splimp(); ! 1303: sc->sc_flags |= SC_VJ_RESET; ! 1304: splx(s); ! 1305: } ! 1306: ! 1307: #if PPP_COMPRESS ! 1308: /* ! 1309: * Decompress this packet if necessary, update the receiver's ! 1310: * dictionary, or take appropriate action on a CCP packet. ! 1311: */ ! 1312: if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN) ! 1313: && !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) { ! 1314: /* decompress this packet */ ! 1315: rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp); ! 1316: if (rv == DECOMP_OK) { ! 1317: m_freem(m); ! 1318: if (dmp == NULL) { ! 1319: /* no error, but no decompressed packet produced */ ! 1320: return; ! 1321: } ! 1322: m = dmp; ! 1323: cp = mtod(m, u_char *); ! 1324: proto = PPP_PROTOCOL(cp); ! 1325: ! 1326: } else { ! 1327: /* ! 1328: * An error has occurred in decompression. ! 1329: * Pass the compressed packet up to pppd, which may take ! 1330: * CCP down or issue a Reset-Req. ! 1331: */ ! 1332: if (sc->sc_flags & SC_DEBUG) ! 1333: printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv); ! 1334: s = splimp(); ! 1335: sc->sc_flags |= SC_VJ_RESET; ! 1336: if (rv == DECOMP_ERROR) ! 1337: sc->sc_flags |= SC_DC_ERROR; ! 1338: else ! 1339: sc->sc_flags |= SC_DC_FERROR; ! 1340: splx(s); ! 1341: } ! 1342: ! 1343: } else { ! 1344: if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) { ! 1345: (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m); ! 1346: } ! 1347: if (proto == PPP_CCP) { ! 1348: ppp_ccp(sc, m, 1); ! 1349: } ! 1350: } ! 1351: #endif ! 1352: ! 1353: ilen = 0; ! 1354: for (mp = m; mp != NULL; mp = mp->m_next) ! 1355: ilen += mp->m_len; ! 1356: ! 1357: #if VJC ! 1358: if (sc->sc_flags & SC_VJ_RESET) { ! 1359: /* ! 1360: * If we've missed a packet, we must toss subsequent compressed ! 1361: * packets which don't have an explicit connection ID. ! 1362: */ ! 1363: if (sc->sc_comp) ! 1364: sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp); ! 1365: s = splimp(); ! 1366: sc->sc_flags &= ~SC_VJ_RESET; ! 1367: splx(s); ! 1368: } ! 1369: ! 1370: /* ! 1371: * See if we have a VJ-compressed packet to uncompress. ! 1372: */ ! 1373: if (proto == PPP_VJC_COMP) { ! 1374: if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) ! 1375: goto bad; ! 1376: ! 1377: xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, ! 1378: ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP, ! 1379: sc->sc_comp, &iphdr, &hlen); ! 1380: ! 1381: if (xlen <= 0) { ! 1382: if (sc->sc_flags & SC_DEBUG) ! 1383: printf("ppp%d: VJ uncompress failed on type comp\n", ! 1384: ifp->if_unit); ! 1385: goto bad; ! 1386: } ! 1387: ! 1388: /* Copy the PPP and IP headers into a new mbuf. */ ! 1389: MGETHDR(mp, M_DONTWAIT, MT_DATA); ! 1390: if (mp == NULL) ! 1391: goto bad; ! 1392: mp->m_len = 0; ! 1393: mp->m_next = NULL; ! 1394: if (hlen + PPP_HDRLEN > MHLEN) { ! 1395: MCLGET(mp, M_DONTWAIT); ! 1396: if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) { ! 1397: m_freem(mp); ! 1398: goto bad; /* lose if big headers and no clusters */ ! 1399: } ! 1400: } ! 1401: cp = mtod(mp, u_char *); ! 1402: cp[0] = adrs; ! 1403: cp[1] = ctrl; ! 1404: cp[2] = 0; ! 1405: cp[3] = PPP_IP; ! 1406: proto = PPP_IP; ! 1407: bcopy(iphdr, cp + PPP_HDRLEN, hlen); ! 1408: mp->m_len = hlen + PPP_HDRLEN; ! 1409: ! 1410: /* ! 1411: * Trim the PPP and VJ headers off the old mbuf ! 1412: * and stick the new and old mbufs together. ! 1413: */ ! 1414: m->m_data += PPP_HDRLEN + xlen; ! 1415: m->m_len -= PPP_HDRLEN + xlen; ! 1416: if (m->m_len <= M_TRAILINGSPACE(mp)) { ! 1417: bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len); ! 1418: mp->m_len += m->m_len; ! 1419: MFREE(m, mp->m_next); ! 1420: } else ! 1421: mp->m_next = m; ! 1422: m = mp; ! 1423: ilen += hlen - xlen; ! 1424: ! 1425: } else if (proto == PPP_VJC_UNCOMP) { ! 1426: if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0) ! 1427: goto bad; ! 1428: ! 1429: xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN, ! 1430: ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP, ! 1431: sc->sc_comp, &iphdr, &hlen); ! 1432: ! 1433: if (xlen < 0) { ! 1434: if (sc->sc_flags & SC_DEBUG) ! 1435: printf("ppp%d: VJ uncompress failed on type uncomp\n", ! 1436: ifp->if_unit); ! 1437: goto bad; ! 1438: } ! 1439: ! 1440: proto = PPP_IP; ! 1441: cp[3] = PPP_IP; ! 1442: } ! 1443: #endif /* VJC */ ! 1444: ! 1445: /* ! 1446: * If the packet will fit in a header mbuf, don't waste a ! 1447: * whole cluster on it. ! 1448: */ ! 1449: if (ilen <= MHLEN && M_IS_CLUSTER(m)) { ! 1450: MGETHDR(mp, M_DONTWAIT, MT_DATA); ! 1451: if (mp != NULL) { ! 1452: m_copydata(m, 0, ilen, mtod(mp, caddr_t)); ! 1453: m_freem(m); ! 1454: m = mp; ! 1455: m->m_len = ilen; ! 1456: } ! 1457: } ! 1458: m->m_pkthdr.len = ilen; ! 1459: m->m_pkthdr.rcvif = ifp; ! 1460: ! 1461: if ((proto & 0x8000) == 0) { ! 1462: #if PPP_FILTER ! 1463: /* ! 1464: * See whether we want to pass this packet, and ! 1465: * if it counts as link activity. ! 1466: */ ! 1467: adrs = *mtod(m, u_char *); /* save address field */ ! 1468: *mtod(m, u_char *) = 0; /* indicate inbound */ ! 1469: if (sc->sc_pass_filt.bf_insns != 0 ! 1470: && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m, ! 1471: ilen, 0) == 0) { ! 1472: /* drop this packet */ ! 1473: m_freem(m); ! 1474: return; ! 1475: } ! 1476: if (sc->sc_active_filt.bf_insns == 0 ! 1477: || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0)) ! 1478: sc->sc_last_recv = time_second; ! 1479: ! 1480: *mtod(m, u_char *) = adrs; ! 1481: #else ! 1482: /* ! 1483: * Record the time that we received this packet. ! 1484: */ ! 1485: sc->sc_last_recv = time_second; ! 1486: #endif /* PPP_FILTER */ ! 1487: } ! 1488: ! 1489: #if NBPFILTER > 0 ! 1490: /* See if bpf wants to look at the packet. */ ! 1491: if (sc->sc_if.if_bpf) ! 1492: bpf_mtap(&sc->sc_if, m); ! 1493: #endif ! 1494: ! 1495: rv = 0; ! 1496: switch (proto) { ! 1497: #if INET ! 1498: case PPP_IP: ! 1499: /* ! 1500: * IP packet - take off the ppp header and pass it up to IP. ! 1501: */ ! 1502: if ((ifp->if_flags & IFF_UP) == 0 ! 1503: || sc->sc_npmode[NP_IP] != NPMODE_PASS) { ! 1504: /* interface is down - drop the packet. */ ! 1505: m_freem(m); ! 1506: return; ! 1507: } ! 1508: m->m_pkthdr.len -= PPP_HDRLEN; ! 1509: m->m_data += PPP_HDRLEN; ! 1510: m->m_len -= PPP_HDRLEN; ! 1511: if (ipflow_fastforward(m)) { ! 1512: sc->sc_last_recv = time_second; ! 1513: return; ! 1514: } ! 1515: schednetisr(NETISR_IP); ! 1516: inq = &ipintrq; ! 1517: sc->sc_last_recv = time_second; /* update time of last pkt rcvd */ ! 1518: break; ! 1519: #endif ! 1520: #if IPX ! 1521: case PPP_IPX: ! 1522: /* ! 1523: * IPX packet - take off the ppp header and pass it up to IPX. ! 1524: */ ! 1525: if ((sc->sc_if.if_flags & IFF_UP) == 0 ! 1526: /* XXX: || sc->sc_npmode[NP_IPX] != NPMODE_PASS*/) { ! 1527: /* interface is down - drop the packet. */ ! 1528: m_freem(m); ! 1529: return; ! 1530: } ! 1531: m->m_pkthdr.len -= PPP_HDRLEN; ! 1532: m->m_data += PPP_HDRLEN; ! 1533: m->m_len -= PPP_HDRLEN; ! 1534: schednetisr(NETISR_IPX); ! 1535: inq = &ipxintrq; ! 1536: sc->sc_last_recv = time_second; /* update time of last pkt rcvd */ ! 1537: break; ! 1538: #endif ! 1539: ! 1540: default: ! 1541: /* ! 1542: * Some other protocol - place on input queue for read(). ! 1543: */ ! 1544: inq = &sc->sc_inq; ! 1545: rv = 1; ! 1546: break; ! 1547: } ! 1548: ! 1549: /* ! 1550: * Put the packet on the appropriate input queue. ! 1551: */ ! 1552: s = splimp(); ! 1553: if (IF_QFULL(inq)) { ! 1554: IF_DROP(inq); ! 1555: splx(s); ! 1556: if (sc->sc_flags & SC_DEBUG) ! 1557: printf("ppp%d: input queue full\n", ifp->if_unit); ! 1558: ifp->if_iqdrops++; ! 1559: goto bad; ! 1560: } ! 1561: IF_ENQUEUE(inq, m); ! 1562: splx(s); ! 1563: ifp->if_ipackets++; ! 1564: ifp->if_ibytes += ilen; ! 1565: getmicrotime(&ifp->if_lastchange); ! 1566: ! 1567: if (rv) ! 1568: (*sc->sc_ctlp)(sc); ! 1569: ! 1570: return; ! 1571: ! 1572: bad: ! 1573: m_freem(m); ! 1574: sc->sc_if.if_ierrors++; ! 1575: sc->sc_stats.ppp_ierrors++; ! 1576: } ! 1577: ! 1578: #define MAX_DUMP_BYTES 128 ! 1579: ! 1580: static void ! 1581: pppdumpm(m0) ! 1582: struct mbuf *m0; ! 1583: { ! 1584: char buf[3*MAX_DUMP_BYTES+4]; ! 1585: char *bp = buf; ! 1586: struct mbuf *m; ! 1587: ! 1588: for (m = m0; m; m = m->m_next) { ! 1589: int l = m->m_len; ! 1590: u_char *rptr = (u_char *)m->m_data; ! 1591: ! 1592: while (l--) { ! 1593: if (bp > buf + sizeof(buf) - 4) ! 1594: goto done; ! 1595: *bp++ = hex2ascii(*rptr >> 4); ! 1596: *bp++ = hex2ascii(*rptr++ & 0xf); ! 1597: } ! 1598: ! 1599: if (m->m_next) { ! 1600: if (bp > buf + sizeof(buf) - 3) ! 1601: goto done; ! 1602: *bp++ = '|'; ! 1603: } else ! 1604: *bp++ = ' '; ! 1605: } ! 1606: done: ! 1607: if (m) ! 1608: *bp++ = '>'; ! 1609: *bp = 0; ! 1610: printf("%s\n", buf); ! 1611: } ! 1612: ! 1613: #endif /* NPPP > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.