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

Cache object: 7698ab46678f66946d61095d180dc3b7


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