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.53 2008/05/25 19:22:21 ad 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.53 2008/05/25 19:22:21 ad 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, void *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 uint16_t pppfcs(uint16_t fcs, const uint8_t *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         NULL)) != 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 = (void *) sc;
  254     mutex_spin_enter(&tty_lock);
  255     ttyflush(tp, FREAD | FWRITE);
  256     mutex_spin_exit(&tty_lock);
  257 
  258     splx(s);
  259     return (0);
  260 }
  261 
  262 /*
  263  * Line specific close routine, called from device close routine
  264  * and from ttioctl.
  265  * Detach the tty from the ppp unit.
  266  * Mimics part of ttyclose().
  267  */
  268 static int
  269 pppclose(struct tty *tp, int flag)
  270 {
  271     struct ppp_softc *sc;
  272     int s;
  273 
  274     s = spltty();
  275     mutex_spin_enter(&tty_lock);
  276     ttyflush(tp, FREAD|FWRITE);
  277     mutex_spin_exit(&tty_lock); /* XXX */
  278     ttyldisc_release(tp->t_linesw);
  279     tp->t_linesw = ttyldisc_default();
  280     sc = (struct ppp_softc *) tp->t_sc;
  281     if (sc != NULL) {
  282         tp->t_sc = NULL;
  283         if (tp == (struct tty *) sc->sc_devp) {
  284             pppasyncrelinq(sc);
  285             pppdealloc(sc);
  286         }
  287     }
  288     splx(s);
  289     return 0;
  290 }
  291 
  292 /*
  293  * Relinquish the interface unit to another device.
  294  */
  295 static void
  296 pppasyncrelinq(struct ppp_softc *sc)
  297 {
  298     int s;
  299 
  300 #if NBPFILTER > 0
  301     /* Change DLT to back none. */
  302     bpf_change_type(&sc->sc_if, DLT_NULL, 0);
  303 #endif
  304 
  305     s = spltty();
  306     if (sc->sc_outm) {
  307         m_freem(sc->sc_outm);
  308         sc->sc_outm = NULL;
  309     }
  310     if (sc->sc_m) {
  311         m_freem(sc->sc_m);
  312         sc->sc_m = NULL;
  313     }
  314     if (sc->sc_flags & SC_TIMEOUT) {
  315         callout_stop(&sc->sc_timo_ch);
  316         sc->sc_flags &= ~SC_TIMEOUT;
  317     }
  318     splx(s);
  319 }
  320 
  321 /*
  322  * Line specific (tty) read routine.
  323  */
  324 static int
  325 pppread(struct tty *tp, struct uio *uio, int flag)
  326 {
  327     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  328     struct mbuf *m, *m0;
  329     int error = 0;
  330 
  331     if (sc == NULL)
  332         return 0;
  333     /*
  334      * Loop waiting for input, checking that nothing disasterous
  335      * happens in the meantime.
  336      */
  337     mutex_spin_enter(&tty_lock);
  338     for (;;) {
  339         if (tp != (struct tty *) sc->sc_devp ||
  340             tp->t_linesw != &ppp_disc) {
  341             mutex_spin_exit(&tty_lock);
  342             return 0;
  343         }
  344         if (sc->sc_inq.ifq_head != NULL)
  345             break;
  346         if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0
  347             && (tp->t_state & TS_ISOPEN)) {
  348             mutex_spin_exit(&tty_lock);
  349             return 0;           /* end of file */
  350         }
  351         if (tp->t_state & TS_ASYNC || flag & IO_NDELAY) {
  352             mutex_spin_exit(&tty_lock);
  353             return (EWOULDBLOCK);
  354         }
  355         error = ttysleep(tp, &tp->t_rawcv, true, 0);
  356         if (error) {
  357             mutex_spin_exit(&tty_lock);
  358             return error;
  359         }
  360     }
  361 
  362     /* Pull place-holder byte out of canonical queue */
  363     getc(&tp->t_canq);
  364 
  365     /* Get the packet from the input queue */
  366     IF_DEQUEUE(&sc->sc_inq, m0);
  367     mutex_spin_exit(&tty_lock);
  368 
  369     for (m = m0; m && uio->uio_resid; m = m->m_next)
  370         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
  371             break;
  372     m_freem(m0);
  373     return (error);
  374 }
  375 
  376 /*
  377  * Line specific (tty) write routine.
  378  */
  379 static int
  380 pppwrite(struct tty *tp, struct uio *uio, int flag)
  381 {
  382     struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  383     struct mbuf *m, *m0;
  384     struct sockaddr dst;
  385     int len, error;
  386 
  387     if ((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
  388         return 0;               /* wrote 0 bytes */
  389     if (tp->t_linesw != &ppp_disc)
  390         return (EINVAL);
  391     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  392         return EIO;
  393     if (uio->uio_resid > sc->sc_if.if_mtu + PPP_HDRLEN ||
  394         uio->uio_resid < PPP_HDRLEN)
  395         return (EMSGSIZE);
  396 
  397     MGETHDR(m0, M_WAIT, MT_DATA);
  398     if (m0 == NULL)
  399         return ENOBUFS;
  400 
  401     m0->m_len = 0;
  402     m0->m_pkthdr.len = uio->uio_resid;
  403     m0->m_pkthdr.rcvif = NULL;
  404 
  405     if (uio->uio_resid >= MCLBYTES / 2)
  406         MCLGET(m0, M_DONTWAIT);
  407 
  408     for (m = m0; uio->uio_resid;) {
  409         len = M_TRAILINGSPACE(m);
  410         if (len > uio->uio_resid)
  411             len = uio->uio_resid;
  412         if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
  413             m_freem(m0);
  414             return (error);
  415         }
  416         m->m_len = len;
  417 
  418         if (uio->uio_resid == 0)
  419             break;
  420 
  421         MGET(m->m_next, M_WAIT, MT_DATA);
  422         if (m->m_next == NULL) {
  423             m_freem(m0);
  424             return ENOBUFS;
  425         }
  426         m = m->m_next;
  427         m->m_len = 0;
  428     }
  429     dst.sa_family = AF_UNSPEC;
  430     bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
  431     m_adj(m0, PPP_HDRLEN);
  432     return ((*sc->sc_if.if_output)(&sc->sc_if, m0, &dst, (struct rtentry *)0));
  433 }
  434 
  435 /*
  436  * Line specific (tty) ioctl routine.
  437  * This discipline requires that tty device drivers call
  438  * the line specific l_ioctl routine from their ioctl routines.
  439  */
  440 /* ARGSUSED */
  441 static int
  442 ppptioctl(struct tty *tp, u_long cmd, void *data, int flag, struct lwp *l)
  443 {
  444     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
  445     int error, s;
  446 
  447     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  448         return (EPASSTHROUGH);
  449 
  450     error = 0;
  451     switch (cmd) {
  452     case TIOCRCVFRAME:
  453         ppprcvframe(sc,*((struct mbuf **)data));
  454         break;
  455 
  456     case PPPIOCSASYNCMAP:
  457         if ((error = kauth_authorize_generic(l->l_cred,
  458           KAUTH_GENERIC_ISSUSER, NULL)) != 0)
  459             break;
  460         sc->sc_asyncmap[0] = *(u_int *)data;
  461         break;
  462 
  463     case PPPIOCGASYNCMAP:
  464         *(u_int *)data = sc->sc_asyncmap[0];
  465         break;
  466 
  467     case PPPIOCSRASYNCMAP:
  468         if ((error = kauth_authorize_generic(l->l_cred,
  469           KAUTH_GENERIC_ISSUSER, NULL)) != 0)
  470             break;
  471         sc->sc_rasyncmap = *(u_int *)data;
  472         break;
  473 
  474     case PPPIOCGRASYNCMAP:
  475         *(u_int *)data = sc->sc_rasyncmap;
  476         break;
  477 
  478     case PPPIOCSXASYNCMAP:
  479         if ((error = kauth_authorize_generic(l->l_cred,
  480           KAUTH_GENERIC_ISSUSER, NULL)) != 0)
  481             break;
  482         s = spltty();
  483         bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
  484         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
  485         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
  486         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
  487         splx(s);
  488         break;
  489 
  490     case PPPIOCGXASYNCMAP:
  491         bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
  492         break;
  493 
  494     default:
  495         error = pppioctl(sc, cmd, data, flag, l);
  496         if (error == 0 && cmd == PPPIOCSMRU)
  497             pppgetm(sc);
  498     }
  499 
  500     return error;
  501 }
  502 
  503 /* receive a complete ppp frame from device in synchronous
  504  * hdlc mode. caller gives up ownership of mbuf
  505  */
  506 static void
  507 ppprcvframe(struct ppp_softc *sc, struct mbuf *m)
  508 {
  509         int len, s;
  510         struct mbuf *n;
  511         u_char hdr[4];
  512         int hlen,count;
  513 
  514         for (n=m,len=0;n != NULL;n = n->m_next)
  515                 len += n->m_len;
  516         if (len==0) {
  517                 m_freem(m);
  518                 return;
  519         }
  520 
  521         /* extract PPP header from mbuf chain (1 to 4 bytes) */
  522         for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
  523                 count = (sizeof(hdr)-hlen) < n->m_len ?
  524                                 sizeof(hdr)-hlen : n->m_len;
  525                 bcopy(mtod(n,u_char*),&hdr[hlen],count);
  526                 hlen+=count;
  527         }
  528 
  529         s = spltty();
  530 
  531         /* if AFCF compressed then prepend AFCF */
  532         if (hdr[0] != PPP_ALLSTATIONS) {
  533                 if (sc->sc_flags & SC_REJ_COMP_AC) {
  534                         if (sc->sc_flags & SC_DEBUG)
  535                                 printf(
  536                                     "%s: garbage received: 0x%x (need 0xFF)\n",
  537                                     sc->sc_if.if_xname, hdr[0]);
  538                                 goto bail;
  539                         }
  540                 M_PREPEND(m,2,M_DONTWAIT);
  541                 if (m==NULL) {
  542                         splx(s);
  543                         return;
  544                 }
  545                 hdr[3] = hdr[1];
  546                 hdr[2] = hdr[0];
  547                 hdr[0] = PPP_ALLSTATIONS;
  548                 hdr[1] = PPP_UI;
  549                 len += 2;
  550         }
  551 
  552         /* if protocol field compressed, add MSB of protocol field = 0 */
  553         if (hdr[2] & 1) {
  554                 /* a compressed protocol */
  555                 M_PREPEND(m,1,M_DONTWAIT);
  556                 if (m==NULL) {
  557                         splx(s);
  558                         return;
  559                 }
  560                 hdr[3] = hdr[2];
  561                 hdr[2] = 0;
  562                 len++;
  563         }
  564 
  565         /* valid LSB of protocol field has bit0 set */
  566         if (!(hdr[3] & 1)) {
  567                 if (sc->sc_flags & SC_DEBUG)
  568                         printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
  569                                 (hdr[2] << 8) + hdr[3]);
  570                         goto bail;
  571         }
  572 
  573         /* packet beyond configured mru? */
  574         if (len > sc->sc_mru + PPP_HDRLEN) {
  575                 if (sc->sc_flags & SC_DEBUG)
  576                         printf("%s: packet too big\n", sc->sc_if.if_xname);
  577                 goto bail;
  578         }
  579 
  580         /* add expanded 4 byte header to mbuf chain */
  581         for (n=m,hlen=0;n!=NULL && hlen<sizeof(hdr);n=n->m_next) {
  582                 count = (sizeof(hdr)-hlen) < n->m_len ?
  583                                 sizeof(hdr)-hlen : n->m_len;
  584                 bcopy(&hdr[hlen],mtod(n,u_char*),count);
  585                 hlen+=count;
  586         }
  587 
  588         /* if_ppp.c requires the PPP header and IP header */
  589         /* to be contiguous */
  590         count = len < MHLEN ? len : MHLEN;
  591         if (m->m_len < count) {
  592                 m = m_pullup(m,count);
  593                 if (m==NULL)
  594                         goto bail;
  595         }
  596 
  597         sc->sc_stats.ppp_ibytes += len;
  598 
  599         if (sc->sc_flags & SC_LOG_RAWIN)
  600                 pppdumpframe(sc,m,0);
  601 
  602         ppppktin(sc, m, 0);
  603         splx(s);
  604         return;
  605 bail:
  606         m_freem(m);
  607         splx(s);
  608 }
  609 
  610 /*
  611  * FCS lookup table as calculated by genfcstab.
  612  */
  613 static const uint16_t fcstab[256] = {
  614         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  615         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  616         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  617         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  618         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  619         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  620         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  621         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  622         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  623         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  624         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  625         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  626         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  627         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  628         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  629         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  630         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  631         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  632         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  633         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  634         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  635         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  636         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  637         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  638         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  639         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  640         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  641         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  642         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  643         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  644         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  645         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  646 };
  647 
  648 /*
  649  * Calculate a new FCS given the current FCS and the new data.
  650  */
  651 static uint16_t
  652 pppfcs(uint16_t fcs, const uint8_t *cp, int len)
  653 {
  654     while (len--)
  655         fcs = PPP_FCS(fcs, *cp++);
  656     return (fcs);
  657 }
  658 
  659 /* This gets called at splsoftnet from pppasyncstart at various times
  660  * when there is data ready to be sent.
  661  */
  662 static void
  663 pppsyncstart(struct ppp_softc *sc)
  664 {
  665         struct tty *tp = (struct tty *) sc->sc_devp;
  666         struct mbuf *m, *n;
  667         const struct cdevsw *cdev;
  668         int len;
  669 
  670         for(m = sc->sc_outm;;) {
  671                 if (m == NULL) {
  672                         m = ppp_dequeue(sc);    /* get new packet */
  673                         if (m == NULL)
  674                                 break;          /* no more packets */
  675                         if (sc->sc_flags & SC_DEBUG)
  676                                 pppdumpframe(sc,m,1);
  677                 }
  678                 for(n=m,len=0;n!=NULL;n=n->m_next)
  679                         len += n->m_len;
  680 
  681                 /* call device driver IOCTL to transmit a frame */
  682                 cdev = cdevsw_lookup(tp->t_dev);
  683                 if (cdev == NULL ||
  684                     (*cdev->d_ioctl)(tp->t_dev, TIOCXMTFRAME, (void *)&m,
  685                                      0, 0)) {
  686                         /* busy or error, set as current packet */
  687                         sc->sc_outm = m;
  688                         break;
  689                 }
  690                 sc->sc_outm = m = NULL;
  691                 sc->sc_stats.ppp_obytes += len;
  692         }
  693 }
  694 
  695 /*
  696  * This gets called at splsoftnet from if_ppp.c at various times
  697  * when there is data ready to be sent.
  698  */
  699 static void
  700 pppasyncstart(struct ppp_softc *sc)
  701 {
  702     struct tty *tp = (struct tty *) sc->sc_devp;
  703     struct mbuf *m;
  704     int len;
  705     u_char *start, *stop, *cp;
  706     int n, ndone, done, idle;
  707     struct mbuf *m2;
  708 
  709     if (sc->sc_flags & SC_SYNC){
  710         pppsyncstart(sc);
  711         return;
  712     }
  713 
  714     mutex_spin_enter(&tty_lock);
  715 
  716     idle = 0;
  717     while (CCOUNT(&tp->t_outq) < PPP_HIWAT) {
  718         /*
  719          * See if we have an existing packet partly sent.
  720          * If not, get a new packet and start sending it.
  721          */
  722         m = sc->sc_outm;
  723         if (m == NULL) {
  724             /*
  725              * Get another packet to be sent.
  726              */
  727             m = ppp_dequeue(sc);
  728             if (m == NULL) {
  729                 idle = 1;
  730                 break;
  731             }
  732 
  733             /*
  734              * The extra PPP_FLAG will start up a new packet, and thus
  735              * will flush any accumulated garbage.  We do this whenever
  736              * the line may have been idle for some time.
  737              */
  738             if (CCOUNT(&tp->t_outq) == 0) {
  739                 ++sc->sc_stats.ppp_obytes;
  740                 (void) putc(PPP_FLAG, &tp->t_outq);
  741             }
  742 
  743             /* Calculate the FCS for the first mbuf's worth. */
  744             sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, uint8_t *), m->m_len);
  745         }
  746 
  747         for (;;) {
  748             start = mtod(m, u_char *);
  749             len = m->m_len;
  750             stop = start + len;
  751             while (len > 0) {
  752                 /*
  753                  * Find out how many bytes in the string we can
  754                  * handle without doing something special.
  755                  */
  756                 for (cp = start; cp < stop; cp++)
  757                     if (ESCAPE_P(*cp))
  758                         break;
  759                 n = cp - start;
  760                 if (n) {
  761                     /* NetBSD (0.9 or later), 4.3-Reno or similar. */
  762                     ndone = n - b_to_q(start, n, &tp->t_outq);
  763                     len -= ndone;
  764                     start += ndone;
  765                     sc->sc_stats.ppp_obytes += ndone;
  766 
  767                     if (ndone < n)
  768                         break;  /* packet doesn't fit */
  769                 }
  770                 /*
  771                  * If there are characters left in the mbuf,
  772                  * the first one must be special.
  773                  * Put it out in a different form.
  774                  */
  775                 if (len) {
  776                     if (putc(PPP_ESCAPE, &tp->t_outq))
  777                         break;
  778                     if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
  779                         (void) unputc(&tp->t_outq);
  780                         break;
  781                     }
  782                     sc->sc_stats.ppp_obytes += 2;
  783                     start++;
  784                     len--;
  785                 }
  786             }
  787 
  788             /*
  789              * If we didn't empty this mbuf, remember where we're up to.
  790              * If we emptied the last mbuf, try to add the FCS and closing
  791              * flag, and if we can't, leave sc_outm pointing to m, but with
  792              * m->m_len == 0, to remind us to output the FCS and flag later.
  793              */
  794             done = len == 0;
  795             if (done && m->m_next == NULL) {
  796                 u_char *p, *q;
  797                 int c;
  798                 u_char endseq[8];
  799 
  800                 /*
  801                  * We may have to escape the bytes in the FCS.
  802                  */
  803                 p = endseq;
  804                 c = ~sc->sc_outfcs & 0xFF;
  805                 if (ESCAPE_P(c)) {
  806                     *p++ = PPP_ESCAPE;
  807                     *p++ = c ^ PPP_TRANS;
  808                 } else
  809                     *p++ = c;
  810                 c = (~sc->sc_outfcs >> 8) & 0xFF;
  811                 if (ESCAPE_P(c)) {
  812                     *p++ = PPP_ESCAPE;
  813                     *p++ = c ^ PPP_TRANS;
  814                 } else
  815                     *p++ = c;
  816                 *p++ = PPP_FLAG;
  817 
  818                 /*
  819                  * Try to output the FCS and flag.  If the bytes
  820                  * don't all fit, back out.
  821                  */
  822                 for (q = endseq; q < p; ++q)
  823                     if (putc(*q, &tp->t_outq)) {
  824                         done = 0;
  825                         for (; q > endseq; --q)
  826                             unputc(&tp->t_outq);
  827                         break;
  828                     }
  829                 if (done)
  830                     sc->sc_stats.ppp_obytes += q - endseq;
  831             }
  832 
  833             if (!done) {
  834                 /* remember where we got to */
  835                 m->m_data = start;
  836                 m->m_len = len;
  837                 break;
  838             }
  839 
  840             /* Finished with this mbuf; free it and move on. */
  841             MFREE(m, m2);
  842             m = m2;
  843             if (m == NULL) {
  844                 /* Finished a packet */
  845                 break;
  846             }
  847             sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, uint8_t *), m->m_len);
  848         }
  849 
  850         /*
  851          * If m == NULL, we have finished a packet.
  852          * If m != NULL, we've either done as much work this time
  853          * as we need to, or else we've filled up the output queue.
  854          */
  855         sc->sc_outm = m;
  856         if (m)
  857             break;
  858     }
  859 
  860     /* Call pppstart to start output again if necessary. */
  861     pppstart(tp);
  862 
  863     /*
  864      * This timeout is needed for operation on a pseudo-tty,
  865      * because the pty code doesn't call pppstart after it has
  866      * drained the t_outq.
  867      */
  868     if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
  869         callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
  870         sc->sc_flags |= SC_TIMEOUT;
  871     }
  872 
  873     mutex_spin_exit(&tty_lock);
  874 }
  875 
  876 /*
  877  * This gets called when a received packet is placed on
  878  * the inq, at splsoftnet.
  879  */
  880 static void
  881 pppasyncctlp(struct ppp_softc *sc)
  882 {
  883     struct tty *tp;
  884 
  885     /* Put a placeholder byte in canq for ttselect()/ttnread(). */
  886     mutex_spin_enter(&tty_lock);
  887     tp = (struct tty *) sc->sc_devp;
  888     putc(0, &tp->t_canq);
  889     ttwakeup(tp);
  890     mutex_spin_exit(&tty_lock);
  891 }
  892 
  893 /*
  894  * Start output on async tty interface.  If the transmit queue
  895  * has drained sufficiently, arrange for pppasyncstart to be
  896  * called later at splsoftnet.
  897  * Called at spltty or higher.
  898  */
  899 static int
  900 pppstart(struct tty *tp)
  901 {
  902     struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
  903 
  904     /*
  905      * If there is stuff in the output queue, send it now.
  906      * We are being called in lieu of ttstart and must do what it would.
  907      */
  908     if (tp->t_oproc != NULL)
  909         (*tp->t_oproc)(tp);
  910 
  911     /*
  912      * If the transmit queue has drained and the tty has not hung up
  913      * or been disconnected from the ppp unit, then tell if_ppp.c that
  914      * we need more output.
  915      */
  916     if ((CCOUNT(&tp->t_outq) >= PPP_LOWAT)
  917         && ((sc == NULL) || (sc->sc_flags & SC_TIMEOUT)))
  918         return 0;
  919 #ifdef ALTQ
  920     /*
  921      * if ALTQ is enabled, don't invoke NETISR_PPP.
  922      * pppintr() could loop without doing anything useful
  923      * under rate-limiting.
  924      */
  925     if (ALTQ_IS_ENABLED(&sc->sc_if.if_snd))
  926         return 0;
  927 #endif
  928     if (!((tp->t_state & TS_CARR_ON) == 0 && (tp->t_cflag & CLOCAL) == 0)
  929         && sc != NULL && tp == (struct tty *) sc->sc_devp) {
  930         ppp_restart(sc);
  931     }
  932 
  933     return 0;
  934 }
  935 
  936 /*
  937  * Timeout routine - try to start some more output.
  938  */
  939 static void
  940 ppp_timeout(void *x)
  941 {
  942     struct ppp_softc *sc = (struct ppp_softc *) x;
  943     struct tty *tp = (struct tty *) sc->sc_devp;
  944 
  945     mutex_spin_enter(&tty_lock);
  946     sc->sc_flags &= ~SC_TIMEOUT;
  947     pppstart(tp);
  948     mutex_spin_exit(&tty_lock);
  949 }
  950 
  951 /*
  952  * Allocate enough mbuf to handle current MRU.
  953  */
  954 static void
  955 pppgetm(struct ppp_softc *sc)
  956 {
  957     struct mbuf *m, **mp;
  958     int len;
  959 
  960     mp = &sc->sc_m;
  961     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
  962         if ((m = *mp) == NULL) {
  963             MGETHDR(m, M_DONTWAIT, MT_DATA);
  964             if (m == NULL)
  965                 break;
  966             *mp = m;
  967             MCLGET(m, M_DONTWAIT);
  968         }
  969         len -= M_DATASIZE(m);
  970         mp = &m->m_next;
  971     }
  972 }
  973 
  974 /*
  975  * tty interface receiver interrupt.
  976  */
  977 static const unsigned paritytab[8] = {
  978     0x96696996, 0x69969669, 0x69969669, 0x96696996,
  979     0x69969669, 0x96696996, 0x96696996, 0x69969669
  980 };
  981 
  982 static int
  983 pppinput(int c, struct tty *tp)
  984 {
  985     struct ppp_softc *sc;
  986     struct mbuf *m;
  987     const struct cdevsw *cdev;
  988     int ilen, s;
  989 
  990     sc = (struct ppp_softc *) tp->t_sc;
  991     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  992         return 0;
  993 
  994     ++tk_nin;
  995     ++sc->sc_stats.ppp_ibytes;
  996 
  997     if (c & TTY_FE) {
  998         /* framing error or overrun on this char - abort packet */
  999         if (sc->sc_flags & SC_DEBUG)
 1000             printf("%s: bad char %x\n", sc->sc_if.if_xname, c);
 1001         goto flush;
 1002     }
 1003 
 1004     c &= 0xff;
 1005 
 1006     /*
 1007      * Handle software flow control of output.
 1008      */
 1009     if (tp->t_iflag & IXON) {
 1010         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
 1011             if ((tp->t_state & TS_TTSTOP) == 0) {
 1012                 tp->t_state |= TS_TTSTOP;
 1013                 cdev = cdevsw_lookup(tp->t_dev);
 1014                 if (cdev != NULL)
 1015                         (*cdev->d_stop)(tp, 0);
 1016             }
 1017             return 0;
 1018         }
 1019         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
 1020             tp->t_state &= ~TS_TTSTOP;
 1021             if (tp->t_oproc != NULL) {
 1022                 mutex_spin_enter(&tty_lock);    /* XXX */
 1023                 (*tp->t_oproc)(tp);
 1024                 mutex_spin_exit(&tty_lock);     /* XXX */
 1025             }
 1026             return 0;
 1027         }
 1028     }
 1029 
 1030     s = spltty();
 1031     if (c & 0x80)
 1032         sc->sc_flags |= SC_RCV_B7_1;
 1033     else
 1034         sc->sc_flags |= SC_RCV_B7_0;
 1035     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
 1036         sc->sc_flags |= SC_RCV_ODDP;
 1037     else
 1038         sc->sc_flags |= SC_RCV_EVNP;
 1039     splx(s);
 1040 
 1041     ppplogchar(sc, c);
 1042 
 1043     if (c == PPP_FLAG) {
 1044         ilen = sc->sc_ilen;
 1045         sc->sc_ilen = 0;
 1046 
 1047         if ((sc->sc_flags & SC_LOG_RAWIN) && sc->sc_rawin.count > 0)
 1048             ppplogchar(sc, -1);
 1049 
 1050         /*
 1051          * If SC_ESCAPED is set, then we've seen the packet
 1052          * abort sequence "}~".
 1053          */
 1054         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
 1055             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
 1056             s = spltty();
 1057             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
 1058             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
 1059                 if (sc->sc_flags & SC_DEBUG)
 1060                     printf("%s: bad fcs %x\n", sc->sc_if.if_xname,
 1061                         sc->sc_fcs);
 1062                 sc->sc_if.if_ierrors++;
 1063                 sc->sc_stats.ppp_ierrors++;
 1064             } else
 1065                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
 1066             splx(s);
 1067             return 0;
 1068         }
 1069 
 1070         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
 1071             if (ilen) {
 1072                 if (sc->sc_flags & SC_DEBUG)
 1073                     printf("%s: too short (%d)\n", sc->sc_if.if_xname, ilen);
 1074                 s = spltty();
 1075                 sc->sc_if.if_ierrors++;
 1076                 sc->sc_stats.ppp_ierrors++;
 1077                 sc->sc_flags |= SC_PKTLOST;
 1078                 splx(s);
 1079             }
 1080             return 0;
 1081         }
 1082 
 1083         /*
 1084          * Remove FCS trailer.  Somewhat painful...
 1085          */
 1086         ilen -= 2;
 1087         if (--sc->sc_mc->m_len == 0) {
 1088             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
 1089                 ;
 1090             sc->sc_mc = m;
 1091         }
 1092         sc->sc_mc->m_len--;
 1093 
 1094         /* excise this mbuf chain */
 1095         m = sc->sc_m;
 1096         sc->sc_m = sc->sc_mc->m_next;
 1097         sc->sc_mc->m_next = NULL;
 1098 
 1099         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
 1100         if (sc->sc_flags & SC_PKTLOST) {
 1101             s = spltty();
 1102             sc->sc_flags &= ~SC_PKTLOST;
 1103             splx(s);
 1104         }
 1105 
 1106         pppgetm(sc);
 1107         return 0;
 1108     }
 1109 
 1110     if (sc->sc_flags & SC_FLUSH) {
 1111         if (sc->sc_flags & SC_LOG_FLUSH)
 1112             ppplogchar(sc, c);
 1113         return 0;
 1114     }
 1115 
 1116     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
 1117         return 0;
 1118 
 1119     s = spltty();
 1120     if (sc->sc_flags & SC_ESCAPED) {
 1121         sc->sc_flags &= ~SC_ESCAPED;
 1122         c ^= PPP_TRANS;
 1123     } else if (c == PPP_ESCAPE) {
 1124         sc->sc_flags |= SC_ESCAPED;
 1125         splx(s);
 1126         return 0;
 1127     }
 1128     splx(s);
 1129 
 1130     /*
 1131      * Initialize buffer on first octet received.
 1132      * First octet could be address or protocol (when compressing
 1133      * address/control).
 1134      * Second octet is control.
 1135      * Third octet is first or second (when compressing protocol)
 1136      * octet of protocol.
 1137      * Fourth octet is second octet of protocol.
 1138      */
 1139     if (sc->sc_ilen == 0) {
 1140         /* reset the first input mbuf */
 1141         if (sc->sc_m == NULL) {
 1142             pppgetm(sc);
 1143             if (sc->sc_m == NULL) {
 1144                 if (sc->sc_flags & SC_DEBUG)
 1145                     printf("%s: no input mbufs!\n", sc->sc_if.if_xname);
 1146                 goto flush;
 1147             }
 1148         }
 1149         m = sc->sc_m;
 1150         m->m_len = 0;
 1151         m->m_data = M_DATASTART(sc->sc_m);
 1152         sc->sc_mc = m;
 1153         sc->sc_mp = mtod(m, char *);
 1154         sc->sc_fcs = PPP_INITFCS;
 1155         if (c != PPP_ALLSTATIONS) {
 1156             if (sc->sc_flags & SC_REJ_COMP_AC) {
 1157                 if (sc->sc_flags & SC_DEBUG)
 1158                     printf("%s: garbage received: 0x%x (need 0xFF)\n",
 1159                     sc->sc_if.if_xname, c);
 1160                 goto flush;
 1161             }
 1162             *sc->sc_mp++ = PPP_ALLSTATIONS;
 1163             *sc->sc_mp++ = PPP_UI;
 1164             sc->sc_ilen += 2;
 1165             m->m_len += 2;
 1166         }
 1167     }
 1168     if (sc->sc_ilen == 1 && c != PPP_UI) {
 1169         if (sc->sc_flags & SC_DEBUG)
 1170             printf("%s: missing UI (0x3), got 0x%x\n",
 1171                 sc->sc_if.if_xname, c);
 1172         goto flush;
 1173     }
 1174     if (sc->sc_ilen == 2 && (c & 1) == 1) {
 1175         /* a compressed protocol */
 1176         *sc->sc_mp++ = 0;
 1177         sc->sc_ilen++;
 1178         sc->sc_mc->m_len++;
 1179     }
 1180     if (sc->sc_ilen == 3 && (c & 1) == 0) {
 1181         if (sc->sc_flags & SC_DEBUG)
 1182             printf("%s: bad protocol %x\n", sc->sc_if.if_xname,
 1183                 (sc->sc_mp[-1] << 8) + c);
 1184         goto flush;
 1185     }
 1186 
 1187     /* packet beyond configured mru? */
 1188     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
 1189         if (sc->sc_flags & SC_DEBUG)
 1190             printf("%s: packet too big\n", sc->sc_if.if_xname);
 1191         goto flush;
 1192     }
 1193 
 1194     /* is this mbuf full? */
 1195     m = sc->sc_mc;
 1196     if (M_TRAILINGSPACE(m) <= 0) {
 1197         if (m->m_next == NULL) {
 1198             pppgetm(sc);
 1199             if (m->m_next == NULL) {
 1200                 if (sc->sc_flags & SC_DEBUG)
 1201                     printf("%s: too few input mbufs!\n", sc->sc_if.if_xname);
 1202                 goto flush;
 1203             }
 1204         }
 1205         sc->sc_mc = m = m->m_next;
 1206         m->m_len = 0;
 1207         m->m_data = M_DATASTART(m);
 1208         sc->sc_mp = mtod(m, char *);
 1209     }
 1210 
 1211     ++m->m_len;
 1212     *sc->sc_mp++ = c;
 1213     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
 1214     return 0;
 1215 
 1216  flush:
 1217     if (!(sc->sc_flags & SC_FLUSH)) {
 1218         s = spltty();
 1219         sc->sc_if.if_ierrors++;
 1220         sc->sc_stats.ppp_ierrors++;
 1221         sc->sc_flags |= SC_FLUSH;
 1222         splx(s);
 1223         if (sc->sc_flags & SC_LOG_FLUSH)
 1224             ppplogchar(sc, c);
 1225     }
 1226     return 0;
 1227 }
 1228 
 1229 #define MAX_DUMP_BYTES  128
 1230 
 1231 static void
 1232 ppplogchar(struct ppp_softc *sc, int c)
 1233 {
 1234     if (c >= 0) {
 1235         sc->sc_rawin.buf[sc->sc_rawin_start++] = c;
 1236         if (sc->sc_rawin.count < sizeof(sc->sc_rawin.buf))
 1237             sc->sc_rawin.count++;
 1238     }
 1239     if (sc->sc_rawin_start >= sizeof(sc->sc_rawin.buf)
 1240         || (c < 0 && sc->sc_rawin_start > 0)) {
 1241         if (sc->sc_flags & (SC_LOG_FLUSH|SC_LOG_RAWIN)) {
 1242             printf("%s input: ", sc->sc_if.if_xname);
 1243             pppdumpb(sc->sc_rawin.buf, sc->sc_rawin_start);
 1244         }
 1245         if (c < 0)
 1246             sc->sc_rawin.count = 0;
 1247         sc->sc_rawin_start = 0;
 1248     }
 1249 }
 1250 
 1251 static void
 1252 pppdumpb(u_char *b, int l)
 1253 {
 1254     char bf[3*MAX_DUMP_BYTES+4];
 1255     char *bp = bf;
 1256 
 1257     while (l--) {
 1258         if (bp >= bf + sizeof(bf) - 3) {
 1259             *bp++ = '>';
 1260             break;
 1261         }
 1262         *bp++ = hexdigits[*b >> 4]; /* convert byte to ascii hex */
 1263         *bp++ = hexdigits[*b++ & 0xf];
 1264         *bp++ = ' ';
 1265     }
 1266 
 1267     *bp = 0;
 1268     printf("%s\n", bf);
 1269 }
 1270 
 1271 static void
 1272 pppdumpframe(struct ppp_softc *sc, struct mbuf *m, int xmit)
 1273 {
 1274         int i,lcount,copycount,count;
 1275         char lbuf[16];
 1276         char *data;
 1277 
 1278         if (m == NULL)
 1279                 return;
 1280 
 1281         for(count=m->m_len,data=mtod(m,char*);m != NULL;) {
 1282                 /* build a line of output */
 1283                 for(lcount=0;lcount < sizeof(lbuf);lcount += copycount) {
 1284                         if (!count) {
 1285                                 m = m->m_next;
 1286                                 if (m == NULL)
 1287                                         break;
 1288                                 count = m->m_len;
 1289                                 data  = mtod(m,char*);
 1290                         }
 1291                         copycount = (count > sizeof(lbuf)-lcount) ?
 1292                                         sizeof(lbuf)-lcount : count;
 1293                         bcopy(data,&lbuf[lcount],copycount);
 1294                         data  += copycount;
 1295                         count -= copycount;
 1296                 }
 1297 
 1298                 /* output line (hex 1st, then ascii) */
 1299                 printf("%s %s:", sc->sc_if.if_xname,
 1300                     xmit ? "output" : "input ");
 1301                 for(i=0;i<lcount;i++)
 1302                         printf("%02x ",(u_char)lbuf[i]);
 1303                 for(;i<sizeof(lbuf);i++)
 1304                         printf("   ");
 1305                 for(i=0;i<lcount;i++)
 1306                         printf("%c",(lbuf[i] >= 040 &&
 1307                             lbuf[i] <= 0176) ? lbuf[i] : '.');
 1308                 printf("\n");
 1309         }
 1310 }

Cache object: 2381a0b517eaa279dd0bb8257648414b


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