[BACK]Return to if_ppp.c CVS log [TXT][DIR] Up to [local] / sys / net

Annotation of sys/net/if_ppp.c, Revision 1.1.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