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

Cache object: 0bbef2f7a65602ed26983fac38d72a46


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