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

Cache object: 3adbe209cbb7511488702bcc9459b791


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