Source code of Windows XP (NT5)
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.

1551 lines
37 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. Contains routines for querying subagents.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Feb-1997 DonRyan
  11. Rewrote to implement SNMPv2 support.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. #include "varbinds.h"
  20. #include "network.h"
  21. #include "query.h"
  22. #include "snmpmgmt.h"
  23. ///////////////////////////////////////////////////////////////////////////////
  24. // //
  25. // Private procedures //
  26. // //
  27. ///////////////////////////////////////////////////////////////////////////////
  28. BOOL
  29. FindQueryBySLE(
  30. PQUERY_LIST_ENTRY * ppQLE,
  31. PNETWORK_LIST_ENTRY pNLE,
  32. PSUBAGENT_LIST_ENTRY pSLE
  33. )
  34. /*++
  35. Routine Description:
  36. Allocates query list entry.
  37. Arguments:
  38. ppQLE - pointer to receive query entry pointer.
  39. pNLE - pointer to network list entry.
  40. pSLE - pointer to subagent list entry.
  41. Return Values:
  42. Returns true if successful.
  43. --*/
  44. {
  45. PLIST_ENTRY pLE;
  46. PQUERY_LIST_ENTRY pQLE = NULL;
  47. // point to first query
  48. pLE = pNLE->Queries.Flink;
  49. // process each query
  50. while (pLE != &pNLE->Queries) {
  51. // retrieve pointer to query entry from link
  52. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  53. // compare subagents
  54. if (pQLE->pSLE == pSLE) {
  55. // transfer
  56. *ppQLE = pQLE;
  57. // success
  58. return TRUE;
  59. }
  60. // next entry
  61. pLE = pLE->Flink;
  62. }
  63. // initialize
  64. *ppQLE = NULL;
  65. // failure
  66. return FALSE;
  67. }
  68. BOOL
  69. LoadSubagentData(
  70. PNETWORK_LIST_ENTRY pNLE,
  71. PQUERY_LIST_ENTRY pQLE
  72. )
  73. /*++
  74. Routine Description:
  75. Loads data to be passed to the subagent DLL.
  76. Arguments:
  77. pNLE - pointer to network list entry.
  78. pQLE - pointer to current query.
  79. Return Values:
  80. Returns true if successful.
  81. --*/
  82. {
  83. PLIST_ENTRY pLE;
  84. PVARBIND_LIST_ENTRY pVLE;
  85. SNMPDBG((
  86. SNMP_LOG_VERBOSE,
  87. "SNMP: SVC: query 0x%08lx loading.\n", pQLE
  88. ));
  89. // attempt to allocate varbind list
  90. pQLE->SubagentVbl.list = SnmpUtilMemAlloc(
  91. pQLE->nSubagentVbs * sizeof(SnmpVarBind)
  92. );
  93. // validate varbind list pointer
  94. if (pQLE->SubagentVbl.list != NULL) {
  95. // point to first varbind
  96. pLE = pQLE->SubagentVbs.Flink;
  97. // process each outgoing varbind
  98. while (pLE != &pQLE->SubagentVbs) {
  99. // retrieve pointer to varbind entry from query link
  100. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  101. // transfer varbind
  102. SnmpUtilVarBindCpy(
  103. &pQLE->SubagentVbl.list[pQLE->SubagentVbl.len++],
  104. &pVLE->ResolvedVb
  105. );
  106. SNMPDBG((
  107. SNMP_LOG_VERBOSE,
  108. "SNMP: SVC: variable %d copied to query 0x%08lx.\n",
  109. pVLE->nErrorIndex,
  110. pQLE
  111. ));
  112. // next entry
  113. pLE = pLE->Flink;
  114. }
  115. // create copy of context in case subagent mucks with it
  116. SnmpUtilOctetsCpy(&pQLE->ContextInfo, &pNLE->Community);
  117. } else {
  118. SNMPDBG((
  119. SNMP_LOG_ERROR,
  120. "SNMP: SVC: could not allocate varbind list.\n"
  121. ));
  122. // failure
  123. return FALSE;
  124. }
  125. // success
  126. return TRUE;
  127. }
  128. BOOL
  129. UnloadSubagentData(
  130. PQUERY_LIST_ENTRY pQLE
  131. )
  132. /*++
  133. Routine Description:
  134. Unloads data passed to the subagent DLL.
  135. Arguments:
  136. pQLE - pointer to current query.
  137. Return Values:
  138. Returns true if successful.
  139. --*/
  140. {
  141. __try {
  142. // release subagent varbind list
  143. SnmpUtilVarBindListFree(&pQLE->SubagentVbl);
  144. // release subagent context information
  145. SnmpUtilOctetsFree(&pQLE->ContextInfo);
  146. } __except (EXCEPTION_EXECUTE_HANDLER) {
  147. SNMPDBG((
  148. SNMP_LOG_ERROR,
  149. "SNMP: SVC: exception 0x%08lx processing structure from %s.\n",
  150. GetExceptionCode(),
  151. (pQLE->pSLE != NULL)
  152. ? pQLE->pSLE->pPathname
  153. : "<unknown>"
  154. ));
  155. // failure
  156. return FALSE;
  157. }
  158. // success
  159. return TRUE;
  160. }
  161. BOOL
  162. UpdateResolvedVarBind(
  163. PQUERY_LIST_ENTRY pQLE,
  164. PVARBIND_LIST_ENTRY pVLE,
  165. UINT iVb
  166. )
  167. /*++
  168. Routine Description:
  169. Updates resolved varbind with data from subagent DLL.
  170. Arguments:
  171. pQLE - pointer to current query.
  172. pVLE - pointer to varbind.
  173. iVb - index of varbind.
  174. Return Values:
  175. Returns true if successful.
  176. --*/
  177. {
  178. // see if this is non-repeater
  179. if (pVLE->nMaxRepetitions == 1) {
  180. // flag varbind as resolved
  181. pVLE->nState = VARBIND_RESOLVED;
  182. // release memory for current varbind
  183. SnmpUtilVarBindFree(&pVLE->ResolvedVb);
  184. // transfer varbind from subagent
  185. SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
  186. &pQLE->SubagentVbl.list[iVb]
  187. );
  188. SNMPDBG((
  189. SNMP_LOG_VERBOSE,
  190. "SNMP: SVC: variable %d name %s.\n",
  191. pVLE->nErrorIndex,
  192. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  193. ));
  194. SNMPDBG((
  195. SNMP_LOG_VERBOSE,
  196. "SNMP: SVC: variable %d state '%s'.\n",
  197. pVLE->nErrorIndex,
  198. VARBINDSTATESTRING(pVLE->nState)
  199. ));
  200. // success
  201. return TRUE;
  202. }
  203. // see if varbind list allocated
  204. if ((pVLE->ResolvedVbl.len == 0) &&
  205. (pVLE->ResolvedVbl.list == NULL)) {
  206. // allocate varbind list to fill in
  207. pVLE->ResolvedVbl.list = SnmpUtilMemAlloc(
  208. pVLE->nMaxRepetitions *
  209. sizeof(SnmpVarBind)
  210. );
  211. // validate pointer before continuing
  212. if (pVLE->ResolvedVbl.list == NULL) {
  213. SNMPDBG((
  214. SNMP_LOG_ERROR,
  215. "SNMP: SVC: could not allocate new varbinds.\n"
  216. ));
  217. // failure
  218. return FALSE;
  219. }
  220. }
  221. // release working varbind name
  222. SnmpUtilOidFree(&pVLE->ResolvedVb.name);
  223. // transfer name for next iteration
  224. SnmpUtilOidCpy(&pVLE->ResolvedVb.name,
  225. &pQLE->SubagentVbl.list[iVb].name
  226. );
  227. // transfer varbind
  228. SnmpUtilVarBindCpy(
  229. &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len],
  230. &pQLE->SubagentVbl.list[iVb]
  231. );
  232. // increment count
  233. pVLE->ResolvedVbl.len++;
  234. // see if this is the last varbind to retrieve
  235. pVLE->nState = (pVLE->nMaxRepetitions > pVLE->ResolvedVbl.len)
  236. ? VARBIND_PARTIALLY_RESOLVED
  237. : VARBIND_RESOLVED
  238. ;
  239. SNMPDBG((
  240. SNMP_LOG_VERBOSE,
  241. "SNMP: SVC: variable %d name %s.\n",
  242. pVLE->nErrorIndex,
  243. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  244. ));
  245. SNMPDBG((
  246. SNMP_LOG_VERBOSE,
  247. "SNMP: SVC: variable %d state '%s'.\n",
  248. pVLE->nErrorIndex,
  249. VARBINDSTATESTRING(pVLE->nState)
  250. ));
  251. // success
  252. return TRUE;
  253. }
  254. BOOL
  255. UpdateVarBind(
  256. PNETWORK_LIST_ENTRY pNLE,
  257. PQUERY_LIST_ENTRY pQLE,
  258. PVARBIND_LIST_ENTRY pVLE,
  259. UINT iVb
  260. )
  261. /*++
  262. Routine Description:
  263. Updates varbind with data from subagent DLL.
  264. Arguments:
  265. pNLE - pointer to network list entry.
  266. pQLE - pointer to current query.
  267. pVLE - pointer to varbind.
  268. iVb - index of varbind.
  269. Return Values:
  270. Returns true if successful.
  271. --*/
  272. {
  273. PLIST_ENTRY pLE;
  274. INT nDiff1;
  275. INT nDiff2;
  276. __try {
  277. // determine order of returned varbind
  278. nDiff1 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name,
  279. &pVLE->ResolvedVb.name
  280. );
  281. // see if this is getnext or getbulk
  282. if ((pNLE->Pdu.nType == SNMP_PDU_GETNEXT) ||
  283. (pNLE->Pdu.nType == SNMP_PDU_GETBULK)) {
  284. // determine whether returned varbind in range
  285. nDiff2 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name,
  286. &pVLE->pCurrentRLE->LimitOid
  287. );
  288. // make sure returned oid in range
  289. if ((nDiff1 > 0) && (nDiff2 < 0)) {
  290. // update resolved variable binding
  291. return UpdateResolvedVarBind(pQLE, pVLE, iVb);
  292. } else if (nDiff2 >= 0) {
  293. SNMPDBG((
  294. SNMP_LOG_VERBOSE,
  295. "SNMP: SVC: %s received getnext request for %s.\n",
  296. pQLE->pSLE->pPathname,
  297. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  298. ));
  299. SNMPDBG((
  300. SNMP_LOG_VERBOSE,
  301. "SNMP: SVC: %s returned out-of-range oid %s.\n",
  302. pQLE->pSLE->pPathname,
  303. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  304. ));
  305. // retrieve pointer to next region
  306. pLE = pVLE->pCurrentRLE->Link.Flink;
  307. // see if we exhausted regions
  308. if (pLE != &g_SupportedRegions) {
  309. PMIB_REGION_LIST_ENTRY pNextRLE;
  310. // retrieve pointer to mib region
  311. pNextRLE = CONTAINING_RECORD(pLE,
  312. MIB_REGION_LIST_ENTRY,
  313. Link
  314. );
  315. // see if next region supported by same subagent
  316. if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE) {
  317. BOOL retCode;
  318. SNMPDBG((
  319. SNMP_LOG_TRACE,
  320. "SNMP: SVC: next region also supported by %s.\n",
  321. pVLE->pCurrentRLE->pSLE->pPathname
  322. ));
  323. // update resolved variable binding
  324. retCode = UpdateResolvedVarBind(pQLE, pVLE, iVb);
  325. if (pQLE->SubagentVbl.list[iVb].value.asnType != ASN_NULL)
  326. {
  327. return retCode;
  328. }
  329. }
  330. // point to next region
  331. pVLE->pCurrentRLE = pNextRLE;
  332. // change state to partially resolved
  333. pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
  334. SNMPDBG((
  335. SNMP_LOG_VERBOSE,
  336. "SNMP: SVC: variable %d state '%s'.\n",
  337. pVLE->nErrorIndex,
  338. VARBINDSTATESTRING(pVLE->nState)
  339. ));
  340. SNMPDBG((
  341. SNMP_LOG_TRACE,
  342. "SNMP: SVC: variable %d re-assigned to %s.\n",
  343. pVLE->nErrorIndex,
  344. pVLE->pCurrentRLE->pSLE->pPathname
  345. ));
  346. }
  347. else if ((pVLE->ResolvedVbl.len == 0) &&
  348. (pVLE->ResolvedVbl.list == NULL)) {
  349. // flag varbind as resolved
  350. pVLE->nState = VARBIND_RESOLVED;
  351. // set default varbind to eomv
  352. pVLE->ResolvedVb.value.asnType =
  353. SNMP_EXCEPTION_ENDOFMIBVIEW;
  354. // update error status counter for the operation
  355. mgmtCTick(CsnmpOutNoSuchNames);
  356. SNMPDBG((
  357. SNMP_LOG_VERBOSE,
  358. "SNMP: SVC: variable %d state '%s'.\n",
  359. pVLE->nErrorIndex,
  360. VARBINDSTATESTRING(pVLE->nState)
  361. ));
  362. } else {
  363. // flag varbind as resolved
  364. pVLE->nState = VARBIND_RESOLVED;
  365. // transfer name
  366. SnmpUtilOidCpy(
  367. &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].name,
  368. &pVLE->ResolvedVb.name
  369. );
  370. // set current varbind to eomv
  371. pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].value.asnType =
  372. SNMP_EXCEPTION_ENDOFMIBVIEW;
  373. // increment count
  374. pVLE->ResolvedVbl.len++;
  375. // update error status counter for the operation
  376. mgmtCTick(CsnmpOutNoSuchNames);
  377. SNMPDBG((
  378. SNMP_LOG_VERBOSE,
  379. "SNMP: SVC: variable %d state '%s'.\n",
  380. pVLE->nErrorIndex,
  381. VARBINDSTATESTRING(pVLE->nState)
  382. ));
  383. }
  384. } else {
  385. SNMPDBG((
  386. SNMP_LOG_ERROR,
  387. "SNMP: SVC: %s received getnext request for %s.\n",
  388. pQLE->pSLE->pPathname,
  389. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  390. ));
  391. SNMPDBG((
  392. SNMP_LOG_ERROR,
  393. "SNMP: SVC: %s returned invalid oid %s.\n",
  394. pQLE->pSLE->pPathname,
  395. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  396. ));
  397. SNMPDBG((
  398. SNMP_LOG_ERROR,
  399. "SNMP: SVC: Ban %s subagent, forward the request to a different one.\n",
  400. pQLE->pSLE->pPathname
  401. ));
  402. // trying to forward this getnext request to the next region but only if not handled
  403. // by the same subagent!
  404. pLE = pVLE->pCurrentRLE->Link.Flink;
  405. while( pLE != &g_SupportedRegions)
  406. {
  407. PMIB_REGION_LIST_ENTRY pNextRLE;
  408. // retrieve pointer to mib region
  409. pNextRLE = CONTAINING_RECORD(pLE,
  410. MIB_REGION_LIST_ENTRY,
  411. Link
  412. );
  413. // if this 'next' region is handled by the same subagent, skip to the next!
  414. if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE)
  415. {
  416. pLE = pNextRLE->Link.Flink;
  417. continue;
  418. }
  419. // ok, we have one, forward the original GetNext request to it
  420. pVLE->pCurrentRLE = pNextRLE;
  421. pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
  422. SNMPDBG((
  423. SNMP_LOG_TRACE,
  424. "SNMP: SVC: variable %d re-assigned to %s.\n",
  425. pVLE->nErrorIndex,
  426. pVLE->pCurrentRLE->pSLE->pPathname
  427. ));
  428. return TRUE;
  429. }
  430. // failure
  431. // here I should emulate a (NO_SUCH_NAME) EndOfMibView, resolve the variable and return TRUE.
  432. pVLE->nState = VARBIND_RESOLVED;
  433. pVLE->ResolvedVb.value.asnType = SNMP_EXCEPTION_ENDOFMIBVIEW;
  434. pVLE->pCurrentRLE = NULL;
  435. // update error status counter
  436. mgmtCTick(CsnmpOutNoSuchNames);
  437. return TRUE;
  438. }
  439. } else if (pNLE->Pdu.nType == SNMP_PDU_GET) {
  440. // must match
  441. if (nDiff1 == 0) {
  442. // flag varbind as resolved
  443. pVLE->nState = VARBIND_RESOLVED;
  444. // release memory for current varbind
  445. SnmpUtilVarBindFree(&pVLE->ResolvedVb);
  446. // transfer varbind from subagent
  447. SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
  448. &pQLE->SubagentVbl.list[iVb]
  449. );
  450. SNMPDBG((
  451. SNMP_LOG_VERBOSE,
  452. "SNMP: SVC: variable %d name %s.\n",
  453. pVLE->nErrorIndex,
  454. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  455. ));
  456. SNMPDBG((
  457. SNMP_LOG_VERBOSE,
  458. "SNMP: SVC: variable %d state '%s'.\n",
  459. pVLE->nErrorIndex,
  460. VARBINDSTATESTRING(pVLE->nState)
  461. ));
  462. } else {
  463. SNMPDBG((
  464. SNMP_LOG_ERROR,
  465. "SNMP: SVC: %s received get request for %s.\n",
  466. pQLE->pSLE->pPathname,
  467. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  468. ));
  469. SNMPDBG((
  470. SNMP_LOG_ERROR,
  471. "SNMP: SVC: %s returned invalid oid %s.\n",
  472. pQLE->pSLE->pPathname,
  473. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  474. ));
  475. // failure
  476. return FALSE;
  477. }
  478. } else if (nDiff1 != 0) {
  479. // set request failed -> invalid oid
  480. SNMPDBG((
  481. SNMP_LOG_ERROR,
  482. "SNMP: SVC: %s received set request for %s.\n",
  483. pQLE->pSLE->pPathname,
  484. SnmpUtilOidToA(&pVLE->ResolvedVb.name)
  485. ));
  486. SNMPDBG((
  487. SNMP_LOG_ERROR,
  488. "SNMP: SVC: %s returned invalid oid %s.\n",
  489. pQLE->pSLE->pPathname,
  490. SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name)
  491. ));
  492. // failure
  493. return FALSE;
  494. } else {
  495. // set request, oids match
  496. // WARNING!! - state might be set prematurely on SET_TEST / SET_CLEANUP
  497. pVLE->nState = VARBIND_RESOLVED;
  498. return TRUE;
  499. }
  500. } __except (EXCEPTION_EXECUTE_HANDLER) {
  501. SNMPDBG((
  502. SNMP_LOG_ERROR,
  503. "SNMP: SVC: exception 0x%08lx processing structure from %s.\n",
  504. GetExceptionCode(),
  505. pQLE->pSLE->pPathname
  506. ));
  507. // failure
  508. return FALSE;
  509. }
  510. // success
  511. return TRUE;
  512. }
  513. BOOL
  514. UpdateVarBinds(
  515. PNETWORK_LIST_ENTRY pNLE,
  516. PQUERY_LIST_ENTRY pQLE
  517. )
  518. /*++
  519. Routine Description:
  520. Updates varbind list entries with data from subagent DLL.
  521. Arguments:
  522. pNLE - pointer to network list entry.
  523. pQLE - pointer to current query.
  524. Return Values:
  525. Returns true if successful.
  526. --*/
  527. {
  528. PLIST_ENTRY pLE;
  529. PVARBIND_LIST_ENTRY pVLE;
  530. BOOL fOk = TRUE;
  531. UINT iVb = 0;
  532. // point to first varbind
  533. pLE = pQLE->SubagentVbs.Flink;
  534. // see if error encountered during callback
  535. if (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR) {
  536. // process each outgoing varbind
  537. while (pLE != &pQLE->SubagentVbs) {
  538. // retrieve pointer to varbind entry from query link
  539. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  540. // update individual varbind
  541. if (!UpdateVarBind(pNLE, pQLE, pVLE, iVb++)) {
  542. SNMPDBG((
  543. SNMP_LOG_ERROR,
  544. "SNMP: SVC: variable %d could not be updated.\n",
  545. pQLE->nErrorIndex
  546. ));
  547. // update pdu with the proper varbind error index
  548. pNLE->Pdu.Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_GENERR;
  549. pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
  550. // failure
  551. return FALSE;
  552. }
  553. // next entry
  554. pLE = pLE->Flink;
  555. }
  556. } else {
  557. SNMPDBG((
  558. SNMP_LOG_VERBOSE,
  559. "SNMP: SVC: searching for errant variable.\n"
  560. ));
  561. // update pdu with status returned from subagent
  562. pNLE->Pdu.Pdu.NormPdu.nErrorStatus = pQLE->nErrorStatus;
  563. // process each outgoing varbind
  564. while (pLE != &pQLE->SubagentVbs) {
  565. // retrieve pointer to varbind entry from query link
  566. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
  567. // see if errant varbind nErrorIndex is starts from 1 !!
  568. if (pQLE->nErrorIndex == ++iVb) {
  569. SNMPDBG((
  570. SNMP_LOG_TRACE,
  571. "SNMP: SVC: variable %d involved in failure.\n",
  572. pVLE->nErrorIndex
  573. ));
  574. // update pdu with the proper varbind error index
  575. pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
  576. // the error code was successfully identified
  577. return TRUE;
  578. }
  579. // next entry
  580. pLE = pLE->Flink;
  581. }
  582. SNMPDBG((
  583. SNMP_LOG_TRACE,
  584. "SNMP: SVC: no variable involved in failure.\n"
  585. ));
  586. // failure
  587. return FALSE;
  588. }
  589. // success
  590. return TRUE;
  591. }
  592. BOOL
  593. CallSubagent(
  594. PQUERY_LIST_ENTRY pQLE,
  595. UINT nRequestType,
  596. UINT nTransactionId
  597. )
  598. /*++
  599. Routine Description:
  600. Invokes method from subagent DLL.
  601. Arguments:
  602. pNLE - pointer to network list entry.
  603. nRequestType - type of request to post to subagent.
  604. nTransactionId - identifies snmp pdu sent from manager.
  605. Return Values:
  606. Returns true if successful.
  607. --*/
  608. {
  609. BOOL fOk = FALSE;
  610. SNMPDBG((
  611. SNMP_LOG_VERBOSE,
  612. "SNMP: SVC: --- query %s begin ---\n",
  613. pQLE->pSLE->pPathname
  614. ));
  615. __try {
  616. // determine which version of query supported
  617. if (pQLE->pSLE->pfnSnmpExtensionQueryEx != NULL) {
  618. // process query using new interface
  619. fOk = (*pQLE->pSLE->pfnSnmpExtensionQueryEx)(
  620. nRequestType,
  621. nTransactionId,
  622. &pQLE->SubagentVbl,
  623. &pQLE->ContextInfo,
  624. &pQLE->nErrorStatus,
  625. &pQLE->nErrorIndex
  626. );
  627. // see if query is actually valid for downlevel call
  628. } else if ((pQLE->pSLE->pfnSnmpExtensionQuery != NULL) &&
  629. ((nRequestType == SNMP_EXTENSION_GET) ||
  630. (nRequestType == SNMP_EXTENSION_GET_NEXT) ||
  631. (nRequestType == SNMP_EXTENSION_SET_COMMIT))) {
  632. // process query using old interface
  633. fOk = (*pQLE->pSLE->pfnSnmpExtensionQuery)(
  634. (BYTE)(UINT)nRequestType,
  635. &pQLE->SubagentVbl,
  636. &pQLE->nErrorStatus,
  637. &pQLE->nErrorIndex
  638. );
  639. // see if query can be completed successfully anyway
  640. } else if ((nRequestType == SNMP_EXTENSION_SET_TEST) ||
  641. (nRequestType == SNMP_EXTENSION_SET_CLEANUP)) {
  642. // fake it
  643. fOk = TRUE;
  644. }
  645. } __except (EXCEPTION_EXECUTE_HANDLER) {
  646. SNMPDBG((
  647. SNMP_LOG_ERROR,
  648. "SNMP: SVC: exception 0x%08lx calling %s.\n",
  649. GetExceptionCode(),
  650. pQLE->pSLE->pPathname
  651. ));
  652. }
  653. SNMPDBG((
  654. SNMP_LOG_VERBOSE,
  655. "SNMP: SVC: --- query %s end ---\n",
  656. pQLE->pSLE->pPathname
  657. ));
  658. // validate
  659. if (!fOk) {
  660. // identify failing subagent
  661. pQLE->nErrorStatus = SNMP_ERRORSTATUS_GENERR;
  662. pQLE->nErrorIndex = 1;
  663. } else if (pQLE->nErrorStatus != SNMP_ERRORSTATUS_NOERROR) {
  664. // see if error index needs to be adjusted
  665. if ((pQLE->nErrorIndex > pQLE->nSubagentVbs) ||
  666. (pQLE->nErrorIndex == 0)) {
  667. // set to first varbind
  668. pQLE->nErrorIndex = 1;
  669. }
  670. } else {
  671. // re-initialize
  672. pQLE->nErrorIndex = 0;
  673. }
  674. SNMPDBG((
  675. SNMP_LOG_VERBOSE,
  676. "SNMP: SVC: query 0x%08lx %s, errorStatus=%s, errorIndex=%d.\n",
  677. pQLE,
  678. (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR)
  679. ? "succeeded"
  680. : "failed"
  681. ,
  682. SNMPERRORSTRING(pQLE->nErrorStatus),
  683. pQLE->nErrorIndex
  684. ));
  685. return TRUE;
  686. }
  687. BOOL
  688. ProcessSet(
  689. PNETWORK_LIST_ENTRY pNLE
  690. )
  691. /*++
  692. Routine Description:
  693. Processes SNMP_PDU_SET requests.
  694. Arguments:
  695. pNLE - pointer to network list entry.
  696. Return Values:
  697. Returns true if successful.
  698. --*/
  699. {
  700. PLIST_ENTRY pLE = NULL;
  701. PQUERY_LIST_ENTRY pQLE;
  702. BOOL fOk = TRUE;
  703. // load subagent queries
  704. if (!LoadQueries(pNLE)) {
  705. // unload immediately
  706. UnloadQueries(pNLE);
  707. // failure
  708. return FALSE;
  709. }
  710. // point to first query
  711. pLE = pNLE->Queries.Flink;
  712. // process each subagent query
  713. while (fOk && (pLE != &pNLE->Queries)) {
  714. // retrieve pointer to query entry from link
  715. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  716. // load outgoing varbinds
  717. fOk = LoadSubagentData(pNLE, pQLE);
  718. // validate
  719. if (fOk) {
  720. // dispatch
  721. CallSubagent(
  722. pQLE,
  723. SNMP_EXTENSION_SET_TEST,
  724. pNLE->nTransactionId
  725. );
  726. // process results returned
  727. fOk = UpdateVarBinds(pNLE, pQLE);
  728. }
  729. // next entry (or reverse direction)
  730. pLE = fOk ? pLE->Flink : pLE->Blink;
  731. }
  732. // validate
  733. if (fOk) {
  734. // if this line is missing => GenErr on UpdatePdu()
  735. pLE = pNLE->Queries.Flink;
  736. // process each subagent query
  737. while (fOk && (pLE != &pNLE->Queries)) {
  738. // retrieve pointer to query entry from link
  739. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  740. // dispatch
  741. CallSubagent(
  742. pQLE,
  743. SNMP_EXTENSION_SET_COMMIT,
  744. pNLE->nTransactionId
  745. );
  746. // process results returned
  747. fOk = UpdateVarBinds(pNLE, pQLE);
  748. // next entry (or reverse direction)
  749. pLE = fOk ? pLE->Flink : pLE->Blink;
  750. }
  751. // validate
  752. if (!fOk) {
  753. // process each subagent query
  754. while (pLE != &pNLE->Queries) {
  755. // retrieve pointer to query entry from link
  756. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  757. // dispatch
  758. CallSubagent(
  759. pQLE,
  760. SNMP_EXTENSION_SET_UNDO,
  761. pNLE->nTransactionId
  762. );
  763. // process results returned
  764. UpdateVarBinds(pNLE, pQLE);
  765. // previous entry
  766. pLE = pLE->Blink;
  767. }
  768. }
  769. // point to last query
  770. pLE = pNLE->Queries.Blink;
  771. }
  772. // process each subagent query
  773. while (pLE != &pNLE->Queries) {
  774. // retrieve pointer to query entry from link
  775. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  776. // dispatch
  777. CallSubagent(
  778. pQLE,
  779. SNMP_EXTENSION_SET_CLEANUP,
  780. pNLE->nTransactionId
  781. );
  782. // process results returned
  783. UpdateVarBinds(pNLE, pQLE);
  784. // previous entry
  785. pLE = pLE->Blink;
  786. }
  787. // cleanup queries
  788. UnloadQueries(pNLE);
  789. return TRUE;
  790. }
  791. BOOL
  792. ProcessGet(
  793. PNETWORK_LIST_ENTRY pNLE
  794. )
  795. /*++
  796. Routine Description:
  797. Queries subagents to resolve varbinds.
  798. Arguments:
  799. pNLE - pointer to network list entry.
  800. Return Values:
  801. Returns true if successful.
  802. --*/
  803. {
  804. PLIST_ENTRY pLE;
  805. PQUERY_LIST_ENTRY pQLE = NULL;
  806. BOOL fOk = TRUE;
  807. // load subagent queries
  808. if (!LoadQueries(pNLE)) {
  809. // unload immediately
  810. UnloadQueries(pNLE);
  811. // failure
  812. return FALSE;
  813. }
  814. // point to first query
  815. pLE = pNLE->Queries.Flink;
  816. // process each subagent query
  817. while (fOk && (pLE != &pNLE->Queries)) {
  818. // retrieve pointer to query entry from link
  819. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  820. // load outgoing varbinds
  821. fOk = LoadSubagentData(pNLE, pQLE);
  822. // validate
  823. if (fOk) {
  824. // dispatch
  825. CallSubagent(
  826. pQLE,
  827. SNMP_EXTENSION_GET,
  828. pNLE->nTransactionId
  829. );
  830. // process results returned
  831. fOk = UpdateVarBinds(pNLE, pQLE);
  832. }
  833. // next entry
  834. pLE = pLE->Flink;
  835. }
  836. // cleanup queries
  837. UnloadQueries(pNLE);
  838. return fOk;
  839. }
  840. BOOL
  841. ProcessGetBulk(
  842. PNETWORK_LIST_ENTRY pNLE
  843. )
  844. /*++
  845. Routine Description:
  846. Queries subagents to resolve varbinds.
  847. Arguments:
  848. pNLE - pointer to network list entry.
  849. Return Values:
  850. Returns true if successful.
  851. --*/
  852. {
  853. PLIST_ENTRY pLE;
  854. PQUERY_LIST_ENTRY pQLE = NULL;
  855. BOOL fOk = TRUE;
  856. SNMPDBG((
  857. SNMP_LOG_VERBOSE,
  858. "SNMP: SVC: getbulk request, non-repeaters %d, max-repetitions %d.\n",
  859. pNLE->Pdu.Pdu.BulkPdu.nNonRepeaters,
  860. pNLE->Pdu.Pdu.BulkPdu.nMaxRepetitions
  861. ));
  862. // loop
  863. while (fOk) {
  864. // load subagent queries
  865. fOk = LoadQueries(pNLE);
  866. // validate
  867. if (fOk && !IsListEmpty(&pNLE->Queries)) {
  868. // point to first query
  869. pLE = pNLE->Queries.Flink;
  870. // process each subagent query
  871. while (fOk && (pLE != &pNLE->Queries)) {
  872. // retrieve pointer to query entry from link
  873. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  874. // load outgoing varbinds
  875. fOk = LoadSubagentData(pNLE, pQLE);
  876. // validate
  877. if (fOk) {
  878. // dispatch
  879. CallSubagent(
  880. pQLE,
  881. SNMP_EXTENSION_GET_NEXT,
  882. pNLE->nTransactionId
  883. );
  884. // process results returned
  885. fOk = UpdateVarBinds(pNLE, pQLE);
  886. }
  887. // next entry
  888. pLE = pLE->Flink;
  889. }
  890. } else if (IsListEmpty(&pNLE->Queries)) {
  891. SNMPDBG((
  892. SNMP_LOG_VERBOSE,
  893. "SNMP: SVC: no more queries to process.\n"
  894. ));
  895. break; // finished...
  896. }
  897. // cleanup queries
  898. UnloadQueries(pNLE);
  899. }
  900. return fOk;
  901. }
  902. ///////////////////////////////////////////////////////////////////////////////
  903. // //
  904. // Public procedures //
  905. // //
  906. ///////////////////////////////////////////////////////////////////////////////
  907. BOOL
  908. AllocQLE(
  909. PQUERY_LIST_ENTRY * ppQLE
  910. )
  911. /*++
  912. Routine Description:
  913. Allocates query list entry.
  914. Arguments:
  915. ppQLE - pointer to receive list entry pointer.
  916. Return Values:
  917. Returns true if successful.
  918. --*/
  919. {
  920. BOOL fOk = FALSE;
  921. PQUERY_LIST_ENTRY pQLE = NULL;
  922. // attempt to allocate structure
  923. pQLE = AgentMemAlloc(sizeof(QUERY_LIST_ENTRY));
  924. // validate
  925. if (pQLE != NULL) {
  926. // initialize outgoing varbind list
  927. InitializeListHead(&pQLE->SubagentVbs);
  928. // success
  929. fOk = TRUE;
  930. } else {
  931. SNMPDBG((
  932. SNMP_LOG_ERROR,
  933. "SNMP: SVC: could not allocate query.\n"
  934. ));
  935. }
  936. // transfer
  937. *ppQLE = pQLE;
  938. return fOk;
  939. }
  940. BOOL
  941. FreeQLE(
  942. PQUERY_LIST_ENTRY pQLE
  943. )
  944. /*++
  945. Routine Description:
  946. Creates queries from varbind list entries.
  947. Arguments:
  948. pNLE - pointer to network list entry with SNMP message.
  949. Return Values:
  950. Returns true if successful.
  951. --*/
  952. {
  953. // validate pointer
  954. if (pQLE != NULL) {
  955. // release subagent info
  956. UnloadSubagentData(pQLE);
  957. // release structure
  958. AgentMemFree(pQLE);
  959. }
  960. return TRUE;
  961. }
  962. BOOL
  963. LoadQueries(
  964. PNETWORK_LIST_ENTRY pNLE
  965. )
  966. /*++
  967. Routine Description:
  968. Creates queries from varbind list entries.
  969. Arguments:
  970. pNLE - pointer to network list entry.
  971. Return Values:
  972. Returns true if successful.
  973. --*/
  974. {
  975. PLIST_ENTRY pLE;
  976. PVARBIND_LIST_ENTRY pVLE;
  977. PQUERY_LIST_ENTRY pQLE = NULL;
  978. // point to first varbind
  979. pLE = pNLE->Bindings.Flink;
  980. // process each binding
  981. while (pLE != &pNLE->Bindings) {
  982. // retrieve pointer to varbind entry from link
  983. pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, Link);
  984. // analyze current state of varbind
  985. if ((pVLE->nState == VARBIND_INITIALIZED) ||
  986. (pVLE->nState == VARBIND_PARTIALLY_RESOLVED)) {
  987. // attempt to locate existing query
  988. if (FindQueryBySLE(&pQLE, pNLE, pVLE->pCurrentRLE->pSLE)) {
  989. // attach varbind entry to query via query link
  990. InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
  991. // change varbind state
  992. pVLE->nState = VARBIND_RESOLVING;
  993. // increment total
  994. pQLE->nSubagentVbs++;
  995. SNMPDBG((
  996. SNMP_LOG_VERBOSE,
  997. "SNMP: SVC: variable %d added to existing query 0x%08lx.\n",
  998. pVLE->nErrorIndex,
  999. pQLE
  1000. ));
  1001. SNMPDBG((
  1002. SNMP_LOG_VERBOSE,
  1003. "SNMP: SVC: variable %d state '%s'.\n",
  1004. pVLE->nErrorIndex,
  1005. VARBINDSTATESTRING(pVLE->nState)
  1006. ));
  1007. // attempt to allocate entry
  1008. } else if (AllocQLE(&pQLE)) {
  1009. // obtain subagent pointer
  1010. pQLE->pSLE = pVLE->pCurrentRLE->pSLE;
  1011. // insert into query list
  1012. InsertTailList(&pNLE->Queries, &pQLE->Link);
  1013. // attach varbind entry to query via query link
  1014. InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
  1015. // change varbind state
  1016. pVLE->nState = VARBIND_RESOLVING;
  1017. // increment total
  1018. pQLE->nSubagentVbs++;
  1019. SNMPDBG((
  1020. SNMP_LOG_VERBOSE,
  1021. "SNMP: SVC: variable %d added to new query 0x%08lx.\n",
  1022. pVLE->nErrorIndex,
  1023. pQLE
  1024. ));
  1025. SNMPDBG((
  1026. SNMP_LOG_VERBOSE,
  1027. "SNMP: SVC: variable %d state '%s'.\n",
  1028. pVLE->nErrorIndex,
  1029. VARBINDSTATESTRING(pVLE->nState)
  1030. ));
  1031. } else {
  1032. SNMPDBG((
  1033. SNMP_LOG_ERROR,
  1034. "SNMP: SVC: could not contruct query.\n"
  1035. ));
  1036. // failure
  1037. return FALSE;
  1038. }
  1039. }
  1040. // next entry
  1041. pLE = pLE->Flink;
  1042. }
  1043. // success
  1044. return TRUE;
  1045. }
  1046. BOOL
  1047. UnloadQueries(
  1048. PNETWORK_LIST_ENTRY pNLE
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Destroys queries from varbind list entries.
  1053. Arguments:
  1054. pNLE - pointer to network list entry with SNMP message.
  1055. Return Values:
  1056. Returns true if successful.
  1057. --*/
  1058. {
  1059. PLIST_ENTRY pLE;
  1060. PQUERY_LIST_ENTRY pQLE;
  1061. // process each query entry
  1062. while (!IsListEmpty(&pNLE->Queries)) {
  1063. // point to first query
  1064. pLE = RemoveHeadList(&pNLE->Queries);
  1065. // retrieve pointer to query from link
  1066. pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
  1067. // release
  1068. FreeQLE(pQLE);
  1069. }
  1070. return TRUE;
  1071. }
  1072. BOOL
  1073. ProcessQueries(
  1074. PNETWORK_LIST_ENTRY pNLE
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. Queries subagents to resolve varbinds.
  1079. Arguments:
  1080. pNLE - pointer to network list entry.
  1081. Return Values:
  1082. Returns true if successful.
  1083. --*/
  1084. {
  1085. // determine pdu
  1086. switch (pNLE->Pdu.nType) {
  1087. case SNMP_PDU_GETNEXT:
  1088. case SNMP_PDU_GETBULK:
  1089. // multiple non-exact reads
  1090. return ProcessGetBulk(pNLE);
  1091. case SNMP_PDU_GET:
  1092. // single exact read
  1093. return ProcessGet(pNLE);
  1094. case SNMP_PDU_SET:
  1095. // single exact write
  1096. return ProcessSet(pNLE);
  1097. }
  1098. // failure
  1099. return FALSE;
  1100. }