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