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.

4281 lines
113 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. ultci.c - UL TrafficControl Interface
  5. Abstract:
  6. This module implements a wrapper for QoS TC (Traffic Control)
  7. Interface since the Kernel level API don't exist at this time.
  8. Any HTTP module can use this interface to invoke QoS calls.
  9. Author:
  10. Ali Ediz Turkoglu (aliTu) 28-Jul-2000 Created a draft
  11. version
  12. Revision History:
  13. Ali Ediz Turkoglu (aliTu) 03-11-2000 Modified to handle
  14. Flow & Filter (re)config
  15. as well as various other
  16. major changes.
  17. --*/
  18. #include "precomp.h"
  19. LIST_ENTRY g_TciIfcListHead = {NULL,NULL};
  20. BOOLEAN g_InitTciCalled = FALSE;
  21. //
  22. // GPC handles to talk to
  23. //
  24. HANDLE g_GpcFileHandle = NULL; // result of CreateFile on GPC device
  25. GPC_HANDLE g_GpcClientHandle = NULL; // result of GPC client registration
  26. //
  27. // For querying the interface info like index & mtu size
  28. //
  29. HANDLE g_TcpDeviceHandle = NULL;
  30. //
  31. // Shows if PSCHED is installed or not, protected by its
  32. // private push lock.
  33. //
  34. BOOLEAN g_PSchedInstalled = FALSE;
  35. UL_PUSH_LOCK g_PSchedStatePushLock;
  36. //
  37. // Optional Filter Stats
  38. //
  39. #if ENABLE_TC_STATS
  40. typedef struct _TC_FILTER_STATS {
  41. LONG Add;
  42. LONG Delete;
  43. LONG AddFailure;
  44. LONG DeleteFailure;
  45. } TC_FILTER_STATS, *PTC_FILTER_STATS;
  46. TC_FILTER_STATS g_TcStats = { 0, 0, 0, 0 };
  47. #define INCREMENT_FILTER_ADD() \
  48. InterlockedIncrement( &g_TcStats.Add )
  49. #define INCREMENT_FILTER_ADD_FAILURE() \
  50. InterlockedIncrement( &g_TcStats.AddFailure )
  51. #define INCREMENT_FILTER_DELETE() \
  52. InterlockedIncrement( &g_TcStats.Delete )
  53. #define INCREMENT_FILTER_DELETE_FAILURE() \
  54. InterlockedIncrement( &g_TcStats.DeleteFailure )
  55. #else
  56. #define INCREMENT_FILTER_ADD()
  57. #define INCREMENT_FILTER_ADD_FAILURE()
  58. #define INCREMENT_FILTER_DELETE()
  59. #define INCREMENT_FILTER_DELETE_FAILURE()
  60. #endif
  61. //
  62. // For interface notifications
  63. //
  64. PVOID g_TcInterfaceUpNotificationObject = NULL;
  65. PVOID g_TcInterfaceDownNotificationObject = NULL;
  66. PVOID g_TcInterfaceChangeNotificationObject = NULL;
  67. //
  68. // Simple macro for interface (ref) tracing.
  69. // Actually we don't have the ref yet, but when
  70. // and if we have we can use the 3rd param.
  71. //
  72. #define INT_TRACE(pTcIfc,Action) \
  73. WRITE_REF_TRACE_LOG( \
  74. (pTcIfc)->pTraceLog, \
  75. REF_ACTION_ ## Action, \
  76. 0, \
  77. (pTcIfc), \
  78. __FILE__, \
  79. __LINE__ \
  80. )
  81. #ifdef ALLOC_PRAGMA
  82. #pragma alloc_text(INIT, UlTcInitialize)
  83. #pragma alloc_text(PAGE, UlTcTerminate)
  84. #pragma alloc_text(PAGE, UlpTcInitializeGpc)
  85. #pragma alloc_text(PAGE, UlpTcRegisterGpcClient)
  86. #pragma alloc_text(PAGE, UlpTcDeRegisterGpcClient)
  87. #pragma alloc_text(PAGE, UlpTcGetFriendlyNames)
  88. #pragma alloc_text(PAGE, UlpTcReleaseAll)
  89. #pragma alloc_text(PAGE, UlpTcCloseInterface)
  90. #pragma alloc_text(PAGE, UlpTcCloseAllInterfaces)
  91. #pragma alloc_text(PAGE, UlpTcDeleteFlow)
  92. #pragma alloc_text(PAGE, UlpAddFlow)
  93. #pragma alloc_text(PAGE, UlpModifyFlow)
  94. #pragma alloc_text(PAGE, UlTcAddFlows)
  95. #pragma alloc_text(PAGE, UlTcModifyFlows)
  96. #pragma alloc_text(PAGE, UlTcRemoveFlows)
  97. #endif // ALLOC_PRAGMA
  98. #if 0
  99. NOT PAGEABLE -- UlpRemoveFilterEntry
  100. NOT PAGEABLE -- UlpInsertFilterEntry
  101. #endif
  102. //
  103. // Init & Terminate stuff comes here.
  104. //
  105. /***************************************************************************++
  106. Routine Description:
  107. UlTcInitialize :
  108. Will also initiate the Gpc client registration and make few WMI calls
  109. down to psched.
  110. Return Value:
  111. NTSTATUS - Completion status.
  112. --***************************************************************************/
  113. NTSTATUS
  114. UlTcInitialize (
  115. VOID
  116. )
  117. {
  118. PAGED_CODE();
  119. ASSERT(!g_InitTciCalled);
  120. if (!g_InitTciCalled)
  121. {
  122. InitializeListHead(&g_TciIfcListHead);
  123. //
  124. // Init locks, they will be used until termination.
  125. //
  126. UlInitializePushLock(
  127. &g_pUlNonpagedData->TciIfcPushLock,
  128. "TciIfcPushLock",
  129. 0,
  130. UL_TCI_PUSHLOCK_TAG
  131. );
  132. UlInitializePushLock(
  133. &g_PSchedStatePushLock,
  134. "PSchedStatePushLock",
  135. 0,
  136. UL_PSCHED_STATE_PUSHLOCK_TAG
  137. );
  138. //
  139. // Attempt to init PSched and interface settings.
  140. // It may fail if Psched's not installed.
  141. //
  142. UlTcInitPSched();
  143. g_InitTciCalled = TRUE;
  144. }
  145. return STATUS_SUCCESS;
  146. }
  147. /***************************************************************************++
  148. Routine Description:
  149. Terminates the TCI module by releasing our TCI resource and
  150. cleaning up all the qos stuff.
  151. --***************************************************************************/
  152. VOID
  153. UlTcTerminate(
  154. VOID
  155. )
  156. {
  157. NTSTATUS Status;
  158. PAGED_CODE();
  159. if (g_InitTciCalled)
  160. {
  161. //
  162. // Terminate the PSched related global state
  163. //
  164. UlAcquirePushLockExclusive(&g_PSchedStatePushLock);
  165. if (g_PSchedInstalled)
  166. {
  167. //
  168. // No more Wmi callbacks for interface changes
  169. //
  170. if (g_TcInterfaceUpNotificationObject!=NULL)
  171. {
  172. ObDereferenceObject(g_TcInterfaceUpNotificationObject);
  173. g_TcInterfaceUpNotificationObject=NULL;
  174. }
  175. if(g_TcInterfaceDownNotificationObject!=NULL)
  176. {
  177. ObDereferenceObject(g_TcInterfaceDownNotificationObject);
  178. g_TcInterfaceDownNotificationObject = NULL;
  179. }
  180. if(g_TcInterfaceChangeNotificationObject!=NULL)
  181. {
  182. ObDereferenceObject(g_TcInterfaceChangeNotificationObject);
  183. g_TcInterfaceChangeNotificationObject = NULL;
  184. }
  185. //
  186. // Make sure to terminate all the QoS stuff.
  187. //
  188. Status = UlpTcReleaseAll();
  189. ASSERT(NT_SUCCESS(Status));
  190. if (g_TcpDeviceHandle != NULL)
  191. {
  192. ZwClose(g_TcpDeviceHandle);
  193. g_TcpDeviceHandle = NULL;
  194. }
  195. }
  196. g_PSchedInstalled = FALSE;
  197. g_InitTciCalled = FALSE;
  198. UlReleasePushLockExclusive(&g_PSchedStatePushLock);
  199. //
  200. // Now terminate the global locks.
  201. //
  202. UlDeletePushLock( &g_pUlNonpagedData->TciIfcPushLock );
  203. UlDeletePushLock( &g_PSchedStatePushLock );
  204. }
  205. UlTrace( TC, ("Http!UlTcTerminate.\n" ));
  206. }
  207. /***************************************************************************++
  208. Routine Description:
  209. Try to init global tc state. Fails if PSched is not initialized.
  210. Return Value:
  211. NTSTATUS - Completion status.
  212. --***************************************************************************/
  213. NTSTATUS
  214. UlTcInitPSched(
  215. VOID
  216. )
  217. {
  218. NTSTATUS Status = STATUS_SUCCESS;
  219. UlAcquirePushLockExclusive(&g_PSchedStatePushLock);
  220. if (g_PSchedInstalled) // do not attempt to reinit
  221. goto cleanup;
  222. Status = UlpTcInitializeGpc();
  223. if (!NT_SUCCESS(Status))
  224. {
  225. UlTrace(TC,
  226. ("Http!UlTcInitPSched: InitializeGpc FAILED %08lx \n",
  227. Status ));
  228. goto cleanup;
  229. }
  230. Status = UlpTcInitializeTcpDevice();
  231. if (!NT_SUCCESS(Status))
  232. {
  233. UlTrace(TC,
  234. ("Http!UlTcInitPSched: InitializeTcp FAILED %08lx \n",
  235. Status ));
  236. goto cleanup;
  237. }
  238. Status = UlpTcGetFriendlyNames();
  239. if (!NT_SUCCESS(Status))
  240. {
  241. UlTrace(TC,
  242. ("Http!UlTcInitialize: GetFriendlyNames FAILED %08lx \n",
  243. Status ));
  244. goto cleanup;
  245. }
  246. Status = UlpTcRegisterForCallbacks();
  247. if (!NT_SUCCESS(Status))
  248. {
  249. UlTrace(TC,
  250. ("Http!UlTcInitialize: RegisterForCallbacks FAILED %08lx \n",
  251. Status ));
  252. goto cleanup;
  253. }
  254. //
  255. // Mark that PSched is installed & interface state is initialized !
  256. //
  257. g_PSchedInstalled = TRUE;
  258. cleanup:
  259. if (!NT_SUCCESS(Status))
  260. {
  261. //
  262. // Do not forget to deregister Gpc client
  263. // and close tcp device handle.
  264. //
  265. if (g_GpcClientHandle != NULL)
  266. {
  267. NTSTATUS TempStatus;
  268. TempStatus = UlpTcDeRegisterGpcClient();
  269. ASSERT(NT_SUCCESS(TempStatus));
  270. ASSERT(g_GpcFileHandle);
  271. ZwClose(g_GpcFileHandle);
  272. g_GpcFileHandle= NULL;
  273. }
  274. if (g_TcpDeviceHandle != NULL)
  275. {
  276. ZwClose(g_TcpDeviceHandle);
  277. g_TcpDeviceHandle=NULL;
  278. }
  279. }
  280. UlReleasePushLockExclusive(&g_PSchedStatePushLock);
  281. UlTrace(TC,
  282. ("Http!UlTcInitPSched: Initializing global Psched state. Status %08lx\n",
  283. Status
  284. ));
  285. return Status;
  286. }
  287. /***************************************************************************++
  288. To check whether packet scheduler is installed and global interface state
  289. is initialized properly or not.
  290. Caller may decide to attempt to reinit the setting if we return FALSE.
  291. --***************************************************************************/
  292. BOOLEAN
  293. UlTcPSchedInstalled(
  294. VOID
  295. )
  296. {
  297. BOOLEAN Installed;
  298. //
  299. // Probe the value inside the lock.
  300. //
  301. UlAcquirePushLockShared(&g_PSchedStatePushLock);
  302. Installed = ( g_InitTciCalled && g_PSchedInstalled );
  303. UlReleasePushLockShared(&g_PSchedStatePushLock);
  304. return Installed;
  305. }
  306. /***************************************************************************++
  307. Routine Description:
  308. UlpTcInitializeGpc :
  309. It will open the Gpc file handle and attempt to register as Gpc
  310. client.
  311. Return Value:
  312. NTSTATUS - Completion status.
  313. --***************************************************************************/
  314. NTSTATUS
  315. UlpTcInitializeGpc(
  316. VOID
  317. )
  318. {
  319. NTSTATUS Status;
  320. IO_STATUS_BLOCK IoStatusBlock;
  321. UNICODE_STRING GpcNameString;
  322. OBJECT_ATTRIBUTES GpcObjAttribs;
  323. Status = STATUS_SUCCESS;
  324. //
  325. // Open Gpc Device Handle
  326. //
  327. Status = UlInitUnicodeStringEx(&GpcNameString, DD_GPC_DEVICE_NAME);
  328. if (!NT_SUCCESS(Status))
  329. {
  330. goto end;
  331. }
  332. InitializeObjectAttributes(&GpcObjAttribs,
  333. &GpcNameString,
  334. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  335. NULL,
  336. NULL
  337. );
  338. Status = ZwCreateFile(&g_GpcFileHandle,
  339. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  340. &GpcObjAttribs,
  341. &IoStatusBlock,
  342. NULL,
  343. FILE_ATTRIBUTE_NORMAL,
  344. FILE_SHARE_READ | FILE_SHARE_WRITE,
  345. FILE_OPEN_IF,
  346. 0,
  347. NULL,
  348. 0
  349. );
  350. if (!NT_SUCCESS(Status))
  351. {
  352. goto end;
  353. }
  354. ASSERT( g_GpcFileHandle != NULL );
  355. UlTrace( TC, ("Http!UlpTcInitializeGpc: Gpc Device Opened. %p\n",
  356. g_GpcFileHandle ));
  357. //
  358. // Register as GPC_CF_QOS Gpc Client
  359. //
  360. Status = UlpTcRegisterGpcClient(GPC_CF_QOS);
  361. end:
  362. return Status;
  363. }
  364. /***************************************************************************++
  365. Routine Description:
  366. UlpTcRegisterGpcClient :
  367. Will build up the necessary structures and make a register call down
  368. to Gpc
  369. Arguments:
  370. CfInfoType - Should be GPC_CF_QOS for our purposes.
  371. Return Value:
  372. NTSTATUS - Completion status.
  373. --***************************************************************************/
  374. NTSTATUS
  375. UlpTcRegisterGpcClient(
  376. IN ULONG CfInfoType
  377. )
  378. {
  379. NTSTATUS Status;
  380. GPC_REGISTER_CLIENT_REQ GpcReq;
  381. GPC_REGISTER_CLIENT_RES GpcRes;
  382. ULONG InBuffSize;
  383. ULONG OutBuffSize;
  384. IO_STATUS_BLOCK IoStatBlock;
  385. Status = STATUS_SUCCESS;
  386. if ( g_GpcFileHandle == NULL )
  387. {
  388. return STATUS_INVALID_PARAMETER;
  389. }
  390. InBuffSize = sizeof(GPC_REGISTER_CLIENT_REQ);
  391. OutBuffSize = sizeof(GPC_REGISTER_CLIENT_RES);
  392. //
  393. // In HTTP we should only register for GPC_CF_QOS.
  394. //
  395. ASSERT(CfInfoType == GPC_CF_QOS);
  396. GpcReq.CfId = CfInfoType;
  397. GpcReq.Flags = GPC_FLAGS_FRAGMENT;
  398. GpcReq.MaxPriorities = 1;
  399. GpcReq.ClientContext = (GPC_CLIENT_HANDLE) 0; // ???????? Possible BUGBUG ...
  400. //GpcReq.ClientContext = (GPC_CLIENT_HANDLE)GetCurrentProcessId(); // process id
  401. Status = UlpTcDeviceControl(g_GpcFileHandle,
  402. NULL,
  403. NULL,
  404. NULL,
  405. &IoStatBlock,
  406. IOCTL_GPC_REGISTER_CLIENT,
  407. &GpcReq,
  408. InBuffSize,
  409. &GpcRes,
  410. OutBuffSize
  411. );
  412. if (NT_SUCCESS(Status))
  413. {
  414. Status = GpcRes.Status;
  415. if (NT_SUCCESS(Status))
  416. {
  417. g_GpcClientHandle = GpcRes.ClientHandle;
  418. UlTrace(TC,
  419. ("Http!UlpTcRegisterGpcClient: Gpc Client %p Registered.\n",
  420. g_GpcClientHandle
  421. ));
  422. }
  423. }
  424. if (!NT_SUCCESS(Status))
  425. {
  426. g_GpcClientHandle = NULL;
  427. UlTrace(TC,
  428. ("Http!UlpTcRegisterGpcClient: FAILURE %08lx \n", Status ));
  429. }
  430. return Status;
  431. }
  432. /***************************************************************************++
  433. Routine Description:
  434. UlpTcDeRegisterGpcClient :
  435. Self explainatory.
  436. Return Value:
  437. NTSTATUS - Completion status.
  438. --***************************************************************************/
  439. NTSTATUS
  440. UlpTcDeRegisterGpcClient(
  441. VOID
  442. )
  443. {
  444. NTSTATUS Status;
  445. GPC_DEREGISTER_CLIENT_REQ GpcReq;
  446. GPC_DEREGISTER_CLIENT_RES GpcRes;
  447. ULONG InBuffSize;
  448. ULONG OutBuffSize;
  449. IO_STATUS_BLOCK IoStatBlock;
  450. Status = STATUS_SUCCESS;
  451. if (g_GpcFileHandle == NULL && g_GpcClientHandle == NULL)
  452. {
  453. return STATUS_INVALID_PARAMETER;
  454. }
  455. InBuffSize = sizeof(GPC_REGISTER_CLIENT_REQ);
  456. OutBuffSize = sizeof(GPC_REGISTER_CLIENT_RES);
  457. GpcReq.ClientHandle = g_GpcClientHandle;
  458. Status = UlpTcDeviceControl(g_GpcFileHandle,
  459. NULL,
  460. NULL,
  461. NULL,
  462. &IoStatBlock,
  463. IOCTL_GPC_DEREGISTER_CLIENT,
  464. &GpcReq,
  465. InBuffSize,
  466. &GpcRes,
  467. OutBuffSize
  468. );
  469. if (NT_SUCCESS(Status))
  470. {
  471. Status = GpcRes.Status;
  472. if (NT_SUCCESS(Status))
  473. {
  474. g_GpcClientHandle = NULL;
  475. UlTrace(TC,
  476. ("Http!UlpTcDeRegisterGpcClient: Client Deregistered.\n" ));
  477. }
  478. }
  479. if (!NT_SUCCESS(Status))
  480. {
  481. UlTrace(TC,
  482. ("Http!UlpTcDeRegisterGpcClient: FAILURE %08lx \n", Status ));
  483. }
  484. return Status;
  485. }
  486. /***************************************************************************++
  487. Routine Description:
  488. UlpTcInitializeTcpDevice :
  489. Arguments:
  490. Return Value:
  491. NTSTATUS - Completion status.
  492. --***************************************************************************/
  493. NTSTATUS
  494. UlpTcInitializeTcpDevice(
  495. VOID
  496. )
  497. {
  498. NTSTATUS Status;
  499. IO_STATUS_BLOCK IoStatusBlock;
  500. UNICODE_STRING TcpNameString;
  501. OBJECT_ATTRIBUTES TcpObjAttribs;
  502. Status = STATUS_SUCCESS;
  503. //
  504. // Open Gpc Device
  505. //
  506. Status = UlInitUnicodeStringEx(&TcpNameString, DD_TCP_DEVICE_NAME);
  507. if ( !NT_SUCCESS(Status) )
  508. {
  509. goto end;
  510. }
  511. InitializeObjectAttributes(&TcpObjAttribs,
  512. &TcpNameString,
  513. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  514. NULL,
  515. NULL);
  516. Status = ZwCreateFile( &g_TcpDeviceHandle,
  517. GENERIC_EXECUTE,
  518. &TcpObjAttribs,
  519. &IoStatusBlock,
  520. NULL,
  521. FILE_ATTRIBUTE_NORMAL,
  522. FILE_SHARE_READ | FILE_SHARE_WRITE,
  523. FILE_OPEN_IF,
  524. 0,
  525. NULL,
  526. 0);
  527. if ( !NT_SUCCESS(Status) )
  528. {
  529. goto end;
  530. }
  531. ASSERT( g_TcpDeviceHandle != NULL );
  532. end:
  533. return Status;
  534. }
  535. /***************************************************************************++
  536. Routine Description:
  537. UlpTcGetInterfaceIndex :
  538. Helper function to get the interface index from TCP for our internal
  539. interface structure.
  540. Arguments:
  541. PUL_TCI_INTERFACE pIntfc - The interface we will find the index for.
  542. --***************************************************************************/
  543. NTSTATUS
  544. UlpTcGetInterfaceIndex(
  545. IN PUL_TCI_INTERFACE pIntfc
  546. )
  547. {
  548. NTSTATUS Status;
  549. IPAddrEntry *pIpAddrTbl;
  550. ULONG IpAddrTblSize;
  551. ULONG k;
  552. IO_STATUS_BLOCK IoStatBlock;
  553. TDIObjectID *ID;
  554. TCP_REQUEST_QUERY_INFORMATION_EX trqiInBuf;
  555. ULONG InBuffLen;
  556. ULONG NumEntries;
  557. IPSNMPInfo IPSnmpInfo;
  558. NETWORK_ADDRESS UNALIGNED64 *pAddr;
  559. NETWORK_ADDRESS_IP UNALIGNED64 *pIpNetAddr = NULL;
  560. ULONG cAddr;
  561. ULONG index;
  562. //
  563. // Initialize & Sanity check first
  564. //
  565. Status = STATUS_SUCCESS;
  566. NumEntries = 0;
  567. pIpAddrTbl = NULL;
  568. UlTrace(TC,("Http!UlpTcGetInterfaceIndex: ....\n" ));
  569. ASSERT( g_TcpDeviceHandle != NULL );
  570. if (!pIntfc->pAddressListDesc->AddressList.AddressCount)
  571. {
  572. return Status;
  573. }
  574. RtlZeroMemory(&trqiInBuf,sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
  575. InBuffLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  576. ID = &(trqiInBuf.ID);
  577. ID->toi_entity.tei_entity = CL_NL_ENTITY;
  578. ID->toi_entity.tei_instance = 0;
  579. ID->toi_class = INFO_CLASS_PROTOCOL;
  580. ID->toi_type = INFO_TYPE_PROVIDER;
  581. for(;;)
  582. {
  583. // First, get the count of addresses.
  584. ID->toi_id = IP_MIB_STATS_ID;
  585. Status = UlpTcDeviceControl(
  586. g_TcpDeviceHandle,
  587. NULL,
  588. NULL,
  589. NULL,
  590. &IoStatBlock,
  591. IOCTL_TCP_QUERY_INFORMATION_EX,
  592. &trqiInBuf,
  593. InBuffLen,
  594. (PVOID)&IPSnmpInfo,
  595. sizeof(IPSnmpInfo)
  596. );
  597. if (!NT_SUCCESS(Status))
  598. {
  599. break;
  600. }
  601. // Allocate a private buffer to retrieve Ip Address table from TCP
  602. IpAddrTblSize = IPSnmpInfo.ipsi_numaddr * sizeof(IPAddrEntry);
  603. ASSERT(NULL == pIpAddrTbl);
  604. pIpAddrTbl = (IPAddrEntry *) UL_ALLOCATE_ARRAY(
  605. PagedPool,
  606. UCHAR,
  607. IpAddrTblSize,
  608. UL_TCI_GENERIC_POOL_TAG
  609. );
  610. if (pIpAddrTbl == NULL)
  611. {
  612. Status = STATUS_NO_MEMORY;
  613. break;
  614. }
  615. RtlZeroMemory(pIpAddrTbl,IpAddrTblSize);
  616. // Now, get the addresses.
  617. ID->toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  618. Status = UlpTcDeviceControl(
  619. g_TcpDeviceHandle,
  620. NULL,
  621. NULL,
  622. NULL,
  623. &IoStatBlock,
  624. IOCTL_TCP_QUERY_INFORMATION_EX,
  625. &trqiInBuf,
  626. InBuffLen,
  627. pIpAddrTbl,
  628. IpAddrTblSize
  629. );
  630. if(STATUS_BUFFER_OVERFLOW == Status)
  631. {
  632. // Someone has added a few more IP addresses. Let's re-do
  633. // the count query. Free the old buffer, we'll loop back &
  634. // re-do the count query.
  635. UL_FREE_POOL(pIpAddrTbl, UL_TCI_GENERIC_POOL_TAG);
  636. pIpAddrTbl = NULL;
  637. }
  638. else
  639. {
  640. break;
  641. }
  642. }
  643. if(NT_SUCCESS(Status))
  644. {
  645. // Look at how many entries were written to the output buffer
  646. // (pIpAddrTbl)
  647. NumEntries = (((ULONG)IoStatBlock.Information)/sizeof(IPAddrEntry));
  648. UlTrace(TC,
  649. ("Http!UlpTcGetInterfaceIndex: NumEntries %d\n", NumEntries ));
  650. //
  651. // Search for the matching IP address to IpAddr
  652. // in the table we got back from the stack
  653. //
  654. for (k=0; k<NumEntries; k++)
  655. {
  656. cAddr = pIntfc->pAddressListDesc->AddressList.AddressCount;
  657. pAddr = (UNALIGNED64 NETWORK_ADDRESS *)
  658. &pIntfc->pAddressListDesc->AddressList.Address[0];
  659. for (index = 0; index < cAddr; index++)
  660. {
  661. if (pAddr->AddressType == NDIS_PROTOCOL_ID_TCP_IP)
  662. {
  663. pIpNetAddr =
  664. (UNALIGNED64 NETWORK_ADDRESS_IP *)&pAddr->Address[0];
  665. if(pIpNetAddr->in_addr == pIpAddrTbl[k].iae_addr)
  666. {
  667. pIntfc->IfIndex = pIpAddrTbl[k].iae_index;
  668. UlTrace(TC,
  669. ("Http!UlpTcGetInterfaceIndex: got for index %d\n",
  670. pIntfc->IfIndex ));
  671. goto end;
  672. }
  673. }
  674. pAddr = (UNALIGNED64 NETWORK_ADDRESS *)(((PUCHAR)pAddr)
  675. + pAddr->AddressLength
  676. + FIELD_OFFSET(NETWORK_ADDRESS, Address));
  677. }
  678. }
  679. }
  680. else
  681. {
  682. UlTrace(TC,("Http!UlpTcGetInterfaceIndex: FAILED Status %08lx\n",
  683. Status));
  684. }
  685. end:
  686. if ( pIpAddrTbl != NULL )
  687. {
  688. UL_FREE_POOL( pIpAddrTbl, UL_TCI_GENERIC_POOL_TAG );
  689. }
  690. return Status;
  691. }
  692. /***************************************************************************++
  693. Routine Description:
  694. Allocates a interface structure from the given arguments.
  695. Marks the interface enabled, if its address count is non-zero.
  696. Argument:
  697. DescSize Address list desc size in bytes
  698. Desc Pointer to address list desc
  699. NameLength Length is in bytes
  700. Name Interface Name (Unicode buffer)
  701. InstanceIDLength Length is in bytes.
  702. InstanceID Instance Id is also unicode buffer
  703. Return Value:
  704. PUL_TCI_INTERFACE - Newly allocated interface structure
  705. --***************************************************************************/
  706. PUL_TCI_INTERFACE
  707. UlpTcAllocateInterface(
  708. IN ULONG DescSize,
  709. IN PADDRESS_LIST_DESCRIPTOR Desc,
  710. IN ULONG NameLength,
  711. IN PUCHAR Name,
  712. IN ULONG InstanceIDLength,
  713. IN PUCHAR InstanceID
  714. )
  715. {
  716. PUL_TCI_INTERFACE pTcIfc;
  717. //
  718. // Sanity Checks
  719. //
  720. PAGED_CODE();
  721. ASSERT(NameLength <= MAX_STRING_LENGTH);
  722. ASSERT(InstanceIDLength <= MAX_STRING_LENGTH);
  723. if (NameLength > MAX_STRING_LENGTH ||
  724. InstanceIDLength > MAX_STRING_LENGTH)
  725. {
  726. return NULL;
  727. }
  728. //
  729. // Allocate a new interface structure & initialize it
  730. //
  731. pTcIfc = UL_ALLOCATE_STRUCT(
  732. PagedPool,
  733. UL_TCI_INTERFACE,
  734. UL_TCI_INTERFACE_POOL_TAG
  735. );
  736. if ( pTcIfc == NULL )
  737. {
  738. return NULL;
  739. }
  740. RtlZeroMemory( pTcIfc, sizeof(UL_TCI_INTERFACE) );
  741. pTcIfc->Signature = UL_TCI_INTERFACE_POOL_TAG;
  742. InitializeListHead( &pTcIfc->FlowList );
  743. // Variable size addresslist
  744. pTcIfc->pAddressListDesc = (PADDRESS_LIST_DESCRIPTOR)
  745. UL_ALLOCATE_ARRAY(
  746. PagedPool,
  747. UCHAR,
  748. DescSize,
  749. UL_TCI_INTERFACE_POOL_TAG
  750. );
  751. if ( pTcIfc->pAddressListDesc == NULL )
  752. {
  753. UL_FREE_POOL_WITH_SIG(pTcIfc, UL_TCI_INTERFACE_POOL_TAG);
  754. return NULL;
  755. }
  756. CREATE_REF_TRACE_LOG(
  757. pTcIfc->pTraceLog,
  758. 96 - REF_TRACE_OVERHEAD,
  759. 0,
  760. TRACELOG_LOW_PRIORITY,
  761. UL_TCI_INTERFACE_REF_TRACE_LOG_POOL_TAG
  762. );
  763. INT_TRACE(pTcIfc, TC_ALLOC);
  764. pTcIfc->AddrListBytesCount = DescSize;
  765. // Copy the instance name string data
  766. RtlCopyMemory(pTcIfc->Name,Name,NameLength);
  767. pTcIfc->NameLength = (USHORT)NameLength;
  768. pTcIfc->Name[NameLength/sizeof(WCHAR)] = UNICODE_NULL;
  769. // Copy the instance ID string data
  770. RtlCopyMemory(pTcIfc->InstanceID,InstanceID,InstanceIDLength);
  771. pTcIfc->InstanceIDLength = (USHORT)InstanceIDLength;
  772. pTcIfc->InstanceID[InstanceIDLength/sizeof(WCHAR)] = UNICODE_NULL;
  773. // Copy the Description data and extract the corresponding ip address
  774. RtlCopyMemory(pTcIfc->pAddressListDesc, Desc, DescSize);
  775. // IP Address of the interface is hidden in this desc data
  776. // we will find out and save it for faster lookup.
  777. pTcIfc->IsQoSEnabled = (BOOLEAN)
  778. (pTcIfc->pAddressListDesc->AddressList.AddressCount != 0);
  779. return pTcIfc;
  780. }
  781. /***************************************************************************++
  782. Routine Description:
  783. Frees up the
  784. - Adress list descriptor
  785. - RefTrace log
  786. - The interface structure
  787. Argument:
  788. pTcIfc Pointer to the interface struct.
  789. --***************************************************************************/
  790. VOID
  791. UlpTcFreeInterface(
  792. IN OUT PUL_TCI_INTERFACE pTcIfc
  793. )
  794. {
  795. PAGED_CODE();
  796. //
  797. // Do the cleanup.
  798. //
  799. if (pTcIfc)
  800. {
  801. DESTROY_REF_TRACE_LOG(
  802. pTcIfc->pTraceLog,
  803. UL_TCI_INTERFACE_REF_TRACE_LOG_POOL_TAG
  804. );
  805. if (pTcIfc->pAddressListDesc)
  806. {
  807. UL_FREE_POOL(pTcIfc->pAddressListDesc,
  808. UL_TCI_INTERFACE_POOL_TAG
  809. );
  810. }
  811. UL_FREE_POOL_WITH_SIG(pTcIfc, UL_TCI_INTERFACE_POOL_TAG);
  812. }
  813. }
  814. /***************************************************************************++
  815. Routine Description:
  816. Make a Wmi Querry to get the firendly names of all interfaces.
  817. Its basically replica of the tcdll enumerate interfaces call.
  818. This function also allocates the global interface list. If it's not
  819. successfull it doesn't though.
  820. Return Value:
  821. NTSTATUS - Completion status.
  822. --***************************************************************************/
  823. NTSTATUS
  824. UlpTcGetFriendlyNames(
  825. VOID
  826. )
  827. {
  828. NTSTATUS Status;
  829. PVOID WmiObject;
  830. ULONG MyBufferSize;
  831. PWNODE_ALL_DATA pWnode;
  832. PWNODE_ALL_DATA pWnodeBuffer;
  833. PUL_TCI_INTERFACE pTcIfc;
  834. GUID QoSGuid;
  835. PLIST_ENTRY pEntry;
  836. PUL_TCI_INTERFACE pInterface;
  837. //
  838. // Initialize defaults
  839. //
  840. Status = STATUS_SUCCESS;
  841. WmiObject = NULL;
  842. pWnodeBuffer = NULL;
  843. pTcIfc = NULL;
  844. MyBufferSize = UL_DEFAULT_WMI_QUERY_BUFFER_SIZE;
  845. QoSGuid = GUID_QOS_TC_SUPPORTED;
  846. //
  847. // Get a WMI block handle to the GUID_QOS_SUPPORTED
  848. //
  849. Status = IoWMIOpenBlock( (GUID *) &QoSGuid, 0, &WmiObject );
  850. if (!NT_SUCCESS(Status))
  851. {
  852. if (Status == STATUS_WMI_GUID_NOT_FOUND)
  853. {
  854. // This means there is no TC data provider (which's Psched)
  855. UlTrace(
  856. TC,
  857. ("Http!UlpTcGetFriendlyNames: PSCHED hasn't been "
  858. "installed !\n"));
  859. }
  860. else
  861. {
  862. UlTrace(
  863. TC,
  864. ("Http!UlpTcGetFriendlyNames:IoWMIOpenBlock FAILED Status "
  865. "%08lx\n", Status));
  866. }
  867. return Status;
  868. }
  869. do
  870. {
  871. //
  872. // Allocate a private buffer to retrieve all wnodes
  873. //
  874. pWnodeBuffer = (PWNODE_ALL_DATA) UL_ALLOCATE_ARRAY(
  875. NonPagedPool,
  876. UCHAR,
  877. MyBufferSize,
  878. UL_TCI_WMI_POOL_TAG
  879. );
  880. if (pWnodeBuffer == NULL)
  881. {
  882. ObDereferenceObject(WmiObject);
  883. return STATUS_NO_MEMORY;
  884. }
  885. __try
  886. {
  887. Status = IoWMIQueryAllData(WmiObject, &MyBufferSize, pWnodeBuffer);
  888. UlTrace( TC,
  889. ("Http!UlpTcGetFriendlyNames: IoWMIQueryAllData Status %08lx\n",
  890. Status
  891. ));
  892. }
  893. __except ( UL_EXCEPTION_FILTER() )
  894. {
  895. Status = GetExceptionCode();
  896. }
  897. if (Status == STATUS_BUFFER_TOO_SMALL)
  898. {
  899. //
  900. // Failed since the buffer was too small.
  901. // Release the buffer and double the size.
  902. //
  903. MyBufferSize *= 2;
  904. UL_FREE_POOL( pWnodeBuffer, UL_TCI_WMI_POOL_TAG );
  905. pWnodeBuffer = NULL;
  906. }
  907. } while (Status == STATUS_BUFFER_TOO_SMALL);
  908. if (NT_SUCCESS(Status))
  909. {
  910. ULONG dwInstanceNum;
  911. ULONG InstanceSize = 0;
  912. PULONG lpdwNameOffsets;
  913. BOOLEAN bFixedSize = FALSE;
  914. USHORT usNameLength;
  915. ULONG DescSize;
  916. PTC_SUPPORTED_INFO_BUFFER pTcInfoBuffer = NULL;
  917. pWnode = pWnodeBuffer;
  918. ASSERT(pWnode->WnodeHeader.Flags & WNODE_FLAG_ALL_DATA);
  919. do
  920. {
  921. //
  922. // Check for fixed instance size
  923. //
  924. if (pWnode->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE)
  925. {
  926. InstanceSize = pWnode->FixedInstanceSize;
  927. bFixedSize = TRUE;
  928. pTcInfoBuffer =
  929. (PTC_SUPPORTED_INFO_BUFFER)OffsetToPtr(
  930. pWnode,
  931. pWnode->DataBlockOffset);
  932. }
  933. //
  934. // Get a pointer to the array of offsets to the instance names
  935. //
  936. lpdwNameOffsets = (PULONG) OffsetToPtr(
  937. pWnode,
  938. pWnode->OffsetInstanceNameOffsets);
  939. for ( dwInstanceNum = 0;
  940. dwInstanceNum < pWnode->InstanceCount;
  941. dwInstanceNum++ )
  942. {
  943. usNameLength = *(PUSHORT)OffsetToPtr(
  944. pWnode,
  945. lpdwNameOffsets[dwInstanceNum]);
  946. //
  947. // Length and offset for variable data
  948. //
  949. if ( !bFixedSize )
  950. {
  951. InstanceSize =
  952. pWnode->OffsetInstanceDataAndLength[
  953. dwInstanceNum].LengthInstanceData;
  954. pTcInfoBuffer = (PTC_SUPPORTED_INFO_BUFFER)
  955. OffsetToPtr(
  956. (PBYTE)pWnode,
  957. pWnode->OffsetInstanceDataAndLength[
  958. dwInstanceNum].OffsetInstanceData);
  959. }
  960. //
  961. // We have all that is needed.
  962. //
  963. ASSERT(usNameLength < MAX_STRING_LENGTH);
  964. DescSize = InstanceSize - FIELD_OFFSET(
  965. TC_SUPPORTED_INFO_BUFFER,
  966. AddrListDesc
  967. );
  968. //
  969. // Allocate a new interface structure & initialize it with
  970. // the wmi data we have acquired.
  971. //
  972. pTcIfc = UlpTcAllocateInterface(
  973. DescSize,
  974. &pTcInfoBuffer->AddrListDesc,
  975. usNameLength,
  976. (PUCHAR) OffsetToPtr(
  977. pWnode,
  978. lpdwNameOffsets[dwInstanceNum] +
  979. sizeof(USHORT)),
  980. pTcInfoBuffer->InstanceIDLength,
  981. (PUCHAR) &pTcInfoBuffer->InstanceID[0]
  982. );
  983. if ( pTcIfc == NULL )
  984. {
  985. Status = STATUS_NO_MEMORY;
  986. goto end;
  987. }
  988. //
  989. // Get the interface index from TCP
  990. //
  991. Status = UlpTcGetInterfaceIndex( pTcIfc );
  992. ASSERT(NT_SUCCESS(Status));
  993. //
  994. // Add this interface to the global interface list
  995. //
  996. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  997. InsertTailList(&g_TciIfcListHead, &pTcIfc->Linkage );
  998. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  999. //
  1000. // Set to Null so we don't try to cleanup after we insert it
  1001. // to the global list.
  1002. //
  1003. pTcIfc = NULL;
  1004. }
  1005. //
  1006. // Update Wnode to point to next node
  1007. //
  1008. if ( pWnode->WnodeHeader.Linkage != 0)
  1009. {
  1010. pWnode = (PWNODE_ALL_DATA) OffsetToPtr( pWnode,
  1011. pWnode->WnodeHeader.Linkage);
  1012. }
  1013. else
  1014. {
  1015. pWnode = NULL;
  1016. }
  1017. }
  1018. while ( pWnode != NULL && NT_SUCCESS(Status) );
  1019. UlTrace(TC,("Http!UlpTcGetFriendlyNames: got all the names.\n"));
  1020. }
  1021. end:
  1022. if (!NT_SUCCESS(Status))
  1023. {
  1024. UlTrace(TC,("Http!UlpTcGetFriendlyNames: FAILED Status %08lx\n",
  1025. Status
  1026. ));
  1027. if (pTcIfc)
  1028. {
  1029. UlpTcFreeInterface( pTcIfc );
  1030. }
  1031. //
  1032. // Cleanup the partially done interface list if not empty
  1033. //
  1034. while ( !IsListEmpty( &g_TciIfcListHead ) )
  1035. {
  1036. pEntry = g_TciIfcListHead.Flink;
  1037. pInterface = CONTAINING_RECORD( pEntry,
  1038. UL_TCI_INTERFACE,
  1039. Linkage
  1040. );
  1041. RemoveEntryList( pEntry );
  1042. UlpTcFreeInterface( pInterface );
  1043. }
  1044. }
  1045. //
  1046. // Release resources and close WMI handle
  1047. //
  1048. if (WmiObject != NULL)
  1049. {
  1050. ObDereferenceObject(WmiObject);
  1051. }
  1052. if (pWnodeBuffer)
  1053. {
  1054. UL_FREE_POOL(pWnodeBuffer, UL_TCI_WMI_POOL_TAG);
  1055. }
  1056. return Status;
  1057. }
  1058. /***************************************************************************++
  1059. Routine Description:
  1060. UlpTcReleaseAll :
  1061. Close all interfaces, all flows and all filters.
  1062. Also deregister GPC clients and release all TC ineterfaces.
  1063. Return Value:
  1064. NTSTATUS - Completion status.
  1065. --***************************************************************************/
  1066. NTSTATUS
  1067. UlpTcReleaseAll(
  1068. VOID
  1069. )
  1070. {
  1071. NTSTATUS Status;
  1072. //
  1073. // Close all interfaces their flows & filters
  1074. //
  1075. UlpTcCloseAllInterfaces();
  1076. //
  1077. // DeRegister the QoS GpcClient
  1078. //
  1079. Status = UlpTcDeRegisterGpcClient();
  1080. if (!NT_SUCCESS(Status))
  1081. {
  1082. UlTrace( TC, ("Http!UlpTcReleaseAll: FAILURE %08lx \n", Status ));
  1083. }
  1084. //
  1085. // Finally close our gpc file handle
  1086. //
  1087. ZwClose(g_GpcFileHandle);
  1088. return Status;
  1089. }
  1090. /***************************************************************************++
  1091. Routine Description:
  1092. UlpTcCloseAllInterfaces :
  1093. Return Value:
  1094. NTSTATUS - Completion status.
  1095. --***************************************************************************/
  1096. NTSTATUS
  1097. UlpTcCloseAllInterfaces(
  1098. VOID
  1099. )
  1100. {
  1101. NTSTATUS Status;
  1102. PLIST_ENTRY pEntry;
  1103. PUL_TCI_INTERFACE pInterface;
  1104. Status = STATUS_SUCCESS;
  1105. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1106. //
  1107. // Close all interfaces in our global list
  1108. //
  1109. while ( !IsListEmpty( &g_TciIfcListHead ) )
  1110. {
  1111. pEntry = g_TciIfcListHead.Flink;
  1112. pInterface = CONTAINING_RECORD( pEntry,
  1113. UL_TCI_INTERFACE,
  1114. Linkage
  1115. );
  1116. UlpTcCloseInterface( pInterface );
  1117. RemoveEntryList( pEntry );
  1118. UlpTcFreeInterface( pInterface );
  1119. }
  1120. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1121. return Status;
  1122. }
  1123. /***************************************************************************++
  1124. Routine Description:
  1125. Cleans up all the flows on the interface.
  1126. Arguments:
  1127. pInterface - to be closed
  1128. --***************************************************************************/
  1129. NTSTATUS
  1130. UlpTcCloseInterface(
  1131. PUL_TCI_INTERFACE pInterface
  1132. )
  1133. {
  1134. NTSTATUS Status;
  1135. PLIST_ENTRY pEntry;
  1136. PUL_TCI_FLOW pFlow;
  1137. PAGED_CODE();
  1138. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  1139. INT_TRACE(pInterface, TC_CLOSE);
  1140. //
  1141. // Go clean up all flows for the interface and remove itself as well
  1142. //
  1143. Status = STATUS_SUCCESS;
  1144. while (!IsListEmpty(&pInterface->FlowList))
  1145. {
  1146. pEntry= pInterface->FlowList.Flink;
  1147. pFlow = CONTAINING_RECORD(
  1148. pEntry,
  1149. UL_TCI_FLOW,
  1150. Linkage
  1151. );
  1152. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  1153. //
  1154. // Remove flow from the corresponding owner's flowlist
  1155. // as well. Owner pointer should not be null for a flow.
  1156. //
  1157. ASSERT_FLOW_OWNER(pFlow->pOwner);
  1158. RemoveEntryList(&pFlow->Siblings);
  1159. pFlow->Siblings.Flink = pFlow->Siblings.Blink = NULL;
  1160. pFlow->pOwner = NULL;
  1161. //
  1162. // Now remove from the interface.
  1163. //
  1164. Status = UlpTcDeleteFlow(pFlow);
  1165. //
  1166. // Above call may fail,if GPC removes the flow based on PSCHED's
  1167. // notification before we get a chance to close our GPC handle.
  1168. //
  1169. }
  1170. UlTrace(TC,("Http!UlpTcCloseInterface: All flows deleted on Ifc @ %p\n",
  1171. pInterface ));
  1172. return Status;
  1173. }
  1174. /***************************************************************************++
  1175. Routine Description:
  1176. UlpTcWalkWnode :
  1177. Arguments:
  1178. ... the WMI provided data buffer ...
  1179. --***************************************************************************/
  1180. NTSTATUS
  1181. UlpTcWalkWnode(
  1182. IN PWNODE_HEADER pWnodeHdr,
  1183. IN PUL_TC_NOTIF_HANDLER pNotifHandler
  1184. )
  1185. {
  1186. NTSTATUS Status;
  1187. PWCHAR NamePtr;
  1188. USHORT NameSize;
  1189. PUCHAR DataBuffer;
  1190. ULONG DataSize;
  1191. ULONG Flags;
  1192. PULONG NameOffset;
  1193. //
  1194. // Try to capture the data frm WMI Buffer
  1195. //
  1196. ASSERT(pNotifHandler);
  1197. Status = STATUS_SUCCESS;
  1198. Flags = pWnodeHdr->Flags;
  1199. if (Flags & WNODE_FLAG_ALL_DATA)
  1200. {
  1201. //
  1202. // WNODE_ALL_DATA structure has multiple interfaces
  1203. //
  1204. PWNODE_ALL_DATA pWnode = (PWNODE_ALL_DATA)pWnodeHdr;
  1205. ULONG Instance;
  1206. UlTrace(TC,("Http!UlpTcWalkWnode: ALL_DATA ... \n" ));
  1207. NameOffset = (PULONG) OffsetToPtr(pWnode,
  1208. pWnode->OffsetInstanceNameOffsets );
  1209. DataBuffer = (PUCHAR) OffsetToPtr(pWnode,
  1210. pWnode->DataBlockOffset);
  1211. for (Instance = 0;
  1212. Instance < pWnode->InstanceCount;
  1213. Instance++)
  1214. {
  1215. // Instance Name
  1216. NamePtr = (PWCHAR) OffsetToPtr(pWnode,NameOffset[Instance] + sizeof(USHORT));
  1217. NameSize = * (PUSHORT) OffsetToPtr(pWnode,NameOffset[Instance]);
  1218. // Instance Data
  1219. if ( Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE )
  1220. {
  1221. DataSize = pWnode->FixedInstanceSize;
  1222. }
  1223. else
  1224. {
  1225. DataSize =
  1226. pWnode->OffsetInstanceDataAndLength[Instance].LengthInstanceData;
  1227. DataBuffer =
  1228. (PUCHAR)OffsetToPtr(pWnode,
  1229. pWnode->OffsetInstanceDataAndLength[Instance].OffsetInstanceData);
  1230. }
  1231. // Call the handler
  1232. pNotifHandler( NamePtr, NameSize, (PTC_INDICATION_BUFFER) DataBuffer, DataSize );
  1233. }
  1234. }
  1235. else if (Flags & WNODE_FLAG_SINGLE_INSTANCE)
  1236. {
  1237. //
  1238. // WNODE_SINGLE_INSTANCE structure has only one instance
  1239. //
  1240. PWNODE_SINGLE_INSTANCE pWnode = (PWNODE_SINGLE_INSTANCE)pWnodeHdr;
  1241. if (Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES)
  1242. {
  1243. return STATUS_SUCCESS;
  1244. }
  1245. UlTrace(TC,("Http!UlpTcWalkWnode: SINGLE_INSTANCE ... \n" ));
  1246. NamePtr = (PWCHAR)OffsetToPtr(pWnode,pWnode->OffsetInstanceName + sizeof(USHORT));
  1247. NameSize = * (USHORT *) OffsetToPtr(pWnode,pWnode->OffsetInstanceName);
  1248. // Instance Data
  1249. DataSize = pWnode->SizeDataBlock;
  1250. DataBuffer = (PUCHAR)OffsetToPtr (pWnode, pWnode->DataBlockOffset);
  1251. // Call the handler
  1252. pNotifHandler( NamePtr, NameSize, (PTC_INDICATION_BUFFER) DataBuffer, DataSize );
  1253. }
  1254. else if (Flags & WNODE_FLAG_SINGLE_ITEM)
  1255. {
  1256. //
  1257. // WNODE_SINGLE_ITEM is almost identical to single_instance
  1258. //
  1259. PWNODE_SINGLE_ITEM pWnode = (PWNODE_SINGLE_ITEM)pWnodeHdr;
  1260. if (Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES)
  1261. {
  1262. return STATUS_SUCCESS;
  1263. }
  1264. UlTrace(TC,("Http!UlpTcWalkWnode: SINGLE_ITEM ... \n" ));
  1265. NamePtr = (PWCHAR)OffsetToPtr(pWnode,pWnode->OffsetInstanceName + sizeof(USHORT));
  1266. NameSize = * (USHORT *) OffsetToPtr(pWnode, pWnode->OffsetInstanceName);
  1267. // Instance Data
  1268. DataSize = pWnode->SizeDataItem;
  1269. DataBuffer = (PUCHAR)OffsetToPtr (pWnode, pWnode->DataBlockOffset);
  1270. // Call the handler
  1271. pNotifHandler( NamePtr, NameSize, (PTC_INDICATION_BUFFER) DataBuffer, DataSize );
  1272. }
  1273. return Status;
  1274. }
  1275. /***************************************************************************++
  1276. Routine Description:
  1277. UlpTcHandleIfcUp :
  1278. This functions handles the interface change notifications.
  1279. We register for the corresponding notifications during init.
  1280. Arguments:
  1281. PVOID Wnode - PSched data provided with WMI way
  1282. --***************************************************************************/
  1283. VOID
  1284. UlpTcHandleIfcUp(
  1285. IN PWSTR Name,
  1286. IN ULONG NameSize,
  1287. IN PTC_INDICATION_BUFFER pTcBuffer,
  1288. IN ULONG BufferSize
  1289. )
  1290. {
  1291. NTSTATUS Status;
  1292. ULONG AddrListDescSize;
  1293. PTC_SUPPORTED_INFO_BUFFER pTcInfoBuffer;
  1294. PUL_TCI_INTERFACE pTcIfc;
  1295. PUL_TCI_INTERFACE pTcIfcTemp;
  1296. PLIST_ENTRY pEntry;
  1297. Status = STATUS_SUCCESS;
  1298. UlTrace(TC,("Http!UlpTcHandleIfcUp: Adding %ws %d\n", Name, BufferSize ));
  1299. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1300. //
  1301. // Allocate a new interface structure for the newcoming interface
  1302. //
  1303. AddrListDescSize = BufferSize
  1304. - FIELD_OFFSET(TC_INDICATION_BUFFER,InfoBuffer)
  1305. - FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc);
  1306. UlTrace(TC,("Http!UlpTcHandleIfcUp: AddrListDescSize %d\n", AddrListDescSize ));
  1307. pTcInfoBuffer = & pTcBuffer->InfoBuffer;
  1308. pTcIfc = UlpTcAllocateInterface(
  1309. AddrListDescSize,
  1310. &pTcInfoBuffer->AddrListDesc,
  1311. NameSize,
  1312. (PUCHAR) Name,
  1313. pTcInfoBuffer->InstanceIDLength,
  1314. (PUCHAR) &pTcInfoBuffer->InstanceID[0]
  1315. );
  1316. if ( pTcIfc == NULL )
  1317. {
  1318. Status = STATUS_NO_MEMORY;
  1319. goto end;
  1320. }
  1321. UL_DUMP_TC_INTERFACE( pTcIfc );
  1322. //
  1323. // If we are receiving a notification for an interface already exist then
  1324. // drop this call. Prevent global interface list corruption if we receive
  1325. // inconsistent notifications. But there may be multiple interfaces with
  1326. // same zero IPs.
  1327. //
  1328. pEntry = g_TciIfcListHead.Flink;
  1329. while ( pEntry != &g_TciIfcListHead )
  1330. {
  1331. pTcIfcTemp = CONTAINING_RECORD( pEntry, UL_TCI_INTERFACE, Linkage );
  1332. if (wcsncmp(pTcIfcTemp->Name, pTcIfc->Name, NameSize/sizeof(WCHAR))==0)
  1333. {
  1334. ASSERT(!"Conflict in the global interface list !");
  1335. Status = STATUS_CONFLICTING_ADDRESSES;
  1336. goto end;
  1337. }
  1338. pEntry = pEntry->Flink;
  1339. }
  1340. //
  1341. // Get the interface index from TCP.
  1342. //
  1343. Status = UlpTcGetInterfaceIndex( pTcIfc );
  1344. if (!NT_SUCCESS(Status))
  1345. goto end;
  1346. //
  1347. // Insert to the global interface list
  1348. //
  1349. InsertTailList( &g_TciIfcListHead, &pTcIfc->Linkage );
  1350. INT_TRACE(pTcIfc, TC_UP);
  1351. end:
  1352. if (!NT_SUCCESS(Status))
  1353. {
  1354. UlTrace(TC,("Http!UlpTcHandleIfcUp: FAILURE %08lx \n", Status ));
  1355. if (pTcIfc != NULL)
  1356. {
  1357. UlpTcFreeInterface(pTcIfc);
  1358. }
  1359. }
  1360. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1361. return;
  1362. }
  1363. /***************************************************************************++
  1364. Routine Description:
  1365. UlpTcHandleIfcDown :
  1366. This functions handles the interface change notifications.
  1367. We register for the corresponding notifications during init.
  1368. Arguments:
  1369. PVOID Wnode - PSched data provided with WMI way
  1370. --***************************************************************************/
  1371. VOID
  1372. UlpTcHandleIfcDown(
  1373. IN PWSTR Name,
  1374. IN ULONG NameSize,
  1375. IN PTC_INDICATION_BUFFER pTcBuffer,
  1376. IN ULONG BufferSize
  1377. )
  1378. {
  1379. NTSTATUS Status;
  1380. PUL_TCI_INTERFACE pTcIfc;
  1381. PUL_TCI_INTERFACE pTcIfcTemp;
  1382. PLIST_ENTRY pEntry;
  1383. UNREFERENCED_PARAMETER(pTcBuffer);
  1384. UNREFERENCED_PARAMETER(BufferSize);
  1385. Status = STATUS_SUCCESS;
  1386. UlTrace(TC,("Http!UlpTcHandleIfcDown: Removing %ws\n", Name ));
  1387. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1388. //
  1389. // Find the corresponding ifc structure we keep.
  1390. //
  1391. pTcIfc = NULL;
  1392. pEntry = g_TciIfcListHead.Flink;
  1393. while ( pEntry != &g_TciIfcListHead )
  1394. {
  1395. pTcIfcTemp = CONTAINING_RECORD( pEntry, UL_TCI_INTERFACE, Linkage );
  1396. if ( wcsncmp(pTcIfcTemp->Name, Name, NameSize) == 0 )
  1397. {
  1398. pTcIfc = pTcIfcTemp;
  1399. break;
  1400. }
  1401. pEntry = pEntry->Flink;
  1402. }
  1403. if (pTcIfc == NULL)
  1404. {
  1405. ASSERT(FALSE);
  1406. Status = STATUS_NOT_FOUND;
  1407. goto end;
  1408. }
  1409. INT_TRACE(pTcIfc, TC_DOWN);
  1410. //
  1411. // Remove this interface and its flows etc ...
  1412. //
  1413. UlpTcCloseInterface( pTcIfc );
  1414. RemoveEntryList( &pTcIfc->Linkage );
  1415. UlpTcFreeInterface( pTcIfc );
  1416. end:
  1417. if (!NT_SUCCESS(Status))
  1418. {
  1419. UlTrace(TC,("Http!UlpTcHandleIfcDown: FAILURE %08lx \n", Status ));
  1420. }
  1421. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1422. return;
  1423. }
  1424. /***************************************************************************++
  1425. Routine Description:
  1426. UlpTcHandleIfcChange :
  1427. This functions handles the interface change notifications.
  1428. We register for the corresponding notifications during init.
  1429. Arguments:
  1430. PVOID Wnode - PSched data provided with WMI way
  1431. --***************************************************************************/
  1432. VOID
  1433. UlpTcHandleIfcChange(
  1434. IN PWSTR Name,
  1435. IN ULONG NameSize,
  1436. IN PTC_INDICATION_BUFFER pTcBuffer,
  1437. IN ULONG BufferSize
  1438. )
  1439. {
  1440. NTSTATUS Status;
  1441. ULONG AddrListDescSize;
  1442. PTC_SUPPORTED_INFO_BUFFER pTcInfoBuffer;
  1443. PUL_TCI_INTERFACE pTcIfc;
  1444. PUL_TCI_INTERFACE pTcIfcTemp;
  1445. PLIST_ENTRY pEntry;
  1446. PADDRESS_LIST_DESCRIPTOR pAddressListDesc;
  1447. Status = STATUS_SUCCESS;
  1448. UlTrace(TC,("Http!UlpTcHandleIfcChange: Updating %ws\n", Name ));
  1449. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1450. AddrListDescSize = BufferSize
  1451. - FIELD_OFFSET(TC_INDICATION_BUFFER,InfoBuffer)
  1452. - FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc);
  1453. pTcInfoBuffer = & pTcBuffer->InfoBuffer;
  1454. // Find the corresponding ifc structure we keep.
  1455. pTcIfc = NULL;
  1456. pEntry = g_TciIfcListHead.Flink;
  1457. while ( pEntry != &g_TciIfcListHead )
  1458. {
  1459. pTcIfcTemp = CONTAINING_RECORD( pEntry, UL_TCI_INTERFACE, Linkage );
  1460. if ( wcsncmp(pTcIfcTemp->Name, Name, NameSize) == 0 )
  1461. {
  1462. pTcIfc = pTcIfcTemp;
  1463. break;
  1464. }
  1465. pEntry = pEntry->Flink;
  1466. }
  1467. if (pTcIfc == NULL)
  1468. {
  1469. ASSERT(FALSE);
  1470. Status = STATUS_NOT_FOUND;
  1471. goto end;
  1472. }
  1473. INT_TRACE(pTcIfc, TC_CHANGE);
  1474. // Instance id
  1475. RtlCopyMemory(pTcIfc->InstanceID,
  1476. pTcInfoBuffer->InstanceID,
  1477. pTcInfoBuffer->InstanceIDLength
  1478. );
  1479. pTcIfc->InstanceIDLength = pTcInfoBuffer->InstanceIDLength;
  1480. pTcIfc->InstanceID[pTcIfc->InstanceIDLength/sizeof(WCHAR)] = UNICODE_NULL;
  1481. // The Description data and extract the corresponding ip address
  1482. // ReWrite the fresh data. Size of the description data might be changed
  1483. // so wee need to dynamically allocate it everytime changes
  1484. pAddressListDesc =
  1485. (PADDRESS_LIST_DESCRIPTOR) UL_ALLOCATE_ARRAY(
  1486. PagedPool,
  1487. UCHAR,
  1488. AddrListDescSize,
  1489. UL_TCI_INTERFACE_POOL_TAG
  1490. );
  1491. if ( pAddressListDesc == NULL )
  1492. {
  1493. Status = STATUS_NO_MEMORY;
  1494. goto end;
  1495. }
  1496. if (pTcIfc->pAddressListDesc)
  1497. {
  1498. UL_FREE_POOL(pTcIfc->pAddressListDesc,UL_TCI_INTERFACE_POOL_TAG);
  1499. }
  1500. pTcIfc->pAddressListDesc = pAddressListDesc;
  1501. pTcIfc->AddrListBytesCount = AddrListDescSize;
  1502. RtlCopyMemory( pTcIfc->pAddressListDesc,
  1503. &pTcInfoBuffer->AddrListDesc,
  1504. AddrListDescSize
  1505. );
  1506. // IP Address of the interface is hidden in this desc data
  1507. pTcIfc->IsQoSEnabled = (BOOLEAN)
  1508. (pTcIfc->pAddressListDesc->AddressList.AddressCount != 0);
  1509. // ReFresh the interface index from TCP.
  1510. Status = UlpTcGetInterfaceIndex( pTcIfc );
  1511. if (!NT_SUCCESS(Status))
  1512. goto end;
  1513. end:
  1514. if (!NT_SUCCESS(Status))
  1515. {
  1516. UlTrace(TC,("Http!UlpTcHandleIfcChange: FAILURE %08lx \n", Status ));
  1517. }
  1518. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  1519. return;
  1520. }
  1521. /***************************************************************************++
  1522. Routine Description:
  1523. UlTcNotifyCallback :
  1524. This callback functions handles the interface change notifications.
  1525. We register for the corresponding notifications during init.
  1526. Arguments:
  1527. PVOID Wnode - PSched data provided with WMI way
  1528. --***************************************************************************/
  1529. VOID
  1530. UlTcNotifyCallback(
  1531. IN PVOID pWnode,
  1532. IN PVOID Context
  1533. )
  1534. {
  1535. GUID *pGuid;
  1536. PWNODE_HEADER pWnodeHeader;
  1537. UNREFERENCED_PARAMETER(Context);
  1538. UlTrace( TC, ("Http!UlTcNotifyCallback: ... \n" ));
  1539. pWnodeHeader = (PWNODE_HEADER) pWnode;
  1540. pGuid = &pWnodeHeader->Guid;
  1541. if (UL_COMPARE_QOS_NOTIFICATION(pGuid,&GUID_QOS_TC_INTERFACE_UP_INDICATION))
  1542. {
  1543. UlpTcWalkWnode( pWnodeHeader, UlpTcHandleIfcUp );
  1544. }
  1545. else if
  1546. (UL_COMPARE_QOS_NOTIFICATION(pGuid, &GUID_QOS_TC_INTERFACE_DOWN_INDICATION))
  1547. {
  1548. UlpTcWalkWnode( pWnodeHeader, UlpTcHandleIfcDown );
  1549. }
  1550. else if
  1551. (UL_COMPARE_QOS_NOTIFICATION(pGuid, &GUID_QOS_TC_INTERFACE_CHANGE_INDICATION))
  1552. {
  1553. UlpTcWalkWnode( pWnodeHeader, UlpTcHandleIfcChange );
  1554. }
  1555. UlTrace( TC, ("Http!UlTcNotifyCallback: Handled.\n" ));
  1556. }
  1557. /***************************************************************************++
  1558. Routine Description:
  1559. UlpTcRegisterForCallbacks :
  1560. We will open Block object until termination for each type of
  1561. notification. And we will deref each object upon termination
  1562. Return Value:
  1563. NTSTATUS - Completion status.
  1564. --***************************************************************************/
  1565. NTSTATUS
  1566. UlpTcRegisterForCallbacks(
  1567. VOID
  1568. )
  1569. {
  1570. NTSTATUS Status = STATUS_SUCCESS;
  1571. GUID Guid;
  1572. //
  1573. // Get a WMI block handle register all the callback functions.
  1574. //
  1575. Guid = GUID_QOS_TC_INTERFACE_UP_INDICATION;
  1576. Status = IoWMIOpenBlock(&Guid,
  1577. WMIGUID_NOTIFICATION,
  1578. &g_TcInterfaceUpNotificationObject
  1579. );
  1580. if (NT_SUCCESS(Status))
  1581. {
  1582. Status = IoWMISetNotificationCallback(
  1583. g_TcInterfaceUpNotificationObject,
  1584. (WMI_NOTIFICATION_CALLBACK) UlTcNotifyCallback,
  1585. NULL
  1586. );
  1587. if (!NT_SUCCESS(Status))
  1588. goto end;
  1589. }
  1590. Guid = GUID_QOS_TC_INTERFACE_DOWN_INDICATION;
  1591. Status = IoWMIOpenBlock(&Guid,
  1592. WMIGUID_NOTIFICATION,
  1593. &g_TcInterfaceDownNotificationObject
  1594. );
  1595. if (NT_SUCCESS(Status))
  1596. {
  1597. Status = IoWMISetNotificationCallback(
  1598. g_TcInterfaceDownNotificationObject,
  1599. (WMI_NOTIFICATION_CALLBACK) UlTcNotifyCallback,
  1600. NULL
  1601. );
  1602. if (!NT_SUCCESS(Status))
  1603. goto end;
  1604. }
  1605. Guid = GUID_QOS_TC_INTERFACE_CHANGE_INDICATION;
  1606. Status = IoWMIOpenBlock(&Guid,
  1607. WMIGUID_NOTIFICATION,
  1608. &g_TcInterfaceChangeNotificationObject
  1609. );
  1610. if (NT_SUCCESS(Status))
  1611. {
  1612. Status = IoWMISetNotificationCallback(
  1613. g_TcInterfaceChangeNotificationObject,
  1614. (WMI_NOTIFICATION_CALLBACK) UlTcNotifyCallback,
  1615. NULL
  1616. );
  1617. if (!NT_SUCCESS(Status))
  1618. goto end;
  1619. }
  1620. end:
  1621. // Cleanup if necessary
  1622. if (!NT_SUCCESS(Status))
  1623. {
  1624. UlTrace(TC,("Http!UlpTcRegisterForCallbacks: FAILED %08lx\n",Status));
  1625. if(g_TcInterfaceUpNotificationObject!=NULL)
  1626. {
  1627. ObDereferenceObject(g_TcInterfaceUpNotificationObject);
  1628. g_TcInterfaceUpNotificationObject = NULL;
  1629. }
  1630. if(g_TcInterfaceDownNotificationObject!=NULL)
  1631. {
  1632. ObDereferenceObject(g_TcInterfaceDownNotificationObject);
  1633. g_TcInterfaceDownNotificationObject = NULL;
  1634. }
  1635. if(g_TcInterfaceChangeNotificationObject!=NULL)
  1636. {
  1637. ObDereferenceObject(g_TcInterfaceChangeNotificationObject);
  1638. g_TcInterfaceChangeNotificationObject = NULL;
  1639. }
  1640. }
  1641. return Status;
  1642. }
  1643. //
  1644. // Following functions provide public/private interfaces for flow & filter
  1645. // creation/removal/modification for site & global flows.
  1646. //
  1647. /***************************************************************************++
  1648. Routine Description:
  1649. UlpTcDeleteFlow :
  1650. you should own the TciIfcPushLock exclusively before calling
  1651. this function
  1652. Arguments:
  1653. Return Value:
  1654. NTSTATUS - Completion status.
  1655. --***************************************************************************/
  1656. NTSTATUS
  1657. UlpTcDeleteFlow(
  1658. IN PUL_TCI_FLOW pFlow
  1659. )
  1660. {
  1661. NTSTATUS Status;
  1662. PLIST_ENTRY pEntry;
  1663. PUL_TCI_FILTER pFilter;
  1664. HANDLE FlowHandle;
  1665. PUL_TCI_INTERFACE pInterface;
  1666. //
  1667. // Initialize
  1668. //
  1669. PAGED_CODE();
  1670. Status = STATUS_SUCCESS;
  1671. ASSERT(g_InitTciCalled);
  1672. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  1673. //
  1674. // First remove all the filters belong to us
  1675. //
  1676. while (!IsListEmpty(&pFlow->FilterList))
  1677. {
  1678. pEntry = pFlow->FilterList.Flink;
  1679. pFilter = CONTAINING_RECORD(
  1680. pEntry,
  1681. UL_TCI_FILTER,
  1682. Linkage
  1683. );
  1684. Status = UlpTcDeleteFilter( pFlow, pFilter );
  1685. ASSERT(NT_SUCCESS(Status));
  1686. }
  1687. //
  1688. // Now remove the flow itself from our flowlist on the interface
  1689. //
  1690. pInterface = pFlow->pInterface;
  1691. ASSERT( pInterface != NULL );
  1692. RemoveEntryList( &pFlow->Linkage );
  1693. ASSERT(pInterface->FlowListSize > 0);
  1694. pInterface->FlowListSize -= 1;
  1695. pFlow->Linkage.Flink = pFlow->Linkage.Blink = NULL;
  1696. FlowHandle = pFlow->FlowHandle;
  1697. UlTrace( TC, ("Http!UlpTcDeleteFlow: Flow deleted. %p\n", pFlow ));
  1698. UL_FREE_POOL_WITH_SIG( pFlow, UL_TCI_FLOW_POOL_TAG );
  1699. //
  1700. // Finally talk to TC
  1701. //
  1702. Status = UlpTcDeleteGpcFlow( FlowHandle );
  1703. if (!NT_SUCCESS(Status))
  1704. {
  1705. UlTrace(TC, ("Http!UlpTcDeleteFlow: FAILURE %08lx \n",
  1706. Status ));
  1707. }
  1708. else
  1709. {
  1710. UlTrace(TC,
  1711. ("Http!UlpTcDeleteFlow: FlowHandle %d deleted in TC as well.\n",
  1712. FlowHandle
  1713. ));
  1714. }
  1715. return Status;
  1716. }
  1717. /***************************************************************************++
  1718. Routine Description:
  1719. UlpTcDeleteFlow :
  1720. remove a flow from existing QoS Enabled interface
  1721. Arguments:
  1722. Return Value:
  1723. NTSTATUS - Completion status.
  1724. --***************************************************************************/
  1725. NTSTATUS
  1726. UlpTcDeleteGpcFlow(
  1727. IN HANDLE FlowHandle
  1728. )
  1729. {
  1730. NTSTATUS Status;
  1731. ULONG InBuffSize;
  1732. ULONG OutBuffSize;
  1733. GPC_REMOVE_CF_INFO_REQ GpcReq;
  1734. GPC_REMOVE_CF_INFO_RES GpcRes;
  1735. IO_STATUS_BLOCK IoStatusBlock;
  1736. //
  1737. // Remove the flow frm psched
  1738. //
  1739. InBuffSize = sizeof(GPC_REMOVE_CF_INFO_REQ);
  1740. OutBuffSize = sizeof(GPC_REMOVE_CF_INFO_RES);
  1741. GpcReq.ClientHandle = g_GpcClientHandle;
  1742. GpcReq.GpcCfInfoHandle = FlowHandle;
  1743. Status = UlpTcDeviceControl( g_GpcFileHandle,
  1744. NULL,
  1745. NULL,
  1746. NULL,
  1747. &IoStatusBlock,
  1748. IOCTL_GPC_REMOVE_CF_INFO,
  1749. &GpcReq,
  1750. InBuffSize,
  1751. &GpcRes,
  1752. OutBuffSize
  1753. );
  1754. if (NT_SUCCESS(Status))
  1755. {
  1756. Status = GpcRes.Status;
  1757. }
  1758. if (!NT_SUCCESS(Status))
  1759. {
  1760. UlTrace(TC,
  1761. ("Http!UlpTcDeleteGpcFlow: FAILURE %08lx \n", Status ));
  1762. }
  1763. return Status;
  1764. }
  1765. /***************************************************************************++
  1766. Routine Description:
  1767. UlpTcAllocateFlow :
  1768. Allocates a flow and setup the FlowSpec according the passed BWT
  1769. parameter
  1770. Arguments:
  1771. HTTP_BANDWIDTH_LIMIT - FlowSpec will be created using this BWT limit
  1772. in B/s
  1773. Return Value
  1774. PUL_TCI_FLOW - The newly allocated flow
  1775. NULL - If memory allocation failed
  1776. --***************************************************************************/
  1777. PUL_TCI_FLOW
  1778. UlpTcAllocateFlow(
  1779. IN HTTP_BANDWIDTH_LIMIT MaxBandwidth
  1780. )
  1781. {
  1782. PUL_TCI_FLOW pFlow;
  1783. TC_GEN_FLOW TcGenFlow;
  1784. //
  1785. // Setup the FlowSpec frm MaxBandwidth passed by the config handler
  1786. //
  1787. RtlZeroMemory(&TcGenFlow,sizeof(TcGenFlow));
  1788. UL_SET_FLOWSPEC(TcGenFlow,MaxBandwidth);
  1789. //
  1790. // Since we hold a spinlock inside the flow structure allocating from
  1791. // NonPagedPool. We will have this allocation only for bt enabled sites.
  1792. //
  1793. pFlow = UL_ALLOCATE_STRUCT(
  1794. NonPagedPool,
  1795. UL_TCI_FLOW,
  1796. UL_TCI_FLOW_POOL_TAG
  1797. );
  1798. if( pFlow == NULL )
  1799. {
  1800. return NULL;
  1801. }
  1802. // Initialize the rest
  1803. RtlZeroMemory( pFlow, sizeof(UL_TCI_FLOW) );
  1804. pFlow->Signature = UL_TCI_FLOW_POOL_TAG;
  1805. pFlow->GenFlow = TcGenFlow;
  1806. UlInitializeSpinLock( &pFlow->FilterListSpinLock, "FilterListSpinLock" );
  1807. InitializeListHead( &pFlow->FilterList );
  1808. pFlow->pOwner = NULL;
  1809. return pFlow;
  1810. }
  1811. /***************************************************************************++
  1812. Routine Description:
  1813. UlpModifyFlow :
  1814. Modify an existing flow by sending an IOCTL down to GPC. Basically
  1815. what this function does is to provide an updated TC_GEN_FLOW field
  1816. to GPC for an existing flow.
  1817. Arguments:
  1818. PUL_TCI_INTERFACE - Required to get the interfaces friendly name.
  1819. PUL_TCI_FLOW - To get the GPC flow handle as well as to be able to
  1820. update the new flow parameters.
  1821. --***************************************************************************/
  1822. NTSTATUS
  1823. UlpModifyFlow(
  1824. IN PUL_TCI_INTERFACE pInterface,
  1825. IN PUL_TCI_FLOW pFlow
  1826. )
  1827. {
  1828. PCF_INFO_QOS Kflow;
  1829. PGPC_MODIFY_CF_INFO_REQ pGpcReq;
  1830. GPC_MODIFY_CF_INFO_RES GpcRes;
  1831. ULONG InBuffSize;
  1832. ULONG OutBuffSize;
  1833. IO_STATUS_BLOCK IoStatusBlock;
  1834. NTSTATUS Status;
  1835. //
  1836. // Sanity check
  1837. //
  1838. PAGED_CODE();
  1839. ASSERT(g_GpcClientHandle);
  1840. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  1841. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  1842. InBuffSize = sizeof(GPC_MODIFY_CF_INFO_REQ) + sizeof(CF_INFO_QOS);
  1843. OutBuffSize = sizeof(GPC_MODIFY_CF_INFO_RES);
  1844. pGpcReq = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1845. PagedPool,
  1846. GPC_MODIFY_CF_INFO_REQ,
  1847. sizeof(CF_INFO_QOS),
  1848. UL_TCI_GENERIC_POOL_TAG
  1849. );
  1850. if (pGpcReq == NULL)
  1851. {
  1852. return STATUS_NO_MEMORY;
  1853. }
  1854. RtlZeroMemory(pGpcReq, InBuffSize);
  1855. RtlZeroMemory(&GpcRes, OutBuffSize);
  1856. pGpcReq->ClientHandle = g_GpcClientHandle;
  1857. pGpcReq->GpcCfInfoHandle = pFlow->FlowHandle;
  1858. pGpcReq->CfInfoSize = sizeof(CF_INFO_QOS);
  1859. Kflow = (PCF_INFO_QOS)&pGpcReq->CfInfo;
  1860. Kflow->InstanceNameLength = (USHORT) pInterface->NameLength;
  1861. RtlCopyMemory(Kflow->InstanceName,
  1862. pInterface->Name,
  1863. pInterface->NameLength* sizeof(WCHAR));
  1864. RtlCopyMemory(&Kflow->GenFlow,
  1865. &pFlow->GenFlow,
  1866. sizeof(TC_GEN_FLOW));
  1867. Status = UlpTcDeviceControl( g_GpcFileHandle,
  1868. NULL,
  1869. NULL,
  1870. NULL,
  1871. &IoStatusBlock,
  1872. IOCTL_GPC_MODIFY_CF_INFO,
  1873. pGpcReq,
  1874. InBuffSize,
  1875. &GpcRes,
  1876. OutBuffSize
  1877. );
  1878. if (NT_SUCCESS(Status))
  1879. {
  1880. Status = GpcRes.Status;
  1881. }
  1882. if (!NT_SUCCESS(Status))
  1883. {
  1884. UlTrace( TC, ("Http!UlpModifyFlow: FAILURE %08lx\n",
  1885. Status
  1886. ));
  1887. }
  1888. else
  1889. {
  1890. UlTrace( TC, ("Http!UlpModifyFlow: flow %p modified on interface %p \n",
  1891. pFlow,
  1892. pInterface
  1893. ));
  1894. }
  1895. UL_FREE_POOL( pGpcReq, UL_TCI_GENERIC_POOL_TAG );
  1896. return Status;
  1897. }
  1898. /***************************************************************************++
  1899. Routine Description:
  1900. Builds the GPC structure and tries to add a QoS flow.
  1901. Updates the handle if call is successfull.
  1902. Arguments:
  1903. pInterface
  1904. pGenericFlow
  1905. pHandle
  1906. Return Value:
  1907. NTSTATUS - Completion status.
  1908. --***************************************************************************/
  1909. NTSTATUS
  1910. UlpAddFlow(
  1911. IN PUL_TCI_INTERFACE pInterface,
  1912. IN PUL_TCI_FLOW pGenericFlow,
  1913. OUT PHANDLE pHandle
  1914. )
  1915. {
  1916. NTSTATUS Status;
  1917. PCF_INFO_QOS Kflow;
  1918. PGPC_ADD_CF_INFO_REQ pGpcReq;
  1919. GPC_ADD_CF_INFO_RES GpcRes;
  1920. ULONG InBuffSize;
  1921. ULONG OutBuffSize;
  1922. IO_STATUS_BLOCK IoStatusBlock;
  1923. //
  1924. // Find the interface from handle
  1925. //
  1926. PAGED_CODE();
  1927. ASSERT(g_GpcClientHandle);
  1928. InBuffSize = sizeof(GPC_ADD_CF_INFO_REQ) + sizeof(CF_INFO_QOS);
  1929. OutBuffSize = sizeof(GPC_ADD_CF_INFO_RES);
  1930. pGpcReq = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1931. PagedPool,
  1932. GPC_ADD_CF_INFO_REQ,
  1933. sizeof(CF_INFO_QOS),
  1934. UL_TCI_GENERIC_POOL_TAG
  1935. );
  1936. if (pGpcReq == NULL)
  1937. {
  1938. return STATUS_NO_MEMORY;
  1939. }
  1940. RtlZeroMemory( pGpcReq, InBuffSize);
  1941. RtlZeroMemory( &GpcRes, OutBuffSize);
  1942. pGpcReq->ClientHandle = g_GpcClientHandle;
  1943. pGpcReq->ClientCfInfoContext= pGenericFlow; // GPC_CF_QOS;
  1944. pGpcReq->CfInfoSize = sizeof( CF_INFO_QOS);
  1945. Kflow = (PCF_INFO_QOS)&pGpcReq->CfInfo;
  1946. Kflow->InstanceNameLength = (USHORT) pInterface->NameLength;
  1947. RtlCopyMemory( Kflow->InstanceName,
  1948. pInterface->Name,
  1949. pInterface->NameLength* sizeof(WCHAR)
  1950. );
  1951. RtlCopyMemory( &Kflow->GenFlow,
  1952. &pGenericFlow->GenFlow,
  1953. sizeof(TC_GEN_FLOW)
  1954. );
  1955. Status = UlpTcDeviceControl( g_GpcFileHandle,
  1956. NULL,
  1957. NULL,
  1958. NULL,
  1959. &IoStatusBlock,
  1960. IOCTL_GPC_ADD_CF_INFO,
  1961. pGpcReq,
  1962. InBuffSize,
  1963. &GpcRes,
  1964. OutBuffSize
  1965. );
  1966. if (NT_SUCCESS(Status))
  1967. {
  1968. Status = GpcRes.Status;
  1969. if (NT_SUCCESS(Status))
  1970. {
  1971. (*pHandle) = (HANDLE) GpcRes.GpcCfInfoHandle;
  1972. UlTrace( TC,
  1973. ("Http!UlpAddFlow: a new flow added %p on interface %p \n",
  1974. pGenericFlow,
  1975. pInterface
  1976. ));
  1977. }
  1978. }
  1979. if (!NT_SUCCESS(Status))
  1980. {
  1981. UlTrace( TC, ("Http!UlpAddFlow: FAILURE %08lx\n",
  1982. Status
  1983. ));
  1984. }
  1985. UL_FREE_POOL( pGpcReq, UL_TCI_GENERIC_POOL_TAG );
  1986. return Status;
  1987. }
  1988. /***************************************************************************++
  1989. Routine Description:
  1990. Add a flow on existing QoS Enabled interfaces for the caller. And updates
  1991. the callers list. Caller is either cgroup or control channel.
  1992. Will return (the last) error if * all * of the flow additions fail.
  1993. If at least one flow addition is successfull, it will return success.
  1994. Consider a machine with 2 NICs, if media is disconnected on one NIC, you
  1995. would still expect to see QoS running properly on the other one. Returning
  1996. success here means, there is at least one NIC with bandwidth throttling is
  1997. properly enforced.
  1998. Arguments:
  1999. pOwner - Pointer to the cgroup or control channel.
  2000. NewBandwidth - The new bandwidth throttling setting in B/s
  2001. Global - TRUE if this call is for global flows.
  2002. Return Value:
  2003. NTSTATUS - Completion status. (Last failure if all additions are failed)
  2004. - Success if at least one flow addition was success.
  2005. --***************************************************************************/
  2006. NTSTATUS
  2007. UlTcAddFlows(
  2008. IN PVOID pOwner,
  2009. IN HTTP_BANDWIDTH_LIMIT MaxBandwidth,
  2010. IN BOOLEAN Global
  2011. )
  2012. {
  2013. NTSTATUS Status;
  2014. BOOLEAN FlowAdded;
  2015. PLIST_ENTRY pFlowListHead;
  2016. PLIST_ENTRY pInterfaceEntry;
  2017. PUL_TCI_INTERFACE pInterface;
  2018. PUL_TCI_FLOW pFlow;
  2019. //
  2020. // Sanity check and init first.
  2021. //
  2022. PAGED_CODE();
  2023. Status = STATUS_SUCCESS;
  2024. FlowAdded = FALSE;
  2025. ASSERT(MaxBandwidth != HTTP_LIMIT_INFINITE);
  2026. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2027. if (Global)
  2028. {
  2029. PUL_CONTROL_CHANNEL
  2030. pControlChannel = (PUL_CONTROL_CHANNEL) pOwner;
  2031. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  2032. UlTrace(TC,("Http!UlTcAddFlows: For ControlChannel: %p"
  2033. "@ bwt-rate of %d B/s\n",
  2034. pControlChannel,
  2035. MaxBandwidth
  2036. ));
  2037. pFlowListHead = &pControlChannel->FlowListHead;
  2038. }
  2039. else
  2040. {
  2041. PUL_CONFIG_GROUP_OBJECT
  2042. pConfigGroup = (PUL_CONFIG_GROUP_OBJECT) pOwner;
  2043. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  2044. UlTrace(TC,("Http!UlTcAddFlows: For CGroup: %p"
  2045. "@ bwt-rate of %d B/s\n",
  2046. pConfigGroup,
  2047. MaxBandwidth
  2048. ));
  2049. pFlowListHead = &pConfigGroup->FlowListHead;
  2050. }
  2051. //
  2052. // Visit each interface and add a flow for the caller.
  2053. //
  2054. pInterfaceEntry = g_TciIfcListHead.Flink;
  2055. while (pInterfaceEntry != &g_TciIfcListHead)
  2056. {
  2057. pInterface = CONTAINING_RECORD(
  2058. pInterfaceEntry,
  2059. UL_TCI_INTERFACE,
  2060. Linkage
  2061. );
  2062. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  2063. //
  2064. // Only if interface has a valid IP address, we attempt to add a
  2065. // flow for it. Otherwise we skip adding a flow for the interface.
  2066. //
  2067. if (!pInterface->IsQoSEnabled)
  2068. {
  2069. UlTrace(TC,
  2070. ("Http!UlTcAddFlows: Skipping for interface %p !\n",
  2071. pInterface
  2072. ));
  2073. goto proceed;
  2074. }
  2075. //
  2076. // Allocate a http flow structure.
  2077. //
  2078. pFlow = UlpTcAllocateFlow(MaxBandwidth);
  2079. if (pFlow == NULL)
  2080. {
  2081. Status = STATUS_NO_MEMORY;
  2082. UlTrace(TC, ("Http!UlTcAddFlows: Failure %08lx \n",
  2083. Status
  2084. ));
  2085. goto proceed;
  2086. }
  2087. //
  2088. // Create the corresponding QoS flow as well. If GPC call fails
  2089. // cleanup the allocated Http flow.
  2090. //
  2091. Status = UlpAddFlow(
  2092. pInterface,
  2093. pFlow,
  2094. &pFlow->FlowHandle
  2095. );
  2096. if (!NT_SUCCESS(Status))
  2097. {
  2098. UlTrace(TC, ("Http!UlTcAddFlows: Failure %08lx \n",
  2099. Status
  2100. ));
  2101. UL_FREE_POOL_WITH_SIG(pFlow, UL_TCI_FLOW_POOL_TAG);
  2102. goto proceed;
  2103. }
  2104. if (Global)
  2105. {
  2106. INT_TRACE(pInterface, TC_GFLOW_ADD);
  2107. }
  2108. else
  2109. {
  2110. INT_TRACE(pInterface, TC_FLOW_ADD);
  2111. }
  2112. //
  2113. // Proceed with further initialization as we have successfully
  2114. // installed the flow. First link the flow back to its owner
  2115. // interface. And add this to the interface's flowlist.
  2116. //
  2117. pFlow->pInterface = pInterface;
  2118. InsertHeadList(&pInterface->FlowList, &pFlow->Linkage);
  2119. pInterface->FlowListSize++;
  2120. //
  2121. // Also add this to the owner's flowlist. Set the owner pointer.
  2122. // Do not bump up the owner's refcount. Otherwise owner cannot be
  2123. // cleaned up until Tc terminates. And flows cannot be removed
  2124. // untill termination.
  2125. //
  2126. InsertHeadList(pFlowListHead, &pFlow->Siblings);
  2127. pFlow->pOwner = pOwner;
  2128. //
  2129. // Mark that there's at least one interface on which we were able
  2130. // to install a flow.
  2131. //
  2132. FlowAdded = TRUE;
  2133. UlTrace( TC,
  2134. ("Http!UlTcAddFlows: Flow %p on pInterface %p\n",
  2135. pFlow,
  2136. pInterface
  2137. ));
  2138. UL_DUMP_TC_FLOW(pFlow);
  2139. proceed:
  2140. //
  2141. // Proceed to the next interface.
  2142. //
  2143. pInterfaceEntry = pInterfaceEntry->Flink;
  2144. }
  2145. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2146. if (FlowAdded)
  2147. {
  2148. //
  2149. // Return success if at least one flow installed.
  2150. //
  2151. return STATUS_SUCCESS;
  2152. }
  2153. return Status;
  2154. }
  2155. /***************************************************************************++
  2156. Routine Description:
  2157. Will walk the caller's flow list and update the existing flows with the
  2158. new flowspec.
  2159. Its caller responsiblity to remember the new settings in the store.
  2160. Caller is either cgroup or control channel.
  2161. Will return error if one or some of the updates fails, but proceed walking
  2162. the whole list.
  2163. Arguments:
  2164. pOwner - Pointer to the cgroup or control channel.
  2165. NewBandwidth - The new bandwidth throttling setting in B/s
  2166. Global - TRUE if this call is for global flows.
  2167. Return Value:
  2168. NTSTATUS - Completion status. (Last failure if there was any)
  2169. --***************************************************************************/
  2170. NTSTATUS
  2171. UlTcModifyFlows(
  2172. IN PVOID pOwner,
  2173. IN HTTP_BANDWIDTH_LIMIT NewBandwidth,
  2174. IN BOOLEAN Global
  2175. )
  2176. {
  2177. NTSTATUS Status;
  2178. BOOLEAN FlowModified;
  2179. PLIST_ENTRY pFlowListHead;
  2180. PLIST_ENTRY pFlowEntry;
  2181. PUL_TCI_FLOW pFlow;
  2182. HTTP_BANDWIDTH_LIMIT OldBandwidth;
  2183. //
  2184. // Sanity check and init.
  2185. //
  2186. PAGED_CODE();
  2187. Status = STATUS_SUCCESS;
  2188. FlowModified = FALSE;
  2189. OldBandwidth = 0;
  2190. ASSERT(NewBandwidth != HTTP_LIMIT_INFINITE); // we do not remove flows.
  2191. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2192. if (Global)
  2193. {
  2194. PUL_CONTROL_CHANNEL
  2195. pControlChannel = (PUL_CONTROL_CHANNEL) pOwner;
  2196. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  2197. UlTrace(TC,("Http!UlTcModifyFlows: For ControlChannel: %p"
  2198. "to bwt-rate of %d B/s\n",
  2199. pControlChannel,
  2200. NewBandwidth
  2201. ));
  2202. pFlowListHead = &pControlChannel->FlowListHead;
  2203. }
  2204. else
  2205. {
  2206. PUL_CONFIG_GROUP_OBJECT
  2207. pConfigGroup = (PUL_CONFIG_GROUP_OBJECT) pOwner;
  2208. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  2209. UlTrace(TC,("Http!UlTcModifyFlows: For CGroup: %p"
  2210. "to bwt-rate of %d B/s\n",
  2211. pConfigGroup,
  2212. NewBandwidth
  2213. ));
  2214. pFlowListHead = &pConfigGroup->FlowListHead;
  2215. }
  2216. //
  2217. // Walk the list and attempt to modify the flows.
  2218. //
  2219. pFlowEntry = pFlowListHead->Flink;
  2220. while (pFlowEntry != pFlowListHead)
  2221. {
  2222. PUL_TCI_INTERFACE pInterface;
  2223. pFlow = CONTAINING_RECORD(
  2224. pFlowEntry,
  2225. UL_TCI_FLOW,
  2226. Siblings
  2227. );
  2228. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  2229. ASSERT(pOwner == pFlow->pOwner);
  2230. pInterface = pFlow->pInterface;
  2231. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  2232. if (Global)
  2233. {
  2234. INT_TRACE(pInterface, TC_GFLOW_MODIFY);
  2235. }
  2236. else
  2237. {
  2238. INT_TRACE(pInterface, TC_FLOW_MODIFY);
  2239. }
  2240. //
  2241. // Save the old bandwidth before attempting to modify.
  2242. //
  2243. OldBandwidth = UL_GET_BW_FRM_FLOWSPEC(pFlow->GenFlow);
  2244. UL_SET_FLOWSPEC(pFlow->GenFlow, NewBandwidth);
  2245. Status = UlpModifyFlow(pFlow->pInterface, pFlow);
  2246. if (!NT_SUCCESS(Status))
  2247. {
  2248. //
  2249. // Whine about it, but still continue. Restore the original
  2250. // flowspec back.
  2251. //
  2252. UlTrace(TC,("Http!UlTcModifyFlowsForSite: FAILURE %08lx \n",
  2253. Status
  2254. ));
  2255. UL_SET_FLOWSPEC(pFlow->GenFlow, OldBandwidth);
  2256. }
  2257. else
  2258. {
  2259. FlowModified = TRUE;
  2260. }
  2261. UL_DUMP_TC_FLOW(pFlow);
  2262. //
  2263. // Proceed to the next flow
  2264. //
  2265. pFlowEntry = pFlowEntry->Flink;
  2266. }
  2267. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2268. if (FlowModified)
  2269. {
  2270. //
  2271. // Return success if at least one flow modified.
  2272. //
  2273. return STATUS_SUCCESS;
  2274. }
  2275. return Status;
  2276. }
  2277. /***************************************************************************++
  2278. Routine Description:
  2279. Walks the caller's list (either cgroup or control channel) and removes
  2280. the flows on the list. Since this flows are always added to these lists
  2281. while holding the Interface lock exclusive, we will also acquire the
  2282. Interface lock exclusive here.
  2283. Arguments:
  2284. pOwner : Either points to pConfigGroup or pControlChannel.
  2285. Global : Must be true if this call is for removing global flows.
  2286. In that case pOwner points to pControlChannel
  2287. --***************************************************************************/
  2288. VOID
  2289. UlTcRemoveFlows(
  2290. IN PVOID pOwner,
  2291. IN BOOLEAN Global
  2292. )
  2293. {
  2294. NTSTATUS Status;
  2295. PLIST_ENTRY pFlowListHead;
  2296. PLIST_ENTRY pFlowEntry;
  2297. PUL_TCI_FLOW pFlow;
  2298. //
  2299. // Sanity check and dispatch the flow type.
  2300. //
  2301. PAGED_CODE();
  2302. Status = STATUS_SUCCESS;
  2303. UlAcquirePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2304. if (Global)
  2305. {
  2306. PUL_CONTROL_CHANNEL
  2307. pControlChannel = (PUL_CONTROL_CHANNEL) pOwner;
  2308. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  2309. UlTrace(TC,("Http!UlTcRemoveFlows: For ControlChannel: %p \n",
  2310. pControlChannel
  2311. ));
  2312. pFlowListHead = &pControlChannel->FlowListHead;
  2313. }
  2314. else
  2315. {
  2316. PUL_CONFIG_GROUP_OBJECT
  2317. pConfigGroup = (PUL_CONFIG_GROUP_OBJECT) pOwner;
  2318. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  2319. UlTrace(TC,("Http!UlTcRemoveFlows: For CGroup %p\n",
  2320. pConfigGroup
  2321. ));
  2322. pFlowListHead = &pConfigGroup->FlowListHead;
  2323. }
  2324. //
  2325. // Walk the list and remove the flows.
  2326. //
  2327. while (!IsListEmpty(pFlowListHead))
  2328. {
  2329. PUL_TCI_INTERFACE pInterface;
  2330. pFlowEntry = pFlowListHead->Flink;
  2331. pFlow = CONTAINING_RECORD(
  2332. pFlowEntry,
  2333. UL_TCI_FLOW,
  2334. Siblings
  2335. );
  2336. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  2337. ASSERT(pOwner == pFlow->pOwner);
  2338. pInterface = pFlow->pInterface;
  2339. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  2340. if (Global)
  2341. {
  2342. INT_TRACE(pInterface, TC_GFLOW_REMOVE);
  2343. }
  2344. else
  2345. {
  2346. INT_TRACE(pInterface, TC_FLOW_REMOVE);
  2347. }
  2348. //
  2349. // Remove this from the owner's flowlist.
  2350. //
  2351. RemoveEntryList(&pFlow->Siblings);
  2352. pFlow->Siblings.Flink = pFlow->Siblings.Blink = NULL;
  2353. pFlow->pOwner = NULL;
  2354. //
  2355. // Remove it from the interface list as well.And delete
  2356. // the corresponding QoS flow. This should not fail.
  2357. //
  2358. Status = UlpTcDeleteFlow(pFlow);
  2359. //
  2360. // Above call may fail,if GPC removes the flow based on PSCHED's
  2361. // notification before we get a chance to close our GPC handle.
  2362. //
  2363. }
  2364. UlReleasePushLockExclusive(&g_pUlNonpagedData->TciIfcPushLock);
  2365. return;
  2366. }
  2367. /***************************************************************************++
  2368. Routine Description:
  2369. //
  2370. // There are two possibilities. The request could be served frm
  2371. // cache or can be routed to the user. In either case we need a
  2372. // flow installed if the BW is enabled for this request's site
  2373. // and there's no filter installed for this connection yet. We
  2374. // will remove the filter as soon as the connection dropped. But
  2375. // yes there's always a but,if the client is attempting to make
  2376. // requests to different sites using the same connection then we
  2377. // need to drop the filter frm the old site and move it to the
  2378. // newly requested site. This is a rare case but lets handle it
  2379. // anyway.
  2380. //
  2381. It's callers responsibility to ensure proper removal of the filter,
  2382. after it's done.
  2383. Algorithm:
  2384. 1. Find the flow from the flow list of cgroup (or from global flows)
  2385. 2. Add filter to that flow
  2386. Arguments:
  2387. pHttpConnection - required - Filter will be attached for this connection
  2388. pOwner - Either points to cgroup or control channel.
  2389. Global - must be true if the flow owner is a control channel.
  2390. Return Values:
  2391. STATUS_NOT_SUPPORTED - For attempts on Local Loopback
  2392. STATUS_OBJECT_NAME_NOT_FOUND - If flow has not been found for the cgroup
  2393. STATUS_SUCCESS - In other cases
  2394. --***************************************************************************/
  2395. NTSTATUS
  2396. UlTcAddFilter(
  2397. IN PUL_HTTP_CONNECTION pHttpConnection,
  2398. IN PVOID pOwner,
  2399. IN BOOLEAN Global
  2400. )
  2401. {
  2402. NTSTATUS Status;
  2403. TC_GEN_FILTER TcGenericFilter;
  2404. PUL_TCI_FLOW pFlow;
  2405. PUL_TCI_INTERFACE pInterface;
  2406. IP_PATTERN Pattern;
  2407. IP_PATTERN Mask;
  2408. PUL_TCI_FILTER pFilter;
  2409. ULONG InterfaceId;
  2410. ULONG LinkId;
  2411. //
  2412. // Sanity check
  2413. //
  2414. PAGED_CODE();
  2415. Status = STATUS_SUCCESS;
  2416. ASSERT_FLOW_OWNER(pOwner);
  2417. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConnection));
  2418. ASSERT(pHttpConnection->pConnection->AddressType == TDI_ADDRESS_TYPE_IP);
  2419. //
  2420. // Need to get the routing info to find the interface.
  2421. //
  2422. Status = UlGetConnectionRoutingInfo(
  2423. pHttpConnection->pConnection,
  2424. &InterfaceId,
  2425. &LinkId
  2426. );
  2427. if(!NT_SUCCESS(Status))
  2428. {
  2429. return Status;
  2430. }
  2431. //
  2432. // At this point we will be refering to the flows & filters
  2433. // in our list therefore we need to acquire the lock
  2434. //
  2435. UlAcquirePushLockShared(&g_pUlNonpagedData->TciIfcPushLock);
  2436. //
  2437. // If connection already has a filter attached, need do few
  2438. // more checks.
  2439. //
  2440. if (pHttpConnection->pFlow)
  2441. {
  2442. //
  2443. // Already present flow and filter must be valid.
  2444. //
  2445. ASSERT(IS_VALID_TCI_FLOW(pHttpConnection->pFlow));
  2446. ASSERT(IS_VALID_TCI_FILTER(pHttpConnection->pFilter));
  2447. ASSERT_FLOW_OWNER(pHttpConnection->pFlow->pOwner);
  2448. //
  2449. // If pOwner is same with the old filter's, then
  2450. // we will skip adding the same filter again.
  2451. //
  2452. if (pOwner == pHttpConnection->pFlow->pOwner)
  2453. {
  2454. //
  2455. // No need to add a new filter we are done.
  2456. //
  2457. UlTrace( TC,
  2458. ("Http!UlTcAddFilter: Skipping same pFlow %p and"
  2459. "pFilter %p already exist\n",
  2460. pHttpConnection->pFlow,
  2461. pHttpConnection->pFilter,
  2462. pHttpConnection
  2463. ));
  2464. ASSERT(NT_SUCCESS(Status));
  2465. goto end;
  2466. }
  2467. else
  2468. {
  2469. //
  2470. // If there was another filter before and this newly coming request
  2471. // is being going to a different site/flow. Then move the filter frm
  2472. // the old one to the new flow.
  2473. //
  2474. Status = UlpTcDeleteFilter(
  2475. pHttpConnection->pFlow,
  2476. pHttpConnection->pFilter
  2477. );
  2478. ASSERT(NT_SUCCESS(Status)); // We trust MSGPC.SYS
  2479. }
  2480. }
  2481. //
  2482. // Search through the cgroup's flowlist to find the one we need.
  2483. // This must find the flow which is installed on the interface
  2484. // on which we will send the outgoing packets. Not necessarily
  2485. // the same ip we have received the request. See the routing call
  2486. // above.
  2487. //
  2488. pFlow = UlpFindFlow(pOwner, Global, InterfaceId, LinkId);
  2489. if ( pFlow == NULL )
  2490. {
  2491. //
  2492. // Note: We'll come here for loopback interfaces, since we will not
  2493. // find a Traffic Control interfaces for loopback.
  2494. //
  2495. UlTrace( TC,
  2496. ("Http!UlTcAddFilter: Unable to find interface %x \n",
  2497. InterfaceId
  2498. ));
  2499. //
  2500. // It's possible that we might not find out a flow
  2501. // after all the interfaces went down, even though
  2502. // qos configured on the cgroup.
  2503. //
  2504. Status = STATUS_SUCCESS;
  2505. goto end;
  2506. }
  2507. pFilter = NULL;
  2508. pInterface = pFlow->pInterface;
  2509. ASSERT(IS_VALID_TCI_INTERFACE(pInterface));
  2510. RtlZeroMemory( &Pattern, sizeof(IP_PATTERN) );
  2511. RtlZeroMemory( &Mask, sizeof(IP_PATTERN) );
  2512. // Setup the filter's pattern
  2513. Pattern.SrcAddr = pHttpConnection->pConnection->LocalAddrIn.in_addr;
  2514. Pattern.S_un.S_un_ports.s_srcport = pHttpConnection->pConnection->LocalAddrIn.sin_port;
  2515. Pattern.DstAddr = pHttpConnection->pConnection->RemoteAddrIn.in_addr;
  2516. Pattern.S_un.S_un_ports.s_dstport = pHttpConnection->pConnection->RemoteAddrIn.sin_port;
  2517. Pattern.ProtocolId = IPPROTO_TCP;
  2518. // Setup the filter's Mask
  2519. RtlFillMemory(&Mask, sizeof(IP_PATTERN), 0xff);
  2520. TcGenericFilter.AddressType = NDIS_PROTOCOL_ID_TCP_IP;
  2521. TcGenericFilter.PatternSize = sizeof( IP_PATTERN );
  2522. TcGenericFilter.Pattern = &Pattern;
  2523. TcGenericFilter.Mask = &Mask;
  2524. Status = UlpTcAddFilter(
  2525. pFlow,
  2526. &TcGenericFilter,
  2527. LinkId,
  2528. &pFilter
  2529. );
  2530. if (!NT_SUCCESS(Status))
  2531. {
  2532. //
  2533. // Now this is a real failure, we will reject the connection.
  2534. //
  2535. UlTrace( TC,
  2536. ("Http!UlTcAddFilter: Unable to add filter for;\n"
  2537. "\t pInterface : %p\n"
  2538. "\t pFlow : %p\n",
  2539. pInterface,
  2540. pFlow
  2541. ));
  2542. goto end;
  2543. }
  2544. //
  2545. // Update the connection's pointers here.
  2546. //
  2547. pHttpConnection->pFlow = pFlow;
  2548. pHttpConnection->pFilter = pFilter;
  2549. pHttpConnection->BandwidthThrottlingEnabled = 1;
  2550. //
  2551. // Remember the connection for cleanup. If flow & filter get
  2552. // removed aynscly when connection still pointing to them
  2553. // we can go and null out the connection's private pointers.
  2554. //
  2555. pFilter->pHttpConnection = pHttpConnection;
  2556. //
  2557. // Sweet smell of success !
  2558. //
  2559. UlTrace(TC,
  2560. ("Http!UlTcAddFilter: Success for;\n"
  2561. "\t pInterface : %p\n"
  2562. "\t pFlow : %p\n",
  2563. pInterface,
  2564. pFlow
  2565. ));
  2566. UL_DUMP_TC_FILTER(pFilter);
  2567. end:
  2568. if (!NT_SUCCESS(Status))
  2569. {
  2570. UlTrace( TC, ("Http!UlTcAddFilter: FAILURE %08lx \n", Status ));
  2571. }
  2572. UlReleasePushLockShared(&g_pUlNonpagedData->TciIfcPushLock);
  2573. return Status;
  2574. }
  2575. /***************************************************************************++
  2576. Routine Description:
  2577. Add a filter on an existing flow.
  2578. Arguments:
  2579. pFlow - Filter will be added on to this flow.
  2580. pGenericFilter - Generic filter parameters.
  2581. ppFilter - if everything goes ok. A new filter will be allocated.
  2582. --***************************************************************************/
  2583. NTSTATUS
  2584. UlpTcAddFilter(
  2585. IN PUL_TCI_FLOW pFlow,
  2586. IN PTC_GEN_FILTER pGenericFilter,
  2587. IN ULONG LinkId,
  2588. OUT PUL_TCI_FILTER *ppFilter
  2589. )
  2590. {
  2591. NTSTATUS Status;
  2592. PGPC_ADD_PATTERN_REQ pGpcReq;
  2593. GPC_ADD_PATTERN_RES GpcRes;
  2594. ULONG InBuffSize;
  2595. ULONG OutBuffSize;
  2596. ULONG PatternSize;
  2597. IO_STATUS_BLOCK IoStatBlock;
  2598. PUCHAR pTemp;
  2599. PGPC_IP_PATTERN pIpPattern;
  2600. PUL_TCI_FILTER pFilter;
  2601. //
  2602. // Sanity check
  2603. //
  2604. Status = STATUS_SUCCESS;
  2605. pGpcReq = NULL;
  2606. if ( !pGenericFilter || !pFlow || !g_GpcClientHandle )
  2607. {
  2608. return STATUS_INVALID_PARAMETER;
  2609. }
  2610. // Allocate a space for the filter
  2611. pFilter = UL_ALLOCATE_STRUCT(
  2612. NonPagedPool,
  2613. UL_TCI_FILTER,
  2614. UL_TCI_FILTER_POOL_TAG
  2615. );
  2616. if ( pFilter == NULL )
  2617. {
  2618. Status = STATUS_NO_MEMORY;
  2619. goto end;
  2620. }
  2621. pFilter->Signature = UL_TCI_FILTER_POOL_TAG;
  2622. // Buffer monkeying
  2623. PatternSize = sizeof(GPC_IP_PATTERN);
  2624. InBuffSize = sizeof(GPC_ADD_PATTERN_REQ) + (2 * PatternSize);
  2625. OutBuffSize = sizeof(GPC_ADD_PATTERN_RES);
  2626. pGpcReq = UL_ALLOCATE_STRUCT_WITH_SPACE(
  2627. PagedPool,
  2628. GPC_ADD_PATTERN_REQ,
  2629. (2 * PatternSize),
  2630. UL_TCI_GENERIC_POOL_TAG
  2631. );
  2632. if (pGpcReq == NULL)
  2633. {
  2634. Status = STATUS_NO_MEMORY;
  2635. goto end;
  2636. }
  2637. RtlZeroMemory( pGpcReq, InBuffSize);
  2638. RtlZeroMemory( &GpcRes, OutBuffSize);
  2639. pGpcReq->ClientHandle = g_GpcClientHandle;
  2640. pGpcReq->GpcCfInfoHandle = pFlow->FlowHandle;
  2641. pGpcReq->PatternSize = PatternSize;
  2642. pGpcReq->ProtocolTemplate = GPC_PROTOCOL_TEMPLATE_IP;
  2643. pTemp = (PUCHAR) &pGpcReq->PatternAndMask;
  2644. // Fill in the IP Pattern first
  2645. RtlCopyMemory( pTemp, pGenericFilter->Pattern, PatternSize );
  2646. pIpPattern = (PGPC_IP_PATTERN) pTemp;
  2647. //
  2648. // According to QoS Tc.dll ;
  2649. // This is a work around so that TCPIP wil not to find the index/link
  2650. // for ICMP/IGMP packets
  2651. //
  2652. pIpPattern->InterfaceId.InterfaceId = pFlow->pInterface->IfIndex;
  2653. pIpPattern->InterfaceId.LinkId = LinkId;
  2654. pIpPattern->Reserved[0] = 0;
  2655. pIpPattern->Reserved[1] = 0;
  2656. pIpPattern->Reserved[2] = 0;
  2657. // Fill in the mask
  2658. pTemp += PatternSize;
  2659. RtlCopyMemory( pTemp, pGenericFilter->Mask, PatternSize );
  2660. pIpPattern = (PGPC_IP_PATTERN) pTemp;
  2661. pIpPattern->InterfaceId.InterfaceId = 0xffffffff;
  2662. pIpPattern->InterfaceId.LinkId = 0xffffffff;
  2663. pIpPattern->Reserved[0] = 0xff;
  2664. pIpPattern->Reserved[1] = 0xff;
  2665. pIpPattern->Reserved[2] = 0xff;
  2666. // Time to invoke Gpsy
  2667. Status = UlpTcDeviceControl( g_GpcFileHandle,
  2668. NULL,
  2669. NULL,
  2670. NULL,
  2671. &IoStatBlock,
  2672. IOCTL_GPC_ADD_PATTERN,
  2673. pGpcReq,
  2674. InBuffSize,
  2675. &GpcRes,
  2676. OutBuffSize);
  2677. if (NT_SUCCESS(Status))
  2678. {
  2679. Status = GpcRes.Status;
  2680. if (NT_SUCCESS(Status))
  2681. {
  2682. //
  2683. // Insert the freshly created filter to the flow.
  2684. //
  2685. pFilter->FilterHandle = (HANDLE) GpcRes.GpcPatternHandle;
  2686. UlpInsertFilterEntry( pFilter, pFlow );
  2687. //
  2688. // Success!
  2689. //
  2690. *ppFilter = pFilter;
  2691. INCREMENT_FILTER_ADD();
  2692. }
  2693. }
  2694. end:
  2695. if (!NT_SUCCESS(Status))
  2696. {
  2697. INCREMENT_FILTER_ADD_FAILURE();
  2698. UlTrace( TC, ("Http!UlpTcAddFilter: FAILURE %08lx \n", Status ));
  2699. // Cleanup filter only if we failed, otherwise it will go to
  2700. // the filterlist of the flow.
  2701. if (pFilter)
  2702. {
  2703. UL_FREE_POOL( pFilter, UL_TCI_FILTER_POOL_TAG );
  2704. }
  2705. }
  2706. // Cleanup the temp Gpc buffer which we used to pass down filter info
  2707. // to GPC. We don't need it anymore.
  2708. if (pGpcReq)
  2709. {
  2710. UL_FREE_POOL( pGpcReq, UL_TCI_GENERIC_POOL_TAG );
  2711. }
  2712. return Status;
  2713. }
  2714. /***************************************************************************++
  2715. Routine Description:
  2716. UlTcDeleteFilter :
  2717. Connection only deletes the filter prior to deleting itself. Any
  2718. operation initiated by the connection requires tc resource shared
  2719. and none of those cause race condition.
  2720. Anything other than this, such as flow & filter removal because of
  2721. BW disabling on the site will acquire the lock exclusively. Hence
  2722. the pFlow & pFilter are safe as long as we acquire the tc resource
  2723. shared.
  2724. Arguments:
  2725. connection object to get the flow & filter after we acquire the tc lock
  2726. --***************************************************************************/
  2727. NTSTATUS
  2728. UlTcDeleteFilter(
  2729. IN PUL_HTTP_CONNECTION pHttpConnection
  2730. )
  2731. {
  2732. NTSTATUS Status;
  2733. //
  2734. // Sanity check
  2735. //
  2736. Status = STATUS_SUCCESS;
  2737. //
  2738. // If we have been called w/o being initialized
  2739. //
  2740. ASSERT(g_InitTciCalled);
  2741. UlTrace(TC,("Http!UlTcDeleteFilter: for connection %p\n", pHttpConnection));
  2742. UlAcquirePushLockShared(&g_pUlNonpagedData->TciIfcPushLock);
  2743. if (pHttpConnection->pFlow)
  2744. {
  2745. Status = UlpTcDeleteFilter(
  2746. pHttpConnection->pFlow,
  2747. pHttpConnection->pFilter
  2748. );
  2749. }
  2750. UlReleasePushLockShared(&g_pUlNonpagedData->TciIfcPushLock);
  2751. return Status;
  2752. }
  2753. /***************************************************************************++
  2754. Routine Description:
  2755. UlpTcRemoveFilter :
  2756. Arguments:
  2757. flow & filter
  2758. --***************************************************************************/
  2759. NTSTATUS
  2760. UlpTcDeleteFilter(
  2761. IN PUL_TCI_FLOW pFlow,
  2762. IN PUL_TCI_FILTER pFilter
  2763. )
  2764. {
  2765. NTSTATUS Status;
  2766. HANDLE FilterHandle;
  2767. //
  2768. // Sanity check
  2769. //
  2770. Status = STATUS_SUCCESS;
  2771. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  2772. ASSERT(IS_VALID_TCI_FILTER(pFilter));
  2773. if (pFlow == NULL || pFilter == NULL)
  2774. {
  2775. return STATUS_INVALID_PARAMETER;
  2776. }
  2777. FilterHandle = pFilter->FilterHandle;
  2778. pFilter->pHttpConnection->pFlow = NULL;
  2779. pFilter->pHttpConnection->pFilter = NULL;
  2780. //
  2781. // Now call the actual worker for us
  2782. //
  2783. UlpRemoveFilterEntry( pFilter, pFlow );
  2784. Status = UlpTcDeleteGpcFilter( FilterHandle );
  2785. if (!NT_SUCCESS(Status))
  2786. {
  2787. UlTrace( TC, ("Http!UlpTcDeleteFilter: FAILURE %08lx \n", Status ));
  2788. }
  2789. return Status;
  2790. }
  2791. /***************************************************************************++
  2792. Routine Description:
  2793. UlpTcRemoveFilter :
  2794. This procedure builds up the structure necessary to delete a filter.
  2795. It then calls a routine to pass this info to the GPC.
  2796. Arguments:
  2797. FilterHandle - Handle of the filter to be deleted
  2798. --***************************************************************************/
  2799. NTSTATUS
  2800. UlpTcDeleteGpcFilter(
  2801. IN HANDLE FilterHandle
  2802. )
  2803. {
  2804. NTSTATUS Status;
  2805. ULONG InBuffSize;
  2806. ULONG OutBuffSize;
  2807. GPC_REMOVE_PATTERN_REQ GpcReq;
  2808. GPC_REMOVE_PATTERN_RES GpcRes;
  2809. IO_STATUS_BLOCK IoStatBlock;
  2810. Status = STATUS_SUCCESS;
  2811. ASSERT(FilterHandle != NULL);
  2812. InBuffSize = sizeof(GPC_REMOVE_PATTERN_REQ);
  2813. OutBuffSize = sizeof(GPC_REMOVE_PATTERN_RES);
  2814. GpcReq.ClientHandle = g_GpcClientHandle;
  2815. GpcReq.GpcPatternHandle = FilterHandle;
  2816. ASSERT(g_GpcFileHandle);
  2817. ASSERT(GpcReq.ClientHandle);
  2818. ASSERT(GpcReq.GpcPatternHandle);
  2819. Status = UlpTcDeviceControl( g_GpcFileHandle,
  2820. NULL,
  2821. NULL,
  2822. NULL,
  2823. &IoStatBlock,
  2824. IOCTL_GPC_REMOVE_PATTERN,
  2825. &GpcReq,
  2826. InBuffSize,
  2827. &GpcRes,
  2828. OutBuffSize
  2829. );
  2830. if (NT_SUCCESS(Status))
  2831. {
  2832. Status = GpcRes.Status;
  2833. if (NT_SUCCESS(Status))
  2834. {
  2835. UlTrace( TC,
  2836. ("Http!UlpTcDeleteGpcFilter: FilterHandle %d deleted in TC as well.\n",
  2837. FilterHandle
  2838. ));
  2839. INCREMENT_FILTER_DELETE();
  2840. }
  2841. }
  2842. if (!NT_SUCCESS(Status))
  2843. {
  2844. INCREMENT_FILTER_DELETE_FAILURE();
  2845. UlTrace( TC, ("Http!UlpTcDeleteGpcFilter: FAILURE %08lx \n", Status ));
  2846. }
  2847. return Status;
  2848. }
  2849. /***************************************************************************++
  2850. Routine Description:
  2851. UlpInsertFilterEntry :
  2852. Inserts a filter entry to the filter list of the flow.
  2853. Arguments:
  2854. pEntry - The filter entry to be added to the flow list
  2855. --***************************************************************************/
  2856. VOID
  2857. UlpInsertFilterEntry(
  2858. IN PUL_TCI_FILTER pEntry,
  2859. IN OUT PUL_TCI_FLOW pFlow
  2860. )
  2861. {
  2862. LONGLONG listSize;
  2863. KIRQL oldIrql;
  2864. //
  2865. // Sanity check.
  2866. //
  2867. ASSERT(pEntry);
  2868. ASSERT(IS_VALID_TCI_FILTER(pEntry));
  2869. ASSERT(pFlow);
  2870. //
  2871. // add to the list
  2872. //
  2873. UlAcquireSpinLock( &pFlow->FilterListSpinLock, &oldIrql );
  2874. InsertHeadList( &pFlow->FilterList, &pEntry->Linkage );
  2875. pFlow->FilterListSize += 1;
  2876. listSize = pFlow->FilterListSize;
  2877. UlReleaseSpinLock( &pFlow->FilterListSpinLock, oldIrql );
  2878. ASSERT( listSize >= 1);
  2879. }
  2880. /***************************************************************************++
  2881. Routine Description:
  2882. UlRemoveFilterEntry :
  2883. Removes a filter entry frm the filter list of the flow.
  2884. Arguments:
  2885. pEntry - The filter entry to be removed from the flow list
  2886. --***************************************************************************/
  2887. VOID
  2888. UlpRemoveFilterEntry(
  2889. IN PUL_TCI_FILTER pEntry,
  2890. IN OUT PUL_TCI_FLOW pFlow
  2891. )
  2892. {
  2893. LONGLONG listSize;
  2894. KIRQL oldIrql;
  2895. //
  2896. // Sanity check.
  2897. //
  2898. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  2899. ASSERT(IS_VALID_TCI_FILTER(pEntry));
  2900. //
  2901. // And the work
  2902. //
  2903. UlAcquireSpinLock( &pFlow->FilterListSpinLock, &oldIrql );
  2904. RemoveEntryList( &pEntry->Linkage );
  2905. pFlow->FilterListSize -= 1;
  2906. listSize = pFlow->FilterListSize;
  2907. pEntry->Linkage.Flink = pEntry->Linkage.Blink = NULL;
  2908. UlReleaseSpinLock( &pFlow->FilterListSpinLock, oldIrql );
  2909. ASSERT( listSize >= 0 );
  2910. UlTrace( TC, ("Http!UlpRemoveFilterEntry: FilterEntry %p removed/deleted.\n",
  2911. pEntry
  2912. ));
  2913. UL_FREE_POOL_WITH_SIG( pEntry, UL_TCI_FILTER_POOL_TAG );
  2914. }
  2915. //
  2916. // Various helpful utilities for TCI module
  2917. //
  2918. /***************************************************************************++
  2919. Routine Description:
  2920. Find the flow in the cgroups flow list by looking at the IP address
  2921. of each flows interface. The rule is cgroup will install one flow
  2922. on each interface available.
  2923. By having a flow list in each cgroup we are able to do a faster
  2924. flow lookup. This is more scalable than doing a linear search for
  2925. all the flows of the interface.
  2926. Arguments:
  2927. pOwner - The config group of the site OR the control channel
  2928. Global - Must be TRUE if the owner is control channel.
  2929. InterfaceID - Interface ID
  2930. LinkID - LinkID
  2931. Return Value:
  2932. PUL_TCI_FLOW - The flow we found OR NULL if we couldn't find one.
  2933. --***************************************************************************/
  2934. PUL_TCI_FLOW
  2935. UlpFindFlow(
  2936. IN PVOID pOwner,
  2937. IN BOOLEAN Global,
  2938. IN ULONG InterfaceId,
  2939. IN ULONG LinkId
  2940. )
  2941. {
  2942. PLIST_ENTRY pFlowListHead;
  2943. PLIST_ENTRY pFlowEntry;
  2944. PUL_TCI_FLOW pFlow;
  2945. //
  2946. // Sanity check and dispatch the flowlist.
  2947. //
  2948. PAGED_CODE();
  2949. if (Global)
  2950. {
  2951. PUL_CONTROL_CHANNEL
  2952. pControlChannel = (PUL_CONTROL_CHANNEL) pOwner;
  2953. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  2954. pFlowListHead = &pControlChannel->FlowListHead;
  2955. }
  2956. else
  2957. {
  2958. PUL_CONFIG_GROUP_OBJECT
  2959. pConfigGroup = (PUL_CONFIG_GROUP_OBJECT) pOwner;
  2960. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  2961. pFlowListHead = &pConfigGroup->FlowListHead;
  2962. }
  2963. //
  2964. // Walk the list and try to find the flow.
  2965. //
  2966. pFlowEntry = pFlowListHead->Flink;
  2967. while ( pFlowEntry != pFlowListHead )
  2968. {
  2969. pFlow = CONTAINING_RECORD(
  2970. pFlowEntry,
  2971. UL_TCI_FLOW,
  2972. Siblings
  2973. );
  2974. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  2975. ASSERT(IS_VALID_TCI_INTERFACE(pFlow->pInterface));
  2976. if(UlpMatchTcInterface(
  2977. pFlow->pInterface,
  2978. InterfaceId,
  2979. LinkId
  2980. ))
  2981. {
  2982. return pFlow;
  2983. }
  2984. pFlowEntry = pFlowEntry->Flink;
  2985. }
  2986. //
  2987. // Couldn't find one. Actually this could be the right time to
  2988. // refresh the flow list of this cgroup or control channel !!
  2989. //
  2990. return NULL;
  2991. }
  2992. /***************************************************************************++
  2993. Routine Description:
  2994. UlpTcDeviceControl :
  2995. Arguments:
  2996. As usual
  2997. Return Value:
  2998. NTSTATUS - Completion status.
  2999. --***************************************************************************/
  3000. NTSTATUS
  3001. UlpTcDeviceControl(
  3002. IN HANDLE FileHandle,
  3003. IN HANDLE EventHandle,
  3004. IN PIO_APC_ROUTINE ApcRoutine,
  3005. IN PVOID ApcContext,
  3006. OUT PIO_STATUS_BLOCK pIoStatusBlock,
  3007. IN ULONG Ioctl,
  3008. IN PVOID InBuffer,
  3009. IN ULONG InBufferSize,
  3010. IN PVOID OutBuffer,
  3011. IN ULONG OutBufferSize
  3012. )
  3013. {
  3014. NTSTATUS Status;
  3015. UNREFERENCED_PARAMETER(EventHandle);
  3016. UNREFERENCED_PARAMETER(ApcRoutine);
  3017. UNREFERENCED_PARAMETER(ApcContext);
  3018. //
  3019. // Sanity check.
  3020. //
  3021. PAGED_CODE();
  3022. Status = STATUS_SUCCESS;
  3023. Status = ZwDeviceIoControlFile(
  3024. FileHandle, // FileHandle
  3025. NULL, // Event
  3026. NULL, // ApcRoutine
  3027. NULL, // ApcContext
  3028. pIoStatusBlock, // IoStatusBlock
  3029. Ioctl, // IoControlCode
  3030. InBuffer, // InputBuffer
  3031. InBufferSize, // InputBufferLength
  3032. OutBuffer, // OutputBuffer
  3033. OutBufferSize // OutputBufferLength
  3034. );
  3035. if (Status == STATUS_PENDING)
  3036. {
  3037. Status = ZwWaitForSingleObject(
  3038. FileHandle, // Handle
  3039. TRUE, // Alertable
  3040. NULL // Timeout
  3041. );
  3042. Status = pIoStatusBlock->Status;
  3043. }
  3044. return Status;
  3045. }
  3046. #if DBG
  3047. /***************************************************************************++
  3048. Routine Description:
  3049. UlDumpTCInterface :
  3050. Helper utility to display interface content.
  3051. Arguments:
  3052. PUL_TCI_INTERFACE - TC Interface to be dumped
  3053. --***************************************************************************/
  3054. VOID
  3055. UlDumpTCInterface(
  3056. IN PUL_TCI_INTERFACE pTcIfc
  3057. )
  3058. {
  3059. ASSERT(IS_VALID_TCI_INTERFACE(pTcIfc));
  3060. UlTrace( TC,("Http!UlDumpTCInterface: \n pTcIfc @ %p\n"
  3061. "\t Signature = %08lx \n",
  3062. pTcIfc, pTcIfc->Signature));
  3063. UlTrace( TC,(
  3064. "\t IsQoSEnabled: = %u \n"
  3065. "\t IfIndex: = %d \n"
  3066. "\t NameLength: = %u \n"
  3067. "\t Name: = %ws \n"
  3068. "\t InstanceIDLength: = %u \n"
  3069. "\t InstanceID: = %ws \n"
  3070. "\t FlowListSize: = %d \n"
  3071. "\t AddrListBytesCount: = %d \n"
  3072. "\t pAddressListDesc: = %p \n",
  3073. pTcIfc->IsQoSEnabled,
  3074. pTcIfc->IfIndex,
  3075. pTcIfc->NameLength,
  3076. pTcIfc->Name,
  3077. pTcIfc->InstanceIDLength,
  3078. pTcIfc->InstanceID,
  3079. pTcIfc->FlowListSize,
  3080. pTcIfc->AddrListBytesCount,
  3081. pTcIfc->pAddressListDesc
  3082. ));
  3083. }
  3084. /***************************************************************************++
  3085. Routine Description:
  3086. UlDumpTCFlow :
  3087. Helper utility to display interface content.
  3088. Arguments:
  3089. PUL_TCI_FLOW - TC Flow to be dumped
  3090. --***************************************************************************/
  3091. VOID
  3092. UlDumpTCFlow(
  3093. IN PUL_TCI_FLOW pFlow
  3094. )
  3095. {
  3096. ASSERT(IS_VALID_TCI_FLOW(pFlow));
  3097. UlTrace( TC,
  3098. ("Http!UlDumpTCFlow: \n"
  3099. " pFlow @ %p\n"
  3100. "\t Signature = %08lx \n"
  3101. "\t pInterface @ %p \n"
  3102. "\t FlowHandle = %d \n"
  3103. "\t GenFlow @ %p \n"
  3104. "\t FlowRate KB/s = %d \n"
  3105. "\t FilterListSize = %I64d \n"
  3106. "\t pOwner (store) = %p \n"
  3107. ,
  3108. pFlow,
  3109. pFlow->Signature,
  3110. pFlow->pInterface,
  3111. pFlow->FlowHandle,
  3112. &pFlow->GenFlow,
  3113. pFlow->GenFlow.SendingFlowspec.TokenRate / 1024,
  3114. pFlow->FilterListSize,
  3115. pFlow->pOwner
  3116. ));
  3117. UNREFERENCED_PARAMETER(pFlow);
  3118. }
  3119. /***************************************************************************++
  3120. Routine Description:
  3121. UlDumpTCFilter :
  3122. Helper utility to display filter structure content.
  3123. Arguments:
  3124. PUL_TCI_FILTER pFilter
  3125. --***************************************************************************/
  3126. VOID
  3127. UlDumpTCFilter(
  3128. IN PUL_TCI_FILTER pFilter
  3129. )
  3130. {
  3131. ASSERT(IS_VALID_TCI_FILTER(pFilter));
  3132. UlTrace( TC,
  3133. ("Http!UlDumpTCFilter: \n"
  3134. " pFilter @ %p\n"
  3135. "\t Signature = %08lx \n"
  3136. "\t pHttpConnection = %p \n"
  3137. "\t FilterHandle = %d \n",
  3138. pFilter,
  3139. pFilter->Signature,
  3140. pFilter->pHttpConnection,
  3141. pFilter->FilterHandle
  3142. ));
  3143. UNREFERENCED_PARAMETER(pFilter);
  3144. }
  3145. #endif // DBG
  3146. /***************************************************************************++
  3147. Routine Description:
  3148. See if the Traffic Interface matches the InterfaceID & LinkID. LinkId
  3149. matches are done only for WAN connections.
  3150. Arguments:
  3151. pIntfc - The TC inteface
  3152. InterfaceId - Interface index.
  3153. LinkId - Link ID
  3154. Return Value:
  3155. TRUE - Matches.
  3156. FALSE - Does not match.
  3157. --***************************************************************************/
  3158. BOOLEAN
  3159. UlpMatchTcInterface(
  3160. IN PUL_TCI_INTERFACE pIntfc,
  3161. IN ULONG InterfaceId,
  3162. IN ULONG LinkId
  3163. )
  3164. {
  3165. NETWORK_ADDRESS UNALIGNED64 *pAddr;
  3166. NETWORK_ADDRESS_IP UNALIGNED64 *pIpNetAddr = NULL;
  3167. ULONG cAddr;
  3168. ULONG index;
  3169. if(pIntfc->IfIndex == InterfaceId)
  3170. {
  3171. // InterfaceID's matched. If it's a wan-link, we need to compare the
  3172. // LinkId with the remote address.
  3173. if(pIntfc->pAddressListDesc->MediaType == NdisMediumWan)
  3174. {
  3175. cAddr = pIntfc->pAddressListDesc->AddressList.AddressCount;
  3176. pAddr = (UNALIGNED64 NETWORK_ADDRESS *)
  3177. &pIntfc->pAddressListDesc->AddressList.Address[0];
  3178. for (index = 0; index < cAddr; index++)
  3179. {
  3180. if (pAddr->AddressType == NDIS_PROTOCOL_ID_TCP_IP)
  3181. {
  3182. pIpNetAddr =
  3183. (UNALIGNED64 NETWORK_ADDRESS_IP *)&pAddr->Address[0];
  3184. if(pIpNetAddr->in_addr == LinkId)
  3185. {
  3186. return TRUE;
  3187. }
  3188. }
  3189. pAddr = (UNALIGNED64 NETWORK_ADDRESS *)(((PUCHAR)pAddr)
  3190. + pAddr->AddressLength
  3191. + FIELD_OFFSET(NETWORK_ADDRESS, Address));
  3192. }
  3193. }
  3194. else
  3195. {
  3196. return TRUE;
  3197. }
  3198. }
  3199. return FALSE;
  3200. }