LCOV - code coverage report
Current view: top level - net - if_ppp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 736 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_ppp.c,v 1.111 2018/02/19 08:59:52 mpi 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_var.h>
     124             : #include <net/if_types.h>
     125             : #include <net/netisr.h>
     126             : #include <net/route.h>
     127             : #include <net/bpf.h>
     128             : 
     129             : #include <netinet/in.h>
     130             : #include <netinet/ip.h>
     131             : 
     132             : #include "bpfilter.h"
     133             : 
     134             : #ifdef VJC
     135             : #include <net/slcompress.h>
     136             : #endif
     137             : 
     138             : #include <net/ppp_defs.h>
     139             : #include <net/if_ppp.h>
     140             : #include <net/if_pppvar.h>
     141             : 
     142             : #ifdef PPP_COMPRESS
     143             : #define PACKETPTR       struct mbuf *
     144             : #include <net/ppp-comp.h>
     145             : #endif
     146             : 
     147             : static int       pppsioctl(struct ifnet *, u_long, caddr_t);
     148             : static void      ppp_requeue(struct ppp_softc *);
     149             : static void      ppp_ccp(struct ppp_softc *, struct mbuf *m, int rcvd);
     150             : static void      ppp_ccp_closed(struct ppp_softc *);
     151             : static void      ppp_inproc(struct ppp_softc *, struct mbuf *);
     152             : static void      pppdumpm(struct mbuf *m0);
     153             : static void      ppp_ifstart(struct ifnet *ifp);
     154             : int              ppp_clone_create(struct if_clone *, int);
     155             : int              ppp_clone_destroy(struct ifnet *);
     156             : 
     157             : void             ppp_pkt_list_init(struct ppp_pkt_list *, u_int);
     158             : int              ppp_pkt_enqueue(struct ppp_pkt_list *, struct ppp_pkt *);
     159             : struct ppp_pkt  *ppp_pkt_dequeue(struct ppp_pkt_list *);
     160             : struct mbuf     *ppp_pkt_mbuf(struct ppp_pkt *);
     161             : 
     162             : /*
     163             :  * We steal two bits in the mbuf m_flags, to mark high-priority packets
     164             :  * for output, and received packets following lost/corrupted packets.
     165             :  */
     166             : #define M_ERRMARK       M_LINK0         /* steal a bit in mbuf m_flags */
     167             : 
     168             : 
     169             : #ifdef PPP_COMPRESS
     170             : /*
     171             :  * List of compressors we know about.
     172             :  */
     173             : 
     174             : extern struct compressor ppp_bsd_compress;
     175             : extern struct compressor ppp_deflate, ppp_deflate_draft;
     176             : 
     177             : struct compressor *ppp_compressors[] = {
     178             : #if DO_BSD_COMPRESS && defined(PPP_BSDCOMP)
     179             :         &ppp_bsd_compress,
     180             : #endif
     181             : #if DO_DEFLATE && defined(PPP_DEFLATE)
     182             :         &ppp_deflate,
     183             :         &ppp_deflate_draft,
     184             : #endif
     185             :         NULL
     186             : };
     187             : #endif /* PPP_COMPRESS */
     188             : 
     189             : LIST_HEAD(, ppp_softc) ppp_softc_list;
     190             : struct if_clone ppp_cloner =
     191             :     IF_CLONE_INITIALIZER("ppp", ppp_clone_create, ppp_clone_destroy);
     192             : 
     193             : /*
     194             :  * Called from boot code to establish ppp interfaces.
     195             :  */
     196             : void
     197           0 : pppattach(void)
     198             : {
     199           0 :         LIST_INIT(&ppp_softc_list);
     200           0 :         if_clone_attach(&ppp_cloner);
     201           0 : }
     202             : 
     203             : int
     204           0 : ppp_clone_create(struct if_clone *ifc, int unit)
     205             : {
     206             :         struct ppp_softc *sc;
     207             : 
     208           0 :         sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
     209           0 :         sc->sc_unit = unit;
     210           0 :         snprintf(sc->sc_if.if_xname, sizeof sc->sc_if.if_xname, "%s%d",
     211           0 :             ifc->ifc_name, unit);
     212           0 :         sc->sc_if.if_softc = sc;
     213           0 :         sc->sc_if.if_mtu = PPP_MTU;
     214           0 :         sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
     215           0 :         sc->sc_if.if_type = IFT_PPP;
     216           0 :         sc->sc_if.if_hdrlen = PPP_HDRLEN;
     217           0 :         sc->sc_if.if_ioctl = pppsioctl;
     218           0 :         sc->sc_if.if_output = pppoutput;
     219           0 :         sc->sc_if.if_start = ppp_ifstart;
     220           0 :         sc->sc_if.if_rtrequest = p2p_rtrequest;
     221           0 :         IFQ_SET_MAXLEN(&sc->sc_if.if_snd, IFQ_MAXLEN);
     222           0 :         mq_init(&sc->sc_inq, IFQ_MAXLEN, IPL_NET);
     223           0 :         ppp_pkt_list_init(&sc->sc_rawq, IFQ_MAXLEN);
     224           0 :         if_attach(&sc->sc_if);
     225           0 :         if_alloc_sadl(&sc->sc_if);
     226             : #if NBPFILTER > 0
     227           0 :         bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
     228             : #endif
     229           0 :         NET_LOCK();
     230           0 :         LIST_INSERT_HEAD(&ppp_softc_list, sc, sc_list);
     231           0 :         NET_UNLOCK();
     232             : 
     233           0 :         return (0);
     234             : }
     235             : 
     236             : int
     237           0 : ppp_clone_destroy(struct ifnet *ifp)
     238             : {
     239           0 :         struct ppp_softc *sc = ifp->if_softc;
     240             : 
     241           0 :         if (sc->sc_devp != NULL)
     242           0 :                 return (EBUSY);
     243             : 
     244           0 :         NET_LOCK();
     245           0 :         LIST_REMOVE(sc, sc_list);
     246           0 :         NET_UNLOCK();
     247             : 
     248           0 :         if_detach(ifp);
     249             : 
     250           0 :         free(sc, M_DEVBUF, 0);
     251           0 :         return (0);
     252           0 : }
     253             : 
     254             : /*
     255             :  * Allocate a ppp interface unit and initialize it.
     256             :  */
     257             : struct ppp_softc *
     258           0 : pppalloc(pid_t pid)
     259             : {
     260             :         int i;
     261             :         struct ppp_softc *sc;
     262             : 
     263           0 :         NET_LOCK();
     264           0 :         LIST_FOREACH(sc, &ppp_softc_list, sc_list) {
     265           0 :                 if (sc->sc_xfer == pid) {
     266           0 :                         sc->sc_xfer = 0;
     267           0 :                         NET_UNLOCK();
     268           0 :                         return sc;
     269             :                 }
     270             :         }
     271           0 :         LIST_FOREACH(sc, &ppp_softc_list, sc_list) {
     272           0 :                 if (sc->sc_devp == NULL)
     273             :                         break;
     274             :         }
     275           0 :         NET_UNLOCK();
     276           0 :         if (sc == NULL)
     277           0 :                 return NULL;
     278             : 
     279           0 :         sc->sc_flags = 0;
     280           0 :         sc->sc_mru = PPP_MRU;
     281           0 :         sc->sc_relinq = NULL;
     282           0 :         bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
     283             : #ifdef VJC
     284           0 :         sc->sc_comp = malloc(sizeof(struct slcompress), M_DEVBUF, M_NOWAIT);
     285           0 :         if (sc->sc_comp)
     286           0 :                 sl_compress_init(sc->sc_comp);
     287             : #endif
     288             : #ifdef PPP_COMPRESS
     289           0 :         sc->sc_xc_state = NULL;
     290           0 :         sc->sc_rc_state = NULL;
     291             : #endif /* PPP_COMPRESS */
     292           0 :         for (i = 0; i < NUM_NP; ++i)
     293           0 :                 sc->sc_npmode[i] = NPMODE_ERROR;
     294           0 :         ml_init(&sc->sc_npqueue);
     295           0 :         sc->sc_last_sent = sc->sc_last_recv = time_uptime;
     296             : 
     297           0 :         return sc;
     298           0 : }
     299             : 
     300             : /*
     301             :  * Deallocate a ppp unit.
     302             :  */
     303             : void
     304           0 : pppdealloc(struct ppp_softc *sc)
     305             : {
     306             :         struct ppp_pkt *pkt;
     307             : 
     308           0 :         NET_LOCK();
     309           0 :         if_down(&sc->sc_if);
     310           0 :         sc->sc_if.if_flags &= ~IFF_RUNNING;
     311           0 :         sc->sc_devp = NULL;
     312           0 :         sc->sc_xfer = 0;
     313           0 :         while ((pkt = ppp_pkt_dequeue(&sc->sc_rawq)) != NULL)
     314           0 :                 ppp_pkt_free(pkt);
     315           0 :         mq_purge(&sc->sc_inq);
     316           0 :         ml_purge(&sc->sc_npqueue);
     317           0 :         m_freem(sc->sc_togo);
     318           0 :         sc->sc_togo = NULL;
     319             : 
     320             : #ifdef PPP_COMPRESS
     321           0 :         ppp_ccp_closed(sc);
     322           0 :         sc->sc_xc_state = NULL;
     323           0 :         sc->sc_rc_state = NULL;
     324             : #endif /* PPP_COMPRESS */
     325             : #if NBPFILTER > 0
     326           0 :         if (sc->sc_pass_filt.bf_insns != 0) {
     327           0 :                 free(sc->sc_pass_filt.bf_insns, M_DEVBUF, 0);
     328           0 :                 sc->sc_pass_filt.bf_insns = 0;
     329           0 :                 sc->sc_pass_filt.bf_len = 0;
     330           0 :         }
     331           0 :         if (sc->sc_active_filt.bf_insns != 0) {
     332           0 :                 free(sc->sc_active_filt.bf_insns, M_DEVBUF, 0);
     333           0 :                 sc->sc_active_filt.bf_insns = 0;
     334           0 :                 sc->sc_active_filt.bf_len = 0;
     335           0 :         }
     336             : #endif
     337             : #ifdef VJC
     338           0 :         if (sc->sc_comp != 0) {
     339           0 :                 free(sc->sc_comp, M_DEVBUF, 0);
     340           0 :                 sc->sc_comp = 0;
     341           0 :         }
     342             : #endif
     343           0 :         NET_UNLOCK();
     344           0 : }
     345             : 
     346             : /*
     347             :  * Ioctl routine for generic ppp devices.
     348             :  */
     349             : int
     350           0 : pppioctl(struct ppp_softc *sc, u_long cmd, caddr_t data, int flag,
     351             :     struct proc *p)
     352             : {
     353             :         int s, error, flags, mru, npx;
     354             :         u_int nb;
     355             :         struct ppp_option_data *odp;
     356             :         struct compressor **cp;
     357             :         struct npioctl *npi;
     358             :         time_t t;
     359             : #if NBPFILTER > 0
     360             :         struct bpf_program *bp, *nbp;
     361             :         struct bpf_insn *newcode, *oldcode;
     362             :         int newcodelen;
     363             : #endif
     364             : #ifdef  PPP_COMPRESS
     365           0 :         u_char ccp_option[CCP_MAX_OPTION_LENGTH];
     366             : #endif
     367             : 
     368           0 :         switch (cmd) {
     369             :         case FIONREAD:
     370           0 :                 *(int *)data = mq_len(&sc->sc_inq);
     371           0 :                 break;
     372             : 
     373             :         case PPPIOCGUNIT:
     374           0 :                 *(int *)data = sc->sc_unit;  /* XXX */
     375           0 :                 break;
     376             : 
     377             :         case PPPIOCGFLAGS:
     378           0 :                 *(u_int *)data = sc->sc_flags;
     379           0 :                 break;
     380             : 
     381             :         case PPPIOCSFLAGS:
     382           0 :                 if ((error = suser(p)) != 0)
     383           0 :                         return (error);
     384           0 :                 flags = *(int *)data & SC_MASK;
     385             : #ifdef PPP_COMPRESS
     386           0 :                 if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
     387           0 :                         ppp_ccp_closed(sc);
     388             : #endif
     389           0 :                 s = splnet();
     390           0 :                 sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
     391           0 :                 splx(s);
     392           0 :                 break;
     393             : 
     394             :         case PPPIOCSMRU:
     395           0 :                 if ((error = suser(p)) != 0)
     396           0 :                         return (error);
     397           0 :                 mru = *(int *)data;
     398           0 :                 if (mru >= PPP_MRU && mru <= PPP_MAXMRU)
     399           0 :                         sc->sc_mru = mru;
     400             :                 break;
     401             : 
     402             :         case PPPIOCGMRU:
     403           0 :                 *(int *)data = sc->sc_mru;
     404           0 :                 break;
     405             : 
     406             : #ifdef VJC
     407             :         case PPPIOCSMAXCID:
     408           0 :                 if ((error = suser(p)) != 0)
     409           0 :                         return (error);
     410           0 :                 if (sc->sc_comp)
     411           0 :                         sl_compress_setup(sc->sc_comp, *(int *)data);
     412             :                 break;
     413             : #endif
     414             : 
     415             :         case PPPIOCXFERUNIT:
     416           0 :                 if ((error = suser(p)) != 0)
     417           0 :                         return (error);
     418           0 :                 sc->sc_xfer = p->p_p->ps_pid;
     419           0 :                 break;
     420             : 
     421             : #ifdef PPP_COMPRESS
     422             :         case PPPIOCSCOMPRESS:
     423           0 :                 if ((error = suser(p)) != 0)
     424           0 :                         return (error);
     425           0 :                 odp = (struct ppp_option_data *) data;
     426           0 :                 nb = odp->length;
     427           0 :                 if (nb > sizeof(ccp_option))
     428             :                         nb = sizeof(ccp_option);
     429           0 :                 if ((error = copyin(odp->ptr, ccp_option, nb)) != 0)
     430           0 :                         return (error);
     431             :                  /* preliminary check on the length byte */
     432           0 :                 if (ccp_option[1] < 2)
     433           0 :                         return (EINVAL);
     434           0 :                 for (cp = ppp_compressors; *cp != NULL; ++cp)
     435           0 :                         if ((*cp)->compress_proto == ccp_option[0]) {
     436             :                         /*
     437             :                          * Found a handler for the protocol - try to allocate
     438             :                          * a compressor or decompressor.
     439             :                          */
     440             :                         error = 0;
     441           0 :                         if (odp->transmit) {
     442           0 :                                 if (sc->sc_xc_state != NULL) {
     443           0 :                                         (*sc->sc_xcomp->comp_free)(
     444             :                                             sc->sc_xc_state);
     445           0 :                                 }
     446           0 :                                 sc->sc_xcomp = *cp;
     447           0 :                                 sc->sc_xc_state = (*cp)->comp_alloc(ccp_option,
     448             :                                     nb);
     449           0 :                                 if (sc->sc_xc_state == NULL) {
     450           0 :                                         if (sc->sc_flags & SC_DEBUG)
     451           0 :                                                 printf(
     452             :                                                     "%s: comp_alloc failed\n",
     453           0 :                                                     sc->sc_if.if_xname);
     454             :                                         error = ENOBUFS;
     455           0 :                                 }
     456           0 :                                 s = splnet();
     457           0 :                                 sc->sc_flags &= ~SC_COMP_RUN;
     458           0 :                                 splx(s);
     459           0 :                         } else {
     460           0 :                                 if (sc->sc_rc_state != NULL) {
     461           0 :                                         (*sc->sc_rcomp->decomp_free)(
     462             :                                             sc->sc_rc_state);
     463           0 :                                 }
     464           0 :                                 sc->sc_rcomp = *cp;
     465           0 :                                 sc->sc_rc_state = (*cp)->decomp_alloc(
     466             :                                     ccp_option, nb);
     467           0 :                                 if (sc->sc_rc_state == NULL) {
     468           0 :                                         if (sc->sc_flags & SC_DEBUG) {
     469           0 :                                                 printf(
     470             :                                                     "%s: decomp_alloc failed\n",
     471           0 :                                                     sc->sc_if.if_xname);
     472           0 :                                         }
     473             :                                         error = ENOBUFS;
     474           0 :                                 }
     475           0 :                                 s = splnet();
     476           0 :                                 sc->sc_flags &= ~SC_DECOMP_RUN;
     477           0 :                                 splx(s);
     478             :                         }
     479           0 :                         return (error);
     480             :                 }
     481           0 :                 if (sc->sc_flags & SC_DEBUG) {
     482           0 :                         printf("%s: no compressor for [%x %x %x], %x\n",
     483           0 :                             sc->sc_if.if_xname, ccp_option[0], ccp_option[1],
     484           0 :                             ccp_option[2], nb);
     485           0 :                 }
     486           0 :                 return (EINVAL);        /* no handler found */
     487             : #endif /* PPP_COMPRESS */
     488             : 
     489             :         case PPPIOCGNPMODE:
     490             :         case PPPIOCSNPMODE:
     491           0 :                 npi = (struct npioctl *)data;
     492           0 :                 switch (npi->protocol) {
     493             :                 case PPP_IP:
     494             :                         npx = NP_IP;
     495             :                         break;
     496             :                 default:
     497           0 :                         return EINVAL;
     498             :                 }
     499           0 :                 if (cmd == PPPIOCGNPMODE) {
     500           0 :                         npi->mode = sc->sc_npmode[npx];
     501           0 :                 } else {
     502           0 :                         if ((error = suser(p)) != 0)
     503           0 :                                 return (error);
     504           0 :                         if (npi->mode != sc->sc_npmode[npx]) {
     505           0 :                                 sc->sc_npmode[npx] = npi->mode;
     506           0 :                                 if (npi->mode != NPMODE_QUEUE) {
     507           0 :                                         ppp_requeue(sc);
     508           0 :                                         (*sc->sc_start)(sc);
     509           0 :                                 }
     510             :                         }
     511             :                 }
     512             :                 break;
     513             : 
     514             :         case PPPIOCGIDLE:
     515           0 :                 t = time_uptime;
     516           0 :                 ((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
     517           0 :                 ((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
     518           0 :                 break;
     519             : 
     520             : #if NBPFILTER > 0
     521             :         case PPPIOCSPASS:
     522             :         case PPPIOCSACTIVE:
     523           0 :                 nbp = (struct bpf_program *) data;
     524           0 :                 if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
     525           0 :                         return EINVAL;
     526           0 :                 newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
     527           0 :                 if (nbp->bf_len != 0) {
     528           0 :                         newcode = mallocarray(nbp->bf_len,
     529             :                             sizeof(struct bpf_insn), M_DEVBUF, M_WAITOK);
     530           0 :                         if ((error = copyin((caddr_t)nbp->bf_insns,
     531           0 :                             (caddr_t)newcode, newcodelen)) != 0) {
     532           0 :                                 free(newcode, M_DEVBUF, 0);
     533           0 :                                 return error;
     534             :                         }
     535           0 :                         if (!bpf_validate(newcode, nbp->bf_len)) {
     536           0 :                                 free(newcode, M_DEVBUF, 0);
     537           0 :                                 return EINVAL;
     538             :                         }
     539             :                 } else
     540             :                         newcode = 0;
     541           0 :                 bp = (cmd == PPPIOCSPASS) ?
     542           0 :                     &sc->sc_pass_filt : &sc->sc_active_filt;
     543           0 :                 oldcode = bp->bf_insns;
     544           0 :                 s = splnet();
     545           0 :                 bp->bf_len = nbp->bf_len;
     546           0 :                 bp->bf_insns = newcode;
     547           0 :                 splx(s);
     548           0 :                 if (oldcode != 0)
     549           0 :                         free(oldcode, M_DEVBUF, 0);
     550             :                 break;
     551             : #endif
     552             : 
     553             :         default:
     554           0 :                 return (-1);
     555             :         }
     556           0 :         return (0);
     557           0 : }
     558             : 
     559             : /*
     560             :  * Process an ioctl request to the ppp network interface.
     561             :  */
     562             : static int
     563           0 : pppsioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     564             : {
     565           0 :         struct ppp_softc *sc = ifp->if_softc;
     566           0 :         struct ifaddr *ifa = (struct ifaddr *)data;
     567           0 :         struct ifreq *ifr = (struct ifreq *)data;
     568             :         struct ppp_stats *psp;
     569             : #ifdef  PPP_COMPRESS
     570             :         struct ppp_comp_stats *pcp;
     571             : #endif
     572           0 :         int s = splnet(), error = 0;
     573             : 
     574           0 :         switch (cmd) {
     575             :         case SIOCSIFFLAGS:
     576           0 :                 if ((ifp->if_flags & IFF_RUNNING) == 0)
     577           0 :                         ifp->if_flags &= ~IFF_UP;
     578             :                 break;
     579             : 
     580             :         case SIOCSIFADDR:
     581           0 :                 if (ifa->ifa_addr->sa_family != AF_INET)
     582           0 :                         error = EAFNOSUPPORT;
     583             :                 break;
     584             : 
     585             :         case SIOCSIFDSTADDR:
     586           0 :                 if (ifa->ifa_addr->sa_family != AF_INET)
     587           0 :                         error = EAFNOSUPPORT;
     588             :                 break;
     589             : 
     590             :         case SIOCSIFMTU:
     591           0 :                 sc->sc_if.if_mtu = ifr->ifr_mtu;
     592           0 :                 break;
     593             : 
     594             :         case SIOCADDMULTI:
     595             :         case SIOCDELMULTI:
     596             :                 break;
     597             : 
     598             :         case SIOCGPPPSTATS:
     599           0 :                 psp = &((struct ifpppstatsreq *) data)->stats;
     600           0 :                 bzero(psp, sizeof(*psp));
     601           0 :                 psp->p = sc->sc_stats;
     602             : #if defined(VJC) && !defined(SL_NO_STATS)
     603           0 :                 if (sc->sc_comp) {
     604           0 :                         psp->vj.vjs_packets = sc->sc_comp->sls_packets;
     605           0 :                         psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
     606           0 :                         psp->vj.vjs_searches = sc->sc_comp->sls_searches;
     607           0 :                         psp->vj.vjs_misses = sc->sc_comp->sls_misses;
     608           0 :                         psp->vj.vjs_uncompressedin =
     609           0 :                             sc->sc_comp->sls_uncompressedin;
     610           0 :                         psp->vj.vjs_compressedin =
     611           0 :                             sc->sc_comp->sls_compressedin;
     612           0 :                         psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
     613           0 :                         psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
     614           0 :                 }
     615             : #endif /* VJC */
     616             :                 break;
     617             : 
     618             : #ifdef PPP_COMPRESS
     619             :         case SIOCGPPPCSTATS:
     620           0 :                 pcp = &((struct ifpppcstatsreq *) data)->stats;
     621           0 :                 bzero(pcp, sizeof(*pcp));
     622           0 :                 if (sc->sc_xc_state != NULL)
     623           0 :                         (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
     624           0 :                 if (sc->sc_rc_state != NULL)
     625           0 :                         (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
     626             :                 break;
     627             : #endif /* PPP_COMPRESS */
     628             : 
     629             :         default:
     630             :                 error = ENOTTY;
     631           0 :         }
     632           0 :         splx(s);
     633           0 :         return (error);
     634             : }
     635             : 
     636             : /*
     637             :  * Queue a packet.  Start transmission if not active.
     638             :  * Packet is placed in Information field of PPP frame.
     639             :  */
     640             : int
     641           0 : pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
     642             :     struct rtentry *rtp)
     643             : {
     644           0 :         struct ppp_softc *sc = ifp->if_softc;
     645             :         int protocol, address, control;
     646             :         u_char *cp;
     647             :         int error;
     648             :         enum NPmode mode;
     649             :         int len;
     650             : 
     651           0 :         if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
     652           0 :             || ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
     653             :                 error = ENETDOWN;       /* sort of */
     654           0 :                 goto bad;
     655             :         }
     656             : 
     657             : #ifdef DIAGNOSTIC
     658           0 :         if (ifp->if_rdomain != rtable_l2(m0->m_pkthdr.ph_rtableid)) {
     659           0 :                 printf("%s: trying to send packet on wrong domain. "
     660           0 :                     "if %d vs. mbuf %d, AF %d\n", ifp->if_xname,
     661           0 :                     ifp->if_rdomain, rtable_l2(m0->m_pkthdr.ph_rtableid),
     662           0 :                     dst->sa_family);
     663           0 :         }
     664             : #endif
     665             : 
     666             :         /*
     667             :          * Compute PPP header.
     668             :          */
     669           0 :         switch (dst->sa_family) {
     670             :         case AF_INET:
     671             :                 address = PPP_ALLSTATIONS;
     672             :                 control = PPP_UI;
     673             :                 protocol = PPP_IP;
     674           0 :                 mode = sc->sc_npmode[NP_IP];
     675           0 :                 break;
     676             :         case AF_UNSPEC:
     677           0 :                 address = PPP_ADDRESS(dst->sa_data);
     678           0 :                 control = PPP_CONTROL(dst->sa_data);
     679           0 :                 protocol = PPP_PROTOCOL(dst->sa_data);
     680             :                 mode = NPMODE_PASS;
     681           0 :                 break;
     682             :         default:
     683           0 :                 printf("%s: af%d not supported\n", ifp->if_xname,
     684             :                     dst->sa_family);
     685             :                 error = EAFNOSUPPORT;
     686           0 :                 goto bad;
     687             :         }
     688             : 
     689             :         /*
     690             :          * Drop this packet, or return an error, if necessary.
     691             :          */
     692           0 :         if (mode == NPMODE_ERROR) {
     693             :                 error = ENETDOWN;
     694           0 :                 goto bad;
     695             :         }
     696           0 :         if (mode == NPMODE_DROP) {
     697             :                 error = 0;
     698           0 :                 goto bad;
     699             :         }
     700             : 
     701             :         /*
     702             :          * Add PPP header.  If no space in first mbuf, allocate another.
     703             :          * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
     704             :          */
     705           0 :         M_PREPEND(m0, PPP_HDRLEN, M_DONTWAIT);
     706           0 :         if (m0 == NULL) {
     707             :                 error = ENOBUFS;
     708           0 :                 goto bad;
     709             :         }
     710             : 
     711           0 :         cp = mtod(m0, u_char *);
     712           0 :         *cp++ = address;
     713           0 :         *cp++ = control;
     714           0 :         *cp++ = protocol >> 8;
     715           0 :         *cp++ = protocol & 0xff;
     716             : 
     717           0 :         if ((m0->m_flags & M_PKTHDR) == 0)
     718           0 :                 panic("mbuf packet without packet header!");
     719           0 :         len = m0->m_pkthdr.len;
     720             : 
     721           0 :         if (sc->sc_flags & SC_LOG_OUTPKT) {
     722           0 :                 printf("%s output: ", ifp->if_xname);
     723           0 :                 pppdumpm(m0);
     724           0 :         }
     725             : 
     726           0 :         if ((protocol & 0x8000) == 0) {
     727             : #if NBPFILTER > 0
     728             :                 /*
     729             :                  * Apply the pass and active filters to the packet,
     730             :                  * but only if it is a data packet.
     731             :                  */
     732           0 :                 *mtod(m0, u_char *) = 1;        /* indicates outbound */
     733           0 :                 if (sc->sc_pass_filt.bf_insns != 0 &&
     734           0 :                     bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *)m0,
     735           0 :                     len, 0) == 0) {
     736             :                         error = 0; /* drop this packet */
     737           0 :                         goto bad;
     738             :                 }
     739             : 
     740             :                 /*
     741             :                  * Update the time we sent the most recent packet.
     742             :                  */
     743           0 :                 if (sc->sc_active_filt.bf_insns == 0 ||
     744           0 :                     bpf_filter(sc->sc_active_filt.bf_insns, (u_char *)m0,
     745             :                     len, 0))
     746           0 :                         sc->sc_last_sent = time_uptime;
     747             : 
     748           0 :                 *mtod(m0, u_char *) = address;
     749             : #else
     750             :                 /*
     751             :                  * Update the time we sent the most recent packet.
     752             :                  */
     753             :                 sc->sc_last_sent = time_uptime;
     754             : #endif
     755           0 :         }
     756             : 
     757             : #if NBPFILTER > 0
     758             :         /*
     759             :          * See if bpf wants to look at the packet.
     760             :          */
     761           0 :         if (sc->sc_bpf)
     762           0 :                 bpf_mtap(sc->sc_bpf, m0, BPF_DIRECTION_OUT);
     763             : #endif
     764             : 
     765             :         /*
     766             :          * Put the packet on the appropriate queue.
     767             :          */
     768           0 :         if (mode == NPMODE_QUEUE) {
     769             :                 /* XXX we should limit the number of packets on this queue */
     770           0 :                 ml_enqueue(&sc->sc_npqueue, m0);
     771           0 :         } else {
     772           0 :                 IFQ_ENQUEUE(&sc->sc_if.if_snd, m0, error);
     773           0 :                 if (error) {
     774           0 :                         sc->sc_if.if_oerrors++;
     775           0 :                         sc->sc_stats.ppp_oerrors++;
     776           0 :                         return (error);
     777             :                 }
     778           0 :                 (*sc->sc_start)(sc);
     779             :         }
     780           0 :         ifp->if_opackets++;
     781           0 :         ifp->if_obytes += len;
     782             : 
     783           0 :         return (0);
     784             : 
     785             : bad:
     786           0 :         m_freem(m0);
     787           0 :         return (error);
     788           0 : }
     789             : 
     790             : 
     791             : 
     792             : /*
     793             :  * After a change in the NPmode for some NP, move packets from the
     794             :  * npqueue to the send queue or the fast queue as appropriate.
     795             :  */
     796             : static void
     797           0 : ppp_requeue(struct ppp_softc *sc)
     798             : {
     799           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     800             :         struct mbuf *m;
     801             :         enum NPmode mode;
     802             :         int error;
     803             : 
     804           0 :         while ((m = ml_dequeue(&sc->sc_npqueue)) != NULL) {
     805           0 :                 switch (PPP_PROTOCOL(mtod(m, u_char *))) {
     806             :                 case PPP_IP:
     807           0 :                         mode = sc->sc_npmode[NP_IP];
     808           0 :                         break;
     809             :                 default:
     810             :                         mode = NPMODE_PASS;
     811           0 :                 }
     812             : 
     813           0 :                 switch (mode) {
     814             :                 case NPMODE_PASS:
     815           0 :                         IFQ_ENQUEUE(&sc->sc_if.if_snd, m, error);
     816           0 :                         if (error) {
     817           0 :                                 sc->sc_if.if_oerrors++;
     818           0 :                                 sc->sc_stats.ppp_oerrors++;
     819           0 :                         }
     820             :                         break;
     821             : 
     822             :                 case NPMODE_DROP:
     823             :                 case NPMODE_ERROR:
     824           0 :                         m_freem(m);
     825           0 :                         break;
     826             : 
     827             :                 case NPMODE_QUEUE:
     828           0 :                         ml_enqueue(&ml, m);
     829           0 :                         break;
     830             :                 }
     831             :         }
     832           0 :         sc->sc_npqueue = ml;
     833           0 : }
     834             : 
     835             : /*
     836             :  * Transmitter has finished outputting some stuff;
     837             :  */
     838             : void
     839           0 : ppp_restart(struct ppp_softc *sc)
     840             : {
     841           0 :         int s = splnet();
     842             : 
     843           0 :         sc->sc_flags &= ~SC_TBUSY;
     844           0 :         schednetisr(NETISR_PPP);
     845           0 :         splx(s);
     846           0 : }
     847             : 
     848             : /*
     849             :  * Get a packet to send.
     850             :  */
     851             : struct mbuf *
     852           0 : ppp_dequeue(struct ppp_softc *sc)
     853             : {
     854             :         struct mbuf *m, *mp;
     855             :         u_char *cp;
     856             :         int address, control, protocol;
     857             : 
     858             :         /*
     859             :          * Grab a packet to send: first try the fast queue, then the
     860             :          * normal queue.
     861             :          */
     862           0 :         IFQ_DEQUEUE(&sc->sc_if.if_snd, m);
     863           0 :         if (m == NULL)
     864           0 :                 return NULL;
     865             : 
     866           0 :         ++sc->sc_stats.ppp_opackets;
     867             : 
     868             :         /*
     869             :          * Extract the ppp header of the new packet.
     870             :          * The ppp header will be in one mbuf.
     871             :          */
     872           0 :         cp = mtod(m, u_char *);
     873           0 :         address = PPP_ADDRESS(cp);
     874           0 :         control = PPP_CONTROL(cp);
     875           0 :         protocol = PPP_PROTOCOL(cp);
     876             : 
     877           0 :         switch (protocol) {
     878             :         case PPP_IP:
     879             : #ifdef VJC
     880             :                 /*
     881             :                  * If the packet is a TCP/IP packet, see if we can compress it.
     882             :                  */
     883           0 :                 if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
     884             :                         struct ip *ip;
     885             :                         int type;
     886             : 
     887             :                         mp = m;
     888           0 :                         ip = (struct ip *)(cp + PPP_HDRLEN);
     889           0 :                         if (mp->m_len <= PPP_HDRLEN) {
     890           0 :                                 mp = mp->m_next;
     891           0 :                                 if (mp == NULL)
     892           0 :                                         break;
     893           0 :                                 ip = mtod(mp, struct ip *);
     894           0 :                         }
     895             :                         /*
     896             :                          * this code assumes the IP/TCP header is in one
     897             :                          * non-shared mbuf.
     898             :                          */
     899           0 :                         if (ip->ip_p == IPPROTO_TCP) {
     900           0 :                                 type = sl_compress_tcp(mp, ip, sc->sc_comp,
     901           0 :                                     !(sc->sc_flags & SC_NO_TCP_CCID));
     902           0 :                                 switch (type) {
     903             :                                 case TYPE_UNCOMPRESSED_TCP:
     904             :                                         protocol = PPP_VJC_UNCOMP;
     905           0 :                                         break;
     906             :                                 case TYPE_COMPRESSED_TCP:
     907             :                                         protocol = PPP_VJC_COMP;
     908           0 :                                         cp = mtod(m, u_char *);
     909           0 :                                         cp[0] = address; /* header has moved */
     910           0 :                                         cp[1] = control;
     911           0 :                                         cp[2] = 0;
     912           0 :                                         break;
     913             :                                 }
     914             :                                 /* update protocol in PPP header */
     915           0 :                                 cp[3] = protocol;
     916           0 :                         }
     917           0 :                 }
     918             : #endif  /* VJC */
     919             :                 break;
     920             : 
     921             : #ifdef PPP_COMPRESS
     922             :         case PPP_CCP:
     923           0 :                 ppp_ccp(sc, m, 0);
     924           0 :                 break;
     925             : #endif  /* PPP_COMPRESS */
     926             :         }
     927             : 
     928             : #ifdef PPP_COMPRESS
     929           0 :         if (protocol != PPP_LCP && protocol != PPP_CCP &&
     930           0 :             sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
     931           0 :                 struct mbuf *mcomp = NULL;
     932             :                 int slen;
     933             : 
     934             :                 slen = 0;
     935           0 :                 for (mp = m; mp != NULL; mp = mp->m_next)
     936           0 :                         slen += mp->m_len;
     937           0 :                 (*sc->sc_xcomp->compress)(sc->sc_xc_state, &mcomp, m, slen,
     938           0 :                     (sc->sc_flags & SC_CCP_UP ?
     939           0 :                     sc->sc_if.if_mtu + PPP_HDRLEN : 0));
     940           0 :                 if (mcomp != NULL) {
     941           0 :                         if (sc->sc_flags & SC_CCP_UP) {
     942             :                                 /* Send the compressed packet instead. */
     943           0 :                                 m_freem(m);
     944           0 :                                 m = mcomp;
     945           0 :                                 cp = mtod(m, u_char *);
     946           0 :                                 protocol = cp[3];
     947           0 :                         } else {
     948             :                                 /*
     949             :                                  * Can't transmit compressed packets until
     950             :                                  * CCP is up.
     951             :                                  */
     952           0 :                                 m_freem(mcomp);
     953             :                         }
     954             :                 }
     955           0 :         }
     956             : #endif  /* PPP_COMPRESS */
     957             : 
     958             :         /*
     959             :          * Compress the address/control and protocol, if possible.
     960             :          */
     961           0 :         if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
     962           0 :             control == PPP_UI && protocol != PPP_ALLSTATIONS &&
     963           0 :             protocol != PPP_LCP) {
     964             :                 /* can compress address/control */
     965           0 :                 m->m_data += 2;
     966           0 :                 m->m_len -= 2;
     967           0 :         }
     968           0 :         if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
     969             :                 /* can compress protocol */
     970           0 :                 if (mtod(m, u_char *) == cp) {
     971           0 :                         cp[2] = cp[1];  /* move address/control up */
     972           0 :                         cp[1] = cp[0];
     973           0 :                 }
     974           0 :                 ++m->m_data;
     975           0 :                 --m->m_len;
     976           0 :         }
     977             : 
     978           0 :         return m;
     979           0 : }
     980             : 
     981             : /*
     982             :  * Software interrupt routine.
     983             :  */
     984             : void
     985           0 : pppintr(void)
     986             : {
     987             :         struct ppp_softc *sc;
     988             :         int s;
     989             :         struct ppp_pkt *pkt;
     990             :         struct mbuf *m;
     991             : 
     992           0 :         NET_ASSERT_LOCKED();
     993             : 
     994           0 :         LIST_FOREACH(sc, &ppp_softc_list, sc_list) {
     995           0 :                 if (!(sc->sc_flags & SC_TBUSY) &&
     996           0 :                     (!IFQ_IS_EMPTY(&sc->sc_if.if_snd))) {
     997           0 :                         s = splnet();
     998           0 :                         sc->sc_flags |= SC_TBUSY;
     999           0 :                         splx(s);
    1000           0 :                         (*sc->sc_start)(sc);
    1001           0 :                 }
    1002           0 :                 while ((pkt = ppp_pkt_dequeue(&sc->sc_rawq)) != NULL) {
    1003           0 :                         m = ppp_pkt_mbuf(pkt);
    1004           0 :                         if (m == NULL)
    1005           0 :                                 continue;
    1006           0 :                         ppp_inproc(sc, m);
    1007             :                 }
    1008             :         }
    1009           0 : }
    1010             : 
    1011             : #ifdef PPP_COMPRESS
    1012             : /*
    1013             :  * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
    1014             :  * 0 if it is about to be transmitted.
    1015             :  */
    1016             : static void
    1017           0 : ppp_ccp(struct ppp_softc *sc, struct mbuf *m, int rcvd)
    1018             : {
    1019             :         u_char *dp, *ep;
    1020             :         struct mbuf *mp;
    1021             :         int slen, s;
    1022             : 
    1023             :         /*
    1024             :          * Get a pointer to the data after the PPP header.
    1025             :          */
    1026           0 :         if (m->m_len <= PPP_HDRLEN) {
    1027           0 :                 mp = m->m_next;
    1028           0 :                 if (mp == NULL)
    1029           0 :                         return;
    1030           0 :                 dp = mtod(mp, u_char *);
    1031           0 :         } else {
    1032             :                 mp = m;
    1033           0 :                 dp = mtod(mp, u_char *) + PPP_HDRLEN;
    1034             :         }
    1035             : 
    1036           0 :         ep = mtod(mp, u_char *) + mp->m_len;
    1037           0 :         if (dp + CCP_HDRLEN > ep)
    1038           0 :                 return;
    1039           0 :         slen = CCP_LENGTH(dp);
    1040           0 :         if (dp + slen > ep) {
    1041           0 :                 if (sc->sc_flags & SC_DEBUG) {
    1042           0 :                         printf("if_ppp/ccp: not enough data in mbuf"
    1043             :                             " (%p+%x > %p+%x)\n", dp, slen,
    1044             :                             mtod(mp, u_char *), mp->m_len);
    1045           0 :                 }
    1046           0 :                 return;
    1047             :         }
    1048             : 
    1049           0 :         switch (CCP_CODE(dp)) {
    1050             :         case CCP_CONFREQ:
    1051             :         case CCP_TERMREQ:
    1052             :         case CCP_TERMACK:
    1053             :                 /* CCP must be going down - disable compression */
    1054           0 :                 if (sc->sc_flags & SC_CCP_UP) {
    1055           0 :                         s = splnet();
    1056           0 :                         sc->sc_flags &=
    1057             :                             ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
    1058           0 :                         splx(s);
    1059           0 :                 }
    1060             :                 break;
    1061             : 
    1062             :         case CCP_CONFACK:
    1063           0 :                 if (sc->sc_flags & SC_CCP_OPEN &&
    1064           0 :                     !(sc->sc_flags & SC_CCP_UP) &&
    1065           0 :                     slen >= CCP_HDRLEN + CCP_OPT_MINLEN &&
    1066           0 :                     slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
    1067           0 :                         if (!rcvd) {
    1068             :                                 /* we're agreeing to send compressed packets. */
    1069           0 :                                 if (sc->sc_xc_state != NULL &&
    1070           0 :                                     (*sc->sc_xcomp->comp_init)(sc->sc_xc_state,
    1071           0 :                                     dp + CCP_HDRLEN, slen - CCP_HDRLEN,
    1072           0 :                                     sc->sc_unit, 0, sc->sc_flags & SC_DEBUG)) {
    1073           0 :                                         s = splnet();
    1074           0 :                                         sc->sc_flags |= SC_COMP_RUN;
    1075           0 :                                         splx(s);
    1076           0 :                                 }
    1077             :                         } else {
    1078             :                                 /* peer agrees to send compressed packets */
    1079           0 :                                 if (sc->sc_rc_state != NULL &&
    1080           0 :                                     (*sc->sc_rcomp->decomp_init)(
    1081             :                                      sc->sc_rc_state, dp + CCP_HDRLEN,
    1082           0 :                                      slen - CCP_HDRLEN, sc->sc_unit, 0,
    1083           0 :                                      sc->sc_mru, sc->sc_flags & SC_DEBUG)) {
    1084           0 :                                         s = splnet();
    1085           0 :                                         sc->sc_flags |= SC_DECOMP_RUN;
    1086           0 :                                         sc->sc_flags &=
    1087             :                                             ~(SC_DC_ERROR | SC_DC_FERROR);
    1088           0 :                                         splx(s);
    1089           0 :                                 }
    1090             :                         }
    1091             :                 }
    1092             :                 break;
    1093             : 
    1094             :         case CCP_RESETACK:
    1095           0 :                 if (sc->sc_flags & SC_CCP_UP) {
    1096           0 :                         if (!rcvd) {
    1097           0 :                                 if (sc->sc_xc_state &&
    1098           0 :                                     (sc->sc_flags & SC_COMP_RUN)) {
    1099           0 :                                         (*sc->sc_xcomp->comp_reset)(
    1100             :                                             sc->sc_xc_state);
    1101           0 :                                 }
    1102             :                         } else {
    1103           0 :                                 if (sc->sc_rc_state &&
    1104           0 :                                     (sc->sc_flags & SC_DECOMP_RUN)) {
    1105           0 :                                         (*sc->sc_rcomp->decomp_reset)(
    1106             :                                             sc->sc_rc_state);
    1107           0 :                                         s = splnet();
    1108           0 :                                         sc->sc_flags &= ~SC_DC_ERROR;
    1109           0 :                                         splx(s);
    1110           0 :                                 }
    1111             :                         }
    1112             :                 }
    1113             :                 break;
    1114             :         }
    1115           0 : }
    1116             : 
    1117             : /*
    1118             :  * CCP is down; free (de)compressor state if necessary.
    1119             :  */
    1120             : static void
    1121           0 : ppp_ccp_closed(struct ppp_softc *sc)
    1122             : {
    1123           0 :         if (sc->sc_xc_state) {
    1124           0 :                 (*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
    1125           0 :                 sc->sc_xc_state = NULL;
    1126           0 :         }
    1127           0 :         if (sc->sc_rc_state) {
    1128           0 :                 (*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
    1129           0 :                 sc->sc_rc_state = NULL;
    1130           0 :         }
    1131           0 : }
    1132             : #endif /* PPP_COMPRESS */
    1133             : 
    1134             : /*
    1135             :  * PPP packet input routine.
    1136             :  * The caller has checked and removed the FCS and has inserted
    1137             :  * the address/control bytes and the protocol high byte if they
    1138             :  * were omitted.
    1139             :  */
    1140             : void
    1141           0 : ppppktin(struct ppp_softc *sc, struct ppp_pkt *pkt, int lost)
    1142             : {
    1143           0 :         pkt->p_hdr.ph_errmark = lost;
    1144           0 :         if (ppp_pkt_enqueue(&sc->sc_rawq, pkt) == 0)
    1145           0 :                 schednetisr(NETISR_PPP);
    1146           0 : }
    1147             : 
    1148             : /*
    1149             :  * Process a received PPP packet, doing decompression as necessary.
    1150             :  */
    1151             : #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
    1152             :                          TYPE_UNCOMPRESSED_TCP)
    1153             : 
    1154             : static void
    1155           0 : ppp_inproc(struct ppp_softc *sc, struct mbuf *m)
    1156             : {
    1157           0 :         struct ifnet *ifp = &sc->sc_if;
    1158             :         int s, ilen, xlen, proto, rv;
    1159             :         u_char *cp, adrs, ctrl;
    1160           0 :         struct mbuf *mp, *dmp = NULL;
    1161           0 :         u_char *iphdr;
    1162           0 :         u_int hlen;
    1163             : 
    1164           0 :         sc->sc_stats.ppp_ipackets++;
    1165             : 
    1166           0 :         if (sc->sc_flags & SC_LOG_INPKT) {
    1167             :                 ilen = 0;
    1168           0 :                 for (mp = m; mp != NULL; mp = mp->m_next)
    1169           0 :                         ilen += mp->m_len;
    1170           0 :                 printf("%s: got %d bytes\n", ifp->if_xname, ilen);
    1171           0 :                 pppdumpm(m);
    1172           0 :         }
    1173             : 
    1174           0 :         cp = mtod(m, u_char *);
    1175           0 :         adrs = PPP_ADDRESS(cp);
    1176           0 :         ctrl = PPP_CONTROL(cp);
    1177           0 :         proto = PPP_PROTOCOL(cp);
    1178             : 
    1179           0 :         if (m->m_flags & M_ERRMARK) {
    1180           0 :                 m->m_flags &= ~M_ERRMARK;
    1181           0 :                 s = splnet();
    1182           0 :                 sc->sc_flags |= SC_VJ_RESET;
    1183           0 :                 splx(s);
    1184           0 :         }
    1185             : 
    1186             : #ifdef PPP_COMPRESS
    1187             :         /*
    1188             :          * Decompress this packet if necessary, update the receiver's
    1189             :          * dictionary, or take appropriate action on a CCP packet.
    1190             :          */
    1191           0 :         if (proto == PPP_COMP && sc->sc_rc_state &&
    1192           0 :             (sc->sc_flags & SC_DECOMP_RUN) && !(sc->sc_flags & SC_DC_ERROR) &&
    1193           0 :             !(sc->sc_flags & SC_DC_FERROR)) {
    1194             :                 /* decompress this packet */
    1195           0 :                 rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
    1196           0 :                 if (rv == DECOMP_OK) {
    1197           0 :                         m_freem(m);
    1198           0 :                         if (dmp == NULL) {
    1199             :                                 /*
    1200             :                                  * no error, but no decompressed packet
    1201             :                                  * produced
    1202             :                                  */
    1203           0 :                                 return;
    1204             :                         }
    1205             :                         m = dmp;
    1206           0 :                         cp = mtod(m, u_char *);
    1207           0 :                         proto = PPP_PROTOCOL(cp);
    1208             : 
    1209           0 :                 } else {
    1210             :                         /*
    1211             :                          * An error has occurred in decompression.
    1212             :                          * Pass the compressed packet up to pppd, which may
    1213             :                          * take CCP down or issue a Reset-Req.
    1214             :                          */
    1215           0 :                         if (sc->sc_flags & SC_DEBUG) {
    1216           0 :                                 printf("%s: decompress failed %d\n",
    1217           0 :                                     ifp->if_xname, rv);
    1218           0 :                         }
    1219           0 :                         s = splnet();
    1220           0 :                         sc->sc_flags |= SC_VJ_RESET;
    1221           0 :                         if (rv == DECOMP_ERROR)
    1222           0 :                                 sc->sc_flags |= SC_DC_ERROR;
    1223             :                         else
    1224           0 :                                 sc->sc_flags |= SC_DC_FERROR;
    1225           0 :                         splx(s);
    1226             :                 }
    1227             : 
    1228             :         } else {
    1229           0 :                 if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
    1230           0 :                         (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
    1231           0 :                 }
    1232           0 :                 if (proto == PPP_CCP) {
    1233           0 :                         ppp_ccp(sc, m, 1);
    1234           0 :                 }
    1235             :         }
    1236             : #endif
    1237             : 
    1238             :         ilen = 0;
    1239           0 :         for (mp = m; mp != NULL; mp = mp->m_next)
    1240           0 :                 ilen += mp->m_len;
    1241             : 
    1242             : #ifdef VJC
    1243           0 :         if (sc->sc_flags & SC_VJ_RESET) {
    1244             :                 /*
    1245             :                 * If we've missed a packet, we must toss subsequent compressed
    1246             :                 * packets which don't have an explicit connection ID.
    1247             :                 */
    1248           0 :                 if (sc->sc_comp)
    1249           0 :                         sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
    1250           0 :                 s = splnet();
    1251           0 :                 sc->sc_flags &= ~SC_VJ_RESET;
    1252           0 :                 splx(s);
    1253           0 :         }
    1254             : 
    1255             :         /*
    1256             :          * See if we have a VJ-compressed packet to uncompress.
    1257             :          */
    1258           0 :         if (proto == PPP_VJC_COMP) {
    1259           0 :                 if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
    1260             :                         goto bad;
    1261             : 
    1262           0 :                 xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN,
    1263           0 :                     m->m_len - PPP_HDRLEN, ilen - PPP_HDRLEN,
    1264             :                     TYPE_COMPRESSED_TCP, sc->sc_comp, &iphdr, &hlen);
    1265             : 
    1266           0 :                 if (xlen <= 0) {
    1267           0 :                         if (sc->sc_flags & SC_DEBUG) {
    1268           0 :                                 printf("%s: VJ uncompress failed "
    1269           0 :                                     "on type comp\n", ifp->if_xname);
    1270           0 :                         }
    1271             :                         goto bad;
    1272             :                 }
    1273             : 
    1274             :                 /* Copy the PPP and IP headers into a new mbuf. */
    1275           0 :                 MGETHDR(mp, M_DONTWAIT, MT_DATA);
    1276           0 :                 if (mp == NULL)
    1277             :                         goto bad;
    1278           0 :                 mp->m_len = 0;
    1279           0 :                 mp->m_next = NULL;
    1280           0 :                 if (hlen + PPP_HDRLEN > MHLEN) {
    1281           0 :                         MCLGET(mp, M_DONTWAIT);
    1282           0 :                         if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
    1283           0 :                                 m_freem(mp);
    1284             :                                 /* lose if big headers and no clusters */
    1285           0 :                                 goto bad;
    1286             :                         }
    1287             :                 }
    1288           0 :                 if (m->m_flags & M_PKTHDR)
    1289           0 :                         M_MOVE_HDR(mp, m);
    1290           0 :                 cp = mtod(mp, u_char *);
    1291           0 :                 cp[0] = adrs;
    1292           0 :                 cp[1] = ctrl;
    1293           0 :                 cp[2] = 0;
    1294           0 :                 cp[3] = PPP_IP;
    1295             :                 proto = PPP_IP;
    1296           0 :                 bcopy(iphdr, cp + PPP_HDRLEN, hlen);
    1297           0 :                 mp->m_len = hlen + PPP_HDRLEN;
    1298             : 
    1299             :                 /*
    1300             :                  * Trim the PPP and VJ headers off the old mbuf
    1301             :                  * and stick the new and old mbufs together.
    1302             :                  */
    1303           0 :                 m->m_data += PPP_HDRLEN + xlen;
    1304           0 :                 m->m_len -= PPP_HDRLEN + xlen;
    1305           0 :                 if (m->m_len <= M_TRAILINGSPACE(mp)) {
    1306           0 :                         bcopy(mtod(m, u_char *),
    1307           0 :                             mtod(mp, u_char *) + mp->m_len, m->m_len);
    1308           0 :                         mp->m_len += m->m_len;
    1309           0 :                         mp->m_next = m_free(m);
    1310           0 :                 } else
    1311           0 :                         mp->m_next = m;
    1312             :                 m = mp;
    1313           0 :                 ilen += hlen - xlen;
    1314             : 
    1315           0 :         } else if (proto == PPP_VJC_UNCOMP) {
    1316           0 :                 if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
    1317             :                         goto bad;
    1318             : 
    1319           0 :                 xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN,
    1320           0 :                     m->m_len - PPP_HDRLEN, ilen - PPP_HDRLEN,
    1321             :                     TYPE_UNCOMPRESSED_TCP, sc->sc_comp, &iphdr, &hlen);
    1322             : 
    1323           0 :                 if (xlen < 0) {
    1324           0 :                         if (sc->sc_flags & SC_DEBUG) {
    1325           0 :                                 printf("%s: VJ uncompress failed "
    1326           0 :                                     "on type uncomp\n", ifp->if_xname);
    1327           0 :                         }
    1328             :                         goto bad;
    1329             :                 }
    1330             : 
    1331             :                 proto = PPP_IP;
    1332           0 :                 cp[3] = PPP_IP;
    1333           0 :         }
    1334             : #endif /* VJC */
    1335             : 
    1336           0 :         m->m_pkthdr.len = ilen;
    1337           0 :         m->m_pkthdr.ph_ifidx = ifp->if_index;
    1338             : 
    1339             :         /* mark incoming routing table */
    1340           0 :         m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
    1341             : 
    1342           0 :         if ((proto & 0x8000) == 0) {
    1343             : #if NBPFILTER > 0
    1344             :                 /*
    1345             :                  * See whether we want to pass this packet, and
    1346             :                  * if it counts as link activity.
    1347             :                  */
    1348           0 :                 adrs = *mtod(m, u_char *);      /* save address field */
    1349           0 :                 *mtod(m, u_char *) = 0;         /* indicate inbound */
    1350           0 :                 if (sc->sc_pass_filt.bf_insns != 0 &&
    1351           0 :                     bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
    1352           0 :                      ilen, 0) == 0) {
    1353             :                         /* drop this packet */
    1354           0 :                         m_freem(m);
    1355           0 :                         return;
    1356             :                 }
    1357           0 :                 if (sc->sc_active_filt.bf_insns == 0 ||
    1358           0 :                     bpf_filter(sc->sc_active_filt.bf_insns, (u_char *)m,
    1359             :                      ilen, 0))
    1360           0 :                         sc->sc_last_recv = time_uptime;
    1361             : 
    1362           0 :                 *mtod(m, u_char *) = adrs;
    1363             : #else
    1364             :                 /*
    1365             :                  * Record the time that we received this packet.
    1366             :                  */
    1367             :                 sc->sc_last_recv = time_uptime;
    1368             : #endif
    1369           0 :         }
    1370             : 
    1371             : #if NBPFILTER > 0
    1372             :         /* See if bpf wants to look at the packet. */
    1373           0 :         if (sc->sc_bpf)
    1374           0 :                 bpf_mtap(sc->sc_bpf, m, BPF_DIRECTION_IN);
    1375             : #endif
    1376             : 
    1377             :         rv = 0;
    1378           0 :         switch (proto) {
    1379             :         case PPP_IP:
    1380             :                 /*
    1381             :                  * IP packet - take off the ppp header and pass it up to IP.
    1382             :                  */
    1383           0 :                 if ((ifp->if_flags & IFF_UP) == 0 ||
    1384           0 :                     sc->sc_npmode[NP_IP] != NPMODE_PASS) {
    1385             :                         /* interface is down - drop the packet. */
    1386           0 :                         m_freem(m);
    1387           0 :                         return;
    1388             :                 }
    1389           0 :                 m->m_pkthdr.len -= PPP_HDRLEN;
    1390           0 :                 m->m_data += PPP_HDRLEN;
    1391           0 :                 m->m_len -= PPP_HDRLEN;
    1392             : 
    1393           0 :                 ipv4_input(ifp, m);
    1394             :                 rv = 1;
    1395           0 :                 break;
    1396             : 
    1397             :         default:
    1398             :                 /*
    1399             :                  * Some other protocol - place on input queue for read().
    1400             :                  */
    1401           0 :                 if (mq_enqueue(&sc->sc_inq, m) != 0) {
    1402           0 :                         if_congestion();
    1403             :                         rv = 0; /* failure */
    1404           0 :                 } else
    1405             :                         rv = 2; /* input queue */
    1406             :                 break;
    1407             :         }
    1408             : 
    1409           0 :         if (rv == 0) {
    1410             :                 /* failure */
    1411           0 :                 if (sc->sc_flags & SC_DEBUG)
    1412           0 :                         printf("%s: input queue full\n", ifp->if_xname);
    1413           0 :                 ifp->if_iqdrops++;
    1414           0 :                 goto dropped;
    1415             :         }
    1416             : 
    1417           0 :         ifp->if_ipackets++;
    1418           0 :         ifp->if_ibytes += ilen;
    1419             : 
    1420           0 :         if (rv == 2)
    1421           0 :                 (*sc->sc_ctlp)(sc);
    1422             : 
    1423           0 :         return;
    1424             : 
    1425             : bad:
    1426           0 :         m_freem(m);
    1427             : dropped:
    1428           0 :         sc->sc_if.if_ierrors++;
    1429           0 :         sc->sc_stats.ppp_ierrors++;
    1430           0 : }
    1431             : 
    1432             : #define MAX_DUMP_BYTES  128
    1433             : 
    1434             : static void
    1435           0 : pppdumpm(struct mbuf *m0)
    1436             : {
    1437           0 :         char buf[3*MAX_DUMP_BYTES+4];
    1438           0 :         char *bp = buf;
    1439             :         struct mbuf *m;
    1440             :         static char digits[] = "0123456789abcdef";
    1441             : 
    1442           0 :         for (m = m0; m; m = m->m_next) {
    1443           0 :                 int l = m->m_len;
    1444           0 :                 u_char *rptr = mtod(m, u_char *);
    1445             : 
    1446           0 :                 while (l--) {
    1447           0 :                         if (bp > buf + sizeof(buf) - 4)
    1448           0 :                                 goto done;
    1449             : 
    1450             :                         /* convert byte to ascii hex */
    1451           0 :                         *bp++ = digits[*rptr >> 4];
    1452           0 :                         *bp++ = digits[*rptr++ & 0xf];
    1453             :                 }
    1454             : 
    1455           0 :                 if (m->m_next) {
    1456           0 :                         if (bp > buf + sizeof(buf) - 3)
    1457           0 :                                 goto done;
    1458           0 :                         *bp++ = '|';
    1459           0 :                 } else
    1460           0 :                         *bp++ = ' ';
    1461           0 :         }
    1462             : done:
    1463           0 :         if (m)
    1464           0 :                 *bp++ = '>';
    1465           0 :         *bp = 0;
    1466           0 :         printf("%s\n", buf);
    1467           0 : }
    1468             : 
    1469             : static void
    1470           0 : ppp_ifstart(struct ifnet *ifp)
    1471             : {
    1472             :         struct ppp_softc *sc;
    1473             : 
    1474           0 :         sc = ifp->if_softc;
    1475           0 :         (*sc->sc_start)(sc);
    1476           0 : }
    1477             : 
    1478             : void
    1479           0 : ppp_pkt_list_init(struct ppp_pkt_list *pl, u_int limit)
    1480             : {
    1481           0 :         mtx_init(&pl->pl_mtx, IPL_TTY);
    1482           0 :         pl->pl_head = pl->pl_tail = NULL;
    1483           0 :         pl->pl_count = 0;
    1484           0 :         pl->pl_limit = limit;
    1485           0 : }
    1486             : 
    1487             : int
    1488           0 : ppp_pkt_enqueue(struct ppp_pkt_list *pl, struct ppp_pkt *pkt)
    1489             : {
    1490             :         int drop = 0;
    1491             : 
    1492           0 :         mtx_enter(&pl->pl_mtx);
    1493           0 :         if (pl->pl_count < pl->pl_limit) {
    1494           0 :                 if (pl->pl_tail == NULL)
    1495           0 :                         pl->pl_head = pl->pl_tail = pkt;
    1496             :                 else {
    1497           0 :                         PKT_NEXTPKT(pl->pl_tail) = pkt;
    1498           0 :                         pl->pl_tail = pkt;
    1499             :                 }
    1500           0 :                 PKT_NEXTPKT(pkt) = NULL;
    1501           0 :                 pl->pl_count++;
    1502           0 :         } else
    1503             :                 drop = 1;
    1504           0 :         mtx_leave(&pl->pl_mtx);
    1505             : 
    1506           0 :         if (drop)
    1507           0 :                 ppp_pkt_free(pkt);
    1508             : 
    1509           0 :         return (drop);
    1510             : }
    1511             : 
    1512             : struct ppp_pkt *
    1513           0 : ppp_pkt_dequeue(struct ppp_pkt_list *pl)
    1514             : {
    1515             :         struct ppp_pkt *pkt;
    1516             : 
    1517           0 :         mtx_enter(&pl->pl_mtx);
    1518           0 :         pkt = pl->pl_head;
    1519           0 :         if (pkt != NULL) {
    1520           0 :                 pl->pl_head = PKT_NEXTPKT(pkt);
    1521           0 :                 if (pl->pl_head == NULL)
    1522           0 :                         pl->pl_tail = NULL;
    1523             : 
    1524           0 :                 pl->pl_count--;
    1525           0 :         }
    1526           0 :         mtx_leave(&pl->pl_mtx);
    1527             : 
    1528           0 :         return (pkt);
    1529             : }
    1530             : 
    1531             : struct mbuf *
    1532           0 : ppp_pkt_mbuf(struct ppp_pkt *pkt0)
    1533             : {
    1534             :         extern struct pool ppp_pkts;
    1535           0 :         struct mbuf *m0 = NULL, **mp = &m0, *m;
    1536             :         struct ppp_pkt *pkt = pkt0;
    1537             :         size_t len = 0;
    1538             : 
    1539           0 :         do {
    1540           0 :                 MGETHDR(m, M_DONTWAIT, MT_DATA);
    1541           0 :                 if (m == NULL)
    1542             :                         goto fail;
    1543             : 
    1544           0 :                 MEXTADD(m, pkt, sizeof(*pkt), M_EXTWR,
    1545             :                     MEXTFREE_POOL, &ppp_pkts);
    1546           0 :                 m->m_data += sizeof(pkt->p_hdr);
    1547           0 :                 m->m_len = PKT_LEN(pkt);
    1548             : 
    1549           0 :                 len += m->m_len;
    1550             : 
    1551           0 :                 *mp = m;
    1552           0 :                 mp = &m->m_next;
    1553             : 
    1554           0 :                 pkt = PKT_NEXT(pkt);
    1555           0 :         } while (pkt != NULL);
    1556             : 
    1557           0 :         m0->m_pkthdr.len = len;
    1558           0 :         if (pkt0->p_hdr.ph_errmark)
    1559           0 :                 m0->m_flags |= M_ERRMARK;
    1560             : 
    1561           0 :         return (m0);
    1562             : 
    1563             : fail:
    1564           0 :         m_freem(m0);
    1565           0 :         ppp_pkt_free(pkt0);
    1566           0 :         return (NULL);
    1567           0 : }
    1568             : 
    1569             : #endif  /* NPPP > 0 */

Generated by: LCOV version 1.13