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

Cache object: 3a28e53818706ae4587832131113f726


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