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

Cache object: 7ccb5527a57616e74a5612a57abb071b


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