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/ppp_tty.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: ppp_tty.c,v 1.45 2006/11/16 01:33:40 christos Exp $    */
    2 /*      Id: ppp_tty.c,v 1.3 1996/07/01 01:04:11 paulus Exp      */
    3 
    4 /*
    5  * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
    6  *             tty devices.
    7  *
    8  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  *
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  *
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in
   19  *    the documentation and/or other materials provided with the
   20  *    distribution.
   21  *
   22  * 3. The name "Carnegie Mellon University" must not be used to
   23  *    endorse or promote products derived from this software without
   24  *    prior written permission. For permission or any legal
   25  *    details, please contact
   26  *      Office of Technology Transfer
   27  *      Carnegie Mellon University
   28  *      5000 Forbes Avenue
   29  *      Pittsburgh, PA  15213-3890
   30  *      (412) 268-4387, fax: (412) 268-7395
   31  *      tech-transfer@andrew.cmu.edu
   32  *
   33  * 4. Redistributions of any form whatsoever must retain the following
   34  *    acknowledgment:
   35  *    "This product includes software developed by Computing Services
   36  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
   37  *
   38  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
   39  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
   40  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
   41  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   42  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
   43  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
   44  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   45  *
   46  * Based on:
   47  *      @(#)if_sl.c     7.6.1.2 (Berkeley) 2/15/89
   48  *
   49  * Copyright (c) 1987 Regents of the University of California.
   50  * All rights reserved.
   51  *
   52  * Redistribution and use in source and binary forms are permitted
   53  * provided that the above copyright notice and this paragraph are
   54  * duplicated in all such forms and that any documentation,
   55  * advertising materials, and other materials related to such
   56  * distribution and use acknowledge that the software was developed
   57  * by the University of California, Berkeley.  The name of the
   58  * University may not be used to endorse or promote products derived
   59  * from this software without specific prior written permission.
   60  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
   61  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
   62  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
   63  *
   64  * Serial Line interface
   65  *
   66  * Rick Adams
   67  * Center for Seismic Studies
   68  * 1300 N 17th Street, Suite 1450
   69  * Arlington, Virginia 22209
   70  * (703)276-7900
   71  * rick@seismo.ARPA
   72  * seismo!rick
   73  *
   74  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
   75  * Converted to 4.3BSD Beta by Chris Torek.
   76  * Other changes made at Berkeley, based in part on code by Kirk Smith.
   77  *
   78  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
   79  * Added VJ tcp header compression; more unified ioctls
   80  *
   81  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
   82  * Cleaned up a lot of the mbuf-related code to fix bugs that
   83  * caused system crashes and packet corruption.  Changed pppstart
   84  * so that it doesn't just give up with a "collision" if the whole
   85  * packet doesn't fit in the output ring buffer.
   86  *
   87  * Added priority queueing for interactive IP packets, following
   88  * the model of if_sl.c, plus hooks for bpf.
   89  * Paul Mackerras (paulus@cs.anu.edu.au).
   90  */
   91 
   92 /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
   93 /* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
   94 
   95 #include <sys/cdefs.h>
   96 __KERNEL_RCSID(0, "$NetBSD: ppp_tty.c,v 1.45 2006/11/16 01:33:40 christos Exp $");
   97 
   98 #include "ppp.h"
   99 
  100 #include "opt_ppp.h"
  101 #define VJC
  102 #define PPP_COMPRESS
  103 
  104 #include <sys/param.h>
  105 #include <sys/proc.h>
  106 #include <sys/mbuf.h>
  107 #include <sys/dkstat.h>
  108 #include <sys/socket.h>
  109 #include <sys/ioctl.h>
  110 #include <sys/file.h>
  111 #include <sys/tty.h>
  112 #include <sys/kernel.h>
  113 #include <sys/conf.h>
  114 #include <sys/vnode.h>
  115 #include <sys/systm.h>
  116 #include <sys/kauth.h>
  117 
  118 #include <net/if.h>
  119 #include <net/if_types.h>
  120 
  121 #ifdef VJC
  122 #include <netinet/in.h>
  123 #include <netinet/in_systm.h>
  124 #include <netinet/ip.h>
  125 #include <net/slcompress.h>
  126 #endif
  127 
  128 #include "bpfilter.h"
  129 #if NBPFILTER > 0 || defined(PPP_FILTER)
  130 #include <net/bpf.h>
  131 #endif
  132 #include <net/ppp_defs.h>
  133 #include <net/if_ppp.h>
  134 #include <net/if_pppvar.h>
  135 
  136 static int      pppopen(dev_t dev, struct tty *tp);
  137 static int      pppclose(struct tty *tp, int flag);
  138 static int      pppread(struct tty *tp, struct uio *uio, int flag);
  139 static int      pppwrite(struct tty *tp, struct uio *uio, int flag);
  140 static int      ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag,
  141                           struct lwp *);
  142 static int      pppinput(int c, struct tty *tp);
  143 static int      pppstart(struct tty *tp);
  144 
  145 struct linesw ppp_disc = {      /* XXX should be static */
  146         .l_name = "ppp",
  147         .l_open = pppopen,
  148         .l_close = pppclose,
  149         .l_read = pppread,
  150         .l_write = pppwrite,
  151         .l_ioctl = ppptioctl,
  152         .l_rint = pppinput,
  153         .l_start = pppstart,
  154         .l_modem = ttymodem,
  155         .l_poll = ttpoll
  156 };
  157 
  158 static void     ppprcvframe(struct ppp_softc *sc, struct mbuf *m);
  159 static u_int16_t pppfcs(u_int16_t fcs, u_char *cp, int len);
  160 static void     pppsyncstart(struct ppp_softc *sc);
  161 static void     pppasyncstart(struct ppp_softc *);
  162 static void     pppasyncctlp(struct ppp_softc *);
  163 static void     pppasyncrelinq(struct ppp_softc *);
  164 static void     ppp_timeout(void *);
  165 static void     pppgetm(struct ppp_softc *sc);
  166 static void     pppdumpb(u_char *b, int l);
  167 static void     ppplogchar(struct ppp_softc *, int);
  168 static void     pppdumpframe(struct ppp_softc *sc, struct mbuf* m, int xmit);
  169 
  170 /*
  171  * Some useful mbuf macros not in mbuf.h.
  172  */
  173 #define M_IS_CLUSTER(m) ((m)->m_flags & M_EXT)
  174 
  175 #define M_DATASTART(m)  \
  176         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
  177             (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
  178 
  179 #define M_DATASIZE(m)   \
  180         (M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
  181             (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
  182 
  183 /*
  184  * Does c need to be escaped?
  185  */
  186 #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
  187 
  188 /*
  189  * Procedures for using an async tty interface for PPP.
  190  */
  191 
  192 /* This is a NetBSD-1.0 or later kernel. */
  193 #define CCOUNT(q)       ((q)->c_cc)
  194 
  195 #define PPP_LOWAT       100     /* Process more output when < LOWAT on queue */
  196 #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
  197 
  198 /*
  199  * Line specific open routine for async tty devices.
  200  * Attach the given tty to the first available ppp unit.
  201  * Called from device open routine or ttioctl.
  202  */
  203 /* ARGSUSED */
  204 static int
  205 pppopen(dev_t dev, struct tty *tp)
  206 {
  207     struct lwp *l = curlwp;             /* XXX */
  208     struct ppp_softc *sc;
  209     int error, s;
  210 
  211     if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  212         &l->l_acflag)) != 0)
  213         return (error);
  214 
  215     s = spltty();
  216 
  217     if (tp->t_linesw == &ppp_disc) {
  218         sc = (struct ppp_softc *) tp->t_sc;
  219         if (sc != NULL && sc->sc_devp == (void *) tp) {
  220             splx(s);
  221             return (0);
  222         }
  223     }
  224 
  225     if ((sc = pppalloc(l->l_proc->p_pid)) == NULL) {
  226         splx(s);
  227         return ENXIO;
  228     }
  229 
  230     if (sc->sc_relinq)
  231         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
  232 
  233 #if NBPFILTER > 0
  234     /* Switch DLT to PPP-over-serial. */
  235     bpf_change_type(&sc->sc_if, DLT_PPP_SERIAL, PPP_HDRLEN);
  236 #endif
  237 
  238     sc->sc_ilen = 0;
  239     sc->sc_m = NULL;
  240     memset(sc->sc_asyncmap, 0, sizeof(sc->sc_asyncmap));
  241     sc->sc_asyncmap[0] = 0xffffffff;
  242     sc->sc_asyncmap[3] = 0x60000000;
  243     sc->sc_rasyncmap = 0;
  244     sc->sc_devp = (void *) tp;
  245     sc->sc_start = pppasyncstart;
  246     sc->sc_ctlp = pppasyncctlp;
  247     sc->sc_relinq = pppasyncrelinq;
  248     sc->sc_outm = NULL;
  249     pppgetm(sc);
  250     sc->sc_if.if_flags |= IFF_RUNNING;
  251     sc->sc_if.if_baudrate = tp->t_ospeed;
  252 
  253     tp->t_sc = (caddr_t) sc;
  254     ttyflush(tp, FREAD | FWRITE);
  255 
  256     splx(s);
  257     return (0);
  258 }
  259 
  260 /*
  261  * Line specific close routine, called from device close routine
  262  * and from ttioctl.
  263  * Detach the tty from the ppp unit.
  264  * Mimics part of ttyclose().
  265  */
  266 static int
  267 pppclose(struct tty *tp, int flag)
  268 {
  269     struct ppp_softc *sc;
  270     int s;
  271 
  272     s = spltty();
  273     ttyflush(tp, FREAD|FWRITE);
  274     ttyldisc_release(tp->t_linesw);
  275     tp->t_linesw = ttyldisc_default();
  276     sc = (struct ppp_softc *) tp->t_sc;
  277     if (sc != NULL) {
  278         tp->t_sc = NULL;
  279         if (tp == (struct tty *) sc->sc_devp) {
  280             pppasyncrelinq(sc);
  281             pppdealloc(sc);
  282         }
  283     }
  284     splx(s);
  285     return 0;
  286 }
  287 
  288 /*
  289  * Relinquish the interface unit to another device.
  290  */
  291 static void
  292 pppasyncrelinq(struct ppp_softc *sc)
  293 {
  294     int s;
  295 
  296 #if NBPFILTER > 0
  297     /* Change DLT to back none. */
  298     bpf_change_type(&sc->sc_if, DLT_NULL, 0);
  299 #endif
  300 
  301     s = spltty();
  302     if (sc->sc_outm) {
  303         m_freem(sc->sc_outm);
  304         sc->sc_outm = NULL;
  305     }
  306     if (sc->sc_m) {
  307         m_freem(sc->sc_m);
  308         sc->sc_m = NULL;
  309     }
  310     if (sc->sc_flags & SC_TIMEOUT) {
  311         callout_stop(&sc->sc_timo_ch);
  312         sc->sc_flags &= ~SC_TIMEOUT;
  313     }
  314     splx(s);
  315 }
  316 
  317 /*
  318  * Line specific (tty) read routine.
  319  */
  320 static int
  321 pppread(struct tty *tp, struct uio *uio, int flag)
  322 {
  323     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  324     struct mbuf *m, *m0;
  325     int s;
  326     int error = 0;
  327 
  328     if (sc == NULL)
  329         return 0;
  330     /*
  331      * Loop waiting for input, checking that nothing disasterous
  332      * happens in the meantime.
  333      */
  334     s = spltty();
  335     for (;;) {
  336         if (tp != (struct tty *) sc->sc_devp ||
  337             tp->t_linesw != &ppp_disc) {
  338             splx(s);
  339             return 0;
  340         }
  341         if (sc->sc_inq.ifq_head != NULL)
  342             break;
  343         if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
  344             && (tp->t_state & TS_ISOPEN)) {
  345             splx(s);
  346             return 0;           /* end of file */
  347         }
  348         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
  349             splx(s);
  350             return (EWOULDBLOCK);
  351         }
  352         error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI|PCATCH, ttyin, 0);
  353         if (error) {
  354             splx(s);
  355             return error;
  356         }
  357     }
  358 
  359     /* Pull place-holder byte out of canonical queue */
  360     getc(&tp->t_canq);
  361 
  362     /* Get the packet from the input queue */
  363     IF_DEQUEUE(&sc->sc_inq, m0);
  364     splx(s);
  365 
  366     for (m = m0; m && uio->uio_resid; m = m->m_next)
  367         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
  368             break;
  369     m_freem(m0);
  370     return (error);
  371 }
  372 
  373 /*
  374  * Line specific (tty) write routine.
  375  */
  376 static int
  377 pppwrite(struct tty *tp, struct uio *uio, int flag)
  378 {
  379     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  380     struct mbuf *m, *m0;
  381     struct sockaddr dst;
  382     int len, error;
  383 
  384     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
  385         return 0;               /* wrote 0 bytes */
  386     if (tp->t_linesw != &ppp_disc)
  387         return (EINVAL);
  388     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  389         return EIO;
  390     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
  391         uio->uio_resid < PPP_HDRLEN)
  392         return (EMSGSIZE);
  393 
  394     MGETHDR(m0, M_WAIT, MT_DATA);
  395     if (m0 == NULL)
  396         return ENOBUFS;
  397 
  398     m0->m_len = 0;
  399     m0->m_pkthdr.len = uio->uio_resid;
  400     m0->m_pkthdr.rcvif = NULL;
  401 
  402     if (uio->uio_resid >= MCLBYTES / 2)
  403         MCLGET(m0, M_DONTWAIT);
  404 
  405     for (m = m0; uio->uio_resid;) {
  406         len = M_TRAILINGSPACE(m);
  407         if (len > uio->uio_resid)
  408             len = uio->uio_resid;
  409         if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
  410             m_freem(m0);
  411             return (error);
  412         }
  413         m->m_len = len;
  414 
  415         if (uio->uio_resid == 0)
  416             break;
  417 
  418         MGET(m->m_next, M_WAIT, MT_DATA);
  419         if (m->m_next == NULL) {
  420             m_freem(m0);
  421             return ENOBUFS;
  422         }
  423         m = m->m_next;
  424         m->m_len = 0;
  425     }
  426     dst.sa_family = AF_UNSPEC;
  427     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
  428     m_adj(m0, PPP_HDRLEN);
  429     return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
  430 }
  431 
  432 /*
  433  * Line specific (tty) ioctl routine.
  434  * This discipline requires that tty device drivers call
  435  * the line specific l_ioctl routine from their ioctl routines.
  436  */
  437 /* ARGSUSED */
  438 static int
  439 ppptioctl(struct tty *tp, u_long cmd, caddr_t data, int flag, struct lwp *l)
  440 {
  441     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
  442     int error, s;
  443 
  444     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  445         return (EPASSTHROUGH);
  446 
  447     error = 0;
  448     switch (cmd) {
  449     case TIOCRCVFRAME:
  450         ppprcvframe(sc,*((struct mbuf **)data));
  451         break;
  452 
  453     case PPPIOCSASYNCMAP:
  454         if ((error = kauth_authorize_generic(l->l_cred,
  455           KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
  456             break;
  457         sc->sc_asyncmap[0] = *(u_int *)data;
  458         break;
  459 
  460     case PPPIOCGASYNCMAP:
  461         *(u_int *)data = sc->sc_asyncmap[0];
  462         break;
  463 
  464     case PPPIOCSRASYNCMAP:
  465         if ((error = kauth_authorize_generic(l->l_cred,
  466           KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
  467             break;
  468         sc->sc_rasyncmap = *(u_int *)data;
  469         break;
  470 
  471     case PPPIOCGRASYNCMAP:
  472         *(u_int *)data = sc->sc_rasyncmap;
  473         break;
  474 
  475     case PPPIOCSXASYNCMAP:
  476         if ((error = kauth_authorize_generic(l->l_cred,
  477           KAUTH_GENERIC_ISSUSER, &l->l_acflag)) != 0)
  478             break;
  479         s = spltty();
  480         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
  481         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
  482         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
  483         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
  484         splx(s);
  485         break;
  486 
  487     case PPPIOCGXASYNCMAP:
  488         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
  489         break;
  490 
  491     default:
  492         error = pppioctl(sc, cmd, data, flag, l);
  493         if (error == 0 && cmd == PPPIOCSMRU)
  494             pppgetm(sc);
  495     }
  496 
  497     return error;
  498 }
  499 
  500 /* receive a complete ppp frame from device in synchronous
  501  * hdlc mode. caller gives up ownership of mbuf
  502  */
  503 static void
  504 ppprcvframe(struct ppp_softc *sc, struct mbuf *m)
  505 {
  506         int len, s;
  507         struct mbuf *n;
  508         u_char hdr[4];
  509         int hlen,count;
  510 
  511         for (n=m,len=0;n != NULL;n = n->m_next)
  512                 len += n->m_len;
  513         if (len==0) {
  514                 m_freem(m);
  515                 return;
  516         }
  517 
  518         /* extract PPP header from mbuf chain (1 to 4 bytes) */
  519         for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
  520                 count = (sizeof(hdr)-hlen) < n->m_len ?
  521                                 sizeof(hdr)-hlen : n->m_len;
  522                 bcopy(mtod(n,u_char*),&hdr[hlen],count);
  523                 hlen+=count;
  524         }
  525 
  526         s = spltty();
  527 
  528         /* if AFCF compressed then prepend AFCF */
  529         if (hdr[0] != PPP_ALLSTATIONS) {
  530                 if (sc->sc_flags & SC_REJ_COMP_AC) {
  531                         if (sc->sc_flags & SC_DEBUG)
  532                                 printf(
  533                                     "%s: garbage received: 0x%x (need 0xFF)\n",
  534                                     sc->sc_if.if_xname, hdr[0]);
  535                                 goto bail;
  536                         }
  537                 M_PREPEND(m,2,M_DONTWAIT);
  538                 if (m==NULL) {
  539                         splx(s);
  540                         return;
  541                 }
  542                 hdr[3] = hdr[1];
  543                 hdr[2] = hdr[0];
  544                 hdr[0] = PPP_ALLSTATIONS;
  545                 hdr[1] = PPP_UI;
  546                 len += 2;
  547         }
  548 
  549         /* if protocol field compressed, add MSB of protocol field = 0 */
  550         if (hdr[2] & 1) {
  551                 /* a compressed protocol */
  552                 M_PREPEND(m,1,M_DONTWAIT);
  553                 if (m==NULL) {
  554                         splx(s);
  555                         return;
  556                 }
  557                 hdr[3] = hdr[2];
  558                 hdr[2] = 0;
  559                 len++;
  560         }
  561 
  562         /* valid LSB of protocol field has bit0 set */
  563         if (!(hdr[3] & 1)) {
  564                 if (sc->sc_flags & SC_DEBUG)
  565                         printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
  566                                 (hdr[2] << 8) + hdr[3]);
  567                         goto bail;
  568         }
  569 
  570         /* packet beyond configured mru? */
  571         if (len > sc->sc_mru + PPP_HDRLEN) {
  572                 if (sc->sc_flags & SC_DEBUG)
  573                         printf("%s: packet too big\n", sc->sc_if.if_xname);
  574                 goto bail;
  575         }
  576 
  577         /* add expanded 4 byte header to mbuf chain */
  578         for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
  579                 count = (sizeof(hdr)-hlen) < n->m_len ?
  580                                 sizeof(hdr)-hlen : n->m_len;
  581                 bcopy(&hdr[hlen],mtod(n,u_char*),count);
  582                 hlen+=count;
  583         }
  584 
  585         /* if_ppp.c requires the PPP header and IP header */
  586         /* to be contiguous */
  587         count = len < MHLEN ? len : MHLEN;
  588         if (m->m_len < count) {
  589                 m = m_pullup(m,count);
  590                 if (m==NULL)
  591                         goto bail;
  592         }
  593 
  594         sc->sc_stats.ppp_ibytes += len;
  595 
  596         if (sc->sc_flags & SC_LOG_RAWIN)
  597                 pppdumpframe(sc,m,0);
  598 
  599         ppppktin(sc, m, 0);
  600         splx(s);
  601         return;
  602 bail:
  603         m_freem(m);
  604         splx(s);
  605 }
  606 
  607 /*
  608  * FCS lookup table as calculated by genfcstab.
  609  */
  610 static const u_int16_t fcstab[256] = {
  611         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  612         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  613         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  614         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  615         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  616         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  617         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  618         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  619         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  620         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  621         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  622         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  623         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  624         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  625         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  626         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  627         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  628         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  629         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  630         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  631         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  632         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  633         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  634         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  635         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  636         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  637         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  638         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  639         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  640         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  641         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  642         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  643 };
  644 
  645 /*
  646  * Calculate a new FCS given the current FCS and the new data.
  647  */
  648 static u_int16_t
  649 pppfcs(u_int16_t fcs, u_char *cp, int len)
  650 {
  651     while (len--)
  652         fcs = PPP_FCS(fcs, *cp++);
  653     return (fcs);
  654 }
  655 
  656 /* This gets called at splsoftnet from pppasyncstart at various times
  657  * when there is data ready to be sent.
  658  */
  659 static void
  660 pppsyncstart(struct ppp_softc *sc)
  661 {
  662         struct tty *tp = (struct tty *) sc->sc_devp;
  663         struct mbuf *m, *n;
  664         const struct cdevsw *cdev;
  665         int len;
  666 
  667         for(m = sc->sc_outm;;) {
  668                 if (m == NULL) {
  669                         m = ppp_dequeue(sc);    /* get new packet */
  670                         if (m == NULL)
  671                                 break;          /* no more packets */
  672                         if (sc->sc_flags & SC_DEBUG)
  673                                 pppdumpframe(sc,m,1);
  674                 }
  675                 for(n=m,len=0;n!=NULL;n=n->m_next)
  676                         len += n->m_len;
  677 
  678                 /* call device driver IOCTL to transmit a frame */
  679                 cdev = cdevsw_lookup(tp->t_dev);
  680                 if (cdev == NULL ||
  681                     (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (caddr_t)&m,
  682                                      0, 0)) {
  683                         /* busy or error, set as current packet */
  684                         sc->sc_outm = m;
  685                         break;
  686                 }
  687                 sc->sc_outm = m = NULL;
  688                 sc->sc_stats.ppp_obytes += len;
  689         }
  690 }
  691 
  692 /*
  693  * This gets called at splsoftnet from if_ppp.c at various times
  694  * when there is data ready to be sent.
  695  */
  696 static void
  697 pppasyncstart(struct ppp_softc *sc)
  698 {
  699     struct tty *tp = (struct tty *) sc->sc_devp;
  700     struct mbuf *m;
  701     int len;
  702     u_char *start, *stop, *cp;
  703     int n, ndone, done, idle;
  704     struct mbuf *m2;
  705     int s;
  706 
  707     if (sc->sc_flags & SC_SYNC){
  708         pppsyncstart(sc);
  709         return;
  710     }
  711 
  712     idle = 0;
  713     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
  714         /*
  715          * See if we have an existing packet partly sent.
  716          * If not, get a new packet and start sending it.
  717          */
  718         m = sc->sc_outm;
  719         if (m == NULL) {
  720             /*
  721              * Get another packet to be sent.
  722              */
  723             m = ppp_dequeue(sc);
  724             if (m == NULL) {
  725                 idle = 1;
  726                 break;
  727             }
  728 
  729             /*
  730              * The extra PPP_FLAG will start up a new packet, and thus
  731              * will flush any accumulated garbage.  We do this whenever
  732              * the line may have been idle for some time.
  733              */
  734             if (CCOUNT(&tp->t_outq) == 0) {
  735                 ++sc->sc_stats.ppp_obytes;
  736                 (void) putc(PPP_FLAG, &tp->t_outq);
  737             }
  738 
  739             /* Calculate the FCS for the first mbuf's worth. */
  740             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
  741         }
  742 
  743         for (;;) {
  744             start = mtod(m, u_char *);
  745             len = m->m_len;
  746             stop = start + len;
  747             while (len > 0) {
  748                 /*
  749                  * Find out how many bytes in the string we can
  750                  * handle without doing something special.
  751                  */
  752                 for (cp = start; cp < stop; cp++)
  753                     if (ESCAPE_P(*cp))
  754                         break;
  755                 n = cp - start;
  756                 if (n) {
  757                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
  758                     ndone = n - b_to_q(start, n, &tp->t_outq);
  759                     len -= ndone;
  760                     start += ndone;
  761                     sc->sc_stats.ppp_obytes += ndone;
  762 
  763                     if (ndone < n)
  764                         break;  /* packet doesn't fit */
  765                 }
  766                 /*
  767                  * If there are characters left in the mbuf,
  768                  * the first one must be special.
  769                  * Put it out in a different form.
  770                  */
  771                 if (len) {
  772                     s = spltty();
  773                     if (putc(PPP_ESCAPE, &tp->t_outq)) {
  774                         splx(s);
  775                         break;
  776                     }
  777                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
  778                         (void) unputc(&tp->t_outq);
  779                         splx(s);
  780                         break;
  781                     }
  782                     splx(s);
  783                     sc->sc_stats.ppp_obytes += 2;
  784                     start++;
  785                     len--;
  786                 }
  787             }
  788 
  789             /*
  790              * If we didn't empty this mbuf, remember where we're up to.
  791              * If we emptied the last mbuf, try to add the FCS and closing
  792              * flag, and if we can't, leave sc_outm pointing to m, but with
  793              * m->m_len == 0, to remind us to output the FCS and flag later.
  794              */
  795             done = len == 0;
  796             if (done && m->m_next == NULL) {
  797                 u_char *p, *q;
  798                 int c;
  799                 u_char endseq[8];
  800 
  801                 /*
  802                  * We may have to escape the bytes in the FCS.
  803                  */
  804                 p = endseq;
  805                 c = ~sc->sc_outfcs & 0xFF;
  806                 if (ESCAPE_P(c)) {
  807                     *p++ = PPP_ESCAPE;
  808                     *p++ = c ^ PPP_TRANS;
  809                 } else
  810                     *p++ = c;
  811                 c = (~sc->sc_outfcs >> 8) & 0xFF;
  812                 if (ESCAPE_P(c)) {
  813                     *p++ = PPP_ESCAPE;
  814                     *p++ = c ^ PPP_TRANS;
  815                 } else
  816                     *p++ = c;
  817                 *p++ = PPP_FLAG;
  818 
  819                 /*
  820                  * Try to output the FCS and flag.  If the bytes
  821                  * don't all fit, back out.
  822                  */
  823                 s = spltty();
  824                 for (q = endseq; q < p; ++q)
  825                     if (putc(*q, &tp->t_outq)) {
  826                         done = 0;
  827                         for (; q > endseq; --q)
  828                             unputc(&tp->t_outq);
  829                         break;
  830                     }
  831                 splx(s);
  832                 if (done)
  833                     sc->sc_stats.ppp_obytes += q - endseq;
  834             }
  835 
  836             if (!done) {
  837                 /* remember where we got to */
  838                 m->m_data = start;
  839                 m->m_len = len;
  840                 break;
  841             }
  842 
  843             /* Finished with this mbuf; free it and move on. */
  844             MFREE(m, m2);
  845             m = m2;
  846             if (m == NULL) {
  847                 /* Finished a packet */
  848                 break;
  849             }
  850             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
  851         }
  852 
  853         /*
  854          * If m == NULL, we have finished a packet.
  855          * If m != NULL, we've either done as much work this time
  856          * as we need to, or else we've filled up the output queue.
  857          */
  858         sc->sc_outm = m;
  859         if (m)
  860             break;
  861     }
  862 
  863     /* Call pppstart to start output again if necessary. */
  864     s = spltty();
  865     pppstart(tp);
  866 
  867     /*
  868      * This timeout is needed for operation on a pseudo-tty,
  869      * because the pty code doesn't call pppstart after it has
  870      * drained the t_outq.
  871      */
  872     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
  873         callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
  874         sc->sc_flags |= SC_TIMEOUT;
  875     }
  876 
  877     splx(s);
  878 }
  879 
  880 /*
  881  * This gets called when a received packet is placed on
  882  * the inq, at splsoftnet.
  883  */
  884 static void
  885 pppasyncctlp(struct ppp_softc *sc)
  886 {
  887     struct tty *tp;
  888     int s;
  889 
  890     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
  891     s = spltty();
  892     tp = (struct tty *) sc->sc_devp;
  893     putc(0, &tp->t_canq);
  894     ttwakeup(tp);
  895     splx(s);
  896 }
  897 
  898 /*
  899  * Start output on async tty interface.  If the transmit queue
  900  * has drained sufficiently, arrange for pppasyncstart to be
  901  * called later at splsoftnet.
  902  * Called at spltty or higher.
  903  */
  904 static int
  905 pppstart(struct tty *tp)
  906 {
  907     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
  908 
  909     /*
  910      * If there is stuff in the output queue, send it now.
  911      * We are being called in lieu of ttstart and must do what it would.
  912      */
  913     if (tp->t_oproc != NULL)
  914         (*tp->t_oproc)(tp);
  915 
  916     /*
  917      * If the transmit queue has drained and the tty has not hung up
  918      * or been disconnected from the ppp unit, then tell if_ppp.c that
  919      * we need more output.
  920      */
  921     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
  922         && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
  923         return 0;
  924 #ifdef ALTQ
  925     /*
  926      * if ALTQ is enabled, don't invoke NETISR_PPP.
  927      * pppintr() could loop without doing anything useful
  928      * under rate-limiting.
  929      */
  930     if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
  931         return 0;
  932 #endif
  933     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
  934         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
  935         ppp_restart(sc);
  936     }
  937 
  938     return 0;
  939 }
  940 
  941 /*
  942  * Timeout routine - try to start some more output.
  943  */
  944 static void
  945 ppp_timeout(void *x)
  946 {
  947     struct ppp_softc *sc = (struct ppp_softc *) x;
  948     struct tty *tp = (struct tty *) sc->sc_devp;
  949     int s;
  950 
  951     s = spltty();
  952     sc->sc_flags &= ~SC_TIMEOUT;
  953     pppstart(tp);
  954     splx(s);
  955 }
  956 
  957 /*
  958  * Allocate enough mbuf to handle current MRU.
  959  */
  960 static void
  961 pppgetm(struct ppp_softc *sc)
  962 {
  963     struct mbuf *m, **mp;
  964     int len;
  965 
  966     mp = &sc->sc_m;
  967     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
  968         if ((m = *mp) == NULL) {
  969             MGETHDR(m, M_DONTWAIT, MT_DATA);
  970             if (m == NULL)
  971                 break;
  972             *mp = m;
  973             MCLGET(m, M_DONTWAIT);
  974         }
  975         len -= M_DATASIZE(m);
  976         mp = &m->m_next;
  977     }
  978 }
  979 
  980 /*
  981  * tty interface receiver interrupt.
  982  */
  983 static const unsigned paritytab[8] = {
  984     0x96696996, 0x69969669, 0x69969669, 0x96696996,
  985     0x69969669, 0x96696996, 0x96696996, 0x69969669
  986 };
  987 
  988 static int
  989 pppinput(int c, struct tty *tp)
  990 {
  991     struct ppp_softc *sc;
  992     struct mbuf *m;
  993     const struct cdevsw *cdev;
  994     int ilen, s;
  995 
  996     sc = (struct ppp_softc *) tp->t_sc;
  997     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  998         return 0;
  999 
 1000     ++tk_nin;
 1001     ++sc->sc_stats.ppp_ibytes;
 1002 
 1003     if (c & TTY_FE) {
 1004         /* framing error or overrun on this char - abort packet */
 1005         if (sc->sc_flags & SC_DEBUG)
 1006             printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
 1007         goto flush;
 1008     }
 1009 
 1010     c &= 0xff;
 1011 
 1012     /*
 1013      * Handle software flow control of output.
 1014      */
 1015     if (tp->t_iflag & IXON) {
 1016         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
 1017             if ((tp->t_state & TS_TTSTOP) == 0) {
 1018                 tp->t_state |= TS_TTSTOP;
 1019                 cdev = cdevsw_lookup(tp->t_dev);
 1020                 if (cdev != NULL)
 1021                         (*cdev->d_stop)(tp, 0);
 1022             }
 1023             return 0;
 1024         }
 1025         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
 1026             tp->t_state &= ~TS_TTSTOP;
 1027             if (tp->t_oproc != NULL)
 1028                 (*tp->t_oproc)(tp);
 1029             return 0;
 1030         }
 1031     }
 1032 
 1033     s = spltty();
 1034     if (c & 0x80)
 1035         sc->sc_flags |= SC_RCV_B7_1;
 1036     else
 1037         sc->sc_flags |= SC_RCV_B7_0;
 1038     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
 1039         sc->sc_flags |= SC_RCV_ODDP;
 1040     else
 1041         sc->sc_flags |= SC_RCV_EVNP;
 1042     splx(s);
 1043 
 1044     ppplogchar(sc, c);
 1045 
 1046     if (c == PPP_FLAG) {
 1047         ilen = sc->sc_ilen;
 1048         sc->sc_ilen = 0;
 1049 
 1050         if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
 1051             ppplogchar(sc, -1);
 1052 
 1053         /*
 1054          * If SC_ESCAPED is set, then we've seen the packet
 1055          * abort sequence "}~".
 1056          */
 1057         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
 1058             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
 1059             s = spltty();
 1060             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
 1061             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
 1062                 if (sc->sc_flags & SC_DEBUG)
 1063                     printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
 1064                         sc->sc_fcs);
 1065                 sc->sc_if.if_ierrors++;
 1066                 sc->sc_stats.ppp_ierrors++;
 1067             } else
 1068                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
 1069             splx(s);
 1070             return 0;
 1071         }
 1072 
 1073         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
 1074             if (ilen) {
 1075                 if (sc->sc_flags & SC_DEBUG)
 1076                     printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
 1077                 s = spltty();
 1078                 sc->sc_if.if_ierrors++;
 1079                 sc->sc_stats.ppp_ierrors++;
 1080                 sc->sc_flags |= SC_PKTLOST;
 1081                 splx(s);
 1082             }
 1083             return 0;
 1084         }
 1085 
 1086         /*
 1087          * Remove FCS trailer.  Somewhat painful...
 1088          */
 1089         ilen -= 2;
 1090         if (--sc->sc_mc->m_len == 0) {
 1091             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
 1092                 ;
 1093             sc->sc_mc = m;
 1094         }
 1095         sc->sc_mc->m_len--;
 1096 
 1097         /* excise this mbuf chain */
 1098         m = sc->sc_m;
 1099         sc->sc_m = sc->sc_mc->m_next;
 1100         sc->sc_mc->m_next = NULL;
 1101 
 1102         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
 1103         if (sc->sc_flags & SC_PKTLOST) {
 1104             s = spltty();
 1105             sc->sc_flags &= ~SC_PKTLOST;
 1106             splx(s);
 1107         }
 1108 
 1109         pppgetm(sc);
 1110         return 0;
 1111     }
 1112 
 1113     if (sc->sc_flags & SC_FLUSH) {
 1114         if (sc->sc_flags & SC_LOG_FLUSH)
 1115             ppplogchar(sc, c);
 1116         return 0;
 1117     }
 1118 
 1119     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
 1120         return 0;
 1121 
 1122     s = spltty();
 1123     if (sc->sc_flags & SC_ESCAPED) {
 1124         sc->sc_flags &= ~SC_ESCAPED;
 1125         c ^= PPP_TRANS;
 1126     } else if (c == PPP_ESCAPE) {
 1127         sc->sc_flags |= SC_ESCAPED;
 1128         splx(s);
 1129         return 0;
 1130     }
 1131     splx(s);
 1132 
 1133     /*
 1134      * Initialize buffer on first octet received.
 1135      * First octet could be address or protocol (when compressing
 1136      * address/control).
 1137      * Second octet is control.
 1138      * Third octet is first or second (when compressing protocol)
 1139      * octet of protocol.
 1140      * Fourth octet is second octet of protocol.
 1141      */
 1142     if (sc->sc_ilen == 0) {
 1143         /* reset the first input mbuf */
 1144         if (sc->sc_m == NULL) {
 1145             pppgetm(sc);
 1146             if (sc->sc_m == NULL) {
 1147                 if (sc->sc_flags & SC_DEBUG)
 1148                     printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
 1149                 goto flush;
 1150             }
 1151         }
 1152         m = sc->sc_m;
 1153         m->m_len = 0;
 1154         m->m_data = M_DATASTART(sc->sc_m);
 1155         sc->sc_mc = m;
 1156         sc->sc_mp = mtod(m, char *);
 1157         sc->sc_fcs = PPP_INITFCS;
 1158         if (c != PPP_ALLSTATIONS) {
 1159             if (sc->sc_flags & SC_REJ_COMP_AC) {
 1160                 if (sc->sc_flags & SC_DEBUG)
 1161                     printf("%s: garbage received: 0x%x (need 0xFF)\n",
 1162                     sc->sc_if.if_xname, c);
 1163                 goto flush;
 1164             }
 1165             *sc->sc_mp++ = PPP_ALLSTATIONS;
 1166             *sc->sc_mp++ = PPP_UI;
 1167             sc->sc_ilen += 2;
 1168             m->m_len += 2;
 1169         }
 1170     }
 1171     if (sc->sc_ilen == 1 && c != PPP_UI) {
 1172         if (sc->sc_flags & SC_DEBUG)
 1173             printf("%s: missing UI (0x3), got 0x%x\n",
 1174                 sc->sc_if.if_xname, c);
 1175         goto flush;
 1176     }
 1177     if (sc->sc_ilen == 2 && (c & 1) == 1) {
 1178         /* a compressed protocol */
 1179         *sc->sc_mp++ = 0;
 1180         sc->sc_ilen++;
 1181         sc->sc_mc->m_len++;
 1182     }
 1183     if (sc->sc_ilen == 3 && (c & 1) == 0) {
 1184         if (sc->sc_flags & SC_DEBUG)
 1185             printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
 1186                 (sc->sc_mp[-1] << 8) + c);
 1187         goto flush;
 1188     }
 1189 
 1190     /* packet beyond configured mru? */
 1191     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
 1192         if (sc->sc_flags & SC_DEBUG)
 1193             printf("%s: packet too big\n", sc->sc_if.if_xname);
 1194         goto flush;
 1195     }
 1196 
 1197     /* is this mbuf full? */
 1198     m = sc->sc_mc;
 1199     if (M_TRAILINGSPACE(m) <= 0) {
 1200         if (m->m_next == NULL) {
 1201             pppgetm(sc);
 1202             if (m->m_next == NULL) {
 1203                 if (sc->sc_flags & SC_DEBUG)
 1204                     printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
 1205                 goto flush;
 1206             }
 1207         }
 1208         sc->sc_mc = m = m->m_next;
 1209         m->m_len = 0;
 1210         m->m_data = M_DATASTART(m);
 1211         sc->sc_mp = mtod(m, char *);
 1212     }
 1213 
 1214     ++m->m_len;
 1215     *sc->sc_mp++ = c;
 1216     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
 1217     return 0;
 1218 
 1219  flush:
 1220     if (!(sc->sc_flags & SC_FLUSH)) {
 1221         s = spltty();
 1222         sc->sc_if.if_ierrors++;
 1223         sc->sc_stats.ppp_ierrors++;
 1224         sc->sc_flags |= SC_FLUSH;
 1225         splx(s);
 1226         if (sc->sc_flags & SC_LOG_FLUSH)
 1227             ppplogchar(sc, c);
 1228     }
 1229     return 0;
 1230 }
 1231 
 1232 #define MAX_DUMP_BYTES  128
 1233 
 1234 static void
 1235 ppplogchar(struct ppp_softc *sc, int c)
 1236 {
 1237     if (c >= 0) {
 1238         sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
 1239         if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
 1240             sc->sc_rawin.count++;
 1241     }
 1242     if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
 1243         || (c < 0 && sc->sc_rawin_start > 0)) {
 1244         if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
 1245             printf("%s input: ", sc->sc_if.if_xname);
 1246             pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
 1247         }
 1248         if (c < 0)
 1249             sc->sc_rawin.count = 0;
 1250         sc->sc_rawin_start = 0;
 1251     }
 1252 }
 1253 
 1254 static void
 1255 pppdumpb(u_char *b, int l)
 1256 {
 1257     char bf[3*MAX_DUMP_BYTES+4];
 1258     char *bp = bf;
 1259 
 1260     while (l--) {
 1261         if (bp >= bf + sizeof(bf) - 3) {
 1262             *bp++ = '>';
 1263             break;
 1264         }
 1265         *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
 1266         *bp++ = hexdigits[*b++ & 0xf];
 1267         *bp++ = ' ';
 1268     }
 1269 
 1270     *bp = 0;
 1271     printf("%s\n", bf);
 1272 }
 1273 
 1274 static void
 1275 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
 1276 {
 1277         int i,lcount,copycount,count;
 1278         char lbuf[16];
 1279         char *data;
 1280 
 1281         if (m == NULL)
 1282                 return;
 1283 
 1284         for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
 1285                 /* build a line of output */
 1286                 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
 1287                         if (!count) {
 1288                                 m = m->m_next;
 1289                                 if (m == NULL)
 1290                                         break;
 1291                                 count = m->m_len;
 1292                                 data  = mtod(m,char*);
 1293                         }
 1294                         copycount = (count > sizeof(lbuf)-lcount) ?
 1295                                         sizeof(lbuf)-lcount : count;
 1296                         bcopy(data,&lbuf[lcount],copycount);
 1297                         data  += copycount;
 1298                         count -= copycount;
 1299                 }
 1300 
 1301                 /* output line (hex 1st, then ascii) */
 1302                 printf("%s %s:", sc->sc_if.if_xname,
 1303                     xmit ? "output" : "input ");
 1304                 for(i=0;i<lcount;i++)
 1305                         printf("%02x ",(u_char)lbuf[i]);
 1306                 for(;i<sizeof(lbuf);i++)
 1307                         printf("   ");
 1308                 for(i=0;i<lcount;i++)
 1309                         printf("%c",(lbuf[i] >= 040 &&
 1310                             lbuf[i] <= 0176) ? lbuf[i] : '.');
 1311                 printf("\n");
 1312         }
 1313 }

Cache object: 572b9e75d74f0f92261b7a9afa116139


[ 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.