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

Cache object: ee08e4a180fddf0d3c3f5dbb9148b427


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