if_ppp.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:51k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver */
  2. /* Copyright 1996 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /* $NetBSD: if_ppp.c,v 1.20 1994/10/30 21:48:52 cgd Exp $ */
  5. /*
  6.  * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
  7.  *
  8.  * Copyright (c) 1989 Carnegie Mellon University.
  9.  * All rights reserved.
  10.  *
  11.  * Redistribution and use in source and binary forms are permitted
  12.  * provided that the above copyright notice and this paragraph are
  13.  * duplicated in all such forms and that any documentation,
  14.  * advertising materials, and other materials related to such
  15.  * distribution and use acknowledge that the software was developed
  16.  * by Carnegie Mellon University.  The name of the
  17.  * University may not be used to endorse or promote products derived
  18.  * from this software without specific prior written permission.
  19.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  20.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  21.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  22.  *
  23.  * Drew D. Perkins
  24.  * Carnegie Mellon University
  25.  * 4910 Forbes Ave.
  26.  * Pittsburgh, PA 15213
  27.  * (412) 268-8576
  28.  * ddp@andrew.cmu.edu
  29.  *
  30.  * Based on:
  31.  * @(#)if_sl.c 7.6.1.2 (Berkeley) 2/15/89
  32.  *
  33.  * Copyright (c) 1987 Regents of the University of California.
  34.  * All rights reserved.
  35.  *
  36.  * Redistribution and use in source and binary forms are permitted
  37.  * provided that the above copyright notice and this paragraph are
  38.  * duplicated in all such forms and that any documentation,
  39.  * advertising materials, and other materials related to such
  40.  * distribution and use acknowledge that the software was developed
  41.  * by the University of California, Berkeley.  The name of the
  42.  * University may not be used to endorse or promote products derived
  43.  * from this software without specific prior written permission.
  44.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  45.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  46.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  47.  *
  48.  * Serial Line interface
  49.  *
  50.  * Rick Adams
  51.  * Center for Seismic Studies
  52.  * 1300 N 17th Street, Suite 1450
  53.  * Arlington, Virginia 22209
  54.  * (703)276-7900
  55.  * rick@seismo.ARPA
  56.  * seismo!rick
  57.  *
  58.  * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
  59.  * Converted to 4.3BSD Beta by Chris Torek.
  60.  * Other changes made at Berkeley, based in part on code by Kirk Smith.
  61.  *
  62.  * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
  63.  * Added VJ tcp header compression; more unified ioctls
  64.  *
  65.  * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
  66.  * Cleaned up a lot of the mbuf-related code to fix bugs that
  67.  * caused system crashes and packet corruption.  Changed pppstart
  68.  * so that it doesn't just give up with a collision if the whole
  69.  * packet doesn't fit in the output ring buffer.
  70.  *
  71.  * Added priority queueing for interactive IP packets, following
  72.  * the model of if_sl.c, plus hooks for bpf.
  73.  * Paul Mackerras (paulus@cs.anu.edu.au).
  74.  */
  75. /* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
  76. /*
  77. modification history
  78. --------------------
  79. 01y,20may02,vvv  modified receive mechanism to use ipintr without queueing
  80. 01x,28mar02,jmp  Increased again read buffer size for solaris simulator and
  81.  added global variable simPppRBufSize to make this buffer
  82.  size increasable from solaris's bsp (SPR #74733).
  83. 01w,17sep01,jmp  Increased read buffer size for solaris simulator (SPR
  84.                  #34025).
  85. 01v,06feb01,ijm  Fix for SPR# 62196: pppDelete should not delete ppp_wrt_task
  86.  while it holds the semaphore that tNetTask needs to run.
  87. 01u,17oct00,spm  updated for new if_attach: reports memory allocation failures
  88. 01t,16apr99,koz  Fix for 25165, communications error handling
  89. 01s,17feb99,sgv  Fix for spr 23702, pppintr check for NULL ppp_softc
  90. 01r,17feb99,sgv  Fix for spr 24459. pppalloc was not setting the correct
  91.  ppp_softc structure to NULL on error condition
  92. 01q.10sep98,sgv  Added fix for interoperating with Windows
  93. 01p,18aug97,jmb  Add code to discard packets at interrupt level due
  94.  to overflow of input ring buffer.
  95. 01o,30dec97,sgv  fixed problem in PPP output Hooks
  96. 01n,26sep97,sgv  Added PPP output Hooks
  97. 01m,19sep97,vin  changed m_ext.ext_buf to m_extBuf and m_ext.ext_size to
  98.  m_extSize
  99. 01l,14nov96,vin  upgraded to use new buffering scheme.
  100. 01k,13aug96,vin  upgraded to BSD4.4, removed call in_ifaddr_remove as it is 
  101.  being done in if_dettach. 
  102. 01j,30jul95,dzb  cleanup on errors while openning serial device.
  103. 01i,05jul95,dzb  close out serial fd on errors in pppalloc().
  104. 01h,12jun95,dzb  added SNMP MIBII support (counters and ioctl).
  105.                  header file consolidation.
  106. 01g,24apr95,dzb  removed in_ifaddr_remove() because added to in.c (SPR #4109).
  107. 01f,09mar95,dzb  added counters for ip packets sent/received.
  108. 01e,06mar95,dzb  changed cfree() to free() (ANSI).
  109. 01d,09feb95,dab  added SIOCGIFMTU command to ppptioctl().
  110. 01c,07feb95,dzb  changed pppoutput() to return errno, instead of ERROR.
  111.                  removed redundant mbuf check from ppp_wrt_flush().
  112.  zeroed out m_len after MGET (SPR #4037).
  113. 01b,16jan95,dzb  warnings cleanup.  moved global prototypes to if_ppp.h.
  114. 01a,21dec94,dab  VxWorks port - first WRS version.
  115.            +dzb  added: path for ppp header files, WRS copyright.
  116. */
  117. #include "vxWorks.h"
  118. #include "net/mbuf.h"
  119. #include "sockLib.h"
  120. #include "ioctl.h"
  121. #include "stdio.h"
  122. #include "errnoLib.h"
  123. #include "ioLib.h"
  124. #include "iosLib.h"
  125. #include "semLib.h"
  126. #include "memLib.h"
  127. #include "taskLib.h"
  128. #include "signal.h"
  129. #include "sigLib.h"
  130. #include "etherLib.h"
  131. #include "netLib.h"
  132. #include "m2Lib.h"
  133. #include "private/m2LibP.h"
  134. #include "net/if.h"
  135. #include "net/unixLib.h"
  136. #include "net/route.h"
  137. #include "netinet/in.h"
  138. #include "netinet/in_systm.h"
  139. #include "netinet/in_var.h"
  140. #include "netinet/ip.h"
  141. #include "netinet/ip_var.h"
  142. #include "pppLib.h"
  143. #include "rngLib.h"
  144. #include "tyLib.h"
  145. #include "tickLib.h"
  146. #if NPPP > 0
  147. #ifdef VJC
  148. #define HDROFF  MAX_HDR
  149. /* HDROFF should really be 128, but other parts of the system will
  150.    panic on TCP+IP headers bigger than MAX_HDR = MHLEN (100). */
  151. #else
  152. #define HDROFF  (0)
  153. #endif
  154. #define PPP_HIWAT       400     /* Don't start a new packet if HIWAT on que */
  155. /* external variables */
  156. IMPORT void if_dettach();
  157. IMPORT void if_down();
  158. /* global variables */
  159. struct ppp_softc *ppp_softc[NPPP] = { 0 } ;
  160. int ppp_wrt_task_priority     = 60;
  161. int ppp_wrt_task_options      = VX_SUPERVISOR_MODE | VX_UNBREAKABLE;
  162. int ppp_wrt_task_stack_size    = 0x4000;
  163. char *ppp_device_name = "ppp";
  164. #if (CPU_FAMILY==SIMSPARCSOLARIS)
  165. int simPppRBufSize = 48 * PPP_MTU; /* size of PPP read ring buffer */
  166. #endif
  167. static int pppioctl __ARGS((struct ifnet *, int , caddr_t));
  168. static int pppattach __ARGS((int));
  169. static int pppoutput __ARGS((struct ifnet *, struct mbuf *, struct sockaddr *,
  170.      struct rtentry *));
  171. static void pppinput __ARGS((struct ppp_softc *, int));
  172. static int pppasyncstart __ARGS((struct ppp_softc *));
  173. static u_short pppfcs __ARGS((int, u_char *, int));
  174. static int pppgetm __ARGS((struct ppp_softc *sc));
  175. static void pppdumpm __ARGS((struct mbuf *, int));
  176. static void pppdumpb __ARGS((u_char *, int));
  177. static void ppplogchar __ARGS((struct ppp_softc *, int));
  178. static void pppdealloc __ARGS((struct ppp_softc *));
  179. static struct ppp_softc *pppalloc __ARGS((int, char *));
  180. static void ppp_wrt_flush __ARGS((struct ppp_softc *));
  181. static void pinit __ARGS((int));
  182. static int pppintr __ARGS((int, int));
  183. static void ppp_tty_read __ARGS((int, struct ppp_softc *, int));
  184. /*
  185.  * Some useful mbuf macros not in mbuf.h.
  186.  */
  187. #define M_DATASTART(m) (m)->m_extBuf
  188. #define M_DATASIZE(m) (m)->m_extSize
  189. #define PPPBUFSIZE        (PPP_MTU * 2)
  190. /*
  191.  * The following disgusting hack gets around the problem that IP TOS
  192.  * can't be set yet.  We want to put "interactive" traffic on a high
  193.  * priority queue.  To decide if traffic is interactive, we check that
  194.  * a) it is TCP and b) one of its ports is telnet, rlogin or ftp control.
  195.  */
  196. static u_short interactive_ports[8] = {
  197.         0,      513,    0,      0,
  198.         0,      21,     0,      23,
  199. };
  200. #define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
  201. /*
  202.  * Does c need to be escaped?
  203.  */
  204. #define ESCAPE_P(c)     (sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
  205. /*
  206.  * Called to establish ppp interfaces.
  207.  */
  208. static int
  209. pppattach(unit)
  210.     int unit;
  211. {
  212.     register struct ppp_softc *sc;
  213.     int status;
  214.     sc = ppp_softc[unit];
  215.     sc->sc_if.if_name = "ppp";
  216.     sc->sc_if.if_unit = unit;
  217.     sc->sc_if.if_mtu = PPP_MTU;
  218.     sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST ;
  219.     sc->sc_if.if_type = IFT_PPP;
  220.     sc->sc_if.if_hdrlen = PPP_HDRLEN;
  221.     sc->sc_if.if_ioctl = pppioctl;
  222.     sc->sc_if.if_output = pppoutput;
  223.     sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
  224.     sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
  225.     sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
  226.     sc->sc_if.if_reset = pppclose;
  227.     sc->sc_if.if_init = (FUNCPTR) pinit;
  228.     status = if_attach(&sc->sc_if);
  229.     return (status);
  230. }
  231. /*
  232.  * Allocate a ppp interface unit and initialize it.
  233.  */
  234. static struct ppp_softc *
  235. pppalloc(unit, device)
  236.     int unit;
  237.     char *device;
  238. {
  239.     struct ppp_softc *sc;
  240.     if (ppp_softc[unit] != NULL)
  241.         return NULL;
  242.     if ((sc = (struct ppp_softc *)calloc(1, sizeof(struct ppp_softc))) == NULL)
  243.         return (NULL);
  244.     ppp_softc[unit] = sc;
  245.     if ((sc->sc_fd = open(device, O_RDWR, 0)) == ERROR)
  246.         {
  247.         ppp_softc[unit] = (struct ppp_softc *)NULL;
  248.         free((char *) sc);
  249.         return NULL;
  250. }
  251. #if (CPU_FAMILY==SIMSPARCSOLARIS)
  252.     /*
  253.      * For PPP on solaris simulator, the receive buffer size must be more
  254.      * important. This is necessary because the solaris host can send several 
  255.      * several PPP packets to the simulator before he is able to
  256.      * handle them (don't forget that they share the same CPU).
  257.      * If the receive buffer size is too small to store all the received
  258.      * characters, some of them may be lost. The new value has been chosen
  259.      * after some testing (with this value, the simulator has time to
  260.      * handle packets before the receive buffer is full) but may not be
  261.      * sufficient in all cases, if not sufficient simPppRBufSize can be
  262.      * increased in sysLib.c.
  263.      */
  264.     if (ioctl(sc->sc_fd, FIORBUFSET, simPppRBufSize) == ERROR ||
  265. #else /* CPU_FAMILY==SIMSPARCSOLARIS */
  266.     if (ioctl(sc->sc_fd, FIORBUFSET, 4 * PPP_MTU) == ERROR ||
  267. #endif
  268.         ioctl(sc->sc_fd, FIOWBUFSET, 4 * PPP_MTU) == ERROR) {
  269.         close(sc->sc_fd);
  270.         ppp_softc[unit] = (struct ppp_softc *)NULL;
  271.         free((char *) sc);
  272.         return NULL;
  273.     }
  274.     if (pppattach(unit) == ERROR) { 
  275.         close(sc->sc_fd);
  276.         ppp_softc[unit] = (struct ppp_softc *)NULL;
  277.         free((char *) sc);
  278.         return (NULL);
  279.     }
  280.     if (ioctl(sc->sc_fd, FIOPROTOHOOK, (int)pppintr) == ERROR ||
  281.         ioctl(sc->sc_fd, FIOPROTOARG, unit) == ERROR) {
  282.         close(sc->sc_fd);
  283.         pppdealloc(sc);
  284.         return (NULL);
  285.     }
  286.     sc->sc_flags = 0;
  287.     sc->sc_mru = PPP_MRU;
  288. #ifdef VJC
  289.     sl_compress_init(&sc->sc_comp);
  290. #endif
  291.     sc->sc_if.if_flags |=  IFF_RUNNING;
  292.     return sc;
  293. }
  294. /*
  295.  * Deallocate a ppp unit.
  296.  */
  297. static void
  298. pppdealloc(sc)
  299.     struct ppp_softc *sc;
  300. {
  301.     struct mbuf *m;
  302.     if_down(&sc->sc_if);
  303.     sc->sc_devp = NULL;
  304.     sc->sc_xfer = 0;
  305.     for (;;) {
  306.         IF_DEQUEUE(&sc->sc_inq, m);
  307.         if (m == NULL)
  308.             break;
  309.         m_freem(m);
  310.     }
  311.     for (;;) {
  312.         IF_DEQUEUE(&sc->sc_fastq, m);
  313.         if (m == NULL)
  314.             break;
  315.         m_freem(m);
  316.     }
  317.     sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
  318.     if_dettach(&sc->sc_if);
  319.     ppp_softc[sc->sc_if.if_unit] = (struct ppp_softc *)NULL;
  320.     free((char *) sc);
  321. }
  322. /*
  323.  * pppopen - open the ppp interface.
  324.  *       Returns unit id.
  325.  */
  326. int
  327. pppopen(unit, device)
  328.     int unit;
  329.     char *device;
  330. {
  331.     register struct ppp_softc *sc;
  332.     char ppp_wrt_name[10];
  333.     if ((sc = pppalloc(unit, device)) == NULL)
  334.         return (ERROR);
  335.     if (sc->sc_outm != NULL) {
  336.         m_freem(sc->sc_outm);
  337.         sc->sc_outm = NULL;
  338.     }
  339.     if (pppgetm(sc) == 0) {
  340.         sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
  341.         return (ERROR);
  342.     }
  343.     sc->sc_ilen  = 0;
  344.     bzero((char *)sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
  345.     sc->sc_asyncmap[0] = 0xffffffff;
  346.     sc->sc_asyncmap[3] = 0x60000000;
  347.     sc->sc_rasyncmap = 0;
  348.     sc->sc_devp = (void *) NULL;
  349.     sc->sc_start = pppasyncstart;
  350.     sc->sc_qlen  = 0;
  351.     sc->sc_tid = taskIdSelf();
  352.     semBInit(&sc->sc_wrtsem, SEM_Q_PRIORITY, SEM_EMPTY);
  353.     ioctl(sc->sc_fd, FIOFLUSH, 0);
  354.     sprintf(ppp_wrt_name, "tPPP%dWrt", sc->sc_if.if_unit);
  355.     sc->sc_wrt_task_id = taskSpawn(ppp_wrt_name, ppp_wrt_task_priority,
  356.                                    ppp_wrt_task_options,
  357.                                    ppp_wrt_task_stack_size,
  358.    (FUNCPTR)ppp_wrt_task, (int)sc,
  359.    0, 0, 0, 0, 0, 0, 0, 0, 0);
  360.     if (sc->sc_wrt_task_id == ERROR) {
  361.         close(sc->sc_fd);
  362.         pppdealloc(sc);
  363.         return (ERROR);
  364.     }
  365.     return (OK);
  366. }
  367.     
  368. /*
  369.  * Line specific close routine.
  370.  * Detach the tty from the ppp unit.
  371.  * Mimics part of ttyclose().
  372.  */
  373. int
  374. pppclose(unit)
  375.     int unit;
  376. {
  377.     register struct ppp_softc *sc;
  378.     int s;
  379.     if (unit >= 0 && unit < NPPP)
  380.         sc = ppp_softc[unit];
  381.     else
  382.         return (ERROR);
  383.     if (sc != NULL) {
  384. ppp_wrt_flush(sc);
  385.         ioctl(sc->sc_fd, FIOPROTOHOOK, (int) NULL);
  386.         taskDelete(sc->sc_wrt_task_id);
  387.         s = splimp(); /* paranoid; splnet probably ok */
  388.         close(sc->sc_fd);
  389.         m_freem(sc->sc_outm);
  390.         sc->sc_outm = NULL;
  391.         m_freem(sc->sc_m);
  392.         sc->sc_m = NULL;
  393.         pppdealloc(sc);
  394.         splx(s);
  395.     }
  396.     else
  397.         return (ERROR);
  398.     return(OK);
  399. }
  400. /*
  401.  * Line specific (tty) read routine.
  402.  */
  403. int
  404. pppread(unit, buf, count)
  405.     int unit;
  406.     char *buf;
  407.     int count;
  408. {
  409.     register struct ppp_softc *sc = ppp_softc[unit];
  410.     struct mbuf *m;
  411.     register int s;
  412.     s = splimp();
  413.     IF_DEQUEUE(&sc->sc_inq, m);
  414.     splx(s);
  415.     if (m == NULL)
  416. return 0;
  417.     copy_from_mbufs(buf, m, count);
  418.     return (count);
  419. }
  420. /*
  421.  * Line specific (tty) write routine.
  422.  */
  423. int
  424. pppwrite(unit, buf, count)
  425.     int unit;
  426.     char *buf;
  427.     int count;
  428. {
  429.     register struct ppp_softc *sc = ppp_softc[unit];
  430.     struct mbuf *m, *m0, **mp;
  431.     struct sockaddr dst;
  432.     struct ppp_header *ph1, *ph2;
  433.     int len;
  434.     if (count > sc->sc_if.if_mtu + PPP_HDRLEN ||
  435.         count < PPP_HDRLEN) {
  436.         errno = EMSGSIZE;
  437.         return (-1);
  438.     }
  439.     for (mp = &m0; count; mp = &m->m_next) {
  440.         m = mBufClGet(M_WAIT, MT_DATA, count, FALSE);
  441.         if ((*mp = m) == NULL) {
  442.             m_freem(m0);
  443.             errno = ENOBUFS;
  444.             return (-1);
  445.         }
  446. len = min (count, m->m_extSize); /* num for copy */
  447.         bcopy(buf, mtod(m, caddr_t), len);
  448.         count -= len;
  449.         m->m_len = len;
  450.     }
  451.     dst.sa_family = AF_UNSPEC;
  452.     ph1 = (struct ppp_header *) &dst.sa_data;
  453.     ph2 = mtod(m0, struct ppp_header *);
  454.     memcpy (ph1, ph2, sizeof (*ph1)); /* from RTP for bug on 29k */
  455.     m0->m_data += PPP_HDRLEN;
  456.     m0->m_len -= PPP_HDRLEN;
  457.     return (pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0));
  458. }
  459. /*
  460.  * Line specific (tty) ioctl routine.
  461.  * Provide a way to get the ppp unit number.
  462.  * This discipline requires that tty device drivers call
  463.  * the line specific l_ioctl routine from their ioctl routines.
  464.  */
  465. int
  466. ppptioctl(unit, cmd, data)
  467.     int unit;
  468.     int cmd;
  469.     caddr_t data;
  470. {
  471.     register struct ppp_softc *sc = ppp_softc[unit];
  472.     int s, flags, mru;
  473.     int error = 0; 
  474.     if (sc == NULL)
  475.         return -1;
  476.     switch (cmd) {
  477.     case FIONREAD:
  478.         *(int *)data = sc->sc_qlen;
  479.         break;
  480.     case PPPIOCGUNIT:
  481.         *(int *)data = sc->sc_if.if_unit;
  482.         break;
  483.     case PPPIOCGFLAGS:
  484.         *(u_int *)data = sc->sc_flags;
  485.         break;
  486.     case PPPIOCSFLAGS:
  487.         flags = *(int *)data & SC_MASK;
  488.         s = splimp();
  489.         sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
  490.         splx(s);
  491.         break;
  492.     case PPPIOCSASYNCMAP:
  493.         sc->sc_asyncmap[0] = *(u_int *)data;
  494.         break;
  495.     case PPPIOCGASYNCMAP:
  496.         *(u_int *)data = sc->sc_asyncmap[0];
  497.         break;
  498.     case PPPIOCSRASYNCMAP:
  499.         sc->sc_rasyncmap = *(u_int *)data;
  500.         break;
  501.     case PPPIOCGRASYNCMAP:
  502.         *(u_int *)data = sc->sc_rasyncmap;
  503.         break;
  504.     case PPPIOCSXASYNCMAP:
  505.         bcopy((char *)data, (char *)sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
  506.         sc->sc_asyncmap[1] = 0;             /* mustn't escape 0x20 - 0x3f */
  507.         sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
  508.         sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
  509.         break;
  510.     case PPPIOCGXASYNCMAP:
  511.         bcopy((char *)sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
  512.         break;
  513.     case PPPIOCSMRU:
  514.         mru = *(int *)data;
  515.         if (mru >= PPP_MRU && mru <= PPP_MAXMRU) {
  516.             sc->sc_mru = mru;
  517.             if (pppgetm(sc) == 0) {
  518.         error = ENOBUFS;
  519.         sc->sc_mru = PPP_MRU;
  520.         if (pppgetm(sc) == 0)
  521. sc->sc_if.if_flags &= ~IFF_UP;
  522.             }
  523.         }
  524.         break;
  525.     case PPPIOCGMRU:
  526.         *(int *)data = sc->sc_mru;
  527.         break;
  528. #ifdef VJC
  529.     case PPPIOCSMAXCID:
  530. if (*(int *)data > MAX_STATES)
  531.     {
  532.     error = EINVAL; 
  533.     break;
  534.     }
  535.         sl_compress_init(&sc->sc_comp);
  536.         break;
  537. #endif
  538.     case PPPIOCXFERUNIT:
  539.         sc->sc_xfer = 0;
  540.         break;
  541.     case SIOCSIFMTU:
  542. sc->sc_if.if_mtu = *(int *)data;
  543. break;
  544.     case SIOCGIFMTU:
  545.         *(int *)data = sc->sc_if.if_mtu;
  546.         break;
  547.     case PPPIOCGFD:
  548.         *(int *)data = sc->sc_fd;
  549.         break;
  550.     default:
  551.         return (ENOTSUP);
  552.     }
  553.     return (error);
  554. }
  555. static
  556. void pinit(unit)
  557.     int unit;
  558. {
  559.     struct ppp_softc *ppp = ppp_softc [unit];
  560.     ppp->sc_if.if_flags |= IFF_UP | IFF_RUNNING; /* open for business */
  561. }
  562. /*
  563.  * FCS lookup table as calculated by genfcstab.
  564.  */
  565. static u_short fcstab[256] = {
  566. 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
  567. 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
  568. 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
  569. 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
  570. 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
  571. 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
  572. 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
  573. 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
  574. 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
  575. 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
  576. 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
  577. 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
  578. 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
  579. 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
  580. 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
  581. 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
  582. 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
  583. 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
  584. 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
  585. 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
  586. 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
  587. 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
  588. 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
  589. 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
  590. 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
  591. 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
  592. 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
  593. 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
  594. 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
  595. 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
  596. 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
  597. 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
  598. };
  599. /*
  600.  * Calculate a new FCS given the current FCS and the new data.
  601.  */
  602. static u_short
  603. pppfcs(fcs, cp, len)
  604.     register u_short fcs;
  605.     register u_char *cp;
  606.     register int len;
  607. {
  608.     while (len--)
  609.         fcs = PPP_FCS(fcs, *cp++);
  610.     return (fcs);
  611. }
  612. /*
  613.  * Queue a packet.  Start transmission if not active.
  614.  * Packet is placed in Information field of PPP frame.
  615.  */
  616. static int
  617. pppoutput(ifp, m0, dst, pRtEntry)
  618.     struct ifnet *ifp;
  619.     struct mbuf *m0;
  620.     struct sockaddr *dst;
  621.     struct rtentry * pRtEntry;  /* to satisfy compiler */
  622. {
  623.     register struct ppp_softc *sc = ppp_softc[ifp->if_unit];
  624.     struct ppp_header *ph;
  625.     int protocol, address, control;
  626.     u_char *cp;
  627.     int s, error;
  628.     struct ip *ip;
  629.     struct ifqueue *ifq;
  630.     char buf[PPPBUFSIZE];
  631.     if ((sc->sc_fd == 0 || (ifp->if_flags & IFF_RUNNING) == 0
  632.         || (ifp->if_flags & IFF_UP) == 0) && dst->sa_family != AF_UNSPEC) {
  633.         error = ENETDOWN; /* sort of */
  634.         goto bad;
  635.     }
  636.     /*
  637.      * Compute PPP header.
  638.      */
  639.     address = PPP_ALLSTATIONS;
  640.     control = PPP_UI;
  641.     ifq = &ifp->if_snd;
  642.     switch (dst->sa_family) {
  643.     case AF_INET:
  644.         protocol = PPP_IP;
  645.         if ((sc->sc_flags & SC_ENABLE_IP) == 0) {
  646.             error = ENETDOWN;
  647.             goto bad;
  648.         }
  649. sc->sc_ipsent++; /* incr ip packets sent */
  650.         /*
  651.          * If this is a TCP packet to or from an "interactive" port,
  652.          * put the packet on the fastq instead.
  653.          */
  654.         if ((ip = mtod(m0, struct ip *))->ip_p == IPPROTO_TCP) {
  655.             register int p = ntohl(((int *)ip)[ip->ip_hl]);
  656.             if (INTERACTIVE(p & 0xffff) || INTERACTIVE(p >> 16))
  657.                 ifq = &sc->sc_fastq;
  658.         }
  659.         break;
  660. #ifdef NS
  661.     case AF_NS:
  662.         protocol = PPP_XNS;
  663.             break;
  664. #endif
  665.     case AF_UNSPEC:
  666.         ph = (struct ppp_header *)dst->sa_data;
  667.         address = ph->ph_address;
  668.         control = ph->ph_control;
  669.         protocol = ntohs(ph->ph_protocol);
  670.         break;
  671.     default:
  672.         printf("ppp%d: af%d not supportedn",
  673.         ifp->if_unit, dst->sa_family);
  674.         error = EAFNOSUPPORT;
  675.         goto bad;
  676.     }
  677.     /*
  678.      * Add PPP header.  If no space in first mbuf, allocate another.
  679.      * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
  680.      */
  681.     if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
  682.         m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
  683.         if (m0 == 0) {
  684.             error = ENOBUFS;
  685.         goto bad;
  686.         }
  687.         m0->m_len = 0;
  688.     } else
  689.         m0->m_data -= PPP_HDRLEN;
  690.     cp = mtod(m0, u_char *);
  691.     *cp++ = address;
  692.     *cp++ = control;
  693.     *cp++ = protocol >> 8;
  694.     *cp++ = protocol & 0xff;
  695.     m0->m_len += PPP_HDRLEN;
  696.     if (sc->sc_flags & SC_LOG_OUTPKT) {
  697.         printf("ppp%d output: ", ifp->if_unit);
  698.         pppdumpm(m0, -1);
  699.     }
  700.     /* Process etherOutputHook */
  701.     if ((etherOutputHookRtn != NULL))
  702. {
  703. struct mbuf *mp;
  704. int ilen;
  705. FAST char *p = (char *)buf;
  706. ilen = 0;
  707. /* Calculate the packet len */
  708. for (mp = m0; mp != NULL; mp = mp->m_next)
  709.         ilen += mp->m_len;
  710. /* Copy the packet to the buffer */
  711. for (mp = m0; mp != NULL; p += mp->m_len, mp = mp->m_next)
  712.             bcopy(mtod (mp, char *), p, mp->m_len);
  713. if ((*etherOutputHookRtn) (ifp, buf, ilen) != 0)
  714.             {
  715.     /* output hook has already processed this packet */
  716.             return (OK);
  717.             }
  718. }
  719.     /*
  720.      * Put the packet on the appropriate queue.
  721.      */
  722.     s = splimp();
  723.     if (IF_QFULL(ifq)) {
  724.         IF_DROP(ifq);
  725.         splx(s);
  726.         sc->sc_if.if_oerrors++;
  727.         error = ENOBUFS;
  728.         goto bad;
  729.     }
  730.     IF_ENQUEUE(ifq, m0);
  731.     ifp->if_lastchange = tickGet ();  /* record the last change */
  732.     /*
  733.      * Tell the device to send it out.
  734.      */
  735.     (*sc->sc_start)(sc);
  736.     splx(s);
  737.     return (OK);
  738. bad:
  739.     m_freem(m0);
  740.     errno = error;
  741.     return (error);
  742. }
  743. /*
  744.  * Grab another packet off a queue and apply VJ compression,
  745.  * address/control and/or protocol compression if appropriate.
  746.  */
  747. static struct mbuf *
  748. ppp_dequeue(sc)
  749.     struct ppp_softc *sc;
  750. {
  751.     int s;
  752.     struct mbuf *m;
  753.     u_char *cp;
  754.     int address, control, protocol;
  755.     s = splimp();
  756.     IF_DEQUEUE(&sc->sc_fastq, m);
  757.     if (m == NULL)
  758.         IF_DEQUEUE(&sc->sc_if.if_snd, m);
  759.     splx(s);
  760.     if (m == NULL)
  761.         return NULL;
  762.     /*
  763.      * Extract the ppp header of the new packet.
  764.      * The ppp header will be in one mbuf.
  765.      */
  766.     cp = mtod(m, u_char *);
  767.     address = cp[0];
  768.     control = cp[1];
  769.     protocol = (cp[2] << 8) + cp[3];
  770.     switch (protocol) {
  771. #ifdef VJC
  772.     case PPP_IP:
  773.     /*
  774.      * If the packet is a TCP/IP packet, see if we can compress it.
  775.      */
  776. if (sc->sc_flags & SC_COMP_TCP) {
  777.             struct ip *ip;
  778.     int type;
  779.     struct mbuf *mp;
  780.     mp = m;
  781.     ip = (struct ip *) (cp + PPP_HDRLEN);
  782.     if (mp->m_len <= PPP_HDRLEN) {
  783.                 mp = mp->m_next;
  784. if (mp == NULL)
  785.     break;
  786. ip = mtod(mp, struct ip *);
  787.     }
  788.         /* this code assumes the IP/TCP header is in one non-shared mbuf */
  789.     if (ip->ip_p == IPPROTO_TCP) {
  790.                 type = sl_compress_tcp(mp, ip, &sc->sc_comp,
  791.        !(sc->sc_flags & SC_NO_TCP_CCID));
  792. switch (type) {
  793. case TYPE_UNCOMPRESSED_TCP:
  794.     protocol = PPP_VJC_UNCOMP;
  795.     break;
  796. case TYPE_COMPRESSED_TCP:
  797.     protocol = PPP_VJC_COMP;
  798.     cp = mtod(m, u_char *);
  799.     cp[0] = address;        /* header has moved */
  800.     cp[1] = control;
  801.     cp[2] = 0;
  802.     break;
  803. }
  804. cp[3] = protocol;   /* update protocol in PPP header */
  805.     }
  806. }
  807. #endif  /* VJC */
  808.     }
  809.     /*
  810.      * Compress the address/control and protocol, if possible.
  811.      */
  812.     if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
  813.         control == PPP_UI && protocol != PPP_ALLSTATIONS &&
  814.         protocol != PPP_LCP) {
  815.         /* can compress address/control */
  816.         m->m_data += 2;
  817.         m->m_len -= 2;
  818.     }
  819.     if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
  820.         /* can compress protocol */
  821.         if (mtod(m, u_char *) == cp) {
  822.             cp[2] = cp[1];      /* move address/control up */
  823.             cp[1] = cp[0];
  824.         }
  825.         ++m->m_data;
  826.         --m->m_len;
  827.     }
  828.     return m;
  829. }
  830. /*
  831.  * This gets called from pppoutput when a new packet is
  832.  * put on a queue.
  833.  */
  834. static int
  835. pppasyncstart(sc)
  836.     register struct ppp_softc *sc;
  837. {
  838.     semGive(&sc->sc_wrtsem);
  839.     return 1;
  840. }
  841. /* 
  842.  * Start output on interface.  Get another datagram
  843.  * to send from the interface queue and map it to
  844.  * the interface before starting output.
  845.  */
  846. void
  847. ppp_wrt_task(sc)
  848.     register struct ppp_softc *sc;
  849. {
  850.     register struct mbuf *m;
  851.     register int len;
  852.     register u_char *start, *stop, *cp;
  853.     int n, ndone, done;
  854.     struct mbuf *m2;
  855.     int count, fd;
  856.     char ch;
  857.     fd = sc->sc_fd;
  858.     for (;;) {
  859. semTake(&sc->sc_wrtsem, WAIT_FOREVER);
  860. taskSafe();
  861. for (;;) {
  862.             /*
  863.              * See if we have an existing packet partly sent.
  864.              * If not, get a new packet and start sending it.
  865.              * We take packets on the priority queue ahead of those
  866.              * on the normal queue.
  867.              */
  868.             m = sc->sc_outm;
  869.             if (m == NULL) {
  870.                 /*
  871.                  * Get another packet to be sent
  872.                  */
  873.                 m = ppp_dequeue(sc);
  874.                 if (m == NULL)
  875.                     break;
  876.                 /*
  877.                  * The extra PPP_FLAG will start up a new packet, and thus
  878.                  * will flush any accumulated garbage.  We do this whenever
  879.                  * the line may have been idle for some time.
  880.                  */
  881.         ioctl(fd, FIONWRITE, (int) &count);
  882.         if (count == 0) {
  883.     ++sc->sc_bytessent;
  884.     ch = PPP_FLAG;
  885.     (void) write(fd, &ch, 1);
  886.         }
  887.                 /* Calculate the FCS for the first mbuf's worth. */
  888.                 sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
  889.             }
  890.     for (;;) {
  891. start = mtod(m, u_char *);
  892. len = m->m_len;
  893. stop = start + len;
  894.         while (len > 0) {
  895.                     /*
  896.                      * Find out how many bytes in the string we can
  897.                      * handle without doing something special.
  898.                      */
  899.                     for (cp = start; cp < stop; cp++)
  900.                         if (ESCAPE_P(*cp))
  901.                             break;
  902.                     n = cp - start;
  903.     if (n) {
  904.                         int cc, nleft;
  905.                         for (nleft = n; nleft > 0; nleft -= cc) {
  906.                             if ((cc =  write(fd, (char *)start, n)) <= 0)
  907.                                 break;
  908.                             if (cc > nleft)
  909.                                 cc = nleft;
  910.                         }
  911.                         ndone = n - nleft;
  912.                         len -= ndone;
  913.                         start += ndone;
  914.                         sc->sc_bytessent += ndone;
  915.                         if (ndone < n)
  916.                             break;  /* packet doesn't fit */
  917.                     }
  918.     /*
  919.      * If there are characters left in the mbuf,
  920.      * the first one must be special..
  921.      * Put it out in a different form.
  922.      */
  923.     if (len) {
  924. ch = PPP_ESCAPE;
  925. if (write(fd, &ch, 1) != 1)
  926.     break;
  927.     
  928. ch = *start ^ PPP_TRANS;
  929. if (write(fd, &ch, 1) != 1)
  930.     break;
  931.     
  932. sc->sc_bytessent += 2;
  933. start++;
  934. len--;
  935.     }
  936.         }
  937.                 /*
  938.                  * If we didn't empty this mbuf, remember where we're up to.
  939.                  * If we emptied the last mbuf, try to add the FCS and closing
  940.                  * flag, and if we can't, leave sc_outm pointing to m, but with
  941.                  * m->m_len == 0, to remind us to output the FCS and flag later.
  942.                  */
  943.                 done = len == 0;
  944.                 if (done && m->m_next == NULL) {
  945.                     u_char *p;
  946.                     int c;
  947.                     u_char endseq[8];
  948.                     /*
  949.                      * We may have to escape the bytes in the FCS.
  950.                      */
  951.                     p = endseq;
  952.                     c = ~sc->sc_outfcs & 0xFF;
  953.                     if (ESCAPE_P(c)) {
  954.                         *p++ = PPP_ESCAPE;
  955.                         *p++ = c ^ PPP_TRANS;
  956.                     } else
  957.                         *p++ = c;
  958.                     c = (~sc->sc_outfcs >> 8) & 0xFF;
  959.                     if (ESCAPE_P(c)) {
  960.                         *p++ = PPP_ESCAPE;
  961.                         *p++ = c ^ PPP_TRANS;
  962.                     } else
  963.                         *p++ = c;
  964.                     *p++ = PPP_FLAG;
  965.                     /*
  966.                      * Try to output the FCS and flag.  If the bytes
  967.                      * don't all fit, back out.
  968.                      */
  969.                     write(fd, (char *)endseq, (int)p-(int)endseq);
  970.                 }
  971.                 if (!done) {
  972.     m->m_data = (caddr_t)start; 
  973.                     m->m_len = len;
  974.                     sc->sc_outm = m;
  975.                     break;         /* can't do any more at the moment */
  976.                 }
  977.                 /* Finished with this mbuf; free it and move on. */
  978.                 m2 = m_free (m);
  979.                 if (m2 == NULL)
  980.                     break;
  981.                 m = m2;
  982.                 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
  983.             }
  984.             /* Finished a packet */
  985.             sc->sc_outm = NULL;
  986.             sc->sc_bytessent++;     /* account for closing flag */
  987.             sc->sc_if.if_opackets++;
  988.     sc->sc_if.if_obytes = sc->sc_bytessent;
  989. }
  990. taskUnsafe();
  991.     }
  992. }
  993. /*
  994.  * Allocate enough mbuf to handle current MRU.
  995.  */
  996. static int
  997. pppgetm(sc)
  998.     register struct ppp_softc *sc;
  999. {
  1000.     struct mbuf *m, **mp;
  1001.     int len;
  1002.     int s;
  1003.     s = splimp();
  1004.     mp = &sc->sc_m;
  1005.     for (len = HDROFF + sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
  1006. if ((m = *mp) == NULL) {
  1007.     m = mHdrClGet (M_DONTWAIT, MT_DATA, len, FALSE);
  1008.     if (m == NULL)
  1009. break;
  1010.     *mp = m;
  1011. }
  1012. len -= M_DATASIZE(m);
  1013. mp = &m->m_next;
  1014.     }
  1015.     splx(s);
  1016.     return len <= 0;
  1017. }
  1018. /*
  1019.  * pppintr - PPP tty protocol hook routine
  1020.  */
  1021. static int
  1022. pppintr(unit, c)
  1023.     int unit;
  1024.     int c;
  1025. {
  1026.     register struct ppp_softc *sc = ppp_softc[unit];
  1027.     TY_DEV * pTyDev;
  1028.     RING_ID ringId;
  1029.     if (ppp_softc[unit] == NULL)
  1030.         return FALSE;
  1031.     /* Set discard flag if this is a new packet and ring buffer full */
  1032.     if ( sc->sc_qlen == 0 )
  1033.     {
  1034.         pTyDev = (TY_DEV *) iosFdDevFind(sc->sc_fd);
  1035.         ringId = pTyDev->rdBuf;
  1036.         if (rngIsFull (ringId))
  1037.             sc->sc_flags |= SC_DISCARD_PKT;
  1038.         else
  1039.             sc->sc_flags &= ~SC_DISCARD_PKT;
  1040.     }
  1041.     ++sc->sc_qlen;
  1042.     if (sc->sc_qlen > PPPBUFSIZE)
  1043.         {
  1044.         netJobAdd((FUNCPTR) ppp_tty_read, (int)unit, (int) sc,
  1045.                   (int) sc->sc_qlen, 0, 0);
  1046.         sc->sc_qlen = 0;
  1047.         return (FALSE);
  1048.         }
  1049.      
  1050.     if (((ppp_if[unit]->lcp_fsm.state) != OPENED) && ((c & 0xff) == 'T'))
  1051.         {
  1052.         netJobAdd((FUNCPTR) ppp_tty_read, (int)unit, (int) sc,
  1053.                   (int) sc->sc_qlen, 0, 0);
  1054.         return (FALSE);
  1055.         }
  1056.     if ((c & 0xff) == PPP_FLAG) 
  1057.         {
  1058.         netJobAdd((FUNCPTR) ppp_tty_read, (int)unit, (int) sc, 
  1059.                       (int) sc->sc_qlen, 0, 0);
  1060.         sc->sc_qlen = 0;
  1061.         }
  1062.     return (FALSE);
  1063. }
  1064. /*
  1065.  * ppp_tty_read - read from ppp tty interface
  1066.  */
  1067. static void
  1068. ppp_tty_read(unit, sc, count)
  1069.     int unit;
  1070.     register struct ppp_softc *sc;
  1071.     register int count;
  1072. {
  1073.     register int i;
  1074.     register int num;
  1075.     char buf[PPPBUFSIZE + 2];
  1076.     /* count should never be greater than PPPBUFSIZE+1 */
  1077.     num = read(sc->sc_fd, buf, count);
  1078.     if (count > PPPBUFSIZE)
  1079.        {
  1080.        /* The received packet is greater than the MTU - Drop the packet */
  1081.        sc->sc_if.if_ierrors++;
  1082.        return;
  1083.        }
  1084.     if ((ppp_if[unit]->lcp_fsm.state) != OPENED)
  1085.         {
  1086.         if (strncmp("CLIENT", buf, strlen("CLIENT") )==0)
  1087.            {
  1088.            sc->sc_qlen = 0;
  1089.            write(sc->sc_fd, "CLIENTSERVER", strlen("CLIENTSERVER"));
  1090.            return;
  1091.            }
  1092.         }
  1093.     if (sc->sc_flags & SC_DISCARD_PKT)
  1094.         {
  1095.         /* Packet discarded */
  1096.         sc->sc_if.if_ierrors++;
  1097.         sc->sc_flags &= ~SC_DISCARD_PKT;
  1098.         return;
  1099.         }
  1100.     for (i = 0; i < num; i++)
  1101.         pppinput(sc, buf[i]);
  1102. }
  1103. /*
  1104.  * PPP packet input routine.
  1105.  * The caller has checked and removed the FCS.
  1106.  * The return value is 1 if the packet was put on sc->sc_inq,
  1107.  * 0 otherwise.
  1108.  */
  1109. #define COMPTYPE(proto) ((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: 
  1110.                          TYPE_UNCOMPRESSED_TCP)
  1111. /*******************************************************************************
  1112. * ppppktin - pass the packet to the appropriate stack LCP or IP
  1113. * This routine determines packet type and queues the mbuf to the appropriate
  1114. * queue. This routine returns a value of 1 if the packet type is other than
  1115. * PPP_IP.
  1116. *
  1117. * NOMANUAL
  1118. *
  1119. * RETURNS: 0/1
  1120. */
  1121. static int
  1122. ppppktin(sc, m)
  1123.     struct ppp_softc *sc;
  1124.     struct mbuf *m;
  1125. {
  1126.     struct ifqueue *inq;
  1127.     int s, ilen, xlen, proto, rv;
  1128.     u_char *cp, adrs, ctrl;
  1129.     struct mbuf *mp;
  1130.     char buf[PPPBUFSIZE];
  1131.     sc->sc_if.if_ipackets++;
  1132.     sc->sc_if.if_lastchange = tickGet ();  /* record the last change */
  1133.     rv = 0;
  1134.     cp = mtod(m, u_char *);
  1135.     adrs = cp[0];
  1136.     ctrl = cp[1];
  1137.     proto = (cp[2] << 8) + cp[3];
  1138.     ilen = 0;
  1139.     for (mp = m; mp != NULL; mp = mp->m_next)
  1140. ilen += mp->m_len;
  1141. #ifdef VJC
  1142.     /*
  1143.      * See if we have a VJ-compressed packet to uncompress.
  1144.      */
  1145.     if (proto == PPP_VJC_COMP || proto == PPP_VJC_UNCOMP) {
  1146. char *pkttype = proto == PPP_VJC_COMP? "": "un";
  1147. if (sc->sc_flags & SC_REJ_COMP_TCP) {
  1148.     if (sc->sc_flags & SC_DEBUG)
  1149. printf("ppp%d: %scomp pkt w/o compression; flags 0x%xn",
  1150. sc->sc_if.if_unit, pkttype, sc->sc_flags);
  1151.     m_freem(m);
  1152.     sc->sc_if.if_ierrors++;
  1153.     return 0;
  1154. }
  1155. if (proto == PPP_VJC_COMP && m->m_data - M_DATASTART(m) < MAX_HDR) {
  1156.     /*
  1157.      * We don't have room in the mbuf to decompress this packet.
  1158.      * XXX For now we just drop the packet.
  1159.      */
  1160.     if (sc->sc_flags & SC_DEBUG)
  1161. printf("ppp%d: no room to VJ-decompress packetn",
  1162.        sc->sc_if.if_unit);
  1163.     m_freem(m);
  1164.     sc->sc_if.if_ierrors++;
  1165.     return 0;
  1166. }
  1167. m->m_data += PPP_HDRLEN;
  1168. m->m_len -= PPP_HDRLEN;
  1169. ilen -= PPP_HDRLEN;
  1170. xlen = sl_uncompress_tcp((u_char **)(&m->m_data), m->m_len,
  1171.   COMPTYPE(proto), &sc->sc_comp);
  1172. if (xlen == 0) {
  1173.     if (sc->sc_flags & SC_DEBUG)
  1174. printf("ppp%d: sl_uncompress failed on type %scompn",
  1175. sc->sc_if.if_unit, pkttype);
  1176.     m_freem(m);
  1177.     sc->sc_if.if_ierrors++;
  1178.     return 0;
  1179. }
  1180. /* adjust the first mbuf by the decompressed amt */
  1181. xlen += PPP_HDRLEN;
  1182. m->m_len += xlen - ilen;
  1183. ilen = xlen;
  1184. m->m_data -= PPP_HDRLEN;
  1185. proto = PPP_IP;
  1186. /* put the ppp header back in place */
  1187. if (cp != mtod(m, u_char *)) {
  1188.     cp = mtod(m, u_char *);
  1189.     cp[0] = adrs;
  1190.     cp[1] = ctrl;
  1191.     cp[2] = 0;
  1192. }
  1193. cp[3] = PPP_IP;
  1194.     }
  1195. #endif /* VJC */
  1196.     /*
  1197.      * If the packet will fit in a header mbuf, don't waste a
  1198.      * whole cluster on it.
  1199.      */
  1200.     m->m_pkthdr.len = ilen;
  1201.     m->m_pkthdr.rcvif = &sc->sc_if;
  1202. #if NBPFILTER > 0
  1203.     /* See if bpf wants to look at the packet. */
  1204.     if (sc->sc_bpf)
  1205. bpf_mtap(sc->sc_bpf, m);
  1206. #endif
  1207.     
  1208.     /* call etherInputHookRtn here */
  1209.     if (etherInputHookRtn != NULL) {
  1210.         FAST char *p = (char *) buf;
  1211.  
  1212. for (mp = m; mp != NULL; p += mp->m_len, mp = mp->m_next)
  1213.     bcopy(mtod (mp, char *), p, mp->m_len);
  1214.  
  1215. if ((*etherInputHookRtn) (&sc->sc_if, buf, ilen) != 0)
  1216.     {
  1217.     m_freem (m);  /* free mbuf, not handed to the upperlayer */
  1218.     return (OK);
  1219.     }
  1220.     }
  1221.     switch (proto) {
  1222. #ifdef INET
  1223.     case PPP_IP:
  1224. /*
  1225.  * IP packet - take off the ppp header and pass it up to IP.
  1226.  */
  1227. if ((sc->sc_if.if_flags & IFF_UP) == 0
  1228.     || (sc->sc_flags & SC_ENABLE_IP) == 0) {
  1229.     /* interface is down - drop the packet. */
  1230.     m_freem(m);
  1231.     return 0;
  1232. }
  1233. m->m_pkthdr.len -= PPP_HDRLEN;
  1234. m->m_data += PPP_HDRLEN;
  1235. m->m_len -= PPP_HDRLEN;
  1236. inq = &ipintrq;
  1237. break;
  1238. #endif
  1239.     default:
  1240. /*
  1241.  * Some other protocol - place on input queue for read().
  1242.  */
  1243. inq = &sc->sc_inq;
  1244. rv = 1;
  1245. break;
  1246.     }
  1247.     /*
  1248.      * Put the packet on the appropriate input queue.
  1249.      */
  1250.     if (proto == PPP_IP)
  1251. {
  1252. sc->sc_iprcvd++;            /* incr ip packets received */
  1253. ipintr (m);
  1254. }
  1255.     else
  1256. {
  1257.         s = splimp();
  1258.         if (IF_QFULL(inq)) 
  1259.     {
  1260.     IF_DROP(inq);
  1261.     if (sc->sc_flags & SC_DEBUG)
  1262.     printf("ppp%d: queue fulln", sc->sc_if.if_unit);
  1263.     sc->sc_if.if_ierrors++;
  1264.     sc->sc_if.if_iqdrops++;
  1265.     m_freem(m);
  1266.     rv = 0;
  1267.             } 
  1268.         else
  1269.     {
  1270.             IF_ENQUEUE(inq, m);
  1271.     kill(sc->sc_tid, SIGIO);  /* give to alternate processing */
  1272.     }
  1273.         splx(s);
  1274. }
  1275.     return rv;
  1276. }
  1277. /*
  1278.  * tty interface receiver interrupt.
  1279.  */
  1280. static unsigned paritytab[8] = {
  1281.     0x96696996, 0x69969669, 0x69969669, 0x96696996,
  1282.     0x69969669, 0x96696996, 0x96696996, 0x69969669
  1283. };
  1284. static void
  1285. pppinput(sc, c)
  1286.     struct ppp_softc *sc;
  1287.     register int c;
  1288. {
  1289.     struct mbuf *m;
  1290.     int ilen;
  1291.     ++sc->sc_bytesrcvd;
  1292.     c &= 0xff;
  1293.     if (c & 0x80)
  1294. sc->sc_flags |= SC_RCV_B7_1;
  1295.     else
  1296. sc->sc_flags |= SC_RCV_B7_0;
  1297.     if (paritytab[c >> 5] & (1 << (c & 0x1F)))
  1298. sc->sc_flags |= SC_RCV_ODDP;
  1299.     else
  1300. sc->sc_flags |= SC_RCV_EVNP;
  1301.     if (sc->sc_flags & SC_LOG_RAWIN)
  1302. ppplogchar(sc, c);
  1303.     if (c == PPP_FLAG) {
  1304. ilen = sc->sc_ilen;
  1305. sc->sc_ilen = 0;
  1306. sc->sc_if.if_ibytes = sc->sc_bytesrcvd;
  1307. if (sc->sc_rawin_count > 0) 
  1308.     ppplogchar(sc, -1);
  1309. /*
  1310.  * If SC_ESCAPED is set, then we've seen the packet
  1311.  * abort sequence "}~".
  1312.  */
  1313. if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
  1314.     || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
  1315. #ifdef VJC
  1316.     /*
  1317.      * If we've missed a packet, we must toss subsequent compressed
  1318.      * packets which don't have an explicit connection ID.
  1319.      */
  1320.     sl_uncompress_tcp(NULL, 0, TYPE_ERROR, &sc->sc_comp);
  1321. #endif
  1322.     if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
  1323. if (sc->sc_flags & SC_DEBUG)
  1324.     printf("ppp%d: bad fcs %xn", sc->sc_if.if_unit,
  1325.    sc->sc_fcs);
  1326. sc->sc_if.if_ierrors++;
  1327.     } else
  1328. sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
  1329.     return;
  1330. }
  1331. if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
  1332.     if (ilen) {
  1333. if (sc->sc_flags & SC_DEBUG)
  1334.     printf("ppp%d: too short (%d)n", sc->sc_if.if_unit, ilen);
  1335. sc->sc_if.if_ierrors++;
  1336.     }
  1337.     return;
  1338. }
  1339. /*
  1340.  * Remove FCS trailer.  Somewhat painful...
  1341.  */
  1342. ilen -= 2;
  1343. if (--sc->sc_mc->m_len == 0) {
  1344.     for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
  1345. ;
  1346.     sc->sc_mc = m;
  1347. }
  1348. sc->sc_mc->m_len--;
  1349. /* excise this mbuf chain */
  1350. m = sc->sc_m;
  1351. sc->sc_m = sc->sc_mc->m_next;
  1352. sc->sc_mc->m_next = NULL;
  1353. if (sc->sc_flags & SC_LOG_INPKT) {
  1354.     printf("ppp%d: got %d bytesn", sc->sc_if.if_unit, ilen);
  1355.     pppdumpm(m, ilen);
  1356. }
  1357. ppppktin(sc, m);  /* handover packet to upper layer */
  1358. pppgetm(sc);
  1359. return;
  1360.     }
  1361.     if (sc->sc_flags & SC_FLUSH) {
  1362. if (sc->sc_flags & SC_LOG_FLUSH)
  1363.     ppplogchar(sc, c);
  1364. return;
  1365.     }
  1366.     if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
  1367. return;
  1368.     if (sc->sc_flags & SC_ESCAPED) {
  1369. sc->sc_flags &= ~SC_ESCAPED;
  1370. c ^= PPP_TRANS;
  1371.     } else if (c == PPP_ESCAPE) {
  1372. sc->sc_flags |= SC_ESCAPED;
  1373. return;
  1374.     }
  1375.     /*
  1376.      * Initialize buffer on first octet received.
  1377.      * First octet could be address or protocol (when compressing
  1378.      * address/control).
  1379.      * Second octet is control.
  1380.      * Third octet is first or second (when compressing protocol)
  1381.      * octet of protocol.
  1382.      * Fourth octet is second octet of protocol.
  1383.      */
  1384.     if (sc->sc_ilen == 0) {
  1385. /* reset the first input mbuf */
  1386. if (sc->sc_m == NULL) {
  1387.     pppgetm(sc);
  1388.     if (sc->sc_m == NULL) {
  1389. if (sc->sc_flags & SC_DEBUG)
  1390.     printf("ppp%d: no input mbufs!n", sc->sc_if.if_unit);
  1391. goto flush;
  1392.     }
  1393. }
  1394. m = sc->sc_m;
  1395. m->m_len = 0;
  1396. m->m_data = M_DATASTART(sc->sc_m);
  1397. if (M_DATASIZE(sc->sc_m) >= HDROFF + PPP_HDRLEN)
  1398.     m->m_data += HDROFF; /* allow room for VJ decompression */
  1399. sc->sc_mc = m;
  1400. sc->sc_mp = mtod(m, char *);
  1401. sc->sc_fcs = PPP_INITFCS;
  1402. if (c != PPP_ALLSTATIONS) {
  1403.     if (sc->sc_flags & SC_REJ_COMP_AC) {
  1404. if (sc->sc_flags & SC_DEBUG)
  1405.     printf("ppp%d: garbage received: 0x%x (need 0xFF)n",
  1406.    sc->sc_if.if_unit, c);
  1407. goto flush;
  1408.     }
  1409.     *sc->sc_mp++ = PPP_ALLSTATIONS;
  1410.     *sc->sc_mp++ = PPP_UI;
  1411.     sc->sc_ilen += 2;
  1412.     m->m_len += 2;
  1413. }
  1414.     }
  1415.     if (sc->sc_ilen == 1 && c != PPP_UI) {
  1416. if (sc->sc_flags & SC_DEBUG)
  1417.     printf("ppp%d: missing UI (0x3), got 0x%xn",
  1418.    sc->sc_if.if_unit, c);
  1419. goto flush;
  1420.     }
  1421.     if (sc->sc_ilen == 2 && (c & 1) == 1) {
  1422. /* a compressed protocol */
  1423. *sc->sc_mp++ = 0;
  1424. sc->sc_ilen++;
  1425. sc->sc_mc->m_len++;
  1426.     }
  1427.     if (sc->sc_ilen == 3 && (c & 1) == 0) {
  1428. if (sc->sc_flags & SC_DEBUG)
  1429.     printf("ppp%d: bad protocol %xn", sc->sc_if.if_unit,
  1430.    (sc->sc_mp[-1] << 8) + c);
  1431. goto flush;
  1432.     }
  1433.     /* packet beyond configured mru? */
  1434.     if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
  1435. if (sc->sc_flags & SC_DEBUG)
  1436.     printf("ppp%d: packet too bign", sc->sc_if.if_unit);
  1437. goto flush;
  1438.     }
  1439.     /* is this mbuf full? */
  1440.     m = sc->sc_mc;
  1441.     if (M_TRAILINGSPACE(m) <= 0) {
  1442. if (m->m_next == NULL) {
  1443.     pppgetm(sc);
  1444.     if (m->m_next == NULL) {
  1445. if (sc->sc_flags & SC_DEBUG)
  1446.     printf("ppp%d: too few input mbufs!n", sc->sc_if.if_unit);
  1447. goto flush;
  1448.     }
  1449. }
  1450. sc->sc_mc = m = m->m_next;
  1451. m->m_len = 0;
  1452. m->m_data = M_DATASTART(m);
  1453. sc->sc_mp = mtod(m, char *);
  1454.     }
  1455.     ++m->m_len;
  1456.     *sc->sc_mp++ = c;
  1457.     sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
  1458.     return;
  1459.  flush:
  1460.     if (!(sc->sc_flags & SC_FLUSH)) {
  1461. sc->sc_if.if_ierrors++;
  1462. sc->sc_flags |= SC_FLUSH;
  1463. if (sc->sc_flags & SC_LOG_FLUSH)
  1464.     ppplogchar(sc, c);
  1465.     }
  1466. }
  1467. /*
  1468.  * Process an ioctl request to interface.
  1469.  */
  1470. static int
  1471. pppioctl(ifp, cmd, data)
  1472.     register struct ifnet *ifp;
  1473.     int cmd;
  1474.     caddr_t data;
  1475. {
  1476.     register struct ppp_softc *sc = ppp_softc[ifp->if_unit];
  1477.     register struct ifaddr *ifa = (struct ifaddr *)data;
  1478.     register struct ifreq *ifr = (struct ifreq *)data;
  1479.     register M2_NETDRVCNFG *pm2DrvCnfg = (M2_NETDRVCNFG *)data;
  1480.     register M2_NETDRVCNTRS *pm2DrvCntr = (M2_NETDRVCNTRS *)data;
  1481.     int s = splimp(), error = 0;
  1482.     switch (cmd) {
  1483.     case SIOCGIFFLAGS:
  1484.         *(short *)data = ifp->if_flags;
  1485.          break;
  1486.     case SIOCSIFFLAGS:
  1487. if ((ifp->if_flags & IFF_RUNNING) == 0)
  1488.     ifp->if_flags &= ~IFF_UP;
  1489. break;
  1490.     case SIOCSIFADDR:
  1491. if (ifa->ifa_addr->sa_family != AF_INET)
  1492.     error = EAFNOSUPPORT;
  1493. break;
  1494.     case SIOCSIFDSTADDR:
  1495. if (ifa->ifa_dstaddr->sa_family != AF_INET)
  1496.     error = EAFNOSUPPORT;
  1497. break;
  1498.     case SIOCSIFMTU:
  1499. sc->sc_if.if_mtu = ifr->ifr_mtu;
  1500. break;
  1501.     case SIOCGIFMTU:
  1502. ifr->ifr_mtu = sc->sc_if.if_mtu;
  1503. break;
  1504.     case SIOCADDMULTI:
  1505.     case SIOCDELMULTI:
  1506.         if (ifr == 0) {
  1507.             error = EAFNOSUPPORT;
  1508.             break;
  1509.         }
  1510.         switch(ifr->ifr_addr.sa_family) {
  1511. #ifdef INET
  1512.         case AF_INET:
  1513.             break;
  1514. #endif
  1515.         default:
  1516.             error = EAFNOSUPPORT;
  1517.             break;
  1518.         }
  1519.         break;
  1520.     case SIOCGMIB2CNFG:
  1521.         pm2DrvCnfg->ifType = M2_ifType_ppp; /* ppp type */
  1522.         pm2DrvCnfg->ifSpecific.idLength = 0; /* use default */
  1523. break;
  1524.     case SIOCGMIB2CNTRS: /* fill in counters */
  1525. pm2DrvCntr->ifInOctets = sc->sc_bytesrcvd;
  1526.         pm2DrvCntr->ifInNUcastPkts = 0;
  1527.         pm2DrvCntr->ifInDiscards = 0;
  1528.         pm2DrvCntr->ifInUnknownProtos = ppp_if[ppp_unit]->unknownProto;
  1529. pm2DrvCntr->ifOutOctets = sc->sc_bytessent;
  1530.         pm2DrvCntr->ifOutNUcastPkts = 0;
  1531.         pm2DrvCntr->ifOutDiscards = 0;
  1532. if ((pm2DrvCntr->ifSpeed = ppp_if[ppp_unit]->baud_rate) == 0)
  1533.     pm2DrvCntr->ifSpeed = 9600; /* nominal default */
  1534. break;
  1535.     default:
  1536. error = EINVAL;
  1537.     }
  1538.     splx(s);
  1539.     return (error);
  1540. }
  1541. #define MAX_DUMP_BYTES 128
  1542. static void
  1543. pppdumpm(m0, pktlen)
  1544.     struct mbuf *m0;
  1545.     int pktlen;
  1546. {
  1547.     char buf [3*MAX_DUMP_BYTES+4];
  1548.     char *bp = buf;
  1549.     struct mbuf *m;
  1550.     static char digits [] = "0123456789abcdef";
  1551.     for (m = m0; m && pktlen; m = m->m_next) {
  1552. int l = m->m_len;
  1553. u_char *rptr = mtod(m, u_char *);
  1554.         if (pktlen > 0) {
  1555.             if (l > pktlen)
  1556.                 l = pktlen;
  1557.     pktlen -= l;
  1558. }
  1559.         while (l--) {
  1560.             if (bp > buf + sizeof(buf) - 4)
  1561.                 goto done;
  1562.             *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
  1563.             *bp++ = digits[*rptr++ & 0xf];
  1564.         }
  1565.         if (m->m_next) {
  1566.             if (bp > buf + sizeof(buf) - 3)
  1567.                 goto done;
  1568.             *bp++ = '|';
  1569.         } else
  1570.             *bp++ = ' ';
  1571.     }
  1572. done:
  1573.     if (m && pktlen)
  1574.         *bp++ = '>';
  1575.     *bp = 0;
  1576.     printf("%sn", buf);
  1577. }
  1578. static void
  1579. ppplogchar(sc, c)
  1580.     struct ppp_softc *sc;
  1581.     int c;
  1582. {
  1583.     if (c >= 0)
  1584.         sc->sc_rawin[sc->sc_rawin_count++] = c;
  1585.     if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
  1586.         || (c < 0 && sc->sc_rawin_count > 0)) {
  1587.         printf("ppp%d input: ", sc->sc_if.if_unit);
  1588.         pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
  1589.         sc->sc_rawin_count = 0;
  1590.     }
  1591. }
  1592. static void
  1593. pppdumpb(b, l)
  1594.     u_char *b;
  1595.     int l;
  1596. {
  1597.     char buf [3*MAX_DUMP_BYTES+4];
  1598.     char *bp = buf;
  1599.     static char digits[] = "0123456789abcdef";
  1600.     while (l--) {
  1601. if (bp >= buf + sizeof (buf) - 3) {
  1602.     *bp++ = '>';
  1603.     break;
  1604. }
  1605. *bp++ = digits [*b >> 4]; /* convert byte to ascii hex */
  1606. *bp++ = digits [*b++ & 0xf];
  1607.         *bp++ = ' ';
  1608.     }
  1609.     *bp = 0;
  1610.     printf("%sn", buf);
  1611. }
  1612. /* 
  1613.  * Flush write output on the interface. 
  1614.  */
  1615. static void
  1616. ppp_wrt_flush(sc)
  1617.     register struct ppp_softc *sc;
  1618. {
  1619.     register struct mbuf *m;
  1620.     register int len;
  1621.     register u_char *start, *stop, *cp;
  1622.     int n, ndone, done;
  1623.     struct mbuf *m2;
  1624.     int count, fd;
  1625.     char ch;
  1626.     fd = sc->sc_fd;
  1627.     for (;;) {
  1628.         /*
  1629.          * See if we have an existing packet partly sent.
  1630.          * If not, get a new packet and start sending it.
  1631.          * We take packets on the priority queue ahead of those
  1632.          * on the normal queue.
  1633.          */
  1634.         m = sc->sc_outm;
  1635.         if (m == NULL) {
  1636.     /*
  1637.      * Get another packet to be sent
  1638.      */
  1639.     m = ppp_dequeue(sc);
  1640.     if (m == NULL)
  1641.         break;
  1642.     /*
  1643.      * The extra PPP_FLAG will start up a new packet, and thus
  1644.      * will flush any accumulated garbage.  We do this whenever
  1645.      * the line may have been idle for some time.
  1646.      */
  1647.     ioctl(fd, FIONWRITE, (int) &count);
  1648.     if (count == 0) {
  1649.         ++sc->sc_bytessent;
  1650.         ch = PPP_FLAG;
  1651.         (void) write(fd, &ch, 1);
  1652.     }
  1653.     /* Calculate the FCS for the first mbuf's worth. */
  1654.     sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
  1655.         }
  1656.         for (;;) {
  1657.     start = mtod(m, u_char *);
  1658.     len = m->m_len;
  1659.     stop = start + len;
  1660.     while (len > 0) {
  1661.         /*
  1662.          * Find out how many bytes in the string we can
  1663.          * handle without doing something special.
  1664.          */
  1665.         for (cp = start; cp < stop; cp++)
  1666.     if (ESCAPE_P(*cp))
  1667.         break;
  1668.         n = cp - start;
  1669.         if (n) {
  1670.     int cc, nleft;
  1671.     for (nleft = n; nleft > 0; nleft -= cc) {
  1672.         if ((cc =  write(fd, (char *)start, n)) <= 0)
  1673.     break;
  1674.         if (cc > nleft)
  1675.     cc = nleft;
  1676.     }
  1677.     ndone = n - nleft;
  1678.     len -= ndone;
  1679.     start += ndone;
  1680.     sc->sc_bytessent += ndone;
  1681.     if (ndone < n)
  1682.         break;  /* packet doesn't fit */
  1683.         }
  1684.         /*
  1685.          * If there are characters left in the mbuf,
  1686.          * the first one must be special..
  1687.          * Put it out in a different form.
  1688.          */
  1689.         if (len) {
  1690.     ch = PPP_ESCAPE;
  1691.     if (write(fd, &ch, 1) != 1)
  1692.         break;
  1693.     ch = *start ^ PPP_TRANS;
  1694.     if (write(fd, &ch, 1) != 1)
  1695.         break;
  1696.     sc->sc_bytessent += 2;
  1697.     start++;
  1698.     len--;
  1699.         }
  1700.     }
  1701.     /*
  1702.      * If we didn't empty this mbuf, remember where we're up to.
  1703.      * If we emptied the last mbuf, try to add the FCS and closing
  1704.      * flag, and if we can't, leave sc_outm pointing to m, but with
  1705.      * m->m_len == 0, to remind us to output the FCS and flag later.
  1706.      */
  1707.     done = len == 0;
  1708.     if (done && m->m_next == NULL) {
  1709.         u_char *p;
  1710.         int c;
  1711.         u_char endseq[8];
  1712.     
  1713.         /*
  1714.          * We may have to escape the bytes in the FCS.
  1715.          */
  1716.         p = endseq;
  1717.         c = ~sc->sc_outfcs & 0xFF;
  1718.         if (ESCAPE_P(c)) {
  1719.     *p++ = PPP_ESCAPE;
  1720.     *p++ = c ^ PPP_TRANS;
  1721.         } else
  1722.     *p++ = c;
  1723.         c = (~sc->sc_outfcs >> 8) & 0xFF;
  1724.         if (ESCAPE_P(c)) {
  1725.     *p++ = PPP_ESCAPE;
  1726.     *p++ = c ^ PPP_TRANS;
  1727.         } else
  1728.     *p++ = c;
  1729.         *p++ = PPP_FLAG;
  1730.         /*
  1731.          * Try to output the FCS and flag.  If the bytes
  1732.          * don't all fit, back out.
  1733.          */
  1734.         write(fd, (char *)endseq, (int)p-(int)endseq);
  1735.     }
  1736.     if (!done) {
  1737.         m->m_data = (caddr_t)start; 
  1738.         m->m_len = len;
  1739.         sc->sc_outm = m;
  1740.         break;         /* can't do any more at the moment */
  1741.     }
  1742.     /* Finished with this mbuf; free it and move on. */
  1743.     m2 = m_free (m);
  1744.     if (m2 == NULL)
  1745.         break;
  1746.     m = m2;
  1747.     sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
  1748.         }
  1749.         /* Finished a packet */
  1750.         sc->sc_outm = NULL;
  1751.         sc->sc_bytessent++;     /* account for closing flag */
  1752.         sc->sc_if.if_opackets++;
  1753.     }
  1754. }
  1755. #endif  /* NPPP > 0 */