Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4521 lines
116 KiB

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