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

Cache object: 35cd997a6ccb38d165456345afc728f0


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