Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1543 lines
45 KiB

  1. /*++ BUILD Version: 0001 // Increment this if a change has global effects
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dhcpmib.c
  5. Abstract:
  6. DHCP SNMP Extension Agent for Windows NT.
  7. These files (dhcpmibm.c, dhcpmib.c, and dhcpmib.h) provide an example of
  8. how to structure an Extension Agent DLL which works in conjunction with
  9. the SNMP Extendible Agent for Windows NT.
  10. Extensive comments have been included to describe its structure and
  11. operation. See also "Microsoft Windows/NT SNMP Programmer's Reference".
  12. Created:
  13. 15-Jan-1994
  14. Revision History:
  15. Pradeep Bahl 1/11/94
  16. --*/
  17. // This Extension Agent implements the DHCP MIB. It's
  18. // definition follows here:
  19. //
  20. //
  21. // Necessary includes.
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <nt.h>
  25. #include <ntrtl.h>
  26. #include <nturtl.h>
  27. #include <windows.h>
  28. #include <winbase.h> //for SYSTEMTIME def
  29. #include <rpc.h>
  30. #include "dhcpapi.h"
  31. #include <string.h>
  32. #include <time.h>
  33. #include <search.h>
  34. // Contains definitions for the table structure describing the MIB. This
  35. // is used in conjunction with winsmib.c where the MIB requests are resolved.
  36. #include "dhcpmib.h"
  37. // If an addition or deletion to the MIB is necessary, there are several
  38. // places in the code that must be checked and possibly changed.
  39. //
  40. // The last field in each MIB entry is used to point to the NEXT
  41. // leaf variable. If an addition or deletetion is made, these pointers
  42. // may need to be updated to reflect the modification.
  43. #define LOCAL_ADD L"127.0.0.1"
  44. //
  45. // Used by MIBStat
  46. //
  47. #define TMST(x) x.wHour,\
  48. x.wMinute,\
  49. x.wSecond,\
  50. x.wMonth,\
  51. x.wDay,\
  52. x.wYear
  53. #define PRINTTIME(Var, x) sprintf(Var, "%02u:%02u:%02u on %02u:%02u:%04u.\n", TMST(x))
  54. //
  55. // All MIB variables in the common group have 1 as their first id
  56. //
  57. #define COMMON_VAL_M(pMib) ((pMib)->Oid.ids[0] == 1)
  58. //
  59. // All MIB variables in the scope group have 2 as their first id
  60. //
  61. #define SCOPE_VAL_M(pMib) ((pMib)->Oid.ids[0] == 2)
  62. static LPDHCP_MIB_INFO spMibInfo = NULL;
  63. //
  64. // The prefix to all of the DHCP MIB variables is 1.3.6.1.4.1.311.1.3
  65. //
  66. // The last digit -- 3 is for the DHCP MIB
  67. //
  68. UINT OID_Prefix[] = { 1, 3, 6, 1, 4, 1, 311, 1, 3 };
  69. AsnObjectIdentifier MIB_OidPrefix = { OID_SIZEOF(OID_Prefix), OID_Prefix };
  70. BOOL fDhcpMibVarsAccessed = FALSE;
  71. //
  72. // Definition of the Dhcp MIB (not used)
  73. //
  74. //UINT MIB_Dhcp[] = { 3 };
  75. //
  76. // OID definitions for MIB
  77. //
  78. //
  79. // Definition of group and leaf variables under the wins group
  80. // All leaf variables have a zero appended to their OID to indicate
  81. // that it is the only instance of this variable and it exists.
  82. //
  83. UINT MIB_Parameters[] = { 1 };
  84. UINT MIB_DhcpStartTime[] = { 1, 1, 0 };
  85. UINT MIB_NoOfDiscovers[] = { 1, 2, 0 };
  86. UINT MIB_NoOfRequests[] = { 1, 3, 0 };
  87. UINT MIB_NoOfReleases[] = { 1, 4, 0 };
  88. UINT MIB_NoOfOffers[] = { 1, 5, 0 };
  89. UINT MIB_NoOfAcks[] = { 1, 6, 0 };
  90. UINT MIB_NoOfNacks[] = { 1, 7, 0 };
  91. UINT MIB_NoOfDeclines[] = { 1, 8, 0 };
  92. //
  93. // Scope table
  94. //
  95. UINT MIB_Scope[] = { 2 };
  96. UINT MIB_ScopeTable[] = { 2, 1};
  97. UINT MIB_ScopeTableEntry[] = { 2, 1, 1};
  98. //
  99. // //
  100. // Storage definitions for MIB //
  101. // //
  102. char MIB_DhcpStartTimeStore[80];
  103. AsnCounter MIB_NoOfDiscoversStore;
  104. AsnCounter MIB_NoOfRequestsStore;
  105. AsnCounter MIB_NoOfReleasesStore;
  106. AsnCounter MIB_NoOfOffersStore;
  107. AsnCounter MIB_NoOfAcksStore;
  108. AsnCounter MIB_NoOfNacksStore;
  109. AsnCounter MIB_NoOfDeclinesStore;
  110. static
  111. UINT
  112. MIB_Table(
  113. IN DWORD Index,
  114. IN UINT Action,
  115. IN PMIB_ENTRY pMibPtr,
  116. IN RFC1157VarBind *VarBind
  117. );
  118. static
  119. UINT
  120. ScopeTable(
  121. IN UINT Action,
  122. IN PMIB_ENTRY pMibPtr,
  123. IN RFC1157VarBind *VarBind
  124. );
  125. static
  126. UINT
  127. MIB_leaf_func(
  128. IN UINT Action,
  129. IN MIB_ENTRY *MibPtr,
  130. IN RFC1157VarBind *VarBind
  131. );
  132. static
  133. UINT
  134. MIB_Stat(
  135. IN UINT Action,
  136. IN MIB_ENTRY *MibPtr,
  137. IN RFC1157VarBind *VarBind
  138. );
  139. static
  140. DWORD
  141. GetMibInfo (
  142. LPWSTR DhcpAdd,
  143. LPDHCP_MIB_INFO *ppMibInfo
  144. );
  145. //
  146. // MIB definiton
  147. //
  148. MIB_ENTRY Mib[] = {
  149. //parameters
  150. { { OID_SIZEOF(MIB_Parameters), MIB_Parameters },
  151. NULL, ASN_RFC1155_OPAQUE,
  152. MIB_NOACCESS, NULL, &Mib[1] },
  153. { { OID_SIZEOF(MIB_DhcpStartTime), MIB_DhcpStartTime },
  154. &MIB_DhcpStartTimeStore, ASN_RFC1213_DISPSTRING,
  155. MIB_ACCESS_READ, MIB_Stat, &Mib[2] },
  156. { { OID_SIZEOF(MIB_NoOfDiscovers), MIB_NoOfDiscovers },
  157. &MIB_NoOfDiscoversStore, ASN_RFC1155_COUNTER,
  158. MIB_ACCESS_READ, MIB_Stat, &Mib[3] },
  159. { { OID_SIZEOF(MIB_NoOfRequests), MIB_NoOfRequests },
  160. &MIB_NoOfRequestsStore, ASN_RFC1155_COUNTER,
  161. MIB_ACCESS_READ, MIB_Stat, &Mib[4] },
  162. { { OID_SIZEOF(MIB_NoOfReleases), MIB_NoOfReleases },
  163. &MIB_NoOfReleasesStore, ASN_RFC1155_COUNTER,
  164. MIB_ACCESS_READ, MIB_Stat, &Mib[5] },
  165. { { OID_SIZEOF(MIB_NoOfOffers), MIB_NoOfOffers },
  166. &MIB_NoOfOffersStore, ASN_RFC1155_COUNTER,
  167. MIB_ACCESS_READ, MIB_Stat, &Mib[6] },
  168. { { OID_SIZEOF(MIB_NoOfAcks), MIB_NoOfAcks },
  169. &MIB_NoOfAcksStore, ASN_RFC1155_COUNTER,
  170. MIB_ACCESS_READ, MIB_Stat, &Mib[7] },
  171. { { OID_SIZEOF(MIB_NoOfNacks), MIB_NoOfNacks },
  172. &MIB_NoOfNacksStore, ASN_RFC1155_COUNTER,
  173. MIB_ACCESS_READ, MIB_Stat, &Mib[8] },
  174. { { OID_SIZEOF(MIB_NoOfDeclines), MIB_NoOfDeclines },
  175. &MIB_NoOfDeclinesStore, ASN_RFC1155_COUNTER,
  176. MIB_ACCESS_READ, MIB_Stat, &Mib[9] },
  177. //
  178. // Scope
  179. //
  180. { { OID_SIZEOF(MIB_Scope), MIB_Scope },
  181. NULL, ASN_RFC1155_OPAQUE,
  182. MIB_NOACCESS, NULL, &Mib[10] },
  183. { { OID_SIZEOF(MIB_ScopeTable), MIB_ScopeTable },
  184. NULL, ASN_RFC1155_OPAQUE,
  185. MIB_ACCESS_READ, NULL, &Mib[11] },
  186. { { OID_SIZEOF(MIB_ScopeTableEntry), MIB_ScopeTableEntry },
  187. NULL, ASN_SEQUENCE,
  188. MIB_ACCESS_READ, ScopeTable, NULL }
  189. };
  190. //
  191. // defines pertaining to tables
  192. //
  193. #define SCOPE_OIDLEN (MIB_PREFIX_LEN + OID_SIZEOF(MIB_ScopeTableEntry))
  194. #define NO_FLDS_IN_SCOPE_ROW 4
  195. #define SCOPE_TABLE_INDEX 0
  196. #define NUM_TABLES sizeof(Tables)/sizeof(TAB_INFO_T)
  197. UINT MIB_num_variables = sizeof Mib / sizeof( MIB_ENTRY );
  198. //
  199. // table structure containing the functions to invoke for different actions
  200. // on the table
  201. //
  202. typedef struct _TAB_INFO_T {
  203. UINT (*ti_get)(
  204. RFC1157VarBind *VarBind
  205. );
  206. UINT (*ti_getf)(
  207. RFC1157VarBind *VarBind,
  208. PMIB_ENTRY pMibEntry
  209. );
  210. UINT (*ti_getn)(
  211. RFC1157VarBind *VarBind,
  212. PMIB_ENTRY pMibEntry
  213. );
  214. UINT (*ti_set)(
  215. RFC1157VarBind *VarBind
  216. );
  217. PMIB_ENTRY pMibPtr;
  218. } TAB_INFO_T, *PTAB_INFO_T;
  219. static
  220. UINT
  221. ScopeGetNext(
  222. IN RFC1157VarBind *VarBind,
  223. IN PMIB_ENTRY pMibPtr
  224. );
  225. static
  226. UINT
  227. ScopeGet(
  228. IN RFC1157VarBind *VarBind
  229. );
  230. static
  231. UINT
  232. ScopeGetFirst(
  233. IN RFC1157VarBind *VarBind,
  234. IN PMIB_ENTRY pMibPtr
  235. );
  236. static
  237. UINT
  238. ScopeMatch(
  239. IN RFC1157VarBind *VarBind,
  240. IN LPDWORD pIndex,
  241. IN LPDWORD pField,
  242. IN UINT PduAction,
  243. IN LPBOOL pfFirst
  244. );
  245. extern
  246. UINT
  247. ScopeFindNext(
  248. INT SubnetIndex
  249. );
  250. static
  251. int
  252. __cdecl
  253. CompareScopes(
  254. const VOID *pKey1,
  255. const VOID *pKey2
  256. );
  257. static
  258. UINT
  259. GetNextVar(
  260. IN RFC1157VarBind *pVarBind,
  261. IN PMIB_ENTRY pMibPtr
  262. );
  263. TAB_INFO_T Tables[] = {
  264. ScopeGet,
  265. ScopeGetFirst,
  266. ScopeGetNext,
  267. NULL,
  268. &Mib[11]
  269. };
  270. UINT
  271. ResolveVarBind(
  272. IN OUT RFC1157VarBind *VarBind, // Variable Binding to resolve
  273. IN UINT PduAction // Action specified in PDU
  274. )
  275. //
  276. // ResolveVarBind
  277. // Resolves a single variable binding. Modifies the variable on a GET
  278. // or a GET-NEXT.
  279. //
  280. // Notes:
  281. //
  282. // Return Codes:
  283. // Standard PDU error codes.
  284. //
  285. // Error Codes:
  286. // None.
  287. //
  288. {
  289. MIB_ENTRY *MibPtr;
  290. AsnObjectIdentifier TempOid;
  291. int CompResult;
  292. UINT I;
  293. UINT nResult;
  294. DWORD TableIndex;
  295. BOOL fTableMatch = FALSE;
  296. //
  297. // Check the Tables array
  298. //
  299. // See if the prefix of the variable matches the prefix of
  300. // any of the tables
  301. //
  302. for (TableIndex = 0; TableIndex < NUM_TABLES; TableIndex++)
  303. {
  304. //
  305. // Construct OID with complete prefix for comparison purposes
  306. //
  307. SnmpUtilOidCpy( &TempOid, &MIB_OidPrefix );
  308. SnmpUtilOidAppend( &TempOid, &Tables[TableIndex].pMibPtr->Oid );
  309. //
  310. // is there a match with the prefix oid of a table entry
  311. //
  312. if (
  313. SnmpUtilOidNCmp(
  314. &VarBind->name,
  315. &TempOid,
  316. MIB_PREFIX_LEN +
  317. Tables[TableIndex].pMibPtr->Oid.idLength
  318. ) == 0
  319. )
  320. {
  321. //
  322. // the prefix string of the var. matched the oid
  323. // of a table.
  324. //
  325. MibPtr = Tables[TableIndex].pMibPtr;
  326. fTableMatch = TRUE;
  327. break;
  328. }
  329. // Free OID memory before checking with another table entry
  330. SnmpUtilOidFree( &TempOid );
  331. }
  332. //
  333. // There was an exact match with a table entry's prefix.
  334. //
  335. if ( fTableMatch)
  336. {
  337. if (
  338. (SnmpUtilOidCmp(
  339. &VarBind->name,
  340. &TempOid
  341. ) == 0)
  342. )
  343. {
  344. //
  345. // The oid specified is a prefix of a table entry. if the operation
  346. // is not GETNEXT, return NOSUCHNAME
  347. //
  348. if (PduAction != MIB_GETNEXT)
  349. {
  350. SnmpUtilOidFree( &TempOid );
  351. nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
  352. goto Exit;
  353. }
  354. else
  355. {
  356. UINT TableEntryIds[1];
  357. AsnObjectIdentifier TableEntryOid = {
  358. OID_SIZEOF(TableEntryIds), TableEntryIds };
  359. //
  360. // Replace var bind name with new name
  361. //
  362. //
  363. // A sequence item oid always starts with a field no.
  364. // The first item has a field no of 1.
  365. //
  366. TableEntryIds[0] = 1;
  367. SnmpUtilOidAppend( &VarBind->name, &TableEntryOid);
  368. //
  369. // Get the first entry in the table
  370. //
  371. PduAction = MIB_GETFIRST;
  372. }
  373. }
  374. SnmpUtilOidFree( &TempOid );
  375. //
  376. // if there was no exact match with a prefix entry, then we
  377. // don't touch the PduAction value specified.
  378. //
  379. }
  380. else
  381. {
  382. //
  383. // There was no match with any table entry. Let us see if there is
  384. // a match with a group entry, a table, or a leaf variable
  385. //
  386. //
  387. // Search for var bind name in the MIB
  388. //
  389. I = 0;
  390. MibPtr = NULL;
  391. while ( MibPtr == NULL && I < MIB_num_variables )
  392. {
  393. //
  394. // Construct OID with complete prefix for comparison purposes
  395. //
  396. SnmpUtilOidCpy( &TempOid, &MIB_OidPrefix );
  397. SnmpUtilOidAppend( &TempOid, &Mib[I].Oid );
  398. //
  399. //Check for OID in MIB - On a GET-NEXT the OID does not have to exactly
  400. // match a variable in the MIB, it must only fall under the MIB root.
  401. //
  402. CompResult = SnmpUtilOidCmp( &VarBind->name, &TempOid );
  403. //
  404. // If CompResult is negative, the only valid operation is GET_NEXT
  405. //
  406. if ( CompResult < 0)
  407. {
  408. //
  409. // This could be the oid of a leaf (without a 0)
  410. // or it could be an invalid oid (in between two valid oids)
  411. // The next oid might be that of a group or a table or table
  412. // entry. In that case, we do not change the PduAction
  413. //
  414. if (PduAction == MIB_GETNEXT)
  415. {
  416. MibPtr = &Mib[I];
  417. SnmpUtilOidFree( &VarBind->name );
  418. SnmpUtilOidCpy( &VarBind->name, &MIB_OidPrefix );
  419. SnmpUtilOidAppend( &VarBind->name, &MibPtr->Oid );
  420. if (
  421. (MibPtr->Type != ASN_RFC1155_OPAQUE)
  422. &&
  423. (MibPtr->Type != ASN_SEQUENCE)
  424. )
  425. {
  426. PduAction = MIB_GET;
  427. }
  428. }
  429. else
  430. {
  431. nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
  432. SnmpUtilOidFree( &TempOid );
  433. goto Exit;
  434. }
  435. SnmpUtilOidFree( &TempOid );
  436. break;
  437. }
  438. else
  439. {
  440. //
  441. // An exact match was found ( a group, table, or leaf).
  442. //
  443. if ( CompResult == 0)
  444. {
  445. MibPtr = &Mib[I];
  446. }
  447. }
  448. //
  449. // Free OID memory before checking another variable
  450. //
  451. SnmpUtilOidFree( &TempOid );
  452. I++;
  453. } // while
  454. } // end of else
  455. //
  456. // if there was a match
  457. //
  458. if (MibPtr != NULL)
  459. {
  460. //
  461. // the function will be NULL only if the match was with a group
  462. // or a sequence (table). If the match was with a table entry
  463. // (entire VarBind string match or partial string match), we
  464. // function would be a table function
  465. //
  466. if (MibPtr->MibFunc == NULL)
  467. {
  468. if(PduAction != MIB_GETNEXT)
  469. {
  470. nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
  471. goto Exit;
  472. }
  473. else
  474. {
  475. //
  476. // Get the next variable which allows access
  477. //
  478. nResult = GetNextVar(VarBind, MibPtr);
  479. goto Exit;
  480. }
  481. }
  482. }
  483. else
  484. {
  485. nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
  486. goto Exit;
  487. }
  488. //
  489. // Call function to process request. Each MIB entry has a function pointer
  490. // that knows how to process its MIB variable.
  491. //
  492. nResult = (*MibPtr->MibFunc)( PduAction, MibPtr, VarBind );
  493. Exit:
  494. return nResult;
  495. } // ResolveVarBind
  496. //
  497. // MIB_leaf_func
  498. // Performs generic actions on LEAF variables in the MIB.
  499. //
  500. // Notes:
  501. //
  502. // Return Codes:
  503. // Standard PDU error codes.
  504. //
  505. // Error Codes:
  506. // None.
  507. //
  508. UINT MIB_leaf_func(
  509. IN UINT Action,
  510. IN MIB_ENTRY *MibPtr,
  511. IN RFC1157VarBind *VarBind
  512. )
  513. {
  514. UINT ErrStat;
  515. switch ( Action )
  516. {
  517. case MIB_GETNEXT:
  518. //
  519. // If there is no GET-NEXT pointer, this is the end of this MIB
  520. //
  521. if ( MibPtr->MibNext == NULL )
  522. {
  523. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  524. goto Exit;
  525. }
  526. ErrStat = GetNextVar(VarBind, MibPtr);
  527. if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
  528. {
  529. goto Exit;
  530. }
  531. break;
  532. case MIB_GETFIRST: // fall through
  533. case MIB_GET:
  534. // Make sure that this variable's ACCESS is GET'able
  535. if ( MibPtr->Access != MIB_ACCESS_READ &&
  536. MibPtr->Access != MIB_ACCESS_READWRITE )
  537. {
  538. ErrStat = SNMP_ERRORSTATUS_NOACCESS;
  539. goto Exit;
  540. }
  541. // Setup varbind's return value
  542. VarBind->value.asnType = MibPtr->Type;
  543. switch ( VarBind->value.asnType )
  544. {
  545. case ASN_RFC1155_COUNTER:
  546. VarBind->value.asnValue.number = *(AsnCounter *)(MibPtr->Storage);
  547. break;
  548. case ASN_RFC1155_GAUGE:
  549. case ASN_INTEGER:
  550. VarBind->value.asnValue.number = *(AsnInteger *)(MibPtr->Storage);
  551. break;
  552. case ASN_RFC1155_IPADDRESS:
  553. //
  554. // fall through
  555. //
  556. case ASN_OCTETSTRING:
  557. if (VarBind->value.asnType == ASN_RFC1155_IPADDRESS)
  558. {
  559. VarBind->value.asnValue.string.length = 4;
  560. }
  561. else
  562. {
  563. VarBind->value.asnValue.string.length =
  564. strlen( (LPSTR)MibPtr->Storage );
  565. }
  566. if ( NULL ==
  567. (VarBind->value.asnValue.string.stream =
  568. SnmpUtilMemAlloc(VarBind->value.asnValue.string.length *
  569. sizeof(char))) )
  570. {
  571. ErrStat = SNMP_ERRORSTATUS_GENERR;
  572. goto Exit;
  573. }
  574. memcpy( VarBind->value.asnValue.string.stream,
  575. (LPSTR)MibPtr->Storage,
  576. VarBind->value.asnValue.string.length );
  577. VarBind->value.asnValue.string.dynamic = TRUE;
  578. break;
  579. default:
  580. ErrStat = SNMP_ERRORSTATUS_GENERR;
  581. goto Exit;
  582. }
  583. break;
  584. case MIB_SET:
  585. // Make sure that this variable's ACCESS is SET'able
  586. if ( MibPtr->Access != MIB_ACCESS_READWRITE &&
  587. MibPtr->Access != MIB_ACCESS_WRITE )
  588. {
  589. ErrStat = SNMP_ERRORSTATUS_NOTWRITABLE;
  590. goto Exit;
  591. }
  592. // Check for proper type before setting
  593. if ( MibPtr->Type != VarBind->value.asnType )
  594. {
  595. ErrStat = SNMP_ERRORSTATUS_WRONGTYPE;
  596. goto Exit;
  597. }
  598. // Save value in MIB
  599. switch ( VarBind->value.asnType )
  600. {
  601. case ASN_RFC1155_COUNTER:
  602. *(AsnCounter *)(MibPtr->Storage) = VarBind->value.asnValue.number;
  603. break;
  604. case ASN_RFC1155_GAUGE:
  605. case ASN_INTEGER:
  606. *(AsnInteger *)(MibPtr->Storage) = VarBind->value.asnValue.number;
  607. break;
  608. case ASN_RFC1155_IPADDRESS:
  609. //
  610. // fall through
  611. //
  612. case ASN_OCTETSTRING:
  613. // The storage must be adequate to contain the new string
  614. // including a NULL terminator.
  615. memcpy( (LPSTR)MibPtr->Storage,
  616. VarBind->value.asnValue.string.stream,
  617. VarBind->value.asnValue.string.length );
  618. ((LPSTR)MibPtr->Storage)[VarBind->value.asnValue.string.length] =
  619. '\0';
  620. if ( VarBind->value.asnValue.string.dynamic)
  621. {
  622. SnmpUtilMemFree( VarBind->value.asnValue.string.stream);
  623. }
  624. break;
  625. default:
  626. ErrStat = SNMP_ERRORSTATUS_GENERR;
  627. goto Exit;
  628. }
  629. break;
  630. default:
  631. ErrStat = SNMP_ERRORSTATUS_GENERR;
  632. goto Exit;
  633. } // switch
  634. // Signal no error occurred
  635. ErrStat = SNMP_ERRORSTATUS_NOERROR;
  636. Exit:
  637. return ErrStat;
  638. } // MIB_leaf_func
  639. //
  640. // MIB_Stat
  641. // Performs specific actions on the different MIB variable
  642. //
  643. // Notes:
  644. //
  645. // Return Codes:
  646. // Standard PDU error codes.
  647. //
  648. // Error Codes:
  649. // None.
  650. //
  651. UINT MIB_Stat(
  652. IN UINT Action,
  653. IN MIB_ENTRY *MibPtr,
  654. IN RFC1157VarBind *VarBind
  655. )
  656. {
  657. DWORD Status;
  658. UINT ErrStat;
  659. SYSTEMTIME DhcpStartTime;
  660. switch ( Action )
  661. {
  662. case MIB_SET:
  663. ErrStat = MIB_leaf_func( Action, MibPtr, VarBind );
  664. break;
  665. case MIB_GETNEXT:
  666. ErrStat = MIB_leaf_func( Action, MibPtr, VarBind );
  667. break;
  668. case MIB_GETFIRST:
  669. //
  670. // fall through
  671. //
  672. case MIB_GET:
  673. //
  674. // Call the DhcpStatus function to get the statistics
  675. //
  676. Status = GetMibInfo(LOCAL_ADD, &spMibInfo);
  677. if (Status == ERROR_SUCCESS)
  678. {
  679. if (FileTimeToSystemTime(
  680. (FILETIME *)&spMibInfo->ServerStartTime,
  681. &DhcpStartTime
  682. ) == FALSE)
  683. {
  684. goto Exit;
  685. }
  686. if (MibPtr->Storage == &MIB_DhcpStartTimeStore)
  687. {
  688. PRINTTIME(MIB_DhcpStartTimeStore, DhcpStartTime);
  689. goto LEAF1;
  690. }
  691. if (MibPtr->Storage == &MIB_NoOfDiscoversStore)
  692. {
  693. MIB_NoOfDiscoversStore = spMibInfo->Discovers;
  694. goto LEAF1;
  695. }
  696. if (MibPtr->Storage == &MIB_NoOfRequestsStore)
  697. {
  698. MIB_NoOfRequestsStore = spMibInfo->Requests;
  699. goto LEAF1;
  700. }
  701. if (MibPtr->Storage == &MIB_NoOfReleasesStore)
  702. {
  703. MIB_NoOfReleasesStore = spMibInfo->Releases;
  704. goto LEAF1;
  705. }
  706. if (MibPtr->Storage == &MIB_NoOfOffersStore)
  707. {
  708. MIB_NoOfOffersStore = spMibInfo->Offers;
  709. goto LEAF1;
  710. }
  711. if (MibPtr->Storage == &MIB_NoOfAcksStore)
  712. {
  713. MIB_NoOfAcksStore = spMibInfo->Acks;
  714. goto LEAF1;
  715. }
  716. if (MibPtr->Storage == &MIB_NoOfNacksStore)
  717. {
  718. MIB_NoOfNacksStore = spMibInfo->Naks;
  719. goto LEAF1;
  720. }
  721. if (MibPtr->Storage == &MIB_NoOfDeclinesStore)
  722. {
  723. MIB_NoOfNacksStore = spMibInfo->Naks;
  724. goto LEAF1;
  725. }
  726. ErrStat = SNMP_ERRORSTATUS_GENERR;
  727. goto Exit;
  728. }
  729. else
  730. {
  731. printf("Error from DhcpStatus = (%d)\n", Status);
  732. ErrStat = (Status == RPC_S_SERVER_UNAVAILABLE) ?
  733. SNMP_ERRORSTATUS_NOSUCHNAME :
  734. SNMP_ERRORSTATUS_GENERR;
  735. goto Exit;
  736. }
  737. LEAF1:
  738. // Call the more generic function to perform the action
  739. ErrStat = MIB_leaf_func( Action, MibPtr, VarBind );
  740. break;
  741. default:
  742. ErrStat = SNMP_ERRORSTATUS_GENERR;
  743. goto Exit;
  744. } // switch
  745. Exit:
  746. return ErrStat;
  747. } // MIB_Stat
  748. DWORD GetMibInfo (
  749. LPWSTR DhcpAdd,
  750. LPDHCP_MIB_INFO *ppMibInfo
  751. )
  752. {
  753. DWORD Status = ERROR_SUCCESS;
  754. if (!fDhcpMibVarsAccessed)
  755. {
  756. //
  757. // The Dhcp server does a single node allocation. So we
  758. // we need to free only spMibInfo.
  759. //
  760. if (spMibInfo != NULL)
  761. {
  762. #if 0
  763. if (spMibInfo->ScopeInfo != NULL)
  764. {
  765. DhcpRpcFreeMemory(spMibInfo->ScopeInfo);
  766. spMibInfo->ScopeInfo = NULL;
  767. }
  768. #endif
  769. DhcpRpcFreeMemory(spMibInfo);
  770. spMibInfo = NULL;
  771. }
  772. Status = DhcpGetMibInfo(LOCAL_ADD, &spMibInfo);
  773. if (Status == ERROR_SUCCESS)
  774. {
  775. if (spMibInfo->Scopes > 1)
  776. {
  777. ASSERT(spMibInfo->ScopeInfo != NULL);
  778. qsort(spMibInfo->ScopeInfo,(size_t)spMibInfo->Scopes,
  779. sizeof(SCOPE_MIB_INFO),CompareScopes );
  780. }
  781. fDhcpMibVarsAccessed = TRUE;
  782. }
  783. else
  784. {
  785. fDhcpMibVarsAccessed = FALSE;
  786. }
  787. }
  788. return(Status);
  789. }
  790. int
  791. __cdecl
  792. CompareScopes(
  793. const VOID *pKey1,
  794. const VOID *pKey2
  795. )
  796. {
  797. const LPSCOPE_MIB_INFO pScopeKey1 = (LPSCOPE_MIB_INFO)pKey1;
  798. const LPSCOPE_MIB_INFO pScopeKey2 = (LPSCOPE_MIB_INFO)pKey2;
  799. if( pScopeKey1->Subnet < pScopeKey2->Subnet)
  800. return -1;
  801. if (pScopeKey1->Subnet != pScopeKey2->Subnet )
  802. return 1;
  803. return 0;
  804. }
  805. UINT
  806. GetNextVar(
  807. IN RFC1157VarBind *pVarBind,
  808. IN MIB_ENTRY *pMibPtr
  809. )
  810. {
  811. UINT ErrStat;
  812. while (pMibPtr != NULL)
  813. {
  814. if (pMibPtr->MibNext != NULL)
  815. {
  816. //
  817. // Setup var bind name of NEXT MIB variable
  818. //
  819. SnmpUtilOidFree( &pVarBind->name );
  820. SnmpUtilOidCpy( &pVarBind->name, &MIB_OidPrefix );
  821. SnmpUtilOidAppend( &pVarBind->name, &pMibPtr->MibNext->Oid );
  822. //
  823. // If the func. ptr is NULL and the type of the mib variable
  824. // is anything but OPAQUE, call function to process the
  825. // MIB variable
  826. //
  827. if (
  828. (pMibPtr->MibNext->MibFunc != NULL)
  829. &&
  830. (pMibPtr->MibNext->Type != ASN_RFC1155_OPAQUE)
  831. )
  832. {
  833. ErrStat = (*pMibPtr->MibNext->MibFunc)( MIB_GETFIRST,
  834. pMibPtr->MibNext, pVarBind );
  835. if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
  836. {
  837. goto Exit;
  838. }
  839. break;
  840. }
  841. else
  842. {
  843. pMibPtr = pMibPtr->MibNext;
  844. }
  845. }
  846. else
  847. {
  848. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  849. break;
  850. }
  851. }
  852. if (pMibPtr == NULL)
  853. {
  854. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  855. }
  856. Exit:
  857. return(ErrStat);
  858. }
  859. UINT
  860. ScopeTable(
  861. IN UINT Action,
  862. IN MIB_ENTRY *MibPtr,
  863. IN RFC1157VarBind *VarBind
  864. )
  865. {
  866. DWORD status;
  867. if (Action == MIB_SET)
  868. {
  869. return(SNMP_ERRORSTATUS_READONLY);
  870. }
  871. //
  872. // if the length indicates a 0 or partial key, then only the get next
  873. // operation is allowed. The field and the full key
  874. // have a length of 5
  875. //
  876. if (VarBind->name.idLength <= (SCOPE_OIDLEN + 4))
  877. {
  878. if ((Action == MIB_GET) || (Action == MIB_SET))
  879. {
  880. return(SNMP_ERRORSTATUS_NOSUCHNAME);
  881. }
  882. }
  883. status = GetMibInfo(LOCAL_ADD, &spMibInfo);
  884. if (status != ERROR_SUCCESS)
  885. {
  886. if (Action == MIB_GETNEXT)
  887. {
  888. return(GetNextVar(VarBind, MibPtr));
  889. }
  890. else
  891. {
  892. return (status == RPC_S_SERVER_UNAVAILABLE) ?
  893. SNMP_ERRORSTATUS_NOSUCHNAME :
  894. SNMP_ERRORSTATUS_GENERR;
  895. }
  896. }
  897. return( MIB_Table(SCOPE_TABLE_INDEX, Action, MibPtr, VarBind) );
  898. }
  899. UINT
  900. MIB_Table(
  901. IN DWORD Index,
  902. IN UINT Action,
  903. IN MIB_ENTRY *MibPtr,
  904. IN RFC1157VarBind *VarBind
  905. )
  906. {
  907. UINT ErrStat;
  908. switch(Action)
  909. {
  910. case(MIB_GET):
  911. ErrStat = (*Tables[Index].ti_get)(VarBind);
  912. break;
  913. case(MIB_GETFIRST):
  914. ErrStat = (*Tables[Index].ti_getf)(VarBind, MibPtr);
  915. break;
  916. case(MIB_GETNEXT):
  917. ErrStat = (*Tables[Index].ti_getn)(VarBind, MibPtr);
  918. break;
  919. case(MIB_SET):
  920. ErrStat = (*Tables[Index].ti_set)(VarBind);
  921. break;
  922. default:
  923. ErrStat = SNMP_ERRORSTATUS_GENERR;
  924. break;
  925. }
  926. return(ErrStat);
  927. } //MIB_Table
  928. UINT
  929. ScopeGet(
  930. IN RFC1157VarBind *VarBind
  931. )
  932. {
  933. UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
  934. DWORD Field;
  935. DWORD Index;
  936. LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
  937. ErrStat = ScopeMatch(VarBind, &Index, &Field, MIB_GET, NULL);
  938. if (ErrStat != SNMP_ERRORSTATUS_NOERROR)
  939. {
  940. return(ErrStat);
  941. }
  942. switch(Field)
  943. {
  944. case 1: //subnet itself
  945. VarBind->value.asnType = ASN_RFC1155_IPADDRESS;
  946. VarBind->value.asnValue.string.length = sizeof(ULONG);
  947. if ( NULL ==
  948. (VarBind->value.asnValue.string.stream =
  949. SnmpUtilMemAlloc(VarBind->value.asnValue.string.length
  950. )) )
  951. {
  952. ErrStat = SNMP_ERRORSTATUS_GENERR;
  953. goto Exit;
  954. }
  955. //
  956. // SNMP expects the MSB to be in the first byte, MSB-1
  957. // to be in the second, ....
  958. //
  959. VarBind->value.asnValue.string.stream[0] =
  960. (BYTE)((pScope + Index)->Subnet >> 24);
  961. VarBind->value.asnValue.string.stream[1] =
  962. (BYTE)(((pScope + Index)->Subnet >> 16) & 0xFF);
  963. VarBind->value.asnValue.string.stream[2] =
  964. (BYTE)(((pScope + Index)->Subnet >> 8) & 0xFF);
  965. VarBind->value.asnValue.string.stream[3] =
  966. (BYTE)((pScope + Index)->Subnet & 0xFF );
  967. VarBind->value.asnValue.address.dynamic = TRUE;
  968. break;
  969. case 2: // NumAddressesInUse
  970. VarBind->value.asnType = ASN_RFC1155_COUNTER;
  971. VarBind->value.asnValue.number =
  972. (AsnCounter)((pScope + Index)->
  973. NumAddressesInuse);
  974. break;
  975. case 3: // NumAddressesFree
  976. VarBind->value.asnType = ASN_RFC1155_COUNTER;
  977. VarBind->value.asnValue.number =
  978. (AsnCounter)((pScope + Index)->
  979. NumAddressesFree);
  980. break;
  981. case 4: // NumPendingOffers
  982. VarBind->value.asnType = ASN_RFC1155_COUNTER;
  983. VarBind->value.asnValue.number =
  984. (AsnCounter)((pScope + Index)->
  985. NumPendingOffers);
  986. break;
  987. default:
  988. ErrStat = SNMP_ERRORSTATUS_BADVALUE;
  989. break;
  990. }
  991. Exit:
  992. return(ErrStat);
  993. } // ScopeGet
  994. UINT
  995. ScopeGetNext(
  996. IN RFC1157VarBind *VarBind,
  997. IN MIB_ENTRY *MibPtr
  998. )
  999. {
  1000. DWORD OidIndex;
  1001. INT Index;
  1002. DWORD FieldNo;
  1003. UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
  1004. BOOL fFirst;
  1005. LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
  1006. //
  1007. // Check if the name passed matches any in the table (i.e. table of
  1008. // of ADD_KEY_T structures. If there is a match, the address
  1009. // of the ip address key and the matching field's no. are returned
  1010. //
  1011. ErrStat = ScopeMatch(VarBind, &Index, &FieldNo, MIB_GETNEXT, &fFirst);
  1012. if (
  1013. (ErrStat != SNMP_ERRORSTATUS_NOERROR)
  1014. &&
  1015. (ErrStat != SNMP_ERRORSTATUS_NOSUCHNAME)
  1016. )
  1017. {
  1018. return(GetNextVar(VarBind, MibPtr));
  1019. }
  1020. //
  1021. // We were passed an oid that is less than all oids in the table. Set
  1022. // the Index to -1 so that we retrieve the first record in the table
  1023. //
  1024. if (fFirst)
  1025. {
  1026. Index = -1;
  1027. }
  1028. //
  1029. // Since the operation is GETNEXT, get the next IP address (i.e. one
  1030. // that is lexicographically bigger. If there is none, we must increment
  1031. // the field value and move back to the lexically first item in the table
  1032. // If the new field value is more than the largest supported, we call
  1033. // the MibFunc of the next MIB entry.
  1034. //
  1035. if ((Index = ScopeFindNext(Index)) < 0)
  1036. {
  1037. //
  1038. // if we were trying to retrieve the second or subsequent record
  1039. // we must increment the field number nd get the first record in
  1040. // the table. If we were retrieving the first record, then
  1041. // we should get the next var.
  1042. //
  1043. if (!fFirst)
  1044. {
  1045. Index = ScopeFindNext(-1);
  1046. }
  1047. else
  1048. {
  1049. return(GetNextVar(VarBind, MibPtr));
  1050. }
  1051. //
  1052. // If either there is no entry in the table or if we have
  1053. // exhausted all fields of the entry, call the function
  1054. // of the next mib entry.
  1055. //
  1056. if (
  1057. (++FieldNo > NO_FLDS_IN_SCOPE_ROW) || (Index < 0)
  1058. )
  1059. {
  1060. return(GetNextVar(VarBind, MibPtr));
  1061. }
  1062. }
  1063. if (VarBind->name.idLength <= (SCOPE_OIDLEN + 4))
  1064. {
  1065. UINT TableEntryIds[5]; //field and subnet mask have a length of 5
  1066. AsnObjectIdentifier TableEntryOid = {OID_SIZEOF(TableEntryIds),
  1067. TableEntryIds };
  1068. SnmpUtilOidFree( &VarBind->name);
  1069. SnmpUtilOidCpy(&VarBind->name, &MIB_OidPrefix);
  1070. SnmpUtilOidAppend(&VarBind->name, &MibPtr->Oid);
  1071. TableEntryIds[0] = (UINT)FieldNo;
  1072. OidIndex = 1;
  1073. TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 24);
  1074. TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 16 & 0xFF);
  1075. TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 8 & 0xFF);
  1076. TableEntryIds[OidIndex++] = (UINT)((pScope + Index)->Subnet & 0xFF);
  1077. TableEntryOid.idLength = OidIndex;
  1078. SnmpUtilOidAppend(&VarBind->name, &TableEntryOid);
  1079. }
  1080. else
  1081. {
  1082. //
  1083. // The fixed part of the objid is corect. Update the rest.
  1084. //
  1085. OidIndex = SCOPE_OIDLEN;
  1086. VarBind->name.ids[OidIndex++] = (UINT)FieldNo;
  1087. VarBind->name.ids[OidIndex++] = (UINT)((pScope + Index)->Subnet >> 24);
  1088. VarBind->name.ids[OidIndex++] = (UINT)(((pScope + Index)->Subnet >> 16) & 0xFF);
  1089. VarBind->name.ids[OidIndex++] = (UINT)(((pScope + Index)->Subnet >> 8) & 0xFF);
  1090. VarBind->name.ids[OidIndex++] = (UINT)((pScope + Index)->Subnet & 0xFF);
  1091. VarBind->name.idLength = OidIndex;
  1092. }
  1093. //
  1094. // Get the value
  1095. //
  1096. ErrStat = ScopeGet(VarBind);
  1097. return(ErrStat);
  1098. }
  1099. UINT
  1100. ScopeMatch(
  1101. IN RFC1157VarBind *VarBind,
  1102. IN LPDWORD pIndex,
  1103. IN LPDWORD pField,
  1104. IN UINT PduAction,
  1105. IN LPBOOL pfFirst
  1106. )
  1107. {
  1108. DWORD OidIndex;
  1109. DWORD Index;
  1110. DWORD ScopeIndex;
  1111. DWORD Add = 0;
  1112. UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
  1113. INT CmpVal;
  1114. DWORD AddLen;
  1115. LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
  1116. ASSERT(PduAction != MIB_SET);
  1117. if (pfFirst != NULL)
  1118. {
  1119. *pfFirst = FALSE;
  1120. }
  1121. //
  1122. // If there are no keys, return error
  1123. //
  1124. if (spMibInfo->Scopes == 0)
  1125. {
  1126. if (PduAction == MIB_GETNEXT)
  1127. {
  1128. *pfFirst = TRUE;
  1129. }
  1130. else
  1131. {
  1132. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  1133. }
  1134. goto Exit;
  1135. }
  1136. //
  1137. // fixed part of the PullPnr table entries
  1138. //
  1139. OidIndex = SCOPE_OIDLEN;
  1140. //
  1141. // if the field specified is more than the max. in the table entry
  1142. // barf
  1143. //
  1144. if (
  1145. (*pField = VarBind->name.ids[OidIndex++]) >
  1146. (DWORD)NO_FLDS_IN_SCOPE_ROW
  1147. )
  1148. {
  1149. if (PduAction == MIB_GETNEXT)
  1150. {
  1151. *pIndex = spMibInfo->Scopes - 1;
  1152. goto Exit;
  1153. }
  1154. else
  1155. {
  1156. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  1157. goto Exit;
  1158. }
  1159. }
  1160. //
  1161. // get the length of key specified
  1162. //
  1163. AddLen = VarBind->name.idLength - (SCOPE_OIDLEN + 1);
  1164. ScopeIndex = OidIndex;
  1165. for (Index = 0; Index < AddLen; Index++)
  1166. {
  1167. Add = Add | (((BYTE)(VarBind->name.ids[ScopeIndex++])) << (24 - (Index * 8)));
  1168. }
  1169. //
  1170. // Check if the address specified matches with one of the keys
  1171. //
  1172. for (Index = 0; Index < spMibInfo->Scopes; Index++, pScope++)
  1173. {
  1174. if (Add == pScope->Subnet)
  1175. {
  1176. *pIndex = Index;
  1177. return(SNMP_ERRORSTATUS_NOERROR);
  1178. }
  1179. else
  1180. {
  1181. //
  1182. // if passed in value is greater, continue on to
  1183. // the next item. The list is in ascending order
  1184. //
  1185. if (Add > pScope->Subnet)
  1186. {
  1187. continue;
  1188. }
  1189. else
  1190. {
  1191. //
  1192. // the list element is > passed in value,
  1193. // break out of the loop
  1194. //
  1195. break;
  1196. }
  1197. }
  1198. }
  1199. //
  1200. // if no match, but field is GetNext, return the (highest index - 1)
  1201. // reached above. This is because, ScopeFindNext will be called by
  1202. // the caller
  1203. //
  1204. if (PduAction == MIB_GETNEXT)
  1205. {
  1206. if (Index == 0)
  1207. {
  1208. *pfFirst = TRUE;
  1209. }
  1210. else
  1211. {
  1212. *pIndex = Index - 1;
  1213. }
  1214. ErrStat = SNMP_ERRORSTATUS_NOERROR;
  1215. }
  1216. else
  1217. {
  1218. ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
  1219. }
  1220. Exit:
  1221. return(ErrStat);
  1222. }
  1223. UINT
  1224. ScopeFindNext(
  1225. INT SubKeyIndex
  1226. )
  1227. {
  1228. DWORD i;
  1229. LONG nextif;
  1230. LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
  1231. //
  1232. // if SubKeyIndex is 0 or more, search for the key next to
  1233. // the key passed.
  1234. //
  1235. for (nextif = -1, i = 0 ; i < spMibInfo->Scopes; i++)
  1236. {
  1237. if (SubKeyIndex >= 0)
  1238. {
  1239. if (
  1240. (pScope + i)->Subnet <=
  1241. (pScope + SubKeyIndex)->Subnet
  1242. )
  1243. {
  1244. //
  1245. // This item is lexicographically less or equal,
  1246. // continue
  1247. //
  1248. continue;
  1249. }
  1250. else
  1251. {
  1252. //
  1253. // We found an item that is > than the item indicated
  1254. // to us. Break out of the loop
  1255. //
  1256. nextif = i;
  1257. break;
  1258. }
  1259. }
  1260. else
  1261. {
  1262. #if 0
  1263. //
  1264. // if we want the first entry, then continue until
  1265. // we get an entry that is lexicographically same or
  1266. // greater
  1267. //
  1268. if (
  1269. (nextif < 0)
  1270. ||
  1271. (pScope + (i - 1))->Subnet < (pScope + nextif)->Subnet
  1272. )
  1273. {
  1274. nextif = i;
  1275. }
  1276. #endif
  1277. nextif = 0;
  1278. break;
  1279. }
  1280. }
  1281. return(nextif);
  1282. }
  1283. UINT
  1284. ScopeGetFirst(
  1285. IN RFC1157VarBind *VarBind,
  1286. IN MIB_ENTRY *MibPtr
  1287. )
  1288. {
  1289. LPSCOPE_MIB_INFO pScope = spMibInfo->ScopeInfo;
  1290. INT Iface;
  1291. UINT TableEntryIds[5];
  1292. AsnObjectIdentifier TableEntryOid = { OID_SIZEOF(TableEntryIds),
  1293. TableEntryIds };
  1294. UINT ErrStat;
  1295. //
  1296. // If there is no entry in the table, go to the next MIB variable
  1297. //
  1298. if (spMibInfo->Scopes == 0)
  1299. {
  1300. return(GetNextVar(VarBind, MibPtr));
  1301. }
  1302. //
  1303. // Get the first entry in the table
  1304. //
  1305. Iface = ScopeFindNext(-1);
  1306. //
  1307. // Write the object Id into the binding list and call get
  1308. // func
  1309. //
  1310. SnmpUtilOidFree( &VarBind->name );
  1311. SnmpUtilOidCpy( &VarBind->name, &MIB_OidPrefix );
  1312. SnmpUtilOidAppend( &VarBind->name, &MibPtr->Oid );
  1313. //
  1314. // The fixed part of the objid is correct. Update the rest.
  1315. //
  1316. TableEntryIds[0] = 1;
  1317. TableEntryIds[1] = (UINT)((pScope + Iface)->Subnet >> 24);
  1318. TableEntryIds[2] = (UINT)(((pScope + Iface)->Subnet >> 16) & 0xFF);
  1319. TableEntryIds[3] = (UINT)(((pScope + Iface)->Subnet >> 8) & 0xFF);
  1320. TableEntryIds[4] = (UINT)((pScope + Iface)->Subnet & 0xFF);
  1321. SnmpUtilOidAppend( &VarBind->name, &TableEntryOid );
  1322. ErrStat = ScopeGet(VarBind);
  1323. return(ErrStat);
  1324. }