m2IpLib.c
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:41k
开发平台:

MultiPlatform

  1. /* m2IpLib.c - MIB-II IP-group API for SNMP agents */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,06mar02,vvv  fixed m2IpAtransTblEntryGet to retrieve all entries
  8.  (SPR #72963)
  9. 01n,15oct01,rae  merge from truestack ver 02b, base 01k (SPRs 69556, 63629,
  10.                  68525, 67888, etc)
  11. 01m,24oct00,niq  Merging RFC2233 changes from tor2_0.open_stack-f1 branch
  12.                  01o,18may00,pul  modified m2IpRouteTblEntrySet() to pass 
  13.                  FALSE to routeEntryFill to support addition of network routes.
  14.                  01n,18may00,ann  merging from post R1 to include RFC2233
  15. 01l,07feb00,ann  changing the references to the code in m2IfLib
  16. 01k,16mar99,spm  recovered orphaned code from tor1_0_1.sens1_1 (SPR #25770)
  17. 01j,29sep98,spm  added support for dynamic routing protocols (SPR #9374)
  18. 01i,30dec97,vin  fixed SPR 20090
  19. 01h,26aug97,spm  removed compiler warnings (SPR #7866)
  20. 01g,17may96,rjc  routeEntryFill called with 1 less parmam. fixed.
  21. 01f,03apr96,rjc  set the m2RouteSem semaphore to NULL in in m2IpDelete
  22. 01e,25jan95,jdi  doc cleanup.
  23. 01d,11nov94,rhp  fixed typo in library man page
  24. 01c,11nov94,rhp  edited man pages
  25. 01b,03mar94,elh  modifed m2IpRouteTblEntrySet to return ERROR if rtioctl
  26.  failed.
  27. 01a,08dec93,jag  written
  28. */
  29. /*
  30. DESCRIPTION
  31. This library provides MIB-II services for the IP group.  It provides
  32. routines to initialize the group, access the group scalar variables, read
  33. the table IP address, route and ARP table.  The route and ARP table can
  34. also be modified.  For a broader description of MIB-II services,
  35. see the manual entry for m2Lib.
  36. To use this feature, include the following component:
  37. INCLUDE_MIB2_IP
  38. USING THIS LIBRARY
  39. To use this library, the MIB-II interface group must also be initialized;
  40. see the manual entry for m2IfLib.  This library (m2IpLib) can be
  41. initialized and deleted by calling m2IpInit() and m2IpDelete()
  42. respectively, if only the IP group's services are needed.  If full MIB-II
  43. support is used, this group and all other groups can be initialized and
  44. deleted by calling m2Init() and m2Delete().
  45. The following example demonstrates how to access and change IP scalar
  46. variables:
  47. .CS
  48.     M2_IP   ipVars;
  49.     int     varToSet;
  50.     if (m2IpGroupInfoGet (&ipVars) == OK)
  51. /@ values in ipVars are valid @/
  52.     /@ if IP is forwarding packets (MIB-II value is 1) turn it off @/
  53.     if (ipVars.ipForwarding == M2_ipForwarding_forwarding)
  54. {
  55.     /@ Not forwarding (MIB-II value is 2) @/
  56. ipVars.ipForwarding = M2_ipForwarding_not_forwarding;      
  57. varToSet |= M2_IPFORWARDING;
  58. }
  59.     /@ change the IP default time to live parameter @/
  60.     ipVars.ipDefaultTTL = 55;
  61.     if (m2IpGroupInfoSet (varToSet, &ipVars) == OK)
  62. /@ values in ipVars are valid @/
  63. .CE
  64. The IP address table is a read-only table.  Entries to this table can be 
  65. retrieved as follows:
  66. .CS
  67.     M2_IPADDRTBL ipAddrEntry;
  68.     /@ Specify the index as zero to get the first entry in the table @/
  69.     ipAddrEntry.ipAdEntAddr = 0;       /@ Local IP address in host byte order @/
  70.     /@ get the first entry in the table @/
  71.     if ((m2IpAddrTblEntryGet (M2_NEXT_VALUE, &ipAddrEntry) == OK)
  72. /@ values in ipAddrEntry in the first entry are valid  @/
  73.     /@ Process first entry in the table @/
  74.     /@ 
  75.      * For the next call, increment the index returned in the previous call.
  76.      * The increment is to the next possible lexicographic entry; for
  77.      * example, if the returned index was 147.11.46.8 the index passed in the
  78.      * next invocation should be 147.11.46.9.  If an entry in the table
  79.      * matches the specified index, then that entry is returned.
  80.      * Otherwise the closest entry following it, in lexicographic order,
  81.      * is returned.
  82.      @/
  83.     /@ get the second entry in the table @/
  84.     if ((m2IpAddrTblEntryGet (M2_NEXT_VALUE, &ipAddrEntryEntry) == OK)
  85. /@ values in ipAddrEntry in the second entry are valid  @/
  86. .CE
  87. The IP Address Translation Table (ARP table) includes the functionality of
  88. the AT group plus additional functionality.  The AT group is supported
  89. through this MIB-II table.  Entries in this table can be added and
  90. deleted.  An entry is deleted (with a set operation) by setting the
  91. `ipNetToMediaType' field to the MIB-II "invalid" value (2).  The 
  92. following example shows how to delete an entry:
  93. .CS
  94. M2_IPATRANSTBL        atEntry;
  95.     /@ Specify the index for the connection to be deleted in the table @/
  96.     atEntry.ipNetToMediaIfIndex     = 1       /@ interface index @/
  97.     /@ destination IP address in host byte order @/
  98.     atEntry.ipNetToMediaNetAddress  = 0x930b2e08;
  99.     /@ mark entry as invalid @/
  100.     atEntry.ipNetToMediaType        = M2_ipNetToMediaType_invalid; 
  101.     /@ set the entry in the table @/
  102.     if ((m2IpAtransTblEntrySet (&atEntry) == OK)
  103. /@ Entry deleted successfully @/
  104. .CE
  105. The IP route table allows for entries to be read, deleted, and modified.  This
  106. example demonstrates how an existing route is deleted:
  107. .CS
  108.     M2_IPROUTETBL        routeEntry;
  109.     /@ Specify the index for the connection to be deleted in the table @/
  110.     /@ destination IP address in host byte order @/
  111.     routeEntry.ipRouteDest       = 0x930b2e08;
  112. /@ mark entry as invalid @/
  113.     routeEntry.ipRouteType       = M2_ipRouteType_invalid;
  114.     /@ set the entry in the table @/
  115.     if ((m2IpRouteTblEntrySet (M2_IP_ROUTE_TYPE, &routeEntry) == OK)
  116. /@ Entry deleted successfully @/
  117. .CE
  118. INCLUDE FILES: m2Lib.h
  119.  
  120. SEE ALSO:
  121. m2Lib, m2SysLib, m2IfLib, m2IcmpLib, m2UdpLib, m2TcpLib
  122. */
  123. /* includes */
  124. #include "vxWorks.h"
  125. #include "stdlib.h"
  126. #include "m2Lib.h"
  127. #include "private/m2LibP.h"
  128. #include "netLib.h"
  129. #include <netinet/in_systm.h>
  130. #include <netinet/ip.h>
  131. #include <netinet/ip_var.h>
  132. #include <net/route.h>
  133. #include <net/radix.h>
  134. #include <netinet/in_var.h>
  135. #include <netinet/if_ether.h>
  136. #include <net/if_dl.h>
  137. #include <net/if_arp.h>
  138. #include "ioctl.h"
  139. #include "net/mbuf.h"
  140. #include "tickLib.h"
  141. #include "sysLib.h"
  142. #include "routeLib.h"
  143. #include "semLib.h"
  144. #include "errnoLib.h"
  145. #include "memPartLib.h"
  146. #include "routeEnhLib.h"
  147. #ifdef VIRTUAL_STACK
  148. #include "netinet/vsLib.h"
  149. #endif /* VIRTUAL_STACK */
  150. #ifdef ROUTER_STACK
  151. #include "wrn/fastPath/fastPathLib.h"
  152. #endif /* ROUTER_STACK */
  153. /* defines */
  154. #define M2_MAX_ROUTE_DEFAULT  40
  155. /* globals */
  156. #ifndef VIRTUAL_STACK
  157. LOCAL int  m2RouteTableSaved;
  158. LOCAL int m2RouteTableSize;
  159. LOCAL int m2NumRouteEntries;
  160. LOCAL M2_IPROUTETBL   * m2RouteTable;
  161. LOCAL SEM_ID            m2RouteSem;
  162. #endif /* VIRTUAL_STACK */
  163. /*
  164.  * The zero object id is used throught out the MIB-II library to fill OID 
  165.  * requests when an object ID is not provided by a group variable.
  166.  */
  167. LOCAL M2_OBJECTID ipZeroObjectId = { 2, {0,0} };
  168. /* forward declarations */
  169. LOCAL int       m2RouteTableGet();
  170. LOCAL int  routeCacheInit (struct radix_node *rn, void * pRtArg);
  171. /* external declarations */
  172. #ifndef VIRTUAL_STACK
  173. extern SEM_ID m2InterfaceSem;
  174. IMPORT struct radix_node_head *rt_tables[]; /* table of radix nodes */
  175. IMPORT struct llinfo_arp llinfo_arp; 
  176. IMPORT int  _ipCfgFlags; 
  177. IMPORT int  ipMaxUnits;
  178. #endif /* VIRTUAL_STACK */
  179. IMPORT int  arpioctl (int, caddr_t);
  180. IMPORT void routeEntryFill (struct ortentry *, int, int, BOOL);
  181. /******************************************************************************
  182. *
  183. * m2IpInit - initialize MIB-II IP-group access
  184. *
  185. * This routine allocates the resources needed to allow access to the MIB-II
  186. * IP variables.  This routine must be called before any IP variables
  187. * can be accessed.  The parameter <maxRouteTableSize> is used to increase the
  188. * default size of the MIB-II route table cache.
  189. *
  190. * RETURNS:
  191. * OK, or ERROR if the route table or the route semaphore cannot be allocated.
  192. *
  193. * ERRNO:
  194. * S_m2Lib_CANT_CREATE_ROUTE_SEM
  195. *
  196. * SEE ALSO:
  197. * m2IpGroupInfoGet(), m2IpGroupInfoSet(), m2IpAddrTblEntryGet(),
  198. * m2IpAtransTblEntrySet(),  m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(), 
  199. * m2IpDelete()
  200. */
  201. STATUS m2IpInit
  202.     (
  203.     int maxRouteTableSize  /* max size of routing table */ 
  204.     )
  205.     {
  206.     /* initialize the routing table stuff */
  207.     if (m2RouteTable == NULL)
  208. {
  209. /* only initialized the first time called */
  210.         m2RouteTableSaved = 0;
  211. m2RouteTableSize = (maxRouteTableSize == 0) ? 
  212.    M2_MAX_ROUTE_DEFAULT :  maxRouteTableSize ;
  213.      m2RouteTable = (M2_IPROUTETBL *) KHEAP_ALLOC(m2RouteTableSize *
  214.                  sizeof (M2_IPROUTETBL));
  215. if (m2RouteTable == NULL)
  216.     {
  217.     return (ERROR);
  218.     }
  219.         bzero ((char *)m2RouteTable, m2RouteTableSize * sizeof (M2_IPROUTETBL));
  220. }
  221.         if (m2RouteSem == NULL)
  222.             {
  223.     m2RouteSem = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE |
  224.    SEM_DELETE_SAFE);
  225.     if (m2RouteSem == NULL)
  226. {
  227.         errnoSet (S_m2Lib_CANT_CREATE_ROUTE_SEM);
  228. return (ERROR);
  229. }
  230.     }
  231.     (void) m2RouteTableGet (m2RouteTable, m2RouteTableSize);
  232.     return (OK);
  233.     }
  234. /******************************************************************************
  235. *
  236. * m2IpGroupInfoGet - get the MIB-II IP-group scalar variables
  237. *
  238. * This routine fills in the IP structure at <pIpInfo> with the
  239. * values of MIB-II IP global variables.
  240. *
  241. * RETURNS: OK, or ERROR if <pIpInfo> is not a valid pointer.
  242. *
  243. * ERRNO:
  244. * S_m2Lib_INVALID_PARAMETER
  245. *
  246. * SEE ALSO: m2IpInit(), m2IpGroupInfoSet(), m2IpAddrTblEntryGet(),
  247. * m2IpAtransTblEntrySet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  248. * m2IpDelete()
  249. */
  250. STATUS m2IpGroupInfoGet
  251.     (
  252.     M2_IP * pIpInfo /* pointer to IP MIB-II global group variables */
  253.     )
  254.     {
  255.  
  256.     /* Validate Pointer to IP structure */
  257.  
  258.     if (pIpInfo == NULL)
  259. {
  260. errnoSet (S_m2Lib_INVALID_PARAMETER);
  261.         return (ERROR);
  262. }
  263.  
  264.     if (_ipCfgFlags & IP_DO_FORWARDING)
  265.         pIpInfo->ipForwarding       = M2_ipForwarding_forwarding;
  266.     else
  267.         pIpInfo->ipForwarding       = M2_ipForwarding_not_forwarding;
  268.  
  269.     pIpInfo->ipDefaultTTL       = ipTimeToLive;
  270. #ifdef VIRTUAL_STACK
  271.     pIpInfo->ipInReceives       = _ipstat.ips_total;
  272.  
  273.     pIpInfo->ipInHdrErrors      = _ipstat.ips_badsum + _ipstat.ips_tooshort +
  274.                                   _ipstat.ips_toosmall + _ipstat.ips_badhlen +
  275.                                   _ipstat.ips_badlen + _ipstat.ips_badoptions +
  276.   _ipstat.ips_badvers;
  277.     pIpInfo->ipInAddrErrors     = _ipstat.ips_cantforward;
  278.     pIpInfo->ipForwDatagrams    = _ipstat.ips_forward;
  279.     pIpInfo->ipReasmReqds       = _ipstat.ips_fragments;
  280.     pIpInfo->ipReasmFails       = _ipstat.ips_fragdropped +
  281.                                   _ipstat.ips_fragtimeout;
  282.     pIpInfo->ipReasmOKs         = _ipstat.ips_reassembled; 
  283.     pIpInfo->ipInDiscards       = _ipstat.ips_toosmall;
  284.     pIpInfo->ipInUnknownProtos  = _ipstat.ips_noproto; 
  285.     pIpInfo->ipInDelivers       = _ipstat.ips_delivered; 
  286.     pIpInfo->ipOutRequests      = _ipstat.ips_localout;
  287.     pIpInfo->ipFragOKs          = _ipstat.ips_fragmented;
  288.     pIpInfo->ipFragFails        = _ipstat.ips_cantfrag;
  289.     pIpInfo->ipFragCreates      = _ipstat.ips_ofragments;
  290.     pIpInfo->ipOutDiscards      = _ipstat.ips_odropped;
  291.     pIpInfo->ipOutNoRoutes      = _ipstat.ips_noroute;
  292. #else
  293.     pIpInfo->ipInReceives       = ipstat.ips_total;
  294.  
  295.     pIpInfo->ipInHdrErrors      = ipstat.ips_badsum + ipstat.ips_tooshort +
  296.                                   ipstat.ips_toosmall + ipstat.ips_badhlen +
  297.                                   ipstat.ips_badlen + ipstat.ips_badoptions +
  298.   ipstat.ips_badvers;
  299.  
  300.     pIpInfo->ipInAddrErrors     = ipstat.ips_cantforward;
  301.     pIpInfo->ipForwDatagrams    = ipstat.ips_forward;
  302.     pIpInfo->ipReasmReqds       = ipstat.ips_fragments;
  303.     pIpInfo->ipReasmFails       = ipstat.ips_fragdropped +
  304.                                   ipstat.ips_fragtimeout;
  305.     pIpInfo->ipReasmOKs         = ipstat.ips_reassembled; 
  306.     pIpInfo->ipInDiscards       = ipstat.ips_toosmall;
  307.     pIpInfo->ipInUnknownProtos  = ipstat.ips_noproto; 
  308.     pIpInfo->ipInDelivers       = ipstat.ips_delivered; 
  309.     pIpInfo->ipOutRequests      = ipstat.ips_localout;
  310.     pIpInfo->ipFragOKs          = ipstat.ips_fragmented;
  311.     pIpInfo->ipFragFails        = ipstat.ips_cantfrag;
  312.     pIpInfo->ipFragCreates      = ipstat.ips_ofragments;
  313.     pIpInfo->ipOutDiscards      = ipstat.ips_odropped;
  314.     pIpInfo->ipOutNoRoutes      = ipstat.ips_noroute;
  315. #endif /* VIRTUAL_STACK */
  316.     pIpInfo->ipReasmTimeout     = IPFRAGTTL;
  317.  
  318.     /* 
  319.      * The MIB-II defines this variable to be the number of routing entries
  320.      * that were discarded to free up buffer space.  The BSD VxWorks 
  321.      * implementation does not free routes to free buffer space.
  322.      */
  323.     pIpInfo->ipRoutingDiscards  = 0;
  324.  
  325.     return (OK);
  326.     }
  327. /******************************************************************************
  328. *
  329. * m2IpGroupInfoSet - set MIB-II IP-group variables to new values
  330. *
  331. * This routine sets one or more variables in the IP group, as specified in the
  332. * input structure <pIpInfo> and the bit field parameter <varToSet>.
  333. *
  334. * RETURNS: OK, or ERROR if <pIpInfo> is not a valid pointer, or <varToSet> has
  335. * an invalid bit field.
  336. *
  337. * ERRNO:
  338. *  S_m2Lib_INVALID_PARAMETER
  339. *  S_m2Lib_INVALID_VAR_TO_SET
  340. *
  341. * SEE ALSO: m2IpInit(), m2IpGroupInfoGet(), m2IpAddrTblEntryGet(), 
  342. * m2IpAtransTblEntrySet(), m2IpRouteTblEntryGet(),
  343. * m2IpRouteTblEntrySet(), m2IpDelete()
  344. */
  345. STATUS m2IpGroupInfoSet
  346.     (
  347.     unsigned int varToSet,   /* bit field used to set variables */
  348.     M2_IP * pIpInfo      /* ptr to the MIB-II IP group global variables */
  349.     )
  350.     {
  351.  
  352.     /* Validate pointer and variable */
  353.  
  354.     if (pIpInfo == NULL ||
  355.         (varToSet & (M2_IPFORWARDING | M2_IPDEFAULTTTL)) == 0)
  356. {
  357. if (pIpInfo == NULL)
  358.     errnoSet (S_m2Lib_INVALID_PARAMETER);
  359. else
  360.     errnoSet (S_m2Lib_INVALID_VAR_TO_SET);
  361.         return (ERROR);
  362. }
  363.  
  364.     /*
  365.      * This variable is toggle from NOT forwarding to forwarding, and vice versa
  366.      */
  367.     if (varToSet & M2_IPFORWARDING)
  368.         {
  369.         if (pIpInfo->ipForwarding == M2_ipForwarding_not_forwarding)
  370.             _ipCfgFlags &= (~IP_DO_FORWARDING);
  371.         else
  372.             _ipCfgFlags |= IP_DO_FORWARDING; 
  373. #ifdef ROUTER_STACK
  374.         /* Inform Fastpath about the change */
  375.  
  376.         FFL_CALL (ffLibIpConfigFlagsChanged, (_ipCfgFlags));
  377. #endif /* ROUTER_STACK */
  378.         }
  379.  
  380.     /*
  381.      * Set the new time.  The calling routine is expected to have verified that
  382.      * the new time is a valid value.
  383.      */
  384.     if (varToSet & M2_IPDEFAULTTTL)
  385.         ipTimeToLive = pIpInfo->ipDefaultTTL;
  386.  
  387.     return (OK);
  388.     }
  389.  
  390. /******************************************************************************
  391. *
  392. * m2IpAddrTblEntryGet - get an IP MIB-II address entry
  393. *
  394. * This routine traverses the IP address table and does an M2_EXACT_VALUE or
  395. * a M2_NEXT_VALUE search based on the <search> parameter.  The calling 
  396. * routine is responsible for supplying a valid MIB-II entry index in the
  397. * input structure <pIpAddrTblEntry>.  The index is the local IP
  398. * address. The first entry in the table is retrieved by doing a NEXT search
  399. * with the index field set to zero. 
  400. *
  401. * RETURNS: 
  402. * OK, ERROR if the input parameter is not specified, or a match is not found.
  403. *
  404. * ERRNO:
  405. *  S_m2Lib_INVALID_PARAMETER
  406. *  S_m2Lib_ENTRY_NOT_FOUND
  407. *
  408. * SEE ALSO:
  409. * m2Lib, m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  410. * m2IpAtransTblEntrySet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  411. * m2IpDelete()
  412. */
  413. STATUS m2IpAddrTblEntryGet
  414.     (
  415.     int            search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */ 
  416.     M2_IPADDRTBL * pIpAddrTblEntry /* ptr to requested IP address entry */
  417.     )
  418.     {
  419.     struct in_ifaddr * pIfAddr;        /* Pointer to IP list of internet addr */
  420.     struct in_ifaddr * pIfAddrSaved;   /* Pointer to IP entry */
  421.     unsigned long      ipAddrSaved;    /* IP address selected */
  422.     unsigned long      ipAddr;         /* Caller IP address Table index req */
  423.     unsigned long      currIpAddr;     /* Current IP address Table index req */
  424.     int                netLock;     /* Used to secure the Network Code Access */
  425.  
  426.     /* Validate the input pointer */
  427.     if (pIpAddrTblEntry == NULL)
  428. {
  429. errnoSet (S_m2Lib_INVALID_PARAMETER);
  430.         return (ERROR);
  431. }
  432.  
  433.     /* Setup variables to be used in the table search */
  434.     pIfAddrSaved = NULL;  /* Nothing found yeat */
  435.     ipAddrSaved  = -1;  /* Largest IP address */
  436.       /* Requested IP address */
  437.     ipAddr       = pIpAddrTblEntry->ipAdEntAddr; 
  438.  
  439.     netLock = splnet ();        /* Get exclusive access to Network Code */
  440.  
  441.     /* Search the IP list of internet addresses to satisfy the request */
  442.  
  443. #ifdef VIRTUAL_STACK
  444.     for (pIfAddr = _in_ifaddr; pIfAddr != NULL; pIfAddr = pIfAddr->ia_next)
  445. #else
  446.     for (pIfAddr = in_ifaddr; pIfAddr != NULL; pIfAddr = pIfAddr->ia_next)
  447. #endif /* VIRTUAL_STACK */
  448.         {
  449. currIpAddr = ntohl((IA_SIN(pIfAddr)->sin_addr.s_addr));
  450.  
  451.         if (search == M2_EXACT_VALUE)
  452.             {
  453.             if (ipAddr == currIpAddr)
  454.                 {
  455. /* 
  456.  * Match found. Save a pointer to the entry and the ip address 
  457.  */
  458.                 pIfAddrSaved = pIfAddr;
  459.                 ipAddrSaved = currIpAddr;
  460.                 break;          /* Found EXACT Match */
  461.                 }
  462.             }
  463.         else
  464.             {
  465.     /*
  466.      * A NEXT search is satisfied by an IP address lexicographicaly 
  467.      * greater than the input IP address.  Because IP addresses are not 
  468.      * in order in the IP list, the list must be traverse complety 
  469.      * before a selection is made.
  470.      */
  471.             if (currIpAddr >= ipAddr && currIpAddr < ipAddrSaved)
  472.                 {
  473. /* Save possible IP address selection */
  474.                 pIfAddrSaved = pIfAddr;
  475.                 ipAddrSaved = currIpAddr;
  476.                 }
  477.             }
  478.         }
  479.     /* Entry not found */
  480.     if (pIfAddrSaved == NULL)
  481.         {
  482.         splx (netLock);         /* Give up exclusive access to Network Code */
  483. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  484.         return (ERROR);
  485.         }
  486.  
  487.     /* Fill the request structure with the found entry */
  488.  
  489.     pIpAddrTblEntry->ipAdEntIfIndex      = pIfAddrSaved->ia_ifp->if_index;
  490.     pIpAddrTblEntry->ipAdEntNetMask      = pIfAddrSaved->ia_subnetmask;
  491.  
  492.     if (pIfAddrSaved->ia_ifp->if_flags & IFF_BROADCAST)
  493.         pIpAddrTblEntry->ipAdEntBcastAddr =
  494.                             (ntohl(pIfAddrSaved->ia_netbroadcast.s_addr)) & 1;
  495.     else
  496.         pIpAddrTblEntry->ipAdEntBcastAddr = 1;
  497.  
  498.     splx (netLock);             /* Give up exclusive access to Network Code */
  499.  
  500.     pIpAddrTblEntry->ipAdEntAddr         =  ipAddrSaved;
  501.     pIpAddrTblEntry->ipAdEntReasmMaxSize = IP_MAXPACKET;  /* Fromp ip.h */
  502.  
  503.     return (OK);
  504.     }
  505. /******************************************************************************
  506. *
  507. * m2IpAtransTblEntryGet - get a MIB-II ARP table entry
  508. *
  509. * This routine traverses the ARP table and does an M2_EXACT_VALUE or a
  510. * M2_NEXT_VALUE search based on the <search> parameter.  The calling 
  511. * routine is responsible for supplying a valid MIB-II entry index in the 
  512. * input structure <pReqIpatEntry>.  The index is made up of the network
  513. * interface index and the IP address corresponding to the physical address.
  514. * The first entry in the table is retrieved by doing a NEXT search with the
  515. * index fields set to zero. 
  516. *
  517. * RETURNS: 
  518. * OK, ERROR if the input parameter is not specified, or a match is not found.
  519. *
  520. * ERRNO:
  521. *  S_m2Lib_INVALID_PARAMETER
  522. *  S_m2Lib_ENTRY_NOT_FOUND
  523. *
  524. * SEE ALSO:
  525. * m2Lib, m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  526. * m2IpAtransTblEntrySet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  527. * m2IpDelete()
  528. */
  529. STATUS m2IpAtransTblEntryGet
  530.     (
  531.     int                   search,       /* M2_EXACT_VALUE or M2_NEXT_VALUE */ 
  532.     M2_IPATRANSTBL      * pReqIpAtEntry /* ptr to the requested ARP entry */
  533.     )
  534.     {
  535.     unsigned long  ipAddrSaved;         /* Used for a NEXT search */
  536.     unsigned long  currIpAddr;          /* Current IP address Table index req */
  537.     int            ix;                  /* All purpose loop Index */
  538.     int            netLock;          /* Use to secure the Network Code Access */
  539.     int            maxIndex;            /* max. possible index value */
  540.     int            currIndex;           /* current interface index required */
  541.     struct llinfo_arp * pLnkInfo; 
  542.     struct rtentry * pRtEnt;
  543.     struct rtentry * pRtEntMatch; 
  544.  
  545.     /* Validate Pointer to ARP request structure */
  546.  
  547.     if (pReqIpAtEntry == NULL)
  548. {
  549. errnoSet (S_m2Lib_INVALID_PARAMETER);
  550.         return (ERROR);
  551. }
  552.  
  553.     /* Initialize all local variable before the Network Semaphore is taken */
  554.  
  555.     ix          = 0;
  556.     pRtEntMatch = NULL;  /* initialized to NULL */
  557.     maxIndex    = ipMaxUnits + 1;   /* largest possible value */
  558.     ipAddrSaved = -1; /* Largest IP address */
  559. /* Convert IP address to network byte order */
  560.     netLock = splnet ();        /* Get exclusive access to Network Code */
  561.     /* 
  562.      * Traverse the ARP Table.  The whole table is searched
  563.      */
  564. #ifdef VIRTUAL_STACK
  565.     pLnkInfo = _llinfo_arp.la_next;
  566.     while (pLnkInfo != &_llinfo_arp) 
  567. #else
  568.     pLnkInfo = llinfo_arp.la_next;
  569.     while (pLnkInfo != &llinfo_arp) 
  570. #endif /* VIRTUAL_STACK */
  571. {
  572. pRtEnt = pLnkInfo->la_rt;
  573. pLnkInfo = pLnkInfo->la_next;
  574.         currIpAddr = ntohl(((struct sockaddr_in *)
  575.     rt_key(pRtEnt))->sin_addr.s_addr);
  576.         currIndex = pRtEnt->rt_ifp->if_index;
  577.         if (search == M2_NEXT_VALUE)
  578.             {
  579.     /*
  580.      * A NEXT search is satisfied by an IP address lexicographicaly 
  581.      * equal to or greater than the input IP address.  Because IP 
  582.      * addresses are not in order in the ARP table, the list must 
  583.      * be traverse completely before a selection is made.
  584.      */
  585.             if (((currIndex > pReqIpAtEntry->ipNetToMediaIfIndex) ||
  586.          ((currIndex == pReqIpAtEntry->ipNetToMediaIfIndex) &&
  587.   (currIpAddr >= pReqIpAtEntry->ipNetToMediaNetAddress))) &&
  588. ((currIndex < maxIndex) || ((currIndex == maxIndex) &&
  589.  (currIpAddr < ipAddrSaved))))
  590.                 {
  591. pRtEntMatch = pRtEnt;  /* Found a Candidate */
  592.                 ipAddrSaved = currIpAddr;
  593.                 }
  594.             }
  595.         else
  596.             {
  597.             /* Search for an EXACT match in the ARP Table */
  598.  
  599.             if (pReqIpAtEntry->ipNetToMediaNetAddress == currIpAddr)
  600.                 {
  601. pRtEntMatch = pRtEnt;  /* Found Requested Entry */
  602.                 ipAddrSaved = currIpAddr;
  603.                 break;
  604.                 }
  605.             }
  606. }
  607.     /* pRtEntMatch is pointer to the route for the IP address found 
  608.      * The interface pointer is obtained from pRtEntMatch. This pointer is 
  609.      *  used as a key to search the MIB-II interface table, 
  610.      *  once the key is matched the interface number is found.
  611.      */
  612.  
  613.     if (pRtEntMatch != NULL)
  614.         {
  615. /* Search for Interface number in the MIB-II interface table */
  616.         pReqIpAtEntry->ipNetToMediaIfIndex = pRtEntMatch->rt_ifp->if_index;
  617.  
  618. /* Fill requested ARP entry */
  619.         pReqIpAtEntry->ipNetToMediaNetAddress = ipAddrSaved;
  620.  
  621.         pReqIpAtEntry->ipNetToMediaType =
  622.         (pRtEntMatch->rt_rmx.rmx_expire == 0) ?
  623.                                         M2_ipNetToMediaType_static :
  624.                                         M2_ipNetToMediaType_dynamic;
  625.         bcopy (LLADDR((struct sockaddr_dl *)pRtEntMatch->rt_gateway),
  626.        (char *) pReqIpAtEntry->ipNetToMediaPhysAddress.phyAddress,
  627. ETHERADDRLEN);
  628.  
  629.         splx (netLock); /* Give up exclusive access to Network Code */
  630.  
  631.         pReqIpAtEntry->ipNetToMediaPhysAddress.addrLength = ETHERADDRLEN;
  632.         return (OK);
  633.         }
  634.  
  635.     splx (netLock);             /* Give up exclusive access to Network Code */
  636.     errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  637.     return (ERROR);
  638.     }
  639. /******************************************************************************
  640. *
  641. * m2IpAtransTblEntrySet - add, modify, or delete a MIB-II ARP entry
  642. *
  643. * This routine traverses the ARP table for the entry specified in the parameter
  644. * <pReqIpAtEntry>.  An ARP entry can be added, modified, or deleted.  A  MIB-II
  645. * entry index is specified by the destination IP address and the physical media
  646. * address.  A new ARP entry can be added by specifying all the fields in the
  647. * parameter <pReqIpAtEntry>. An entry can be modified by specifying the MIB-II
  648. * index and the field that is to be modified.  An entry is deleted by 
  649. * specifying the index and setting the type field in the input parameter 
  650. * <pReqIpAtEntry> to the MIB-II value "invalid" (2).
  651. *
  652. * RETURNS: 
  653. * OK, or ERROR if the input parameter is not specified, the physical address
  654. * is not specified for an add/modify request, or the ioctl() request to the ARP
  655. * module fails.
  656. *
  657. * ERRNO:
  658. *  S_m2Lib_INVALID_PARAMETER
  659. *  S_m2Lib_ARP_PHYSADDR_NOT_SPECIFIED
  660. *
  661. * SEE ALSO:
  662. * m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  663. * m2IpAddrTblEntryGet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  664. * m2IpDelete()
  665. */
  666. STATUS m2IpAtransTblEntrySet
  667.     (
  668.     M2_IPATRANSTBL     * pReqIpAtEntry  /* pointer to MIB-II ARP entry */
  669.     )
  670.     {
  671.     int                  ioctlCmd; /* ARP module IOCTL command value */
  672.     struct arpreq        arpCmd;        /* ARP module IOCTL command structure */
  673.     struct sockaddr_in * pIpAddr; /* Pointer to an IP address */
  674.     struct sockaddr    * pPhyAddr; /* Pointer to an ethernet address */
  675.  
  676.     /* Validate Pointer to ARP request structure */
  677.  
  678.     if (pReqIpAtEntry == NULL)
  679. {
  680. errnoSet (S_m2Lib_INVALID_PARAMETER);
  681.         return (ERROR);
  682. }
  683.  
  684.     /* Initialize ARP module IOCTL variables */
  685.     bzero ((char *)&arpCmd, sizeof(struct arpreq));
  686.     pIpAddr = (struct sockaddr_in *) &arpCmd.arp_pa;    /* Protocol address */
  687.  
  688.     pIpAddr->sin_family      = AF_INET;
  689.     pIpAddr->sin_len      = sizeof(struct sockaddr_in); 
  690.     pIpAddr->sin_addr.s_addr = htonl(pReqIpAtEntry->ipNetToMediaNetAddress);
  691.  
  692.     /* Copy the Ethernet address in the IOCTL structure */
  693.     if (pReqIpAtEntry->ipNetToMediaPhysAddress.addrLength > 0)
  694.         {
  695.         pPhyAddr = &arpCmd.arp_ha;
  696.         pPhyAddr->sa_family = AF_UNSPEC;
  697.  
  698.         bcopy ((char *) pReqIpAtEntry->ipNetToMediaPhysAddress.phyAddress,
  699.                pPhyAddr->sa_data,
  700.                pReqIpAtEntry->ipNetToMediaPhysAddress.addrLength );
  701.         }
  702.  
  703.     arpCmd.arp_flags = 0;
  704.  
  705.     /* Check if the ARP entry is to be deleted, Added or Modified */
  706.  
  707.     if (pReqIpAtEntry->ipNetToMediaType == M2_ipNetToMediaType_invalid)
  708.         {
  709.  
  710.         /*
  711.          * Request to DELETE the specified ARP entry.  The hardware address
  712.          * is optional.  However, if the IP address is not found in the ARP
  713.          * table the request to delete the ARP entry can fail.
  714.          */
  715.  
  716.         ioctlCmd = SIOCDARP;
  717.         }
  718.     else
  719.         {
  720.  
  721.         /*
  722.          * Request to ADD or MODIFY the specified ARP entry.  The hardware
  723.          * address must be specified.  If this is not the case then fail.
  724.          */
  725.  
  726.         if (pReqIpAtEntry->ipNetToMediaPhysAddress.addrLength <= 0)
  727.     {
  728.     errnoSet (S_m2Lib_ARP_PHYSADDR_NOT_SPECIFIED);
  729.     return (ERROR);
  730.     }
  731.  
  732.         ioctlCmd = SIOCSARP;
  733.  
  734.         if (pReqIpAtEntry->ipNetToMediaType == M2_ipNetToMediaType_dynamic)
  735.             arpCmd.arp_flags &= ~ATF_PERM;
  736.  
  737.  
  738.         if (pReqIpAtEntry->ipNetToMediaType == M2_ipNetToMediaType_static)
  739.             arpCmd.arp_flags |= ATF_PERM;
  740.         }
  741. /* Issue IOCTL command to the ARP module */
  742.  
  743.         if (arpioctl (ioctlCmd, (caddr_t)&arpCmd) != 0)
  744.             return (ERROR);
  745.  
  746.         return (OK);
  747.     }
  748. /******************************************************************************
  749. *
  750. * m2IpRouteTblEntryGet - get a MIB-2 routing table entry 
  751. *
  752. * This routine retrieves MIB-II information about an entry in 
  753. * the network routing table and returns it in the caller-supplied structure 
  754. * <pIpRouteTblEntry>.  
  755. *
  756. * The routine compares routing table entries to the address specified by the
  757. * `ipRouteDest' member of the <pIpRouteTblEntry> structure, and retrieves an
  758. * entry chosen by the <search> type (M2_EXACT_VALUE or M2_NEXT_VALUE, as
  759. * described in the manual entry for m2Lib).
  760. * RETURNS: OK if successful, otherwise ERROR.
  761. *
  762. * ERRNO:
  763. *   S_m2Lib_INVALID_PARAMETER
  764. *   S_m2Lib_ENTRY_NOT_FOUND
  765. *    
  766. * SEE ALSO: m2Lib, m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  767. * m2IpAddrTblEntryGet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  768. * m2IpDelete()
  769. */
  770. STATUS m2IpRouteTblEntryGet 
  771.     (
  772.     int             search, /* M2_EXACT_VALUE or M2_NEXT_VALUE */ 
  773.     M2_IPROUTETBL * pIpRouteTblEntry /* route table entry */
  774.     )
  775.     {
  776.     int  ix;
  777.     int  index;
  778.     unsigned long nextLarger;
  779.     unsigned long tableDest;
  780.     unsigned long    dstIpAddr;
  781.     /* Validate the arguments */
  782.     if ((pIpRouteTblEntry == NULL) || ((search != M2_EXACT_VALUE) &&
  783.        (search != M2_NEXT_VALUE)))
  784. {
  785.     errnoSet(S_m2Lib_INVALID_PARAMETER);
  786. return (ERROR); /* invalid argument */
  787. }
  788.     dstIpAddr = pIpRouteTblEntry->ipRouteDest;
  789.     semTake (m2RouteSem, WAIT_FOREVER); /* protect the cache */
  790.     /* Reread the route table if it has since been modified. */
  791.     if (m2RouteTableGet (m2RouteTable, m2RouteTableSize) == ERROR)
  792. {
  793. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  794.         semGive (m2RouteSem);
  795. return (ERROR); /* no such entry */
  796. }
  797.     nextLarger = 0xffffffff; /* will decrease to the proper route address */
  798.     /* Find Match */
  799.     for (ix = 0, index = m2NumRouteEntries; ix < m2NumRouteEntries; ix++)
  800. {
  801. /* XXX */
  802. tableDest = ntohl (m2RouteTable [ix].ipRouteDest);
  803. if (search == M2_EXACT_VALUE) 
  804.     {
  805.     if (dstIpAddr == tableDest)
  806. {
  807. index = ix;
  808.         break; /* found exact match */
  809.      } 
  810.     }
  811. else  /* (search == M2_NEXT_VALUE) */
  812.     {
  813.     /* Find the next dest value.  The alternative to 
  814.      * going through the entire array each time is to sort it. 
  815.      * Which is more expensive is dependent on how often 
  816.      * new routes get added to the table, how often this is used,
  817.      * and how long the list is.
  818.      */
  819.      if ((tableDest >= dstIpAddr) && (tableDest < nextLarger)) 
  820. {
  821. nextLarger = tableDest;
  822.      index = ix;
  823. }
  824.     }
  825. }
  826.     if (index >= m2NumRouteEntries)
  827. {
  828. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  829.         semGive (m2RouteSem);
  830. return (ERROR); /* no such entry */
  831. }
  832.   
  833.     /* fill in return structure */    
  834.     bcopy ((char *) &m2RouteTable [index], (char *) pIpRouteTblEntry, 
  835.    sizeof (M2_IPROUTETBL));
  836.     pIpRouteTblEntry->ipRouteAge = 
  837.       (tickGet () - pIpRouteTblEntry->ipRouteAge) / sysClkRateGet ();
  838.     semGive (m2RouteSem); /* release cache */
  839.     pIpRouteTblEntry->ipRouteDest    = ntohl (pIpRouteTblEntry->ipRouteDest);
  840.     pIpRouteTblEntry->ipRouteNextHop = ntohl (pIpRouteTblEntry->ipRouteNextHop);
  841.     pIpRouteTblEntry->ipRouteMask    = ntohl (pIpRouteTblEntry->ipRouteMask);
  842.     return (OK);
  843.     }
  844. /******************************************************************************
  845. *
  846. * m2IpRouteTblEntrySet - set a MIB-II routing table entry
  847. *
  848. * This routine adds, changes, or deletes a network routing table entry.  
  849. * The table entry to be modified is specified by the `ipRouteDest' and
  850. * `ipRouteNextHop' members of the <pIpRouteTblEntry> structure.
  851. *
  852. * The <varToSet> parameter is a bit-field mask that specifies which values
  853. * in the route table entry are to be set.
  854. *
  855. * If <varToSet> has the M2_IP_ROUTE_TYPE bit set and `ipRouteType' has the
  856. * value of M2_ROUTE_TYPE_INVALID, then the the routing table entry is
  857. * deleted.
  858. *
  859. * If <varToSet> has the either the M2_IP_ROUTE_DEST, M2_IP_ROUTE_NEXT_HOP
  860. * and the M2_IP_ROUTE_MASK bits set, then a new route entry is added 
  861. * to the table. 
  862. *
  863. * RETURNS: OK if successful, otherwise ERROR.
  864. *
  865. * SEE ALSO:
  866. * m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  867. * m2IpAddrTblEntryGet(), m2IpRouteTblEntryGet(), m2IpRouteTblEntrySet(),
  868. * m2IpDelete()
  869. */
  870. STATUS m2IpRouteTblEntrySet 
  871.     (
  872.     int varToSet, /* variable to set */
  873.     M2_IPROUTETBL *  pIpRouteTblEntry /* route table entry */
  874.     )
  875.     {
  876.     struct sockaddr_in  ipRouteMask;
  877.     struct ortentry     route;
  878.     /* Convert from host order to network order */
  879.     pIpRouteTblEntry->ipRouteDest    = htonl(pIpRouteTblEntry->ipRouteDest);
  880.     pIpRouteTblEntry->ipRouteNextHop = htonl(pIpRouteTblEntry->ipRouteNextHop);
  881.     bzero ((char *)&ipRouteMask, sizeof (struct sockaddr_in));
  882.     ipRouteMask.sin_family = AF_INET;
  883.     ipRouteMask.sin_len    = sizeof (struct sockaddr_in);
  884.     /* delete the route */
  885.     if ((varToSet & M2_IP_ROUTE_TYPE) && 
  886.         (pIpRouteTblEntry->ipRouteType == M2_ipRouteType_invalid))
  887. {
  888.         if (m2IpRouteTblEntryGet (M2_EXACT_VALUE, pIpRouteTblEntry) != OK)
  889.             return (ERROR);        
  890.         ipRouteMask.sin_addr.s_addr = (u_long)pIpRouteTblEntry->ipRouteMask;
  891.         routeEntryFill (&route, pIpRouteTblEntry->ipRouteDest, 
  892.                         pIpRouteTblEntry->ipRouteNextHop, FALSE);
  893.         route.rt_flags |= RTF_MGMT;
  894.         /*
  895.          * Remove the matching route. Report the change using
  896.          * both routing socket messages and direct callbacks.
  897.          */
  898.         return (rtrequestDelEqui (&route.rt_dst, 
  899.                                   (struct sockaddr *)&ipRouteMask,
  900.                                   &route.rt_gateway, route.rt_flags, 3,
  901.                                   TRUE, TRUE, NULL)); 
  902. }
  903.     /* otherwise change it */ 
  904.     if (varToSet & (M2_IP_ROUTE_DEST | M2_IP_ROUTE_NEXT_HOP | 
  905.                                                 M2_IP_ROUTE_MASK))
  906. {
  907.         /* Fill in the route mask */
  908.         ipRouteMask.sin_addr.s_addr = (u_long)pIpRouteTblEntry->ipRouteMask;
  909.         routeEntryFill (&route, pIpRouteTblEntry->ipRouteDest, 
  910.                         pIpRouteTblEntry->ipRouteNextHop, FALSE);
  911.         route.rt_flags |= RTF_MGMT;
  912.         /*
  913.          * Add the requested route using the default weight value. Report
  914.          * the change using both routing socket messages and direct callbacks.
  915.          */
  916.         if (rtrequestAddEqui (&route.rt_dst, (struct sockaddr *)&ipRouteMask, 
  917.                               &route.rt_gateway, route.rt_flags,
  918.                               M2_ipRouteProto_netmgmt, 0, TRUE, TRUE,
  919.                               NULL) != OK)
  920.     return (ERROR);
  921. }
  922.     return (OK);
  923.     }
  924. /* generic structure for traversing the route table XXX move elsewhere */ 
  925. typedef struct 
  926.     {
  927.     ULONG arg1; 
  928.     ULONG arg2; 
  929.     ULONG arg3; 
  930.     } RT_TBL_ARGS; 
  931. /*
  932.  * Function to pass to rn_walktree().
  933.  * Return non-zero error to abort walk.
  934.  */
  935. LOCAL int routeCacheInit
  936.     (
  937.     struct radix_node * rn,
  938.     void * pRtArg
  939.     )
  940.     {
  941.     M2_IPROUTETBL * pRouteCache;  /* the route table cache */
  942.     M2_IPROUTETBL *     pEntry; /* pointer to route cache */
  943.     int routeCacheSize; /* size of cache */
  944.     int * pRouteCacheIx; 
  945.     struct sockaddr_in * pSin; /* address pointer */
  946.     struct rtentry * pRoute = (struct rtentry *)rn;
  947.     
  948.     pRouteCache =(M2_IPROUTETBL *)((RT_TBL_ARGS *)pRtArg)->arg1; 
  949.     routeCacheSize = (int )((RT_TBL_ARGS *)pRtArg)->arg2; 
  950.     pRouteCacheIx = (int * )&((RT_TBL_ARGS *)pRtArg)->arg3; 
  951.     if (*pRouteCacheIx >= routeCacheSize) /* terminate the table walk */
  952. return (ENOMEM); 
  953.     if ((pRoute->rt_flags & RTF_UP) == 0) /* go to the next entry */
  954. return (OK); /* route not up */
  955.     /* Get the next entry to add */
  956.     
  957.     pEntry = &pRouteCache [*pRouteCacheIx];
  958.     pSin = (struct sockaddr_in *) pRoute->rt_gateway;
  959.     /* test whether the gateway is of type AF_LINK and if so 
  960.      * test whether it is a real arp entry because interfaces 
  961.      * initialized with RTF_CLONE flag have a dummy gateway of 
  962.      * type AF_LINK. If it is a real arp entry then skip to next
  963.      * entry, we are only dealing with gateways of type AF_INET
  964.      */
  965.     if (pRoute->rt_gateway->sa_family == AF_LINK)
  966. {
  967. if (((struct sockaddr_dl *)pSin)->sdl_alen)
  968.     pSin = NULL; 
  969. else 
  970.     pSin = (struct sockaddr_in *)pRoute->rt_ifa->ifa_addr; 
  971. }
  972.     if (pSin == NULL)
  973. return (OK); 
  974.     pEntry->ipRouteNextHop = pSin->sin_addr.s_addr;
  975.     pSin = (struct sockaddr_in *) rt_key(pRoute);
  976.     pEntry->ipRouteDest = pSin->sin_addr.s_addr;
  977.     /* Loop through the interface table looking for a match
  978.      * on the ifp. 
  979.      */
  980.     pEntry->ipRouteIfIndex = pRoute->rt_ifp->if_index;
  981.     /* fill in the route mask */
  982.     if (rt_mask(pRoute) == NULL) /* implicit mask of 0xffffffff */
  983. pEntry->ipRouteMask = ~0L; /* host route */
  984.     else
  985. pEntry->ipRouteMask = ((struct sockaddr_in *)
  986.        rt_mask(pRoute))->sin_addr.s_addr; 
  987.     /* XXX this may not be necessary condition taken care in the above else */
  988.     if (pEntry->ipRouteDest == 0L)
  989. pEntry->ipRouteMask = 0L; /* default route */
  990.     pEntry->ipRouteAge = pRoute->rt_mod; /* initialize last modified */
  991.     /* is it a direct or indirect route ? */
  992.     if (pRoute->rt_flags & RTF_GATEWAY) 
  993. {
  994. pEntry->ipRouteMetric1 =  1; /* 1 means non local */
  995. pEntry->ipRouteType = M2_ipRouteType_indirect;
  996. }
  997.     else
  998. pEntry->ipRouteType = M2_ipRouteType_direct;
  999.     if (pRoute->rt_flags & RTF_MGMT)
  1000.         pEntry->ipRouteProto = M2_ipRouteProto_netmgmt;
  1001.     else if (pRoute->rt_flags & (RTF_DYNAMIC | RTF_MODIFIED))
  1002. pEntry->ipRouteProto = M2_ipRouteProto_icmp;
  1003.     else
  1004.         {
  1005.         /* 
  1006.          * Routes created using the routeLib API store the correct protocol 
  1007.          * value using the RT_PROTO_SET macro. The RT_PROTO_GET macro 
  1008.          * retrieves that information. All routing protocols must alter
  1009.          * the kernel routing table using the routeLib API so that the 
  1010.          * IP group MIB variables can return the correct settings. Both RIP
  1011.          * and OSPF comply with this requirement.
  1012.          */
  1013. pEntry->ipRouteProto = RT_PROTO_GET (pSin);
  1014.         if (pEntry->ipRouteProto == M2_ipRouteProto_rip)
  1015.             {
  1016.             /* 
  1017.              * The VxWorks RIP implementation stores the advertised metric
  1018.              * in the (normally unused) rmx_hopcount field of the kernel's 
  1019.              * routing table. Use that value instead of the simple 0/1 
  1020.              * boolean for local or remote routes assigned earlier.
  1021.              */
  1022.             pEntry->ipRouteMetric1 = pRoute->rt_rmx.rmx_hopcount;
  1023.             }
  1024.         else if (pEntry->ipRouteProto == 0)
  1025.             {
  1026.             /* 
  1027.              * Entries added through ioctl() calls on a routing socket or
  1028.              * otherwise created directly without using the API have an 
  1029.              * undefined value of 0 in the protocol type field. Replace it 
  1030.              * with the correct setting.
  1031.              */
  1032.             if (pRoute->rt_flags & RTF_LLINFO)
  1033.                 {
  1034.                 /* 
  1035.                  * Sanity check: handle route entries for link-level 
  1036.                  * protocols such as ARP in case they are not ignored 
  1037.                  * as expected.
  1038.                  */
  1039.         pEntry->ipRouteProto = M2_ipRouteProto_other;
  1040.                 }
  1041.             else
  1042.                 {
  1043.                 /* Handle protocol-independent locally generated entries. */
  1044.                 pEntry->ipRouteProto = M2_ipRouteProto_local;
  1045.                 }
  1046.             }
  1047.         }
  1048.     (*pRouteCacheIx)++; /* increment the index */
  1049.     return (0);
  1050.     }
  1051. /******************************************************************************
  1052. *
  1053. * m2RouteTableGet - get a copy of the network routing table.
  1054. *
  1055. * This routine gets a copy of the network routing table and puts
  1056. * it into a pre-allocated route table cache.  The route table cache is
  1057. * specified by <pRouteCache> and the size of the cache is <routeCacheSize>.  
  1058. *
  1059. * RETURNS: the number of entries in the route table cache. 
  1060. *
  1061. * ERRNO
  1062. *   S_m2Lib_INVALID_PARAMETER
  1063. */
  1064. LOCAL STATUS m2RouteTableGet 
  1065.     (
  1066.     M2_IPROUTETBL * pRouteCache,  /* the route table cache */
  1067.     int routeCacheSize /* size of cache */
  1068.     )
  1069.     {
  1070.     M2_IPROUTETBL *     pEntry; /* pointer to route cache */
  1071.     int routeCacheIx; /* route cache index */
  1072.     int spl; /* for splnet */
  1073.     struct radix_node_head * rnh; /* pointer to radix node hd*/
  1074.     RT_TBL_ARGS rtTblArgs;
  1075.      
  1076.     if (rtmodified == m2RouteTableSaved)
  1077. return (OK); /* cache still valid */
  1078.     /* Validate argument */
  1079.     if (pRouteCache == NULL)
  1080. {       
  1081. errnoSet (S_m2Lib_INVALID_PARAMETER);
  1082. return (ERROR);     /* bad parameter passed */
  1083. }
  1084.     /* If the network interface table has been changed, re-read it */
  1085.     semTake (m2InterfaceSem, WAIT_FOREVER); /* protect interface */
  1086.     /* Clear out the routing table and rebuild it */
  1087.     bzero ((char *) pRouteCache, routeCacheSize * (sizeof (M2_IPROUTETBL)));
  1088.     for (routeCacheIx = 0; routeCacheIx < routeCacheSize; routeCacheIx++) 
  1089. {
  1090. pEntry = &pRouteCache [routeCacheIx];
  1091. /* fill in defaults */
  1092.      pEntry->ipRouteMetric2  = -1;
  1093. pEntry->ipRouteMetric3  = -1;
  1094. pEntry->ipRouteMetric4  = -1;
  1095.      pEntry->ipRouteMetric5  = -1;
  1096. bcopy ((char *) &ipZeroObjectId, (char *) &pEntry->ipRouteInfo,
  1097.        sizeof (ipZeroObjectId));
  1098. }
  1099.     routeCacheIx = 0;
  1100.     rnh = rt_tables[AF_INET];
  1101.     if (rnh == NULL)
  1102. return (0);
  1103.     rtTblArgs.arg1 = (ULONG) pRouteCache;
  1104.     rtTblArgs.arg2 = (ULONG) routeCacheSize; 
  1105.     rtTblArgs.arg3 = (ULONG) routeCacheIx; 
  1106.     spl = splnet ();
  1107.     rn_walktree(rnh, routeCacheInit, (void *)&rtTblArgs);
  1108.     m2RouteTableSaved = rtmodified;
  1109.     m2NumRouteEntries = rtTblArgs.arg3; /* Number of routes in the system */
  1110.     splx (spl);
  1111.     semGive (m2InterfaceSem);
  1112.     return (OK); /* return the number of entries */
  1113.     }
  1114. /*******************************************************************************
  1115. *
  1116. * m2IpDelete - delete all resources used to access the IP group
  1117. *
  1118. * This routine frees all the resources allocated when the IP group was
  1119. * initialized.  The IP group should not be accessed after this routine has been
  1120. * called.
  1121. *
  1122. * RETURNS: OK, always.
  1123. *
  1124. * SEE ALSO: m2IpInit(), m2IpGroupInfoGet(), m2IpGroupInfoSet(), 
  1125. * m2IpAddrTblEntryGet(), m2IpAtransTblEntrySet(), m2IpRouteTblEntryGet(),
  1126. * m2IpRouteTblEntrySet()
  1127. */
  1128. STATUS m2IpDelete (void)
  1129.    {
  1130.     /* Free route semaphore */
  1131.     if (m2RouteSem != NULL)
  1132.         {
  1133.         semDelete (m2RouteSem);
  1134.         m2RouteSem = NULL;
  1135.         }
  1136.  
  1137.     /* Free route table */
  1138.     if (m2RouteTable != NULL)
  1139.         {
  1140.         KHEAP_FREE((char *)m2RouteTable);
  1141.         m2RouteTable = NULL;
  1142.         }
  1143.    return (OK);
  1144.    }