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

VxWorks

开发平台:

C/C++

  1. /* etherLib.c - Ethernet raw I/O routines and hooks */
  2. /* Copyright 1984 - 2000 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02w,16oct00,spm  fixed etherInputHookAdd and etherInputHookDelete (SPR #30166)
  8. 02v,16oct00,spm  merged documentation updates from tor2_0_x branch (SPR #21383)
  9. 02u,27may99,pul  etherInputHookAdd changes for NPT driver and 
  10.  tagged Ethernet frames support
  11. 02t,27apr99,sj   Merged post SENS1.1 fixes done for Tor2.0
  12. 02s,29mar99,dat  documentation, removed refs to obsolete drivers (26119)
  13. 02r,16mar99,spm  recovered orphaned code from tor1_0_1.sens1_1 (SPR #25770)
  14. 02q,15dec98,jmb  SENS merge, (01w-02p)
  15. 02p,06oct98,spm  fixed buffer overrun in END input hook routine (SPR #22363)
  16. 02o,27aug98,n_s  set unit number in fakeIF for endEtherInputHook. spr #22222.
  17. 02n,14dec97,jdi  doc: cleanup.
  18. 02m,08dec97,gnn  END code review fixes.
  19. 02l,28oct97,gnn  fixed SPR 9606, caused by problems in the endEtherInputHook
  20. 02k,27oct97,spm  corrected input hooks to handle mixed device types; added
  21.                  support for multiple hooks per END device
  22. 02j,25oct97,kbw  making minor man page fixes
  23. 02i,17oct97,vin  changes reflecting protocol recieveRtn changes.
  24. 02h,09oct97,spm  fixed memory leak in END driver input hook handler
  25. 02g,03oct97,gnn  removed necessity for endDriver global
  26. 02f,25sep97,gnn  SENS beta feedback fixes
  27. 02e,26aug97,spm  removed compiler warnings (SPR #7866)
  28. 02d,19aug97,gnn  changes due to new buffering scheme.
  29. 02c,12aug97,gnn  changes necessitated by MUX/END update.
  30. 02b,02jun97,spm  corrected invalid mem width causing m_devget panic (SPR #8640)
  31. 02a,15may97,gnn  removed some warnings.
  32.                  modified muxUnbind.
  33. 01z,20mar97,spm  fixed memory leak in Ethernet hook routines
  34. 01y,21jan97,gnn  changed MUX_PROTO_PROMISC to MUX_PROTO_SNARF.
  35. 01x,17dec96,gnn  added code to handle the new etherHooks and END stuff.
  36. 01w,22oct96,gnn  added etherTypeGet routine to heuristically figure out the
  37.                  proper ethertype for a packet given a pointer to it.
  38.                  This handles 802.3 addressing.
  39. 01w,15apr96,hk   added awai-san's etherOutput() fix for SH.
  40. 01v,01nov95,jdi  doc: updated list of supported drivers (SPR 4545).
  41. 01u,20jan93,jdi  documentation cleanup for 5.1.
  42. 01t,13nov92,dnw  added includes of unixLib.h and hostLib.h
  43. 01s,15aug92,elh  fixed bug in etherAddrResolve.
  44. 01r,26may92,rrr  the tree shuffle
  45.   -changed includes to have absolute path from h/
  46. 01q,19nov91,rrr  shut up some ansi warnings.
  47. 01p,15oct91,elh  added ether{Input,Output}HookDelete
  48. 01o,04oct91,rrr  passed through the ansification filter
  49.                   -changed functions to ansi style
  50.   -changed includes to have absolute path from h/
  51.   -changed copyright notice
  52. 01n,30apr91,jdi  documentation tweaks.
  53. 01m,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  54.  doc review by dnw.
  55. 01l,04feb91,jaa  documentation cleanup.
  56. 01k,05oct90,dnw  documentation tweaks.
  57. 01j,11apr90,hjb  de-linted.
  58. 01i,19mar90,jdi  documentation cleanup.
  59. 01h,20aug88,gae  documentation.
  60. 01g,22jun88,dnw  name tweaks.
  61. 01f,30may88,dnw  changed to v4 names.
  62. 01e,05jan88,rdc  added include of systm.h
  63. 01d,18nov87,ecs  documentation.
  64. 01c,11nov87,dnw  added etherAddOutputHook().
  65.  changed calling sequence to input hook routine.
  66. 01b,05nov87,jlf  moved from netsrc to src
  67.  documentation
  68. 01a,28aug87,dnw  written
  69. */
  70. /*
  71. DESCRIPTION
  72. This library provides utilities that give direct access to Ethernet packets.
  73. Raw packets can be output directly to an interface using etherOutput().
  74. Incoming and outgoing packets can be examined or processed using the hooks
  75. etherInputHookAdd() and etherOutputHookAdd().  The input hook can be used to
  76. receive raw packets that are not part of any of the supported network
  77. protocols.  The input and output hooks can also be used to build network
  78. monitoring and testing tools.
  79. Normally, the network should be accessed through the higher-level socket
  80. interface provided in sockLib.  The routines in etherLib should rarely,
  81. if ever, be necessary for applications.
  82. CAVEAT
  83. All VxWorks Ethernet drivers using the generic MUX/END model support both
  84. the input hook and output hook routines. Both hook types are also supported 
  85. by the following BSD model drivers:
  86.     if_cpm - Motorola CPM Ethernet driver
  87.     if_eex - Intel EtherExpress 16 network interface driver
  88.     if_ei - Intel 82596 Ethernet driver
  89.     if_eihk - Intel 82596 Ethernet driver (for hkv3500)
  90.     if_elc - SMC 8013WC Ethernet driver
  91.     if_elt - 3Com 3C509 Ethernet driver
  92.     if_ene - Novell/Eagle NE2000 network driver
  93.     if_esmc - Ampro Ethernet2 SMC-91c9x Ethernet driver
  94.     if_fei - Intel 82557 Ethernet driver
  95.     if_fn - Fujitsu MB86960 NICE Ethernet driver
  96.     if_ln - Advanced Micro Devices Am7990 LANCE Ethernet driver
  97.     if_mbc - Motorola 68EN302 Ethernet driver 
  98.     if_sm - shared memory backplane network interface driver
  99.     if_sn - National Semiconductor DP83932B SONIC Ethernet driver
  100.     if_ultra - SMC Elite Ultra Ethernet driver
  101. The following BSD drivers support only the input hook routines:
  102.     if_cs - Crystal Semiconductor CS8900 network interface driver
  103.     if_dc - DEC 21x4x Ethernet LAN network interface driver
  104.     if_nicEvb - National Semiconductor ST-NIC Ethernet driver (for evb403)
  105.     if_sl - Serial Line IP (SLIP) network interface driver
  106. The following BSD drivers support only the output hook routines:
  107.     if_ulip - network interface driver for User Level IP (VxSim)
  108. The following BSD drivers do not support either the input hook or
  109. output hook routines:
  110.     if_loop - software loopback network interface driver
  111. INCLUDE FILES: etherLib.h
  112. SEE ALSO:
  113. .pG "Network"
  114. */
  115. #include "vxWorks.h"
  116. #include "lstLib.h"
  117. #include "net/mbuf.h"
  118. #include "net/if.h"
  119. #include "net/route.h"
  120. #include "netinet/if_ether.h"
  121. #include "net/if_llc.h"
  122. #include "net/systm.h"
  123. #include "inetLib.h"
  124. #include "net/unixLib.h"
  125. #include "hostLib.h"
  126. #include "end.h"
  127. #include "muxLib.h"
  128. #include "netBufLib.h"
  129. #include "muxTkLib.h"
  130. #include "private/muxLibP.h"
  131. IMPORT unsigned char etherbroadcastaddr [];
  132. FUNCPTR etherInputHookRtn  = NULL; /* NULL = none */
  133. FUNCPTR etherOutputHookRtn = NULL; /* NULL = none */
  134. LOCAL BOOL endEtherInputHookRtn (void * pCookie, long type, M_BLK_ID pMblk, 
  135.                                  LL_HDR_INFO * pLinkHdrInfo, void * pSpare);
  136. LOCAL BOOL nptEtherInputHookRtn (void * pCallBackId, long type, M_BLK_ID pMblk, 
  137.                                  void * pSpareData);
  138. LOCAL BOOL etherInputHook (struct ifnet * pIf, char * buffer, int length);
  139. LOCAL BOOL etherOutputHook (struct ifnet * pIf, char * buffer, int length);
  140. /* locals */
  141. LOCAL LIST inputHookList;
  142. LOCAL LIST outputHookList;
  143. LOCAL BOOL etherInputHookActive = FALSE;
  144. typedef struct hook_entry
  145.     {
  146.     NODE node;  /* Attachment point for linked list. */
  147.     FUNCPTR routine;
  148.     void * pCookie;  /* For use with END devices, NULL for BSD devices. */
  149.     char name[8];  /* Device name (END devices only). */
  150.     int unit;  /* Device unit number (END devices only). */
  151.     } HOOK_ENTRY;
  152. /* defints */
  153. #define STREQ(A, B) (strcmp(A, B) == 0 ? 1 : 0)
  154. /* RFC 894 Header. */
  155. typedef struct enet_hdr
  156.     {
  157.     char dst [6];
  158.     char src [6];
  159.     USHORT type;
  160.     } ENET_HDR;
  161. /*******************************************************************************
  162. *
  163. * etherOutput - send a packet on an Ethernet interface
  164. *
  165. * This routine sends a packet on the specified Ethernet interface by
  166. * calling the interface's output routine directly.
  167. *
  168. * The first argument <pIf> is a pointer to a variable of type `struct ifnet'
  169. * which contains some useful information about the network interface.  A
  170. * routine named ifunit() can retrieve this pointer from the system in the
  171. * following way:
  172. * .CS
  173. *     struct ifnet *pIf;
  174. *     ...
  175. *     pIf = ifunit ("ln0");
  176. * .CE
  177. * If ifunit() returns a non-NULL pointer, it is a valid pointer to
  178. * the named network interface device structure of type `struct ifnet'.
  179. * In the above example, <pIf> points to the data structure that
  180. * describes the first LANCE network interface device if ifunit() is
  181. * successful.
  182. *
  183. * The second argument <pEtherHeader> should contain a valid Ethernet address
  184. * of the machine for which the message contained in the argument <pData> is
  185. * intended.  If the Ethernet address of this machine is fixed and well-known
  186. * to the user, filling in the structure `ether_header' can be accomplished by
  187. * using bcopy() to copy the six-byte Ethernet address into the `ether_dhost'
  188. * field of the structure `ether_header'.  Alternatively, users can make use of
  189. * the routine etherAddrResolve() which will use ARP (Address Resolution
  190. * Protocol) to resolve the Ethernet address for a specified Internet
  191. * address.
  192. *
  193. * RETURNS: OK, or ERROR if the routine runs out of mbufs.
  194. *
  195. * SEE ALSO:
  196. * etherAddrResolve()
  197. */
  198. STATUS etherOutput
  199.     (
  200.     struct ifnet *pIf,                  /* interface on which to send */
  201.     struct ether_header *pEtherHeader,  /* Ethernet header to send    */
  202.     FAST char *pData,                   /* data to send               */
  203.     FAST int dataLength                 /* # of bytes of data to send */
  204.     )
  205.     {
  206.     FAST struct mbuf *m; /* ptr to current mbuf piece */
  207. #if (CPU_FAMILY==SH)
  208.     FAST int i;
  209. #endif /* CPU_FAMILY==SH */
  210.     struct sockaddr dst; /* destination address */
  211.     int oldLevel;
  212.     /* construct dst sockaddr required by interface output routine;
  213.      * all Ethernet drivers interpret address family AF_UNSPEC as raw
  214.      * Ethernet header (this is used by arp) */
  215.     dst.sa_family = AF_UNSPEC;
  216.     dst.sa_len = sizeof(dst);
  217. #if (CPU_FAMILY==SH)
  218.     for ( i=0; i<SIZEOF_ETHERHEADER; i+=2 )
  219.         *((UINT16 *)((int)&(dst.sa_data[0])+i)) =
  220.                                         *((UINT16 *)((int)pEtherHeader+i));
  221. #else /* CPU_FAMILY==SH */
  222.     *((struct ether_header *) dst.sa_data) = *pEtherHeader;
  223. #endif /* CPU_FAMILY==SH */
  224.     if ((m = bcopy_to_mbufs (pData, dataLength, 0, pIf, NONE)) == NULL)
  225. return (ERROR);
  226.     /* call interface's output routine */
  227.     oldLevel = splnet ();
  228.     (* pIf->if_output) (pIf, m, &dst, (struct rtentry *)NULL);
  229.     splx (oldLevel);
  230.     return (OK);
  231.     }
  232. /*******************************************************************************
  233. *
  234. * etherInputHookAdd - add a routine to receive all Ethernet input packets
  235. *
  236. * This routine adds a hook routine that will be called for every Ethernet
  237. * packet that is received.
  238. *
  239. * The calling sequence of the input hook routine is:
  240. * .CS
  241. *     BOOL inputHook
  242. *          (
  243. *          struct ifnet *pIf,    /@ interface packet was received on @/
  244. *          char         *buffer, /@ received packet @/
  245. *          int          length   /@ length of received packet @/
  246. *          )
  247. * .CE
  248. * The hook routine should return TRUE if it has handled the input packet and
  249. * no further action should be taken with it.  It should return FALSE if it
  250. * has not handled the input packet and normal processing (for example, 
  251. * Internet) should take place.
  252. *
  253. * The packet is in a temporary buffer when the hook routine is called.
  254. * This buffer will be reused upon return from the hook.  If the hook
  255. * routine needs to retain the input packet, it should copy it elsewhere.
  256. *
  257. * IMPLEMENTATION
  258. * A call to the function pointed to by the global function pointer
  259. * `etherInputHookRtn' should be invoked in the receive routine of every
  260. * network driver providing this service.  For example:
  261. * .CS
  262. *     ...
  263. *     #include "etherLib.h"
  264. *     ...
  265. *     xxxRecv ()
  266. *     ...
  267. *     /@ call input hook if any @/
  268. *
  269. *         if ((etherInputHookRtn != NULL) &&
  270. *             (* etherInputHookRtn) (&ls->ls_if, (char *)eh, len))
  271. *             {
  272. *             return; /@ input hook has already processed this packet @/
  273. *             }
  274. * .CE
  275. *
  276. * RETURNS: OK if the hook was added, or ERROR otherwise.
  277. */
  278. STATUS etherInputHookAdd
  279.     (
  280.     FUNCPTR inputHook,   /* routine to receive Ethernet input */
  281.     char* pName,         /* name of device if MUX/END is being used */
  282.     int unit             /* unit of device if MUX/END is being used */
  283.     )
  284.     {
  285.     HOOK_ENTRY *pHookEnt;
  286.     HOOK_ENTRY *pHookCurr;
  287.     void * pBinding = NULL;  /* Existing END device binding, if any. */
  288.     BOOL tkDevice=FALSE;
  289.     if (pName != NULL) /* We are dealing with an END. */
  290.         {
  291.         if (etherInputHookActive == FALSE)     /* First END driver hook? */
  292.             {
  293.             if (etherInputHookRtn == NULL)
  294.                 {
  295.                 /* Initialize list - first network driver of either type. */
  296.  
  297.                 lstInit (&inputHookList);
  298.                 }
  299.             etherInputHookActive = TRUE;
  300.             }
  301.         /* Check if bind is necessary and eliminate duplicate hook routine. */
  302.         for (pHookCurr = (HOOK_ENTRY *)lstFirst(&inputHookList); 
  303.              pHookCurr != NULL;
  304.              pHookCurr = (HOOK_ENTRY *)lstNext(&pHookCurr->node))
  305.             {
  306.             /* Ignore BSD device hook entries. */
  307.             if (pHookCurr->pCookie == NULL)
  308.                 continue;
  309.             if (STREQ(pHookCurr->name, pName) && (pHookCurr->unit == unit))
  310.                 {
  311.                 if (pHookCurr->routine == inputHook)
  312.                     return (ERROR);
  313.                 /* Additional hook for same device - reuse binding. */
  314.                 pBinding = pHookCurr->pCookie;
  315.                 }
  316.             }
  317.         pHookEnt = malloc (sizeof (HOOK_ENTRY));
  318.         if (pHookEnt == NULL)
  319.             return (ERROR);
  320.         bzero ( (char *)pHookEnt, sizeof (HOOK_ENTRY));
  321.         if (pBinding == NULL)  /* No hook entry for this END device? */
  322.             {
  323.             /* Attach Ethernet input hook handler for this device. */
  324.     tkDevice = muxTkDrvCheck (pName);
  325.             if (tkDevice)
  326.                 {
  327.                 pBinding = muxTkBind (pName, unit, nptEtherInputHookRtn, 
  328.                                       NULL, NULL, NULL, MUX_PROTO_SNARF, 
  329.                                       "etherInputHook", pHookEnt, NULL, NULL);
  330.                 }
  331.             else
  332.                 {
  333.                 pBinding = muxBind (pName, unit, endEtherInputHookRtn, 
  334.                                     NULL, NULL, NULL, MUX_PROTO_SNARF, 
  335.                                     "etherInputHook", pHookEnt);
  336.                 }
  337.             if (pBinding == NULL)
  338.                 {
  339.                 free (pHookEnt);
  340.                 return (ERROR);
  341.                 }
  342.             }
  343.         /*
  344.          * Assign (new or existing) handler attachment for the device,
  345.          * allowing hook deletion in any order.
  346.          */
  347.         pHookEnt->pCookie = pBinding;
  348.         strcpy (pHookEnt->name, pName);
  349.         pHookEnt->unit = unit;
  350.         pHookEnt->routine = inputHook;
  351.         lstAdd (&inputHookList, &pHookEnt->node);
  352.         }
  353.     else               /* Old style driver. */
  354.         {
  355.         /* Check for duplicate hook routine. */
  356.         for (pHookCurr = (HOOK_ENTRY *)lstFirst(&inputHookList);
  357.              pHookCurr != NULL;
  358.              pHookCurr = (HOOK_ENTRY *)lstNext(&pHookCurr->node))
  359.             {
  360.             if (pHookCurr->pCookie)    /* Ignore END device hook entries. */
  361.                 continue;
  362.             if (pHookCurr->routine == inputHook)
  363.                 return (ERROR);
  364.             }
  365.         pHookEnt = malloc(sizeof(HOOK_ENTRY));
  366.         if (pHookEnt == NULL)
  367.             return (ERROR);
  368.         bzero ( (char *)pHookEnt, sizeof (HOOK_ENTRY));
  369.         if (etherInputHookRtn == NULL)    /* First BSD driver hook? */
  370.             {
  371.             etherInputHookRtn = etherInputHook;
  372.             if (!etherInputHookActive)
  373.                 {
  374.                 /* Initialize list - first network driver of either type. */
  375.                 lstInit (&inputHookList);
  376.                 }
  377.             }
  378.         pHookEnt->routine = inputHook;
  379.         lstAdd(&inputHookList, &pHookEnt->node);
  380.         }
  381.     return (OK);
  382.     }
  383. /*******************************************************************************
  384. *
  385. * etherInputHookDelete - delete a network interface input hook routine
  386. *
  387. * This routine deletes a network interface input hook.
  388. *
  389. * RETURNS: N/A
  390. */
  391. void etherInputHookDelete
  392.     (
  393.     FUNCPTR inputHook,
  394.     char *pName,
  395.     int unit
  396.     )
  397.     {
  398.     HOOK_ENTRY *pHookEnt;
  399.     HOOK_ENTRY *pTarget = NULL;
  400.     BOOL unbindFlag = TRUE;    /* Remove handler if hook found? */
  401.     if (pName != NULL)                       /* END case */
  402.         {
  403.         for (pHookEnt = (HOOK_ENTRY *)lstFirst(&inputHookList);
  404.              pHookEnt != NULL;
  405.              pHookEnt = (HOOK_ENTRY *)lstNext(&pHookEnt->node))
  406.             {
  407.             /* Ignore BSD device hook entries. */
  408.             if (pHookEnt->pCookie == NULL)
  409.                 continue;
  410.             if (STREQ(pHookEnt->name, pName) && (pHookEnt->unit == unit))
  411.                 {
  412.                 if (pHookEnt->routine == inputHook)
  413.                     {
  414.                     /*
  415.                      * Found matching hook entry to remove. Keep searching
  416.                      * for other hooks on this device if needed.
  417.                      */
  418.                     pTarget = pHookEnt;
  419.                     if (!unbindFlag)    /* Another hook already found? */
  420.                         break;
  421.                     }
  422.                 else
  423.                     {
  424.                     /*
  425.                      * Different hook on same driver - do not unbind.
  426.                      * Stop searching if target hook entry already found.
  427.                      */
  428.                     unbindFlag = FALSE;
  429.                     if (pTarget)
  430.                         break;
  431.                     }
  432.                 }
  433.             }
  434.         if (pTarget)    /* Remove hook entry if match found. */
  435.             {
  436.             if (unbindFlag)   /* Remove binding if last hook for device. */
  437.                 {
  438.                 if (muxTkDrvCheck (pName))
  439.                     {
  440.                     muxUnbind (pTarget->pCookie, MUX_PROTO_SNARF,
  441.                                nptEtherInputHookRtn);
  442.                     }
  443.                 else
  444.                     {
  445.                     muxUnbind (pTarget->pCookie, MUX_PROTO_SNARF,
  446.                                endEtherInputHookRtn);
  447.                     }
  448.                 }
  449.             lstDelete (&inputHookList, &pTarget->node);
  450.             free (pTarget);
  451.             }
  452.         }
  453.     else                                     /* 4.4 case */
  454.         {
  455.         for (pHookEnt = (HOOK_ENTRY *)lstFirst(&inputHookList);
  456.              pHookEnt != NULL; pHookEnt = pTarget)
  457.             {
  458.             if (pHookEnt->pCookie)    /* Ignore END device hook entries. */
  459.                 continue;
  460.             pTarget = (HOOK_ENTRY *)lstNext(&pHookEnt->node);
  461.             if (pHookEnt->routine == inputHook)
  462.                 {
  463.                 lstDelete(&inputHookList, &pHookEnt->node);
  464.                 free(pHookEnt);
  465.                 }
  466.             }
  467.         }
  468.     
  469.     if (lstCount(&inputHookList) <= 0)
  470.         {
  471.         etherInputHookActive = FALSE;     /* No END driver hooks installed. */
  472.         etherInputHookRtn = NULL;         /* No BSD driver hooks installed. */
  473.         lstFree (&inputHookList);
  474.         }
  475.     }
  476. /*******************************************************************************
  477. *
  478. * etherOutputHookAdd - add a routine to receive all Ethernet output packets
  479. *
  480. * This routine adds a hook routine that will be called for every Ethernet
  481. * packet that is transmitted.
  482. *
  483. * The calling sequence of the output hook routine is:
  484. * .CS
  485. *     BOOL outputHook
  486. *         (
  487. *         struct ifnet *pIf,    /@ interface packet will be sent on @/
  488. *         char         *buffer, /@ packet to transmit               @/
  489. *         int          length   /@ length of packet to transmit     @/
  490. *         )
  491. * .CE
  492. * The hook is called immediately before transmission.  The hook routine
  493. * should return TRUE if it has handled the output packet and no further
  494. * action should be taken with it.  It should return FALSE if it has not
  495. * handled the output packet and normal transmission should take place.
  496. *
  497. * The Ethernet packet data is in a temporary buffer when the hook routine
  498. * is called.  This buffer will be reused upon return from the hook.  If
  499. * the hook routine needs to retain the output packet, it should be copied
  500. * elsewhere.
  501. *
  502. * IMPLEMENTATION
  503. * A call to the function pointed to be the global function pointer
  504. * `etherOutputHookRtn' should be invoked in the transmit routine of every
  505. * network driver providing this service.  For example:
  506. * .ne 14
  507. * .CS
  508. *     ...
  509. *     #include "etherLib.h"
  510. *     ...
  511. *     xxxStartOutput ()
  512. *     /@ call output hook if any @/
  513. *     if ((etherOutputHookRtn != NULL) &&
  514. *          (* etherOutputHookRtn) (&ls->ls_if, buf0, len))
  515. *         {
  516. *         /@ output hook has already processed this packet @/
  517. *         }
  518. *     else
  519. *     ...
  520. * .CE
  521. *
  522. * RETURNS: OK if the hook was added, or ERROR otherwise.
  523. */
  524. STATUS etherOutputHookAdd
  525.     (
  526.     FUNCPTR outputHook  /* routine to receive Ethernet output */
  527.     )
  528.     {
  529.     HOOK_ENTRY *pHookEnt;
  530.     
  531.     pHookEnt = malloc(sizeof(HOOK_ENTRY));
  532.     if (pHookEnt == NULL)
  533.         return (ERROR);
  534.     if (etherOutputHookRtn == NULL)
  535.         {
  536.         etherOutputHookRtn = etherOutputHook;
  537.         lstInit(&outputHookList);
  538.         }
  539.     pHookEnt->routine = outputHook;
  540.     lstAdd(&outputHookList, &pHookEnt->node);
  541.     return (OK);
  542.     }
  543. /*******************************************************************************
  544. *
  545. * etherOutputHookDelete - delete a network interface output hook routine
  546. *
  547. * This routine deletes a network interface output hook, which must be supplied
  548. * as the only argument.
  549. *
  550. * RETURNS: N/A
  551. */
  552. void etherOutputHookDelete
  553.     (
  554.     FUNCPTR outputHook
  555.     )
  556.     {
  557.     HOOK_ENTRY *pHookEnt;
  558.     extern LIST outputHookList;
  559.     NODE index;
  560.     for (pHookEnt = (HOOK_ENTRY *)lstFirst(&outputHookList); 
  561.          pHookEnt != NULL;
  562.          pHookEnt = (HOOK_ENTRY *)lstNext(&index))
  563.         {
  564.         index = pHookEnt->node;
  565.         if (pHookEnt->routine == outputHook)
  566.             {
  567.             lstDelete(&outputHookList, &pHookEnt->node);
  568.             free(pHookEnt);
  569.             }
  570.         }
  571.     
  572.     if (lstCount(&outputHookList) <= 0)
  573.         {
  574.         etherOutputHookRtn = NULL;
  575.         lstFree(&outputHookList);
  576.         }
  577.     
  578.     }
  579. /*******************************************************************************
  580. *
  581. * etherAddrResolve - find an Ethernet address for a specified Internet address
  582. *
  583. * This routine uses the Address Resolution Protocol (ARP) and internal ARP
  584. * cache to resolve the Ethernet address of a machine that owns the Internet
  585. * address given in <targetAddr>.
  586. *
  587. * The first argument <pIf> is a pointer to a variable of type `struct ifnet'
  588. * which identifies the network interface through which the ARP request messages
  589. * are to be sent out.  The routine ifunit() is used to retrieve this pointer
  590. * from the system in the following way:
  591. * .CS
  592. *     struct ifnet *pIf;
  593. *     ...
  594. *     pIf = ifunit ("ln0");
  595. * .CE
  596. * If ifunit() returns a non-NULL pointer, it is a valid pointer to
  597. * the named network interface device structure of type `struct ifnet'.
  598. * In the above example, <pIf> will be pointing to the data structure that
  599. * describes the first LANCE network interface device if ifunit() is
  600. * successful.
  601. *
  602. * The six-byte Ethernet address is copied to <eHdr>, if the resolution of
  603. * <targetAddr> is successful.  <eHdr> must point to a buffer of at least
  604. * six bytes.
  605. *
  606. * RETURNS:
  607. * OK if the address is resolved successfully, or ERROR if <eHdr> is NULL,
  608. * <targetAddr> is invalid, or address resolution is unsuccessful.
  609. *
  610. * SEE ALSO:
  611. * etherOutput()
  612. */
  613. STATUS etherAddrResolve
  614.     (
  615.     struct ifnet        *pIf,           /* interface on which to send ARP req */
  616.     char                *targetAddr,    /* name or Internet address of target */
  617.     char                *eHdr,          /* where to return the Ethernet addr */
  618.     int                 numTries,       /* number of times to try ARPing */
  619.     int                 numTicks        /* number of ticks between ARPing */
  620.     )
  621.     {
  622.     struct sockaddr_in  sockInetAddr;
  623.     unsigned long addr;
  624.     int retVal = 0;
  625.     if (eHdr == NULL) /* user messed up */
  626.         return (ERROR);
  627.     /* the 'targetAddr' can either be the hostname or the actual Internet
  628.      * address.
  629.      */
  630.     if ((addr = (unsigned long) hostGetByName (targetAddr)) == ERROR &&
  631. (addr = inet_addr (targetAddr)) == ERROR)
  632. return (ERROR);
  633.     sockInetAddr.sin_len = sizeof(struct sockaddr_in);
  634.     sockInetAddr.sin_family = AF_INET;
  635.     sockInetAddr.sin_addr.s_addr = addr; 
  636.     /* return 0xffffffffffff for broadcast Internet address */
  637.     if (in_broadcast (sockInetAddr.sin_addr, pIf))
  638. {
  639.         bcopy ((char *) etherbroadcastaddr, eHdr, sizeof (etherbroadcastaddr));
  640. return (OK);
  641. }
  642.     /* 
  643.      * Try to resolve the Ethernet address by calling arpresolve() which
  644.      * may send ARP request messages out onto the Ethernet wire.
  645.      */
  646.     while ((numTries == -1 || numTries-- > 0) &&
  647.    (retVal = arpresolve ((struct arpcom *) pIf, 
  648.  (struct rtentry *)NULL, 
  649.  (struct mbuf *) NULL,
  650.  (struct sockaddr *)&sockInetAddr,
  651.  (UCHAR *)eHdr))
  652.    == 0)
  653.      taskDelay (numTicks);
  654.     if (retVal == 0) /* unsuccessful resolution */
  655.         return (ERROR);
  656.     return (OK);
  657.     }
  658. /*******************************************************************************
  659. *
  660. * etherTypeGet - get the type from an ethernet packet
  661. *
  662. * This routine returns a short that is the ethertype (defined in RFC
  663. * 1700) from either an 802.3 addressed packet or an RFC 894 packet.
  664. * Most packets are encoded as described in RFC 894 but 802.3 addressing
  665. * is also recognized.
  666. * RETURNS: A USHORT value that is the ethertype, or 0 on error.
  667. *
  668. * SEE ALSO:
  669. * .I "RFC 894, TCP/IP Illustrated,"
  670. * Volume 1, by Richard Stevens.
  671. */
  672. USHORT etherTypeGet
  673.     (
  674.     char *pPacket /* pointer to the beginning of the packet */
  675.     )
  676.     {
  677.     ENET_HDR* pEnetHdr;
  678.     struct llc* pLLCHdr;
  679.     USHORT ether_type;
  680.     /* Try for RFC 894 first as it's the most common. */
  681.     pEnetHdr = (ENET_HDR *)pPacket;
  682.     ether_type = ntohs(pEnetHdr->type);
  683.     /* Deal with 802.3 addressing. */
  684.     /* Here is the algorithm. */
  685.     /* If the ether_type is less than the MTU then we know that */
  686.     /* this is an 802.x address from RFC 1700. */
  687.     if (ether_type < ETHERMTU)
  688. {
  689. pLLCHdr = (struct llc *) pPacket;
  690. /* Now it may be IP over 802.x so we check to see if the */
  691. /* destination SAP is IP, if so we snag the ethertype from the */
  692. /* proper place. */
  693. /* Now if it's NOT IP over 802.x then we just used the DSAP as */
  694. /* the ether_type.  */
  695. if (pLLCHdr->llc_dsap == LLC_SNAP_LSAP)
  696.     ether_type = ntohs(pLLCHdr->llc_un.type_snap.ether_type);
  697. else
  698.     ether_type = pLLCHdr->llc_dsap;
  699. }
  700.     /* Finally!  Now, who says we should have standards comittees? */
  701.     /* Wouldn't it be easier, and cheaper just to shoot these losers? */
  702.     return (ether_type);
  703.     }
  704. /******************************************************************************
  705. *
  706. * etherInputHook - the system etherInputHook
  707. *
  708. * This routine multiplexes packets to multiple input hooks.
  709. *
  710. * RETURNS: TRUE if one of the routines that it called returns TRUE indicating
  711. * that the hook routine "ate" the packet, otherwise it returns FALSE.
  712. *
  713. * NOMANUAL
  714. *
  715. */
  716. LOCAL BOOL etherInputHook
  717.     (
  718.     struct ifnet *pIf, 
  719.     char *buffer, 
  720.     int length
  721.     )
  722.     {
  723.     HOOK_ENTRY *pHookEnt;
  724.     extern LIST inputHookList;
  725.     for (pHookEnt = (HOOK_ENTRY *)lstFirst(&inputHookList); 
  726.          pHookEnt != NULL; pHookEnt = (HOOK_ENTRY *)lstNext(&pHookEnt->node))
  727. {
  728.         if ((* pHookEnt->routine) (pIf, buffer, length))
  729.             return (TRUE);
  730. }
  731.     return (FALSE);
  732.     }
  733. /******************************************************************************
  734. *
  735. * etherOutputHook - the system etherOutputHook
  736. *
  737. * This routine is used to multiplex access to output hooks.
  738. *
  739. * RETURNS: TRUE if one of its callee consumed the packet otherwise returns
  740. * FALSE.
  741. *
  742. * NOMANUAL
  743. */
  744. LOCAL BOOL etherOutputHook
  745.     (
  746.     struct ifnet *pIf, 
  747.     char *buffer, 
  748.     int length
  749.     )
  750.     {
  751.     HOOK_ENTRY* pHookEnt;
  752.     extern LIST outputHookList;
  753.     for (pHookEnt = (HOOK_ENTRY *)lstFirst(&outputHookList); 
  754.          pHookEnt != NULL; pHookEnt = (HOOK_ENTRY *)lstNext(&pHookEnt->node))
  755. {
  756.         if ((* pHookEnt->routine) (pIf, buffer, length))
  757.             return (TRUE);
  758. }
  759.     return (FALSE);
  760.     }
  761. LOCAL BOOL endEtherInputHookRtn
  762.     (
  763.     void *  pCookie,
  764.     long  type,
  765.     M_BLK_ID  pMblk,  /* Received frame (with link-level header). */
  766.     LL_HDR_INFO * pLinkHdrInfo,
  767.     void *  pSpare  /* Extra protocol data. Unused. */
  768.     )
  769.     {
  770.     HOOK_ENTRY * pHookEnt = (HOOK_ENTRY*) pSpare;
  771.     char devName[32];
  772.     char packetData [ETHERMTU + SIZEOF_ETHERHEADER];
  773.     struct ifnet fakeIF;
  774.     extern LIST inputHookList;
  775.     int flags;
  776.     int len;
  777.     END_OBJ* pEnd=(END_OBJ*)pCookie;
  778.     int ifHdrLen=0;
  779.     bzero ( (char *)&fakeIF, sizeof (fakeIF));
  780.     fakeIF.if_name = &devName[0];
  781.     strcpy (fakeIF.if_name, pEnd->devObject.name);
  782.     fakeIF.if_unit = pEnd->devObject.unit;
  783.     muxIoctl (pHookEnt->pCookie, EIOCGFLAGS, (caddr_t)&flags);
  784.     fakeIF.if_flags = flags;
  785.     
  786.     /* Get the Link Level header length . */
  787.     if (muxIoctl (pHookEnt->pCookie, EIOCGHDRLEN, (caddr_t)&ifHdrLen) != OK)
  788.         fakeIF.if_hdrlen = 0;
  789.     else
  790.         fakeIF.if_hdrlen = (UCHAR)ifHdrLen;
  791.     len = netMblkToBufCopy(pMblk, (char *)packetData, NULL);
  792.     for (pHookEnt = (HOOK_ENTRY *)lstFirst (&inputHookList); 
  793.          pHookEnt != NULL; pHookEnt = (HOOK_ENTRY *)lstNext (&pHookEnt->node))
  794.         {
  795.         if ( (* pHookEnt->routine) (&fakeIF, packetData, len))
  796.             {
  797.             netMblkClChainFree (pMblk); /* hook has consumed the packet */
  798.             return (TRUE);
  799.             }
  800.         }
  801.     return (FALSE);
  802.     }
  803. /********************************************************************************
  804. *
  805. * nptEtherInputHookRtn- EtherInputHook Receive Routine
  806. *
  807. * This is the receive routine for the etherInputHook while binding to an NPT 
  808. * device. This is very similar to endEtherInputHook except that it takes a
  809. * different arguments.
  810. *
  811. */
  812. LOCAL BOOL nptEtherInputHookRtn
  813.     (
  814.     void *      pCallBackId,    /* Sent down in muxTkBind(); same as pSpare 
  815.                                    as in muxBind() 
  816.                                  */
  817.     long        type,           /* SNARF */
  818.     M_BLK_ID    pMblk,          /* Received frame (with link-level header). */
  819.     void *      pSpareData      /* Extra protocol data */
  820.     )
  821.     {
  822.     HOOK_ENTRY * pHookEnt = (HOOK_ENTRY*) pCallBackId;
  823.     char devName[32];
  824.     char packetData [ETHERMTU + SIZEOF_ETHERHEADER];
  825.     struct ifnet fakeIF;
  826.     extern LIST inputHookList;
  827.     int flags;
  828.     int len;
  829.     END_OBJ* pEnd=PCOOKIE_TO_ENDOBJ(pHookEnt->pCookie);
  830.     int ifHdrLen=0;
  831.     bzero ( (char *)&fakeIF, sizeof (fakeIF));
  832.     fakeIF.if_name = &devName[0];
  833.     strcpy (fakeIF.if_name, pEnd->devObject.name);
  834.     fakeIF.if_unit = pEnd->devObject.unit;
  835.     muxIoctl (pHookEnt->pCookie, EIOCGFLAGS, (caddr_t)&flags);
  836.     fakeIF.if_flags = flags;
  837.     /* Get the Link Level header length . */
  838.     if (muxIoctl (pHookEnt->pCookie, EIOCGHDRLEN, (caddr_t)&ifHdrLen) != OK)
  839.         fakeIF.if_hdrlen = 0;
  840.     else
  841.         fakeIF.if_hdrlen = (UCHAR)ifHdrLen;
  842.     len = netMblkToBufCopy(pMblk, (char *)packetData, NULL);
  843.     for (pHookEnt = (HOOK_ENTRY *)lstFirst (&inputHookList);
  844.          pHookEnt != NULL; pHookEnt = (HOOK_ENTRY *)lstNext (&pHookEnt->node))
  845.         {
  846.         if ( (* pHookEnt->routine) (&fakeIF, packetData, len))
  847.             {
  848.             netMblkClChainFree (pMblk); /* hook has consumed the packet */
  849.             return (TRUE);
  850.             }
  851.         }
  852.     return (FALSE);
  853.     }