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

VxWorks

开发平台:

C/C++

  1. /* m2IfLib.c - MIB-II interface-group API for SNMP agents */
  2. /* Copyright 1984 - 2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01w,25jun02,ann  making a temporary fix to the counter update code
  8. 01v,10may02,kbw  making man page edits
  9. 01u,07may02,kbw  making man page edits
  10. 01t,25apr02,vvv  added semaphore protection in m2IfTableUpdate (SPR #74394)
  11. 01s,05dec01,vvv  fixed stack table search for high index values (SPR #71316) 
  12. 01r,15oct01,rae  merge from truestack
  13. 01q,14jun01,vvv  fixed compilation warnings
  14. 01p,30mar01,rae  allow m2 stuff to be excluded (SPR# 65428)
  15. 01o,23jan01,spm  fixed modification history after RFC 2233 merge
  16. 01n,13nov00,niq  merged version 01p of tor2_0.open_stack-f1 branch (base 01l):
  17.                  added RFC 2233 support
  18. 01m,03nov00,zhu  fix SPR#30082: ifIndex should remain constant
  19. 01l,24mar99,ead  Finally fixed the ifLastChange problem!
  20.                  Created the m2SetIfLastChange() function which is called
  21.  from ifioctl() in if.c. (SPR #23290)
  22. 01k,16mar99,ead  additional fixes to SPR #23290, not indexing in pm2IfTable
  23.                  also zeroed each instance of ifLastChange in m2IfInit so
  24.                  the correct zero value is set during a reboot
  25. 01j,16mar99,spm  recovered orphaned code from tor1_0_1.sens1_1 (SPR #25770)
  26. 01i,11mar99,ead  ifLastChange was not getting updated properly (SPR #23290)
  27. 01h,06oct98,ann  corrected the flag check in m2IfTblEntryGet() for
  28.                  ifOperStatus (SPR #22275)
  29. 01g,26aug97,spm  removed compiler warnings (SPR #7866)
  30. 01f,03apr96,rjc  set the m2InterfaceSem semaphore to NULL in m2IfDelete
  31. 01e,25jan95,jdi  doc cleanup.
  32. 01d,11nov94,rhp  edited man pages some more
  33. 01c,11nov94,rhp  edited man pages
  34. 01b,22feb94,elh  added extern to quiet compiler.
  35. 01a,08dec93,jag  written
  36. */
  37. /*
  38. DESCRIPTION
  39. This library provides MIB-II services for the interface group.  It
  40. provides routines to initialize the group, access the group scalar
  41. variables, read the table interfaces and change the state of the interfaces.
  42. For a broader description of MIB-II services, see the manual entry for m2Lib.
  43. To use this feature, include the following component:
  44. INCLUDE_MIB2_IF
  45. USING THIS LIBRARY
  46. This library can be initialized and deleted by calling m2IfInit() and
  47. m2IfDelete() respectively, if only the interface group's services are
  48. needed.  If full MIB-II support is used, this group and all other groups
  49. can be initialized and deleted by calling m2Init() and m2Delete().
  50. The interface group supports the Simple Network Management Protocol (SNMP)
  51. concept of traps, as specified by RFC 1215.  The traps supported by this
  52. group are "link up" and "link down."  This library enables an application
  53. to register a hook routine and an argument.  This hook routine can be
  54. called by the library when a "link up" or "link down" condition is
  55. detected.  The hook routine must have the following prototype:
  56. .CS
  57. void TrapGenerator (int trapType,  /@ M2_LINK_DOWN_TRAP or M2_LINK_UP_TRAP @/ 
  58.     int interfaceIndex, 
  59.     void * myPrivateArg);
  60. .CE
  61. The trap routine and argument can be specified at initialization time as
  62. input parameters to the routine m2IfInit() or to the routine m2Init().
  63. The interface-group global variables can be accessed as follows:
  64. .CS
  65. M2_INTERFACE   ifVars;
  66. if (m2IfGroupInfoGet (&ifVars) == OK)
  67.     /@ values in ifVars are valid @/
  68. .CE
  69. An interface table entry can be retrieved as follows:
  70. .CS
  71. M2_INTERFACETBL  interfaceEntry;
  72. /@ Specify zero as the index to get the first entry in the table @/
  73. interfaceEntry.ifIndex = 2;     /@ Get interface with index 2 @/
  74. if (m2IfTblEntryGet (M2_EXACT_VALUE, &interfaceEntry) == OK)
  75.     /@ values in interfaceEntry are valid @/
  76. .CE
  77. An interface entry operational state can be changed as follows:
  78. .CS
  79. M2_INTERFACETBL ifEntryToSet;
  80. ifEntryToSet.ifIndex = 2; /@ Select interface with index 2     @/
  81.                           /@ MIB-II value to set the interface @/
  82.                           /@ to the down state.                @/
  83. ifEntryToSet.ifAdminStatus = M2_ifAdminStatus_down;
  84. if (m2IfTblEntrySet (&ifEntryToSet) == OK)
  85.     /@ Interface is now in the down state @/
  86. .CE
  87. INCLUDE FILES: m2Lib.h
  88.  
  89. SEE ALSO: m2Lib, m2SysLib, m2IpLib, m2IcmpLib, m2UdpLib, m2TcpLib
  90. */
  91. /* includes */
  92. #include "vxWorks.h"
  93. #include "stdio.h"
  94. #include "stdlib.h"
  95. #include "m2IfLib.h"
  96. #include "private/m2LibP.h"
  97. #include "ioctl.h"
  98. #include "semLib.h"
  99. #include "string.h"
  100. #include "tickLib.h"
  101. #include "sysLib.h"
  102. #include "errnoLib.h"
  103. #include "limits.h"
  104. #include "float.h"
  105. #include "memPartLib.h"
  106. #include "ipProto.h"
  107. #include "private/muxLibP.h"
  108. #ifdef VIRTUAL_STACK
  109. #include "netinet/vsLib.h"
  110. #endif    /* VIRTUAL_STACK */
  111. /* defines */
  112. #define END_OBJ_MIB        1            /* Used in ifnetToEndFieldsGet() */
  113. #define END_OBJ_FLAGS      2            /* Used in ifnetToEndFieldsGet() */
  114. /* imports */
  115. IMPORT FUNCPTR  _m2SetIfLastChange;     /* def'd in if.c for scalability */
  116. IMPORT FUNCPTR  _m2IfTableUpdate;
  117. /* globals */
  118. static const UI64 U64_MAX  = { UINT_MAX, UINT_MAX };
  119. #ifndef VIRTUAL_STACK
  120. AVL_TREE      pM2IfRoot    = NULL;
  121. AVL_TREE *    pM2IfRootPtr = &pM2IfRoot;
  122. M2_IFINDEX *  pm2IfTable;     /* Network I/F table (Allocated Dynamically) */
  123. int           m2IfCount;      /* Number of network interfaces */
  124. int           ifsInList;      /* Actual number of interfaces in our list */
  125. LOCAL FUNCPTR pM2TrapRtn;     /* Pointer to trap routine supplied by the user */
  126. LOCAL void *  pM2TrapRtnArg;  /* Pointer to trap routine argument supplied by */
  127.       /* the user */
  128. /* last time a row was added/removed from the ifTable/ifXTable */
  129. LOCAL ULONG ifTableLastChange;
  130. /* last time a row was added/removed from the ifStackTable or when the
  131.  * ifStackStatus was last changed */
  132. LOCAL ULONG ifStackLastChange;
  133. /* Semaphore used to protect the Interface group */
  134. SEM_ID m2InterfaceSem;
  135. /* 
  136.  * Global variable used to keep the group startup time in hundreds of a second. 
  137.  * The functionality here is the same as the functionality provided in the 
  138.  * module m2SysLib.c.  It is duplicated to allow for both modules to exist
  139.  * independently.
  140.  */
  141. LOCAL unsigned long startCentiSecs; /* Hundred of Seconds at start */
  142. #endif    /* VIRTUAL_STACK */
  143. /*
  144.  * The zero object id is used throught out the MIB-II library to fill OID 
  145.  * requests when an object ID is not provided by a group variable.
  146.  */
  147. LOCAL M2_OBJECTID ifZeroObjectId = { 2, {0,0} };
  148. extern int ifioctl ();
  149. LOCAL void   m2IfIncr32Bit (M2_DATA *, ULONG *, ULONG);
  150. LOCAL void   m2IfIncr64Bit (M2_DATA *, UI64 *, ULONG);
  151. LOCAL void   m2IfDefaultValsGet (M2_DATA *, M2_IFINDEX *);
  152. LOCAL void   m2IfCommonValsGet (M2_DATA *, M2_IFINDEX *);
  153. LOCAL STATUS rcvEtherAddrGet (struct ifnet *, M2_IFINDEX *);
  154. LOCAL STATUS rcvEtherAddrAdd (M2_IFINDEX *, unsigned char *);
  155. LOCAL unsigned long centiSecsGet (void);
  156. LOCAL BOOL   stackEntryIsTop(int);
  157. LOCAL BOOL   stackEntryIsBottom(int);
  158. LOCAL void * ifnetToEndFieldsGet (struct ifnet *, int);
  159. /***************************************************************************
  160. *
  161. * m2IfAlloc - allocate the structure for the interface table
  162. *
  163. * This routine is called by the driver during initialization of the interface.
  164. * The memory for the interface table is allocated here.  We also set the
  165. * default update routines in the M2_ID struct. These fields can later be
  166. * overloaded using the installed routines in the M2_ID.  Once this function
  167. * returns, it is the driver's responsibility to set the pMib2Tbl pointer in
  168. * the END object to the new M2_ID.
  169. *
  170. * When this call returns, the calling routine must set the END_MIB_2233 
  171. * bit of the flags field in the END object.
  172. *
  173. * RETURNS: Pointer to the M2_ID structure that was allocated.
  174. */
  175. M2_ID * m2IfAlloc
  176.     (
  177.     ULONG        ifType,          /* If type of the interface */
  178.     UCHAR *      pEnetAddr,       /* Physical address of interface */
  179.     ULONG        addrLen,         /* Address length */
  180.     ULONG        mtuSize,         /* MTU of interface */
  181.     ULONG        speed,           /* Speed of the interface */
  182.     char *       pName,           /* Name of the device */
  183.     int          unit             /* Unit number of the device */
  184.     )
  185.     {
  186.     M2_ID *             pM2Id;
  187.     M2_INTERFACETBL *   pM2IfTbl;
  188.     M2_2233TBL *        pM2233Tbl;
  189.     /* Allocate memory for the interface table */
  190.     pM2Id = KHEAP_ALLOC(sizeof(M2_ID));
  191.     if (!pM2Id)
  192.         return NULL;
  193.     memset(pM2Id, 0, sizeof(M2_ID));
  194.     /* Enter the values provided by the driver */
  195.     pM2IfTbl = &pM2Id->m2Data.mibIfTbl;
  196.     pM2233Tbl = &pM2Id->m2Data.mibXIfTbl;
  197.     pM2IfTbl->ifType  = ifType;
  198.     pM2IfTbl->ifMtu   = mtuSize;
  199.     pM2IfTbl->ifSpeed = speed;
  200.     memcpy (&pM2IfTbl->ifPhysAddress.phyAddress[0], pEnetAddr, addrLen);
  201.     pM2IfTbl->ifPhysAddress.addrLength = addrLen;
  202.     sprintf (&pM2233Tbl->ifName[0], "%s%d", pName, unit);
  203.     /* Set the default update routines */
  204.     pM2Id->m2PktCountRtn  = m2IfGenericPacketCount;
  205.     pM2Id->m2CtrUpdateRtn = m2IfCounterUpdate;
  206.     pM2Id->m2VarUpdateRtn = m2IfVariableUpdate;
  207.     return (pM2Id);
  208.     }
  209. /***************************************************************************
  210. *
  211. * m2IfFree - free an interface data structure
  212. *
  213. * This routine frees the given M2_ID.  Note if the driver is not an RFC 2233
  214. * driver then the M2_ID is NULL and this function simply returns.
  215. *
  216. * RETURNS: OK if successful, ERROR otherwise
  217. */
  218. STATUS m2IfFree
  219.     (
  220.     M2_ID * pId      /* pointer to the driver's M2_ID object */
  221.     )
  222.     {
  223.     if (pId == NULL)
  224.         {
  225.         return ERROR;
  226.         }
  227.     else
  228.         {
  229.         KHEAP_FREE((char *)pId);
  230.         return OK;
  231.         }
  232.     }
  233. /***************************************************************************
  234. *
  235. * m2IfIncr32Bit - increment a 32 bit interface counter
  236. *
  237. * This function is used to increment an interface counter.  The counter
  238. * to update is pointed to by pStat and amount specifies how much to increment
  239. * the counter.  If the counter would roll-over if incremented by the amount,
  240. * the the ifCounterDiscontinuityTime is set to the system uptime.
  241. *
  242. * RETURNS: N/A
  243. */
  244. LOCAL void m2IfIncr32Bit
  245.     (
  246.     M2_DATA * pMib2Data,        /* pointer to interface stat struct */
  247.     ULONG *   pStat,            /* pointer to the counter to update */
  248.     ULONG     amount            /* amount to update the counter */
  249.     )
  250.     {
  251. #ifdef notdef
  252.     if (*pStat > UINT_MAX)
  253.         {
  254.         *pStat = UINT_MAX;
  255.         }
  256.     if ((UINT_MAX - *pStat) < amount)
  257.         {
  258.         *pStat = UINT_MAX;
  259.         pMib2Data->mibXIfTbl.ifCounterDiscontinuityTime = centiSecsGet();
  260.         }
  261.     else
  262.         {
  263.         *pStat += amount;
  264.         }
  265. #endif
  266.         *pStat += amount;
  267.     }
  268. /***************************************************************************
  269. *
  270. * m2IfIncr64Bit - increment a 64 bit interface counter
  271. *
  272. * This function is used to increment an interface counter.  The counter
  273. * to update is pointed to by pStat and amount specifies how much to increment
  274. * the counter.  If the counter would roll-over if incremented by the amount,
  275. * the the ifCounterDiscontinuityTime is set to the system uptime.
  276. *
  277. * RETURNS: N/A
  278. */
  279. LOCAL void m2IfIncr64Bit
  280.     (
  281.     M2_DATA *   pMib2Data,  /* pointer to interface stat struct */
  282.     UI64 *      pStat,      /* pointer to the counter to update */
  283.     ULONG       amount      /* amount to update the counter */
  284.     )
  285.     {
  286.     UI64 u64Diff;
  287.     UI64 u64Amount;
  288.     if (UI64_COMP(pStat, &U64_MAX) >= 0)
  289.         {
  290.         UI64_COPY(pStat, &U64_MAX);
  291.         }
  292.     UI64_ZERO(&u64Diff);
  293.     UI64_ZERO(&u64Amount);
  294.     u64Amount.low = amount;
  295.     UI64_SUB64(&u64Diff, &U64_MAX, pStat);
  296.     if (UI64_COMP(&u64Diff, &u64Amount) < 0)
  297.         {
  298.         UI64_COPY(pStat, &U64_MAX);
  299.         pMib2Data->mibXIfTbl.ifCounterDiscontinuityTime = centiSecsGet();
  300.         }
  301.     else
  302.         {
  303.         UI64_ADD32(pStat, amount);
  304.         }
  305.     }
  306. /***************************************************************************
  307. *
  308. * m2IfGenericPacketCount - increment the interface packet counters 
  309. *
  310. * This function updates the basic interface counters for a packet. It knows 
  311. * nothing of the underlying media.  Thus, so only the 'ifInOctets', 
  312. * 'ifHCInOctets', 'ifOutOctets', 'ifHCOutOctets', and 
  313. * 'ifCounterDiscontinuityTime' variables are incremented.  The <ctrl> 
  314. * argument specifies whether the packet is being sent or just received 
  315. * (M2_PACKET_IN or M2_PACKET_OUT).
  316. *
  317. * RETURNS: ERROR if the M2_ID is NULL, OK if the counters were updated.
  318. */
  319. STATUS m2IfGenericPacketCount 
  320.     (
  321.     M2_ID *   pId,      /* The pointer to the device M2_ID object */
  322.     UINT      ctrl,     /* Update In or Out counters */
  323.     UCHAR *   pPkt,     /* The incoming/outgoing packet */
  324.     ULONG     pktLen    /* Length of the packet */
  325.     )
  326.     {
  327.     M2_DATA * pMib2Data;
  328.     if (pId == NULL)
  329.         return ERROR;
  330.     pMib2Data = &(pId->m2Data);
  331.     switch (ctrl)
  332.         {
  333.         case M2_PACKET_IN:
  334.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInOctets),
  335.                           pktLen);
  336.             break;
  337.         case M2_PACKET_OUT:
  338.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutOctets),
  339.                           pktLen);
  340.             break;
  341.         default:
  342.             return ERROR;
  343.         }
  344.     return OK;
  345.     }
  346. /***************************************************************************
  347. * m2If8023PacketCount - increment the packet counters for an 802.3 device 
  348. *
  349. * This function is used to update basic interface counters for a packet.  The
  350. * ctrl argument specifies whether the packet is being sent or just received
  351. * (M2_PACKET_IN or M2_PACKET_OUT).  This function only works for 802.3
  352. * devices as it understand the Ethernet packet format.  The following counters
  353. * are updated:
  354. * ml
  355. * m - 
  356. * ifInOctets
  357. * m - 
  358. * ifInUcastPkts
  359. * m - 
  360. * ifInNUcastPkts
  361. * m - 
  362. * ifOutOctets
  363. * m - 
  364. * ifOutUcastPkts
  365. * m - 
  366. * ifOutNUcastPkts
  367. * m - 
  368. * ifInMulticastPkts
  369. * m - 
  370. * ifInBroadcastPkts
  371. * m - 
  372. * ifOutMulticastPkts
  373. * m - 
  374. * ifOutBroadcastPkts
  375. * m - 
  376. * ifHCInOctets
  377. * m - 
  378. * ifHCInUcastPkts
  379. * m - 
  380. * ifHCOutOctets
  381. * m - 
  382. * ifHCOutUcastPkts
  383. * m - 
  384. * ifHCInMulticastPkts
  385. * m - 
  386. * ifHCInBroadcastPkts
  387. * m - 
  388. * ifHCOutMulticastPkts
  389. * m - 
  390. * ifHCOutBroadcastPkts
  391. * m - 
  392. * ifCounterDiscontinuityTime
  393. * me
  394. * This function should be called right after the netMblkToBufCopy() function
  395. * has been completed.  The first 6 bytes in the resulting buffer must contain 
  396. * the destination MAC address and the second 6 bytes of the buffer must 
  397. * contain the source MAC address.
  398. * The type of MAC address (i.e. broadcast, multicast, or unicast) is
  399. * determined by the following:
  400. * ml
  401. * m broadcast address:  
  402. *  ff:ff:ff:ff:ff:ff
  403. * m multicast address:  
  404. *  first bit is set
  405. * m unicast address:  
  406. *  any other address not matching the above
  407. * me
  408. * RETURNS: ERROR, if the M2_ID is NULL, or the ctrl is invalid; OK, if
  409. * the counters were updated.
  410. */
  411. STATUS m2If8023PacketCount
  412.     (
  413.     M2_ID *   pId,      /* The pointer to the device M2_ID object */
  414.     UINT      ctrl,     /* Update In or Out counters */
  415.     UCHAR *   pPkt,     /* The incoming/outgoing packet */
  416.     ULONG     pktLen    /* Length of the packet */
  417.     )
  418.     {
  419.     M2_DATA * pMib2Data;
  420.     UCHAR pBcastAddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  421.     UCHAR mcastBit = 0x01;
  422.     USHORT *pSrc, *pDst;
  423.     if (pId == NULL)
  424.         return ERROR;
  425.     pMib2Data = &(pId->m2Data);
  426.     pDst = (USHORT *)pBcastAddr;
  427.     pSrc = (USHORT *)pPkt;
  428.     switch (ctrl)
  429.         {
  430.         case M2_PACKET_IN:
  431.             {
  432.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInOctets),
  433.                           pktLen);
  434.             /* the first 6 bytes is the destination MAC address */
  435.             if (*pPkt & mcastBit) /* multicast address */
  436.                 {
  437.                 if (pSrc[0] == pDst[0] &&
  438.                     pSrc[1] == pDst[1] &&
  439.                     pSrc[2] == pDst[2])
  440.                     m2IfIncr32Bit(pMib2Data, /* broadcast address */
  441.                                   &(pMib2Data->mibXIfTbl.ifInBroadcastPkts), 1);
  442.                 else
  443.                     m2IfIncr32Bit(pMib2Data,
  444.                                   &(pMib2Data->mibXIfTbl.ifInMulticastPkts), 1);
  445.                 m2IfIncr32Bit(pMib2Data,
  446.                               &(pMib2Data->mibIfTbl.ifInNUcastPkts), 1);
  447.                 }
  448.             else /* unicast address */
  449.                 {
  450.                 m2IfIncr32Bit(pMib2Data,
  451.                               &(pMib2Data->mibIfTbl.ifInUcastPkts), 1);
  452.                 }
  453.             break;
  454.             }
  455.         case M2_PACKET_OUT:
  456.             {
  457.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutOctets),
  458.                           pktLen);
  459.             /* the first 6 bytes is the destination MAC address */
  460.             if (*pPkt & mcastBit) /* multicast address */
  461.                 {
  462.                 if (pSrc[0] == pDst[0] &&
  463.                     pSrc[1] == pDst[1] &&
  464.                     pSrc[2] == pDst[2])
  465.                     m2IfIncr32Bit(pMib2Data,
  466.                                   &(pMib2Data->mibXIfTbl.ifOutBroadcastPkts), 1);
  467.                 else
  468.                     m2IfIncr32Bit(pMib2Data,
  469.                                   &(pMib2Data->mibXIfTbl.ifOutMulticastPkts), 1);
  470.                 m2IfIncr32Bit(pMib2Data,
  471.                               &(pMib2Data->mibIfTbl.ifOutNUcastPkts), 1);
  472.                 }
  473.             else /* unicast address */
  474.                 {
  475.                 m2IfIncr32Bit(pMib2Data,
  476.                               &(pMib2Data->mibIfTbl.ifOutUcastPkts), 1);
  477.                 }
  478.             break;
  479.             }
  480.         default:
  481.             return ERROR;
  482.         }
  483.     return OK;
  484.     }
  485. /***************************************************************************
  486. *
  487. * m2IfCounterUpdate - increment interface counters 
  488. *
  489. * This function is used to directly update an interface counter.  The counter
  490. * is specified by <ctrId> and the amount to increment it is specified by value.
  491. * If the counter would roll over then the 'ifCounterDiscontinuityTime' is
  492. * updated with the current system uptime.
  493. *
  494. * RETURNS: ERROR if the M2_ID is NULL, OK if the counter was updated.
  495. */
  496. STATUS m2IfCounterUpdate 
  497.     (
  498.     M2_ID *   pId,    /* The pointer to the device M2_ID object */
  499.     UINT      ctrId,  /* Counter to update */
  500.     ULONG     value   /* Amount to update the counter by */
  501.     )
  502.     {
  503.     M2_DATA * pMib2Data;
  504.     if (pId == NULL)
  505.         return ERROR;
  506.     pMib2Data = &(pId->m2Data);
  507.     switch (ctrId)
  508.         {
  509.         case M2_ctrId_ifInOctets:
  510.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInOctets),
  511.                           value);
  512.             break;
  513.         case M2_ctrId_ifInUcastPkts:
  514.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInUcastPkts),
  515.                           value);
  516.             break;
  517.         case M2_ctrId_ifInNUcastPkts:
  518.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInNUcastPkts),
  519.                           value);
  520.             break;
  521.         case M2_ctrId_ifInDiscards:
  522.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInDiscards),
  523.                           value);
  524.             break;
  525.         case M2_ctrId_ifInErrors:
  526.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInErrors),
  527.                           value);
  528.             break;
  529.         case M2_ctrId_ifInUnknownProtos:
  530.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifInUnknownProtos),
  531.                           value);
  532.             break;
  533.         case M2_ctrId_ifOutOctets:
  534.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutOctets),
  535.                           value);
  536.             break;
  537.         case M2_ctrId_ifOutUcastPkts:
  538.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutUcastPkts),
  539.                           value);
  540.             break;
  541.         case M2_ctrId_ifOutNUcastPkts:
  542.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutNUcastPkts),
  543.                           value);
  544.             break;
  545.         case M2_ctrId_ifOutDiscards:
  546.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutDiscards),
  547.                           value);
  548.             break;
  549.         case M2_ctrId_ifOutErrors:
  550.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibIfTbl.ifOutErrors),
  551.                           value);
  552.             break;
  553.         case M2_ctrId_ifInMulticastPkts:
  554.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifInMulticastPkts),
  555.                           value);
  556.             break;
  557.         case M2_ctrId_ifInBroadcastPkts:
  558.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifInBroadcastPkts),
  559.                           value);
  560.             break;
  561.         case M2_ctrId_ifOutMulticastPkts:
  562.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifOutMulticastPkts),
  563.                           value);
  564.             break;
  565.         case M2_ctrId_ifOutBroadcastPkts:
  566.             m2IfIncr32Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifOutBroadcastPkts),
  567.                           value);
  568.             break;
  569.         case M2_ctrId_ifHCInOctets:
  570.             m2IfIncr64Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifHCInOctets),
  571.                           value);
  572.             break;
  573.         case M2_ctrId_ifHCInUcastPkts:
  574.             m2IfIncr64Bit(pMib2Data, &(pMib2Data->mibXIfTbl.ifHCInUcastPkts),
  575.                           value);
  576.             break;
  577.         case M2_ctrId_ifHCInMulticastPkts:
  578.             m2IfIncr64Bit(pMib2Data,
  579.                           &(pMib2Data->mibXIfTbl.ifHCInMulticastPkts), value);
  580.             break;
  581.         case M2_ctrId_ifHCInBroadcastPkts:
  582.             m2IfIncr64Bit(pMib2Data,
  583.                           &(pMib2Data->mibXIfTbl.ifHCInBroadcastPkts), value);
  584.             break;
  585.         case M2_ctrId_ifHCOutOctets:
  586.             m2IfIncr64Bit(pMib2Data,
  587.                           &(pMib2Data->mibXIfTbl.ifHCOutOctets), value);
  588.             break;
  589.         case M2_ctrId_ifHCOutUcastPkts:
  590.             m2IfIncr64Bit(pMib2Data,
  591.                           &(pMib2Data->mibXIfTbl.ifHCOutUcastPkts), value);
  592.             break;
  593.         case M2_ctrId_ifHCOutMulticastPkts:
  594.             m2IfIncr64Bit(pMib2Data,
  595.                           &(pMib2Data->mibXIfTbl.ifHCOutMulticastPkts), value);
  596.             break;
  597.         case M2_ctrId_ifHCOutBroadcastPkts:
  598.             m2IfIncr64Bit(pMib2Data,
  599.                           &(pMib2Data->mibXIfTbl.ifHCOutBroadcastPkts), value);
  600.             break;
  601.         default:
  602.             return ERROR;
  603.         }
  604.     return OK;
  605.     }
  606. /***************************************************************************
  607. *
  608. * m2IfVariableUpdate - update the contents of an interface non-counter object 
  609. *
  610. * This function is used to update an interface variable.  The variable is
  611. * specified by varId and the data to use is specified by pData.  Note that
  612. * different variable expect different types of data.  Here is a list of the
  613. * variables and the type of data expected.  Therefore, pData will be cast to 
  614. * the type listed below for each variable.
  615. * ts
  616. * Variable               | Casted to Type
  617. * ----------------------------------------
  618. * ifDescr                | char *
  619. * ifType                 | UINT
  620. * ifMtu                  | ULONG
  621. * ifSpeed                | ULONG
  622. * ifPhysAddress          | M2_PHYADDR *
  623. * ifAdminStatus          | ULONG
  624. * ifOperStatus           | ULONG
  625. * ifLastChange           | ULONG
  626. * ifOutQLen              | ULONG
  627. * ifSpecific             | M2_OBJECTID *
  628. * ifName                 | char *
  629. * ifLinkUpDownTrapEnable | UINT
  630. * ifHighSpeed            | ULONG
  631. * ifPromiscuousMode      | UINT
  632. * ifConnectorPresent     | UINT
  633. * ifAlias                | char *
  634. * te
  635. * RETURNS: ERROR, if the M2_ID is NULL; OK, if the variable was updated.
  636. */
  637. STATUS m2IfVariableUpdate 
  638.     (
  639.     M2_ID *   pId,    /* The pointer to the device M2_ID object */
  640.     UINT      varId,  /* Variable to update */
  641.     caddr_t   pData   /* Data to use */
  642.     )
  643.     {
  644.     M2_DATA * pMib2Data;
  645.     if (pId == NULL)
  646.         return ERROR;
  647.     pMib2Data = &(pId->m2Data);
  648.     switch (varId)
  649.         {
  650.         case M2_varId_ifDescr:
  651.             strcpy(pMib2Data->mibIfTbl.ifDescr, (char *)pData);
  652.             break;
  653.         case M2_varId_ifType:
  654.             pMib2Data->mibIfTbl.ifType = (UINT)pData;
  655.             break;
  656.         case M2_varId_ifMtu:
  657.             pMib2Data->mibIfTbl.ifMtu = (ULONG)pData;
  658.             break;
  659.         case M2_varId_ifSpeed:
  660.             pMib2Data->mibIfTbl.ifSpeed = (ULONG)pData;
  661.             break;
  662.         case M2_varId_ifPhysAddress:
  663.             memcpy(&(pMib2Data->mibIfTbl.ifPhysAddress), (M2_PHYADDR *)pData,
  664.                    sizeof(M2_PHYADDR));
  665.             break;
  666.         case M2_varId_ifAdminStatus:
  667.             pMib2Data->mibIfTbl.ifAdminStatus = (ULONG)pData;
  668.             break;
  669.         case M2_varId_ifOperStatus:
  670.             pMib2Data->mibIfTbl.ifOperStatus = (ULONG)pData;
  671.             break;
  672.         case M2_varId_ifLastChange:
  673.             pMib2Data->mibIfTbl.ifLastChange = (ULONG)pData;
  674.             break;
  675.         case M2_varId_ifOutQLen:
  676.             pMib2Data->mibIfTbl.ifOutQLen = (ULONG)pData;
  677.             break;
  678.         case M2_varId_ifSpecific:
  679.             memcpy(&(pMib2Data->mibIfTbl.ifSpecific), (M2_OBJECTID *)pData,
  680.                    sizeof(M2_OBJECTID));
  681.             break;
  682.         case M2_varId_ifName:
  683.             strcpy(pMib2Data->mibXIfTbl.ifName, (char *)pData);
  684.             break;
  685.         case M2_varId_ifLinkUpDownTrapEnable:
  686.             pMib2Data->mibXIfTbl.ifLinkUpDownTrapEnable = (UINT)pData;
  687.             break;
  688.         case M2_varId_ifHighSpeed:
  689.             pMib2Data->mibXIfTbl.ifHighSpeed = (ULONG)pData;
  690.             break;
  691.         case M2_varId_ifPromiscuousMode:
  692.             pMib2Data->mibXIfTbl.ifPromiscuousMode = (UINT)pData;
  693.             break;
  694.         case M2_varId_ifConnectorPresent:
  695.             pMib2Data->mibXIfTbl.ifConnectorPresent = (UINT)pData;
  696.             break;
  697.         case M2_varId_ifAlias:
  698.             strcpy(pMib2Data->mibXIfTbl.ifAlias, (char *)pData);
  699.             break;
  700.         default:
  701.             return ERROR;
  702.         }
  703.     return OK;
  704.     }
  705. /***************************************************************************
  706. *
  707. * m2IfPktCountRtnInstall - install an interface packet counter routine
  708. *
  709. * This function installs a routine in the M2_ID.  This routine is a packet
  710. * counter which is able to update all the interface counters.
  711. *
  712. * RETURNS: ERROR if the M2_ID is NULL, OK if the routine was installed.
  713. */
  714. STATUS m2IfPktCountRtnInstall
  715.     (
  716.     M2_ID *           pId,
  717.     M2_PKT_COUNT_RTN  pRtn
  718.     )
  719.     {
  720.     if (pId == NULL)
  721.         return ERROR;
  722.     pId->m2PktCountRtn = pRtn;
  723.     return OK;
  724.     }
  725. /***************************************************************************
  726. *
  727. * m2IfCtrUpdateRtnInstall - install an interface counter update routine
  728. *
  729. * This function installs a routine in the M2_ID.  This routine is able to
  730. * update a single specified interface counter.
  731. *
  732. * RETURNS: ERROR if the M2_ID is NULL, OK if the routine was installed.
  733. */
  734. STATUS m2IfCtrUpdateRtnInstall
  735.     (
  736.     M2_ID *            pId,
  737.     M2_CTR_UPDATE_RTN  pRtn
  738.     )
  739.     {
  740.     if (pId == NULL)
  741.         return ERROR;
  742.     pId->m2CtrUpdateRtn = pRtn;
  743.     return OK;
  744.     }
  745. /***************************************************************************
  746. *
  747. * m2IfVarUpdateRtnInstall - install an interface variable update routine
  748. *
  749. * This function installs a routine in the M2_ID.  This routine is able to
  750. * update a single specified interface variable.
  751. *
  752. * RETURNS: ERROR if the M2_ID is NULL, OK if the routine was installed.
  753. */
  754. STATUS m2IfVarUpdateRtnInstall
  755.     (
  756.     M2_ID *            pId,
  757.     M2_VAR_UPDATE_RTN  pRtn
  758.     )
  759.     {
  760.     if (pId == NULL)
  761.         return ERROR;
  762.     pId->m2VarUpdateRtn = pRtn;
  763.     return OK;
  764.     }
  765. /******************************************************************************
  766. *
  767. * centiSecsGet - get hundreds of a second
  768. *
  769. * The number of hundreds of a second that have passed since this routine was
  770. * first called.
  771. *
  772. * RETURNS: Hundreds of a second since the group was initialized.
  773. *
  774. * SEE ALSO: N/A
  775. */
  776. LOCAL unsigned long centiSecsGet (void)
  777.     {
  778.     unsigned long currCentiSecs;
  779.     unsigned long clkRate = sysClkRateGet ();
  780.     if (startCentiSecs == 0)
  781. startCentiSecs = (tickGet () * 100) / clkRate;
  782.     currCentiSecs = (tickGet () * 100) / clkRate;
  783.     return (currCentiSecs - startCentiSecs);
  784.     }
  785. /******************************************************************************
  786. *
  787. * m2IfInit - initialize MIB-II interface-group routines
  788. *
  789. * This routine allocates the resources needed to allow access to the 
  790. * MIB-II interface-group variables.  This routine must be called before any 
  791. * interface variables can be accessed.  The input parameter <pTrapRtn> is an
  792. * optional pointer to a user-supplied SNMP trap generator.  The input parameter
  793. * <pTrapArg> is an optional argument to the trap generator.  Only one trap
  794. * generator is supported.
  795. *
  796. * VXWORKS AE PROTECTION DOMAINS
  797. * Under VxWorks AE, you can call m2IfInit() from within the kernel 
  798. * protection domain only, and the data referenced in the <pTrapRtn> and  
  799. * <pTrapArg> parameters must reside in the kernel protection domain.  
  800. * This restriction does not apply to non-AE versions of VxWorks.  
  801. *
  802. * RETURNS: OK, if successful; ERROR, if an error occurred.
  803. *
  804. * ERRNO:
  805. * S_m2Lib_CANT_CREATE_IF_SEM
  806. *
  807. * SEE ALSO: 
  808. * m2IfGroupInfoGet(), m2IfTblEntryGet(), m2IfTblEntrySet(), m2IfDelete()
  809. */
  810. STATUS m2IfInit 
  811.     (
  812.     FUNCPTR  pTrapRtn,  /* pointer to user trap generator */
  813.     void *  pTrapArg /* pointer to user trap generator argument */
  814.     )
  815.     {
  816.     /* add hooks for if.c */
  817.     _m2SetIfLastChange = (FUNCPTR) m2SetIfLastChange;
  818.     _m2IfTableUpdate   = (FUNCPTR) m2IfTableUpdate;
  819.     /* Create the Interface semaphore */
  820.     if (m2InterfaceSem == NULL)
  821.         {
  822.         m2InterfaceSem = semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE |
  823.                                    SEM_DELETE_SAFE);
  824.         if (m2InterfaceSem == NULL)
  825.             {
  826.     errnoSet (S_m2Lib_CANT_CREATE_IF_SEM);
  827.             return (ERROR);
  828.             }
  829.         }
  830.     /* Take the interface semaphore, and initialize group global variables */
  831.  
  832.     semTake (m2InterfaceSem, WAIT_FOREVER);
  833.     pM2TrapRtn    = pTrapRtn;
  834.     pM2TrapRtnArg = pTrapArg;
  835. #ifdef VIRTUAL_STACK
  836.     _ifTableLastChange = 0;
  837.     _ifStackLastChange = 0;
  838. #else    /* VIRTUAL_STACK */
  839.     ifTableLastChange = 0;
  840.     ifStackLastChange = 0;
  841. #endif   /* VIRTUAL_STACK */
  842.     
  843.     semGive (m2InterfaceSem);
  844.     (void) centiSecsGet ();     /* Initialize group time reference */
  845.     return (OK);
  846.     }
  847. /***************************************************************************
  848. *
  849. * m2IfTableUpdate - insert or remove an entry in the ifTable
  850. *
  851. * This routine is called by if_attach and if_detach to insert/remove
  852. * an entry from the local m2IfLib ifTable.  The status can be either
  853. * M2_IF_TABLE_INSERT or M2_IF_TABLE_REMOVE.  The ifIndex that is searched
  854. * for in the AVL tree is specified in given the ifnet struct.
  855. * <if_ioctl> is a function pointer to change the flags on the interface.
  856. * <addr_get> is a function pointer to add the interface's addresses to
  857. * ifRcvAddressTable.  Ethernet interfaces can use NULL for both function
  858. * pointers, other interfaces will need to pass an appropriate function.
  859. *
  860. * RETURNS: ERROR if entry does not exist, OK if the entry was deleted
  861. */
  862. STATUS m2IfTableUpdate
  863.     (
  864.     struct ifnet *  pIfNet,
  865.     UINT            status,   /* attaching or detaching */
  866.     int             (*if_ioctl) /* protocol specific ioctl or null for default (ethernet) */
  867.       (struct socket*,u_long,caddr_t),
  868.     STATUS          (*addr_get) /* func to grab the interface's addrs, null for default (ethernet) */
  869.       (struct ifnet*, M2_IFINDEX*)
  870.     )
  871.     {
  872.     UINT              index;
  873.     M2_IFINDEX *      pIfIndex;
  874.     M2_IFSTACKTBL *   pIfStackTbl;
  875.     M2_IFSTACKTBL *   pTempS;
  876.     M2_IFRCVADDRTBL * pIfRcvAddrTbl;
  877.     M2_IFRCVADDRTBL * pTempR;
  878.     M2_ID *           pM2Id = NULL;
  879.     long *            pFlags = NULL;
  880.     index = pIfNet->if_index;
  881.     switch (status)
  882.         {
  883.         case M2_IF_TABLE_INSERT:
  884.             {
  885.             pIfIndex = KHEAP_ALLOC(sizeof(M2_IFINDEX));
  886.             if (!pIfIndex)
  887.                 return ERROR;
  888.             memset(pIfIndex, 0, sizeof(M2_IFINDEX));
  889.             pIfIndex->ifIndex  = index;
  890.             pIfIndex->pIfStats = pIfNet;
  891.      
  892.             /* Set the MIB style flag */
  893.             pFlags = (long *) ifnetToEndFieldsGet (pIfNet, END_OBJ_FLAGS);
  894.             if (pFlags)
  895.                 {
  896.                 if (*pFlags & END_MIB_2233)
  897.                     pIfIndex->mibStyle = TRUE;
  898.                 else
  899.                     pIfIndex->mibStyle = FALSE;
  900.                 }
  901.     if (if_ioctl)      /* use supplied ioctl */
  902. {
  903. pIfIndex->ifIoctl = if_ioctl;
  904. }
  905.             else               /* default */
  906. {
  907. pIfIndex->ifIoctl = ifioctl;
  908. }
  909.             if (addr_get)
  910. {
  911. pIfIndex->rcvAddrGet = addr_get;
  912. }
  913.             else
  914. {
  915. pIfIndex->rcvAddrGet = rcvEtherAddrGet;
  916. }
  917.             /* Set Interface OID to default */
  918.             memcpy(pIfIndex->ifOid.idArray, ifZeroObjectId.idArray,
  919.                    ifZeroObjectId.idLength * sizeof(long));
  920.             pIfIndex->ifOid.idLength = ifZeroObjectId.idLength;
  921.             /* Fill in the unicast and the multicast addresses */
  922.     (*pIfIndex->rcvAddrGet)(pIfNet, pIfIndex);
  923.             semTake (m2InterfaceSem, WAIT_FOREVER);
  924.             /* Insert the node in the tree */
  925.             if (avlInsert(pM2IfRootPtr, pIfIndex, (GENERIC_ARGUMENT)index,
  926.                           nextIndex) != OK)
  927.                 {
  928. semGive (m2InterfaceSem);
  929.                 KHEAP_FREE((char *)pIfIndex);
  930.                 return ERROR;
  931.                 }
  932.             m2IfCount++;
  933.             ifsInList = index;
  934. #ifdef VIRTUAL_STACK
  935.             _ifTableLastChange = centiSecsGet();
  936. #else    /* VIRTUAL_STACK */
  937.             ifTableLastChange = centiSecsGet();
  938. #endif   /* VIRTUAL_STACK */          
  939.             semGive (m2InterfaceSem);
  940.             if (pM2TrapRtn != NULL)
  941.                 {
  942.                 (*pM2TrapRtn)(M2_LINK_UP_TRAP, 
  943.                                   pIfIndex->ifIndex, pM2TrapRtnArg);
  944.                 }
  945.             return OK;
  946.             }
  947.         case M2_IF_TABLE_REMOVE:
  948.             {
  949.     semTake (m2InterfaceSem, WAIT_FOREVER);
  950.             /* Remove the node from the tree */
  951.             if ((pIfIndex = (M2_IFINDEX *)avlDelete(pM2IfRootPtr,
  952.                                                     (GENERIC_ARGUMENT)index,
  953.                                                     nextIndex)) == NULL)
  954. {
  955. semGive (m2InterfaceSem);
  956.                 return ERROR;
  957. }
  958.             pIfStackTbl = pIfIndex->pNextLower;
  959.             while (pIfStackTbl != NULL)
  960.                 {
  961.                 pTempS = pIfStackTbl;
  962.                 pIfStackTbl = pIfStackTbl->pNextLower;
  963.                 KHEAP_FREE((char *)pTempS);
  964.                 }
  965.             pIfRcvAddrTbl = pIfIndex->pRcvAddr;
  966.             while (pIfRcvAddrTbl != NULL)
  967.                 {
  968.                 pTempR = pIfRcvAddrTbl;
  969.                 pIfRcvAddrTbl = pIfRcvAddrTbl->pNextEntry;
  970.                 KHEAP_FREE((char *)pTempR);
  971.                 }
  972.             KHEAP_FREE((char *)pIfIndex);
  973.             m2IfCount--;
  974. #ifdef VIRTUAL_STACK
  975.             _ifTableLastChange = centiSecsGet();
  976. #else    /* VIRTUAL_STACK */            
  977.             ifTableLastChange = centiSecsGet();
  978. #endif   /* VIRTUAL_STACK */            
  979.             semGive (m2InterfaceSem);
  980.             if ( (pM2TrapRtn != NULL) && (pIfNet->if_ioctl != NULL) &&
  981.                      ((*pIfNet->if_ioctl)(pIfNet, SIOCGMIB2233,
  982.                                                   (caddr_t)&pM2Id) == 0) )
  983.                 {
  984.                 if (pM2Id->m2Data.mibXIfTbl.ifLinkUpDownTrapEnable 
  985.                                            == M2_LINK_UP_DOWN_TRAP_ENABLED)
  986.                     {
  987.                     (*pM2TrapRtn)(M2_LINK_DOWN_TRAP, 
  988.                                       pIfIndex->ifIndex, pM2TrapRtnArg);
  989.                     }
  990.                 }
  991.             return OK;
  992.             }
  993.         default:
  994.             return ERROR;
  995.         }
  996.     }
  997. /******************************************************************************
  998. *
  999. * rcvEtherAddrGet - populate the rcvAddr fields for the ifRcvAddressTable
  1000. *
  1001. * This function needs to be called to add all physical addresses for which an
  1002. * interface may receive or send packets. This includes unicast and multicast
  1003. * addresses. The address is inserted into the linked list maintained in the
  1004. * AVL node corresponding to the interface. Given the ifnet struct and the
  1005. * AVL node corresponding to the interface, this function goes through all the
  1006. * physical addresses associated with this interface and adds them into the
  1007. * linked list.
  1008. *
  1009. * RETURNS: OK, if successful; ERROR, otherwise. 
  1010. */
  1011. STATUS rcvEtherAddrGet
  1012.     (
  1013.     struct ifnet *     pIfNet,       /* pointer to the interface's ifnet */
  1014.     M2_IFINDEX *       pIfIndexEntry /* avl node */
  1015.     )
  1016.     {
  1017.     struct arpcom *      pIfArpcom = (struct arpcom*) pIfNet;
  1018.     unsigned char *      pEnetAddr = pIfArpcom->ac_enaddr;
  1019.     LIST *               pMCastList = NULL;
  1020.     ETHER_MULTI *        pEtherMulti = NULL;
  1021.     /* Copy the list of mcast addresses */
  1022.     if ( (pIfArpcom->ac_if.if_ioctl != NULL) &&
  1023.              ((*pIfArpcom->ac_if.if_ioctl)((struct ifnet *)pIfArpcom,
  1024.                                SIOCGMCASTLIST, (caddr_t)&pMCastList) != 0) )
  1025.         {
  1026.         return (ERROR);
  1027.         }
  1028.     
  1029.     /* First create the entry for the unicast address */
  1030.     rcvEtherAddrAdd (pIfIndexEntry, pEnetAddr);
  1031.     /* Loop thru the mcast linked list and add the addresses */
  1032.     for ( pEtherMulti = (ETHER_MULTI *) lstFirst (pMCastList);
  1033.              pEtherMulti != NULL;
  1034.                  pEtherMulti = (ETHER_MULTI *) lstNext ((NODE *)pEtherMulti) )
  1035.         {
  1036.         rcvEtherAddrAdd (pIfIndexEntry, (unsigned char *)pEtherMulti->addr);
  1037.         }
  1038.     return (OK);
  1039.     }
  1040. /****************************************************************************
  1041. *
  1042. * rcvEtherAddrAdd - add a physical address into the linked list
  1043. *
  1044. * This function is a helper function for rcvEtherAddrGet.  It is called to
  1045. * add a single physical address into the linked list of addresses maintained
  1046. * by the AVL node.
  1047. *
  1048. * RETURNS: OK, if successful; ERROR, otherwise.
  1049. */
  1050. STATUS rcvEtherAddrAdd
  1051.     (
  1052.     M2_IFINDEX *    pIfIndexEntry,    /* the avl node */
  1053.     unsigned char * pEnetAddr         /* the addr to be added */
  1054.     )
  1055.     {
  1056.     M2_IFRCVADDRTBL *    pIfRcvAddr = NULL;
  1057.     M2_IFRCVADDRTBL **   ppTemp = &pIfIndexEntry->pRcvAddr;
  1058.     if (pEnetAddr)
  1059.         {
  1060.         pIfRcvAddr = KHEAP_ALLOC(sizeof (M2_IFRCVADDRTBL));
  1061.         if (!pIfRcvAddr)
  1062.             return ERROR;
  1063.         bcopy (pEnetAddr, pIfRcvAddr->ifRcvAddrAddr.phyAddress, ETHERADDRLEN);
  1064.         pIfRcvAddr->ifRcvAddrAddr.addrLength = ETHERADDRLEN;
  1065.         pIfRcvAddr->ifRcvAddrStatus = ROW_ACTIVE;
  1066.         pIfRcvAddr->ifRcvAddrType = STORAGE_NONVOLATILE;
  1067.         pIfRcvAddr->pNextEntry = NULL;
  1068.         if (pIfIndexEntry->pRcvAddr)
  1069.             {
  1070.             while (*ppTemp)
  1071.                 {
  1072.                 if (memcmp (pEnetAddr, (*ppTemp)->ifRcvAddrAddr.phyAddress,
  1073.                                                          ETHERADDRLEN) > 0)
  1074.                     {
  1075.                     ppTemp = &(*ppTemp)->pNextEntry;
  1076.                     continue;
  1077.                     }
  1078.                 else
  1079.                     {
  1080.                     pIfRcvAddr->pNextEntry = *ppTemp;
  1081.                     break;
  1082.                     }            
  1083.         
  1084.                 *ppTemp = pIfRcvAddr;
  1085.                 }
  1086.             }
  1087.         else
  1088.             {
  1089.             pIfIndexEntry->pRcvAddr = pIfRcvAddr;
  1090.             }
  1091.         return (OK);
  1092.         }
  1093.     
  1094.     return (ERROR);
  1095.     }
  1096. /******************************************************************************
  1097. *
  1098. * m2IfTblEntryGet - get a MIB-II interface-group table entry
  1099. *
  1100. * This routine maps the MIB-II interface index to the system's internal
  1101. * interface index.  The internal representation is in the form of a balanced
  1102. * AVL tree indexed by ifIndex of the interface. The <search> parameter is 
  1103. * set to either M2_EXACT_VALUE or M2_NEXT_VALUE; for a discussion of its use, see
  1104. * the manual entry for m2Lib. The interface table values are returned in a
  1105. * structure of type M2_DATA, which is passed as the second argument to this 
  1106. * routine.
  1107. *
  1108. * RETURNS: 
  1109. * OK, or ERROR if the input parameter is not specified, or a match is not found.
  1110. *
  1111. * ERRNO:
  1112. *  S_m2Lib_INVALID_PARAMETER
  1113. *  S_m2Lib_ENTRY_NOT_FOUND
  1114. *
  1115. * SEE ALSO:
  1116. * m2Lib, m2IfInit(), m2IfGroupInfoGet(), m2IfTblEntrySet(), m2IfDelete()
  1117. */
  1118. STATUS m2IfTblEntryGet
  1119.     (
  1120.     int       search,       /* M2_EXACT_VALUE or M2_NEXT_VALUE */
  1121.     void *    pIfReqEntry   /* pointer to requested interface entry */
  1122.     )
  1123.     {
  1124.     M2_IFINDEX *   pIfIndexEntry = NULL;
  1125.     struct ifnet * pIfNetEntry = NULL;
  1126.     int            index;
  1127.     M2_ID *        pM2Id = NULL;
  1128.     M2_DATA *      pM2Entry = (M2_DATA *)pIfReqEntry;
  1129.     M2_NETDRVCNFG  ifDrvCnfg;
  1130.     
  1131.     /* Validate pointer to requeste structure */
  1132.  
  1133.     if (pIfReqEntry == NULL)
  1134. {
  1135. errnoSet (S_m2Lib_INVALID_PARAMETER);
  1136.         return (ERROR);
  1137. }
  1138.     semTake (m2InterfaceSem, WAIT_FOREVER);
  1139.     /*
  1140.      * For a M2_EXACT_VALUE search, look up the index provided in the
  1141.      * request and get the node from our internal tree. For a
  1142.      * M2_NEXT_VALUE search, look up the successor of this node.
  1143.      */
  1144.     /* First, Validate the bounds of the requested index  */
  1145.     index = pM2Entry->mibIfTbl.ifIndex;
  1146.     if (index > ifsInList || index < 0)
  1147.         {
  1148.         semGive (m2InterfaceSem);
  1149. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1150.         return (ERROR);
  1151.         }
  1152.     /* Check to see if it is a EXACT search or a next search */
  1153.     if (search == M2_EXACT_VALUE)
  1154.         {
  1155.         pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1156.                                   (GENERIC_ARGUMENT)index, nextIndex);
  1157.         }
  1158.     else
  1159.         {
  1160.         pIfIndexEntry = (M2_IFINDEX *) avlSuccessorGet (pM2IfRoot,
  1161.                                  (GENERIC_ARGUMENT)index, nextIndex);
  1162.         }
  1163.     if (!pIfIndexEntry)
  1164.         {
  1165.         semGive (m2InterfaceSem);
  1166. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1167.         return (ERROR);
  1168.         }
  1169.     /* Get the pointer to the ifnet struct for this ifIndex */
  1170.     
  1171.     pIfNetEntry = (struct ifnet *) pIfIndexEntry->pIfStats;
  1172.     /* Get the interface data from the driver via the Ioctl */
  1173.     if (pIfIndexEntry->mibStyle == TRUE)
  1174.         {
  1175.         /* Call the RFC 2233 Ioctl */
  1176.         if ( (pIfNetEntry->if_ioctl != NULL) &&
  1177.              ((*pIfNetEntry->if_ioctl)(pIfNetEntry, SIOCGMIB2233,
  1178.                                                   (caddr_t)&pM2Id) != 0) )
  1179.             {
  1180.             /* ioctl failed, copy default values and return */
  1181.             
  1182.             m2IfDefaultValsGet (pM2Entry, pIfIndexEntry);
  1183.             pM2Entry->mibIfTbl.ifIndex = pIfIndexEntry->ifIndex;
  1184.             m2IfCommonValsGet (pM2Entry, pIfIndexEntry);
  1185.     semGive(m2InterfaceSem);
  1186.             return (OK);
  1187.             }
  1188.         memcpy ((char *)pM2Entry, (char *)&pM2Id->m2Data, sizeof (M2_DATA));
  1189.         pM2Entry->mibIfTbl.ifIndex = pIfIndexEntry->ifIndex;
  1190.         semGive (m2InterfaceSem);
  1191.         return (OK);
  1192.         }
  1193.     else
  1194.         {
  1195.         /* Declare variables for RFC 1213 support */
  1196.         
  1197.         M2_INTERFACETBL * pM2IntTblEntry = &pM2Entry->mibIfTbl;
  1198.         M2_NETDRVCNTRS    m2DrvCounters;
  1199.         bzero ((char *)pM2IntTblEntry, sizeof (M2_INTERFACETBL));
  1200.         /* Enter some of the values that we already know */
  1201.     
  1202.         pM2IntTblEntry->ifIndex = pIfIndexEntry->ifIndex;    
  1203.         
  1204.         /* Do what we used to do before for the RFC 1213 only counters */
  1205.         if ( (pIfNetEntry->if_ioctl != NULL) &&
  1206.                 ((*pIfNetEntry->if_ioctl)(pIfNetEntry, SIOCGMIB2CNTRS,
  1207.                                          (caddr_t)&m2DrvCounters) != 0) )
  1208.             {
  1209.             m2IfDefaultValsGet (pM2Entry, pIfIndexEntry);
  1210.             }
  1211.         else
  1212.             {
  1213.     /* Fill parameters with driver counters */
  1214.             m2IfDefaultValsGet (pM2Entry, pIfIndexEntry);
  1215.             pM2IntTblEntry->ifSpeed           = m2DrvCounters.ifSpeed;
  1216.             pM2IntTblEntry->ifInOctets        = m2DrvCounters.ifInOctets;
  1217.             pM2IntTblEntry->ifInDiscards      = m2DrvCounters.ifInDiscards;
  1218.             pM2IntTblEntry->ifInUnknownProtos = m2DrvCounters.ifInUnknownProtos;
  1219.             pM2IntTblEntry->ifOutOctets       = m2DrvCounters.ifOutOctets;
  1220.             pM2IntTblEntry->ifOutDiscards     = m2DrvCounters.ifOutDiscards;
  1221.             /* We can now do the second ioctl to get drv cnfg params */
  1222.             
  1223.             if ( (*pIfNetEntry->if_ioctl) &&
  1224.                  ((*pIfNetEntry->if_ioctl)(pIfNetEntry, SIOCGMIB2CNFG,
  1225.                                           (caddr_t)&ifDrvCnfg) == 0) )
  1226.                 {
  1227.                 /* Copy the ifType and the ifSpecific values */
  1228.                 
  1229.                 pM2IntTblEntry->ifType  = ifDrvCnfg.ifType;
  1230.                 if (ifDrvCnfg.ifSpecific.idLength > 0)
  1231.                     {
  1232.             bcopy (((char *) ifDrvCnfg.ifSpecific.idArray), 
  1233.            ((char *) pM2IntTblEntry->ifSpecific.idArray),
  1234.            ifDrvCnfg.ifSpecific.idLength * sizeof (long));
  1235.  
  1236.                     pM2IntTblEntry->ifSpecific.idLength =
  1237.                                         ifDrvCnfg.ifSpecific.idLength;
  1238.                     }
  1239.                 }
  1240.             else
  1241.                 {
  1242.                 /*
  1243.                  * no info from ioctl, make an educated guess at
  1244.                  * the driver configuration
  1245.                  */
  1246.                 if (strncmp(pIfNetEntry->if_name, "lo", 2) == 0)
  1247.                     {
  1248.                     /* IP Loop back interface. */
  1249.                     pM2IntTblEntry->ifType  =
  1250.                                      M2_ifType_softwareLoopback;
  1251.                     pM2IntTblEntry->ifSpeed = 0;
  1252.                     }
  1253.                 else                      
  1254.                     if (strncmp(pIfNetEntry->if_name, "sl", 2) == 0)
  1255.                         {
  1256.                         /* Slip Network Interface */
  1257.  
  1258.                         pM2IntTblEntry->ifType  = M2_ifType_slip;
  1259.                         pM2IntTblEntry->ifSpeed = 19200; /* Baud Rate ??? */
  1260.                         }
  1261.                 else
  1262.                     if (strncmp(pIfNetEntry->if_name, "ppp", 3) == 0)
  1263.                         {
  1264.                         /* PPP Network Interface */
  1265.                         pM2IntTblEntry->ifType  = M2_ifType_ppp;
  1266.                         pM2IntTblEntry->ifSpeed = 19200; /* Baud Rate ??? */
  1267.                         }
  1268.                 else
  1269.                     {
  1270.                     /* Use Ethernet parameters as defaults */
  1271.                     pM2IntTblEntry->ifType  =
  1272.                                       M2_ifType_ethernet_csmacd;
  1273.                     pM2IntTblEntry->ifSpeed = 10000000;
  1274.                     }
  1275.                 }
  1276.             }
  1277.         
  1278.         /* Fill in the other parameters */
  1279.         m2IfCommonValsGet (pM2Entry, pIfIndexEntry);        
  1280.         }
  1281.     semGive (m2InterfaceSem);
  1282.     return (OK);    
  1283.     }
  1284. /******************************************************************************
  1285. *
  1286. * m2IfDefaultValsGet - get the default values for the counters
  1287. *
  1288. * This function fills the given struct with the default values as
  1289. * specified in the RFC. We will enter this routine only if the ioctl
  1290. * to the driver fails.
  1291. *
  1292. * RETURNS: n/a
  1293. */
  1294. void m2IfDefaultValsGet
  1295.     (
  1296.     M2_DATA *    pM2Data,        /* The requested entry */
  1297.     M2_IFINDEX * pIfIndexEntry   /* The ifindex node */
  1298.     )
  1299.     {
  1300.     struct ifnet * pIfNetEntry = (struct ifnet *)pIfIndexEntry->pIfStats;
  1301.     /* We will check only for loopback here */
  1302.     if (strncmp(pIfNetEntry->if_name, "lo", 2) == 0)
  1303.         pM2Data->mibIfTbl.ifType = M2_ifType_softwareLoopback;
  1304.     else
  1305.         pM2Data->mibIfTbl.ifType = M2_ifType_other;
  1306.     if (pIfIndexEntry->mibStyle == TRUE)
  1307.         {
  1308.         pM2Data->mibIfTbl.ifInOctets        = 0;
  1309.         pM2Data->mibIfTbl.ifInUcastPkts     = 0;
  1310.         pM2Data->mibIfTbl.ifInNUcastPkts    = 0;
  1311.         pM2Data->mibIfTbl.ifInDiscards      = 0;
  1312.         pM2Data->mibIfTbl.ifInErrors        = 0;
  1313.         pM2Data->mibIfTbl.ifInUnknownProtos = 0;
  1314.         pM2Data->mibIfTbl.ifOutOctets       = 0;
  1315.         pM2Data->mibIfTbl.ifOutUcastPkts    = 0;
  1316.         pM2Data->mibIfTbl.ifOutNUcastPkts   = 0;
  1317.         pM2Data->mibIfTbl.ifOutDiscards     = 0;
  1318.         pM2Data->mibIfTbl.ifOutErrors       = 0;
  1319.         pM2Data->mibIfTbl.ifOutQLen         = 0;
  1320.         }
  1321.     pM2Data->mibXIfTbl.ifInMulticastPkts = 0;
  1322.     pM2Data->mibXIfTbl.ifInBroadcastPkts = 0;
  1323.     pM2Data->mibXIfTbl.ifOutMulticastPkts = 0;
  1324.     pM2Data->mibXIfTbl.ifOutBroadcastPkts = 0;
  1325.     memset(&(pM2Data->mibXIfTbl.ifHCInOctets), 0, sizeof(UI64)); 
  1326.     memset(&(pM2Data->mibXIfTbl.ifHCInUcastPkts), 0, sizeof(UI64));
  1327.     memset(&(pM2Data->mibXIfTbl.ifHCInMulticastPkts), 0, sizeof(UI64));
  1328.     memset(&(pM2Data->mibXIfTbl.ifHCInBroadcastPkts), 0, sizeof(UI64));
  1329.     memset(&(pM2Data->mibXIfTbl.ifHCOutOctets), 0, sizeof(UI64));
  1330.     memset(&(pM2Data->mibXIfTbl.ifHCOutUcastPkts), 0, sizeof(UI64));
  1331.     memset(&(pM2Data->mibXIfTbl.ifHCOutMulticastPkts), 0, sizeof(UI64));
  1332.     memset(&(pM2Data->mibXIfTbl.ifHCOutBroadcastPkts), 0, sizeof(UI64));
  1333.     memset(pM2Data->mibXIfTbl.ifName, 0, M2DISPLAYSTRSIZE);
  1334.     pM2Data->mibXIfTbl.ifLinkUpDownTrapEnable = M2_LINK_UP_DOWN_TRAP_DISABLED;
  1335.     pM2Data->mibXIfTbl.ifHighSpeed = 0;
  1336.     pM2Data->mibXIfTbl.ifPromiscuousMode = M2_PROMISCUOUS_MODE_OFF; 
  1337.     pM2Data->mibXIfTbl.ifConnectorPresent = M2_CONNECTOR_NOT_PRESENT;
  1338.     memset(pM2Data->mibXIfTbl.ifAlias, 0, M2DISPLAYSTRSIZE);
  1339.     pM2Data->mibXIfTbl.ifCounterDiscontinuityTime = 0;
  1340.     return;
  1341.     }
  1342. /******************************************************************************
  1343. *
  1344. * m2IfCommonValsGet - get the common values
  1345. *
  1346. * This function updates the requested struct with all the data that is
  1347. * independent of the driver ioctl. This information can be obtained
  1348. * from the ifnet structures.
  1349. *
  1350. * RETURNS: n/a
  1351. */
  1352. void m2IfCommonValsGet
  1353.     (
  1354.     M2_DATA *    pM2Data,        /* The requested struct */
  1355.     M2_IFINDEX * pIfIndexEntry   /* The ifindex node */
  1356.     )
  1357.     {
  1358.     struct ifnet *    pIfNetEntry    = (struct ifnet *)pIfIndexEntry->pIfStats;
  1359.     M2_INTERFACETBL * pM2IntTblEntry = &pM2Data->mibIfTbl;
  1360.     struct arpcom *   pArpcomEntry   = (struct arpcom *)pIfNetEntry;
  1361.     
  1362.     sprintf (pM2IntTblEntry->ifDescr, "%s%d",
  1363.                      pIfNetEntry->if_name, pIfNetEntry->if_unit);
  1364.     if (!pM2IntTblEntry->ifSpecific.idLength)
  1365.         {
  1366.         memcpy (pM2IntTblEntry->ifSpecific.idArray, pIfIndexEntry->ifOid.idArray,
  1367.             ((int) pIfIndexEntry->ifOid.idLength * sizeof (long)));
  1368.         pM2IntTblEntry->ifSpecific.idLength = pIfIndexEntry->ifOid.idLength;
  1369.         }
  1370.     pM2IntTblEntry->ifMtu = pIfNetEntry->if_mtu;
  1371.     /* If the device does not have a hardware address set it to zero */
  1372.  
  1373.     if (pIfNetEntry->if_flags &
  1374.                         (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_NOARP))
  1375.         {
  1376.         memset(&(pM2IntTblEntry->ifPhysAddress), 0, sizeof(M2_PHYADDR));
  1377.         }
  1378.     else
  1379.         {
  1380.         bcopy (((char *) pArpcomEntry->ac_enaddr),
  1381.               ((char *) pM2IntTblEntry->ifPhysAddress.phyAddress),
  1382.                                                           ETHERADDRLEN);
  1383.         pM2IntTblEntry->ifPhysAddress.addrLength = ETHERADDRLEN;
  1384.         }
  1385.     /* Get the ifAdminStatus, ifLastChange, and ifOperStatus  */
  1386.     pM2IntTblEntry->ifAdminStatus = (((pIfNetEntry->if_flags & IFF_UP) != 0) ?
  1387.                                      M2_ifAdminStatus_up :
  1388.                                      M2_ifAdminStatus_down);
  1389.     /*
  1390.     pNetIf->netIfAdminStatus  = pIfReqEntry->ifAdminStatus;
  1391.     pM2IntTblEntry->ifLastChange = pIfNetEntry->netIfLastChange;
  1392.     */
  1393.     pM2IntTblEntry->ifOperStatus = (((pIfNetEntry->if_flags & IFF_UP) != 0) ?
  1394.                                     M2_ifOperStatus_up : M2_ifOperStatus_down);
  1395.     if (pIfIndexEntry->mibStyle != TRUE)
  1396.         {
  1397.         pM2IntTblEntry->ifInUcastPkts  = pIfNetEntry->if_ipackets -
  1398.                                          pIfNetEntry->if_imcasts;
  1399.         pM2IntTblEntry->ifInNUcastPkts = pIfNetEntry->if_imcasts;
  1400.         pM2IntTblEntry->ifInErrors     = pIfNetEntry->if_ierrors;
  1401.         pM2IntTblEntry->ifOutUcastPkts = pIfNetEntry->if_opackets -
  1402.                                          pIfNetEntry->if_omcasts;
  1403.         pM2IntTblEntry->ifOutNUcastPkts= pIfNetEntry->if_omcasts;
  1404.         pM2IntTblEntry->ifOutErrors    = pIfNetEntry->if_oerrors;
  1405. pM2IntTblEntry->ifOutQLen      = pIfNetEntry->if_snd.ifq_len;
  1406.         /*
  1407.          * XXX Due to inconsistant increment between ifInUnknownProtos by
  1408.          * muxReceive and if_noproto by do_protocol_with_type, this routine
  1409.          * will synchronize both statistics here. In future, these increments
  1410.          * should be consistantly updated at the same place.
  1411.          */
  1412.         pIfNetEntry->if_noproto = pM2IntTblEntry->ifInUnknownProtos; /* XXX */
  1413.         }
  1414.     return;
  1415.     }
  1416. /******************************************************************************
  1417. *
  1418. * m2IfTblEntrySet - set the state of a MIB-II interface entry to UP or DOWN
  1419. *
  1420. * This routine selects the interface specified in the input parameter
  1421. * <pIfReqEntry> and sets the interface parameters to the requested state.  
  1422. * It is the responsibility of the calling routine to set the interface
  1423. * index, and to make sure that the state specified in the
  1424. * `ifAdminStatus' field of the structure at <pIfTblEntry> is a valid
  1425. * MIB-II state, up(1) or down(2).
  1426. *
  1427. * The fields that can be modified by this routine are the following:
  1428. * ifAdminStatus, ifAlias, ifLinkUpDownTrapEnable and ifName.
  1429. *
  1430. * RETURNS: OK, or ERROR if the input parameter is not specified, an interface
  1431. * is no longer valid, the interface index is incorrect, or the ioctl() command
  1432. * to the interface fails.
  1433. *
  1434. * ERRNO:
  1435. *   S_m2Lib_INVALID_PARAMETER
  1436. *   S_m2Lib_ENTRY_NOT_FOUND
  1437. *   S_m2Lib_IF_CNFG_CHANGED
  1438. *
  1439. * SEE ALSO:
  1440. * m2IfInit(), m2IfGroupInfoGet(), m2IfTblEntryGet(), m2IfDelete()
  1441. */
  1442. STATUS m2IfTblEntrySet
  1443.     (
  1444.     void *        pIfReqEntry   /* pointer to requested entry to change */
  1445.     )
  1446.     {
  1447.     int             index;
  1448.     M2_IFINDEX *    pIfIndexEntry = NULL;
  1449.     struct ifnet *  pIfNetEntry = NULL;
  1450.     struct ifreq    ifReqChange;
  1451.     IF_SETENTRY *   pM2Entry = (IF_SETENTRY *)pIfReqEntry;
  1452.     M2_ID *         pM2Id = NULL;
  1453.     
  1454.     semTake (m2InterfaceSem, WAIT_FOREVER);
  1455.     /* Validate the bounds of the requested index  */
  1456.     index = pM2Entry->ifIndex;
  1457.     if (index < 0 || index > ifsInList)
  1458.         {
  1459. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1460.         semGive (m2InterfaceSem);
  1461.         return (ERROR);
  1462.         }
  1463.     /* Get the node associated with the index */
  1464.     pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1465.                                        (GENERIC_ARGUMENT)index, nextIndex);
  1466.     if (!pIfIndexEntry)
  1467. {
  1468. semGive (m2InterfaceSem);
  1469.         return (ERROR);
  1470.         }
  1471.     pIfNetEntry = (struct ifnet *) pIfIndexEntry->pIfStats;
  1472.     /*
  1473.      * The only supported state changes for the interface are UP and DOWN.
  1474.      * The TEST case is not supported by the drivers.
  1475.      */
  1476.     if (pM2Entry->varToSet & M2_varId_ifAdminStatus)
  1477.         {
  1478.         if (pM2Entry->ifAdminStatus == M2_ifAdminStatus_up)
  1479.             {
  1480.             /*
  1481.              * If the driver is in the UP state, there is no need to send the
  1482.              * IOCTL command, otherwise format the IOCTL request.
  1483.              */
  1484.             if ( (pIfNetEntry->if_flags & IFF_UP) == 0)
  1485.                 ifReqChange.ifr_flags = pIfNetEntry->if_flags | IFF_UP;
  1486.             else
  1487.                 pM2Entry->varToSet =
  1488.                      pM2Entry->varToSet & ~M2_varId_ifAdminStatus;
  1489.             }
  1490.         else
  1491.             {
  1492.             /* 
  1493.      * If the driver is in the DOWN state, there is no need to send the
  1494.      * IOCTL command, otherwise format the IOCTL request. 
  1495.      */
  1496.  
  1497.             if ((pIfNetEntry->if_flags & IFF_UP) != 0)
  1498.                 ifReqChange.ifr_flags = pIfNetEntry->if_flags & ~IFF_UP;
  1499.             else
  1500.                 pM2Entry->varToSet = 
  1501.                       pM2Entry->varToSet & ~M2_varId_ifAdminStatus;
  1502.             }
  1503.         /* Stop if no work is needed. */
  1504.         if (pM2Entry->varToSet == 0)
  1505.     {
  1506.     semGive (m2InterfaceSem);
  1507.             return (OK);
  1508.     }
  1509.         }
  1510.     /* Check to see if we have to set the promiscuous mode */
  1511.     if (pM2Entry->varToSet & M2_varId_ifPromiscuousMode)
  1512.         {
  1513.         if (pM2Entry->ifPromiscuousMode == M2_ifPromiscuousMode_on)
  1514.             ifReqChange.ifr_flags = pIfNetEntry->if_flags | IFF_PROMISC;
  1515.         else 
  1516.             ifReqChange.ifr_flags = pIfNetEntry->if_flags & ~IFF_PROMISC;
  1517.         }
  1518.     /* Do we need to call the Ioctl as a result of any of the above */
  1519.     if (pM2Entry->varToSet & (M2_varId_ifAdminStatus |
  1520.                                  M2_varId_ifPromiscuousMode))
  1521.         {
  1522.         /*
  1523.          * The network semaphore is not taken for this operation because the
  1524.          * called routine takes the network semphore.  Issue the IOCTL to the
  1525.          * driver routine, and verify that the request is honored.
  1526.          */
  1527.         sprintf (ifReqChange.ifr_name,"%s%d", pIfNetEntry->if_name,
  1528. pIfNetEntry->if_unit);
  1529.         if ((*pIfIndexEntry->ifIoctl)(0, SIOCSIFFLAGS, (char *)&ifReqChange) != 0)
  1530.             {
  1531.             semGive (m2InterfaceSem);
  1532.             return (ERROR);
  1533.             }
  1534.         if ( (pIfNetEntry->if_ioctl != NULL) &&
  1535.              ((*pIfNetEntry->if_ioctl)(pIfNetEntry, SIOCGMIB2233,
  1536.                                        (caddr_t)&pM2Id) == OK) )
  1537.             {
  1538.     if (pM2Entry->varToSet & M2_varId_ifAdminStatus)
  1539. {
  1540. (*pM2Id->m2VarUpdateRtn)(pM2Id, M2_varId_ifAdminStatus,
  1541. (caddr_t)pM2Entry->ifAdminStatus);
  1542.                 }
  1543.             if (pM2Entry->varToSet & M2_varId_ifPromiscuousMode)
  1544. {
  1545. (*pM2Id->m2VarUpdateRtn)(pM2Id, M2_varId_ifPromiscuousMode,
  1546. (caddr_t)pM2Entry->ifPromiscuousMode);
  1547.                 }
  1548.             }
  1549.         }
  1550.     else 
  1551.         {
  1552.         /* 
  1553.          * For the others, we have to get a pointer to the interface 
  1554.          * table, so we call the SIOCSMIB2233 IOCTL and let the driver
  1555.          * call our appropriate set routine. In this case, the set
  1556.          * routine is m2IfSnmpSet().
  1557.          */
  1558.         if ( (pIfNetEntry->if_ioctl) &&
  1559.              ((*pIfNetEntry->if_ioctl) (pIfNetEntry, SIOCSMIB2233, 
  1560.                                               (caddr_t)pIfReqEntry) != 0) )
  1561.             {
  1562.             semGive (m2InterfaceSem);
  1563.             return (ERROR);
  1564.             }
  1565.         }
  1566.     semGive (m2InterfaceSem);
  1567.     return (OK);    
  1568.     }
  1569. /******************************************************************************
  1570. *
  1571. * m2IfGroupInfoGet -  get the MIB-II interface-group scalar variables
  1572. *
  1573. * This routine fills the interface-group structure at <pIfInfo> with
  1574. * the values of MIB-II interface-group global variables.
  1575. *
  1576. * RETURNS: OK, or ERROR if <pIfInfo> is not a valid pointer.
  1577. *
  1578. * ERRNO:
  1579. * S_m2Lib_INVALID_PARAMETER
  1580. *
  1581. * SEE ALSO:
  1582. * m2IfInit(), m2IfTblEntryGet(), m2IfTblEntrySet(), m2IfDelete()
  1583. */
  1584. STATUS m2IfGroupInfoGet
  1585.     (
  1586.     M2_INTERFACE * pIfInfo /* pointer to interface group structure */
  1587.     )
  1588.     {
  1589.     semTake (m2InterfaceSem, WAIT_FOREVER);
  1590.  
  1591.     /* Validate the input parameter pointer */
  1592.     if (pIfInfo == NULL)
  1593.         {
  1594.         semGive (m2InterfaceSem);
  1595. errnoSet (S_m2Lib_INVALID_PARAMETER);
  1596.         return (ERROR);
  1597.         }
  1598.     /*
  1599.      * Number of network interfaces in the system independent of
  1600.      * their state
  1601.      */
  1602.  
  1603.     pIfInfo->ifNumber = m2IfCount;  
  1604. #ifdef VIRTUAL_STACK
  1605.     pIfInfo->ifTableLastChange = _ifTableLastChange;
  1606.     pIfInfo->ifStackLastChange = _ifStackLastChange;
  1607. #else    /* VIRTUAL_STACK */
  1608.     pIfInfo->ifTableLastChange = ifTableLastChange;
  1609.     pIfInfo->ifStackLastChange = ifStackLastChange;
  1610. #endif   /* VIRTUAL_STACK */
  1611.  
  1612.     semGive (m2InterfaceSem);
  1613.     return OK;
  1614.     }
  1615. /******************************************************************************
  1616. *
  1617. * m2IfStackTblUpdate - update the relationship between the sub-layers
  1618. *
  1619. * This function must be called to setup the relationship between the
  1620. * ifIndex values for each sub-layer. This information is required to 
  1621. * support the ifStackTable for RFC 2233. Using this data, we can easily
  1622. * determine which sub-layer runs on top of which other. 
  1623. *
  1624. * <action> is either M2_STACK_TABLE_INSERT or M2_STACK_TABLE_REMOVE.
  1625. *
  1626. * Each AVL node keeps a linked list of all the layers that are 
  1627. * directly beneath it. Thus by walking through the AVL nodes in an
  1628. * orderly way, we can understand the relationships between all the 
  1629. * interfaces.
  1630. *
  1631. * RETURNS: OK upon successful addition
  1632. *          ERROR otherwise.
  1633. */
  1634. STATUS m2IfStackTblUpdate
  1635.     (
  1636.     UINT    lowerIndex,        /* The ifIndex of the lower sub-layer */
  1637.     UINT    higherIndex,        /* The ifIndex of the higher sub-layer */
  1638.     int     action             /* insert or remove */
  1639.     )
  1640.     {
  1641.     M2_IFINDEX *      pIfIndexLow = NULL;
  1642.     M2_IFINDEX *      pIfIndexHigh = NULL;
  1643.     M2_IFSTACKTBL *   pIfStackPtr = NULL;
  1644.     M2_IFSTACKTBL **  ppTempPtr = NULL;    
  1645.     /* Check to see if the indexes are within the limits */
  1646.     if ( (lowerIndex < (UINT) 0) || (lowerIndex > (UINT) ifsInList) ||
  1647.          (higherIndex < (UINT) 0) || (higherIndex > (UINT) ifsInList) )
  1648.         {
  1649.         return (ERROR);
  1650.         }
  1651.     semTake(m2InterfaceSem, WAIT_FOREVER);
  1652.     /* Get the nodes associated with the interfaces */
  1653.     pIfIndexLow = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1654.                                  (GENERIC_ARGUMENT)lowerIndex, nextIndex);
  1655.     pIfIndexHigh = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1656.                                  (GENERIC_ARGUMENT)higherIndex, nextIndex);
  1657.     if ( (!pIfIndexLow) || (!pIfIndexHigh) )
  1658. {
  1659. semGive(m2InterfaceSem);
  1660.         return (ERROR);
  1661. };
  1662.     /* Check the slot to insert a new index */
  1663.     pIfStackPtr = pIfIndexHigh->pNextLower;
  1664.     ppTempPtr = &pIfIndexHigh->pNextLower;
  1665.     if (action == M2_STACK_TABLE_INSERT)
  1666.         {
  1667. while (pIfStackPtr && pIfStackPtr->index < lowerIndex)
  1668.     {
  1669.     ppTempPtr = &pIfStackPtr->pNextLower;
  1670.     pIfStackPtr = pIfStackPtr->pNextLower;
  1671.     }
  1672.         *ppTempPtr = (M2_IFSTACKTBL*) malloc(sizeof(M2_IFSTACKTBL));
  1673.         (*ppTempPtr)->index = lowerIndex;
  1674. (*ppTempPtr)->pNextLower = pIfStackPtr;
  1675. (*ppTempPtr)->status = ROW_ACTIVE;
  1676. }
  1677.     else
  1678. {
  1679. while (pIfStackPtr && pIfStackPtr->index < lowerIndex)
  1680.     {
  1681.     ppTempPtr = &pIfStackPtr->pNextLower;
  1682.     pIfStackPtr = pIfStackPtr->pNextLower;
  1683.     }
  1684.         if (pIfStackPtr && pIfStackPtr->index == lowerIndex)
  1685.     {
  1686.     *ppTempPtr = pIfStackPtr->pNextLower;
  1687.     free(pIfStackPtr);
  1688.     }
  1689.         }
  1690.     
  1691. #ifdef VIRTUAL_STACK
  1692.     _ifStackLastChange = centiSecsGet();
  1693. #else    /* VIRTUAL_STACK */
  1694.     ifStackLastChange = centiSecsGet();
  1695. #endif   /* VIRTUAL_STACK */
  1696.     semGive(m2InterfaceSem);
  1697.     return (OK);
  1698.     }
  1699. /******************************************************************************
  1700. *
  1701. * stackEntryIsTop - test if an ifStackTable interface has no layers above
  1702. *
  1703. * This routine returns TRUE if an interface is not below any other interface.
  1704. * That is, it returns TRUE if the given interface is topmost on a stack.  This
  1705. * helper function is not exported.
  1706. *
  1707. * RETURNS: 
  1708. *  TRUE is interface is topmost
  1709. *  FALSE otherwise or for errors
  1710. *
  1711. */
  1712. BOOL stackEntryIsTop
  1713.     (
  1714.     int index  /* the interface to examine */
  1715.     )
  1716.     {
  1717.     M2_IFINDEX *     pIfIndexEntry;
  1718.     M2_IFSTACKTBL *  pIfStackEntry;
  1719.     UINT i = 0;
  1720.     while ((pIfIndexEntry = (M2_IFINDEX*) avlSuccessorGet (pM2IfRoot,
  1721. (GENERIC_ARGUMENT)i, nextIndex)))
  1722. {
  1723. pIfStackEntry = pIfIndexEntry->pNextLower;
  1724. while (pIfStackEntry)
  1725.     {
  1726.     if (pIfStackEntry->index == (UINT) index)
  1727. {
  1728. return FALSE;
  1729. }
  1730.             pIfStackEntry = pIfStackEntry->pNextLower;
  1731.     }
  1732.         i = pIfIndexEntry->ifIndex;
  1733. }
  1734.     return TRUE;
  1735.     }
  1736. /******************************************************************************
  1737. *
  1738. * stackEntryIsBottom - test if an interface has no layers beneath it
  1739. *
  1740. * This routine returns TRUE if an interface has no layers beneath it.  This
  1741. * helper function is not exported.
  1742. *
  1743. * RETURNS: 
  1744. *  TRUE if the interface is the bottom-most layer in a stack
  1745. *  FALSE otherwise or on error
  1746. *
  1747. */
  1748. BOOL stackEntryIsBottom
  1749.     (
  1750.     int index   /* interface to examine */
  1751.     )
  1752.     {
  1753.     M2_IFINDEX *     pIfIndexEntry;
  1754.     pIfIndexEntry = (M2_IFINDEX*) avlSearch (pM2IfRoot,
  1755. (GENERIC_ARGUMENT)index, nextIndex);
  1756.     if (pIfIndexEntry == 0 || pIfIndexEntry->pNextLower != 0)
  1757. {
  1758. return FALSE;
  1759. }
  1760.     return TRUE;
  1761.     }
  1762. /******************************************************************************
  1763. *
  1764. * m2IfStackEntryGet -  get a MIB-II interface-group table entry
  1765. *
  1766. * This routine maps the given high and low indexes to the interfaces in the
  1767. * AVL tree. Using the <high> and <low> indexes, we retrieve the nodes in
  1768. * question and walk through their linked lists to get to the right relation.
  1769. * Once we get to the correct node, we can return the values based on the
  1770. * M2_EXACT_VALUE and the M2_NEXT_VALUE searches.
  1771. *
  1772. * RETURNS: 
  1773. * OK, or ERROR if the input parameter is not specified, or a match is not found.
  1774. *
  1775. * ERRNO:
  1776. *  S_m2Lib_INVALID_PARAMETER
  1777. *  S_m2Lib_ENTRY_NOT_FOUND
  1778. *
  1779. */
  1780. STATUS m2IfStackEntryGet
  1781.     (
  1782.     int             search,       /* M2_EXACT_VALUE or M2_NEXT_VALUE */
  1783.     int *           pHighIndex,   /* the higher layer's ifIndex */
  1784.     M2_IFSTACKTBL * pIfReqEntry   /* pointer to the requested entry */
  1785.     )
  1786.     {
  1787.     M2_IFINDEX *    pIfIndexEntry = NULL;
  1788.     M2_IFSTACKTBL * pIfStackEntry = NULL;
  1789.     
  1790.     /* Validate the pointer to the requested structure */
  1791.     
  1792.     if (pIfReqEntry == NULL)
  1793.         {
  1794.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  1795.         return (ERROR);
  1796.         }
  1797.     semTake (m2InterfaceSem, WAIT_FOREVER);
  1798.     /*
  1799.      *In addition to the relationships created by m2IfStackTblUpdate()
  1800.      * there exists up to 2 virtual relationships for each interface.
  1801.      * These virtual relationships are in the form 0.x and x.0
  1802.      * The virtual relationship 0.x is present if interface x is not
  1803.      * below a real interface.  The virtual relationship x.0 is present
  1804.      * if interface x has not real interfaces below it.
  1805.      *
  1806.      * These virtual relationships have to be handled as
  1807.      * special cases because they are not represented in the stack table
  1808.      * data structure.
  1809.      */
  1810.     if (*pHighIndex == 0)
  1811.         {
  1812. if (search == M2_EXACT_VALUE)
  1813.     {
  1814.     pIfIndexEntry = (M2_IFINDEX*) avlSearch (pM2IfRoot,
  1815.       (GENERIC_ARGUMENT)pIfReqEntry->index, nextIndex);
  1816.             if (pIfIndexEntry)
  1817. {
  1818. if (stackEntryIsTop(pIfReqEntry->index) == FALSE)
  1819.     {
  1820.     goto errorReturn;
  1821.     }
  1822. pIfReqEntry->index = pIfIndexEntry->ifIndex;
  1823. pIfReqEntry->status = ROW_ACTIVE;
  1824. goto goodReturn;
  1825.                 }
  1826.             goto errorReturn;
  1827.     }
  1828.         else
  1829.     {
  1830.     pIfIndexEntry = (M2_IFINDEX*) avlSuccessorGet (pM2IfRoot,
  1831.       (GENERIC_ARGUMENT) pIfReqEntry->index,
  1832.       nextIndex);
  1833.             while (pIfIndexEntry != 0 && stackEntryIsTop(pIfIndexEntry->ifIndex)
  1834.   == FALSE)
  1835.         {
  1836. pIfIndexEntry = (M2_IFINDEX*) avlSuccessorGet (pM2IfRoot,
  1837.     (GENERIC_ARGUMENT) pIfIndexEntry->ifIndex,
  1838.     nextIndex);
  1839.                 }
  1840.             if (pIfIndexEntry)
  1841. {
  1842. pIfReqEntry->index = pIfIndexEntry->ifIndex;
  1843. pIfReqEntry->status = ROW_ACTIVE;
  1844. goto goodReturn;
  1845.                 }
  1846.             pIfIndexEntry = (M2_IFINDEX *) avlSuccessorGet
  1847.                     (pM2IfRoot, (GENERIC_ARGUMENT)0, nextIndex);
  1848.             if (!pIfIndexEntry)
  1849.                 goto errorReturn;
  1850.             pIfReqEntry->index = 0;
  1851.             pIfReqEntry->status = ROW_ACTIVE;
  1852.             *pHighIndex = pIfIndexEntry->ifIndex;
  1853.     if (stackEntryIsBottom(pIfIndexEntry->ifIndex))
  1854. {
  1855. goto goodReturn;
  1856. }
  1857.     }
  1858.         }
  1859.     pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1860.                                   (GENERIC_ARGUMENT)*pHighIndex, nextIndex);
  1861.     if (pIfIndexEntry == 0)
  1862. goto errorReturn;
  1863.     /*
  1864.      * Doing a next match.  The next relation after <interface>.<last_lower> is
  1865.      * the virtual relation <next_interface>.0 if <next_interface> has no
  1866.      * lower layers.
  1867.      */
  1868.     if (search != M2_EXACT_VALUE)
  1869.         {
  1870. while (1)
  1871.     {
  1872.             pIfStackEntry = pIfIndexEntry->pNextLower;
  1873.             /* Doing a next match */
  1874.             while (pIfStackEntry)
  1875.                 {
  1876.                 if (pIfStackEntry->index > pIfReqEntry->index)
  1877.                     {
  1878.                     /* We found a next within the same high index node */
  1879.                 
  1880.                     pIfReqEntry->index = pIfStackEntry->index;
  1881.                     pIfReqEntry->status = pIfStackEntry->status;
  1882.                     goto goodReturn;
  1883.                     }
  1884.                 /*
  1885.                  * Check to see if another lower layer index is available
  1886.                  * for this index. If it is, loop through again, else
  1887.          * start searching the next interface.
  1888.                  */
  1889.             
  1890.                 pIfStackEntry = pIfStackEntry->pNextLower;
  1891.                 }
  1892.             pIfIndexEntry = (M2_IFINDEX *) avlSuccessorGet
  1893.                 (pM2IfRoot, (GENERIC_ARGUMENT)*pHighIndex, nextIndex);
  1894.             if (pIfIndexEntry == 0)
  1895. goto errorReturn;
  1896.             *pHighIndex = pIfIndexEntry->ifIndex;
  1897.             if (stackEntryIsBottom(pIfIndexEntry->ifIndex) == TRUE)
  1898. {
  1899. pIfReqEntry->index = 0;
  1900. pIfReqEntry->status = ROW_ACTIVE;
  1901. goto goodReturn;
  1902. }
  1903.             }
  1904.         }
  1905.     /*
  1906.      * Doing an exact match case.
  1907.      */
  1908.     if (pIfReqEntry->index == 0 && stackEntryIsBottom(*pHighIndex))
  1909.         {
  1910.         pIfReqEntry->status = ROW_ACTIVE;
  1911.         goto goodReturn;
  1912.         }
  1913.     while (pIfStackEntry)
  1914.         {
  1915.         if (pIfStackEntry->index == pIfReqEntry->index)
  1916.             {
  1917.             pIfReqEntry->status = pIfStackEntry->status;
  1918.             goto goodReturn;
  1919.             }
  1920.         pIfStackEntry = pIfStackEntry->pNextLower;
  1921.         }
  1922.     goto errorReturn;
  1923. errorReturn:
  1924.     semGive (m2InterfaceSem);
  1925.     errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1926.     return (ERROR);
  1927. goodReturn:
  1928.     semGive (m2InterfaceSem);
  1929.     return (OK);
  1930.     }
  1931. /******************************************************************************
  1932. *
  1933. * m2IfStackEntrySet - modify the status of a relationship
  1934. *
  1935. * This routine selects the interfaces specified in the input parameters
  1936. * <pIfReqEntry> and <highIndex> and sets the interface's status to the 
  1937. * requested state.  
  1938. *
  1939. * RETURNS: OK, or ERROR if the input parameter is not specified, an interface
  1940. * is no longer valid, or the interface index is incorrect.
  1941. *
  1942. * ERRNO:
  1943. *  S_m2Lib_INVALID_PARAMETER
  1944. *  S_m2Lib_ENTRY_NOT_FOUND
  1945. *  S_m2Lib_IF_CNFG_CHANGED
  1946. *
  1947. */
  1948. STATUS m2IfStackEntrySet
  1949.     (
  1950.     int             highIndex,        /* The higher layer's ifIndex */
  1951.     M2_IFSTACKTBL * pIfReqEntry       /* The requested entry */
  1952.     )
  1953.     {
  1954.     M2_IFINDEX *    pIfIndexEntry = NULL;
  1955.     M2_IFSTACKTBL * pIfStackEntry = NULL;
  1956.     M2_IFSTACKTBL **ppTemp = NULL;
  1957.     /* Check for insert before anything else because m2IfStackTblUpdate()
  1958.      * does all the necessary checking.
  1959.      */
  1960.     if (pIfReqEntry->status == ROW_ACTIVE)
  1961. {
  1962. return m2IfStackTblUpdate(pIfReqEntry->index, highIndex, M2_STACK_TABLE_INSERT);
  1963. }
  1964.     
  1965.     if (pIfReqEntry->status == ROW_DESTROY || pIfReqEntry->status == ROW_NOTINSERVICE)
  1966. {
  1967. return m2IfStackTblUpdate(pIfReqEntry->index, highIndex, M2_STACK_TABLE_REMOVE);
  1968. }
  1969.     semTake (m2InterfaceSem, WAIT_FOREVER);
  1970.     /* Validate the bounds of the requested index  */
  1971.     if (highIndex < 0 || highIndex >= ifsInList)
  1972.         {
  1973. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1974.         semGive (m2InterfaceSem);
  1975.         return (ERROR);
  1976.         }
  1977.     /*
  1978.      * Get the node associated with the higher index, because this
  1979.      * is where we will be making the change.
  1980.      */
  1981.     pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  1982.                                  (GENERIC_ARGUMENT)highIndex, nextIndex);
  1983.     if (!pIfIndexEntry)
  1984. {
  1985. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  1986. semGive(m2InterfaceSem);
  1987.         return (ERROR);
  1988. }
  1989.     
  1990.     pIfStackEntry = pIfIndexEntry->pNextLower;
  1991.     ppTemp = &pIfIndexEntry->pNextLower;
  1992.     
  1993.     while (pIfStackEntry)
  1994.         {
  1995.         if (pIfStackEntry->index == pIfReqEntry->index)
  1996.     break;
  1997.         ppTemp = &pIfStackEntry->pNextLower;
  1998.         pIfStackEntry = pIfStackEntry->pNextLower;
  1999.         }
  2000.     if (pIfStackEntry == 0)
  2001. {
  2002. errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  2003. semGive(m2InterfaceSem);
  2004. return ERROR;
  2005. }
  2006. #ifdef VIRTUAL_STACK
  2007.     _ifStackLastChange = centiSecsGet();
  2008. #else    /* VIRTUAL_STACK */
  2009.     ifStackLastChange = centiSecsGet();
  2010. #endif   /* VIRTUAL_STACK */
  2011.     semGive(m2InterfaceSem);
  2012.     return (OK);
  2013.     }
  2014. /******************************************************************************
  2015. *
  2016. * m2IfRcvAddrEntryGet - get the rcvAddress table entries for a given address
  2017. *
  2018. * This function returns the exact or the next value in the ifRcvAddressTable
  2019. * based on the value of the search parameter. In order to identify the
  2020. * appropriate entry, this function needs two identifiers - the ifIndex of the
  2021. * interface and the physical address for which the status or the type is
  2022. * being requested. For a M2_EXACT_VALUE search, this function returns the
  2023. * status and the type of the physical address in the instance. For a 
  2024. * M2_NEXT_VALUE search, it returns the type and status of the lexicographic
  2025. * successor of the physical address seen in the instance.
  2026. *
  2027. * RETURNS: OK, or ERROR if the input parameter is not specified, an interface
  2028. * is no longer valid, or the interface index is incorrect.
  2029. *
  2030. * ERRNO:
  2031. *   S_m2Lib_INVALID_PARAMETER
  2032. *   S_m2Lib_ENTRY_NOT_FOUND
  2033. *   S_m2Lib_IF_CNFG_CHANGED
  2034. *
  2035. */
  2036. STATUS m2IfRcvAddrEntryGet
  2037.     (
  2038.     int               search,         /* exact search or next search */
  2039.     int *             pIndex,         /* pointer to the ifIndex */
  2040.     M2_IFRCVADDRTBL * pIfReqEntry     /* struct for the values */
  2041.     )
  2042.     {
  2043.     int               index;
  2044.     int               cmp;
  2045.     M2_IFINDEX *      pIfIndexEntry = NULL;
  2046.     M2_IFRCVADDRTBL * pRcvAddrEntry = NULL;
  2047.     
  2048.     /* Validate the pointer to the requested structure */
  2049.     if (pIfReqEntry == NULL)
  2050.         {
  2051.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  2052.         return (ERROR);
  2053.         }
  2054.     index = *pIndex;
  2055.     
  2056.     semTake (m2InterfaceSem, WAIT_FOREVER);
  2057.     if ( (search == M2_NEXT_VALUE) && (index == 0) )
  2058.         {
  2059.         do
  2060.             {
  2061.             pIfIndexEntry = (M2_IFINDEX *) avlSuccessorGet (pM2IfRoot,
  2062.                                   (GENERIC_ARGUMENT)index, nextIndex);
  2063.             if (!pIfIndexEntry)
  2064.                 goto errorReturn;
  2065.             pRcvAddrEntry = pIfIndexEntry->pRcvAddr;
  2066.             index = pIfIndexEntry->ifIndex;
  2067.             } while (!pRcvAddrEntry);
  2068.         }
  2069.     else
  2070.         {
  2071.         pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  2072.                                   (GENERIC_ARGUMENT)index, nextIndex);
  2073.         pRcvAddrEntry = pIfIndexEntry->pRcvAddr;
  2074.         /*
  2075.          * If index is not zero, even though we have a next search,
  2076.          * we would still need to get the node associated with the
  2077.          * current index. The algorithm is as follows:
  2078.          * - Get the node associated with the current index.
  2079.          * - Look thru the list of addresses to see if we have a match.
  2080.          * - For an exact search, we return error upon no match, else
  2081.          *   we just pick up the next address, if any.
  2082.          * - If no address lexicographically greater is present in this
  2083.          *   node, we get the next node and do the above.
  2084.          */
  2085.         while (pRcvAddrEntry)
  2086.             {
  2087.             /* compare the physical addresses */
  2088.             cmp = bcmp (pIfReqEntry->ifRcvAddrAddr.phyAddress,
  2089.                     pRcvAddrEntry->ifRcvAddrAddr.phyAddress, ETHERADDRLEN);
  2090.             if (cmp == 1)
  2091.                 /* the reqested entry is greater than any entry in our base */
  2092.                 goto errorReturn;
  2093.             if ( ((cmp == 0) && (search == M2_NEXT_VALUE)) || (cmp == -1) )
  2094.                 {
  2095.                 /*
  2096.                  * we come here only in one of the two cases:
  2097.                  * either we encountered a match and are looking for a next
  2098.                  * OR we still haven't found a match
  2099.                  */
  2100.                 pRcvAddrEntry = pRcvAddrEntry->pNextEntry;
  2101.                 if (!pRcvAddrEntry)
  2102.                     {
  2103.                     /* no more addresses in this avl node, get next index */
  2104.                     if (search == M2_EXACT_VALUE)
  2105.                         goto errorReturn;
  2106.                     /* For a next search, search the next avl node */
  2107.                     do
  2108.                         {
  2109.                         index = pIfIndexEntry->ifIndex;
  2110.                         pIfIndexEntry = (M2_IFINDEX *) avlSuccessorGet
  2111.                             (pM2IfRoot, (GENERIC_ARGUMENT)index, nextIndex);
  2112.                         if (!pIfIndexEntry)
  2113.                             goto errorReturn;                        
  2114.                         } while (!pIfIndexEntry->pRcvAddr);
  2115.                     
  2116.                     pRcvAddrEntry = pIfIndexEntry->pRcvAddr;
  2117.                     }
  2118.                 /* Continue with the while loop if there is a valid addr */
  2119.                 continue;
  2120.                 }
  2121.             /* Found a perfect match and search is M2_EXACT_VALUE */
  2122.             break;
  2123.             }
  2124.         }
  2125.     
  2126.     /* found a match, copy the values */
  2127.     *pIndex = pIfIndexEntry->ifIndex;
  2128.     bcopy ((char *)pRcvAddrEntry->ifRcvAddrAddr.phyAddress,
  2129.                (char *)pIfReqEntry->ifRcvAddrAddr.phyAddress, ETHERADDRLEN);
  2130.     pIfReqEntry->ifRcvAddrAddr.addrLength = ETHERADDRLEN;
  2131.     pIfReqEntry->ifRcvAddrStatus = pRcvAddrEntry->ifRcvAddrStatus;
  2132.     pIfReqEntry->ifRcvAddrType = pRcvAddrEntry->ifRcvAddrType;
  2133.     semGive (m2InterfaceSem);
  2134.     return OK;
  2135. errorReturn:
  2136.     semGive (m2InterfaceSem);
  2137.     errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  2138.     return (ERROR);
  2139.     }
  2140. /******************************************************************************
  2141. *
  2142. * m2IfRcvAddrEntrySet - modify the entries of the rcvAddressTable
  2143. *
  2144. * This function modifies the status and type fields of a given receive address
  2145. * associated with a given interface. <varToSet> identifies the fields for 
  2146. * which the change is being requested.  We can also add multicast addresses
  2147. * by creating a new row in the table. The physical address is stripped from
  2148. * the instance value of the SNMP request. This routine does not allow the
  2149. * deletion of a unicast address. Neither does it allow the unicast address
  2150. * to be modified or created.
  2151. *
  2152. * RETURNS: OK, or ERROR if the input parameter is not specified, an interface
  2153. * is no longer valid, the interface index is incorrect, or the ioctl() command
  2154. * to the interface fails.
  2155. *
  2156. * ERRNO:
  2157. *   S_m2Lib_INVALID_PARAMETER
  2158. *   S_m2Lib_ENTRY_NOT_FOUND
  2159. *   S_m2Lib_IF_CNFG_CHANGED
  2160. *
  2161. * SEE ALSO:
  2162. * m2IfInit(), m2IfGroupInfoGet(), m2IfTblEntryGet(), m2IfDelete()
  2163. */
  2164. STATUS m2IfRcvAddrEntrySet
  2165.     (
  2166.     int               varToSet,       /* entries that need to be modified */
  2167.     int               index,          /* search type */
  2168.     M2_IFRCVADDRTBL * pIfReqEntry     /* struct containing the new values */
  2169.     )
  2170.     {
  2171.     int               cmp;
  2172.     M2_IFINDEX *      pIfIndexEntry = NULL;
  2173.     M2_IFRCVADDRTBL * pRcvAddrEntry = NULL;
  2174.     M2_IFRCVADDRTBL **ppTemp = NULL;
  2175.     LIST *            pMCastList = NULL;
  2176.     ETHER_MULTI *     pEtherMulti = NULL;
  2177.     struct arpcom *   pIfArpcom = NULL;
  2178.     if (pIfReqEntry == NULL)
  2179.         {
  2180.         errnoSet (S_m2Lib_INVALID_PARAMETER);
  2181.         return (ERROR);
  2182.         }
  2183.     semTake (m2InterfaceSem, WAIT_FOREVER);
  2184.     pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot,
  2185.                                   (GENERIC_ARGUMENT)index, nextIndex);
  2186.     pIfArpcom = (struct arpcom *)pIfIndexEntry->pIfStats;
  2187.     pRcvAddrEntry = pIfIndexEntry->pRcvAddr;
  2188.     ppTemp = &pIfIndexEntry->pRcvAddr;
  2189.     
  2190.     while (pRcvAddrEntry)
  2191.         {
  2192.         cmp = bcmp ((char *)pIfReqEntry->ifRcvAddrAddr.phyAddress,
  2193.                 (char *)pRcvAddrEntry->ifRcvAddrAddr.phyAddress, ETHERADDRLEN);
  2194.         if (cmp == 0)
  2195.             break;
  2196.         if (cmp == -1)
  2197.             goto errorReturn;
  2198.         ppTemp = &pRcvAddrEntry->pNextEntry;; 
  2199.         pRcvAddrEntry = pRcvAddrEntry->pNextEntry;
  2200.         }
  2201.     /* get the list pointer for the mcast address */
  2202.     if ( (pIfArpcom->ac_if.if_ioctl != NULL) &&
  2203.              ((*pIfArpcom->ac_if.if_ioctl)
  2204.               ((struct ifnet *)pIfArpcom, SIOCGMCASTLIST,
  2205.                                                 (caddr_t)&pMCastList) != 0) )
  2206.         {
  2207.         goto errorReturn;        
  2208.         }
  2209.     
  2210.     if ( (!pRcvAddrEntry) &&
  2211.          ((pIfReqEntry->ifRcvAddrStatus == ROW_CREATEANDGO) ||
  2212.           (pIfReqEntry->ifRcvAddrStatus == ROW_CREATEANDWAIT)) )
  2213.         {
  2214.         /* request to create a new entry */
  2215.         pEtherMulti = KHEAP_ALLOC(sizeof (ETHER_MULTI));
  2216.         if (!pEtherMulti)
  2217.             goto errorReturn;
  2218.         bcopy ((char *)pIfReqEntry->ifRcvAddrAddr.phyAddress,
  2219.                                    pEtherMulti->addr, ETHERADDRLEN);
  2220.         pEtherMulti->refcount = 0;
  2221.         if (rcvEtherAddrAdd (pIfIndexEntry,
  2222.                       pIfReqEntry->ifRcvAddrAddr.phyAddress) == OK)
  2223.             {
  2224.             lstAdd (pMCastList, (NODE *)pEtherMulti) ;
  2225.             }
  2226.         else
  2227.             goto errorReturn;
  2228.         }
  2229.     /* perform the set operation */
  2230.     if (pRcvAddrEntry)
  2231.         {
  2232.         if (varToSet & M2_IFRCVADDRSTATUS)
  2233.             {
  2234.             switch (pIfReqEntry->ifRcvAddrStatus)
  2235.                 {
  2236.                 case ROW_NOTINSERVICE:
  2237.                 case ROW_NOTREADY:
  2238.                 case ROW_DESTROY:
  2239.                     *ppTemp = pRcvAddrEntry->pNextEntry;
  2240.                     KHEAP_FREE((char *)pRcvAddrEntry);
  2241.                     break;
  2242.                 case ROW_ACTIVE:
  2243.                 default:
  2244.                     break;
  2245.                 }
  2246.             }
  2247.         if (varToSet & M2_IFRCVADDRTYPE)
  2248.             {
  2249.             pRcvAddrEntry->ifRcvAddrType = pIfReqEntry->ifRcvAddrType;
  2250.             }
  2251.         }
  2252.   
  2253.     semGive(m2InterfaceSem);
  2254.     return OK;
  2255. errorReturn:
  2256.     semGive (m2InterfaceSem);
  2257.     errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  2258.     return (ERROR);
  2259.     }
  2260. /*******************************************************************************
  2261. *
  2262. * m2IfDelete - delete all resources used to access the interface group
  2263. *
  2264. * This routine frees all the resources allocated at the time the group was
  2265. * initialized.  The interface group should not be accessed after this routine 
  2266. * has been called.
  2267. *
  2268. * RETURNS: OK, always.
  2269. *
  2270. * SEE ALSO:
  2271. * m2IfInit(), m2IfGroupInfoGet(), m2IfTblEntryGet(), m2IfTblEntrySet()
  2272. */
  2273. STATUS m2IfDelete (void)
  2274.     {
  2275.     /* Take the interface semaphore to delete the entries */
  2276.     semTake (m2InterfaceSem, WAIT_FOREVER);
  2277.     avlTreeErase (pM2IfRootPtr); 
  2278.     semGive (m2InterfaceSem);
  2279.     /* Release the interface semaphore */
  2280.     if (m2InterfaceSem != NULL)
  2281.         {
  2282.         semDelete (m2InterfaceSem);
  2283.         m2InterfaceSem = NULL;
  2284.         }
  2285.     /* Free Network I/F Table Struct */
  2286.  
  2287.     if (pm2IfTable != NULL)
  2288.         {
  2289.         KHEAP_FREE((char *)pm2IfTable);
  2290.         pm2IfTable = NULL;
  2291.         }
  2292.     /* Clear trap routine variables */
  2293.     pM2TrapRtn    = NULL;
  2294.     pM2TrapRtnArg = NULL;
  2295.     return (OK);
  2296.     }
  2297. /******************************************************************************
  2298. *
  2299. * nextIndex - the comparison routine for the AVL tree
  2300. *
  2301. * This routine compares the two indexes and returns a code based on wether
  2302. * the index, in question, is lesser than, equal to or greater than the one
  2303. * being compared.
  2304. *
  2305. * RETURNS
  2306. * -1, if the given index is lesser; 0, if equal; and 1, if greater.
  2307. */
  2308. int nextIndex
  2309.     (
  2310.     void *            pAvlNode,        /* The node to compare with */
  2311.     GENERIC_ARGUMENT  key              /* The given index */
  2312.     )
  2313.     {
  2314.     UINT             index;
  2315.     M2_IFINDEX *    pTmpIfIndex;
  2316.     pTmpIfIndex = (M2_IFINDEX *)pAvlNode;
  2317.     index = pTmpIfIndex->ifIndex;
  2318.     return ((key.u < index) ? -1 : (key.u == index) ? 0 : 1); 
  2319.     }
  2320. /***************************************************************************
  2321.  *
  2322.  * m2SetIfLastChange - set the ifLastChange MIB variable for the interface
  2323.  *
  2324.  * This routine sets the ifLastChange and ifAdminStatus for the interface
  2325.  * specified by the device and unit arguments.
  2326.  *
  2327.  * NOMANUAL
  2328.  *
  2329.  * RETURNS: OK, or ERROR if the interface isn't found in pm2IfTable
  2330.  *
  2331.  * SEE ALSO:
  2332.  * m2IfInit(), m2IfGroupInfoGet(), m2IfTblEntryGet(), m2IfTblEntrySet()
  2333.  */
  2334. STATUS m2SetIfLastChange
  2335.     (
  2336.     int    ifIndex
  2337.     )
  2338.     {
  2339.     long           adminStatus;
  2340.     M2_ID *        pM2Id = NULL;
  2341.     struct ifnet * pIfNetEntry = NULL;
  2342.     M2_IFINDEX *   pIfIndexEntry = NULL;
  2343.     semTake (m2InterfaceSem, WAIT_FOREVER);
  2344.     /* 
  2345.      * As the ifnet flags has changed, we must change the ifAdminStatus
  2346.      * change the ifAdminStatus in the MIB table. To do this, we have to 
  2347.      * request the driver to provide a pointer to the MIB data and that is
  2348.      * possible only via an IOCTL. So, we must first get the ifnet structure.
  2349.      */
  2350.     pIfIndexEntry = (M2_IFINDEX *) avlSearch (pM2IfRoot, 
  2351.                                           (GENERIC_ARGUMENT)ifIndex, nextIndex);
  2352.     if (pIfIndexEntry == NULL)
  2353.         {
  2354.         semGive (m2InterfaceSem);
  2355.         errnoSet (S_m2Lib_ENTRY_NOT_FOUND);
  2356.         return (ERROR);
  2357.         }
  2358.     /* 
  2359.      * In order to issue an IOCTL, we must know the type of MIB table that
  2360.      * the driver supports ... RFC2233 or RFC1213.
  2361.      */
  2362.     pIfNetEntry = (struct ifnet *) pIfIndexEntry->pIfStats;
  2363.     adminStatus = ((pIfNetEntry->if_flags & IFF_UP) != 0) ? 
  2364.                                     M2_ifAdminStatus_up : M2_ifAdminStatus_down;
  2365.         
  2366.     if (pIfIndexEntry->mibStyle == TRUE)
  2367.         {
  2368.         /* 
  2369.          * RFC 2233 style ... If IOCTL fails, there is nothing we can do, so
  2370.          * we simply return saying OK. 
  2371.          */
  2372.         if ( (pIfNetEntry->if_ioctl != NULL) &&
  2373.                                    ((*pIfNetEntry->if_ioctl)(pIfNetEntry, 
  2374.                                          SIOCGMIB2233, (caddr_t)&pM2Id) == 0) )
  2375.             {
  2376.             if (pM2Id != NULL)
  2377.                 {
  2378.                 pM2Id->m2VarUpdateRtn (pM2Id, M2_varId_ifAdminStatus, 
  2379.                                                          (caddr_t)adminStatus);
  2380.                 pM2Id->m2VarUpdateRtn (pM2Id, M2_varId_ifLastChange, 
  2381.                                                       (caddr_t)centiSecsGet());
  2382.                 }
  2383.             }
  2384.         }
  2385.     else
  2386.         {
  2387.         /* 
  2388.          * RFC 1213 style
  2389.          * We get hold of the END_OBJ so that we can update the ifLastChange
  2390.          * field in the mib2Tbl structure. Ugh.... This is a very bad way
  2391.          * of doing it, but there is no other way currently. Once all
  2392.          * drivers support RFC 2233, this can be removed.
  2393.          */
  2394.         M2_INTERFACETBL * pMib2Tbl = NULL;
  2395.         pMib2Tbl = (M2_INTERFACETBL *) 
  2396.                                 ifnetToEndFieldsGet (pIfNetEntry, END_OBJ_MIB);
  2397.         if (pMib2Tbl == NULL)
  2398.             {
  2399.             semGive (m2InterfaceSem);
  2400.             return (ERROR);
  2401.             }
  2402.         pMib2Tbl->ifLastChange = centiSecsGet ();
  2403.         pMib2Tbl->ifAdminStatus = adminStatus;
  2404.         }
  2405.     semGive (m2InterfaceSem);
  2406.     return (OK);
  2407.     }
  2408. /***************************************************************************
  2409.  *
  2410.  * ifnetToEndFieldsGet - get the END object's various fields given the ifnet 
  2411.  *                       pointer
  2412.  *
  2413.  * This routine returns a pointer to the requested field in the END_OBJ
  2414.  * structure. The values for the <field> parameter are defined at the 
  2415.  * beginning of this module.
  2416.  *
  2417.  * NOMANUAL
  2418.  *
  2419.  * RETURNS: pointer to the requested field of the END_OBJ structure.
  2420.  *          NULL if the field requested is not defined in this module or
  2421.  *               if a NULL pointer was encountered somewhere.
  2422.  *
  2423.  */
  2424. LOCAL void * ifnetToEndFieldsGet
  2425.     (
  2426.     struct ifnet   *pIfNet,       /* ifnet pointer */
  2427.     int             field         /* field of the END_OBJ */
  2428.     )
  2429.     {
  2430.     END_OBJ     *pEnd = NULL;
  2431.     IP_DRV_CTRL *pDrvCtrl = NULL;
  2432.     if (pIfNet)
  2433.         {
  2434.         pDrvCtrl = (IP_DRV_CTRL *) pIfNet->pCookie;
  2435.         if ( (pDrvCtrl) && 
  2436.                 ((pEnd = PCOOKIE_TO_ENDOBJ (pDrvCtrl->pIpCookie)) != NULL) )
  2437.             {
  2438.             switch (field)
  2439.                 {
  2440.                 case END_OBJ_MIB:
  2441.                     return (&pEnd->mib2Tbl);
  2442.                 case END_OBJ_FLAGS:
  2443.                     return (&pEnd->flags);
  2444.                 default:
  2445.                     break;
  2446.                 }
  2447.             }
  2448.         }
  2449.     return (NULL);
  2450.     }