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

VxWorks

开发平台:

C/C++

  1. /* proxyArpLib.c - proxy Address Resolution Protocol (ARP) server library */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01p,07may02,kbw  man page edits
  8. 01o,26mar02,vvv  fixed proxy broadcast storm (SPR #74518)
  9. 01n,07dec01,vvv  fixed proxy broadcast forwarding enabled by proxyPortFwdOn
  10.  (SPR #71656)
  11. 01m,05nov01,vvv  fixed transfer of broadcasts across networks (SPR #70768)
  12. 01l,15oct01,rae  merge from truestack ver 01p, base o1h (cleanup)
  13. 01k,26feb01,spm  fixed transfer of broadcasts across networks (SPR #31718)
  14. 0ij,07feb01,spm  added merge record for 30jan01 update from version 01i of
  15.                  tor2_0_x branch (base 01h) and fixed modification history;
  16.                  removed excess code from merge
  17. 01i,30jan01,ijm  merged SPR# 28602 fixes (proxy ARP services are obsolete);
  18.                  added permanent flag to proxy ARP entries and fixed handling
  19.                  of ARP requests for local addresses
  20. 01h,09feb99,fle  doc: put the library description chart inside .CS / .CE
  21.                  markups
  22.  + and removed dash line to stay in the INTERNAL field
  23. 01g,14dec97,jdi  doc: cleanup.
  24. 01f,25oct97,kbw  fixed man page problems found in beta review
  25. 01e,15apr97,kbw  fixed minor format problems in man page
  26. 01d,29jan97,vin  replaced routeCmd with proxyRouteCmd which adds an 
  27.  explicit network mask of 0xffffffff. Always added
  28.  the route before adding the arp entry.
  29. 01c,22nov96,vin  added cluster support replaced m_gethdr(..) with 
  30.  mHdrClGet(..).
  31. 01h,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  32. 01g,13nov92,dnw  added include of semLibP.h
  33. 01f,21sep92,jdi  Documentation cleanup.
  34. 01e,16aug92,elh  documentation changes.
  35. 01d,15jun92,elh  changed parameters, general cleanup. 
  36. 01c,04jun92,ajm  quieted ansi warnings on netTypeAdd parameters
  37. 01b,26may92,rrr  the tree shuffle
  38.  -changed includes to have absolute path from h/
  39. 01a,20sep91,elh  written.
  40. */
  41. /*
  42. DESCRIPTION
  43. This library implements a proxy ARP server that uses the Address Resolution
  44. Protocol (ARP) to make physically distinct networks appear as one logical
  45. network (that is, the networks share the same address space). The server
  46. forwards ARP messages between the separate networks so that hosts on the
  47. main network can access hosts on the proxy network without altering their
  48. routing tables.
  49. The proxyArpLibInit() initializes the server and adds this library to the
  50. VxWorks image.  This happens automatically if INCLUDE_PROXY_SERVER is
  51. defined at the time the image is built.  The proxyNetCreate() and
  52. proxyNetDelete() routines will enable and disable the forwarding of ARP
  53. messages between networks. The proxyNetShow() routine displays the current
  54. set of proxy networks and the main network and known clients for each.
  55. By default, this server automatically adds a client when it first detects
  56. an ARP message from that host. A VxWorks target can also register as
  57. a client with the proxyReg() routine and remove that registration with
  58. the proxyUnreg() routine. See the proxyLib manual pages for details.
  59. To minimize traffic on the main network, the proxy server will only forward
  60. broadcast packets to the specified destination ports visible with the
  61. proxyPortShow() routine.  The proxyPortFwdOn() and proxyPortFwdOff() routines
  62. will alter the current settings. Initially, broadcast forwarding is not
  63. active for any ports.
  64. INCLUDE FILES: proxyArpLib.h
  65. SEE ALSO: proxyLib, RFC 925, RFC 1027, RFC 826
  66. INTERNAL
  67. Proxy Server Structures
  68. The proxy server must hold information about each of the proxy networks.
  69. A proxy network is defined by a proxy network structure (PROXY_NET) which
  70. contains the local interface addresses for each network and a list of the
  71. current proxy clients. The proxyNetList variable stores all of the proxy
  72. network information.
  73. Proxy Clients
  74. A proxy client corresponds to a host on a proxy network.  The proxy server
  75. stores information about each proxy client in the PROXY_CLNT structure.
  76. By default, the server adds a client when it detects the initial ARP message
  77. from the host. Clients may also be added and deleted explicitly with
  78. proxyLib routines.
  79. The proxy client information is available as both a hash table and a linked
  80. list. The hash table (called clientTbl) provides fast lookup using the
  81. client IP address as the key.  Each proxy network structure provides a
  82. third method for accessing a particular proxy client on that network through
  83. the clientList element of the structure.
  84. The combined collection of proxy ARP structures (i.e the proxyNetList, and
  85. the clientTbl) are protected by a single mutual exclusion semaphore.
  86. Registering and Unregistering Proxy Clients
  87. A vxWorks target can explicitly register and unregister itself as a 
  88. proxy client by generating and sending messages of an unused Ethernet
  89. type to the server. These messages use the format given by the PROXY_MSG
  90. structure and have either operation type PROXY_REG or PROXY_UNREG.  If
  91. the proxy server receives one of these messages it performs the appropriate
  92. action by either adding or deleting the node as a proxy client.  The server
  93. notifies the client on completion by sending back an ACK message. 
  94. By default, the proxy server registers a client when it detects the initial
  95. ARP message from a host and never removes that registration. As a result,
  96. the proxy client component is normally not required. The explicit registration
  97. which that library allows is only necessary for protocols such as BOOTP
  98. that may require proxy ARP services before configuring an interface with
  99. an IP address (which sends a gratuitous ARP message).
  100. There are two main hooks into this library from the network modules.  The
  101. in_arpinput() routine in if_ether.c uses the first hook to handle special
  102. ARP processing.  When the server is active, that routine processes all valid
  103. ARP messages as follows:
  104.                     if (proxyArpHook == NULL ||
  105.                         (* proxyArpHook)
  106.                          ( (struct arpcom *)m->m_pkthdr.rcvif, m) == FALSE)
  107.                         in_arpinput(m);
  108. The proxyArpHook function pointer uses the proxyArpInput() routine to forward
  109. any ARP requests or replies as appropriate. That routine typically returns
  110. FALSE since the standard ARP processing handles most cases correctly.
  111. The ipintr() routine in ip_input.c uses a similar function pointer
  112. (proxyBroadcastHook) so that the proxy ARP server may forward selected
  113. broadcast packets to and from the main network with the proxyBroadcastInput
  114. routine.
  115. VXWORKS AE PROTECTION DOMAINS
  116. Under VxWorks AE, the functions you assign for either 'proxyArpHook' 
  117. or 'proxyBroadcastHook' must be valid within the kernel protection domain. 
  118. This restriction does not apply under non-AE versions of VxWorks.  
  119. Structure Chart:
  120. .CS
  121.  v          v
  122.         proxyArpLibInit  proxyNetShow
  123.        (in_arpinput)
  124.      v
  125.  ----------------proxyArpInput------------------------------------------
  126. /     / |                                   
  127.       v | |  |    |   |
  128. | proxyArpReplyFwd------|---------------|--|---------------------|-------->
  129. |             |         v |  |                    |        |
  130. v       | proxyArpRequestFwd---- -|--|---------------------|-------->
  131. proxyArpReply |  /    |  |               |        |
  132.        |      | |    |  |               |        |
  133.        v      v v           |  |                     |        |
  134.       proxyArpSend          |  |               |        |
  135. |  |               |        |
  136. |  |        |        |
  137. (ipintr) |  |               |        |
  138.            v |  |               |        |
  139.   --proxyBroadcastInput-----------------|-->               |        |
  140.  /           |             |  |               |        |
  141.  v           ------        <-----------/  |     (do_protocol)  |        |
  142. proxyBroadcast |     |    |       v        |        |
  143.                |     |    |   proxyMsgInput----->        |
  144.              |----/         |    |                   | |        |
  145.              |     |    |                   | |        |
  146.              |             |    v            |      | |        |
  147.              |              | proxyIsAMainNet |      | |        |
  148.              |     v       |          | /---/  |        |
  149.      |proxyNetCreate|            | |      |        |
  150.      |      v     |          | |      v        |
  151.      |proxyNetDelete|       ----------------------|-proxyClientAdd|
  152.      |     v      v      /  | v     v   |
  153.      |     proxyNetFind<-/ |proxyClientDelete|
  154.      | v       v         |
  155.       proxyClientFind<-/
  156.       ------------
  157.      v      | v    v
  158. proxyPortFwdOn           |        proxyPortFwdOff proxyPortShow
  159.       |                   |         |        |    |
  160.       ------------------>|<-------/<--------------------/     v
  161.           v      proxyPortPrint
  162.            proxyPortTblFind
  163. .CE
  164. */
  165. /* includes */
  166. #include "vxWorks.h"
  167. #include "netinet/if_ether.h"
  168. #include "proxyArpLib.h"
  169. #include "sys/socket.h"
  170. #include "net/if_arp.h"
  171. #include "net/route.h"
  172. #include "net/if.h"
  173. #include "net/mbuf.h"
  174. #include "netinet/in_systm.h"
  175. #include "netinet/ip.h"
  176. #include "sys/ioctl.h"
  177. #include "netinet/in.h"
  178. #include "errno.h"
  179. #include "hashLib.h"
  180. #include "netinet/ip_var.h"
  181. #include "netinet/udp.h"
  182. #include "netinet/udp_var.h"
  183. #include "inetLib.h"
  184. #include "string.h"
  185. #include "stdlib.h"
  186. #include "logLib.h"
  187. #include "arpLib.h"
  188. #include "routeLib.h"
  189. #include "stdio.h"
  190. #include "net/unixLib.h"
  191. #include "net/if_subr.h"
  192. #include "private/semLibP.h"
  193. #include "memPartLib.h"
  194. #ifdef VIRTUAL_STACK
  195. #include "netinet/vsLib.h"
  196. #include "netinet/vsProxyArp.h"
  197. #endif
  198. /* defines */
  199. #define CLNT_TBL_SZ 8 /* default client table sz 2^8 */
  200. #define PORT_TBL_SZ 8 /* default port table sz 2^8 */
  201. /* useful macros */
  202. #define proxyIsAproxyNet(pAddr) ((proxyNetFind (pAddr) == NULL) ? 
  203. (FALSE) : (TRUE))
  204. #define proxyIsAClient(pAddr) ((proxyClientFind ((pAddr)) == NULL) ?
  205. (FALSE) : (TRUE))
  206. #define NODE_TO_CLIENT(pNode) (PROXY_CLNT *) 
  207. ((u_long)(pNode + 1) - sizeof (PROXY_CLNT))
  208. /* fill in sockaddr_in structure */
  209. #define SIN_FILL(pSin, family, addr, port)
  210.     {
  211.     bzero ((caddr_t) (pSin), sizeof (struct sockaddr_in));
  212.     (pSin)->sin_len = sizeof(struct sockaddr_in);
  213.     (pSin)->sin_family = (family);
  214.     (pSin)->sin_addr.s_addr = (addr);
  215.     (pSin)->sin_port = (port);
  216.     }
  217. /* globals */
  218. #ifndef VIRTUAL_STACK
  219. /* debug variables */
  220. BOOL arpDebug              = FALSE; /* ARP debug messages */
  221. BOOL proxyArpVerbose       = FALSE; /* proxy ARP messages */
  222. BOOL proxyBroadcastVerbose = FALSE; /* broadcast messages */
  223. /* enabling variables */
  224. BOOL proxyBroadcastFwd     = TRUE; /* forward broadcasts */
  225. BOOL arpRegister       = TRUE; /* use ARP message to */
  226.   /* register clients */
  227. int clientTblSizeDefault  = CLNT_TBL_SZ; /* default size  */
  228. int portTblSizeDefault    = PORT_TBL_SZ; /* default size  */
  229. /* locals */
  230. /*
  231.  * proxy semahore & semid and options and structures
  232.  * protected by proxySem (clientTbl, proxyNetList)
  233.  */
  234. LOCAL SEMAPHORE proxySem; /* proxy ARP semphore */
  235. LOCAL SEM_ID proxySemId      = &proxySem;
  236. int proxySemOptions     = (SEM_Q_FIFO | SEM_DELETE_SAFE );
  237. LOCAL HASH_ID clientTbl     = NULL; /* hashed clients     */
  238. LOCAL LIST proxyNetList; /* proxy network list */
  239. /* port table sem semid and options, and port table*/
  240. LOCAL SEMAPHORE portTblSem;
  241. LOCAL SEM_ID    portTblSemId     = &portTblSem;
  242. int portTblSemOptions   = (SEM_Q_FIFO | SEM_DELETE_SAFE );
  243. LOCAL HASH_ID portTbl            = NULL; /* hashed ports       */
  244. LOCAL BOOL proxyLibInitialized = FALSE; /* server initialized */
  245. LOCAL int hashKeyArg      = 425871;  /* hash key        */
  246. #endif /* VIRTUAL_STACK */
  247. /* forward declarations */
  248. IMPORT FUNCPTR proxyArpHook;
  249. IMPORT FUNCPTR proxyBroadcastHook;
  250. IMPORT int in_cksum ();
  251. IMPORT int in_broadcast ();
  252. /* locals */
  253. /* hook routines */
  254. LOCAL void proxyBroadcastInput (struct mbuf *pMbuf, struct ifnet * pIf);
  255. LOCAL BOOL proxyArpInput (struct arpcom * pArpcom, struct mbuf * pMbuf);
  256. LOCAL void proxyMsgInput (struct arpcom * pArpcom, struct mbuf * pMbuf, 
  257.   int len);
  258. LOCAL void proxyArpReply (struct arpcom * pArpcom, struct mbuf * pMbuf,
  259.   int proto);
  260. LOCAL void proxyArpRequestFwd (struct in_addr * pClientAddr, 
  261.        struct mbuf * pMbuf);
  262. LOCAL void proxyArpReplyFwd (PROXY_CLNT * pClient, struct mbuf * pMbuf);
  263. LOCAL void proxyArpSend (struct ifnet * pIf, int op, int proto,
  264.          u_char * srcProtoAddr, u_char * dstHwAddr,
  265.  u_char * dstProtoAddr);
  266. LOCAL void proxyBroadcast (struct ifnet * pIf, struct mbuf * pMbuf, int ttl);
  267. LOCAL PROXY_NET * proxyNetFind (struct in_addr * pProxyAddr);
  268. LOCAL PROXY_CLNT * proxyClientFind (struct in_addr * clientAddr);
  269. LOCAL BOOL proxyIsAMainNet (struct in_addr * pMainAddr);
  270. LOCAL PORT_NODE * portTblFind (int port);
  271. LOCAL BOOL proxyPortPrint (PORT_NODE * pPort);
  272. LOCAL STATUS proxyRouteCmd (int destInetAddr, int gateInetAddr, int ioctlCmd); 
  273. LOCAL STATUS proxyClientAdd (struct arpcom * pArpcom,
  274.                              struct in_addr * pClientAddr,
  275.                              u_char * pClientHwAddr);
  276. LOCAL STATUS proxyClientDelete (struct in_addr * pClientAddr);
  277. LOCAL void proxyClientRemove (PROXY_CLNT * pClient);
  278. LOCAL M_BLK_ID proxyPacketDup (M_BLK_ID pMblk);
  279. /*******************************************************************************
  280. *
  281. * proxyArpLibInit - initialize proxy ARP
  282. *
  283. * This routine starts the proxy ARP server by initializing the required data
  284. * structures and installing the necessary input hooks.  It should be called
  285. *  only once; subsequent calls have no effect. The <clientSizeLog2> and
  286. * <portSizeLog2> parameters specify the internal hash table sizes. Each
  287. * must be equal to a power of two, or zero to use a default size value.
  288. *
  289. * RETURNS: OK, or ERROR if unsuccessful.
  290. */
  291. STATUS proxyArpLibInit
  292.     (
  293.     int clientSizeLog2, /* client table size as power of two */
  294.     int portSizeLog2 /* port table size as power of two   */
  295.     )
  296.     {
  297.     if (proxyLibInitialized) /* already initialized */
  298. return (OK);
  299. #ifdef VIRTUAL_STACK
  300. /* need to initialize vars */
  301. arpDebug              = FALSE;  /* ARP debug messages */
  302. proxyArpVerbose       = FALSE;  /* proxy ARP messages */
  303. proxyBroadcastVerbose = FALSE;  /* broadcast messages */
  304. /* enabling variables */
  305. proxyBroadcastFwd     = TRUE;   /* forward broadcasts */
  306. arpRegister           = TRUE;   /* use ARP message to */
  307. /* to register clients */
  308. clientTblSizeDefault  = CLNT_TBL_SZ; /* default size  */
  309. portTblSizeDefault    = PORT_TBL_SZ; /* default size  */
  310. proxySemId          = &proxySem;
  311. proxySemOptions     = (SEM_Q_FIFO | SEM_DELETE_SAFE );
  312. clientTbl           = NULL;     /* hashed clients     */
  313. /* port table sem semid and options, and port table*/
  314. portTblSemId        = &portTblSem;
  315. portTblSemOptions   = (SEM_Q_FIFO | SEM_DELETE_SAFE );
  316. portTbl             = NULL;     /* hashed ports       */
  317. proxyLibInitialized = FALSE;    /* server initialized */
  318. hashKeyArg          = 425871;   /* hash key           */
  319. #endif /* VIRTUAL_STACK */
  320.     /* use default values if zero passed */
  321.     clientSizeLog2 = (clientSizeLog2 == 0) ? clientTblSizeDefault :
  322.      clientSizeLog2;
  323.     portSizeLog2   = (portSizeLog2 == 0) ? portTblSizeDefault : portSizeLog2;
  324.     lstInit (&proxyNetList);
  325.     if ((proxySemId = semMCreate (proxySemOptions)) == NULL) 
  326. return (ERROR);
  327.     if ((portTblSemId = semMCreate (portTblSemOptions)) == NULL)
  328. {
  329. semDelete (proxySemId);
  330. return (ERROR);
  331. }
  332.     if ((clientTbl = hashTblCreate (clientSizeLog2, hashKeyCmp, hashFuncModulo,
  333.     hashKeyArg)) == NULL)
  334. {
  335. semDelete (proxySemId);
  336. semDelete (portTblSemId);
  337. return (ERROR);
  338. }
  339.     if ((portTbl = hashTblCreate (portSizeLog2, hashKeyCmp, hashFuncModulo,
  340.   hashKeyArg)) == NULL)
  341. {
  342. semDelete (proxySemId);
  343. semDelete (portTblSemId);
  344. hashTblDelete (clientTbl);
  345. return (ERROR);
  346. }
  347.     proxyBroadcastHook = (FUNCPTR) proxyBroadcastInput;
  348.     netTypeAdd (PROXY_TYPE, (FUNCPTR) proxyMsgInput);
  349.     proxyArpHook = (FUNCPTR) proxyArpInput;
  350.     proxyLibInitialized = TRUE;
  351.     return (OK);
  352.     }
  353. /*******************************************************************************
  354. *
  355. * proxyArpInput - proxy ARP input hook
  356. *
  357. * The proxyArpInput routine completes the gateway transparency between a
  358. * proxy network and the main network, allowing the physically distinct
  359. * hosts to share the same logical subnet. The standard ARP processing is
  360. * able to manage all ARP messages except requests from a proxy client for
  361. * a host on the main network. The arpintr routine in the if_ether.c module
  362. * calls this routine to relay those requests to the destination network and
  363. * return the replies. The routine returns TRUE for those messages to prevent
  364. * redundant (and usually incorrect) processing by the in_arpinput routine.
  365. *
  366. * The <pArpcom> parameter identifies the interface which received the
  367. * ARP message contained in the <pMbuf> mbuf chain.
  368. *
  369. * RETURNS: TRUE if message handled, or FALSE otherwise.
  370. *
  371. * NOMANUAL
  372. */
  373. LOCAL BOOL proxyArpInput
  374.     (
  375.     struct arpcom * pArpcom, /* arpcom structure  */
  376.     struct mbuf * pMbuf /* mbuf chain */
  377.     )
  378.     {
  379.     struct ether_arp *  pArp;  /* ARP message */
  380.     struct in_addr  srcAddr;  /* source address */
  381.     struct in_addr  dstAddr;  /* destination address */
  382.     u_short  arpOp;  /* ARP operation */
  383.     PROXY_CLNT *  pClient;  /* registration of proxy client */
  384.     PROXY_NET *         pNet;           /* proxy network */
  385.     /*
  386.      * Extract information from the ARP message which the arpintr()
  387.      * routine has validated.
  388.      */
  389.     pArp = mtod (pMbuf, struct ether_arp *);
  390.     arpOp = ntohs (pArp->arp_op);
  391.     bcopy (pArp->arp_spa, (char *)&srcAddr, sizeof (srcAddr));
  392.     bcopy (pArp->arp_tpa, (char *)&dstAddr, sizeof (dstAddr));
  393.     if (arpDebug) /* ARP debugging info */
  394. {
  395.      logMsg ("op:%s (if 0x%x) src: 0x%x [%s] dst: 0x%x ",
  396. (arpOp == ARPOP_REQUEST) ? (int) "request" : (int) "reply",
  397. ntohl (pArpcom->ac_ipaddr.s_addr), ntohl (srcAddr.s_addr),
  398. (int) ether_sprintf (pArp->arp_sha), ntohl (dstAddr.s_addr), 0);
  399. if (arpOp != ARPOP_REQUEST)
  400.     logMsg ("[%s]", (int) ether_sprintf (pArp->arp_tha), 0, 0, 0, 0 ,0);
  401. logMsg ("n", 0, 0, 0, 0, 0, 0);
  402. }
  403.     /* Ignore any messages containing a broadcast address as the source. */
  404.     if (!(bcmp (pArp->arp_sha, etherbroadcastaddr, sizeof (pArp->arp_sha))))
  405.         {
  406.         m_freem (pMbuf);
  407.         return (TRUE);    /* Invalid message - skip standard ARP processing. */
  408.         }
  409.     semTake (proxySemId, WAIT_FOREVER);
  410.     switch (arpOp)
  411. {
  412. case ARPOP_REQUEST:
  413.             /*
  414.              * Handle any ARP requests which must cross a network boundary
  415.              * that the proxy server hides. The standard ARP processing
  416.              * cannot manage those situations. It will handle all requests
  417.              * from a main network since proxy ARP entries exist for all
  418.              * hosts on the proxy network.
  419.              */
  420.             if ((pNet = proxyNetFind (&pArpcom->ac_ipaddr)) != NULL)
  421.                 {
  422.                 /*
  423.                  * Received an ARP request from a proxy network. 
  424.                  * Add new client if enabled by arpRegister setting.
  425.                  */
  426.                 if (arpRegister && !proxyIsAClient (&srcAddr))
  427.                     (void) proxyClientAdd (pArpcom, &srcAddr, pArp->arp_sha);
  428.                 pClient = proxyClientFind (&dstAddr);
  429.                 if (pClient)
  430.                     {
  431.                     /*
  432.                      * The destination of the request is also a proxy client.
  433.                      * If it is on the same proxy network, ignore the request
  434.                      * since the client will reply for itself. If it is on
  435.                      * a different proxy network, the standard ARP processing
  436.                      * will reply correctly based on the proxy ARP entry.
  437.                      */
  438.                     if (pClient->pNet->proxyAddr.s_addr
  439.                             == pArpcom->ac_ipaddr.s_addr)
  440.                         {
  441.                         /* Client will answer - avoid proxy reply. */
  442.                         semGive (proxySemId);
  443.                         m_freem (pMbuf);
  444.                         return (TRUE);
  445.                         }
  446.                     }
  447.                 else
  448.                     {
  449.                     /*
  450.                      * The destination is not a proxy client. These ARP
  451.                      * requests from a proxy client for a different host on
  452.                      * the main network cannot be handled by the standard
  453.                      * ARP processing. If the destination's hardware address
  454.                      * is available, send a reply giving ours as an alias.
  455.                      * Otherwise, forward the request to the main network.
  456.                      */
  457.                     if (arpCmd (SIOCGARP, &dstAddr, (u_char *)NULL,
  458.                                 (int *) NULL) == OK ||
  459. pNet->proxyAddr.s_addr == dstAddr.s_addr ||
  460. pNet->mainAddr.s_addr == dstAddr.s_addr)
  461.                         proxyArpReply (pArpcom, pMbuf,
  462.                                        ntohs (pArp->arp_pro));
  463.                     else
  464.                         proxyArpRequestFwd (&srcAddr, pMbuf);
  465.                     semGive (proxySemId);
  466.                     m_freem (pMbuf);
  467.                     return (TRUE);    /* Skip standard ARP processing. */
  468.                     }
  469.                 }
  470.             break;
  471. case ARPOP_REPLY:
  472.          /*
  473.            * Received an ARP reply.  If it is a response to an earlier
  474.              * (forwarded) request, generate a reply to the proxy client
  475.              * supplying our hardware address as an alias. Once the 
  476.              * hardware address of the actual destination is in the
  477.              * ARP cache, the proxy server will be able to transparently
  478.              * forward packets from the proxy network to that host. 
  479.            */
  480.             pClient = proxyClientFind (&dstAddr);
  481.             if (pClient && (pClient->pNet->mainAddr.s_addr ==
  482.                                 pArpcom->ac_ipaddr.s_addr))
  483.                 {
  484.                 /*
  485.                  * Note: the second condition of the previous test is a
  486.                  * sanity check preventing the forwarding of replies
  487.                  * between proxy networks, although those messages should
  488.                  * never be sent since requests are not forwarded between
  489.                  * proxy networks in the first place.
  490.                  */
  491.                 proxyArpReplyFwd (pClient, pMbuf);
  492.                 /*
  493.                  * The standard ARP processing would only refresh an existing
  494.                  * entry, not create a new one, so add the entry for the
  495.                  * actual destination of the original ARP request.
  496.                  */
  497.                 arpCmd (SIOCSARP, &srcAddr, pArp->arp_sha, (int *) NULL);
  498.                 semGive (proxySemId);
  499.                 m_freem (pMbuf);
  500.                 return (TRUE);  /* Skip (redundant) standard ARP processing. */
  501.                 }
  502.             break;
  503. default:
  504.     break;
  505. }
  506.     semGive (proxySemId);
  507.     return (FALSE);  /* Standard ARP processing handles remaining cases. */
  508.     }
  509. /*******************************************************************************
  510. *
  511. * proxyArpReply - generate an ARP reply
  512. *
  513. * This routine responds to ARP request messages which would ordinarily
  514. * require forwarding across a network boundary hidden by the proxy server.
  515. * The server advertises the hardware address of its local interface instead
  516. * of the actual hardware address of the destination host. It will forward
  517. * the incoming data to the correct destination on the separate network.
  518. *
  519. * This routine usually handles ARP requests from the proxy network for a host
  520. * on the main network. The standard ARP processing is capable of responding
  521. * to requests from the main network since registering the proxy clients
  522. * creates the necessary proxy ARP entries, but hosts on a main network are
  523. * not registered.
  524. *
  525. * The <pArpcom> parameter identifies the interface which received the
  526. * ARP message contained in the <pMbuf> mbuf chain. The <proto> parameter
  527. * identifies the type of the protocol information for the new ARP message.
  528. * Currently, it is always ETHERTYPE_IP (0x800). 
  529. *
  530. * RETURNS: N/A
  531. *
  532. * NOMANUAL
  533. */
  534. LOCAL void proxyArpReply
  535.     (
  536.     FAST struct arpcom * pArpcom, /* arpcom structure   */
  537.     FAST struct mbuf * pMbuf, /* mbuf chain        */
  538.     int    proto /* format of protocol */
  539.     )
  540.     {
  541.     struct ether_arp * pArp; /* ARP message       */
  542.     struct in_addr srcAddr; /* source address     */
  543.     pArp = mtod (pMbuf, struct ether_arp *);
  544.     /*
  545.      * Add the original source to the ARP cache so that the server can
  546.      * transparently forward data from the proxy client to that host.
  547.      * Ignore failures caused if an entry already exists.
  548.      */
  549.     bcopy (pArp->arp_spa, (char *)&srcAddr, sizeof (srcAddr));
  550.     arpCmd (SIOCSARP, &srcAddr, (u_char *)pArp->arp_sha,  (int *)NULL);
  551.     /*  switch source and target addresses */
  552.     proxyArpSend ( (struct ifnet *) pArpcom, ARPOP_REPLY, proto,
  553.                   pArp->arp_tpa, pArp->arp_sha, pArp->arp_spa);
  554.     }
  555. /*******************************************************************************
  556. *
  557. * proxyArpRequestFwd - forward an ARP request
  558. *
  559. * This routine relays an ARP request message from a proxy network to a
  560. * main network when a proxy client attempts to contact a host across the
  561. * network boundary which the proxy server conceals. The server supplies
  562. * the hardware address of the local interface to the host on the main
  563. * network so that all traffic will be transparently forwarded to the
  564. * proxy client. The <pMbuf> parameter contains the original ARP request
  565. * sent by the proxy client using the <pClientAddr> address.
  566. *
  567. * RETURNS:  N/A
  568. *
  569. * NOMANUAL
  570. */
  571. LOCAL void proxyArpRequestFwd
  572.     (
  573.     struct in_addr * pClientAddr, /* proxy client addr */
  574.     struct mbuf *  pMbuf /* mbuf chain      */
  575.     )
  576.     {
  577.     PROXY_CLNT * pClient; /* proxy client      */
  578.     struct ether_arp * pArp; /* ARP message       */
  579.     struct sockaddr_in sin; /* interface sin     */
  580.     struct ifaddr * pIfa; /* interface address */
  581.     /* find the client's main network interface */
  582.     if ((pClient = proxyClientFind (pClientAddr)) == NULL)
  583. return;
  584.     SIN_FILL (&sin, AF_INET, pClient->pNet->mainAddr.s_addr, 0);
  585.     if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) == NULL)
  586. return;
  587.     if (proxyArpVerbose) /* print debugging info */
  588. logMsg ("(forwarding request to if 0x%x) ", ntohl (pClient->pNet->mainAddr.s_addr),
  589. 0, 0, 0, 0, 0);
  590.     /*
  591.      * Leave the client as the source protocol address so when the reply
  592.      * comes back we know where to forward the reply.
  593.      */
  594.     pArp = mtod (pMbuf, struct ether_arp *);
  595.     proxyArpSend (pIfa->ifa_ifp, ntohs (pArp->arp_op), ntohs (pArp->arp_pro),
  596.   pArp->arp_spa, pArp->arp_tha, pArp->arp_tpa);
  597.     }
  598. /*******************************************************************************
  599. *
  600. * proxyArpReplyFwd - forward an ARP reply
  601. *
  602. * This routine relays an ARP reply message from a main network to a
  603. * proxy network following an earlier transfer in the opposite direction.
  604. * The server supplies the hardware address of the local interface instead
  605. * of the actual destination host on the main network so that all traffic
  606. * from the proxy client will be transparently forwarded. The <pMbuf>
  607. * mbuf chain contains the original ARP reply intended for the  proxy client
  608. * indicated by the <pClient> parameter.
  609. *
  610. * RETURNS: N/A
  611. *
  612. * NOMANUAL
  613. */
  614. LOCAL void proxyArpReplyFwd
  615.     (
  616.     PROXY_CLNT *  pClient,    /* proxy client registration data */
  617.     struct mbuf *  pMbuf       /* original ARP message */
  618.     )
  619.     {
  620.     struct sockaddr_in sin; /* interface sin     */
  621.     struct ifaddr * pIfa; /* interface address */
  622.     struct ether_arp * pArp; /* ARP message       */
  623.     u_short  arpProto; /* ARP type      */
  624.     /* Find the interface connected to the proxy client. */
  625.     SIN_FILL (&sin, AF_INET, pClient->pNet->proxyAddr.s_addr, 0);
  626.     if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) == NULL)
  627. return;
  628.     if (proxyArpVerbose) /* print debugging info */
  629. logMsg ("(forwarding reply to if 0x%x)", ntohl (pClient->pNet->proxyAddr.s_addr),
  630. 0, 0, 0, 0, 0);
  631.     pArp = mtod (pMbuf, struct ether_arp *);
  632.     /*
  633.      * Replace (deprecated) trailer packets with the standard type value. It
  634.      * is theoretically possible to consume those messages since trailer
  635.      * responses are additional replies, but forward them anyway for safety.
  636.      */
  637.     if (ntohs (pArp->arp_pro) == ETHERTYPE_TRAIL)
  638.         arpProto = ETHERTYPE_IP;
  639.     else
  640.         arpProto = ntohs (pArp->arp_pro);
  641.     /*
  642.      * The client's registration data contains a snapshot of the hardware
  643.      * address at that time. Since all clients must register, the lack of
  644.      * dynamic updates (available with an ARP entry) is unimportant.
  645.      */
  646.     proxyArpSend (pIfa->ifa_ifp, ntohs (pArp->arp_op), arpProto,
  647.                   pArp->arp_spa, pClient->hwaddr, pArp->arp_tpa);
  648.     }
  649. /*******************************************************************************
  650. *
  651. * proxyArpSend - generate and send an ARP message
  652. *
  653. * This routine constructs and sends an ARP message over the network interface
  654. * specified by <pIf>.  <op> specifies the ARP operation, <proto> is the format
  655. * of protocol address.  <srcProtoAddr> is the source protocol address,
  656. * <dstHwAddr> is the destination hardware address and <dstProtoAddr> is the
  657. * destination protocol addresses.
  658. *
  659. * RETURNS: N/A
  660. *
  661. * NOMANUAL
  662. */
  663. LOCAL void proxyArpSend
  664.     (
  665.     struct ifnet * pIf, /* interface pointer  */
  666.     int op, /* ARP op */
  667.     int proto, /* ARP protocol */
  668.     u_char * srcProtoAddr, /* src ip address */
  669.     u_char * dstHwAddr, /* dest hw address */
  670.     u_char * dstProtoAddr /* dest ip address */
  671.     )
  672.     {
  673.     FAST struct mbuf * pMbuf; /* mbuf chain */
  674.     FAST struct ether_arp * pArp; /* ARP message */
  675.     struct ether_header * pEh; /* ether header */
  676.     struct sockaddr  sa; /* sockaddr structure */
  677.     if ((pMbuf = mHdrClGet(M_DONTWAIT, MT_DATA, sizeof(*pArp), TRUE)) == NULL)
  678. return;
  679.     pMbuf->m_len = sizeof(*pArp);
  680.     pMbuf->m_pkthdr.len = sizeof(*pArp);
  681.     MH_ALIGN(pMbuf, sizeof(*pArp));
  682.     pArp = mtod(pMbuf, struct ether_arp *); /* fill in ARP message */
  683.     bzero ((caddr_t) pArp, sizeof (struct ether_arp));
  684.     pArp->arp_hrd = htons (ARPHRD_ETHER);
  685.     pArp->arp_pro = htons (proto);
  686.     pArp->arp_hln = sizeof (pArp->arp_sha);
  687.     pArp->arp_pln = sizeof (pArp->arp_spa);
  688.     pArp->arp_op  = htons (op);
  689.     bcopy ((caddr_t) ((struct arpcom *) pIf)->ac_enaddr,
  690.    (caddr_t) pArp->arp_sha, sizeof (pArp->arp_sha));
  691.     bcopy ((caddr_t) srcProtoAddr, (caddr_t) pArp->arp_spa,
  692.    sizeof (pArp->arp_spa));
  693.     bcopy ((caddr_t) dstProtoAddr, (caddr_t) pArp->arp_tpa,
  694.    sizeof (pArp->arp_tpa));
  695.     bzero ((caddr_t) &sa, sizeof (sa));
  696.     sa.sa_family = AF_UNSPEC;
  697.     pEh = (struct ether_header *) sa.sa_data;
  698.     pEh->ether_type = ETHERTYPE_ARP; /* switched in ether_output */
  699.     if (op == ARPOP_REQUEST)
  700. {
  701.      bcopy ((caddr_t) etherbroadcastaddr, (caddr_t) pEh->ether_dhost,
  702.        sizeof (pEh->ether_dhost));
  703. }
  704.     else
  705. {
  706.      bcopy ((caddr_t) dstHwAddr, (caddr_t) pArp->arp_tha,
  707.        sizeof (pArp->arp_tha));
  708.      bcopy ((caddr_t) dstHwAddr, (caddr_t) pEh->ether_dhost,
  709.        sizeof (pEh->ether_dhost));
  710. }
  711.     if (proxyArpVerbose)
  712. {
  713.      logMsg ("%s (%x): src: 0x%x [%s] dst : 0x%x ", (op == ARPOP_REQUEST) ?
  714. (int) "request" : (int) "reply", proto,
  715. *((int *) pArp->arp_spa), (int) ether_sprintf (pArp->arp_sha),
  716. *((int *) pArp->arp_tpa), 0);
  717. if (op != ARPOP_REQUEST)
  718.     logMsg ("[%s]", (int) ether_sprintf (pArp->arp_tha), 0, 0, 0, 0, 0);
  719. logMsg ("n", 0, 0, 0, 0, 0, 0);
  720. }
  721.     (*pIf->if_output) (pIf, pMbuf, &sa, (struct rtentry *) NULL);
  722.     }
  723. /*******************************************************************************
  724. *
  725. * proxyNetCreate - create a proxy ARP network
  726. *
  727. * This routine activates proxy services between the proxy network connected
  728. * to the interface with the <proxyAddr> IP address and the main network
  729. * connected to the interface with the <mainAddr> address. Once registration
  730. * is complete, the proxy server will disguise the physically separated
  731. * networks as a single logical network. 
  732. *
  733. * The corresponding interfaces must be attached and configured with IP
  734. * addresses before calling this routine. If the proxy network shares the
  735. * same logical subnet number as the main network, the corresponding interface
  736. * to the proxy network must use a value of 255.255.255.255 for the netmask.
  737. *
  738. * RETURNS: OK, or ERROR if unsuccessful.
  739. *
  740. * ERRNO:
  741. *  S_proxyArpLib_INVALID_ADDRESS
  742. */
  743. STATUS proxyNetCreate
  744.     (
  745.     char *  proxyAddr, /* address of proxy network interface */
  746.     char *  mainAddr /* address of main network interface */
  747.     )
  748.     {
  749.     struct sockaddr_in  proxyAddrKey;
  750.     struct sockaddr_in  mainAddrKey;
  751.     PROXY_NET *  pNet;
  752.     struct ifaddr *  pIfa;
  753.     int  flags;
  754.     /*
  755.      * Verify that local interfaces can reach the addresses of the
  756.      * proxy and main networks.
  757.      */
  758.     SIN_FILL (&proxyAddrKey, AF_INET, inet_addr (proxyAddr), 0);
  759.     SIN_FILL (&mainAddrKey, AF_INET, inet_addr (mainAddr), 0);
  760.     if ( (ifa_ifwithaddr ( (struct sockaddr *)&mainAddrKey) == NULL) ||
  761.         ( (pIfa = ifa_ifwithaddr ( (struct sockaddr *)&proxyAddrKey)) == NULL))
  762.         {
  763.         errno = S_proxyArpLib_INVALID_ADDRESS;
  764.         return (ERROR);
  765.         }
  766.     if ((pNet = (PROXY_NET *) calloc (1, sizeof (PROXY_NET))) == NULL)
  767. return (ERROR);
  768.     semTake (proxySemId, WAIT_FOREVER);
  769.     /* Replace any existing proxy network entry with the new values. */
  770.     proxyNetDelete (proxyAddr);
  771.     pNet->proxyAddr    =  proxyAddrKey.sin_addr;
  772.     pNet->mainAddr     =  mainAddrKey.sin_addr;
  773.     lstInit (&pNet->clientList);
  774.     lstAdd (&proxyNetList, &pNet->netNode);
  775.     /*
  776.      * Add a proxy ARP entry allowing the standard ARP processing
  777.      * to reply to requests for this local interface from hosts on
  778.      * other networks. The ATF_PROXY flag indicates a "wildcard" hardware
  779.      * address. Ignore failures caused if an entry already exists.
  780.      */
  781.     flags = ATF_PUBL | ATF_PROXY | ATF_PERM;
  782.     arpCmd (SIOCSARP, &pNet->proxyAddr, NULL, &flags);
  783.     semGive (proxySemId);
  784.     return (OK);
  785.     }
  786. /*******************************************************************************
  787. *
  788. * proxyNetDelete - delete a proxy network
  789. *
  790. * This routine deletes the proxy network specified by <proxyAddr>.  It also
  791. * removes all the proxy clients that exist on that network.
  792. *
  793. * RETURNS: OK, or ERROR if unsuccessful.
  794. *
  795. */
  796. STATUS proxyNetDelete
  797.     (
  798.     char *   proxyAddr /* proxy net address  */
  799.     )
  800.     {
  801.     PROXY_NET * pNet; /* proxy network */
  802.     NODE * pNode; /* client node */
  803.     PROXY_CLNT * pClient; /* proxy client */
  804.     STATUS  status = ERROR; /* return value */
  805.     struct in_addr proxyAddrIn;
  806.     semTake (proxySemId, WAIT_FOREVER);
  807.     proxyAddrIn.s_addr = inet_addr (proxyAddr);
  808.     if ((pNet = proxyNetFind (&proxyAddrIn)) != NULL)
  809. { /* clear out the clients */
  810.         for (pNode = lstFirst (&pNet->clientList); pNode != NULL;)
  811.     {
  812.     pClient = NODE_TO_CLIENT (pNode);
  813.     proxyClientRemove (pClient);
  814.     pNode = lstNext (pNode);
  815.     KHEAP_FREE((caddr_t)pClient);
  816.     }
  817.      lstDelete (&proxyNetList, &pNet->netNode);
  818.      KHEAP_FREE((caddr_t)pNet);
  819. status = OK;
  820. }
  821.     semGive (proxySemId);
  822.     return (status);
  823.     }
  824. /*******************************************************************************
  825. *
  826. * proxyNetFind - find a proxy network structure
  827. *
  828. * This routine finds the proxy network structure associated 
  829. * with <proxyAddr>.  The `proxySemId' semaphore must already 
  830. * be taken before calling this routine.
  831. *
  832. * RETURNS: A PROXY_NET pointer if found, otherwise NULL.
  833. *
  834. * ERRNO: 
  835. *  S_proxyArpLib_INVALID_NET
  836. *
  837. * NOMANUAL
  838. */
  839. LOCAL PROXY_NET * proxyNetFind
  840.     (
  841.     struct in_addr * pProxyAddr /* proxy address */
  842.     )
  843.     {
  844.     PROXY_NET * pNet; /* proxy network */
  845.     for (pNet = (PROXY_NET *) lstFirst (&proxyNetList); (pNet != NULL);
  846.  pNet = (PROXY_NET *) lstNext (&pNet->netNode))
  847. if (pNet->proxyAddr.s_addr == pProxyAddr->s_addr)
  848.     return (pNet);
  849.     errno = S_proxyArpLib_INVALID_PROXY_NET;
  850.     return (NULL);
  851.     }
  852. /*******************************************************************************
  853. *
  854. * proxyIsAMainNet - is the interface a main network ?
  855. *
  856. * This routine determines if <mainAddr> is a main network.  
  857. * `proxySemId' must already be taken before this routine is called.
  858. *
  859. * RETURNS: TRUE if a main network, FALSE otherwise.
  860. *
  861. * NOMANUAL
  862. */
  863. LOCAL BOOL proxyIsAMainNet
  864.     (
  865.     struct in_addr * pMainAddr /* main address */
  866.     )
  867.     {
  868.     PROXY_NET * pNet; /* proxy network */
  869.     for (pNet = (PROXY_NET *) lstFirst (&proxyNetList); (pNet != NULL);
  870.  pNet = (PROXY_NET *) lstNext (&pNet->netNode))
  871. if (pNet->mainAddr.s_addr == pMainAddr->s_addr)
  872.    return (TRUE);
  873.     return (FALSE);
  874.     }
  875. /*******************************************************************************
  876. *
  877. * proxyNetShow - show proxy ARP networks
  878. *
  879. * This routine displays the proxy networks and their associated clients.
  880. *
  881. * EXAMPLE
  882. * .CS
  883. *     -> proxyNetShow
  884. *     main interface 147.11.1.182 proxy interface 147.11.1.183
  885. *        client 147.11.1.184
  886. * .CE
  887. *
  888. * RETURNS: N/A
  889. *
  890. * INTERNAL
  891. * calls printf while semaphore taken.
  892. */
  893. void proxyNetShow (void)
  894.     {
  895.     PROXY_NET * pNet; /* proxy net */
  896.     PROXY_CLNT * pClient; /* proxy client */
  897.     NODE * pNode; /* pointer to node */
  898. /* address in ascii */
  899.     char  asciiAddr [ INET_ADDR_LEN ];
  900.     semTake (proxySemId, WAIT_FOREVER);
  901.     for (pNet = (PROXY_NET *) lstFirst (&proxyNetList);
  902.  pNet != NULL; pNet = (PROXY_NET *) lstNext (&pNet->netNode))
  903. {
  904. inet_ntoa_b (pNet->mainAddr, asciiAddr);
  905. printf ("main interface %s ", asciiAddr);
  906. inet_ntoa_b (pNet->proxyAddr, asciiAddr);
  907. printf ("proxy interface %sn", asciiAddr);
  908. for (pNode = lstFirst (&pNet->clientList); pNode != NULL;
  909.      pNode = lstNext (pNode))
  910.     {
  911.     pClient = NODE_TO_CLIENT (pNode);
  912.     inet_ntoa_b (pClient->ipaddr, asciiAddr);
  913.     printf ("    client:%sn", asciiAddr);
  914.     }
  915. }
  916.     semGive (proxySemId);
  917.     }
  918. /*******************************************************************************
  919. *
  920. * proxyClientAdd - add a proxy client
  921. *
  922. * This routine adds the client, whose ip address is <pArpcom>.ac_ipaddr, onto 
  923. * the proxy network identified by <pProxyNetAddr>.
  924. *
  925. * RETURNS: OK, or ERROR if unsuccessful.
  926. *
  927. * ERRNO:
  928. *  S_proxyArpLib_INVALID_ADDRESS
  929. *
  930. * NOMANUAL
  931. */
  932. LOCAL STATUS proxyClientAdd
  933.     (
  934.     struct arpcom *  pArpcom,  /* interface on proxy network */
  935.     struct in_addr *  pClientAddr,  /* client internet address */
  936.     u_char *  pClientHwAddr  /* client hardware address */
  937.     )
  938.     {
  939.     PROXY_NET *  pNet;  /* proxy net */
  940.     PROXY_CLNT *  pClient;  /* proxy client  */
  941.     struct sockaddr_in  sin; /* sin structure  */
  942.     struct ifaddr *  pIfa; /* interface address */
  943.     struct in_addr *  pProxyNetAddr; /* proxy net address */
  944.     int flags;  /* ARP flags */
  945.     /* validate addresses */
  946.     pProxyNetAddr = &pArpcom->ac_ipaddr;
  947.     if ((in_netof (*pProxyNetAddr) != in_netof (*pClientAddr)) ||
  948.         in_broadcast (*pClientAddr, (struct ifnet *)pArpcom))
  949. {
  950. errno = S_proxyArpLib_INVALID_ADDRESS;
  951. return (ERROR);
  952. }
  953.     if ((pClient = (PROXY_CLNT *) KHEAP_ALLOC(sizeof(PROXY_CLNT))) == NULL)
  954. return (ERROR);
  955.     bzero ((char *)pClient, sizeof(PROXY_CLNT));
  956.     semTake (proxySemId, WAIT_FOREVER);
  957.     if (!proxyIsAproxyNet (pClientAddr) &&
  958.         ((pNet = (PROXY_NET *) proxyNetFind (pProxyNetAddr)) != NULL))
  959. {
  960. /* find main interface */
  961.      SIN_FILL (&sin, AF_INET, pNet->mainAddr.s_addr, 0);
  962.      if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) != NULL)
  963.     {
  964.     (void) proxyClientDelete (pClientAddr);
  965.     /*
  966.      * Create a cloneable route (which will ultimately produce a
  967.      * standard ARP entry for the client) and add the client to
  968.              * the active list.
  969.      */
  970.     if (proxyRouteCmd (pClientAddr->s_addr, pProxyNetAddr->s_addr, 
  971.   SIOCADDRT) == OK)
  972. {
  973. pClient->pNet = pNet;
  974. pClient->ipaddr = *pClientAddr;
  975.         bcopy (pClientHwAddr, pClient->hwaddr,
  976.                        sizeof (struct ether_addr));
  977.               
  978. hashTblPut (clientTbl, &pClient->hashNode);
  979. lstAdd (&pNet->clientList, &pClient->clientNode);
  980.                 /*
  981.                  * Send a gratuitous ARP request to update any entries
  982.                  * on the main network.
  983.                  */
  984.         proxyArpSend (pIfa->ifa_ifp, ARPOP_REQUEST, ETHERTYPE_IP,
  985.       (u_char *) pClientAddr, (u_char *) NULL,
  986.       (u_char *) pClientAddr);
  987.                 /*
  988.                  * Add a proxy ARP entry allowing the standard ARP processing
  989.                  * to reply to requests for this client from hosts on other
  990.                  * networks. Ignore failures caused if an entry already exists.
  991.                  */
  992.                 flags = ATF_PUBL | ATF_PROXY | ATF_PERM;
  993.                 arpCmd (SIOCSARP, pClientAddr, pClientHwAddr, &flags);
  994.         if (proxyArpVerbose)
  995.     logMsg ("added client 0x%x proxyNet 0x%xn",
  996.     ntohl (pClientAddr->s_addr), 
  997.     ntohl (pProxyNetAddr->s_addr), 0, 0, 0, 0);
  998. semGive (proxySemId);
  999. return (OK);
  1000. }
  1001.     }
  1002. else
  1003.     {
  1004.     if (proxyArpVerbose)
  1005. logMsg ("proxyClientAdd: no main if 0x%xn",
  1006. ntohl (pNet->mainAddr.s_addr), 0, 0, 0, 0, 0);
  1007.     }
  1008. }
  1009.     semGive (proxySemId);
  1010.     KHEAP_FREE((caddr_t)pClient);
  1011.     return (ERROR);
  1012.     }
  1013. /*******************************************************************************
  1014. *
  1015. * proxyClientDelete - delete a proxy client
  1016. *
  1017. * This routines deletes the proxy client specified by <pClientAddr>.
  1018. *
  1019. * RETURNS: OK, or ERROR if unsuccessful.
  1020. *
  1021. * NOMANUAL
  1022. */
  1023. LOCAL STATUS proxyClientDelete
  1024.     (
  1025.     struct in_addr * pClientAddr /* client address   */
  1026.     )
  1027.     {
  1028.     PROXY_CLNT * pClient; /* proxy client     */
  1029.     STATUS  status = ERROR; /* return status    */
  1030.     semTake (proxySemId, WAIT_FOREVER);
  1031.     if ((pClient = proxyClientFind (pClientAddr)) != NULL)
  1032. {
  1033. proxyClientRemove (pClient);
  1034. lstDelete (&pClient->pNet->clientList, &pClient->clientNode);
  1035.      if (proxyArpVerbose)
  1036.     logMsg ("deleted client 0x%xn", ntohl (pClientAddr->s_addr), 0, 
  1037.     0, 0, 0, 0);
  1038. status = OK;
  1039. }
  1040.     semGive (proxySemId);
  1041.     if (pClient != NULL)
  1042. KHEAP_FREE((caddr_t)pClient);
  1043.     return (status);
  1044.     }
  1045. /*******************************************************************************
  1046. *
  1047. * proxyClientFind - find a proxy client
  1048. *
  1049. * This routine finds the proxy client structure associated with <pClientAddr>.
  1050. * Caller must have taken `proxySemId' before this routine is called.
  1051. *
  1052. * RETURNS: Pointer to PROXY_CLNT if found, NULL otherwise.
  1053. *
  1054. * ERRNO:
  1055. *  S_proxyArpLib_INVALID_CLIENT
  1056. *
  1057. * NOMANUAL
  1058. */
  1059. LOCAL PROXY_CLNT * proxyClientFind
  1060.     (
  1061.     struct in_addr * pClientAddr /* client address    */
  1062.     )
  1063.     {
  1064.     PROXY_CLNT client; /* client to find    */
  1065.     PROXY_CLNT * pClient; /* pointer to client */
  1066.     client.ipaddr.s_addr = pClientAddr->s_addr;
  1067.     if ((pClient = (PROXY_CLNT *)
  1068.    hashTblFind (clientTbl, &client.hashNode, 0)) == NULL)
  1069.      errno = S_proxyArpLib_INVALID_CLIENT;
  1070.     return (pClient);
  1071.     }
  1072. /*******************************************************************************
  1073. *
  1074. * proxyPortFwdOn - enable broadcast forwarding for a particular port
  1075. *
  1076. * This routine enables broadcasts destined for the port, <port>, to be 
  1077. * forwarded to and from the proxy network.  To enable all ports, specify 
  1078. * zero for <port>.
  1079. *
  1080. * RETURNS: OK, or ERROR if unsuccessful.
  1081. */
  1082. STATUS proxyPortFwdOn
  1083.     (
  1084.     int port /* port number  */
  1085.     )
  1086.     {
  1087.     PORT_NODE * pPort; /* port node  */
  1088.     if ((pPort = (PORT_NODE *) KHEAP_ALLOC(sizeof(PORT_NODE))) == NULL)
  1089. return (ERROR);
  1090.     bzero ((char *)pPort, sizeof(PORT_NODE));
  1091.     semTake (portTblSemId, WAIT_FOREVER);
  1092.     if (portTblFind (port) != NULL) /* already enabled so ok */
  1093. {
  1094. semGive (portTblSemId);
  1095. KHEAP_FREE((caddr_t)pPort);
  1096. return (OK);
  1097. }
  1098.     pPort->port = (int) port;
  1099.     (void) hashTblPut (portTbl, &pPort->hashNode);
  1100.     semGive (portTblSemId);
  1101.     return (OK);
  1102.     }
  1103. /*******************************************************************************
  1104. *
  1105. * proxyPortFwdOff - disable broadcast forwarding for a particular port
  1106. *
  1107. * This routine disables broadcast forwarding on port number <port>.  To
  1108. * disable the (previously enabled) forwarding of all ports via
  1109. * proxyPortFwdOn(), specify zero for <port>.
  1110. *
  1111. * RETURNS: OK, or ERROR if unsuccessful.
  1112. */
  1113. STATUS proxyPortFwdOff
  1114.     (
  1115.     int port /* port number */
  1116.     )
  1117.     {
  1118.     PORT_NODE * pPort; /* port node  */
  1119.     semTake (portTblSemId, WAIT_FOREVER);
  1120.     if ((pPort = portTblFind (port)) == NULL)
  1121. { /* not in port table so ok */
  1122. semGive (portTblSemId);
  1123. return (OK);
  1124. }
  1125.     (void) hashTblRemove (portTbl, &pPort->hashNode);
  1126.     semGive (portTblSemId);
  1127.     KHEAP_FREE((caddr_t)pPort);
  1128.     return (OK);
  1129.     }
  1130. /*******************************************************************************
  1131. *
  1132. * portTblFind - find the port node
  1133. *
  1134. * This routine finds the port node associated with port number <port>.
  1135. *
  1136. * RETURNS: A pointer to the port node, or NULL if not found.
  1137. *
  1138. * NOMANUAL
  1139. */
  1140. LOCAL PORT_NODE * portTblFind
  1141.     (
  1142.     int port /* port number */
  1143.     )
  1144.     {
  1145.     PORT_NODE portNode; /* port node */
  1146.     portNode.port = (int) port;
  1147.     return ((PORT_NODE *) hashTblFind (portTbl, &portNode.hashNode, 0));
  1148.     }
  1149. /*******************************************************************************
  1150. *
  1151. * proxyPortShow - show ports enabled for broadcast forwarding
  1152. *
  1153. * This routine displays the destination ports for which the proxy ARP server
  1154. * will forward broadcast messages between the physically separate networks.
  1155. *
  1156. * EXAMPLE
  1157. * .CS
  1158. *     -> proxyPortShow
  1159. *     enabled ports:
  1160. *        port 67
  1161. * .CE
  1162. *
  1163. * RETURNS: N/A
  1164. *
  1165. * INTERNAL
  1166. * calls printf() while semaphore taken.
  1167. */
  1168. void proxyPortShow (void)
  1169.     {
  1170.     semTake (portTblSemId, WAIT_FOREVER);
  1171.     printf ("enabled ports:n");
  1172.     if (portTblFind (0) != NULL)
  1173. printf ("    all ports enabledn");
  1174.     else
  1175. hashTblEach (portTbl, proxyPortPrint, 0);
  1176.     semGive (portTblSemId);
  1177.     }
  1178. /*******************************************************************************
  1179. *
  1180. * proxyPortPrint - print ports enabled
  1181. *
  1182. * This routine prints the list of enabled ports.
  1183. *
  1184. * RETURNS: TRUE (always)
  1185. *
  1186. * NOMANUAL
  1187. */
  1188. LOCAL BOOL proxyPortPrint
  1189.     (
  1190.     PORT_NODE * pPort /* port node  */
  1191.     )
  1192.     {
  1193.     printf ("    port %dn", pPort->port);
  1194.     return (TRUE);
  1195.     }
  1196. /*******************************************************************************
  1197. *
  1198. * proxyBroadcastInput - hook routine for broadcasts
  1199. *
  1200. * This routine is the hook routine that forwards a broadcast datagram
  1201. * <pMbuf> which was received on interface <pIf> to and from proxy interfaces.
  1202. * As a measure of control, it only forwards broadcasts that are destined for
  1203. * ports that have been previously enabled (with proxyPortFwdOn()).
  1204. * proxyBroadcastInput() gets called from routine ipintr(), in file ip_input.c.
  1205. * It assumes the datagram is whole (i.e., if the datagram was fragmented,
  1206. * then it was previously reassembled).
  1207. *
  1208. * If the broadcast datagram came from a main network, then forward the
  1209. * broadcast to all proxy network's that have the input interface as their
  1210. * main network.  If the broadcast came from a proxy network, then forward
  1211. * the broadcast to all other proxy networks that have that proxy network's main
  1212. * network as their main network (and forward it to the main network as well).
  1213. *
  1214. * INTERNAL
  1215. * Would we ever want to forward anything beyond UDP broadcasts (what
  1216. * about ICMP?)? The old backplane driver makes a local copy of broadcasts
  1217. * so we'll get an extra copy of broadcast packets if we are using the old
  1218. * backplane driver.
  1219. *
  1220. * RETURNS: N/A
  1221. *
  1222. * NOMANUAL
  1223. */
  1224. LOCAL void proxyBroadcastInput
  1225.     (
  1226.     struct mbuf * pMbuf, /* mbuf chain      */
  1227.     struct ifnet * pIf /* interface pointer */
  1228.     )
  1229.     {
  1230.     struct in_addr inputAddr; /* input interface   */
  1231.     PROXY_NET * pNet; /* proxy network     */
  1232.     struct in_addr mainAddr; /* main interface    */
  1233.     struct ifaddr * pIfa; /* if address      */
  1234.     struct sockaddr_in sin; /* sin structure     */
  1235.     struct ip * pIP; /* ip header pointer */
  1236.     int hlen; /* ip header length  */
  1237.     struct udphdr * pUDP; /* udp header       */
  1238.     if (!proxyBroadcastFwd)  /* broadcasts got turned off */
  1239. return;
  1240.     if (pMbuf->m_len < sizeof (struct ip) &&
  1241. (pMbuf = m_pullup(pMbuf, sizeof (struct ip))) == 0)
  1242. return;
  1243.     
  1244.     pIP = mtod (pMbuf, struct ip *); /* pulled tight in ip_input */
  1245.     /*
  1246.      * Only forward UDP broadcast packets.
  1247.      */
  1248.     if (pIP->ip_p != IPPROTO_UDP)
  1249. return;
  1250.     hlen = pIP->ip_hl << 2;
  1251.     /*
  1252.      * make sure IP header (with options) and UDP header fit into the
  1253.      * first mbuf.
  1254.      */
  1255.     if (pMbuf->m_len < (hlen + sizeof (struct udphdr)))
  1256. {
  1257.         if ((pMbuf = m_pullup (pMbuf, hlen + sizeof (struct udphdr))) == 0)
  1258.     return;
  1259.      pIP = mtod (pMbuf, struct ip *);
  1260. }
  1261.     pUDP = (struct udphdr *) ((u_char *) pIP + hlen);
  1262.     if (!portTblFind (ntohs (pUDP->uh_dport)) && !portTblFind ((u_short) 0))
  1263. return;
  1264.     semTake (proxySemId, WAIT_FOREVER);
  1265.     inputAddr.s_addr  =  ((struct arpcom *) pIf)->ac_ipaddr.s_addr;
  1266.     /* Validate the interface which received the original broadcast message. */
  1267.     pNet = proxyNetFind (&inputAddr);
  1268.     if (pNet == NULL && !proxyIsAMainNet (&inputAddr))
  1269.         {
  1270.         /*
  1271.          * The receiving interface is not part of any proxy network or
  1272.          * main network. Don't forward the broadcast message.
  1273.          */
  1274.         semGive (proxySemId);
  1275.         return;
  1276.         }
  1277.     
  1278.     if (pNet)
  1279. {
  1280. /*
  1281.  * Input interface was a proxy network.  Find main network associated
  1282.  * with that proxy network (and the interface to the main network)
  1283.  * and forward the datagram onto it.
  1284.  */
  1285. mainAddr.s_addr = pNet->mainAddr.s_addr;
  1286.      SIN_FILL(&sin, AF_INET, pNet->mainAddr.s_addr, 0);
  1287.      if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) != NULL)
  1288.     proxyBroadcast (pIfa->ifa_ifp, pMbuf, pIP->ip_ttl - 1);
  1289. }
  1290.     else
  1291. {
  1292.      mainAddr.s_addr = inputAddr.s_addr;
  1293. }
  1294.     for (pNet = (PROXY_NET *) lstFirst (&proxyNetList); (pNet != NULL);
  1295.  pNet = (PROXY_NET *) lstNext (&pNet->netNode))
  1296. {
  1297.      /*
  1298.  * Forward packet to all appropriate proxy networks. (A copy is not
  1299.          * sent to any proxy network which contained the original broadcast).
  1300.        */
  1301. if ((pNet->mainAddr.s_addr == mainAddr.s_addr)  &&
  1302.     (pNet->proxyAddr.s_addr != inputAddr.s_addr))
  1303.     {
  1304.     /* find proxy interface and ship it off */
  1305.          SIN_FILL(&sin, AF_INET, pNet->proxyAddr.s_addr, 0);
  1306.          if ((pIfa = ifa_ifwithaddr ((struct sockaddr *) &sin)) != NULL)
  1307. proxyBroadcast (pIfa->ifa_ifp, pMbuf, 1);
  1308.     }
  1309. }
  1310.     semGive (proxySemId);
  1311.     }
  1312. /*******************************************************************************
  1313. *
  1314. * proxyBroadcast - send a broadcast
  1315. *
  1316. * This routine sends a copy of the broadcast message <pMbuf> on the interface
  1317. * <pIf> so that all (physically separated) hosts on a logical subnet receive
  1318. * the expected broadcasts.
  1319. *
  1320. * RETURNS: N/A
  1321. *
  1322. * NOMANUAL
  1323. */
  1324. LOCAL void proxyBroadcast
  1325.     (
  1326.     FAST struct ifnet * pIf, /* output interface pointer */
  1327.     struct mbuf * pMbuf,   /* mbuf chain     */
  1328.     int                         ttl             /* time to live */
  1329.     )
  1330.     {
  1331.     struct mbuf * pMbufCopy; /* mbuf chain (copy)     */
  1332.     struct sockaddr_in   sin; /* address      */
  1333.     struct ip * pIP; /* ip header pointer     */
  1334.     /* 
  1335.      * Copy the message to protect forwarded packet from changes made by 
  1336.      * upper layers.
  1337.      */
  1338.     if ((pMbufCopy = (struct mbuf *) proxyPacketDup (pMbuf)) == NULL)
  1339. return;
  1340.     pMbufCopy->mBlkHdr.mFlags |= M_PROXY;
  1341.     pIP = mtod (pMbufCopy, struct ip *);
  1342.     if (proxyBroadcastVerbose)
  1343.      logMsg ("forward broadcast (if:0x%x) src 0x%x [%d] dst 0x%x [%d]n",
  1344.         ((struct arpcom *) pIf)->ac_ipaddr.s_addr,
  1345. pIP->ip_src.s_addr, ((struct udpiphdr *) pIP)->ui_sport,
  1346. pIP->ip_dst.s_addr, ((struct udpiphdr *) pIP)->ui_dport, 0);
  1347.     SIN_FILL(&sin, AF_INET, pIP->ip_dst.s_addr, 0);
  1348.     /* Adjust the IP packet length (modified in receive processing). */
  1349.     pIP->ip_len +=  pIP->ip_hl << 2;
  1350.     /* Convert appropriate header fields to network order for transmission. */
  1351.     pIP->ip_id  = htons ((u_short) pIP->ip_id);
  1352.     pIP->ip_len = htons ((u_short) pIP->ip_len);
  1353.     pIP->ip_off = htons ((u_short) pIP->ip_off);
  1354.     pIP->ip_ttl = ttl;
  1355.     pIP->ip_sum = 0;
  1356.     pIP->ip_sum = in_cksum (pMbufCopy, pIP->ip_hl << 2); 
  1357.     (*pIf->if_output)(pIf, pMbufCopy, (struct sockaddr *) &sin, 
  1358.       (struct rtentry *) NULL);
  1359.     }
  1360. /*******************************************************************************
  1361. *
  1362. * proxyMsgInput - input routine for proxy messages
  1363. *
  1364. * This routine is the input hook routine for proxy messages.  It handles
  1365. * the probe, client register and client unregister messages.  For a probe
  1366. * message it just sends an ACK.  PROXY_REG and PROXY_UNREG messages cause
  1367. * the proxy server to add the client (via proxyClientAdd()) and delete the
  1368. * (via proxyClientDelete()), respectively then reply with an ACK.
  1369. *
  1370. * <pArpcom> is the arpcom structure for the input interface.  <pMbuf> is the
  1371. * mbuf chain.  <len> is the length of the message.
  1372. *
  1373. * RETURNS: N/A
  1374. *
  1375. * NOMANUAL
  1376. */
  1377. LOCAL void proxyMsgInput
  1378.     (
  1379.     FAST struct arpcom * pArpcom, /* arpcom structure  */
  1380.     FAST struct mbuf * pMbuf,          /* mbuf chain        */
  1381.     int                         len             /* length            */
  1382.     )
  1383.     {
  1384.     PROXY_MSG *              pMsg; /* proxy message */
  1385.     int op; /* operation  */
  1386.     BOOL                        sendACK = FALSE;/* send client ack */
  1387.     if (pMbuf->m_len < sizeof (PROXY_MSG))      /* check message length */
  1388.         {
  1389.         m_freem (pMbuf);
  1390.         return;
  1391.         }
  1392.     pMsg = mtod (pMbuf, PROXY_MSG *);
  1393.     op = ntohl (pMsg->op);
  1394.     if (proxyArpVerbose)
  1395.      logMsg ("(%d) from 0x%x [%s]n", op, ntohl (pMsg->clientAddr.s_addr),
  1396.                 (int) ether_sprintf (pMsg->clientHwAddr), 0, 0, 0);
  1397.     if (proxyLibInitialized)
  1398.         {
  1399.      if (op == PROXY_PROBE)       /* probe message        */
  1400.     sendACK = TRUE;
  1401.         semTake (proxySemId, WAIT_FOREVER);
  1402.         if (op == PROXY_REG)    /* add client message   */
  1403.     {
  1404.             if (proxyIsAClient (&pMsg->clientAddr))
  1405.                 sendACK = TRUE;    /* Acknowledge duplicate registrations. */
  1406.     else if (proxyClientAdd (pArpcom, &pMsg->clientAddr,
  1407.                 pMsg->clientHwAddr) == OK)
  1408.                 sendACK = TRUE;
  1409.     }
  1410.         if (op == PROXY_UNREG) /* delete client message */
  1411.             {
  1412.             (void) proxyClientDelete (&pMsg->clientAddr);
  1413.             sendACK = TRUE;
  1414.             }
  1415.         semGive (proxySemId);
  1416. if (sendACK)
  1417.     {
  1418.     struct ether_header * pEh;    /* ether header         */
  1419.     struct sockaddr sa;     /* sockaddr structure   */
  1420.     struct ifnet * pIf; /* interface pointer   */
  1421.     /* fill in proxy message */
  1422.             pMsg->op = htonl (PROXY_ACK);
  1423.             pMsg->serverAddr.s_addr = pArpcom->ac_ipaddr.s_addr;
  1424.             bcopy ((caddr_t) pArpcom->ac_enaddr, (caddr_t) pMsg->serverHwAddr,
  1425.                    sizeof (pMsg->serverHwAddr));
  1426.     if (proxyArpVerbose)
  1427.                 logMsg ("proxy ACK sent to 0x%xn", 
  1428. ntohl (pMsg->clientAddr.s_addr), 0, 0, 0, 0, 0);
  1429.     bzero ((caddr_t) &sa, sizeof (sa));
  1430.     sa.sa_family = AF_UNSPEC;
  1431.     /* fill in ethernet header */
  1432.     pEh = (struct ether_header *) sa.sa_data;
  1433.     pEh->ether_type = PROXY_TYPE;
  1434.     pIf = (struct ifnet *) pArpcom;
  1435.     bcopy ((caddr_t) pMsg->clientHwAddr, (caddr_t) pEh->ether_dhost,
  1436.              sizeof (pEh->ether_dhost));
  1437.     (*pIf->if_output) (pIf, pMbuf, &sa, (struct rtentry *) NULL);
  1438.     return;
  1439.             }
  1440.         }
  1441.     m_freem (pMbuf);
  1442.     }
  1443. /*******************************************************************************
  1444. *
  1445. * proxyRouteCmd - add and delete a proxy client routes
  1446. *
  1447. * This routine adds and deletes routes to the proxy clients with the netmask
  1448. * of 0xffffffff so that arp route entries to the proxy clients can be cloned
  1449. * from the route added by this routine.
  1450. *
  1451. * RETURNS: OK, or ERROR if unsuccessful.
  1452. *
  1453. * NOMANUAL
  1454. */
  1455. LOCAL STATUS proxyRouteCmd
  1456.     (
  1457.     int destInetAddr, /* destination adrs */
  1458.     int gateInetAddr, /* gateway adrs */
  1459.     int ioctlCmd /* route command */
  1460.     )
  1461.     {
  1462.     struct sockaddr  destAddr;
  1463.     struct sockaddr  gateWayAddr;
  1464.     struct sockaddr  netMask;
  1465.     
  1466.     bzero((char *)(&destAddr), sizeof(struct sockaddr));
  1467.     destAddr.sa_family = AF_INET;
  1468.     destAddr.sa_len = sizeof(struct sockaddr_in);
  1469.     ((struct sockaddr_in *)&destAddr)->sin_addr.s_addr = (u_long)destInetAddr;
  1470.     /* zero out sockaddr_in, fill in gateway info */
  1471.     bzero ((char *)&gateWayAddr, sizeof(struct sockaddr));
  1472.     gateWayAddr.sa_family = AF_INET;
  1473.     gateWayAddr.sa_len = sizeof(struct sockaddr_in);
  1474.     ((struct sockaddr_in *)&gateWayAddr)->sin_addr.s_addr = 
  1475.      (u_long)gateInetAddr;
  1476.     /* initialize the netmask to 0xffffffff */
  1477.     netMask.sa_family  = AF_INET;
  1478.     netMask.sa_len = 8; 
  1479.     ((struct sockaddr_in *)&netMask)->sin_addr.s_addr = 0xffffffff;
  1480.     in_socktrim ((struct sockaddr_in *)&netMask); 
  1481.     return (rtrequest (((ioctlCmd == SIOCADDRT) ? RTM_ADD : RTM_DELETE), 
  1482.     &destAddr, &gateWayAddr, &netMask, RTF_CLONING, NULL)); 
  1483.     }
  1484. /*******************************************************************************
  1485. *
  1486. * proxyClientRemove - clear client structures
  1487. *
  1488. * This routine deletes the client routes from the route table.
  1489. *
  1490. * NOMANUAL
  1491. */
  1492. LOCAL void proxyClientRemove
  1493.     (
  1494.     PROXY_CLNT * pClient
  1495.     )
  1496.     {
  1497.     int flags = ATF_PROXY;
  1498.     (void) hashTblRemove (clientTbl, &pClient->hashNode);
  1499.     /* Remove proxy ARP entry explicitly */
  1500.     (void) arpCmd (SIOCDARP, &pClient->ipaddr, (u_char *)  NULL,
  1501.                    &flags);
  1502.     /* Remove regular ARP entry */
  1503.     (void) arpCmd (SIOCDARP, &pClient->ipaddr, (u_char *)  NULL,
  1504.    (int *) NULL);
  1505.     (void) proxyRouteCmd (pClient->ipaddr.s_addr, 
  1506.                      pClient->pNet->proxyAddr.s_addr, SIOCDELRT);
  1507.     }
  1508. /*******************************************************************************
  1509. *
  1510. * proxyPacketDup - copies IP header, dups the rest of the packet
  1511. *
  1512. * This routine makes a new mbuf chain copying the IP header of the
  1513. * original packet to a newly allocated cluster and copying by reference
  1514. * the rest of the packet.  This kind of copying is necessary if the IP
  1515. * header must be altered to reflect a new TTL when broadcast packets
  1516. * are forwarded.
  1517. *
  1518. * RETURNS: An M_BLK_ID for the new mbuf chain if successful, NULL
  1519. *          otherwise.
  1520. *
  1521. * NOMANUAL
  1522. */
  1523. LOCAL M_BLK_ID proxyPacketDup
  1524.     (
  1525.     M_BLK_ID pMblk      /* pointer to source mBlk */
  1526.     )
  1527.     {
  1528.     M_BLK_ID pNewMblk = NULL;
  1529.     M_BLK_ID pPktMblk = NULL;
  1530.     int ipHeaderSize = sizeof (struct ip);
  1531.     int bytesDuped = 0;
  1532.     if (pMblk == NULL)
  1533.         return (NULL);
  1534.     /* First mbuf must have enough room for link layer header */
  1535.     if ((pNewMblk = netTupleGet (_pNetDpool, max_linkhdr + ipHeaderSize,
  1536.  M_DONTWAIT, MT_DATA, TRUE)) == NULL)
  1537. return (NULL);
  1538.     /* Copy IP header which is in the first mbuf (done by m_pullup) */
  1539.     pNewMblk->mBlkHdr.mData += max_linkhdr; /* Leave room */
  1540.     bcopy (pMblk->mBlkHdr.mData, pNewMblk->mBlkHdr.mData, ipHeaderSize);
  1541.     pNewMblk->mBlkHdr.mLen = ipHeaderSize;
  1542.     if (pMblk->mBlkHdr.mFlags & M_PKTHDR)
  1543.         {
  1544.         /* Copy packet header information */
  1545. pNewMblk->mBlkPktHdr = pMblk->mBlkPktHdr;
  1546. pNewMblk->mBlkHdr.mFlags = pMblk->mBlkHdr.mFlags;
  1547. }
  1548.     /* Copy by reference the rest of the packet */
  1549.     bytesDuped = pMblk->mBlkPktHdr.len - ipHeaderSize;
  1550.     pPktMblk = netMblkChainDup (_pNetDpool, pMblk, ipHeaderSize,
  1551. bytesDuped, M_DONTWAIT);
  1552.     if (pPktMblk == NULL)
  1553.         {
  1554.         netMblkClChainFree(pNewMblk);
  1555.         return (NULL);
  1556.         }
  1557.     /* Make chain */
  1558.     pNewMblk->mBlkPktHdr.len = pMblk->mBlkPktHdr.len;
  1559.     pNewMblk->mBlkHdr.mNext = pPktMblk;
  1560.     return (pNewMblk);
  1561.     }