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

VxWorks

开发平台:

C/C++

  1. /* arpLib.c - Address Resolution Protocol (ARP) table manipulation library */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02q,10may02,kbw  making man page edits
  8. 02p,24apr02,rae  Added note about arp flooding to arpResolve(), etc. (SPR #69412)
  9. 02o,07dec01,rae  merge from synth ver 02x (SPR #69889)
  10. 02n,15oct01,rae  merge from truestack ver 02w base 02j (SPRs 69405, 65783, etc.)
  11. 02m,07feb01,spm  added merge record for 30jan01 update from version 02l of
  12.                  tor2_0_x branch (base 02j) and fixed modification history;
  13.                  fixed code conventions and updated documentation; replaced
  14.                  printed error message with errno value
  15. 02l,30jan01,ijm  merged SPR# 28602 fixes: proxy ARP services are obsolete 
  16. 02k,05feb99,dgp  document errno values
  17. 02j,16apr97,vin  changed SOCK_DGRAM to SOCK_RAW as udp can be scaled out.
  18. 02i,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  19. 02h,21sep92,jdi  documentation cleanup. 
  20. 02g,14aug92,elh  documentation changes. 
  21. 02f,11jun92,elh  changed parameter to arpCmd.  Moved arpShow to netShow.
  22. 02e,26may92,rrr  the tree shuffle
  23.   -changed includes to have absolute path from h/
  24. 02d,19apr92,elh  added spl pair around arpFlush.
  25. 02c,04apr92,elh  added arpFlush.
  26. 02b,03jan92,elh  ansi-fied.
  27. 02a,18nov91,elh  major overhaul.  Rewrote to comply with WRS standards and
  28.  coding conventions, added error handling and documentation.
  29. 01a,06jun91,jrb  written.
  30. */
  31. /*
  32. DESCRIPTION
  33. This library provides direct access to the address translation table
  34. maintained by the Address Resolution Protocol (ARP). Each entry in
  35. the table maps an Internet Protocol (IP) address to a physical hardware 
  36. address. This library supports only those entries that translate between IP 
  37. and Ethernet addresses. It is linked into the VxWorks image if INCLUDE_ARP 
  38. is defined at the time the image is built. The underlying ARP protocol, 
  39. which creates and maintains the table, is included automatically as part 
  40. of the IP component.
  41. RELATED INTERFACES
  42. The arpShow() routine (in the netShow library) displays the current 
  43. contents of the ARP table.
  44. A low -evel interface to the ARP table is available with the socket-specific 
  45. SIOCSARP, SIOCDARP and SIOCGARP ioctl functions.
  46. INTERNAL
  47. The structure chart for this module looks like:
  48.      arpAdd arpDelete
  49. |       /
  50. |    v   v
  51.         |    arpCmd
  52. v
  53. etherAsciiToEnet
  54. INCLUDE FILES: arpLib.h
  55. SEE ALSO: inetLib, routeLib, netShow
  56. */
  57. /* includes */
  58. #include "vxWorks.h"
  59. #include "sys/types.h"
  60. #include "sys/socket.h"
  61. #include "sys/ioctl.h"
  62. #include "net/if.h"
  63. #include "netinet/if_ether.h"
  64. #include "net/if_arp.h"
  65. #include "net/unixLib.h"
  66. #include "errno.h"
  67. #include "arpLib.h"
  68. #include "inetLib.h"
  69. #include "stdio.h"
  70. #include "string.h"
  71. #include "sockLib.h"
  72. #include "ioLib.h"
  73. #include "unistd.h"
  74. #include "hostLib.h"
  75. #include "netShow.h"
  76. #include "taskLib.h"
  77. #ifdef VIRTUAL_STACK
  78. #ifdef _WRS_VXWORKS_5_X
  79. #include "memPartLib.h"
  80. #endif /* _WRS_VXWORKS_5_X */
  81. #include "netinet/vsLib.h"
  82. #include "netinet/vsArp.h"
  83. extern void arptimer (int);
  84. #endif
  85. /* defines */
  86. #define ENET_SIZE 6 /* Ethernet address size */
  87. /* forward static functions */
  88. LOCAL STATUS etherAsciiToEnet (char * asciiAddr, u_char * retEnet);
  89. IMPORT void arptfree ();
  90. #ifndef VIRTUAL_STACK
  91. IMPORT struct llinfo_arp llinfo_arp;
  92. #endif
  93. /*******************************************************************************
  94. *
  95. * arpLibInit - ARP table manipulation library initialization
  96. *
  97. * This routine is called during system startup if INCLUDE_ARP_API is defined. 
  98. * Normally, its only purpose is to automatically link this module into the
  99. * runtime image. The virtual stack modifications extend this routine to
  100. * initialize the required variables and start the appropriate timer.
  101. *
  102. * RETURNS: N/A
  103. *
  104. * ERRNO: N/A
  105. *
  106. * NOMANUAL
  107. */
  108. void arpLibInit (void)
  109.     {
  110. #ifdef VIRTUAL_STACK
  111.     /*
  112.      * Make sure arpLibInit has not been called before. This can happen
  113.      * when INCLUDE_ARP_API has been included in a build.
  114.      */
  115.     if (arptimerWd == NULL)
  116. {
  117.         _llinfo_arp.la_next = &_llinfo_arp;
  118.         _llinfo_arp.la_prev = &_llinfo_arp;
  119.         arpRxmitTicks = -1;
  120.         arptimerWd = wdCreate ();
  121.         arptimer(myStackNum);
  122. }
  123. #endif /* VIRTUAL_STACK */
  124.     return;
  125.     }
  126. /*******************************************************************************
  127. *
  128. * arpAdd - create or modify an ARP table entry
  129. *
  130. * This routine assigns an Ethernet address to an IP address in the ARP table.
  131. * The <pHost> parameter specifies the host by name or by Internet address 
  132. * using standard dotted decimal notation. The <pEther> parameter provides the 
  133. * Ethernet address as six hexadecimal bytes (between 0 and ff) separated by 
  134. * colons. A new entry is created for the specified host if necessary.
  135. * Otherwise, the existing entry is changed to use the given Ethernet address.
  136. *
  137. * The <flags> parameter combines any of the following options: 
  138. * .iP "ATF_PERM  (0x04)"
  139. * Create a permanent ARP entry which will not time out.
  140. * .iP "ATF_PUBL  (0x08)"
  141. * Publish this entry. The host will respond to ARP requests even if the
  142. * <pHost> parameter does not match a local IP address. This setting provides 
  143. * a limited form of proxy ARP.
  144. * .iP "ATF_PROXY (0x10)"
  145. * Use a "wildcard" hardware address. The proxy server uses this setting to
  146. * support multiple proxy networks. The entry always supplies the hardware
  147. * address of the sending interface.
  148. * EXAMPLE
  149. * Create a permanent ARP table entry for the host named "myHost" with
  150. * Ethernet address 0:80:f9:1:2:3:
  151. * .CS
  152. *     arpAdd ("myHost", "0:80:f9:1:2:3", 0x4);
  153. * .CE
  154. *
  155. * Assuming "myHost" has the Internet address "90.0.0.3", the following call
  156. * changes the Ethernet address to 0:80:f9:1:2:4. No additional flags are set 
  157. * for that entry.
  158. * .CS
  159. *     arpAdd ("90.0.0.3", "0:80:f9:1:2:4", 0);
  160. * .CE
  161. *
  162. * RETURNS: OK, or ERROR if unsuccessful.
  163. *
  164. * ERRNO:
  165. *  S_arpLib_INVALID_ARGUMENT
  166. *  S_arpLib_INVALID_HOST
  167. *  S_arpLib_INVALID_ENET_ADDRESS
  168. *  S_arpLib_INVALID_FLAG
  169. *  or results of low-level ioctl call.
  170. */
  171. STATUS arpAdd
  172.     (
  173.     char * pHost, /* host name or IP address */
  174.     char * pEther, /* Ethernet address */
  175.     int   flags      /* ARP flags */
  176.     )
  177.     {
  178.     struct in_addr hostAddr; /* host address */
  179.     u_char  ea [ENET_SIZE]; /* Ethernet address */
  180. #ifdef VIRTUAL_STACK
  181.     virtualStackIdCheck();
  182. #endif /* VIRTUAL_STACK */
  183.     if ((pHost == NULL) || (pEther == NULL))  /* validate parameters */
  184. {
  185. errno = S_arpLib_INVALID_ARGUMENT;
  186. return (ERROR);
  187. }
  188. /* convert address from ascii */
  189.     if (((hostAddr.s_addr = inet_addr (pHost)) == ERROR) &&
  190. ((hostAddr.s_addr = hostGetByName (pHost)) == ERROR))
  191. {
  192. errno = S_arpLib_INVALID_HOST;
  193. return (ERROR);
  194. }
  195. /* convert enet from ascii */
  196.     if (etherAsciiToEnet (pEther, ea) != OK)
  197. return (ERROR);
  198. /* validate flags */
  199.     if (flags & ~(ATF_PERM | ATF_PUBL | ATF_INCOMPLETE | ATF_PROXY))
  200. {
  201. errno = S_arpLib_INVALID_FLAG;
  202. return (ERROR);
  203. }
  204.     if (arpCmd (SIOCSARP, &hostAddr, ea, &flags) == ERROR)
  205. return (ERROR);
  206.     return (OK);
  207.     }
  208. /*******************************************************************************
  209. *
  210. * arpDelete - remove an ARP table entry
  211. *
  212. * This routine deletes an ARP table entry. The <pHost> parameter indicates
  213. * the target entry using the host name or Internet address.
  214. *
  215. * EXAMPLE
  216. * .CS
  217. *    arpDelete ("91.0.0.3")
  218. *    arpDelete ("myHost")
  219. * .CE
  220. *
  221. * RETURNS: OK, or ERROR if unsuccessful.
  222. *
  223. * ERRNO
  224. *  S_arpLib_INVALID_ARGUMENT
  225. *  S_arpLib_INVALID_HOST
  226. */
  227. STATUS arpDelete
  228.     (
  229.     char * pHost /* host name or IP address */
  230.     )
  231.     {
  232.     struct in_addr  hostAddr; /* host address  */
  233.     char addrInAscii [ INET_ADDR_LEN ]; /* IP in ascii */
  234. #ifdef VIRTUAL_STACK
  235.     virtualStackIdCheck();
  236. #endif /* VIRTUAL_STACK */
  237.     if (pHost == NULL) /* validate argument */
  238. {
  239. errno = S_arpLib_INVALID_ARGUMENT;
  240. return (ERROR);
  241. }
  242. /* convert addr from ascii */
  243.     if (((hostAddr.s_addr = inet_addr (pHost)) == ERROR) &&
  244. ((hostAddr.s_addr = hostGetByName (pHost)) == ERROR))
  245. {
  246.         errno = S_arpLib_INVALID_HOST;
  247. return (ERROR);
  248. }
  249.     inet_ntoa_b (hostAddr, addrInAscii); /* convert to printable fmt */
  250.     if (arpCmd (SIOCDARP, &hostAddr, (u_char *) NULL, (int *) NULL) == ERROR)
  251. {
  252.         errno = S_arpLib_INVALID_HOST;    /* No such entry in table. */
  253. return (ERROR);
  254. }
  255.     return (OK);
  256.     }
  257. /*******************************************************************************
  258. *
  259. * arpCmd - issues an ARP command
  260. *
  261. * This routine generates the low-level ioctl call for an ARP command. Expected
  262. * values for the <cmd> parameter are SIOCSARP, SIOCGARP, or SIOCDARP. 
  263. * The <pIpAddr> parameter specifies the IP address of the host. The
  264. * <pHwAddr> pointer provides the corresponding link-level address in
  265. * binary form. That parameter is only used with SIOCSARP, and is limited
  266. * to the 6-byte maximum required for Ethernet addresses. The <pFlags> 
  267. * argument provides any flag settings for the entry.
  268. *
  269. * RETURNS: OK, or ERROR if unsuccessful.
  270. *
  271. * NOMANUAL
  272. *
  273. * INTERNAL
  274. * This routine should be LOCAL, but it is also used by the proxy ARP
  275. * library. That library should call the ioctl interface directly instead
  276. * to avoid the overhead created by the additional routines in this
  277. * module which it does not use.
  278. */
  279. STATUS arpCmd
  280.     (
  281.     int                 cmd, /* arp command */
  282.     struct in_addr *    pIpAddr, /* ip address */
  283.     u_char *            pHwAddr, /* hardware address */
  284.     int *               pFlags /* arp flags  */
  285.     )
  286.     {
  287.     struct arpreq       arpRequest; /* arp request struct */
  288.     STATUS              status = ERROR; /* return status  */
  289.     int                 sock; /* socket  */
  290.     /* fill in arp request structure */
  291.     bzero ((caddr_t) &arpRequest, sizeof (struct arpreq));
  292.     arpRequest.arp_pa.sa_family = AF_INET;
  293.     ((struct sockaddr_in *)
  294. &(arpRequest.arp_pa))->sin_addr.s_addr = pIpAddr->s_addr;
  295.     arpRequest.arp_ha.sa_family = AF_UNSPEC;
  296.     if (pHwAddr != NULL)
  297.         bcopy ((caddr_t) pHwAddr ,(caddr_t) arpRequest.arp_ha.sa_data,
  298.        ENET_SIZE);
  299.     if (pFlags != NULL)
  300.      arpRequest.arp_flags = *pFlags;
  301.     if ((sock = socket (AF_INET, SOCK_RAW, 0)) != ERROR)
  302.         {
  303.         if ((status = ioctl (sock, cmd, (int) &arpRequest)) == OK)
  304.     {
  305.          if (pHwAddr != NULL)
  306.          bcopy ((caddr_t) arpRequest.arp_ha.sa_data, (caddr_t) pHwAddr,
  307. ENET_SIZE);
  308.     if (pFlags != NULL)
  309.      *pFlags = arpRequest.arp_flags;
  310.     }
  311.         close (sock);
  312.         }
  313.     return (status);
  314.     }
  315. /*******************************************************************************
  316. *
  317. * arpFlush - flush all entries in the system ARP table
  318. *
  319. * This routine flushes all non-permanent entries in the ARP cache.
  320. *
  321. * RETURNS: N/A
  322. */
  323. void arpFlush (void)
  324.     {
  325.     register struct llinfo_arp *la;
  326.     FAST struct rtentry *  pRoute; 
  327.     int s;
  328. #ifdef VIRTUAL_STACK
  329.     virtualStackIdCheck();
  330.     la = _llinfo_arp.la_next;
  331. #else
  332.     la = llinfo_arp.la_next;
  333. #endif /* VIRTUAL_STACK */
  334.     s = splnet ();
  335. #ifdef VIRTUAL_STACK
  336.     while (la != &_llinfo_arp) 
  337. #else
  338.     while (la != &llinfo_arp) 
  339. #endif
  340. {
  341. pRoute = la->la_rt; 
  342. la = la->la_next;
  343. /* if entry permanent */
  344. if ((pRoute->rt_rmx.rmx_expire == 0) || (pRoute->rt_flags == 0))
  345.     continue;
  346. arptfree(la->la_prev); /* timer has expired; clear */
  347. }
  348.     splx (s);
  349.     }
  350. /*******************************************************************************
  351. *
  352. * etherAsciiToEnet - convert Ethernet address
  353. *
  354. * This routine converts an Ethernet address in ascii format to its normal
  355. * 48 bit format.  <asciiAddr> is the string Ethernet address which has the form
  356. * "x:x:x:x:x:x" where x is a hexadecimal number between 0 and ff.  <retEnet> is
  357. * where the Ethernet address gets returned.   This routine is similar to the
  358. * UNIX call ether_aton.
  359. *
  360. * RETURNS: OK, or ERROR if unsuccessful.
  361. *
  362. * ERRNO: S_arpLib_INVALID_ENET_ADDRESS
  363. */
  364. LOCAL STATUS etherAsciiToEnet
  365.     (
  366.     char * asciiAddr, /* enet addr in ascii */
  367.     u_char * retEnet /* return enet addr */
  368.     )
  369.     {
  370.     int enet [ENET_SIZE]; /* Ethernet address     */
  371.     int ix; /* index variable */
  372.     if (sscanf (asciiAddr, "%x:%x:%x:%x:%x:%x", &enet [0],
  373. &enet [1], &enet [2], &enet [3], &enet [4],
  374. &enet [5]) != ENET_SIZE)
  375. {
  376. printf ("arp: invalid Ethernet address %sn", asciiAddr);
  377. errno = S_arpLib_INVALID_ENET_ADDRESS;
  378. return (ERROR);
  379. }
  380.     for (ix = 0; ix < ENET_SIZE; ix++)
  381. retEnet [ix] = (u_char) enet [ix];
  382.    return (OK);
  383.    }
  384. /*******************************************************************************
  385. *
  386. * arpResolve - resolve a hardware address for a specified Internet address
  387. *
  388. * This routine uses the Address Resolution Protocol (ARP) and internal ARP
  389. * cache to resolve the hardware address of a machine that owns the Internet
  390. * address given in <targetAddr>.
  391. *
  392. * The hardware address is copied to <pHwAddr> as network byte order, if the
  393. * resolution of <targetAddr> is successful.  <pHwAddr> must point to a buffer
  394. * which is large enough to receive the address.
  395. *
  396. * NOTE: RFC 1122 prohibits sending more than one arp request per second.  Any
  397. * numTicks value that would result in a shorter time than this is ignored.
  398. *
  399. * RETURNS:
  400. * OK if the address is resolved successfully, or ERROR if <pHwAddr> is NULL,
  401. * <targetAddr> is invalid, or address resolution is unsuccessful.
  402. *
  403. * ERRNO:
  404. *  S_arpLib_INVALID_ARGUMENT
  405. *  S_arpLib_INVALID_HOST
  406. *
  407. */
  408. STATUS arpResolve
  409.     (
  410.     char                *targetAddr,  /* name or Internet address of target */
  411.     char                *pHwAddr,     /* where to return the H/W address */
  412.     int                 numTries,     /* number of times to try ARPing (-1 means try
  413.                                          forever) */
  414.     int                 numTicks      /* number of ticks between ARPs */
  415.     )
  416.     {
  417.     struct ifnet * pIf = NULL;
  418.     struct sockaddr_in  sockInetAddr;
  419.     struct rtentry * pRt;
  420.     unsigned long addr;
  421.     int retVal = 0;
  422.     if (pHwAddr == NULL || numTries < -1 || numTries == 0)     /* user messed up */
  423. {
  424. errno = S_arpLib_INVALID_ARGUMENT;
  425.         return (ERROR);
  426. }
  427.     /* the 'targetAddr' can either be the hostname or the actual Internet
  428.      * address.
  429.      */
  430.     if ((addr = (unsigned long) hostGetByName (targetAddr)) == ERROR &&
  431. (addr = inet_addr (targetAddr)) == ERROR)
  432. {
  433. errno = S_arpLib_INVALID_HOST;
  434. return (ERROR);
  435. }
  436.     bzero ((caddr_t)&sockInetAddr, sizeof (sockInetAddr));
  437.     sockInetAddr.sin_len = sizeof(struct sockaddr_in);
  438.     sockInetAddr.sin_family = AF_INET;
  439.     sockInetAddr.sin_addr.s_addr = addr; 
  440.     /*
  441.      * Get associated local interface's ifnet. This search also
  442.      * clones an empty ARP entry from the interface route if one
  443.      * does not already exist.
  444.      */
  445.     pRt = rtalloc1 ( (struct sockaddr *)&sockInetAddr, 1);
  446.     if (pRt == NULL)
  447. {
  448. errno = S_arpLib_INVALID_HOST;
  449. return (ERROR);
  450. }
  451.     pIf = pRt->rt_ifp;
  452.     if (pIf == NULL)
  453. {
  454.         rtfree (pRt);
  455. errno = S_arpLib_INVALID_HOST;
  456. return (ERROR);
  457. }
  458.     /* return 0xffffffffffff for broadcast Internet address */
  459.     if (in_broadcast (sockInetAddr.sin_addr, pIf))
  460. {
  461.         bcopy ((char *) etherbroadcastaddr, pHwAddr,
  462.        sizeof (etherbroadcastaddr));
  463.         rtfree (pRt);
  464. return (OK);
  465. }
  466.     /* Try to resolve the Ethernet address by calling arpresolve() which
  467.      * may send out ARP request messages out onto the Ethernet wire.
  468.      */
  469.     while ((numTries == -1 || numTries-- > 0) &&
  470.    (retVal = arpresolve ((struct arpcom *) pIf, 
  471.  (struct rtentry *)pRt, 
  472.  (struct mbuf *) NULL,
  473.  (struct sockaddr *)&sockInetAddr,
  474.  (UCHAR *)pHwAddr))
  475.    == 0)
  476.      if (numTries)           /* don't delay after last arp */
  477.             taskDelay (numTicks);
  478.     rtfree (pRt);
  479.     if (retVal == 0) /* unsuccessful resolution */
  480. {
  481. errno = S_arpLib_INVALID_HOST;
  482.         return (ERROR);
  483. }
  484.     return (OK);
  485.     }