if_sl.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:44k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* if_sl.c - Serial Line IP (SLIP) network interface driver */
  2. /* Copyright 1989 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /* $NetBSD: if_sl.c,v 1.33 1994/12/11 21:39:05 mycroft Exp $ */
  5. /*
  6.  * Copyright (c) 1987, 1989, 1992, 1993
  7.  * The Regents of the University of California.  All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  * This product includes software developed by the University of
  20.  * California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  *
  37.  * @(#)if_sl.c 8.6 (Berkeley) 2/1/94
  38.  */
  39. /*
  40. modification history
  41. --------------------
  42. 02e,16may02,vvv  replaced schednetisr with direct call to ipintr;
  43.  fixed compilation warnings
  44. 02d,17oct00,spm  merged from version 02e of tor2_0_x branch (base version 02c):
  45.                  updated for new if_attach: reports memory allocation failures
  46. 02c,08may97,vin  switched the order of ifDstAddrSet and ifAddrSet, fixed
  47.  SIOCSIFDSTADDR in slioctl, SPR 8531, added slRtRequest().
  48. 02b,01aug97,jmb  Reduce number of slread netJobs by a factor of two
  49.  when FRAME_END character used to begin a new frame.
  50. 02a,16jul97,jmb  Added code to discard packets at interrupt level if
  51.  the input ring buffer is full.
  52. 01z,04dec96,vin  replaced MFREE with m_free (..)
  53. 01y,18jul96,vin  upgraded to BSD4.4, removed call to in_ifaddr_remove as it 
  54.  is being done in if_dettach now. 
  55. 01x,07mar96,gnn  Added code to handle user selectable MTUs for the SLIP
  56.          link.  (SPR #4652)
  57. 01w,14mar95,dzb  make sure to flush the wrt task's queue on close (SPR #4111).
  58. 01v,13mar95,dzb  added call to in_ifaddr_remove when deleting if (SPR #4109).
  59. 01u,13mar95,dzb  changed to use free() instead of cfree() (SPR #4113).
  60. 01t,24jan95,jdi  doc cleanup.
  61. 01s,08dec94,dzb  return ENOBUFS when dropping packet in sloutput() (SPR #3844).
  62. 01r,11nov94,dzb  added CSLIP enhancements.  decreased SLMTU size.  doc tweaks.
  63.  implemented buffer loaning, and removed extra data copies.
  64.  replaced calls to sl_btom() with copy_to_mbufs().
  65. 01q,22apr93,caf  ansification: added cast to ioctl() parameter.
  66. 01p,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  67. 01o,19feb93,jdi  documentation cleanup.
  68. 01n,22sep92,gae  documentation tweaks.
  69. 01m,18jul92,smb  Changed errno.h to errnoLib.h.
  70. 01l,26may92,rrr  the tree shuffle
  71.   -changed includes to have absolute path from h/
  72. 01k,07nov91,jpb  made slipWrtTask global for task TCB "ENTRY" status.
  73. 01j,04oct91,rrr  passed through the ansification filter
  74.                   -changed functions to ansi style
  75.   -changed includes to have absolute path from h/
  76.   -changed VOID to void
  77.   -changed copyright notice
  78. 01i,10apr91,jdi  documentation cleanup; removed stray close-quote in example;
  79.  doc review by elh.
  80. 01h,10aug90,dnw  corrected forward declarations for void functions.
  81. 01g,26jun90,hjb  SLBUFSIZE increased to fix a bug in ESC handling.
  82. 01f,26jun90,jcf  changed semaphore initialization to 5.0.
  83. 01e,07may90,hjb  changed MIN,MAX to min,max; de-linted.
  84. 01d,19apr90,hjb  deleted param.h, de-linted.
  85. 01c,20mar90,jcf  changed semaphores to binary.
  86. 01b,18mar90,hjb  minor cleanup.
  87. 01a,11apr89,hjb  first vxWorks version.
  88. */
  89. /*
  90. DESCRIPTION
  91. This module implements the VxWorks Serial Line IP (SLIP) network 
  92. interface driver.  Support for compressed TCP/IP headers (CSLIP) is included.
  93. The SLIP driver enables VxWorks to talk to other machines over serial
  94. connections by encapsulating IP packets into streams of bytes suitable
  95. for serial transmission.
  96. USER-CALLABLE ROUTINES
  97. SLIP devices are initialized using slipInit().  Its parameters specify 
  98. the Internet address for both sides of the SLIP point-to-point link,
  99. the name of the tty device on the local host, and options to enable CSLIP
  100. header compression.  The slipInit() routine calls slattach() to attach the
  101. SLIP interface to the network.  The slipDelete() routine deletes a specified
  102. SLIP interface.
  103. LINK-LEVEL PROTOCOL
  104. SLIP is a simple protocol that uses four token characters
  105. to delimit each packet:
  106.     - END (0300)
  107.     - ESC (0333)
  108.     - TRANS_END (0334)
  109.     - TRANS_ESC (0335)
  110. The END character denotes the end of an IP packet.  The ESC character is used
  111. with TRANS_END and TRANS_ESC to circumvent potential occurrences of END or ESC
  112. within a packet.  If the END character is to be embedded, SLIP sends 
  113. "ESC TRANS_END" to avoid confusion between a SLIP-specific END and actual
  114. data whose value is END.  If the ESC character is to be embedded, then
  115. SLIP sends "ESC TRANS_ESC" to avoid confusion.  (Note that the SLIP ESC is
  116. not the same as the ASCII ESC.)
  117. On the receiving side of the connection, SLIP uses the opposite actions to
  118. decode the SLIP packets.  Whenever an END character is received, SLIP
  119. assumes a full IP packet has been received and sends it up to the IP layer.
  120. TARGET-SPECIFIC PARAMETERS
  121. The global flag slipLoopBack is set to 1 by default. This flag enables
  122. the packets to be sent to the loopback interface if they are destined to
  123. to a local slip interface address. By setting this flag, any packets
  124. sent to a local slip interface address will not be seen on the actual serial
  125. link. Set this flag to 0 to turn off this facility. If this flag is not set
  126. any packets sent to the local slip interface address will actually be sent
  127. out on the link and it is the peer's responsibility to loop the packet back.
  128. IMPLEMENTATION
  129. The write side of a SLIP connection is an independent task.  Each SLIP
  130. interface has its own output task that sends SLIP packets over a
  131. particular tty device channel.  Whenever a packet is ready to be sent out,
  132. the SLIP driver activates this task by giving a semaphore.  When the
  133. semaphore is available, the output task performs packetization
  134. (as explained above) and writes the packet to the tty device.
  135. The receiving side is implemented as a "hook" into the tty driver.  A tty
  136. ioctl() request, FIOPROTOHOOK, informs the tty driver to call the SLIP
  137. interrupt routine every time a character is received from a serial port.
  138. By tracking the number of characters and watching for the END character,
  139. the number of calls to read() and context switching time have been
  140. reduced.  The SLIP interrupt routine will queue a call to the SLIP read
  141. routine only when it knows that a packet is ready in the tty driver's ring
  142. buffer.  The SLIP read routine will read a whole SLIP packet at a time and
  143. process it according to the SLIP framing rules.  When a full IP packet is
  144. decoded out of a SLIP packet, it is queued to IP's input queue.
  145. CSLIP compression is implemented to decrease the size of the TCP/IP
  146. header information, thereby improving the data to header size ratio.
  147. CSLIP manipulates header information just before a
  148. packet is sent and just after a packet is received.  Only TCP/IP 
  149. headers are compressed and uncompressed; other protocol types are
  150. sent and received normally.  A functioning CSLIP driver is required
  151. on the peer (destination) end of the physical link in order to carry
  152. out a CSLIP "conversation."
  153. Multiple units are supported by this driver.  Each individual unit may
  154. have CSLIP support disabled or enabled, independent of the state of
  155. other units.
  156. INTERNAL
  157. The write side of a SLIP connection is an independent task.  Each SLIP
  158. interface will have its own output task that will send SLIP packets over a
  159. particular tty device channel.  Whenever a packet is ready to be sent out,
  160. sloutput() will activate this task by giving a semaphore.  When the
  161. semaphore is available, the output task will perform packetization
  162. (as explained above) and write the packet to the tty device.
  163. The receiving side is implemented as a "hook" into the tty driver.  A tty
  164. ioctl() request, FIOPROTOHOOK, informs the tty driver to call slintr() every
  165. time a character is received from a serial port.  By tracking the number
  166. of characters and watching for the END character, the number of calls to
  167. read() and context switching time have been reduced.  The slintr() routine
  168. will queue a call to slread() only when it knows that a packet is ready in
  169. the tty driver's ring buffer.  slread() will read a whole SLIP packet at a
  170. time and process it according to the SLIP framing rules.  When a full IP
  171. packet is decoded out of a SLIP packet, it is enqueued to IP's input queue.
  172. The CSLIP compressed header format is only implemented for TCP/IP packets.
  173. The slcompress.c:sl_compress_tcp routine is called from sloutput() to
  174. compress the header while the outgoing packet is still in an mbuf chain.
  175. The slcompress.c:sl_uncompress_tcp routine is called from slRecv() to
  176. uncompress the header before the packet is copied to an mbuf chain (i.e.,
  177. the incoming packet is in a contiguous buffer).
  178. The CSLIP header's first octet contains the packet type (top 3 bits), TCP
  179. 'push' bit, and flags that indicate which of the 4 TCP sequence
  180. numbers have changed (bottom 5 bits).  The next octet is a
  181. conversation number that associates a saved IP/TCP header with
  182. the compressed packet.  The next two octets are the TCP checksum
  183. from the original datagram.  The next 0 to 15 octets are
  184. sequence number changes, one change per bit set in the header
  185. (there may be no changes and there are two special cases where
  186. the receiver implicitly knows what changed).
  187. There are 5 numbers which can change (they are always inserted
  188. in the following order): TCP urgent pointer, window,
  189. acknowlegement, sequence number and IP ID.  (The urgent pointer
  190. is different from the others in that its value is sent, not the
  191. change in value.)  Since typical use of SLIP links is biased
  192. toward small packets, changes use a variable length coding with
  193. one octet for numbers in the range 1 - 255 and 3 octets (0, MSB,
  194. LSB) for numbers in the range 256 - 65535 or 0.  (If the change
  195. in sequence number or ack is more than 65535, an uncompressed
  196. packet is sent.)
  197. BOARD LAYOUT
  198. No hardware is directly associated with this driver; therefore, a jumpering
  199. diagram is not applicable.
  200. SEE ALSO
  201. ifLib, tyLib,
  202. John Romkey: RFC-1055,
  203. .I "A Nonstandard for Transmission of IP Datagrams Over Serial Lines: SLIP,"
  204. Van Jacobson: RFC-1144, entitled
  205. .I "Compressing TCP/IP Headers for Low-Speed Serial Links"
  206. ACKNOWLEDGEMENT
  207. This program is based on original work done by Rick Adams of The Center for
  208. Seismic Studies and Chris Torek of The University of Maryland.
  209. The CSLIP enhancements are based on work done by Van Jacobson of
  210. University of California, Berkeley for the "cslip-2.7" release.
  211. INTERNAL
  212. .CS
  213.         slipInit   sloutput    slipDelete   slipBaudSet   slintr   slioctl
  214.            /          |              |                     |
  215.           /           |semaphore     |                     |
  216.          /            |              |                     |
  217.         /             |--|           |                     |
  218.  slattach slipWrtTask <-  |           |                   slread
  219.       |                   |           |                     |
  220.       |          sl_compress_tcp      |  sl_uncompress_tcp  |
  221.       |                               |         |           |
  222.   slSoftcFree <-----------------------+         ---------slRecv
  223. .CE
  224. */
  225. /* includes */
  226. #include "vxWorks.h"
  227. #include "sys/socket.h"
  228. #include "sys/ioctl.h"
  229. #include "stdio.h"
  230. #include "errnoLib.h"
  231. #include "ioLib.h"
  232. #include "semLib.h"
  233. #include "memLib.h"
  234. #include "taskLib.h"
  235. #include "tickLib.h"
  236. #include "logLib.h"
  237. #include "ifLib.h"
  238. #include "routeLib.h"
  239. #include "netLib.h"
  240. #include "etherLib.h"
  241. #include "net/if.h"
  242. #include "net/if_types.h"
  243. #include "net/if_subr.h"
  244. #include "net/route.h"
  245. #include "net/mbuf.h"
  246. #include "net/unixLib.h"
  247. #include "netinet/in.h"
  248. #include "netinet/in_systm.h"
  249. #include "netinet/in_var.h"
  250. #include "netinet/ip.h"
  251. #include "netinet/ip_var.h"
  252. #include "netinet/sl_compress.h"
  253. #include "if_sl.h"
  254. #include "drv/netif/netifDev.h"
  255. #include "rngLib.h"
  256. #include "tyLib.h"
  257. /* defines */
  258. /*
  259.  * SLMTU is now a hard limit on input packet size.  SLMTU must be <= MCLBYTES
  260.  * to take advantage of buffer loaning.  Additionally, it has been shown
  261.  * that a smaller MTU works well with SLIP, so that echo traffic does
  262.  * not have to wait for larger, bulk data packets.  With an MTU that is
  263.  * 10 to 20 times that TCP/IP header, a reasonable line efficiency is
  264.  * achieved.  For SLIP, this dictates an MTU of 400 to 800 bytes.
  265.  * CSLIP could do well with an MTU as low as 100 to 400 bytes.
  266.  */
  267. #define SLMTU 576 /* max Tx/Rx size in bytes */
  268. #define L_POOL 6 /* Rx loaner buffer pool */
  269. #define NSLIP 20 /* max. number of SLIP interfaces */
  270. #define SLBUF_OFF (sizeof(struct ifnet *) + 128)
  271. #define SLBUF_HI ((SLMTU*2) - 1) /* Rx character threshold */
  272. #define SLBUFSIZE ((SLMTU*2) + SLBUF_OFF)
  273.                                         /* leave room for CSLIP uncompress */
  274. /* SLIP protocol characters */
  275. #define FRAME_END   0300 /* Frame End */
  276. #define FRAME_ESCAPE 0333 /* Frame Esc */
  277. #define TRANS_FRAME_END   0334 /* transposed frame end */
  278. #define TRANS_FRAME_ESCAPE  0335 /* transposed frame esc */
  279. /* SLIP control flags */
  280. #define SL_COMPRESS 0x01 /* enable CSLIP compression */
  281. #define SL_COMPRESS_RX 0x02 /* enable compression on Rx of compress pkt */
  282. #define SL_INTR_PACKET_DISCARD 0x04  /* discard current packet at int. level */
  283. #define SIN(s) ((struct sockaddr_in *)s)
  284.     
  285. /* typedefs */
  286. typedef struct /* SL_SOFTC */
  287.     {
  288.     struct ifnet      sc_if; /* network-visible interface */
  289.     u_char            sc_flags; /* SLIP interface control flags */
  290.     short       sc_ilen; /* chars in current Rx packet */
  291.     short       sc_qlen; /* num of chars in tty input queue */
  292.     char *       sc_buf; /* input buffer */
  293.     char *            sc_orig; /* pointer to malloc'ed buffer space */
  294.     int         sc_fd; /* file descriptor for slip device */
  295.     SEM_ID       sc_wrtSem; /* write semaphore */
  296.     int       sc_wrtTaskId; /* write task ID */
  297.     struct slcompress sc_comp; /* TCP/IP compression info */
  298.     int       sc_nLoanRxBuf; /* number of Rx buffers left to loan */
  299.     char *            sc_lPool[L_POOL]; /* receive buffer loaner pool */
  300.     UINT8 *           sc_pRefC[L_POOL]; /* stack of reference count pointers */
  301.     UINT8       sc_refC[L_POOL]; /* actual reference count values */
  302.     } SL_SOFTC;
  303. /* globals */
  304. int slipTaskPriority = 55; /* netTask priority +5 */
  305. int slipTaskOptions = VX_SUPERVISOR_MODE | VX_UNBREAKABLE;
  306. int slipTaskStackSize = 2000;
  307. int slipLoopBack  = 1;
  308. IMPORT void if_dettach (struct ifnet *ifp);
  309. IMPORT void if_down (struct ifnet *ifp);
  310. IMPORT struct  ifqueue ipintrq; 
  311. IMPORT struct  ifnet loif;
  312. /* locals */
  313. LOCAL SL_SOFTC *sl_softc [NSLIP];
  314. /* forward declarations */
  315. STATUS slipDelete (); /* global for user access */
  316. void slipWrtTask (SL_SOFTC *sc); /* global for "ENTRY" status */
  317. STATUS slattach (int unit, int fd, BOOL compressEnable,
  318.   BOOL compressAllow, int mtu);
  319. /* static forward declarations */
  320. #ifdef __STDC__
  321. static void slSoftcFree (SL_SOFTC *sc, int unit);
  322. static void slinit (int unit);
  323. static STATUS sloutput (struct ifnet *ifp, struct mbuf *m,
  324.                         struct sockaddr* dst, struct rtentry * rtp);
  325. static BOOL slintr (int unit, int inchar);
  326. static void slread (SL_SOFTC *sc, int count);
  327. static char *slRecv (SL_SOFTC *sc, BOOL firstCluster);
  328. static int slioctl (struct ifnet *ifp, int cmd, caddr_t data);
  329. static int numCharsToMask (u_char mask1, u_char mask2, u_int size, u_char *cp);
  330. static void slLoanFree (SL_SOFTC *sc, char *pRxBuf, UINT8 *pRef);
  331. static void slRtRequest (int cmd, struct rtentry * pRtEntry,
  332.                          struct sockaddr * pSockAddr); 
  333. #else /* __STDC__ */
  334. static void slSoftcFree ();
  335. static void slinit ();
  336. static STATUS sloutput ();
  337. static BOOL slintr ();
  338. static void slread ();
  339. static char *slRecv ();
  340. static int slioctl ();
  341. static int numCharsToMask ();
  342. static void slLoanFree ();
  343. #endif /* __STDC__ */
  344. /*******************************************************************************
  345. *
  346. * slipInit - initialize a SLIP interface
  347. *
  348. * This routine initializes a SLIP device.  Its parameters specify the name
  349. * of the tty device, the Internet addresses of both sides of the SLIP
  350. * point-to-point link (i.e., the local and remote sides of the serial line
  351. * connection), and CSLIP options.
  352. *
  353. * The Internet address of the local side of the connection is specified in
  354. * <myAddr> and the name of its tty device is specified in <devName>.
  355. * The Internet address of the remote side is specified in <peerAddr>.
  356. * If <baud> is not zero, the baud rate will be the specified value;
  357. * otherwise, the default baud rate will be the rate set by the tty driver.
  358. * The <unit> parameter specifies the SLIP device unit number.  Up to twenty
  359. * units may be created.
  360. *
  361. * The CLSIP options parameters <compressEnable> and <compressAllow> determine
  362. * support for TCP/IP header compression.  If <compressAllow> is TRUE (1), then
  363. * CSLIP will be enabled only if a CSLIP type packet is received by this
  364. * device.  If <compressEnable> is TRUE (1), then CSLIP compression will be
  365. * enabled explicitly for all transmitted packets, and compressed packets
  366. * can be received.
  367. *
  368. * The MTU option parameter allows the setting of the MTU for the link.
  369. * For example, the following call initializes a SLIP device, using the
  370. * console's second port, where the Internet address of the local host is
  371. * 192.10.1.1 and the address of the remote host is 192.10.1.2.
  372. * The baud rate will be the default rate for /tyCo/1.  CLSIP is enabled
  373. * if a CSLIP type packet is received.  The MTU of the link is 1006.
  374. * .CS
  375. *     slipInit (0, "/tyCo/1", "192.10.1.1", "192.10.1.2", 0, 0, 1, 1006);
  376. * .CE
  377. *
  378. * RETURNS:
  379. * OK, or ERROR if the device cannot be opened, memory is insufficient,
  380. * or the route is invalid.
  381. */
  382. STATUS slipInit
  383.     (
  384.     int         unit,           /* SLIP device unit number (0 - 19) */
  385.     char        *devName,       /* name of the tty device to be initialized */
  386.     char        *myAddr,        /* address of the SLIP interface */
  387.     char        *peerAddr,      /* address of the remote peer SLIP interface */
  388.     int         baud,           /* baud rate of SLIP device: 0=don't set rate */
  389.     BOOL compressEnable, /* explicitly enable CSLIP compression */
  390.     BOOL compressAllow, /* enable CSLIP compression on Rx */
  391.     int mtu /* user set-able MTU */
  392.     )
  393.     {
  394.     SL_SOFTC *sc;
  395.     int  slipFd;
  396.     char  slipName [10];
  397.     char  slipWrtName [10];
  398.     /* check and see of unit is in valid range */
  399.     if (unit < 0 || unit >= NSLIP)
  400. {
  401. (void)errnoSet (S_if_sl_INVALID_UNIT_NUMBER);
  402. return (ERROR);
  403. }
  404.     if ((slipFd = open (devName, O_RDWR, 0)) == ERROR)
  405. return (ERROR);
  406.     /* set the baud rate only if the 'baud' is not equal to zero */
  407.     if (baud != 0 && ioctl (slipFd, FIOBAUDRATE, baud) == ERROR)
  408. {
  409. (void) close (slipFd);
  410. return (ERROR);
  411. }
  412.     if (mtu <= 0 || mtu > 2048)
  413. mtu = SLMTU;
  414.     /*
  415.      * Re-allocate big enough ring buffers for this tty device since
  416.      * the default ring buffer size of tty devices is 512 bytes, which
  417.      * may be smaller than SLMTU.  The ring buffers are 4 times
  418.      * the size of a maximum SLIP packet, for insurance.
  419.      */
  420.     if (ioctl (slipFd, FIORBUFSET, 4 * mtu) == ERROR ||
  421. ioctl (slipFd, FIOWBUFSET, 4 * mtu) == ERROR)
  422. {
  423. (void) close (slipFd);
  424. return (ERROR);
  425. }
  426.     if (slattach (unit, slipFd, compressEnable, compressAllow, mtu) == ERROR)
  427. {
  428. (void) close (slipFd);
  429. return (ERROR);
  430. }
  431.     sc = sl_softc [unit];
  432.     (void) sprintf (slipName, "sl%d", sc->sc_if.if_unit);
  433.     (void) sprintf (slipWrtName, "tSl%dWrt", sc->sc_if.if_unit);
  434.     /* Set own and peer's internet address.
  435.      * Add a routing table entry to tell how to loopback over SLIP.
  436.      * Point to point loopback routing table entry is required to
  437.      * properly talk to myself using the SLIP interface address.
  438.      */
  439.     if (ifDstAddrSet (slipName, peerAddr) == ERROR ||
  440.         ifAddrSet (slipName, myAddr) == ERROR ||
  441. routeAdd (myAddr, myAddr) == ERROR)
  442. {
  443. (void) close (slipFd);
  444. return (ERROR);
  445. }
  446.     /* start up the SLIP output task for this interface */
  447.     sc->sc_wrtTaskId = taskSpawn (slipWrtName, slipTaskPriority,
  448.                   slipTaskOptions, slipTaskStackSize,
  449.                   (FUNCPTR) slipWrtTask, (int) sc,
  450.   0, 0, 0, 0, 0, 0, 0, 0, 0);
  451.     if (sc->sc_wrtTaskId == ERROR)
  452. {
  453. (void) close (slipFd);
  454. return (ERROR);
  455. }
  456.     return (OK);
  457.     }
  458. /*******************************************************************************
  459. *
  460. * slipBaudSet - set the baud rate for a SLIP interface
  461. *
  462. * This routine adjusts the baud rate of a tty device attached to a SLIP
  463. * interface.  It provides a way to modify the baud rate of a tty
  464. * device being used as a SLIP interface.
  465. *
  466. * RETURNS: OK, or ERROR if the unit number is invalid or uninitialized.
  467. */
  468. STATUS slipBaudSet
  469.     (
  470.     int unit,           /* SLIP device unit number */
  471.     int baud            /* baud rate */
  472.     )
  473.     {
  474.     SL_SOFTC *sc;
  475.     /* check for valid unit number */
  476.     if (unit < 0 || unit >= NSLIP)
  477. {
  478. (void)errnoSet (S_if_sl_INVALID_UNIT_NUMBER);
  479. return (ERROR);
  480. }
  481.     /* make sure that the sl_softc for the 'unit' is initialized properly */
  482.     if ((sc = sl_softc [unit]) == NULL)
  483. {
  484. (void)errnoSet (S_if_sl_UNIT_UNINITIALIZED);
  485. return (ERROR);
  486. }
  487.     return (ioctl (sc->sc_fd, FIOBAUDRATE, baud));
  488.     }
  489. /*******************************************************************************
  490. *
  491. * slattach - publish the `sl' network interface and initialize the driver and device
  492. *
  493. * This routine publishes the `sl' interface by filling in a network interface
  494. * record and adding this record to the system list.  It also initializes
  495. * the driver and the device to the operational state.
  496. *
  497. * This routine is usually called by slipInit().
  498. *
  499. * RETURNS: OK or ERROR.
  500. */
  501. STATUS slattach
  502.     (
  503.     int unit, /* SLIP device unit number */
  504.     int fd, /* fd of tty device for SLIP interface */
  505.     BOOL compressEnable, /* explicitly enable CSLIP compression */
  506.     BOOL compressAllow, /* enable CSLIP compression on Rx */
  507.     int mtu /* user setable MTU */
  508.     )
  509.     {
  510.     SL_SOFTC *sc;
  511.     struct ifnet *ifp;
  512.     int ix;
  513.     if (sl_softc [unit] != NULL)
  514. {
  515. (void)errnoSet (S_if_sl_UNIT_ALREADY_INITIALIZED);
  516. return (ERROR);
  517. }
  518.     if ((sc = (SL_SOFTC *) calloc (1, sizeof (SL_SOFTC))) == (SL_SOFTC *) NULL)
  519. return (ERROR);
  520.     if (mtu <= 0 || mtu > 2048)
  521. mtu = SLMTU;
  522.     sl_softc [unit] = sc;
  523.     ifp = &sc->sc_if; /* get a pointer to ifnet structure */
  524.     ifp->if_name     = "sl";
  525.     ifp->if_unit     = unit;
  526.     ifp->if_mtu     = mtu;
  527.     ifp->if_flags     = IFF_POINTOPOINT | IFF_MULTICAST;
  528.     sc->sc_if.if_type     = IFT_SLIP;
  529.     ifp->if_ioctl     = slioctl;
  530.     ifp->if_init    = (FUNCPTR) slinit;
  531.     ifp->if_output     = sloutput;
  532.     ifp->if_reset     = slipDelete;
  533.     ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  534.     /* allocate SLIP input buffer space, including loaner buffers */
  535.     if ((sc->sc_orig = (char *) calloc (L_POOL, (u_int) SLBUFSIZE)) == NULL)
  536.         {
  537.         free ( (char *)sc);
  538.         return (ERROR);
  539.         }
  540.     /* attach SLIP to linked list of all interfaces */
  541.     if (if_attach (ifp) == ERROR)
  542.         {
  543.         free ( (char *)sc);
  544.         return (ERROR);
  545.         }
  546.     sc->sc_flags = 0;
  547.     sc->sc_ilen = 0;
  548.     sc->sc_qlen = 0;
  549.     sc->sc_nLoanRxBuf = L_POOL;
  550.     /* set CSLIP options in the SL_SOFTC flags */
  551.     if (compressEnable || compressAllow)
  552. {
  553.         sl_compress_init (&sc->sc_comp);
  554.         if (compressEnable)
  555.             sc->sc_flags |= SL_COMPRESS;
  556. else
  557.             sc->sc_flags |= SL_COMPRESS_RX;
  558.         }
  559.     sc->sc_buf = sc->sc_orig + SLBUF_OFF; /* leave space for uncompress */
  560.     /* assign loaner buffer addresses */
  561.     for (ix = 0; ix < L_POOL; ix++)
  562. {
  563. sc->sc_lPool[ix] = (sc->sc_buf + (ix * SLBUFSIZE));
  564. sc->sc_refC[ix]  = 0;
  565. sc->sc_pRefC[ix] = &sc->sc_refC[ix];
  566. }
  567.     if ((sc->sc_wrtSem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY)) == NULL)
  568. {
  569. slSoftcFree (sc, unit);
  570. return (ERROR);
  571. }
  572.     /*
  573.      * Make sure that the tty device described by 'fd' is
  574.      * indeed a tty device.
  575.      */
  576.     if (ioctl (fd, FIOISATTY, 0 /*XXX*/) == TRUE)
  577. sc->sc_fd = fd;
  578.     else
  579.         {
  580. slSoftcFree (sc, unit);
  581. return (ERROR);
  582.         }
  583.     /*
  584.      * call ioctl to,
  585.      *   FIOFLUSH     - flush out everything on this tty dev
  586.      *   FIOOPTIONS   - set the tty dev in RAW mode
  587.      *   FIOPROTOHOOK - specify the protocol interface hook routine for SLIP
  588.      *   FIOPROTOARG  - specify the SLIP unit number for this tty dev
  589.      */
  590.     if (ioctl (fd, FIOFLUSH, 0 /*XXX*/)        == ERROR ||
  591. ioctl (fd, FIOOPTIONS, OPT_RAW)        == ERROR ||
  592. ioctl (fd, FIOPROTOHOOK, (int) slintr) == ERROR ||
  593. ioctl (fd, FIOPROTOARG, unit)          == ERROR)
  594. {
  595. slSoftcFree (sc, unit);
  596. return (ERROR);
  597. }
  598.     return (OK);
  599.     }
  600. /*******************************************************************************
  601. *
  602. * slipDelete - delete a SLIP interface
  603. *
  604. * This routine resets a specified SLIP interface.  It detaches the tty from
  605. * the `sl' unit and deletes the specified SLIP interface from the list of
  606. * network interfaces.  For example, the following call will delete the first
  607. * SLIP interface from the list of network interfaces:
  608. * .CS
  609. *     slipDelete (0);
  610. * .CE
  611. *
  612. * RETURNS: OK, or ERROR if the unit number is invalid or uninitialized.
  613. */
  614. STATUS slipDelete
  615.     (
  616.     int unit                    /* SLIP unit number */
  617.     )
  618.     {
  619.     SL_SOFTC *sc;
  620.     struct mbuf *pMbuf;
  621.     int s;
  622.     if (unit >= 0 && unit < NSLIP)
  623.      sc = sl_softc [unit];
  624.     else
  625. {
  626. (void)errnoSet (S_if_sl_INVALID_UNIT_NUMBER);
  627.      return (ERROR);
  628. }
  629.     if (sc == NULL)
  630. {
  631. (void)errnoSet (S_if_sl_UNIT_UNINITIALIZED);
  632. return (ERROR);
  633. }
  634.     /* flush write side of the tty ringer buffer */
  635.     (void) ioctl (sc->sc_fd, FIOWFLUSH, 0 /*XXX*/);
  636.     (void) ioctl (sc->sc_fd, FIOPROTOHOOK, (int) NULL);
  637.     s = splimp (); /* paranoid; splnet probably ok */
  638.     if_down (&sc->sc_if); /* mark it down */
  639.     (void) close (sc->sc_fd); /* close the tty device */
  640.     for (;;) /* flush the wrt task queue and free mbufs */
  641. {
  642. IF_DEQUEUE (&sc->sc_if.if_snd, pMbuf);
  643. if (pMbuf == NULL)
  644.     break;
  645. m_freem (pMbuf);
  646. }
  647.     if (sc->sc_wrtTaskId != ERROR)
  648.         taskDelete (sc->sc_wrtTaskId);
  649.     /*
  650.      * Delete all routes associated with this SLIP interface.
  651.      * This will effectively delete the point-to-point routes for this SLIP.
  652.      */
  653.     (void) ifRouteDelete ("sl", unit);
  654.     slSoftcFree (sc, unit);
  655.     splx (s);
  656.     return (OK);
  657.     }
  658. /*******************************************************************************
  659. *
  660. * slSoftcFree - free the allocated sl_softc structure
  661. *
  662. * This is called by slattach to free the allocated sl_softc structure
  663. * when error occurs within slattach.  The reason for having this routine
  664. * is to get rid of the repetitive code within slattach ().
  665. * This routine is also called by slipDelete ().
  666. */
  667. LOCAL void slSoftcFree
  668.     (
  669.     SL_SOFTC *sc,
  670.     int       unit
  671.     )
  672.     {
  673.     /* Take the pointer to this SLIP interface out of the linked list
  674.      * of all available network interfaces.  The if_dettach () will un-do
  675.      * the action taken by if_attach ().
  676.      */
  677.     if_dettach (&sc->sc_if);
  678.     if (sc->sc_wrtSem)
  679.         semDelete (sc->sc_wrtSem); /* delete write semaphore */
  680.     if (sc->sc_buf)
  681. {
  682. (void) free (sc->sc_orig);
  683. sc->sc_buf = NULL;
  684. }
  685.     (void) free ((char *) sc);
  686.     sl_softc [unit] = (SL_SOFTC *) NULL;
  687.     }
  688. /*******************************************************************************
  689. *
  690. * slinit - initialize SLIP interface
  691. */
  692. LOCAL void slinit
  693.     (
  694.     int unit
  695.     )
  696.     {
  697.     SL_SOFTC *sc = sl_softc [unit];
  698.     sc->sc_if.if_flags |= IFF_UP|IFF_RUNNING; /* open for business */
  699.     }
  700. /*******************************************************************************
  701. *
  702. * sloutput - output a packet over the SLIP line
  703. *
  704. * Queue a packet and trigger the slipWrtTask if a packet is ready
  705. * by releasing the semaphore.  CSLIP compression for TCP/IP headers is
  706. * supported if (enabled).
  707. *
  708. * RETURNS: OK, or ERROR if the output queue is full.
  709. */
  710. LOCAL STATUS sloutput
  711.     (
  712.     FAST struct ifnet   *ifp,           /* SLIP interface pointer */
  713.     FAST struct mbuf    *m,             /* SLIP packet to be sent out */
  714.     struct sockaddr     *dst,           /* address of the destination */
  715.     struct rtentry *rtp /* pointer to the route entry */
  716.     )
  717.     {
  718.     FAST SL_SOFTC *sc;
  719.     FAST struct ip *ip;
  720.     FAST int     s;
  721.     FAST int     unit;
  722.     if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
  723. {
  724.         m_freem (m);
  725.         return (ENETDOWN);
  726. }
  727.     /*
  728.      * Check and see if protocol family is equal to AF_INET.
  729.      * Currently only AF_INET is support for SLIP.
  730.      */
  731.     if (dst->sa_family != AF_INET)
  732.         {
  733.         m_freem (m);
  734. return (EAFNOSUPPORT);
  735.         }
  736.     unit = ifp->if_unit;
  737.     sc = sl_softc [unit];
  738.     /*
  739.      * n.b.-- the `40' below checks that we have a least a min length
  740.      * tcp/ip header contiguous in an mbuf.  We don't do `sizeof' on
  741.      * some struct because too many compilers add random padding.
  742.      */
  743.     if (sc->sc_flags & SL_COMPRESS) /* compress enabled ? */
  744. {
  745.         ip = mtod(m, struct ip *);
  746.         if ((ip->ip_p == IPPROTO_TCP) && (m->m_len >= 40))
  747.             *mtod(m, u_char *) |= sl_compress_tcp (m, ip, &sc->sc_comp, 1);
  748.         }
  749.     s = splimp ();
  750.     /*
  751.      * If send queue is full drop the packet.
  752.      */
  753.     if (IF_QFULL (&ifp->if_snd))
  754.         {
  755.         IF_DROP (&ifp->if_snd);
  756.         m_freem (m);
  757.         ++sc->sc_if.if_oerrors;
  758.         splx (s);
  759.         return (ENOBUFS);
  760.         }
  761.     /* enqueue the packet for IP module to read later */
  762.     IF_ENQUEUE (&ifp->if_snd, m);
  763.     ifp->if_lastchange = tickGet (); 
  764.     splx (s);
  765.     /* wake the SLIP ouput task to let it send out this packet */
  766.     semGive (sc->sc_wrtSem);
  767.     return (OK);
  768.     }
  769. /*******************************************************************************
  770. *
  771. * slipWrtTask - SLIP writer task
  772. *
  773. * This is our write side task.  It waits for a semaphore and
  774. * when sloutput() yields the semaphore, it will try to send out
  775. * the packet that's been queue up so far.  Each SLIP interface
  776. * has its own slipWrtTask which is spawned in slipInit().
  777. * Start output on interface.  Get another datagram
  778. * to send from the interface queue and map it to
  779. * the interface before starting output.
  780. *
  781. * NOMANUAL
  782. */
  783. void slipWrtTask
  784.     (
  785.     FAST SL_SOFTC *sc           /* SLIP softc pointer */
  786.     )
  787.     {
  788.     FAST struct mbuf  *m;
  789.     FAST u_char  *cp;
  790.     FAST int   len;
  791.     int     fd;
  792.     struct mbuf   *m2;
  793.     int   rdCount;
  794.     int   numch;
  795.     char   ch;
  796.     int   s;
  797.     fd = sc->sc_fd;
  798.     FOREVER
  799. {
  800. semTake (sc->sc_wrtSem, WAIT_FOREVER); /* sync w/ sloutput */
  801. FOREVER
  802.     {
  803.     /* get a packet off of the queue */
  804.     s = splimp ();
  805.     IF_DEQUEUE (&sc->sc_if.if_snd, m);
  806.     splx (s);
  807.     if (m == NULL)
  808. break;
  809.     /*
  810.      * Check if the serial line has been idle for awhile.
  811.      * If it has been idle for awhile, we send out a FRAME_END
  812.      * character to clear out any garbage in transit and start
  813.      * fresh with a new packet.  We find out whether or not
  814.      * the line has been idle for awhile by looking at the
  815.      * read side of the tty ring buffer queue.  It is assumed
  816.      * that if there is nothing to read from the queue, we
  817.      * must have been idle for awhile.  If our assumption
  818.      * is incorrect, we only have wasted the amount of work
  819.      * and bandwidth it takes to send a character over SLIP.
  820.      * More than likely, though, this is better than sending
  821.      * out a large packet and clobbering the whole packet
  822.      * because of the bad data.
  823.      */
  824.     (void) ioctl (fd, FIONREAD, (int) &rdCount);
  825.     if (rdCount == 0)
  826. {
  827. ch = FRAME_END;
  828. ++sc->sc_if.if_obytes;
  829. (void) write (fd, &ch, 1);
  830. }
  831.     /*
  832.      * send the packet.
  833.      */
  834.     while (m)
  835. {
  836. cp  = mtod (m, u_char *);
  837. len = m->m_len;
  838. while (len > 0)
  839.     {
  840.     /*
  841.      * Find out how many bytes in the string we can
  842.      * handle without doing something special.
  843.      */
  844.     if ((numch = numCharsToMask (FRAME_ESCAPE, FRAME_END,
  845. (u_int) len, cp)) > 0)
  846. {
  847. /*
  848.  * Put numch characters at once
  849.  * into the tty output queue.
  850.  */
  851. if (write (fd, (char *)cp, numch) != numch)
  852.     break;
  853. sc->sc_if.if_obytes += numch;
  854. len -= numch;
  855. cp  += numch;
  856. }
  857.     /*
  858.      * If there are characters left in the mbuf,
  859.      * the first one must be special..
  860.      * Put it out in a different form.
  861.      */
  862.     if (len)
  863. {
  864. ch = FRAME_ESCAPE;
  865. if (write (fd, &ch, 1) != 1)
  866.     break;
  867. ++sc->sc_if.if_obytes;
  868. ch = (*cp == FRAME_ESCAPE) ?
  869.      TRANS_FRAME_ESCAPE :
  870.      TRANS_FRAME_END;
  871. if (write (fd, &ch, 1) != 1)
  872.     break;
  873. ++sc->sc_if.if_obytes;
  874. ++cp;
  875. --len;
  876. }
  877.     }
  878. m2 = m_free (m); 
  879. m = m2;
  880. }
  881.    /*
  882.     * indicate the end-of-packet.
  883.     */
  884.     ch = FRAME_END;
  885.     if (write (fd, &ch, 1) != 1)
  886. {
  887. /*
  888.  * This shouldn't happen but if it does we try one
  889.  * more time (just for the hack of it) and increment
  890.  * the if_collisions and if_oerrors.
  891.  */
  892. ch = FRAME_END;
  893. (void) write (fd, &ch, 1);
  894. sc->sc_if.if_collisions++;
  895. sc->sc_if.if_oerrors++;
  896. }
  897.     else
  898. {
  899. ++sc->sc_if.if_obytes;
  900. sc->sc_if.if_opackets++;
  901. }
  902.     }
  903. }
  904.     }
  905. /*******************************************************************************
  906. *
  907. * slintr - SLIP tty protocol hook routine
  908. *
  909. * Called at interrupt level by the tty driver input nterrupt routine.
  910. * It is our "protocol hook" routine set by an FIOPROTOHOOK ioctl() call.
  911. * slintr() examines each character coming in and keeps a count
  912. * of input characters in the ring buffer of the tty driver until
  913. * a full packet is indicated by FRAME_END.
  914. * When detected, enqueue a call to slread() via netJobAdd() to
  915. * be processed later at task level.
  916. * A net job will not be added if the first character of the packet
  917. * won't fit into the ring buffer.  In that case the entire packet
  918. * must be discarded at interrupt level.
  919. *
  920. * This routine will return FALSE to tyIRd() to indicate
  921. * that normal processing should continue within tyIRd() when
  922. * this routine returns.
  923. *
  924. * RETURNS: FALSE so tyIRd continues processing
  925. */
  926. LOCAL BOOL slintr
  927.     (
  928.     int unit,   /* SLIP unit number */
  929.     int inchar  /* incoming character */
  930.     )
  931.     {
  932.     FAST SL_SOFTC *sc = sl_softc [unit];
  933.     TY_DEV * pTyDev;
  934.     RING_ID ringId;
  935.     /* Set discard flag if this is a new packet and ring buffer full */
  936.     if ( sc->sc_qlen == 0 )
  937. {
  938.         pTyDev = (TY_DEV *) iosFdDevFind(sc->sc_fd);
  939.         ringId = pTyDev->rdBuf;
  940.         if (rngIsFull (ringId))
  941.     sc->sc_flags |= SL_INTR_PACKET_DISCARD;
  942.         else
  943.     sc->sc_flags &= ~SL_INTR_PACKET_DISCARD;
  944.         }
  945.     ++sc->sc_qlen;
  946.     if ((inchar & 0xff) == FRAME_END || sc->sc_qlen == SLBUF_HI)
  947. {
  948. /* schedule a read for this packet */
  949.         if (sc->sc_flags & SL_INTR_PACKET_DISCARD)
  950.     sc->sc_if.if_ierrors++;
  951.         else
  952.     {
  953.     if (sc->sc_qlen == 1) /* Single FRAME_END character */
  954. {
  955. sc->sc_qlen = 0;
  956. return (TRUE);          /* Don't put it in ring buffer */
  957. }
  958.             else
  959.         (void) netJobAdd ((FUNCPTR) slread, (int) sc, sc->sc_qlen, 
  960.   0, 0, 0);
  961.             }
  962. sc->sc_qlen = 0;
  963. }
  964.     return (FALSE); /* continue ty processing */
  965.     }
  966. /*******************************************************************************
  967. *
  968. * slread - read a whole SLIP packet and call slinput to process each char
  969. *
  970. * slread() is called only when FRAME_END is encountered when
  971. * we have a SLIP packet waiting for us to read in the tty's
  972. * input ring buffer.
  973. */
  974. LOCAL void slread
  975.     (
  976.     FAST SL_SOFTC *sc,  /* SLIP interface */
  977.     FAST int count      /* number of characters to be read */
  978.     )
  979.     {
  980.     BOOL firstCluster = TRUE;
  981.     char *builtCluster;
  982.     char *nextBuf = sc->sc_buf;
  983.     FAST u_char *c1 = (u_char *) sc->sc_buf;
  984.     FAST u_char *c2 = c1;
  985.     FAST u_char *end;
  986.     int len;
  987.     if ((len = read (sc->sc_fd, sc->sc_buf, count)) == 0)
  988. return;
  989.     end = (u_char *) (sc->sc_buf + len);
  990.     while (c1 < end)
  991. {
  992. ++sc->sc_if.if_ibytes; /* increment the recieved bytes */
  993.         
  994. if (sc->sc_ilen > sc->sc_if.if_mtu)
  995.             {
  996.     sc->sc_if.if_ierrors++;
  997.     break;
  998.     }
  999. switch (*c1)
  1000.     {
  1001.     case FRAME_END:
  1002.         {
  1003.                 if (sc->sc_ilen > 0)
  1004.     {
  1005.             if ((builtCluster = slRecv (sc, firstCluster)) != NULL)
  1006.         {
  1007.         nextBuf = builtCluster;
  1008.         firstCluster = FALSE;
  1009. }
  1010.                     sc->sc_ilen = 0;
  1011.     }
  1012.         sc->sc_buf = (char *) ++c1;
  1013. c2 = c1;
  1014. break;
  1015.         }
  1016.     case FRAME_ESCAPE:
  1017. {
  1018. c1++;
  1019.         if (*c1 == TRANS_FRAME_ESCAPE)
  1020.             *c1 = FRAME_ESCAPE;
  1021.         else if (*c1 == TRANS_FRAME_END)
  1022.     *c1 = FRAME_END;
  1023.         else 
  1024.     {
  1025.             sc->sc_if.if_ierrors++;
  1026.                     sc->sc_ilen = 0;
  1027.             sc->sc_buf = (char *) c1;
  1028.     c2 = c1;
  1029.     break;
  1030.     }
  1031. }
  1032.             default:
  1033. {
  1034. sc->sc_ilen++;
  1035.                 *c2++ = *c1++;
  1036. }
  1037.             }
  1038. }
  1039.     sc->sc_buf = nextBuf;
  1040.     sc->sc_ilen = 0;
  1041.     }
  1042. /*******************************************************************************
  1043. *
  1044. * slRecv - process an input frame
  1045. *
  1046. * This routine processes an input frame, then passes it up to the higher
  1047. * level in a form it expects.  Buffer loaning, etherInputHookRtns, and
  1048. * CSLIP uncompression are all supported.  Trailer protocols are not supported.
  1049. *
  1050. * RETURNS: N/A
  1051. */
  1052. LOCAL char *slRecv
  1053.     (
  1054.     FAST SL_SOFTC *sc, /* SLIP interface */
  1055.     BOOL firstCluster
  1056.     )
  1057.     {
  1058.     FAST  struct mbuf *m = NULL;
  1059.     FAST  char type;
  1060.     char  *nextBuf = NULL;
  1061.     char  *origBuf = sc->sc_buf;
  1062.     UINT8 *origRef = sc->sc_pRefC[(sc->sc_nLoanRxBuf - 1)];
  1063.     type = *sc->sc_buf & 0xf0;
  1064.     if (type != (IPVERSION << 4))
  1065.         {
  1066.         if (type & 0x80)
  1067.     type = TYPE_COMPRESSED_TCP;
  1068.         else if (type == TYPE_UNCOMPRESSED_TCP)
  1069.             *sc->sc_buf &= 0x4f;
  1070.         /*
  1071.          * we've got something that's not an IP packet.
  1072.          * If compression is enabled, try to uncompress
  1073.          * it.  Otherwise, if `auto-enable' compression
  1074.          * is on and it's a reasonable packet,
  1075.          * uncompress it then enable compression.
  1076.          * Otherwise, drop it.
  1077.          */
  1078.         if ((sc->sc_flags & SL_COMPRESS) || ((sc->sc_flags & SL_COMPRESS_RX) &&
  1079.              (type == TYPE_UNCOMPRESSED_TCP) && (sc->sc_ilen >= 40)))
  1080.     {
  1081.             if ((sc->sc_ilen = sl_uncompress_tcp ((u_char **)&sc->sc_buf, 
  1082.   sc->sc_ilen, (u_int) type,
  1083.   &sc->sc_comp)) <= 0)
  1084.                 {
  1085.         sc->sc_if.if_ierrors++;
  1086.         return (NULL);
  1087.                 }
  1088.             sc->sc_flags |= SL_COMPRESS;
  1089.             }
  1090.         else
  1091.             {
  1092.     sc->sc_if.if_ierrors++;
  1093.     return (NULL);
  1094.             }
  1095.         }
  1096.     if ((etherInputHookRtn != NULL) && ((*etherInputHookRtn)
  1097.         (&sc->sc_if, sc->sc_buf, sc->sc_ilen) != 0))
  1098.         return (NULL);
  1099.     if ((firstCluster) && (sc->sc_nLoanRxBuf > 0) &&
  1100. (USE_CLUSTER (sc->sc_ilen)))
  1101.         m = build_cluster (sc->sc_buf, sc->sc_ilen, &sc->sc_if,
  1102.             MC_SL, sc->sc_pRefC[(sc->sc_nLoanRxBuf - 1)], 
  1103.     (FUNCPTR) slLoanFree, (int) sc, (int) origBuf, (int) origRef);
  1104.     /* if buffer was successfully turned into mbuf cluster */
  1105.  
  1106.     if (m != NULL)
  1107.         nextBuf = sc->sc_lPool[--sc->sc_nLoanRxBuf];
  1108.     else
  1109.         {
  1110.         /* else do same ol' copy to mbuf */
  1111.         m = copy_to_mbufs (sc->sc_buf, sc->sc_ilen, 0, &sc->sc_if);
  1112. if (m == NULL)
  1113.     {
  1114.     sc->sc_if.if_ierrors++;
  1115.     return (NULL);
  1116.             }
  1117.         }
  1118.     /* send up to protocol */
  1119.     sc->sc_if.if_ipackets++;
  1120.     sc->sc_if.if_lastchange = tickGet(); 
  1121.     ipintr (m);
  1122.     return (nextBuf);
  1123.     }
  1124. /*******************************************************************************
  1125. *
  1126. * slioctl - SLIP ioctl routine
  1127. *
  1128. * Process an ioctl request.
  1129. *
  1130. * RETURNS: 0 or errno
  1131. */
  1132. LOCAL int slioctl
  1133.     (
  1134.     FAST struct ifnet *ifp,     /* pointer to SLIP interface */
  1135.     int cmd,                    /* command */
  1136.     caddr_t data                /* data */
  1137.     )
  1138.     {
  1139.     FAST struct ifaddr * ifa = (struct ifaddr *)data;
  1140.     FAST struct ifreq * ifr;
  1141.     int error = 0;
  1142.     int  s;
  1143.     s = splimp ();
  1144.     switch (cmd)
  1145.         {
  1146.         case SIOCGIFFLAGS:
  1147.             *(short *)data = ifp->if_flags;
  1148.             break;
  1149.         case SIOCSIFADDR:
  1150.     if (ifa->ifa_addr->sa_family == AF_INET)
  1151.                 {
  1152. slinit (ifp->if_unit);
  1153.                 ifa->ifa_rtrequest = slRtRequest;
  1154.                 }
  1155.     else
  1156. error = EAFNOSUPPORT;
  1157.     break;
  1158. case SIOCSIFDSTADDR:
  1159.             if (ifa->ifa_dstaddr->sa_family != AF_INET)
  1160. error = EAFNOSUPPORT;
  1161.         break;
  1162. case SIOCADDMULTI:
  1163. case SIOCDELMULTI:
  1164.     ifr = (struct ifreq *)data;
  1165.     if (ifr == 0) 
  1166. {
  1167. error = EAFNOSUPPORT; /* XXX */
  1168. break;
  1169. }
  1170.     switch (ifr->ifr_addr.sa_family)
  1171. {
  1172. #ifdef INET
  1173. case AF_INET:
  1174.     break;
  1175. #endif
  1176. default:
  1177.     error = EAFNOSUPPORT;
  1178.     break;
  1179. }
  1180.     break;
  1181.         default:
  1182.          error = EINVAL;
  1183.         }
  1184.     splx (s);
  1185.     return (error);
  1186.     }
  1187. /*******************************************************************************
  1188. *
  1189. * numCharsToMask - scan the buffer for a mask
  1190. *
  1191. * numcharsToMask finds out how many characters are in a string
  1192. * before a character that matches the 'mask'.
  1193. *
  1194. * RETURNS: number of chars up to the mask
  1195. */
  1196. LOCAL int numCharsToMask
  1197.     (
  1198.     FAST u_char mask1,
  1199.     FAST u_char mask2,
  1200.     u_int size,
  1201.     FAST u_char *cp
  1202.     )
  1203.     {
  1204.     FAST u_char *end = &cp [size];
  1205.     u_char *start = cp;
  1206.     while ((cp < end) && (*cp != mask1) && (*cp != mask2))
  1207.      cp++;
  1208.     return (cp - start);
  1209.     }
  1210. /********************************************************************************
  1211. * slLoanFree - return the given buffer to loaner pool
  1212. *
  1213. * This routine returns <pRxBuf> to the pool of available loaner buffers.
  1214. * It also returns <pRef> to the pool of available loaner reference counters,
  1215. * then zeroes the reference count.
  1216. *
  1217. * RETURNS: N/A
  1218. */
  1219.  
  1220. LOCAL void slLoanFree
  1221.     (
  1222.     SL_SOFTC *sc,
  1223.     char *pRxBuf,
  1224.     UINT8 *pRef
  1225.     )
  1226.     {
  1227.     /* return loaned buffer to pool */
  1228.     sc->sc_lPool[sc->sc_nLoanRxBuf] = pRxBuf;
  1229.  
  1230.     /* return loaned reference count to pool */
  1231.  
  1232.     sc->sc_pRefC[sc->sc_nLoanRxBuf++] = pRef;
  1233.  
  1234.     /* reset reference count - should have been done from above, but... */
  1235.  
  1236.     *pRef = 0;
  1237.     }
  1238. /*******************************************************************************
  1239. *
  1240. * slRtRequest - perform special routing.
  1241. *
  1242. * This function performs special processing when adding a route to itself
  1243. * on a slip interface. It intializes the interface pointer to the loop back
  1244. * so that the packet can be rerouted through the loopback instead of actually
  1245. * sending the packet out on the wire and have the other end loop back the
  1246. * packet. The capability can be turned off by intializing the global flag
  1247. * slipLoopBack to 0. By default it is turned on. 
  1248. *
  1249. * NOMANUAL
  1250. *
  1251. * RETURNS: N/A
  1252. */
  1253. static void slRtRequest
  1254.     (
  1255.     int  cmd, /* route command */
  1256.     struct rtentry *  pRtEntry, /* pointer to the route entry */
  1257.     struct sockaddr *  pSockAddr /* pointer to the sock addr */
  1258.     )
  1259.     {
  1260.     /* only when adding a route to itself */
  1261.     if (cmd == RTM_ADD)
  1262.         {
  1263.         if (slipLoopBack && (pRtEntry->rt_flags & RTF_HOST) &&
  1264.             (SIN(rt_key(pRtEntry))->sin_addr.s_addr ==
  1265.              (IA_SIN(pRtEntry->rt_ifa))->sin_addr.s_addr))
  1266.             {
  1267.             pRtEntry->rt_rmx.rmx_expire = 0;
  1268.             pRtEntry->rt_ifp = &loif; /* initialize to the loop back */ 
  1269.             }
  1270.         }
  1271.     }