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.

862 lines
22 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. callback.c
  5. Abstract:
  6. This module contains the traffic control call back routines
  7. that are called by OS, either IO conpletion routines or WMI
  8. notifications.
  9. Author:
  10. Ofer Bar (oferbar) Oct 1, 1997
  11. --*/
  12. #include "precomp.h"
  13. /*
  14. Calculate the length of a unicode string with the NULL char
  15. */
  16. int StringLength(TCHAR * String)
  17. {
  18. const TCHAR *eos = String;
  19. while( *eos++ ) ;
  20. return( (int)(eos - String) );
  21. }
  22. VOID
  23. NTAPI CbAddFlowComplete(
  24. IN PVOID ApcContext,
  25. IN PIO_STATUS_BLOCK IoStatusBlock,
  26. IN ULONG Reserved
  27. )
  28. {
  29. PFLOW_STRUC pFlow = (PFLOW_STRUC)ApcContext;
  30. DWORD Status;
  31. PGPC_ADD_CF_INFO_RES GpcRes;
  32. ASSERT(pFlow);
  33. GpcRes = (PGPC_ADD_CF_INFO_RES)pFlow->CompletionBuffer;
  34. ASSERT(GpcRes);
  35. Status = MapNtStatus2WinError(IoStatusBlock->Status);
  36. if (Status == NO_ERROR) {
  37. Status = MapNtStatus2WinError(GpcRes->Status);
  38. }
  39. IF_DEBUG(IOCTLS) {
  40. WSPRINT(("CbAddFlowComplete: Flow=0x%X GpcRes=0x%X IoStatus=0x%X Information=%d Status=0x%X\n",
  41. PtrToUlong(pFlow),
  42. PtrToUlong(GpcRes),
  43. IoStatusBlock->Status, IoStatusBlock->Information,
  44. Status));
  45. }
  46. if (Status == NO_ERROR) {
  47. pFlow->GpcHandle = GpcRes->GpcCfInfoHandle;
  48. pFlow->InstanceNameLength = GpcRes->InstanceNameLength;
  49. wcscpy(pFlow->InstanceName, GpcRes->InstanceName );
  50. }
  51. //
  52. // locate the client and notify the add flow completion
  53. //
  54. ASSERT(pFlow->pInterface->pClient->ClHandlers.ClAddFlowCompleteHandler);
  55. pFlow->pInterface->pClient->ClHandlers.ClAddFlowCompleteHandler(pFlow->ClFlowCtx, Status);
  56. //
  57. // complete the add flow
  58. //
  59. CompleteAddFlow(pFlow, Status);
  60. }
  61. VOID
  62. NTAPI CbModifyFlowComplete(
  63. IN PVOID ApcContext,
  64. IN PIO_STATUS_BLOCK IoStatusBlock,
  65. IN ULONG Reserved
  66. )
  67. {
  68. PFLOW_STRUC pFlow = (PFLOW_STRUC)ApcContext;
  69. DWORD Status;
  70. PGPC_MODIFY_CF_INFO_RES GpcRes;
  71. ASSERT(pFlow);
  72. GpcRes = (PGPC_MODIFY_CF_INFO_RES)pFlow->CompletionBuffer;
  73. // it is likely that the flow got deleted while we tried to
  74. // modify it. in that case, just clean up, remove the ref
  75. // and get out.
  76. GetLock(pFlow->Lock);
  77. if (QUERY_STATE(pFlow->State) != OPEN) {
  78. FreeLock(pFlow->Lock);
  79. if (pFlow->CompletionBuffer) {
  80. FreeMem(pFlow->CompletionBuffer);
  81. pFlow->CompletionBuffer = NULL;
  82. }
  83. if (pFlow->pGenFlow1) {
  84. FreeMem(pFlow->pGenFlow1);
  85. pFlow->pGenFlow1 = NULL;
  86. }
  87. // call them back.
  88. ASSERT(pFlow->pInterface->pClient->ClHandlers.ClModifyFlowCompleteHandler);
  89. pFlow->pInterface->pClient->ClHandlers.ClModifyFlowCompleteHandler(pFlow->ClFlowCtx, ERROR_INVALID_HANDLE);
  90. //
  91. // This ref was taken in TcModifyFlow
  92. //
  93. REFDEL(&pFlow->RefCount, 'TCMF');
  94. return;
  95. }
  96. FreeLock(pFlow->Lock);
  97. ASSERT(GpcRes);
  98. Status = MapNtStatus2WinError(IoStatusBlock->Status);
  99. if (Status == NO_ERROR) {
  100. Status = MapNtStatus2WinError(GpcRes->Status);
  101. }
  102. IF_DEBUG(IOCTLS) {
  103. WSPRINT(("CbModifyFlowComplete: Flow=0x%X GpcRes=0x%X IoStatus=0x%X Information=%d Status=0x%X\n",
  104. PtrToUlong(pFlow),
  105. PtrToUlong(GpcRes),
  106. IoStatusBlock->Status, IoStatusBlock->Information,
  107. Status));
  108. }
  109. //
  110. // locate the client and notify the modify flow completion
  111. //
  112. ASSERT(pFlow->pInterface->pClient->ClHandlers.ClModifyFlowCompleteHandler);
  113. pFlow->pInterface->pClient->ClHandlers.ClModifyFlowCompleteHandler(pFlow->ClFlowCtx, Status);
  114. //
  115. // complete the modify flow
  116. //
  117. CompleteModifyFlow(pFlow, Status);
  118. }
  119. VOID
  120. NTAPI CbDeleteFlowComplete(
  121. IN PVOID ApcContext,
  122. IN PIO_STATUS_BLOCK IoStatusBlock,
  123. IN ULONG Reserved
  124. )
  125. {
  126. PFLOW_STRUC pFlow = (PFLOW_STRUC)ApcContext;
  127. DWORD Status;
  128. PGPC_REMOVE_CF_INFO_RES GpcRes;
  129. ASSERT(pFlow);
  130. GpcRes = (PGPC_REMOVE_CF_INFO_RES)pFlow->CompletionBuffer;
  131. ASSERT(GpcRes);
  132. Status = MapNtStatus2WinError(IoStatusBlock->Status);
  133. if (Status == NO_ERROR) {
  134. Status = MapNtStatus2WinError(GpcRes->Status);
  135. }
  136. ASSERT(Status != ERROR_SIGNAL_PENDING);
  137. IF_DEBUG(IOCTLS) {
  138. WSPRINT(("CbDeleteFlowComplete: Flow=0x%X GpcRes=0x%X IoStatus=0x%X Information=%d Status=0x%X\n",
  139. PtrToUlong(pFlow),
  140. PtrToUlong(GpcRes),
  141. IoStatusBlock->Status, IoStatusBlock->Information,
  142. Status));
  143. }
  144. //
  145. // locate the client and notify the delete flow completion
  146. //
  147. ASSERT(pFlow->pInterface->pClient->ClHandlers.ClDeleteFlowCompleteHandler);
  148. pFlow->pInterface->pClient->ClHandlers.ClDeleteFlowCompleteHandler(pFlow->ClFlowCtx, Status);
  149. //
  150. // complete the Delete flow
  151. //
  152. CompleteDeleteFlow(pFlow, Status);
  153. }
  154. VOID
  155. NTAPI
  156. CbGpcNotifyRoutine(
  157. IN PVOID ApcContext,
  158. IN PIO_STATUS_BLOCK IoStatusBlock,
  159. IN ULONG Reserved
  160. )
  161. {
  162. PGPC_NOTIFY_REQUEST_RES GpcRes = (PGPC_NOTIFY_REQUEST_RES)ApcContext;
  163. PFLOW_STRUC pFlow;
  164. PCLIENT_STRUC pClient;
  165. PINTERFACE_STRUC pInterface;
  166. HANDLE FlowCtx;
  167. if (IoStatusBlock->Status == STATUS_CANCELLED)
  168. {
  169. IF_DEBUG(IOCTLS) {
  170. WSPRINT(("==>CbGpcNotifyRoutine: CANCELLED\n"));
  171. }
  172. if ( GpcCancelEvent != INVALID_HANDLE_VALUE )
  173. SetEvent ( GpcCancelEvent );
  174. return;
  175. }
  176. ASSERT(GpcRes->SubCode == GPC_NOTIFY_CFINFO_CLOSED);
  177. IF_DEBUG(IOCTLS) {
  178. WSPRINT(("==>CbGpcNotifyRoutine: Context=%d IoStatus=0x%X Information=%d\n",
  179. ApcContext, IoStatusBlock->Status, IoStatusBlock->Information));
  180. }
  181. if (GpcRes->SubCode == GPC_NOTIFY_CFINFO_CLOSED) {
  182. pFlow = (PFLOW_STRUC)GpcRes->NotificationCtx;
  183. ASSERT(pFlow);
  184. pInterface = pFlow->pInterface;
  185. pClient = pInterface->pClient;
  186. //
  187. // since the GPC will NOT wait for confirmation about the
  188. // flow deletion, we expect the user to delete each filter
  189. // but don't want the IOCTL to go down to the GPC,
  190. // therefore, we'll mark eahc filter with Delete flag.
  191. //
  192. GetLock(pGlobals->Lock);
  193. FlowCtx = pFlow->ClFlowCtx;
  194. //
  195. // The Flags need protection from flow->lock
  196. //
  197. GetLock(pFlow->Lock);
  198. SET_STATE(pFlow->State, REMOVED);
  199. FreeLock(pFlow->Lock);
  200. DeleteFlow( pFlow, TRUE );
  201. FreeLock(pGlobals->Lock);
  202. //
  203. // notify the user about the flow close
  204. //
  205. pClient->ClHandlers.ClNotifyHandler(pClient->ClRegCtx,
  206. pInterface->ClIfcCtx,
  207. TC_NOTIFY_FLOW_CLOSE,
  208. ULongToPtr(GpcRes->Reason),
  209. sizeof(FlowCtx),
  210. (PVOID)&FlowCtx
  211. );
  212. }
  213. //
  214. // finally, release this memory
  215. //
  216. FreeMem(GpcRes);
  217. //
  218. // make the next call to the GPC.
  219. // Ignoring errors as nothing more can be done :-(
  220. IoRequestNotify();
  221. return;
  222. }
  223. VOID
  224. CbParamNotifyClient(
  225. IN ULONG Context,
  226. IN LPGUID pGuid,
  227. IN LPWSTR InstanceName,
  228. IN ULONG DataSize,
  229. IN PVOID DataBuffer
  230. )
  231. /*
  232. Description:
  233. This is a callback routine that is called when there is a incoming
  234. WMI interface parameter change event notification. The WMI notification
  235. handler calls a helper routine to walk the wnode and passing a pointer
  236. to this routine. This callback routine will be called for each instance
  237. name identified in the wnode with the buffer and buffer size.
  238. The client will be called on its notification handler (given during
  239. client registration) to let it know about the parameter value change.
  240. */
  241. {
  242. PINTERFACE_STRUC pInterface, oldInterface = NULL;
  243. PTC_IFC pTcIfc;
  244. PLIST_ENTRY pHead, pEntry;
  245. TCI_NOTIFY_HANDLER callback;
  246. IF_DEBUG(CALLBACK) {
  247. WSPRINT(("==>CbParamNotifyClient: Context=%d, Guid=%08x-%04x-%04x iName=%S Size=%d\n",
  248. Context, pGuid->Data1, pGuid->Data2, pGuid->Data3, InstanceName, DataSize));
  249. }
  250. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  251. pTcIfc = GetTcIfcWithRef(InstanceName, 'CALL');
  252. if (pTcIfc) {
  253. GetLock(pGlobals->Lock);
  254. pHead = pEntry = &pTcIfc->ClIfcList;
  255. pEntry = pEntry->Flink;
  256. while (pEntry != pHead) {
  257. pInterface = CONTAINING_RECORD(pEntry, INTERFACE_STRUC, NextIfc);
  258. ASSERT(pInterface);
  259. GetLock(pInterface->Lock);
  260. if (QUERY_STATE(pInterface->State) != OPEN) {
  261. FreeLock(pInterface->Lock);
  262. pEntry = pEntry->Flink;
  263. continue;
  264. } else {
  265. FreeLock(pInterface->Lock);
  266. REFADD(&pInterface->RefCount, 'CBNC');
  267. }
  268. FreeLock(pGlobals->Lock);
  269. //
  270. // call the client
  271. //
  272. callback = pInterface->pClient->ClHandlers.ClNotifyHandler;
  273. ASSERT(callback);
  274. IF_DEBUG(CALLBACK) {
  275. WSPRINT(("CbParamNotifyClient: Context=%d, IfcH=%d ClientH=%d ClientCtx=%d IfcCtx=%d\n",
  276. Context, pInterface->ClHandle, pInterface->pClient->ClHandle,
  277. pInterface->pClient->ClRegCtx, pInterface->ClIfcCtx));
  278. }
  279. //
  280. // 258218: call the client only if it registered for this.
  281. //
  282. if (TcipClientRegisteredForNotification(pGuid, pInterface, 0)) {
  283. callback(pInterface->pClient->ClRegCtx,
  284. pInterface->ClIfcCtx,
  285. TC_NOTIFY_PARAM_CHANGED,
  286. pGuid,
  287. DataSize,
  288. DataBuffer
  289. );
  290. }
  291. //
  292. // Take the lock, so that no one's monkeying with the list
  293. // while we are in there.
  294. //
  295. GetLock(pGlobals->Lock);
  296. pEntry = pEntry->Flink;
  297. REFDEL(&pInterface->RefCount, 'CBNC');
  298. }
  299. FreeLock(pGlobals->Lock);
  300. REFDEL(&pTcIfc->RefCount, 'CALL');
  301. }
  302. IF_DEBUG(CALLBACK) {
  303. WSPRINT(("<==CbParamNotifyClient: exit\n"));
  304. }
  305. }
  306. VOID
  307. CbInterfaceNotifyClient(
  308. IN ULONG Context,
  309. IN LPGUID pGuid,
  310. IN LPWSTR InstanceName,
  311. IN ULONG DataSize,
  312. IN PVOID DataBuffer
  313. )
  314. /*
  315. Description:
  316. This is a callback routine that is called when there is a incoming
  317. WMI interface indication event notification. The WMI notification
  318. handler calls a helper routine to walk the wnode and passing a pointer
  319. to this routine. Each registered client should be called at its
  320. notification handler and be passed the client context. In addition,
  321. if the notified interface was opened by the client, the interface
  322. context will also be passed in the same call. There are three kernel
  323. interface indications (UP, DOWN, CHANGE) which are mapped to two
  324. user notifications:
  325. {UP,CHANGE} ==> TC_NOTIFY_IFC_CHANGE
  326. {DOWN} ==> TC_NOTIFY_IFC_CLOSE
  327. This routine first update the internal cached TcIfcList, so that
  328. the next TcEnumerateInterfaces will return an updated view of the
  329. TC kernel interfaces.
  330. */
  331. {
  332. DWORD Status;
  333. PINTERFACE_STRUC pInterface;
  334. PCLIENT_STRUC pClient;
  335. TCI_NOTIFY_HANDLER callback;
  336. PTC_IFC pTcIfc;
  337. PGEN_LIST pNotifyInterfaceList = NULL;
  338. PGEN_LIST pNotifyClientList = NULL;
  339. PGEN_LIST pItem;
  340. PLIST_ENTRY pEntry, pHead, pFlowEntry, pFilterEntry;
  341. PFLOW_STRUC pFlow;
  342. PFILTER_STRUC pFilter;
  343. PGEN_LIST p;
  344. ULONG NotificationCode = 0;
  345. PTC_INDICATION_BUFFER IndicationBuffer
  346. = (PTC_INDICATION_BUFFER)DataBuffer;
  347. if (CompareGUIDs(pGuid, &GUID_QOS_TC_INTERFACE_DOWN_INDICATION)) {
  348. NotificationCode = TC_NOTIFY_IFC_CLOSE;
  349. } else if (CompareGUIDs(pGuid, &GUID_QOS_TC_INTERFACE_UP_INDICATION)) {
  350. NotificationCode = TC_NOTIFY_IFC_UP;
  351. } else if (CompareGUIDs(pGuid, &GUID_QOS_TC_INTERFACE_CHANGE_INDICATION)) {
  352. NotificationCode = TC_NOTIFY_IFC_CHANGE;
  353. }
  354. ASSERT(NotificationCode != 0);
  355. //
  356. // update the TC interface list, this means add a new interface,
  357. // remove an interface or update the net addr list
  358. //
  359. if (NotificationCode != TC_NOTIFY_IFC_CLOSE) {
  360. //
  361. // don't call this in case of IFC_DOWN now.
  362. // we'll do it after notifying the clients
  363. //
  364. Status = UpdateTcIfcList(InstanceName,
  365. DataSize,
  366. IndicationBuffer,
  367. NotificationCode
  368. );
  369. }
  370. //
  371. // find a TC interface that matches the name
  372. //
  373. pTcIfc = GetTcIfcWithRef(InstanceName, 'CALL');
  374. if (pTcIfc == NULL) {
  375. //
  376. // no interface has been opened yet, possible that the driver
  377. // indicated a change before the interface up
  378. //
  379. return;
  380. }
  381. //
  382. // if the Interface is going down - just mark it for now.
  383. // In addition, mark the whole tree of objects that it supports too
  384. // This includes all the filters and flows..
  385. if (NotificationCode == TC_NOTIFY_IFC_CLOSE) {
  386. GetLock(pTcIfc->Lock);
  387. SET_STATE(pTcIfc->State, KERNELCLOSED_USERCLEANUP);
  388. FreeLock(pTcIfc->Lock);
  389. GetLock(pGlobals->Lock);
  390. pHead = &pTcIfc->ClIfcList;
  391. pEntry = pHead->Flink;
  392. while (pHead != pEntry) {
  393. pInterface = CONTAINING_RECORD(pEntry, INTERFACE_STRUC, NextIfc);
  394. GetLock(pInterface->Lock);
  395. if (QUERY_STATE(pInterface->State) == OPEN) {
  396. SET_STATE(pInterface->State, FORCED_KERNELCLOSE);
  397. FreeLock(pInterface->Lock);
  398. MarkAllNodesForClosing(pInterface, FORCED_KERNELCLOSE);
  399. } else {
  400. FreeLock(pInterface->Lock);
  401. ASSERT(IsListEmpty(&pInterface->FlowList));
  402. }
  403. pEntry = pEntry->Flink;
  404. }
  405. FreeLock(pGlobals->Lock);
  406. }
  407. //
  408. // Build the list of every interface that needs to be notified
  409. //
  410. GetLock(pGlobals->Lock);
  411. pHead = &pTcIfc->ClIfcList;
  412. pEntry = pHead->Flink;
  413. while (pHead != pEntry) {
  414. pInterface = CONTAINING_RECORD(pEntry, INTERFACE_STRUC, NextIfc);
  415. //
  416. // Lock and check for open state.
  417. //
  418. GetLock(pInterface->Lock);
  419. if ((QUERY_STATE(pInterface->State) != OPEN) &&
  420. (QUERY_STATE(pInterface->State) != FORCED_KERNELCLOSE)) {
  421. FreeLock(pInterface->Lock);
  422. pEntry = pEntry->Flink;
  423. } else {
  424. FreeLock(pInterface->Lock);
  425. AllocMem(&pItem, sizeof(GEN_LIST));
  426. if (pItem == NULL)
  427. break;
  428. //
  429. // add a refcount since we'll release the lock later
  430. //
  431. REFADD(&pInterface->RefCount, 'CINC');
  432. //
  433. // add the interface to the list head
  434. //
  435. pItem->Next = pNotifyInterfaceList;
  436. pItem->Ptr = (PVOID)pInterface;
  437. pNotifyInterfaceList = pItem;
  438. pEntry = pEntry->Flink;
  439. }
  440. }
  441. //
  442. // now build the list of clients that don't have this interface opened
  443. // they still need to be notified, so they will be able to update the list
  444. // of interfaces
  445. //
  446. pHead = &pGlobals->ClientList;
  447. pEntry = pHead->Flink;
  448. while (pHead != pEntry) {
  449. pClient = CONTAINING_RECORD(pEntry, CLIENT_STRUC, Linkage);
  450. //
  451. // search the client on the interface notify list
  452. //
  453. GetLock(pClient->Lock);
  454. if (QUERY_STATE(pClient->State) != OPEN) {
  455. } else {
  456. for (p = pNotifyInterfaceList; p != NULL; p = p->Next) {
  457. if (pClient == ((PINTERFACE_STRUC)p->Ptr)->pClient) {
  458. //
  459. // found!
  460. //
  461. break;
  462. }
  463. }
  464. if (p == NULL) {
  465. //
  466. // add the client to the list head
  467. //
  468. AllocMem(&pItem, sizeof(GEN_LIST));
  469. if (pItem == NULL) {
  470. FreeLock(pClient->Lock);
  471. break;
  472. }
  473. REFADD(&pClient->RefCount, 'CINC'); // Dont want the client to slip away.
  474. pItem->Next = pNotifyClientList;
  475. pItem->Ptr = (PVOID)pClient;
  476. pNotifyClientList = pItem;
  477. }
  478. }
  479. pEntry = pEntry->Flink;
  480. FreeLock(pClient->Lock);
  481. }
  482. FreeLock(pGlobals->Lock);
  483. //
  484. // now we have two separate lists of clients and interfaces we
  485. // need to send notifications on
  486. //
  487. //
  488. // start with the list of interfaces
  489. //
  490. for (p = pNotifyInterfaceList; p != NULL; ) {
  491. pInterface = (PINTERFACE_STRUC)p->Ptr;
  492. callback = pInterface->pClient->ClHandlers.ClNotifyHandler;
  493. ASSERT(callback);
  494. // we now add the thread id to avoid deadlock.
  495. // in the callback, an app can come back in to
  496. // close the interface, we dont want to block there.
  497. // it is set back to Zero after the callback.
  498. pInterface->CallbackThreadId = GetCurrentThreadId();
  499. //
  500. // 275482 - Indicate the Interfacename instead of the
  501. // the addresses (what good are addresses, asks ericeil).
  502. //
  503. callback(pInterface->pClient->ClRegCtx,
  504. pInterface->ClIfcCtx,
  505. NotificationCode,
  506. ULongToPtr(IndicationBuffer->SubCode),
  507. StringLength(InstanceName) * sizeof(WCHAR),
  508. InstanceName
  509. );
  510. pNotifyInterfaceList = p->Next;
  511. FreeMem(p);
  512. p = pNotifyInterfaceList;
  513. // reset the threadid - the callback is done.
  514. pInterface->CallbackThreadId = 0;
  515. //
  516. // release the previous refcount we kept across the callback
  517. //
  518. REFDEL(&pInterface->RefCount, 'CINC');
  519. if (NotificationCode == TC_NOTIFY_IFC_CLOSE) {
  520. //
  521. // now we can remove the interface, and all the supported flows
  522. // and filters
  523. //
  524. GetLock(pInterface->Lock);
  525. SET_STATE(pInterface->State, KERNELCLOSED_USERCLEANUP);
  526. FreeLock(pInterface->Lock);
  527. CloseInterface(pInterface, TRUE);
  528. }
  529. }
  530. ASSERT(pNotifyInterfaceList == NULL);
  531. //
  532. // next, scan the list of clients (didn't open this interface)
  533. //
  534. for (p = pNotifyClientList; p != NULL; ) {
  535. pClient = (PCLIENT_STRUC)p->Ptr;
  536. callback = pClient->ClHandlers.ClNotifyHandler;
  537. ASSERT(callback);
  538. callback(pClient->ClRegCtx,
  539. NULL,
  540. NotificationCode,
  541. ULongToPtr(IndicationBuffer->SubCode),
  542. (wcslen(InstanceName) + 1)* sizeof(WCHAR),
  543. InstanceName
  544. );
  545. //
  546. // Deref the ref we took to keep the client around when we
  547. // made the pnotifyclientlist
  548. //
  549. REFDEL(&pClient->RefCount, 'CINC');
  550. //
  551. // free the items as we walk down the list
  552. //
  553. pNotifyClientList = p->Next;
  554. FreeMem(p);
  555. p = pNotifyClientList;
  556. }
  557. REFDEL(&pTcIfc->RefCount, 'CALL');
  558. ASSERT(pNotifyClientList == NULL);
  559. if (NotificationCode == TC_NOTIFY_IFC_CLOSE) {
  560. //
  561. // time to remove the TC interface
  562. //
  563. Status = UpdateTcIfcList(InstanceName,
  564. DataSize,
  565. IndicationBuffer,
  566. NotificationCode
  567. );
  568. }
  569. }
  570. VOID
  571. CbWmiParamNotification(
  572. IN PWNODE_HEADER pWnodeHdr,
  573. IN ULONG Context
  574. )
  575. /*
  576. Description:
  577. This callback routine is called by WMI when there is a notification
  578. for the GUID previously registered. The Context parameter is the
  579. interface handle. If it is still valid, we call the client's
  580. notification handler (if exist) and pass it the notified data.
  581. */
  582. {
  583. WalkWnode(pWnodeHdr,
  584. Context,
  585. CbParamNotifyClient
  586. );
  587. }
  588. VOID
  589. CbWmiInterfaceNotification(
  590. IN PWNODE_HEADER pWnodeHdr,
  591. IN ULONG Context
  592. )
  593. /*
  594. Description:
  595. This callback routine is called by WMI when there is a notification
  596. for the GUID_QOS_TC_INTERFACE_INDICATION. We parse the data buffer
  597. in the Wnode and determine which event to notify the client.
  598. Each client will be notified at its notification handler.
  599. */
  600. {
  601. WalkWnode(pWnodeHdr,
  602. Context,
  603. CbInterfaceNotifyClient
  604. );
  605. }