home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / SUN / PPP / SUNOS_OL / DDP_PPP.TAR / if_ppp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-03  |  21.9 KB  |  957 lines

  1. /*
  2.  * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
  3.  *
  4.  * Copyright (c) 1989 Carnegie Mellon University.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by Carnegie Mellon University.  The name of the
  13.  * University may not be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  *
  19.  * Drew D. Perkins
  20.  * Carnegie Mellon University
  21.  * 4910 Forbes Ave.
  22.  * Pittsburgh, PA 15213
  23.  * (412) 268-8576
  24.  * ddp@andrew.cmu.edu
  25.  *
  26.  * Based on:
  27.  *    @(#)if_sl.c    7.6.1.2 (Berkeley) 2/15/89
  28.  *
  29.  * Copyright (c) 1987 Regents of the University of California.
  30.  * All rights reserved.
  31.  *
  32.  * Redistribution and use in source and binary forms are permitted
  33.  * provided that the above copyright notice and this paragraph are
  34.  * duplicated in all such forms and that any documentation,
  35.  * advertising materials, and other materials related to such
  36.  * distribution and use acknowledge that the software was developed
  37.  * by the University of California, Berkeley.  The name of the
  38.  * University may not be used to endorse or promote products derived
  39.  * from this software without specific prior written permission.
  40.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  41.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  42.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  43.  *
  44.  * Serial Line interface
  45.  *
  46.  * Rick Adams
  47.  * Center for Seismic Studies
  48.  * 1300 N 17th Street, Suite 1450
  49.  * Arlington, Virginia 22209
  50.  * (703)276-7900
  51.  * rick@seismo.ARPA
  52.  * seismo!rick
  53.  *
  54.  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
  55.  * Converted to 4.3BSD Beta by Chris Torek.
  56.  * Other changes made at Berkeley, based in part on code by Kirk Smith.
  57.  */
  58.  
  59. /* $Header: if_sl.c,v 1.12 85/12/20 21:54:55 chris Exp $ */
  60. /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
  61.  
  62. #include "ppp.h"
  63. #if NPPP > 0
  64.  
  65. #include "param.h"
  66. #include "systm.h"
  67. #include "dir.h"
  68. #include "user.h"
  69. #include "ioctl.h"
  70. #include "tty.h"
  71. #include "proc.h"
  72. #include "file.h"
  73. #include "conf.h"
  74. #include "buf.h"
  75. #include "dk.h"
  76. #include "uio.h"
  77. #include "errno.h"
  78. #include "mbuf.h"
  79. #include "socket.h"
  80.  
  81. #include "if.h"
  82. #include "netisr.h"
  83. #include "route.h"
  84. #if INET
  85. #include "../netinet/in.h"
  86. #include "../netinet/in_systm.h"
  87. #include "../netinet/in_var.h"
  88. #include "../netinet/ip.h"
  89. #endif
  90.  
  91. #ifndef ibm032
  92. #include "../machine/mtpr.h"
  93. #endif
  94.  
  95. #include "../net/if_ppp.h"
  96.  
  97.  
  98. struct ppp_softc ppp_softc[NPPP];
  99.  
  100. int pppoutput(), pppioctl();
  101.  
  102. /*
  103.  * Called from boot code to establish ppp interfaces.
  104.  */
  105. pppattach()
  106. {
  107.     register struct ppp_softc *sc;
  108.     register int i = 0;
  109.  
  110.     for (sc = ppp_softc; i < NPPP; sc++) {
  111.         sc->sc_if.if_name = "ppp";
  112.         sc->sc_if.if_unit = i++;
  113.         sc->sc_if.if_mtu = PPP_MTU;
  114.         sc->sc_if.if_flags = IFF_POINTOPOINT;
  115.         sc->sc_if.if_ioctl = pppioctl;
  116.         sc->sc_if.if_output = pppoutput;
  117.         sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
  118.         sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
  119.         if_attach(&sc->sc_if);
  120.     }
  121. }
  122.  
  123. /*
  124.  * Line specific open routine.
  125.  * Attach the given tty to the first available ppp unit.
  126.  */
  127. /* ARGSUSED */
  128. pppopen(dev, tp)
  129.     dev_t dev;
  130.     register struct tty *tp;
  131. {
  132.     register struct ppp_softc *sc;
  133.     register int nppp;
  134.  
  135.     if (!suser())
  136.         return (EPERM);
  137.     if (tp->t_line == PPPDISC)
  138.         return (EBUSY);
  139.  
  140.     for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
  141.         if (sc->sc_ttyp == NULL) {
  142.             sc->sc_flags = 0;
  143.             sc->sc_ilen = 0;
  144.             sc->sc_asyncmap = 0xffffffff;
  145.             if (pppinit(sc) == 0) {
  146.                 sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
  147.                 return (ENOBUFS);
  148.             }
  149.             tp->t_sc = (caddr_t)sc;
  150.             sc->sc_ttyp = tp;
  151.             ttyflush(tp, FREAD | FWRITE);
  152.             sc->sc_if.if_flags |= IFF_RUNNING;
  153.             return (0);
  154.         }
  155.  
  156.     return (ENXIO);
  157. }
  158.  
  159. /*
  160.  * Line specific close routine.
  161.  * Detach the tty from the ppp unit.
  162.  * Mimics part of ttyclose().
  163.  */
  164. pppclose(tp)
  165.     struct tty *tp;
  166. {
  167.     register struct ppp_softc *sc;
  168.     struct mbuf *m;
  169.     int s;
  170.  
  171.     ttywflush(tp);
  172.     tp->t_line = 0;
  173.     s = splimp();        /* paranoid; splnet probably ok */
  174.     sc = (struct ppp_softc *)tp->t_sc;
  175.     if (sc != NULL) {
  176.         if_down(&sc->sc_if);
  177.         sc->sc_ttyp = NULL;
  178.         tp->t_sc = NULL;
  179.         m_freem(sc->sc_m);
  180.         sc->sc_m = NULL;
  181.         for (;;) {
  182.             IF_DEQUEUE(&sc->sc_inq, m);
  183.             if (m == NULL)
  184.                 break;
  185.             m_freem(m);
  186.         }
  187.         sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
  188.     }
  189.     splx(s);
  190. }
  191.  
  192. /*
  193.  * Line specific (tty) read routine.
  194.  */
  195. pppread(tp, uio)
  196.     register struct tty *tp;
  197.     struct uio *uio;
  198. {
  199.     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  200.     struct mbuf *m, *m0;
  201.     register int s;
  202.     int error;
  203.  
  204.     if ((tp->t_state&TS_CARR_ON)==0)
  205.         return (EIO);
  206.     s = splimp();
  207.     while (sc->sc_inq.ifq_head == NULL &&
  208.            tp->t_line == PPPDISC)
  209.         if (tp->t_state&TS_NBIO) {
  210.             splx(s);
  211.             return (EWOULDBLOCK);
  212.         }
  213.         else
  214.             sleep((caddr_t)&tp->t_rawq, TTIPRI);
  215.     if (tp->t_line != PPPDISC) {
  216.         splx(s);
  217.         return (-1);
  218.     }
  219.     IF_DEQUEUE(&sc->sc_inq, m);
  220.     splx(s);
  221.     IF_ADJ(m);
  222.     for (m0 = m; m0 && uio->uio_resid; m0 = m0->m_next)
  223.         if (error = uiomove(mtod(m, u_char *), m->m_len,
  224.                     UIO_READ, uio))
  225.             break;
  226.     m_freem(m);
  227.     return (error);
  228. }
  229.  
  230. /*
  231.  * Line specific (tty) write routine.
  232.  */
  233. pppwrite(tp, uio)
  234.     register struct tty *tp;
  235.     struct uio *uio;
  236. {
  237.     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  238.     struct mbuf *m, *m0, **mp;
  239.     struct sockaddr dst;
  240.     struct ppp_header *ph1, *ph2;
  241.     int len, error;
  242.  
  243.     if ((tp->t_state&TS_CARR_ON)==0)
  244.         return (EIO);
  245.     if (tp->t_line != PPPDISC)
  246.         return (-1);
  247.     if (uio->uio_resid > sc->sc_if.if_mtu + sizeof (struct ppp_header) ||
  248.         uio->uio_resid < sizeof (struct ppp_header))
  249.         return (EMSGSIZE);
  250.     for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
  251.         MGET(m, M_WAIT, MT_DATA);
  252.         if ((*mp = m) == NULL) {
  253.             m_freem(m0);
  254.             return (ENOBUFS);
  255.         }
  256.         if (uio->uio_resid >= CLBYTES / 2) {
  257.             MCLGET(m);
  258.         }
  259.         else
  260.             m->m_len = MLEN;
  261.         len = MIN(m->m_len, uio->uio_resid);
  262.         if (error = uiomove(mtod(m, u_char *), len, UIO_WRITE, uio)) {
  263.             m_freem(m0);
  264.             return (error);
  265.         }
  266.         m->m_len = len;
  267.     }
  268.     dst.sa_family = AF_UNSPEC;
  269.     ph1 = (struct ppp_header *) &dst.sa_data;
  270.     ph2 = mtod(m0, struct ppp_header *);
  271.     *ph1 = *ph2;
  272.     m0->m_off += sizeof (struct ppp_header);
  273.     m0->m_len -= sizeof (struct ppp_header);
  274.     return (pppoutput(&sc->sc_if, m0, &dst));
  275. }
  276.  
  277. /*
  278.  * Line specific (tty) select routine.
  279.  */
  280. pppselect(dev, rw)
  281.     dev_t dev;
  282.     int rw;
  283. {
  284.     register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
  285.     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  286.     int s = spltty();
  287.  
  288.     if (tp == 0)
  289.         panic("ttselect");
  290.     switch (rw) {
  291.  
  292.     case FREAD:
  293.         if (sc->sc_inq.ifq_head || ((tp->t_state & TS_CARR_ON) == 0))
  294.             goto win;
  295.         if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
  296.             tp->t_state |= TS_RCOLL;
  297.         else
  298.             tp->t_rsel = u.u_procp;
  299.         break;
  300.  
  301.     case FWRITE:
  302.         if (!IF_QFULL(&sc->sc_if.if_snd))
  303.             goto win;
  304.         if (tp->t_wsel && tp->t_wsel->p_wchan == (caddr_t)&selwait)
  305.             tp->t_state |= TS_WCOLL;
  306.         else
  307.             tp->t_wsel = u.u_procp;
  308.         break;
  309.     }
  310.     splx(s);
  311.     return (0);
  312. win:
  313.     splx(s);
  314.     return (1);
  315. }
  316.  
  317. /*
  318.  * Line specific (tty) ioctl routine.
  319.  * Provide a way to get the ppp unit number.
  320.  * This discipline requires that tty device drivers call
  321.  * the line specific l_ioctl routine from their ioctl routines.
  322.  */
  323. /* ARGSUSED */
  324. ppptioctl(tp, cmd, data, flag)
  325.     struct tty *tp;
  326.     caddr_t data;
  327. {
  328.     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  329.  
  330.     switch (cmd) {
  331.     case TIOCGETD:
  332.         *(int *)data = ((struct ppp_softc *)tp->t_sc)->sc_if.if_unit;
  333.         return (0);
  334.     case FIONREAD:
  335.         *(int *)data = sc->sc_inq.ifq_len;
  336.         return (0);
  337.     }
  338.     return (-1);
  339. }
  340.  
  341. /*
  342.  * FCS lookup table as calculated by genfcstab.
  343.  */
  344. static u_short fcstab[256] = {
  345.     0x0000,    0x1189,    0x2312,    0x329b,    0x4624,    0x57ad,    0x6536,    0x74bf,
  346.     0x8c48,    0x9dc1,    0xaf5a,    0xbed3,    0xca6c,    0xdbe5,    0xe97e,    0xf8f7,
  347.     0x1081,    0x0108,    0x3393,    0x221a,    0x56a5,    0x472c,    0x75b7,    0x643e,
  348.     0x9cc9,    0x8d40,    0xbfdb,    0xae52,    0xdaed,    0xcb64,    0xf9ff,    0xe876,
  349.     0x2102,    0x308b,    0x0210,    0x1399,    0x6726,    0x76af,    0x4434,    0x55bd,
  350.     0xad4a,    0xbcc3,    0x8e58,    0x9fd1,    0xeb6e,    0xfae7,    0xc87c,    0xd9f5,
  351.     0x3183,    0x200a,    0x1291,    0x0318,    0x77a7,    0x662e,    0x54b5,    0x453c,
  352.     0xbdcb,    0xac42,    0x9ed9,    0x8f50,    0xfbef,    0xea66,    0xd8fd,    0xc974,
  353.     0x4204,    0x538d,    0x6116,    0x709f,    0x0420,    0x15a9,    0x2732,    0x36bb,
  354.     0xce4c,    0xdfc5,    0xed5e,    0xfcd7,    0x8868,    0x99e1,    0xab7a,    0xbaf3,
  355.     0x5285,    0x430c,    0x7197,    0x601e,    0x14a1,    0x0528,    0x37b3,    0x263a,
  356.     0xdecd,    0xcf44,    0xfddf,    0xec56,    0x98e9,    0x8960,    0xbbfb,    0xaa72,
  357.     0x6306,    0x728f,    0x4014,    0x519d,    0x2522,    0x34ab,    0x0630,    0x17b9,
  358.     0xef4e,    0xfec7,    0xcc5c,    0xddd5,    0xa96a,    0xb8e3,    0x8a78,    0x9bf1,
  359.     0x7387,    0x620e,    0x5095,    0x411c,    0x35a3,    0x242a,    0x16b1,    0x0738,
  360.     0xffcf,    0xee46,    0xdcdd,    0xcd54,    0xb9eb,    0xa862,    0x9af9,    0x8b70,
  361.     0x8408,    0x9581,    0xa71a,    0xb693,    0xc22c,    0xd3a5,    0xe13e,    0xf0b7,
  362.     0x0840,    0x19c9,    0x2b52,    0x3adb,    0x4e64,    0x5fed,    0x6d76,    0x7cff,
  363.     0x9489,    0x8500,    0xb79b,    0xa612,    0xd2ad,    0xc324,    0xf1bf,    0xe036,
  364.     0x18c1,    0x0948,    0x3bd3,    0x2a5a,    0x5ee5,    0x4f6c,    0x7df7,    0x6c7e,
  365.     0xa50a,    0xb483,    0x8618,    0x9791,    0xe32e,    0xf2a7,    0xc03c,    0xd1b5,
  366.     0x2942,    0x38cb,    0x0a50,    0x1bd9,    0x6f66,    0x7eef,    0x4c74,    0x5dfd,
  367.     0xb58b,    0xa402,    0x9699,    0x8710,    0xf3af,    0xe226,    0xd0bd,    0xc134,
  368.     0x39c3,    0x284a,    0x1ad1,    0x0b58,    0x7fe7,    0x6e6e,    0x5cf5,    0x4d7c,
  369.     0xc60c,    0xd785,    0xe51e,    0xf497,    0x8028,    0x91a1,    0xa33a,    0xb2b3,
  370.     0x4a44,    0x5bcd,    0x6956,    0x78df,    0x0c60,    0x1de9,    0x2f72,    0x3efb,
  371.     0xd68d,    0xc704,    0xf59f,    0xe416,    0x90a9,    0x8120,    0xb3bb,    0xa232,
  372.     0x5ac5,    0x4b4c,    0x79d7,    0x685e,    0x1ce1,    0x0d68,    0x3ff3,    0x2e7a,
  373.     0xe70e,    0xf687,    0xc41c,    0xd595,    0xa12a,    0xb0a3,    0x8238,    0x93b1,
  374.     0x6b46,    0x7acf,    0x4854,    0x59dd,    0x2d62,    0x3ceb,    0x0e70,    0x1ff9,
  375.     0xf78f,    0xe606,    0xd49d,    0xc514,    0xb1ab,    0xa022,    0x92b9,    0x8330,
  376.     0x7bc7,    0x6a4e,    0x58d5,    0x495c,    0x3de3,    0x2c6a,    0x1ef1,    0x0f78
  377. };
  378.  
  379. /*
  380.  * Calculate a new FCS given the current FCS and the new data.
  381.  */
  382. u_short pppfcs(fcs, cp, len)
  383.     register u_short fcs;
  384.     register u_char *cp;
  385.     register int len;
  386. {
  387.     while (len--)
  388.     fcs = PPP_FCS(fcs, *cp++);
  389.     return (fcs);
  390. }
  391.  
  392. /*
  393.  * Queue a packet.  Start transmission if not active.
  394.  * Packet is placed in normally Information field of PPP frame.
  395.  */
  396. pppoutput(ifp, m0, dst)
  397.     struct ifnet *ifp;
  398.     struct mbuf *m0;
  399.     struct sockaddr *dst;
  400. {
  401.     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
  402.     struct mbuf *m, *m1;
  403.     struct ppp_header *ph;
  404.     u_short protocol, fcs;
  405.     u_char address, control, *cp;
  406.     int s, error, compac, compprot;
  407.  
  408.     if (sc->sc_ttyp == NULL ||
  409.         (ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) {
  410.         error = ENETDOWN;    /* sort of */
  411.         goto bad;
  412.     }
  413.     if ((sc->sc_ttyp->t_state & TS_CARR_ON) == 0) {
  414.         error = EHOSTUNREACH;
  415.         goto bad;
  416.     }
  417.  
  418.     /*
  419.      * Compute PPP header.
  420.      */
  421.     address = PPP_ALLSTATIONS;
  422.     control = PPP_UI;
  423.     switch (dst->sa_family) {
  424. #ifdef INET
  425.         case AF_INET:
  426.         protocol = PPP_IP;
  427.         break;
  428. #endif
  429. #ifdef NS
  430.         case AF_NS:
  431.         protocol = PPP_XNS;
  432.         break;
  433. #endif
  434.         case AF_UNSPEC:
  435.         ph = (struct ppp_header *) dst->sa_data;
  436.         address = ph->ph_address;
  437.         control = ph->ph_control;
  438.         protocol = ntohs(ph->ph_protocol);
  439.         break;
  440.         default:
  441.         printf("ppp%d: af%d not supported\n", ifp->if_unit,
  442.             dst->sa_family);
  443.         error = EAFNOSUPPORT;
  444.         goto bad;
  445.     }
  446.     compac = sc->sc_if.if_flags & IFF_COMPAC &&
  447.          address == PPP_ALLSTATIONS &&
  448.          control == PPP_UI &&
  449.          protocol != PPP_ALLSTATIONS;
  450.     compprot = sc->sc_if.if_flags & IFF_COMPPROT &&
  451.          protocol < 0x100;
  452.  
  453.     /*
  454.      * Add PPP header.  If no space in first mbuf, allocate another.
  455.      */
  456.     if (m0->m_off > MMAXOFF ||
  457.         m0->m_off < MMINOFF + sizeof (struct ppp_header)) {
  458.         m = m_get(M_DONTWAIT, MT_HEADER);
  459.         if (m == 0) {
  460.         error = ENOBUFS;
  461.         goto bad;
  462.         }
  463.         m->m_next = m0;
  464.         m->m_len = 0;
  465.         m0 = m;
  466.     } else
  467.         m0->m_off -= (compac ? 0 : 2) + (compprot ? 1 : 2);
  468.  
  469.     cp = mtod(m0, u_char *);
  470.     if (!compac) {
  471.         *cp++ = address;
  472.         *cp++ = control;
  473.         m0->m_len += 2;
  474.     }
  475.     if (!compprot) {
  476.         *cp++ = protocol >> 8;
  477.         m0->m_len++;
  478.     }
  479.     *cp++ = protocol & 0xff;
  480.     m0->m_len++;
  481.  
  482.     /*
  483.      * Add PPP trailer.  Compute one's complement of FCS over frame
  484.      * and attach to mbuf chain least significant byte first.
  485.      */
  486.     fcs = PPP_INITFCS;
  487.     for (m = m0; m; m = m->m_next) {
  488.         fcs = pppfcs(fcs, mtod(m, u_char *), m->m_len);
  489.         m1 = m;
  490.     }
  491.     fcs ^= 0xffff;
  492.  
  493.     if (m1->m_off + m1->m_len > MMAXOFF - sizeof (short) ||
  494.         m1->m_off + m1->m_len < MMINOFF) {
  495.         m = m_get(M_DONTWAIT, MT_HEADER);
  496.         if (m == 0) {
  497.         error = ENOBUFS;
  498.         goto bad;
  499.         }
  500.         m->m_next = NULL;
  501.         m->m_len = 0;
  502.         m1->m_next = m;
  503.         m1 = m;
  504.     }
  505.     cp = mtod(m1, u_char *) + m1->m_len;
  506.     *cp++ = fcs & 0xff;
  507.     *cp++ = fcs >> 8;
  508.     m1->m_len += 2;
  509.  
  510.     s = splimp();
  511.     if (IF_QFULL(&ifp->if_snd)) {
  512.         IF_DROP(&ifp->if_snd);
  513.         sc->sc_if.if_oerrors++;
  514.         splx(s);
  515.         error = ENOBUFS;
  516.         goto bad;
  517.     }
  518.     IF_ENQUEUE(&ifp->if_snd, m0);
  519.     if (sc->sc_ttyp->t_outq.c_cc == 0) {
  520.         splx(s);
  521.         pppstart(sc->sc_ttyp);
  522.     } else
  523.         splx(s);
  524.     return (0);
  525.  
  526. bad:
  527.     m_freem(m0);
  528.     return (error);
  529. }
  530.  
  531. /*
  532.  * Start output on interface.  Get another datagram
  533.  * to send from the interface queue and map it to
  534.  * the interface before starting output.
  535.  */
  536. pppstart(tp)
  537.     register struct tty *tp;
  538. {
  539.     register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
  540.     register struct mbuf *m;
  541.     register int len;
  542.     register u_char *start, *stop, *cp;
  543.     int n, s;
  544.     struct mbuf *m2;
  545.     extern int cfreecount;
  546.  
  547.     for (;;) {
  548.         /*
  549.          * If there is more in the output queue, just send it now.
  550.          * We are being called in lieu of ttstart and must do what
  551.          * it would.
  552.          */
  553.         if (tp->t_outq.c_cc > 0)
  554.             ttstart(tp);
  555.         if (tp->t_outq.c_cc > PPP_HIWAT)
  556.             return;
  557.  
  558.         /*
  559.          * This happens briefly when the line shuts down.
  560.          */
  561.         if (sc == NULL)
  562.             return;
  563.  
  564.         /*
  565.          * If system is getting low on clists
  566.          * and we have something running already, stop here.
  567.          */
  568.         if (cfreecount < CLISTRESERVE +
  569.             sc->sc_if.if_mtu + sizeof (struct ppp_header) &&
  570.             tp->t_outq.c_cc)
  571.             return;
  572.  
  573.         /*
  574.          * Get a packet and send it to the interface.
  575.          */
  576.         s = splimp();
  577.         IF_DEQUEUE(&sc->sc_if.if_snd, m);
  578.         splx(s);
  579.         if (m == NULL)
  580.             return;
  581.  
  582.         /*
  583.          * The extra PPP_FLAG will start up a new packet, and thus
  584.          * will flush any accumulated garbage.  We do this whenever
  585.          * the line may have been idle for some time.
  586.          */
  587.         if (tp->t_outq.c_cc == 0)
  588.             (void) putc(PPP_FLAG, &tp->t_outq);
  589.  
  590.         while (m) {
  591.             start = mtod(m, u_char *);
  592.             len = m->m_len;
  593.             stop = start + len;
  594.             while (len > 0) {
  595.                 /*
  596.                  * Find out how many bytes in the string we can
  597.                  * handle without doing something special.
  598.                  */
  599.                 for (cp = start; cp < stop; cp++)
  600.                     if ((*cp == PPP_FLAG) ||
  601.                         (*cp == PPP_ESCAPE) ||
  602.                         (*cp < 0x20 &&
  603.                          (sc->sc_asyncmap & (1 << *cp))))
  604.                         break;
  605.                 n = cp - start;
  606.                 if (n) {
  607.                     /*
  608.                      * Put n characters at once
  609.                      * into the tty output queue.
  610.                      */
  611.                     if (b_to_q((char *)start, n,
  612.                            &tp->t_outq))
  613.                         break;
  614.                     len -= n;
  615.                     start = cp;
  616.                 }
  617.  
  618.                 /*
  619.                  * If there are characters left in the mbuf,
  620.                  * the first one must be special..
  621.                  * Put it out in a different form.
  622.                  */
  623.                 if (len) {
  624.                     if (putc(PPP_ESCAPE, &tp->t_outq))
  625.                         break;
  626.                     if (putc(*start ^ PPP_TRANS,
  627.                          &tp->t_outq)) {
  628.                         (void) unputc(&tp->t_outq);
  629.                         break;
  630.                     }
  631.                     start++;
  632.                     len--;
  633.                 }
  634.             }
  635.             MFREE(m, m2);
  636.             m = m2;
  637.         }
  638.  
  639.         if (putc(PPP_FLAG, &tp->t_outq)) {
  640.             /*
  641.              * Not enough room.  Remove a char to make room
  642.              * and end the packet normally.
  643.              * If you get many collisions (more than one or two
  644.              * a day) you probably do not have enough clists
  645.              * and you should increase "nclist" in param.c.
  646.              */
  647.             (void) unputc(&tp->t_outq);
  648.             (void) putc(PPP_FLAG, &tp->t_outq);
  649.             sc->sc_if.if_collisions++;
  650.         } else
  651.             sc->sc_if.if_opackets++;
  652.     }
  653. }
  654.  
  655. /*
  656.  * Allocate enough mbuf to handle current MTU.
  657.  */
  658. pppinit(sc)
  659.     register struct ppp_softc *sc;
  660. {
  661.     struct mbuf *m, **mp;
  662.     int len = MAX(sc->sc_if.if_mtu, PPP_MTU) +sizeof (struct ifnet *) +
  663.         sizeof (struct ppp_header) + sizeof (u_short);
  664.     int s;
  665.  
  666.     s = splimp();
  667.     for (mp = &sc->sc_m; *mp; mp = &(*mp)->m_next)
  668.         if ((len -= M_HASCL(*mp) ? MCLBYTES : MLEN) <= 0) {
  669.             splx(s);
  670.             return (1);
  671.         }
  672.  
  673.     for (;; mp = &m->m_next) {
  674.         MGET(m, M_DONTWAIT, MT_DATA);
  675.         if (m) {
  676.             *mp = m;
  677.             MCLGET(m);
  678.             if ((len -= M_HASCL(m) ? MCLBYTES : MLEN) <= 0) {
  679.                 splx(s);
  680.                 return (1);
  681.             }
  682.         }
  683.         else {
  684.             m_freem(sc->sc_m);
  685.             sc->sc_m = NULL;
  686.             splx(s);
  687.             printf("ppp%d: can't allocate mbuf\n", sc - ppp_softc);
  688.             return (0);
  689.         }
  690.     }
  691. }
  692.  
  693. /*
  694.  * Copy mbuf chain.  Would like to use m_copy(), but we need a real copy
  695.  * of the data, not just copies of pointers to the data.
  696.  */
  697. struct mbuf *
  698. ppp_btom(sc)
  699.     struct ppp_softc *sc;
  700. {
  701.     register struct mbuf *m, **mp;
  702.     struct mbuf *top = sc->sc_m;
  703.  
  704.     /*
  705.      * First check current mbuf.  If we have more than MLEN bytes,
  706.      * set beginning of buffer to the next mbuf.
  707.      * Else, copy the current mbuf, attach the copy where the current
  708.      * is attached, and set beginning of buffer to the current mbuf.
  709.      */
  710.     if (sc->sc_mc->m_len > MLEN) {
  711.         sc->sc_m = sc->sc_mc->m_next;
  712.         sc->sc_mc->m_next = NULL;
  713.     }
  714.     else {
  715.         MGET(m, M_DONTWAIT, MT_DATA);
  716.         if (m == NULL)
  717.             return (NULL);
  718.         bcopy(mtod(sc->sc_mc, caddr_t), mtod(m, caddr_t),
  719.               sc->sc_mc->m_len);
  720.         m->m_len = sc->sc_mc->m_len;
  721.         for (mp = ⊤ *mp != sc->sc_mc; mp = &(*mp)->m_next)
  722.             ;
  723.         *mp = m;
  724.         sc->sc_m = sc->sc_mc;
  725.     }
  726.     if (pppinit(sc) == 0) {
  727.         m_freem(top);
  728.         if (pppinit(sc) == 0)
  729.             sc->sc_if.if_flags &= ~IFF_UP;
  730.         return (NULL);
  731.     }
  732.     return (top);
  733. }
  734.  
  735. /*
  736.  * tty interface receiver interrupt.
  737.  */
  738. pppinput(c, tp)
  739.     int c;
  740.     register struct tty *tp;
  741. {
  742.     register struct ppp_softc *sc;
  743.     struct mbuf *m;
  744.     struct ifqueue *inq;
  745.     struct ppp_header *ph;
  746.     int s;
  747.  
  748.     tk_nin++;
  749.     sc = (struct ppp_softc *)tp->t_sc;
  750.     if (sc == NULL)
  751.         return;
  752.  
  753.     c &= 0xff;
  754.     if (c == PPP_FLAG) {
  755.         sc->sc_flags &= ~SC_FLUSH;
  756.  
  757.         if (sc->sc_ilen > 2) {
  758.             /*
  759.              * Remove FCS trailer.  Somewhat painful...
  760.              */
  761.             sc->sc_ilen -= 2;
  762.             if (--sc->sc_mc->m_len == 0) {
  763.             for (m = sc->sc_m;
  764.                  m->m_next != sc->sc_mc;
  765.                  m = m->m_next)
  766.                 ;
  767.             sc->sc_mc = m;
  768.             }
  769.             sc->sc_mc->m_len--;
  770.         }
  771.  
  772.         if (sc->sc_ilen < sizeof (struct ppp_header)) {
  773.             if (sc->sc_ilen)
  774.                 sc->sc_if.if_ierrors++;
  775.             sc->sc_ilen = 0;
  776.             return;
  777.         }
  778.         if (sc->sc_fcs != PPP_GOODFCS ||
  779.             ((m = ppp_btom(sc)) == NULL)) {
  780.             sc->sc_if.if_ierrors++;
  781.             sc->sc_ilen = 0;
  782.             return;
  783.         }
  784.  
  785.         sc->sc_ilen = 0;
  786.         sc->sc_if.if_ipackets++;
  787.         ph = (struct ppp_header *) (mtod(m, struct ifnet **) + 1);
  788.         switch (ntohs(ph->ph_protocol)) {
  789. #ifdef INET
  790.             case PPP_IP:
  791.             schednetisr(NETISR_IP);
  792.             inq = &ipintrq;
  793.             *(((struct ifnet **) (ph + 1)) - 1) =
  794.                 *mtod(m, struct ifnet **);
  795.             m->m_off += sizeof (struct ppp_header);
  796.             m->m_len -= sizeof (struct ppp_header);
  797.             break;
  798. #endif
  799.             default:
  800.             ttwakeup(tp);
  801.             inq = &sc->sc_inq;
  802.         }
  803.         s = splimp();
  804.         if (IF_QFULL(inq)) {
  805.             IF_DROP(inq);
  806.             sc->sc_if.if_ierrors++;
  807.             m_freem(m);
  808.         } else
  809.             IF_ENQUEUE(inq, m);
  810.  
  811.         splx(s);
  812.         return;
  813.     }
  814.     else if (sc->sc_flags & SC_FLUSH)
  815.         return;
  816.     else if (c == PPP_ESCAPE) {
  817.         sc->sc_flags |= SC_ESCAPED;
  818.         return;
  819.     }
  820.  
  821.     if (sc->sc_flags & SC_ESCAPED) {
  822.         sc->sc_flags &= ~SC_ESCAPED;
  823.         c ^= PPP_TRANS;
  824.     }
  825.  
  826.     /*
  827.      * Initialize buffer on first octet received.
  828.      * First octet could be address or protocol (when compressing
  829.      * address/control).
  830.      * Second octet is control.
  831.      * Third octet is first or second (when compressing protocol)
  832.      * octet of protocol.
  833.      * Fourth octet is second octet of protocol.
  834.      */
  835.     if (sc->sc_ilen == 0) {
  836.         sc->sc_mc = sc->sc_m;
  837.         sc->sc_mp = mtod(sc->sc_m, u_char *);
  838.         *((struct ifnet **) sc->sc_mp) = &sc->sc_if;
  839.         sc->sc_mp += sizeof (struct ifnet *);
  840.         sc->sc_m->m_len = sizeof (struct ifnet *);
  841.         sc->sc_fcs = PPP_INITFCS;
  842.         if (c != PPP_ALLSTATIONS) {
  843.             if (sc->sc_if.if_flags & IFF_COMPAC) {
  844.                 *sc->sc_mp++ = PPP_ALLSTATIONS;
  845.                 *sc->sc_mp++ = PPP_UI;
  846.                 sc->sc_ilen += 2;
  847.                 sc->sc_mc->m_len += 2;
  848.             }
  849.             else {
  850.                 sc->sc_if.if_ierrors++;
  851.                 sc->sc_flags |= SC_FLUSH;
  852.                 return;
  853.             }
  854.         }
  855.     }
  856.     if (sc->sc_ilen == 1 &&
  857.         c != PPP_UI) {
  858.         sc->sc_if.if_ierrors++;
  859.         sc->sc_flags |= SC_FLUSH;
  860.         return;
  861.     }
  862.     if (sc->sc_ilen == 2 &&
  863.         (c & 1) == 1) {
  864.         if (sc->sc_if.if_flags & IFF_COMPPROT) {
  865.             *sc->sc_mp++ = 0;
  866.             sc->sc_ilen++;
  867.             sc->sc_mc->m_len++;
  868.         }
  869.         else {
  870.             sc->sc_if.if_ierrors++;
  871.             sc->sc_flags |= SC_FLUSH;
  872.             return;
  873.         }
  874.     }
  875.     if (sc->sc_ilen == 3 &&
  876.         (c & 1) == 0) {
  877.         sc->sc_if.if_ierrors++;
  878.         sc->sc_flags |= SC_FLUSH;
  879.         return;
  880.     }
  881.  
  882.     if (++sc->sc_ilen > MAX(sc->sc_if.if_mtu, PPP_MTU) +
  883.         sizeof (struct ppp_header) + sizeof (u_short)) {
  884.         sc->sc_if.if_ierrors++;
  885.         sc->sc_flags |= SC_FLUSH;
  886.         return;
  887.     }
  888.     if (sc->sc_mc->m_len >=
  889.         (M_HASCL(sc->sc_mc) ? MCLBYTES : MLEN)) {
  890.         sc->sc_mc = sc->sc_mc->m_next;
  891.         sc->sc_mp = mtod(sc->sc_mc, u_char *);
  892.         sc->sc_mc->m_len = 0;
  893.     }
  894.     ++sc->sc_mc->m_len;
  895.     *sc->sc_mp++ = c;
  896.     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
  897. }
  898.  
  899. /*
  900.  * Process an ioctl request.
  901.  */
  902. pppioctl(ifp, cmd, data)
  903.     register struct ifnet *ifp;
  904.     int cmd;
  905.     caddr_t data;
  906. {
  907.     register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
  908.     register struct ifaddr *ifa = (struct ifaddr *)data;
  909.     register struct ifreq *ifr = (struct ifreq *)data;
  910.     int s = splimp(), error = 0;
  911.  
  912.     switch (cmd) {
  913.     case SIOCSIFFLAGS:
  914.         if ((ifp->if_flags & IFF_RUNNING) == 0)
  915.             ifp->if_flags &= ~IFF_UP;
  916.         break;
  917.  
  918.     case SIOCSIFADDR:
  919.         if (ifa->ifa_addr.sa_family != AF_INET)
  920.             error = EAFNOSUPPORT;
  921.         break;
  922.  
  923.     case SIOCSIFDSTADDR:
  924.         if (ifa->ifa_addr.sa_family != AF_INET)
  925.             error = EAFNOSUPPORT;
  926.         break;
  927.  
  928.     case SIOCSIFMTU:
  929.         if (!suser())
  930.             return (EPERM);
  931.         sc->sc_if.if_mtu = ifr->ifr_mtu;
  932.         if (pppinit(sc) == 0)
  933.             error = ENOBUFS;
  934.         break;
  935.  
  936.     case SIOCGIFMTU:
  937.         ifr->ifr_mtu = sc->sc_if.if_mtu;
  938.         break;
  939.  
  940.     case SIOCSIFASYNCMAP:
  941.         if (!suser())
  942.             return (EPERM);
  943.         sc->sc_asyncmap = ifr->ifr_asyncmap;
  944.         break;
  945.  
  946.     case SIOCGIFASYNCMAP:
  947.         ifr->ifr_asyncmap = sc->sc_asyncmap;
  948.         break;
  949.  
  950.     default:
  951.         error = EINVAL;
  952.     }
  953.     splx(s);
  954.     return (error);
  955. }
  956. #endif
  957.