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

Cache object: 372d41f91c4caaceb4b384b2151b225b


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