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

Cache object: c6eea1c31b6ed21aad73d54d43522e92


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