The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_ppp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: c7b86a8777f54396cc085ac71e9ca9ae


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.