root/net/ppp_tty.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pppopen
  2. pppclose
  3. pppasyncrelinq
  4. pppread
  5. pppwrite
  6. ppptioctl
  7. pppfcs
  8. pppasyncstart
  9. pppasyncctlp
  10. pppstart
  11. ppp_timeout
  12. pppgetm
  13. pppinput
  14. ppplogchar
  15. pppdumpb

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

/* [<][>][^][v][top][bottom][index][help] */