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$ */
   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/priv.h>
   83 #include <sys/proc.h>
   84 #include <sys/mbuf.h>
   85 #include <sys/socket.h>
   86 #include <sys/fcntl.h>
   87 #include <sys/tty.h>
   88 #include <sys/conf.h>
   89 #include <sys/uio.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     error = priv_check(td, PRIV_NET_PPP);
  184     if (error)
  185         return (error);
  186 
  187     s = spltty();
  188 
  189     tp->t_hotchar = PPP_FLAG;
  190 
  191     if ((sc = pppalloc(td->td_proc->p_pid)) == NULL) {
  192         splx(s);
  193         return ENXIO;
  194     }
  195 
  196     if (sc->sc_relinq)
  197         (*sc->sc_relinq)(sc);   /* get previous owner to relinquish the unit */
  198 
  199     sc->sc_ilen = 0;
  200     sc->sc_m = NULL;
  201     bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
  202     sc->sc_asyncmap[0] = 0xffffffff;
  203     sc->sc_asyncmap[3] = 0x60000000;
  204     sc->sc_rasyncmap = 0;
  205     sc->sc_devp = (void *) tp;
  206     sc->sc_start = pppasyncstart;
  207     sc->sc_ctlp = pppasyncctlp;
  208     sc->sc_relinq = pppasyncrelinq;
  209     sc->sc_setmtu = pppasyncsetmtu;
  210     sc->sc_outm = NULL;
  211     pppgetm(sc);
  212     PPP2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
  213     getmicrotime(&PPP2IFP(sc)->if_lastchange);
  214     PPP2IFP(sc)->if_baudrate = tp->t_ospeed;
  215 
  216     tp->t_hotchar = PPP_FLAG;
  217     tp->t_lsc = sc;
  218     ttyflush(tp, FREAD | FWRITE);
  219 
  220     /*
  221      * Pre-allocate cblocks to the "just right" amount.  The 1 byte t_canq
  222      * allocation helps avoid the need for select and/or FIONREAD.
  223      * We also pass 1 byte tokens through t_canq...
  224      */
  225     clist_alloc_cblocks(&tp->t_canq, 1, 1);
  226     clist_alloc_cblocks(&tp->t_outq, PPP2IFP(sc)->if_mtu + PPP_HIWAT,
  227                         PPP2IFP(sc)->if_mtu + PPP_HIWAT);
  228     clist_alloc_cblocks(&tp->t_rawq, 0, 0);
  229 
  230     splx(s);
  231 
  232     return (0);
  233 }
  234 
  235 /*
  236  * Line specific close routine, called from device close routine
  237  * and from ttioctl at >= splsofttty().
  238  * Detach the tty from the ppp unit.
  239  * Mimics part of tty_close().
  240  */
  241 static int
  242 pppclose(tp, flag)
  243     struct tty *tp;
  244     int flag;
  245 {
  246     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
  247     int s;
  248 
  249     s = spltty();
  250     ttyflush(tp, FREAD | FWRITE);
  251     clist_free_cblocks(&tp->t_canq);
  252     clist_free_cblocks(&tp->t_outq);
  253     if (sc != NULL) {
  254             pppasyncrelinq(sc);
  255             pppdealloc(sc);
  256     }
  257     splx(s);
  258     return 0;
  259 }
  260 
  261 /*
  262  * Relinquish the interface unit to another device.
  263  */
  264 static void
  265 pppasyncrelinq(sc)
  266     struct ppp_softc *sc;
  267 {
  268     int s;
  269 
  270     s = spltty();
  271     if (sc->sc_outm) {
  272         m_freem(sc->sc_outm);
  273         sc->sc_outm = NULL;
  274     }
  275     if (sc->sc_m) {
  276         m_freem(sc->sc_m);
  277         sc->sc_m = NULL;
  278     }
  279     if (sc->sc_flags & SC_TIMEOUT) {
  280         callout_stop(&sc->sc_timo_ch);
  281         sc->sc_flags &= ~SC_TIMEOUT;
  282     }
  283     splx(s);
  284 }
  285 
  286 /*
  287  * This gets called from the upper layer to notify a mtu change
  288  */
  289 static void
  290 pppasyncsetmtu(sc)
  291 register struct ppp_softc *sc;
  292 {
  293     register struct tty *tp = (struct tty *) sc->sc_devp;
  294     int s;
  295 
  296     s = spltty();
  297     if (tp != NULL)
  298         clist_alloc_cblocks(&tp->t_outq, PPP2IFP(sc)->if_mtu + PPP_HIWAT,
  299                              PPP2IFP(sc)->if_mtu + PPP_HIWAT);
  300     splx(s);
  301 }
  302 
  303 /*
  304  * Line specific (tty) read routine.
  305  * called at zero spl from the device driver in the response to user-level
  306  * reads on the tty file descriptor (ie: pppd).
  307  */
  308 static int
  309 pppread(tp, uio, flag)
  310     register struct tty *tp;
  311     struct uio *uio;
  312     int flag;
  313 {
  314     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
  315     struct mbuf *m, *m0;
  316     register int s;
  317     int error = 0;
  318 
  319     if (sc == NULL)
  320         return 0;
  321     /*
  322      * Loop waiting for input, checking that nothing disasterous
  323      * happens in the meantime.
  324      */
  325     s = spltty();
  326     for (;;) {
  327         if (tp != (struct tty *) sc->sc_devp || tp->t_line != PPPDISC) {
  328             splx(s);
  329             return 0;
  330         }
  331         if (sc->sc_inq.ifq_head != NULL)
  332             break;
  333         if ((tp->t_state & TS_CONNECTED) == 0) {
  334             splx(s);
  335             return 0;           /* end of file */
  336         }
  337         if (tp->t_state & TS_ASYNC || flag & O_NONBLOCK) {
  338             splx(s);
  339             return (EWOULDBLOCK);
  340         }
  341         error = ttysleep(tp, TSA_HUP_OR_INPUT(tp), TTIPRI | PCATCH, "pppin", 0);
  342         if (error) {
  343             splx(s);
  344             return error;
  345         }
  346     }
  347 
  348     /* Pull place-holder byte out of canonical queue */
  349     getc(&tp->t_canq);
  350 
  351     /* Get the packet from the input queue */
  352     IF_DEQUEUE(&sc->sc_inq, m0);
  353     splx(s);
  354 
  355     for (m = m0; m && uio->uio_resid; m = m->m_next)
  356         if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
  357             break;
  358     m_freem(m0);
  359     return (error);
  360 }
  361 
  362 /*
  363  * Line specific (tty) write routine.
  364  * called at zero spl from the device driver in the response to user-level
  365  * writes on the tty file descriptor (ie: pppd).
  366  */
  367 static int
  368 pppwrite(tp, uio, flag)
  369     register struct tty *tp;
  370     struct uio *uio;
  371     int flag;
  372 {
  373     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
  374     struct mbuf *m;
  375     struct sockaddr dst;
  376     int error, s;
  377 
  378     if ((tp->t_state & TS_CONNECTED) == 0)
  379         return 0;               /* wrote 0 bytes */
  380     if (tp->t_line != PPPDISC)
  381         return (EINVAL);
  382     if (sc == NULL)
  383         return EIO;
  384     if (uio->uio_resid > PPP2IFP(sc)->if_mtu + PPP_HDRLEN ||
  385         uio->uio_resid < PPP_HDRLEN)
  386         return (EMSGSIZE);
  387 
  388     s = spltty();
  389     if ((m = m_uiotombuf(uio, M_DONTWAIT, 0, 0, M_PKTHDR)) == NULL) {
  390         splx(s);
  391         return (ENOBUFS);
  392     }
  393 
  394     dst.sa_family = AF_UNSPEC;
  395     bcopy(mtod(m, u_char *), dst.sa_data, PPP_HDRLEN);
  396     m->m_data += PPP_HDRLEN;
  397     m->m_len -= PPP_HDRLEN;
  398 
  399     /* call the upper layer to "transmit" it... */
  400     error = pppoutput(PPP2IFP(sc), m, &dst, NULL);
  401     splx(s);
  402     return (error);
  403 }
  404 
  405 /*
  406  * Line specific (tty) ioctl routine.
  407  * This discipline requires that tty device drivers call
  408  * the line specific l_ioctl routine from their ioctl routines.
  409  */
  410 /* ARGSUSED */
  411 static int
  412 ppptioctl(tp, cmd, data, flag, td)
  413     struct tty *tp;
  414     u_long cmd;
  415     caddr_t data;
  416     int flag;
  417     struct thread *td;
  418 {
  419     struct ppp_softc *sc = (struct ppp_softc *)tp->t_lsc;
  420     int error, s;
  421 
  422     if (sc == NULL || tp != (struct tty *) sc->sc_devp)
  423         return (ENOIOCTL);
  424 
  425     error = 0;
  426     switch (cmd) {
  427     case PPPIOCSASYNCMAP:
  428         error = priv_check(td, PRIV_NET_PPP);
  429         if (error)
  430             break;
  431         sc->sc_asyncmap[0] = *(u_int *)data;
  432         break;
  433 
  434     case PPPIOCGASYNCMAP:
  435         *(u_int *)data = sc->sc_asyncmap[0];
  436         break;
  437 
  438     case PPPIOCSRASYNCMAP:
  439         error = priv_check(td, PRIV_NET_PPP);
  440         if (error)
  441             break;
  442         sc->sc_rasyncmap = *(u_int *)data;
  443         break;
  444 
  445     case PPPIOCGRASYNCMAP:
  446         *(u_int *)data = sc->sc_rasyncmap;
  447         break;
  448 
  449     case PPPIOCSXASYNCMAP:
  450         error = priv_check(td, PRIV_NET_PPP);
  451         if (error)
  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(&PPP2IFP(sc)->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         callout_reset(&sc->sc_timo_ch, 1, ppp_timeout, sc);
  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_lsc;
  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     tt_oproc(tp);
  744 
  745     /*
  746      * If the transmit queue has drained and the tty has not hung up
  747      * or been disconnected from the ppp unit, then tell if_ppp.c that
  748      * we need more output.
  749      */
  750     if (CCOUNT(&tp->t_outq) < PPP_LOWAT
  751         && !((tp->t_state & TS_CONNECTED) == 0)
  752         && sc != NULL) {
  753         ppp_restart(sc);
  754     }
  755 
  756     return 0;
  757 }
  758 
  759 /*
  760  * Timeout routine - try to start some more output.
  761  */
  762 static void
  763 ppp_timeout(x)
  764     void *x;
  765 {
  766     struct ppp_softc *sc = (struct ppp_softc *) x;
  767     struct tty *tp = (struct tty *) sc->sc_devp;
  768     int s;
  769 
  770     s = spltty();
  771     sc->sc_flags &= ~SC_TIMEOUT;
  772     pppstart(tp);
  773     splx(s);
  774 }
  775 
  776 /*
  777  * Allocate enough mbuf to handle current MRU.
  778  */
  779 static void
  780 pppgetm(sc)
  781     register struct ppp_softc *sc;
  782 {
  783     struct mbuf *m, **mp;
  784     int len;
  785 
  786     mp = &sc->sc_m;
  787     for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
  788         if ((m = *mp) == NULL) {
  789             MGETHDR(m, M_DONTWAIT, MT_DATA);
  790             if (m == NULL)
  791                 break;
  792             *mp = m;
  793             MCLGET(m, M_DONTWAIT);
  794         }
  795         len -= M_DATASIZE(m);
  796         mp = &m->m_next;
  797     }
  798 }
  799 
  800 /*
  801  * tty interface receiver interrupt.
  802  */
  803 static unsigned paritytab[8] = {
  804     0x96696996, 0x69969669, 0x69969669, 0x96696996,
  805     0x69969669, 0x96696996, 0x96696996, 0x69969669
  806 };
  807 
  808 /*
  809  * Called when character is available from device driver.
  810  * Only guaranteed to be at splsofttty() or spltty()
  811  * This is safe to be called while the upper half's netisr is preempted.
  812  */
  813 static int
  814 pppinput(c, tp)
  815     int c;
  816     register struct tty *tp;
  817 {
  818     register struct ppp_softc *sc;
  819     struct mbuf *m;
  820     int ilen, s;
  821 
  822     sc = (struct ppp_softc *)tp->t_lsc;
  823     if (sc == NULL)
  824         return 0;
  825 
  826     ++tk_nin;
  827     ++sc->sc_stats.ppp_ibytes;
  828 
  829     if ((tp->t_state & TS_CONNECTED) == 0) {
  830         if (sc->sc_flags & SC_DEBUG)
  831             if_printf(PPP2IFP(sc), "no carrier\n");
  832         goto flush;
  833     }
  834 
  835     if (c & TTY_ERRORMASK) {
  836         /* framing error or overrun on this char - abort packet */
  837         if (sc->sc_flags & SC_DEBUG)
  838             if_printf(PPP2IFP(sc), "line error %x\n", c & TTY_ERRORMASK);
  839         goto flush;
  840     }
  841 
  842     c &= TTY_CHARMASK;
  843 
  844     /*
  845      * Handle software flow control of output.
  846      */
  847     if (tp->t_iflag & IXON) {
  848         if (c == tp->t_cc[VSTOP] && tp->t_cc[VSTOP] != _POSIX_VDISABLE) {
  849             if ((tp->t_state & TS_TTSTOP) == 0) {
  850                 tp->t_state |= TS_TTSTOP;
  851                 tt_stop(tp, 0);
  852             }
  853             return 0;
  854         }
  855         if (c == tp->t_cc[VSTART] && tp->t_cc[VSTART] != _POSIX_VDISABLE) {
  856             tp->t_state &= ~TS_TTSTOP;
  857             tt_oproc(tp);
  858             return 0;
  859         }
  860     }
  861 
  862     s = spltty();
  863     if (c & 0x80)
  864         sc->sc_flags |= SC_RCV_B7_1;
  865     else
  866         sc->sc_flags |= SC_RCV_B7_0;
  867     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
  868         sc->sc_flags |= SC_RCV_ODDP;
  869     else
  870         sc->sc_flags |= SC_RCV_EVNP;
  871     splx(s);
  872 
  873     if (sc->sc_flags & SC_LOG_RAWIN)
  874         ppplogchar(sc, c);
  875 
  876     if (c == PPP_FLAG) {
  877         ilen = sc->sc_ilen;
  878         sc->sc_ilen = 0;
  879 
  880         if (sc->sc_rawin_count > 0) 
  881             ppplogchar(sc, -1);
  882 
  883         /*
  884          * If SC_ESCAPED is set, then we've seen the packet
  885          * abort sequence "}~".
  886          */
  887         if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
  888             || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
  889             s = spltty();
  890             sc->sc_flags |= SC_PKTLOST; /* note the dropped packet */
  891             if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
  892                 if (sc->sc_flags & SC_DEBUG)
  893                     if_printf(PPP2IFP(sc), "bad fcs %x, pkt len %d\n",
  894                            sc->sc_fcs, ilen);
  895                 PPP2IFP(sc)->if_ierrors++;
  896                 sc->sc_stats.ppp_ierrors++;
  897             } else
  898                 sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
  899             splx(s);
  900             return 0;
  901         }
  902 
  903         if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
  904             if (ilen) {
  905                 if (sc->sc_flags & SC_DEBUG)
  906                     if_printf(PPP2IFP(sc), "too short (%d)\n", ilen);
  907                 s = spltty();
  908                 PPP2IFP(sc)->if_ierrors++;
  909                 sc->sc_stats.ppp_ierrors++;
  910                 sc->sc_flags |= SC_PKTLOST;
  911                 splx(s);
  912             }
  913             return 0;
  914         }
  915 
  916         /*
  917          * Remove FCS trailer.  Somewhat painful...
  918          */
  919         ilen -= 2;
  920         if (--sc->sc_mc->m_len == 0) {
  921             for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
  922                 ;
  923             sc->sc_mc = m;
  924         }
  925         sc->sc_mc->m_len--;
  926 
  927         /* excise this mbuf chain */
  928         m = sc->sc_m;
  929         sc->sc_m = sc->sc_mc->m_next;
  930         sc->sc_mc->m_next = NULL;
  931 
  932         ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
  933         if (sc->sc_flags & SC_PKTLOST) {
  934             s = spltty();
  935             sc->sc_flags &= ~SC_PKTLOST;
  936             splx(s);
  937         }
  938 
  939         pppgetm(sc);
  940         return 0;
  941     }
  942 
  943     if (sc->sc_flags & SC_FLUSH) {
  944         if (sc->sc_flags & SC_LOG_FLUSH)
  945             ppplogchar(sc, c);
  946         return 0;
  947     }
  948 
  949     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
  950         return 0;
  951 
  952     s = spltty();
  953     if (sc->sc_flags & SC_ESCAPED) {
  954         sc->sc_flags &= ~SC_ESCAPED;
  955         c ^= PPP_TRANS;
  956     } else if (c == PPP_ESCAPE) {
  957         sc->sc_flags |= SC_ESCAPED;
  958         splx(s);
  959         return 0;
  960     }
  961     splx(s);
  962 
  963     /*
  964      * Initialize buffer on first octet received.
  965      * First octet could be address or protocol (when compressing
  966      * address/control).
  967      * Second octet is control.
  968      * Third octet is first or second (when compressing protocol)
  969      * octet of protocol.
  970      * Fourth octet is second octet of protocol.
  971      */
  972     if (sc->sc_ilen == 0) {
  973         /* reset the first input mbuf */
  974         if (sc->sc_m == NULL) {
  975             pppgetm(sc);
  976             if (sc->sc_m == NULL) {
  977                 if (sc->sc_flags & SC_DEBUG)
  978                     if_printf(PPP2IFP(sc), "no input mbufs!\n");
  979                 goto flush;
  980             }
  981         }
  982         m = sc->sc_m;
  983         m->m_len = 0;
  984         m->m_data = M_DATASTART(sc->sc_m);
  985         sc->sc_mc = m;
  986         sc->sc_mp = mtod(m, char *);
  987         sc->sc_fcs = PPP_INITFCS;
  988         if (c != PPP_ALLSTATIONS) {
  989             if (sc->sc_flags & SC_REJ_COMP_AC) {
  990                 if (sc->sc_flags & SC_DEBUG)
  991                     if_printf(PPP2IFP(sc),
  992                               "garbage received: 0x%x (need 0xFF)\n", c);
  993                 goto flush;
  994             }
  995             *sc->sc_mp++ = PPP_ALLSTATIONS;
  996             *sc->sc_mp++ = PPP_UI;
  997             sc->sc_ilen += 2;
  998             m->m_len += 2;
  999         }
 1000     }
 1001     if (sc->sc_ilen == 1 && c != PPP_UI) {
 1002         if (sc->sc_flags & SC_DEBUG)
 1003             if_printf(PPP2IFP(sc), "missing UI (0x3), got 0x%x\n", c);
 1004         goto flush;
 1005     }
 1006     if (sc->sc_ilen == 2 && (c & 1) == 1) {
 1007         /* a compressed protocol */
 1008         *sc->sc_mp++ = 0;
 1009         sc->sc_ilen++;
 1010         sc->sc_mc->m_len++;
 1011     }
 1012     if (sc->sc_ilen == 3 && (c & 1) == 0) {
 1013         if (sc->sc_flags & SC_DEBUG)
 1014             if_printf(PPP2IFP(sc), "bad protocol %x\n",
 1015                       (sc->sc_mp[-1] << 8) + c);
 1016         goto flush;
 1017     }
 1018 
 1019     /* packet beyond configured mru? */
 1020     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
 1021         if (sc->sc_flags & SC_DEBUG)
 1022             if_printf(PPP2IFP(sc), "packet too big\n");
 1023         goto flush;
 1024     }
 1025 
 1026     /* is this mbuf full? */
 1027     m = sc->sc_mc;
 1028     if (M_TRAILINGSPACE(m) <= 0) {
 1029         if (m->m_next == NULL) {
 1030             pppgetm(sc);
 1031             if (m->m_next == NULL) {
 1032                 if (sc->sc_flags & SC_DEBUG)
 1033                     if_printf(PPP2IFP(sc), "too few input mbufs!\n");
 1034                 goto flush;
 1035             }
 1036         }
 1037         sc->sc_mc = m = m->m_next;
 1038         m->m_len = 0;
 1039         m->m_data = M_DATASTART(m);
 1040         sc->sc_mp = mtod(m, char *);
 1041     }
 1042 
 1043     ++m->m_len;
 1044     *sc->sc_mp++ = c;
 1045     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
 1046     return 0;
 1047 
 1048  flush:
 1049     if (!(sc->sc_flags & SC_FLUSH)) {
 1050         s = spltty();
 1051         PPP2IFP(sc)->if_ierrors++;
 1052         sc->sc_stats.ppp_ierrors++;
 1053         sc->sc_flags |= SC_FLUSH;
 1054         splx(s);
 1055         if (sc->sc_flags & SC_LOG_FLUSH)
 1056             ppplogchar(sc, c);
 1057     }
 1058     return 0;
 1059 }
 1060 
 1061 #define MAX_DUMP_BYTES  128
 1062 
 1063 static void
 1064 ppplogchar(sc, c)
 1065     struct ppp_softc *sc;
 1066     int c;
 1067 {
 1068     if (c >= 0)
 1069         sc->sc_rawin[sc->sc_rawin_count++] = c;
 1070     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
 1071         || (c < 0 && sc->sc_rawin_count > 0)) {
 1072         printf("%s input: %*D", PPP2IFP(sc)->if_xname,
 1073                 sc->sc_rawin_count, sc->sc_rawin, " ");
 1074         sc->sc_rawin_count = 0;
 1075     }
 1076 }

Cache object: 1ba97db6cc94345e36fb6ed507a59cb0


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