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

Cache object: 4945da8e09624ac4977d6aafab519f7c


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