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

4839 lines
130 KiB

  1. /*
  2. ************************************************************************
  3. Copyright (c) 1996-1997 Microsoft Corporation
  4. Module Name:
  5. gpcmain.c
  6. Abstract:
  7. This file contains initialization stuff for the GPC
  8. and all the exposed APIs
  9. Author:
  10. Ofer Bar - April 15, 1997
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. ************************************************************************
  15. */
  16. #include "gpcpre.h"
  17. /*
  18. /////////////////////////////////////////////////////////////////
  19. //
  20. // globals
  21. //
  22. /////////////////////////////////////////////////////////////////
  23. */
  24. NDIS_STRING DriverName = NDIS_STRING_CONST( "\\Device\\Gpc" );
  25. GLOBAL_BLOCK glData;
  26. GPC_STAT glStat;
  27. static _init_driver = FALSE;
  28. ULONG GpcMinorVersion = 0;
  29. #ifdef STANDALONE_DRIVER
  30. GPC_EXPORTED_CALLS glGpcExportedCalls;
  31. #endif
  32. #if DBG
  33. CHAR VersionTimestamp[] = __DATE__ " " __TIME__;
  34. #endif
  35. // tags
  36. ULONG QueuedNotificationTag = 'nqpQ';
  37. ULONG PendingIrpTag = 'ippQ';
  38. ULONG CfInfoTag = 'icpQ';
  39. ULONG ClientTag = 'tcpQ';
  40. ULONG PatternTag = 'appQ';
  41. ULONG HandleFactoryTag = 'fhpQ'; // Gphf
  42. ULONG PathHashTag = 'hppQ';
  43. ULONG RhizomeTag = 'zrpQ';
  44. ULONG GenPatternDbTag = 'dppQ';
  45. ULONG FragmentDbTag = 'dfpQ';
  46. ULONG ClassificationFamilyTag = 'fcpQ';
  47. ULONG CfInfoDataTag = 'dcpQ';
  48. ULONG ClassificationBlockTag = 'bcpQ';
  49. ULONG ProtocolTag = 'tppQ';
  50. ULONG DebugTag = 'gdpQ';
  51. ULONG RequestBlockTag = 'brpQ';
  52. ULONG TcpPatternTag = 'ptpQ';
  53. ULONG TcpQueryContextTag= 'qtpQ';
  54. // Lookaside lists
  55. NPAGED_LOOKASIDE_LIST ClassificationFamilyLL;
  56. NPAGED_LOOKASIDE_LIST ClientLL;
  57. NPAGED_LOOKASIDE_LIST PatternLL;
  58. //NPAGED_LOOKASIDE_LIST CfInfoLL;
  59. NPAGED_LOOKASIDE_LIST QueuedNotificationLL;
  60. NPAGED_LOOKASIDE_LIST PendingIrpLL;
  61. ULONG ClassificationFamilyLLSize = sizeof( CF_BLOCK );
  62. ULONG ClientLLSize = sizeof( CLIENT_BLOCK );
  63. ULONG PatternLLSize = sizeof( PATTERN_BLOCK );
  64. ULONG CfInfoLLSize = sizeof( BLOB_BLOCK );
  65. ULONG QueuedNotificationLLSize = sizeof( QUEUED_NOTIFY );
  66. ULONG PendingIrpLLSize = sizeof( PENDING_IRP );
  67. /*
  68. /////////////////////////////////////////////////////////////////
  69. //
  70. // pragma
  71. //
  72. /////////////////////////////////////////////////////////////////
  73. */
  74. //#pragma NDIS_INIT_FUNCTION(DriverEntry)
  75. #if 0
  76. #pragma NDIS_PAGEABLE_FUNCTION(DriverEntry)
  77. #pragma NDIS_PAGEABLE_FUNCTION(GpcRegisterClient)
  78. #pragma NDIS_PAGEABLE_FUNCTION(GpcDeregisterClient)
  79. #pragma NDIS_PAGEABLE_FUNCTION(GpcAddCfInfo)
  80. #pragma NDIS_PAGEABLE_FUNCTION(GpcAddPattern)
  81. #pragma NDIS_PAGEABLE_FUNCTION(GpcAddCfInfoNotifyComplete)
  82. #pragma NDIS_PAGEABLE_FUNCTION(GpcModifyCfInfo)
  83. #pragma NDIS_PAGEABLE_FUNCTION(GpcModifyCfInfoNotifyComplete)
  84. #pragma NDIS_PAGEABLE_FUNCTION(GpcRemoveCfInfo)
  85. #pragma NDIS_PAGEABLE_FUNCTION(GpcRemoveCfInfoNotifyComplete)
  86. #pragma NDIS_PAGEABLE_FUNCTION(GpcRemovePattern)
  87. #endif
  88. /*
  89. /////////////////////////////////////////////////////////////////
  90. //
  91. // prototypes
  92. //
  93. /////////////////////////////////////////////////////////////////
  94. */
  95. #if DBG
  96. NTSTATUS
  97. InitializeLog();
  98. VOID
  99. FreeDebugLog(
  100. VOID);
  101. #endif
  102. VOID
  103. GpcUnload (
  104. IN PDRIVER_OBJECT DriverObject
  105. );
  106. /*
  107. ************************************************************************
  108. InitGpc -
  109. The initialization routine. It is getting called during load time
  110. and is responsible to call other initialization code.
  111. Arguments
  112. none
  113. Returns
  114. GPC_STATUS
  115. ************************************************************************
  116. */
  117. GPC_STATUS
  118. InitGpc(void)
  119. {
  120. GPC_STATUS Status = STATUS_SUCCESS;
  121. ULONG i, k;
  122. TRACE(INIT, 0, 0, "InitGpc");
  123. //
  124. // init the global data
  125. //
  126. RtlZeroMemory(&glData, sizeof(glData));
  127. InitializeListHead(&glData.CfList);
  128. NDIS_INIT_LOCK(&glData.Lock);
  129. //
  130. // Create a new Request list for blocked requests... [276945]
  131. //
  132. InitializeListHead(&glData.gRequestList);
  133. NDIS_INIT_LOCK(&glData.RequestListLock);
  134. k = sizeof(PROTOCOL_BLOCK) * GPC_PROTOCOL_TEMPLATE_MAX;
  135. GpcAllocMem(&glData.pProtocols, k, ProtocolTag);
  136. if (glData.pProtocols == NULL) {
  137. Status = GPC_STATUS_NO_MEMORY;
  138. TRACE(INIT, Status, 0, "InitGpc==>");
  139. return Status;
  140. }
  141. RtlZeroMemory(glData.pProtocols, k);
  142. RtlZeroMemory(&glStat, sizeof(glStat));
  143. for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
  144. if ((Status = InitPatternTimer(i)) != STATUS_SUCCESS) {
  145. TRACE(INIT, Status, i, "InitGpc, timer==>");
  146. break;
  147. }
  148. //
  149. // init rest of strcture
  150. //
  151. glData.pProtocols[i].ProtocolTemplate = i;
  152. glData.pProtocols[i].SpecificPatternCount = 0;
  153. glData.pProtocols[i].AutoSpecificPatternCount = 0;
  154. glData.pProtocols[i].GenericPatternCount = 0;
  155. switch (i) {
  156. case GPC_PROTOCOL_TEMPLATE_IP:
  157. k = sizeof(GPC_IP_PATTERN);
  158. break;
  159. case GPC_PROTOCOL_TEMPLATE_IPX:
  160. k = sizeof(GPC_IPX_PATTERN);
  161. break;
  162. default:
  163. ASSERT(0);
  164. }
  165. glData.pProtocols[i].PatternSize = k;
  166. //
  167. // init specific pattern db
  168. //
  169. Status = InitSpecificPatternDb(&glData.pProtocols[i].SpecificDb, k);
  170. if (!NT_SUCCESS(Status)) {
  171. TRACE(INIT, Status, 0, "InitGpc==>");
  172. break;
  173. }
  174. //
  175. // init fragments db
  176. //
  177. Status = InitFragmentDb((PFRAGMENT_DB *)&glData.pProtocols[i].pProtocolDb);
  178. if (!NT_SUCCESS(Status)) {
  179. // SS202
  180. //
  181. UninitSpecificPatternDb(&glData.pProtocols[i].SpecificDb);
  182. TRACE(INIT, Status, 0, "InitGpc==>");
  183. break;
  184. }
  185. } // for (i...)
  186. if (!NT_SUCCESS (Status)) {
  187. TRACE(INIT, Status, 0, "InitGpc b");
  188. goto Cleanup;
  189. }
  190. //
  191. // init handle mapping table
  192. //
  193. Status = InitMapHandles();
  194. if (!NT_SUCCESS(Status)) {
  195. TRACE(INIT, Status, 0, "InitGpc b");
  196. goto Cleanup;
  197. }
  198. //
  199. // init classification index table
  200. //
  201. Status = InitClassificationHandleTbl(&glData.pCHTable);
  202. if (!NT_SUCCESS(Status)) {
  203. TRACE(INIT, Status, 0, "InitGpc c");
  204. goto Cleanup;
  205. }
  206. #ifdef STANDALONE_DRIVER
  207. //
  208. // initialize the exported calls table
  209. //
  210. glGpcExportedCalls.GpcVersion = GpcMajorVersion;
  211. glGpcExportedCalls.GpcGetCfInfoClientContextHandler = GpcGetCfInfoClientContext;
  212. glGpcExportedCalls.GpcGetCfInfoClientContextWithRefHandler = GpcGetCfInfoClientContextWithRef;
  213. glGpcExportedCalls.GpcGetUlongFromCfInfoHandler = GpcGetUlongFromCfInfo;
  214. glGpcExportedCalls.GpcRegisterClientHandler = GpcRegisterClient;
  215. glGpcExportedCalls.GpcDeregisterClientHandler = GpcDeregisterClient;
  216. glGpcExportedCalls.GpcAddCfInfoHandler = GpcAddCfInfo;
  217. glGpcExportedCalls.GpcAddPatternHandler = GpcAddPattern;
  218. glGpcExportedCalls.GpcAddCfInfoNotifyCompleteHandler = GpcAddCfInfoNotifyComplete;
  219. glGpcExportedCalls.GpcModifyCfInfoHandler = GpcModifyCfInfo;
  220. glGpcExportedCalls.GpcModifyCfInfoNotifyCompleteHandler = GpcModifyCfInfoNotifyComplete;
  221. glGpcExportedCalls.GpcRemoveCfInfoHandler = GpcRemoveCfInfo;
  222. glGpcExportedCalls.GpcRemoveCfInfoNotifyCompleteHandler = GpcRemoveCfInfoNotifyComplete;
  223. glGpcExportedCalls.GpcRemovePatternHandler = GpcRemovePattern;
  224. glGpcExportedCalls.GpcClassifyPatternHandler = GpcClassifyPattern;
  225. glGpcExportedCalls.GpcClassifyPacketHandler = GpcClassifyPacket;
  226. //glGpcExportedCalls.GpcEnumCfInfoHandler = GpcEnumCfInfo;
  227. #endif
  228. #if DBG
  229. //
  230. // for the debug version, add a ULONG_PTR for the GPC mark ULONG.
  231. // ULONG_PTR is used to ensure 8-byte alignment of the returned block on
  232. // 64-bit platforms.
  233. //
  234. ClassificationFamilyLLSize += sizeof( ULONG_PTR );
  235. ClientLLSize += sizeof( ULONG_PTR );
  236. PatternLLSize += sizeof( ULONG_PTR );
  237. CfInfoLLSize += sizeof( ULONG_PTR );
  238. QueuedNotificationLLSize += sizeof( ULONG_PTR );
  239. PendingIrpLLSize += sizeof( ULONG_PTR );
  240. #endif
  241. NdisInitializeNPagedLookasideList(&ClassificationFamilyLL,
  242. NULL,
  243. NULL,
  244. 0,
  245. ClassificationFamilyLLSize,
  246. ClassificationFamilyTag,
  247. (USHORT)0);
  248. NdisInitializeNPagedLookasideList(&ClientLL,
  249. NULL,
  250. NULL,
  251. 0,
  252. ClientLLSize,
  253. ClientTag,
  254. (USHORT)0);
  255. NdisInitializeNPagedLookasideList(&PatternLL,
  256. NULL,
  257. NULL,
  258. 0,
  259. PatternLLSize,
  260. PatternTag,
  261. (USHORT)0);
  262. /*NdisInitializeNPagedLookasideList(&CfInfoLL,
  263. NULL,
  264. NULL,
  265. 0,
  266. CfInfoLLSize,
  267. CfInfoTag,
  268. (USHORT)0);*/
  269. NdisInitializeNPagedLookasideList(&QueuedNotificationLL,
  270. NULL,
  271. NULL,
  272. 0,
  273. QueuedNotificationLLSize,
  274. QueuedNotificationTag,
  275. (USHORT)0);
  276. NdisInitializeNPagedLookasideList(&PendingIrpLL,
  277. NULL,
  278. NULL,
  279. 0,
  280. PendingIrpLLSize,
  281. PendingIrpTag,
  282. (USHORT)0);
  283. //
  284. // Load cofiguration from registry
  285. // loads default values if reg keys not available
  286. //
  287. GpcReadRegistry();
  288. TRACE(INIT, Status, 0, "InitGpc==>");
  289. Cleanup:
  290. // SS202
  291. // Much leaking above, needed common cleanup block
  292. //
  293. if (!NT_SUCCESS(Status))
  294. {
  295. UninitMapHandles();
  296. if (glData.pProtocols != NULL)
  297. {
  298. for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++)
  299. {
  300. UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb);
  301. UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb);
  302. }
  303. GpcFreeMem(glData.pProtocols, ProtocolTag);
  304. glData.pProtocols = NULL;
  305. }
  306. }
  307. return Status;
  308. }
  309. /*
  310. ************************************************************************
  311. DriverEntry -
  312. The driver's entry point.
  313. Arguments
  314. DriverObject - Pointer to the driver object created by the system.
  315. RegistryPath - string path to the registry.
  316. Returns
  317. NT_STATUS
  318. ************************************************************************
  319. */
  320. NTSTATUS
  321. DriverEntry(
  322. IN PDRIVER_OBJECT DriverObject,
  323. IN PUNICODE_STRING RegistryPath
  324. )
  325. {
  326. GPC_STATUS Status;
  327. ULONG dummy = 0;
  328. PWCHAR EventLogString = DriverName.Buffer;
  329. _init_driver = TRUE;
  330. #if DBG
  331. //
  332. // first thing, init the trace log
  333. //
  334. Status = InitializeLog();
  335. if (Status != STATUS_SUCCESS) {
  336. KdPrint(("!!! GPC Failed to initialize trace log !!!\n", Status));
  337. }
  338. #endif
  339. DriverObject->DriverUnload = GpcUnload;
  340. //
  341. // Call the init routine
  342. //
  343. Status = InitGpc();
  344. if (NT_SUCCESS(Status)) {
  345. //
  346. // initialize the file system device
  347. //
  348. Status = (GPC_STATUS)IoctlInitialize(DriverObject, &dummy);
  349. if (!NT_SUCCESS(Status)) {
  350. NdisWriteEventLogEntry(DriverObject,
  351. EVENT_TRANSPORT_REGISTER_FAILED,
  352. GPC_ERROR_INIT_IOCTL,
  353. 1,
  354. &EventLogString,
  355. 0,
  356. NULL);
  357. }
  358. } else {
  359. NdisWriteEventLogEntry(DriverObject,
  360. EVENT_TRANSPORT_REGISTER_FAILED,
  361. GPC_ERROR_INIT_MAIN,
  362. 1,
  363. &EventLogString,
  364. 0,
  365. NULL);
  366. #if DBG
  367. FreeDebugLog ();
  368. #endif
  369. }
  370. #if DBG
  371. if (!NT_SUCCESS(Status)) {
  372. KdPrint(("!!! GPC loading Failed (%08X) !!!\n", Status));
  373. }
  374. #endif
  375. return (NTSTATUS)Status;
  376. } // end DriverEntry
  377. VOID
  378. GpcUnload(
  379. IN PDRIVER_OBJECT DriverObject
  380. )
  381. {
  382. ULONG i;
  383. NdisDeleteNPagedLookasideList(&ClassificationFamilyLL);
  384. NdisDeleteNPagedLookasideList(&ClientLL);
  385. NdisDeleteNPagedLookasideList(&PatternLL);
  386. // NdisDeleteNPagedLookasideList(&CfInfoLL);
  387. NdisDeleteNPagedLookasideList(&QueuedNotificationLL);
  388. NdisDeleteNPagedLookasideList(&PendingIrpLL);
  389. UninitClassificationHandleTbl(glData.pCHTable);
  390. UninitMapHandles();
  391. for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
  392. UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb);
  393. UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb);
  394. }
  395. GpcFreeMem(glData.pProtocols, ProtocolTag);
  396. #if DBG
  397. FreeDebugLog ();
  398. #endif
  399. }
  400. /*
  401. ************************************************************************
  402. GpcGetCfInfoClientContext -
  403. Returns the client context for blob
  404. Arguments
  405. ClientHandle - the calling client's handle
  406. ClassificationHandle - needless to say
  407. Returns
  408. A CfInfo client context or NULL if the classification
  409. handle is invalid
  410. ************************************************************************
  411. */
  412. GPC_STATUS
  413. GpcGetCfInfoClientContext(
  414. IN GPC_HANDLE ClientHandle,
  415. IN CLASSIFICATION_HANDLE ClassificationHandle,
  416. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext
  417. )
  418. {
  419. PBLOB_BLOCK pBlob;
  420. GPC_CLIENT_HANDLE h;
  421. KIRQL CHirql;
  422. NTSTATUS Status;
  423. PCLASSIFICATION_BLOCK pCB;
  424. TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetCfInfoClientContext");
  425. pCB = NULL;
  426. if (ClientHandle == NULL) {
  427. *pClientCfInfoContext = NULL;
  428. return GPC_STATUS_INVALID_PARAMETER;
  429. }
  430. READ_LOCK(&glData.ChLock, &CHirql);
  431. pBlob = (PBLOB_BLOCK)dereference_HF_handle_with_cb(
  432. glData.pCHTable,
  433. ClassificationHandle,
  434. GetCFIndexFromClient(ClientHandle));
  435. if (pBlob == NULL) {
  436. pCB = dereference_HF_handle(
  437. glData.pCHTable,
  438. ClassificationHandle);
  439. READ_UNLOCK(&glData.ChLock, CHirql);
  440. if (!pCB) {
  441. Status = GPC_STATUS_INVALID_HANDLE;
  442. } else {
  443. Status = GPC_STATUS_NOT_FOUND;
  444. }
  445. *pClientCfInfoContext = 0;
  446. return Status;
  447. }
  448. #if DBG
  449. {
  450. //
  451. // Get the client index to reference into the ClientCtx table
  452. //
  453. ULONG t = GetClientIndexFromClient(ClientHandle);
  454. ASSERT(t < MAX_CLIENTS_CTX_PER_BLOB);
  455. TRACE(CLASSIFY, ClassificationHandle, pBlob->arClientCtx[t],
  456. "GpcGetCfInfoClientContext (ctx)");
  457. }
  458. #endif
  459. h = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
  460. READ_UNLOCK(&glData.ChLock, CHirql);
  461. TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContext==>");
  462. *pClientCfInfoContext = h;
  463. return GPC_STATUS_SUCCESS;
  464. }
  465. /*
  466. ************************************************************************
  467. GpcGetCfInfoClientContextWithRef -
  468. Returns the client context for blob and increments a Dword provided by
  469. the client. This function can be used by clients to synchronize access
  470. to their structures on the remove and send path.
  471. Arguments
  472. ClientHandle - the calling client's handle
  473. ClassificationHandle - needless to say
  474. Offset - Offset to location that needs to be incremented.
  475. Returns
  476. A CfInfo client context or NULL if the classification
  477. handle is invalid
  478. ************************************************************************
  479. */
  480. GPC_CLIENT_HANDLE
  481. GpcGetCfInfoClientContextWithRef(
  482. IN GPC_HANDLE ClientHandle,
  483. IN CLASSIFICATION_HANDLE ClassificationHandle,
  484. IN ULONG Offset
  485. )
  486. {
  487. PBLOB_BLOCK pBlob;
  488. GPC_CLIENT_HANDLE h;
  489. KIRQL CHirql;
  490. PULONG RefPtr = NULL;
  491. TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetCfInfoClientContextWithRef");
  492. if (ClientHandle == NULL)
  493. return NULL;
  494. READ_LOCK(&glData.ChLock, &CHirql);
  495. pBlob = (PBLOB_BLOCK)dereference_HF_handle_with_cb(
  496. glData.pCHTable,
  497. ClassificationHandle,
  498. GetCFIndexFromClient(ClientHandle));
  499. if (pBlob == NULL) {
  500. READ_UNLOCK(&glData.ChLock, CHirql);
  501. return NULL;
  502. }
  503. #if DBG
  504. {
  505. //
  506. // Get the client index to reference into the ClientCtx table
  507. //
  508. ULONG t = GetClientIndexFromClient(ClientHandle);
  509. ASSERT(t < MAX_CLIENTS_CTX_PER_BLOB);
  510. TRACE(CLASSIFY, ClassificationHandle, pBlob->arClientCtx[t],
  511. "GpcGetCfInfoClientContextWithRef (ctx)");
  512. }
  513. #endif
  514. h = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
  515. //
  516. // As part of 390882, it has been noted that sometimes the handle can
  517. // NULL, this could be either due to an Auto pattern or a generic
  518. // pattern.
  519. //
  520. if (!h) {
  521. READ_UNLOCK(&glData.ChLock, CHirql);
  522. TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContextWithRef==>");
  523. return NULL;
  524. }
  525. // The GPC Clients wants GPC to increment the memory at this offset.
  526. ASSERT(h);
  527. RefPtr = (PULONG) (((PUCHAR)h) + Offset);
  528. InterlockedIncrement(RefPtr);
  529. //(*((PUCHAR)h + Offset))++;
  530. READ_UNLOCK(&glData.ChLock, CHirql);
  531. TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContextWithRef==>");
  532. return h;
  533. }
  534. /*
  535. ************************************************************************
  536. GpcGetUlongFromCfInfo -
  537. Returns a ulong in the blob data pointer from the classification handle for
  538. the particular client.
  539. Arguments
  540. ClientHandle - the client handle
  541. ClassificationHandle - the classification handle
  542. Offset - oofset in bytes into the CfInfo structure
  543. pValue - store for the returned value
  544. Returns
  545. GPC_STATUS
  546. ************************************************************************
  547. */
  548. GPC_STATUS
  549. GpcGetUlongFromCfInfo(
  550. IN GPC_HANDLE ClientHandle,
  551. IN CLASSIFICATION_HANDLE ClassificationHandle,
  552. IN ULONG Offset,
  553. IN PULONG pValue
  554. )
  555. {
  556. KIRQL irql;
  557. PCLASSIFICATION_BLOCK pCB;
  558. PBLOB_BLOCK pBlob;
  559. ASSERT( pValue );
  560. TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetUlongFromCfInfo");
  561. if (ClientHandle == NULL)
  562. return GPC_STATUS_INVALID_PARAMETER;
  563. READ_LOCK(&glData.ChLock, &irql);
  564. pCB = (PCLASSIFICATION_BLOCK)dereference_HF_handle(
  565. glData.pCHTable,
  566. ClassificationHandle);
  567. if (pCB == NULL) {
  568. READ_UNLOCK(&glData.ChLock, irql);
  569. return GPC_STATUS_INVALID_HANDLE;
  570. }
  571. pBlob = pCB->arpBlobBlock[GetCFIndexFromClient(ClientHandle)];
  572. if (pBlob == NULL) {
  573. TRACE(CLASSIFY, pBlob, 0, "GpcGetUlongFromCfInfo-->");
  574. READ_UNLOCK(&glData.ChLock, irql);
  575. return GPC_STATUS_NOT_FOUND;
  576. }
  577. TRACE(CLASSIFY, ClassificationHandle, pBlob->pClientData, "GpcGetUlongFromCfInfo (2)");
  578. ASSERT( Offset+sizeof(ULONG) <= pBlob->ClientDataSize );
  579. ASSERT( pBlob->pClientData );
  580. if (pBlob->pClientData == NULL) {
  581. READ_UNLOCK(&glData.ChLock, irql);
  582. return (GPC_STATUS_FAILURE);
  583. }
  584. *pValue = *(PULONG)((PUCHAR)pBlob->pClientData + Offset);
  585. READ_UNLOCK(&glData.ChLock, irql);
  586. TRACE(CLASSIFY, pBlob, *pValue, "GpcGetUlongFromCfInfo==>");
  587. return GPC_STATUS_SUCCESS;
  588. }
  589. /*
  590. ************************************************************************
  591. GetClientCtxAndUlongFromCfInfo -
  592. Returns a ulong in the blob data pointer AND the client context
  593. from the classification handle for the particular client.
  594. Arguments
  595. ClientHandle - the client handle
  596. ClassificationHandle - the classification handle
  597. Offset - oofset in bytes into the CfInfo structure
  598. pValue - store for the returned value
  599. Returns
  600. GPC_STATUS
  601. ************************************************************************
  602. */
  603. GPC_STATUS
  604. GetClientCtxAndUlongFromCfInfo(
  605. IN GPC_HANDLE ClientHandle,
  606. IN OUT PCLASSIFICATION_HANDLE pClassificationHandle,
  607. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext,
  608. IN ULONG Offset,
  609. IN PULONG pValue
  610. )
  611. {
  612. PCLASSIFICATION_BLOCK pCB;
  613. KIRQL irql;
  614. PBLOB_BLOCK pBlob;
  615. ASSERT( ClientHandle );
  616. ASSERT( pClientCfInfoContext || pValue );
  617. TRACE(CLASSIFY, ClientHandle, pClassificationHandle, "GetClientCtxAndUlongFromCfInfo");
  618. READ_LOCK(&glData.ChLock, &irql);
  619. pCB = (PCLASSIFICATION_BLOCK)dereference_HF_handle(
  620. glData.pCHTable,
  621. *pClassificationHandle
  622. );
  623. TRACE(CLASSIFY, pCB, GetCFIndexFromClient(ClientHandle), "GetClientCtxAndUlongFromCfInfo (2)");
  624. if (pCB == NULL) {
  625. //
  626. // didn't find the reference, which means the CH is probably invalid
  627. // reset it to 0 to indicate the caller that it should add a new one
  628. //
  629. *pClassificationHandle = 0;
  630. READ_UNLOCK(&glData.ChLock, irql);
  631. return GPC_STATUS_NOT_FOUND;
  632. }
  633. ASSERT(GetClientIndexFromClient(ClientHandle) < MAX_CLIENTS_CTX_PER_BLOB);
  634. pBlob = pCB->arpBlobBlock[GetCFIndexFromClient(ClientHandle)];
  635. if (pBlob == NULL) {
  636. TRACE(CLASSIFY, pBlob, 0, "GetClientCtxAndUlongFromCfInfo-->");
  637. READ_UNLOCK(&glData.ChLock, irql);
  638. return GPC_STATUS_NOT_FOUND;
  639. }
  640. TRACE(CLASSIFY, *pClassificationHandle, pBlob->pClientData, "GetClientCtxAndUlongFromCfInfo (3)");
  641. ASSERT( Offset+sizeof(ULONG) <= pBlob->ClientDataSize );
  642. ASSERT( pBlob->pClientData );
  643. if (pClientCfInfoContext) {
  644. *pClientCfInfoContext = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
  645. TRACE(CLASSIFY, pBlob, *pClientCfInfoContext, "GetClientCtxAndUlongFromCfInfo==>");
  646. }
  647. if (pValue) {
  648. *pValue = *(PULONG)((PUCHAR)pBlob->pClientData + Offset);
  649. TRACE(CLASSIFY, pBlob, *pValue, "GetClientCtxAndUlongFromCfInfo==>");
  650. }
  651. READ_UNLOCK(&glData.ChLock, irql);
  652. return GPC_STATUS_SUCCESS;
  653. }
  654. /*
  655. ************************************************************************
  656. GpcRegisterClient -
  657. This will register the client in the GPC and return a client handle.
  658. If another client already registered for the same CF, we link this one
  659. on a list for the CF. The first client for the CF will cause a CF block
  660. to be created. CFs are identified by CfName. The other parameters will also
  661. be set in the client's block.
  662. Arguments
  663. CfId - Id of the classification family
  664. Flags - operation modes for the client:
  665. CF_FRAGMENT
  666. MaxPriorities - max number of priorities the client will ever use
  667. pClientFuncList - list of callback functions
  668. ClientContext - client context, GPC will use it in callbacks
  669. pClientHandle - OUT, the returned client handle
  670. Returns
  671. GPC_STATUS
  672. ************************************************************************
  673. */
  674. GPC_STATUS
  675. GpcRegisterClient(
  676. IN ULONG CfId,
  677. IN ULONG Flags,
  678. IN ULONG MaxPriorities,
  679. IN PGPC_CLIENT_FUNC_LIST pClientFuncList,
  680. IN GPC_CLIENT_HANDLE ClientContext,
  681. OUT PGPC_HANDLE pClientHandle
  682. )
  683. {
  684. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  685. PCF_BLOCK pCf;
  686. PCLIENT_BLOCK pClient= NULL;
  687. ULONG i;
  688. PLIST_ENTRY pHead, pEntry;
  689. KIRQL irql;
  690. TRACE(REGISTER, CfId, ClientContext, "GpcRegisterClient");
  691. *pClientHandle = NULL;
  692. if (!_init_driver) {
  693. return GPC_STATUS_NOTREADY;
  694. }
  695. //
  696. // verify the CF Id
  697. //
  698. if (CfId >= GPC_CF_MAX) {
  699. TRACE(REGISTER, GPC_STATUS_INVALID_PARAMETER, CfId, "GpcRegisterClient-->");
  700. StatInc(RejectedCf);
  701. return GPC_STATUS_INVALID_PARAMETER;
  702. }
  703. //
  704. // verify the maximum number of priorities
  705. //
  706. if (MaxPriorities > GPC_PRIORITY_MAX) {
  707. TRACE(REGISTER, GPC_STATUS_INVALID_PARAMETER, MaxPriorities, "GpcRegisterClient~~>");
  708. StatInc(RejectedCf);
  709. return GPC_STATUS_INVALID_PARAMETER;
  710. }
  711. if (MaxPriorities == 0) {
  712. MaxPriorities = 1;
  713. }
  714. //
  715. // find the CF or create a new one
  716. //
  717. NDIS_LOCK(&glData.Lock);
  718. pHead = &glData.CfList;
  719. pEntry = pHead->Flink;
  720. pCf = NULL;
  721. while (pCf == NULL && pEntry != pHead) {
  722. pCf = CONTAINING_RECORD(pEntry, CF_BLOCK, Linkage);
  723. if (pCf->AssignedIndex != CfId) {
  724. pCf = NULL;
  725. }
  726. pEntry = pEntry->Flink;
  727. }
  728. if (pCf == NULL) {
  729. //
  730. // create a new CF
  731. //
  732. pCf = CreateNewCfBlock(CfId, MaxPriorities);
  733. if (pCf == NULL) {
  734. NDIS_UNLOCK(&glData.Lock);
  735. return GPC_STATUS_NO_MEMORY;
  736. }
  737. //
  738. // add the new CF to the list
  739. //
  740. GpcInsertTailList(&glData.CfList, &pCf->Linkage);
  741. }
  742. //
  743. // grab the CF lock before releasing the global lock
  744. //
  745. NDIS_UNLOCK(&glData.Lock);
  746. RSC_WRITE_LOCK(&pCf->ClientSync, &irql);
  747. NDIS_LOCK(&pCf->Lock);
  748. //
  749. // create a new client block and chain it on the CF block
  750. //
  751. pClient = CreateNewClientBlock();
  752. if (pClient == NULL) {
  753. //
  754. // oops
  755. //
  756. NDIS_UNLOCK(&pCf->Lock);
  757. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  758. TRACE(REGISTER, GPC_STATUS_RESOURCES, 0, "GpcRegisterClient==>");
  759. StatInc(RejectedCf);
  760. return GPC_STATUS_NO_MEMORY;
  761. }
  762. //
  763. // assign a new index to the client. This will also mark the index
  764. // as busy for this CF.
  765. //
  766. pClient->AssignedIndex = AssignNewClientIndex(pCf);
  767. if (pClient->AssignedIndex == (-1)) {
  768. //
  769. // too many clients
  770. //
  771. StatInc(RejectedCf);
  772. NDIS_UNLOCK(&pCf->Lock);
  773. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  774. ReleaseClientBlock(pClient);
  775. TRACE(REGISTER, GPC_STATUS_TOO_MANY_HANDLES, 0, "GpcRegisterClient==>");
  776. return GPC_STATUS_TOO_MANY_HANDLES;
  777. }
  778. //
  779. // init the client block
  780. //
  781. pClient->pCfBlock = pCf;
  782. pClient->ClientCtx = ClientContext;
  783. pClient->Flags = Flags;
  784. pClient->State = GPC_STATE_READY;
  785. if (pClientFuncList) {
  786. RtlMoveMemory(&pClient->FuncList,
  787. pClientFuncList,
  788. sizeof(GPC_CLIENT_FUNC_LIST));
  789. }
  790. //
  791. // add the client block to the CF and update CF
  792. //
  793. GpcInsertTailList(&pCf->ClientList, &pClient->ClientLinkage);
  794. pCf->NumberOfClients++;
  795. //
  796. // fill the output client handle
  797. //
  798. *pClientHandle = (GPC_CLIENT_HANDLE)pClient;
  799. //
  800. // release the lock
  801. //
  802. NDIS_UNLOCK(&pCf->Lock);
  803. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  804. #if 0
  805. //
  806. // if this is not the first client for the CF, start a working
  807. // thread to notify the client about each installed blob for the CF.
  808. // In the call include:
  809. //
  810. if (!IsListEmpty(&pCf->BlobList)) {
  811. //
  812. // this is not the first client, start a notification thread
  813. //
  814. }
  815. #endif
  816. TRACE(REGISTER, pClient, Status, "GpcRegisterClient==>");
  817. if (NT_SUCCESS(Status)) {
  818. StatInc(CreatedCf);
  819. StatInc(CurrentCf);
  820. } else {
  821. StatInc(RejectedCf);
  822. }
  823. return Status;
  824. }
  825. /*
  826. ************************************************************************
  827. GpcDeregisterClient -
  828. Deregisters the client and remove associated data from the GPC.
  829. Arguments
  830. ClientHandle - client handle
  831. Returns
  832. GPC_STATUS
  833. ************************************************************************
  834. */
  835. GPC_STATUS
  836. GpcDeregisterClient(
  837. IN GPC_HANDLE ClientHandle
  838. )
  839. {
  840. GPC_STATUS Status = STATUS_SUCCESS;
  841. PCLIENT_BLOCK pClient;
  842. PCF_BLOCK pCf;
  843. TRACE(REGISTER, ClientHandle, 0, "GpcDeregisterClient");
  844. pClient = (PCLIENT_BLOCK)ClientHandle;
  845. NDIS_LOCK(&pClient->Lock);
  846. pCf = pClient->pCfBlock;
  847. if (!IsListEmpty(&pClient->BlobList)) {
  848. Status = GPC_STATUS_NOT_EMPTY;
  849. NDIS_UNLOCK(&pClient->Lock);
  850. return Status;
  851. }
  852. if (pClient->State != GPC_STATE_READY) {
  853. //
  854. // HUH?!?
  855. // Client called to remove twice! probably caller bug
  856. // but we need to protect our selves.
  857. //
  858. NDIS_UNLOCK(&pClient->Lock);
  859. TRACE(REGISTER, GPC_STATUS_NOTREADY, 0, "GpcDeregisterClient==>");
  860. return GPC_STATUS_NOTREADY;
  861. }
  862. //
  863. // remove the client from the Cf's client list
  864. //
  865. pClient->State = GPC_STATE_REMOVE;
  866. pClient->ObjectType = GPC_ENUM_INVALID;
  867. //
  868. // release the client's mapping handle
  869. //
  870. FreeHandle(pClient->ClHandle);
  871. //
  872. // remove the client from the CF list and return the index back
  873. //
  874. #if 0
  875. NDIS_DPR_LOCK(&pCf->Lock);
  876. GpcRemoveEntryList(&pClient->ClientLinkage);
  877. ReleaseClientIndex(pCf->ClientIndexes, pClient->AssignedIndex);
  878. #endif
  879. //
  880. // decrease number of clients
  881. //
  882. if (NdisInterlockedDecrement(&pCf->NumberOfClients) == 0) {
  883. TRACE(CLIENT, pClient, pCf->NumberOfClients, "NumberOfClients");
  884. //
  885. // last client on the CF, we may release all db
  886. //
  887. //UninitializeGenericDb(&pCf->pGenericDb, pCf->MaxPriorities);
  888. }
  889. StatInc(DeletedCf);
  890. StatDec(CurrentCf);
  891. #if 0
  892. NDIS_DPR_UNLOCK(&pCf->Lock);
  893. #endif
  894. NDIS_UNLOCK(&pClient->Lock);
  895. //
  896. // release the client block
  897. //
  898. REFDEL(&pClient->RefCount, 'CLNT');
  899. TRACE(REGISTER, Status, 0, "GpcDeregisterClient==>");
  900. return Status;
  901. }
  902. /*
  903. ************************************************************************
  904. GpcAddCfInfo -
  905. Add A new blob. The blob is copied into the GPC and the GPC notifies
  906. other client for the same CF about the installation.
  907. Arguments
  908. ClientHandle - client handle
  909. CfInfoSize - size of the blob
  910. pClientCfInfoPtr - pointer to the blob
  911. ClientCfInfoContext - client's context to associate with the blob
  912. pGpcCfInfoHandle - OUT, returned blob handle
  913. Returns
  914. GPC_STATUS: SUCCESS, PENDING or FAILURE
  915. ************************************************************************
  916. */
  917. GPC_STATUS
  918. GpcAddCfInfo(
  919. IN GPC_HANDLE ClientHandle,
  920. IN ULONG CfInfoSize,
  921. IN PVOID pClientCfInfoPtr,
  922. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  923. OUT PGPC_HANDLE pGpcCfInfoHandle
  924. )
  925. {
  926. return privateGpcAddCfInfo(ClientHandle,
  927. CfInfoSize,pClientCfInfoPtr,
  928. ClientCfInfoContext,NULL,NULL,
  929. pGpcCfInfoHandle);
  930. }
  931. /*
  932. ************************************************************************
  933. PrivateGpcAddCfInfo -
  934. Add A new blob. The blob is copied into the GPC and the GPC notifies
  935. other client for the same CF about the installation.
  936. Arguments
  937. ClientHandle - client handle
  938. CfInfoSize - size of the blob
  939. pClientCfInfoPtr - pointer to the blob
  940. ClientCfInfoContext - client's context to associate with the blob
  941. pGpcCfInfoHandle - OUT, returned blob handle
  942. Returns
  943. GPC_STATUS: SUCCESS, PENDING or FAILURE
  944. ************************************************************************
  945. */
  946. GPC_STATUS
  947. privateGpcAddCfInfo(
  948. IN GPC_HANDLE ClientHandle,
  949. IN ULONG CfInfoSize,
  950. IN PVOID pClientCfInfoPtr,
  951. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  952. IN PFILE_OBJECT FileObject,
  953. IN PGPC_IP_PATTERN Pattern,
  954. OUT PGPC_HANDLE pGpcCfInfoHandle
  955. )
  956. {
  957. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  958. GPC_STATUS Status1;
  959. PCLIENT_BLOCK pClient;
  960. PCLIENT_BLOCK pNotifyClient;
  961. PCLIENT_BLOCK pNotifyClient2;
  962. PBLOB_BLOCK pBlob;
  963. PCF_BLOCK pCf;
  964. PLIST_ENTRY pEntry, pHead;
  965. int i;
  966. GPC_CLIENT_HANDLE ReturnedCtx;
  967. KIRQL irql;
  968. //If this function fails for any reason we should guarantee that
  969. // Pattern is freed
  970. TRACE(BLOB, ClientHandle, ClientCfInfoContext, "GpcAddCfInfo");
  971. VERIFY_OBJECT_WITH_STATUS(ClientHandle, GPC_ENUM_CLIENT_TYPE,Status);
  972. if(GPC_STATUS_SUCCESS != Status){
  973. if (Pattern){
  974. GpcFreeMem(Pattern,TcpPatternTag);
  975. }
  976. return Status;
  977. }
  978. *pGpcCfInfoHandle = NULL;
  979. //
  980. // cast the client handle to the block
  981. //
  982. pClient = (PCLIENT_BLOCK)ClientHandle;
  983. ASSERT(pClient);
  984. pCf = pClient->pCfBlock;
  985. ASSERT(pCf);
  986. //
  987. // create a new blob block and copy the user data into
  988. //
  989. pBlob = CreateNewBlobBlock(CfInfoSize, pClientCfInfoPtr,IS_USERMODE_CLIENT_EX(pClient));
  990. if (pBlob) {
  991. #if NO_USER_PENDING
  992. //
  993. // this will be only required until we implement the user level
  994. // pending report
  995. //
  996. CTEInitBlockStruc(&pBlob->WaitBlock);
  997. #endif
  998. //
  999. // Put the FileObject and the Pattern information in the Blob.
  1000. //
  1001. if (FileObject || Pattern)
  1002. {
  1003. ASSERT(FileObject);
  1004. ASSERT(Pattern);
  1005. pBlob->FileObject = FileObject;
  1006. pBlob->Pattern = Pattern;
  1007. }
  1008. //
  1009. // Add one reference count to the blob since if during
  1010. // completion, it might be deleted (if the client fails)
  1011. //
  1012. REFADD(&pBlob->RefCount, 'ADCF');
  1013. //
  1014. // set the calling client context inside the blob
  1015. //
  1016. pBlob->arClientCtx[pClient->AssignedIndex] = ClientCfInfoContext;
  1017. //
  1018. // set the owner client's context
  1019. //
  1020. pBlob->OwnerClientCtx = ClientCfInfoContext;
  1021. //
  1022. // set pointer to installer and the state
  1023. //
  1024. pBlob->pOwnerClient = pClient;
  1025. pBlob->State = GPC_STATE_ADD;
  1026. //
  1027. // init the client status array to keep track
  1028. // of how many client have succeeded so far
  1029. //
  1030. RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
  1031. pBlob->ClientStatusCountDown = 0;
  1032. //
  1033. // notify each client
  1034. //
  1035. //NDIS_LOCK(&pCf->Lock);
  1036. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1037. pHead = &pCf->ClientList;
  1038. pEntry = pHead->Flink;
  1039. while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
  1040. Status == GPC_STATUS_PENDING)) {
  1041. //
  1042. // get the notified client block
  1043. //
  1044. pNotifyClient = CONTAINING_RECORD(pEntry,
  1045. CLIENT_BLOCK,
  1046. ClientLinkage);
  1047. if (pNotifyClient != pClient
  1048. &&
  1049. !IS_USERMODE_CLIENT(pNotifyClient) ) {
  1050. //
  1051. // don't notify the caller
  1052. //
  1053. REFADD(&pNotifyClient->RefCount, 'ADCF');
  1054. //
  1055. // okay, we have bumped the ref count for this
  1056. // client. No need to keep the lock
  1057. //
  1058. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1059. //NDIS_UNLOCK(&pCf->Lock);
  1060. //
  1061. // increase number of count down clients,
  1062. // so we keep track how many clients are still
  1063. // pending. We do it *before* the call, since
  1064. // the completion might be called before the notification
  1065. // returns.
  1066. //
  1067. Status1 = ClientAddCfInfo
  1068. (pNotifyClient,
  1069. pBlob,
  1070. &ReturnedCtx
  1071. );
  1072. if (Status1 == GPC_STATUS_PENDING) {
  1073. pBlob->arClientCtx[pNotifyClient->AssignedIndex] =
  1074. ReturnedCtx;
  1075. Status = GPC_STATUS_PENDING;
  1076. if (pBlob->pNotifiedClient == NULL &&
  1077. pNotifyClient->FuncList.ClGetCfInfoName) {
  1078. TRACE(BLOB, pBlob, ReturnedCtx, "GpcAddCfInfo: (client)");
  1079. //ASSERT(ReturnedCtx);
  1080. //
  1081. // assume that is the client returned PENDING
  1082. // it has some interest in the blob...
  1083. //
  1084. pBlob->pNotifiedClient = pNotifyClient;
  1085. pBlob->NotifiedClientCtx = ReturnedCtx;
  1086. }
  1087. } else if (!NT_SUCCESS(Status1)) {
  1088. //
  1089. // some failure, notify each client that reported
  1090. // success on the add blob, to remove it
  1091. //
  1092. //
  1093. // change the state to 'remove'
  1094. //
  1095. pBlob->State = GPC_STATE_REMOVE;
  1096. //
  1097. // set the last status to the failure status
  1098. //
  1099. pBlob->LastStatus = Status = Status1;
  1100. REFDEL(&pNotifyClient->RefCount, 'ADCF');
  1101. for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
  1102. //
  1103. // only clients with none zero entries
  1104. // have succefully installed the blob
  1105. //
  1106. if (pNotifyClient = pBlob->arpClientStatus[i]) {
  1107. //
  1108. // notify each client to remove the blob
  1109. //
  1110. Status1 = ClientRemoveCfInfo
  1111. (
  1112. pNotifyClient,
  1113. pBlob,
  1114. pBlob->arClientCtx[pNotifyClient->AssignedIndex]
  1115. );
  1116. if (Status1 != GPC_STATUS_PENDING) {
  1117. //
  1118. // error or success
  1119. //
  1120. pBlob->arpClientStatus[i] = NULL;
  1121. //DereferenceClient(pNotifyClient);
  1122. }
  1123. }
  1124. } // for
  1125. //
  1126. // don't notify other clients
  1127. //
  1128. //NDIS_LOCK(&pCf->Lock);
  1129. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1130. break;
  1131. } else {
  1132. //
  1133. // status success or ignored reported
  1134. //
  1135. if (Status1 == GPC_STATUS_SUCCESS) {
  1136. pBlob->arClientCtx[pNotifyClient->AssignedIndex] =
  1137. ReturnedCtx;
  1138. pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
  1139. pNotifyClient;
  1140. if (pBlob->pNotifiedClient == NULL &&
  1141. pNotifyClient->FuncList.ClGetCfInfoName) {
  1142. TRACE(BLOB, pBlob, ReturnedCtx, "GpcAddCfInfo: (client 2)");
  1143. //ASSERT(ReturnedCtx);
  1144. //
  1145. // update the notified client
  1146. //
  1147. pBlob->pNotifiedClient = pNotifyClient;
  1148. pBlob->NotifiedClientCtx = ReturnedCtx;
  1149. }
  1150. }
  1151. }
  1152. //
  1153. // This is a tricky part,
  1154. // we need to let go of the ref count of the current client object
  1155. // but get the next one...
  1156. //
  1157. //NDIS_LOCK(&pCf->Lock);
  1158. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1159. pEntry = pEntry->Flink;
  1160. if (pEntry != pHead) {
  1161. pNotifyClient2 = CONTAINING_RECORD(pEntry,
  1162. CLIENT_BLOCK,
  1163. ClientLinkage);
  1164. REFADD(&pNotifyClient2->RefCount, 'ADCF');
  1165. }
  1166. //
  1167. // release the list lock since the next call will try to get it
  1168. //
  1169. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1170. REFDEL(&pNotifyClient->RefCount, 'ADCF');
  1171. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1172. if (pEntry != pHead) {
  1173. //
  1174. // safe to do since the list is locked
  1175. //
  1176. REFDEL(&pNotifyClient2->RefCount, 'ADCF');
  1177. }
  1178. } else { // if (pNotifyClient != pClient)
  1179. //
  1180. // advance to the next client block
  1181. //
  1182. pEntry = pEntry->Flink;
  1183. }
  1184. } // while
  1185. //
  1186. // release the CF lock still got
  1187. //
  1188. //NDIS_UNLOCK(&pCf->Lock);
  1189. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1190. } else { // if (pBlob)...
  1191. //
  1192. // error - no more memory?!?
  1193. //
  1194. // Failed to allocate the blob
  1195. // release the pattern memory.
  1196. // Must release pattern memory if this function
  1197. // fails
  1198. if (Pattern){
  1199. GpcFreeMem(Pattern,TcpPatternTag);
  1200. // Do not access Pattern after
  1201. // this
  1202. Pattern = NULL;
  1203. }
  1204. Status = GPC_STATUS_RESOURCES;
  1205. }
  1206. if (NT_SUCCESS(Status)) {
  1207. ASSERT(pBlob);
  1208. *pGpcCfInfoHandle = (GPC_CLIENT_HANDLE)pBlob;
  1209. if (Status == GPC_STATUS_SUCCESS) {
  1210. //
  1211. // add the blob to the CF and client lists
  1212. //
  1213. GpcInterlockedInsertTailList(&pClient->BlobList,
  1214. &pBlob->ClientLinkage,
  1215. &pClient->Lock
  1216. );
  1217. GpcInterlockedInsertTailList(&pCf->BlobList,
  1218. &pBlob->CfLinkage,
  1219. &pCf->Lock
  1220. );
  1221. pBlob->State = GPC_STATE_READY;
  1222. }
  1223. } else {
  1224. //
  1225. // failed - remove the blob
  1226. //
  1227. if (pBlob)
  1228. REFDEL(&pBlob->RefCount, 'BLOB');
  1229. }
  1230. if (pBlob) {
  1231. //
  1232. // release the first refcount we got up there...
  1233. //
  1234. REFDEL(&pBlob->RefCount, 'ADCF');
  1235. }
  1236. TRACE(BLOB, pBlob, Status, "GpcAddCfInfo==>");
  1237. if (Status == GPC_STATUS_SUCCESS) {
  1238. CfStatInc(pCf->AssignedIndex,CreatedBlobs);
  1239. CfStatInc(pCf->AssignedIndex,CurrentBlobs);
  1240. } else if (Status != GPC_STATUS_PENDING) {
  1241. CfStatInc(pCf->AssignedIndex,RejectedBlobs);
  1242. }
  1243. return Status;
  1244. }
  1245. /*
  1246. ************************************************************************
  1247. GpcAddPattern -
  1248. This will install a pattern into the GPC database. The pattern is hooked
  1249. to a blob. The pattern can be specific or general.
  1250. Adding a specific pattern:
  1251. It goes into the specific hash table (per protocol block)
  1252. ....
  1253. return a classification handle
  1254. Adding general pattern:
  1255. It goes into a separate Rhizome per CF and into its priority slot.
  1256. ....
  1257. Arguments
  1258. ClientHandle - client handle
  1259. ProtocolTemplate - the protocol template ID to use
  1260. Pattern - pattern
  1261. Mask - patern mask
  1262. Priority - pattern priority in case of conflict
  1263. GpcCfInfoHandle - associated blob handle
  1264. pGpcPatternHandle - OUT, returned pattern handle
  1265. pClassificationHandle - OUT, for specific pattern only
  1266. Returns
  1267. GPC_STATUS
  1268. ************************************************************************
  1269. */
  1270. GPC_STATUS
  1271. GpcAddPattern(
  1272. IN GPC_HANDLE ClientHandle,
  1273. IN ULONG ProtocolTemplate,
  1274. IN PVOID Pattern,
  1275. IN PVOID Mask,
  1276. IN ULONG Priority,
  1277. IN GPC_HANDLE GpcCfInfoHandle,
  1278. OUT PGPC_HANDLE pGpcPatternHandle,
  1279. OUT PCLASSIFICATION_HANDLE pClassificationHandle
  1280. )
  1281. {
  1282. GPC_STATUS Status;
  1283. PCLIENT_BLOCK pClient;
  1284. PBLOB_BLOCK pBlob;
  1285. PPATTERN_BLOCK pPattern, pCreatedPattern;
  1286. PGENERIC_PATTERN_DB pGenericDb;
  1287. PCLASSIFICATION_BLOCK pCB;
  1288. ULONG i;
  1289. PUCHAR p;
  1290. ULONG Flags;
  1291. PPROTOCOL_BLOCK pProtocolBlock;
  1292. ULONG CfIndex;
  1293. PGPC_IP_PATTERN pIpPattern;
  1294. REQUEST_BLOCK Request, *pRequest;
  1295. PLIST_ENTRY pLinkage;
  1296. TRACE(PATTERN, ClientHandle, Pattern, "GpcAddPattern");
  1297. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  1298. //VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
  1299. ASSERT(pGpcPatternHandle);
  1300. ASSERT(pClassificationHandle);
  1301. *pGpcPatternHandle = NULL;
  1302. *pClassificationHandle = (CLASSIFICATION_HANDLE)0;
  1303. //
  1304. // NdisInitializeEvent must run at PASSIVE (isnt that sad)
  1305. //
  1306. RtlZeroMemory(&Request, sizeof(REQUEST_BLOCK));
  1307. NdisInitializeEvent(
  1308. &Request.RequestEvent
  1309. );
  1310. //
  1311. // cast the client handle to the block
  1312. // and the CfInfo handle to a blob block
  1313. //
  1314. pClient = (PCLIENT_BLOCK)ClientHandle;
  1315. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1316. ASSERT(pClient);
  1317. CfIndex = pClient->pCfBlock->AssignedIndex;
  1318. if (Priority >= pClient->pCfBlock->MaxPriorities ||
  1319. ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX ) {
  1320. return GPC_STATUS_INVALID_PARAMETER;
  1321. }
  1322. if (pBlob != NULL) {
  1323. NDIS_LOCK(&pBlob->Lock);
  1324. if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
  1325. NDIS_UNLOCK(&pBlob->Lock);
  1326. return GPC_STATUS_INVALID_PARAMETER;
  1327. }
  1328. }
  1329. NDIS_LOCK(&glData.RequestListLock);
  1330. if (pBlob != NULL && pBlob->State != GPC_STATE_READY) {
  1331. //
  1332. // Block until it is safe to restart the work.
  1333. //
  1334. InsertTailList(&glData.gRequestList, &Request.Linkage);
  1335. NDIS_UNLOCK(&glData.RequestListLock);
  1336. //
  1337. // doing something else
  1338. //
  1339. NDIS_UNLOCK(&pBlob->Lock);
  1340. if (TRUE == NdisWaitEvent(
  1341. &Request.RequestEvent,
  1342. 0
  1343. )) {
  1344. //
  1345. // The wait was successful, continue with regularly scheduled programming.
  1346. // This lock needs to be taken when we get out.
  1347. NDIS_LOCK(&pBlob->Lock);
  1348. } else {
  1349. //
  1350. // How could this happen? I dont know.
  1351. // Definitely need to investigate.
  1352. //
  1353. TRACE(PATTERN, GPC_STATUS_FAILURE, 0, "GpcAddPattern: The conflict <-> wait <-> resume plan has FAILED!\n");
  1354. ASSERT(FALSE);
  1355. return GPC_STATUS_NOTREADY;
  1356. }
  1357. } else {
  1358. NDIS_UNLOCK(&glData.RequestListLock);
  1359. }
  1360. //
  1361. // determine if the pattern is specific or generic
  1362. //
  1363. pProtocolBlock = &glData.pProtocols[ProtocolTemplate];
  1364. if (ProtocolTemplate == GPC_PROTOCOL_TEMPLATE_IP) {
  1365. //
  1366. //
  1367. //
  1368. pIpPattern = (PGPC_IP_PATTERN)Pattern;
  1369. pIpPattern->Reserved[0] = pIpPattern->Reserved[1] = pIpPattern->Reserved[2] = 0;
  1370. pIpPattern = (PGPC_IP_PATTERN)Mask;
  1371. pIpPattern->Reserved[0] = pIpPattern->Reserved[1] = pIpPattern->Reserved[2] = 0xff;
  1372. }
  1373. for (i = 0, p=(PUCHAR)Mask; i < pProtocolBlock->PatternSize; i++, p++) {
  1374. if (*p != 0xff)
  1375. break;
  1376. }
  1377. //
  1378. // set the Flags
  1379. //
  1380. Flags = (i < pProtocolBlock->PatternSize) ? 0 : PATTERN_SPECIFIC;
  1381. if (pBlob != NULL) {
  1382. //
  1383. // change the blob state to ADD, so no one can delete it
  1384. // while the pattern is being added to its list
  1385. //
  1386. pBlob->State = GPC_STATE_ADD;
  1387. NDIS_UNLOCK(&pBlob->Lock);
  1388. }
  1389. //
  1390. // increment ref counting
  1391. //
  1392. //NdisInterlockedIncrement(&pClient->RefCount);
  1393. //
  1394. // cerate a new pattern block
  1395. //
  1396. pPattern = CreateNewPatternBlock(Flags);
  1397. pCreatedPattern = pPattern;
  1398. #if DBG
  1399. {
  1400. PGPC_IP_PATTERN pIp = (PGPC_IP_PATTERN)Pattern;
  1401. PGPC_IP_PATTERN pMask = (PGPC_IP_PATTERN)Mask;
  1402. DBGPRINT(PATTERN, ("GpcAddPattern: Client=%X %s - ",
  1403. pClient,
  1404. TEST_BIT_ON(Flags, PATTERN_SPECIFIC)?"Specific":"Generic"));
  1405. DBGPRINT(PATTERN, ("IP: ifc={%d,%d} src=%08X:%04x, dst=%08X:%04x, prot=%d rsv=%x,%x,%x\n",
  1406. pIp->InterfaceId.InterfaceId,
  1407. pIp->InterfaceId.LinkId,
  1408. pIp->SrcAddr,
  1409. pIp->gpcSrcPort,
  1410. pIp->DstAddr,
  1411. pIp->gpcDstPort,
  1412. pIp->ProtocolId,
  1413. pIp->Reserved[0],
  1414. pIp->Reserved[1],
  1415. pIp->Reserved[2]
  1416. ));
  1417. DBGPRINT(PATTERN, ("Mask: ifc={%x,%x} src=%08X:%04x, dst=%08X:%04x, prot=%x rsv=%x,%x,%x\n",
  1418. pMask->InterfaceId.InterfaceId,
  1419. pMask->InterfaceId.LinkId,
  1420. pMask->SrcAddr,
  1421. pMask->gpcSrcPort,
  1422. pMask->DstAddr,
  1423. pMask->gpcDstPort,
  1424. pMask->ProtocolId,
  1425. pMask->Reserved[0],
  1426. pMask->Reserved[1],
  1427. pMask->Reserved[2]
  1428. ));
  1429. }
  1430. #endif
  1431. if (pPattern) {
  1432. //
  1433. // add one reference count to the pattern, so when we add it
  1434. // to the db, we're sure it stays there
  1435. //
  1436. //pPattern->RefCount++;
  1437. pPattern->Priority = Priority;
  1438. pPattern->ProtocolTemplate = ProtocolTemplate;
  1439. if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
  1440. //
  1441. // add a specific pattern
  1442. //
  1443. Status = AddSpecificPattern(
  1444. pClient,
  1445. Pattern,
  1446. Mask,
  1447. pBlob,
  1448. pProtocolBlock,
  1449. &pPattern, // output pattern pointer
  1450. pClassificationHandle
  1451. );
  1452. } else {
  1453. //
  1454. // add a generic pattern
  1455. //
  1456. Status = AddGenericPattern(
  1457. pClient,
  1458. Pattern,
  1459. Mask,
  1460. Priority,
  1461. pBlob,
  1462. pProtocolBlock,
  1463. &pPattern // output pattern pointer
  1464. );
  1465. }
  1466. // [OferBar]
  1467. // release the extra ref count that was added
  1468. // in the case of a specific pattern, this might be a totally different
  1469. // one, but it should still have the extra ref-count
  1470. // if there was an error, this will release the pattern
  1471. // REFDEL(&pPattern->RefCount, 'FILT');
  1472. // [ShreeM]
  1473. // A reference FILT is added to a filter on creation. This will be substituted by 'ADSP' or
  1474. // 'ADGP' whether it was a Generic Pattern or a Specific Pattern. However, it is likely that
  1475. // in the AddSpecificPattern function, the pPattern got changed to something else because a
  1476. // filter already existed. We want to ensure that the tag subsitution happens only in the
  1477. // case where pPattern was not replaced with the existing pattern in AddSpecificPattern.
  1478. //
  1479. REFDEL(&pCreatedPattern->RefCount, 'FILT');
  1480. //
  1481. // check if failure, and if so - release the pattern block
  1482. //
  1483. if (NT_SUCCESS(Status)) {
  1484. //
  1485. // fill the output handle
  1486. //
  1487. *pGpcPatternHandle = (GPC_HANDLE)pPattern;
  1488. }
  1489. } else {
  1490. Status = GPC_STATUS_RESOURCES;
  1491. }
  1492. if (pBlob != NULL) {
  1493. //
  1494. // change the state back to ready, so others can work on this blob
  1495. //
  1496. pBlob->State = GPC_STATE_READY;
  1497. }
  1498. //
  1499. // release the extra ref count
  1500. //
  1501. //NdisInterlockedDecrement(&pClient->RefCount);
  1502. TRACE(PATTERN, pPattern, Status, "GpcAddPattern==>");
  1503. if (NT_SUCCESS(Status)) {
  1504. if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
  1505. ProtocolStatInc(ProtocolTemplate,
  1506. CreatedSp);
  1507. ProtocolStatInc(ProtocolTemplate,
  1508. CurrentSp);
  1509. NdisInterlockedIncrement(&pProtocolBlock->SpecificPatternCount);
  1510. ASSERT(pProtocolBlock->SpecificPatternCount > 0);
  1511. } else {
  1512. ProtocolStatInc(ProtocolTemplate,
  1513. CreatedGp);
  1514. ProtocolStatInc(ProtocolTemplate,
  1515. CurrentGp);
  1516. NdisInterlockedIncrement(&pProtocolBlock->GenericPatternCount);
  1517. ASSERT(pProtocolBlock->GenericPatternCount > 0);
  1518. }
  1519. } else {
  1520. if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
  1521. ProtocolStatInc(ProtocolTemplate,
  1522. RejectedSp);
  1523. } else {
  1524. ProtocolStatInc(ProtocolTemplate,
  1525. RejectedGp);
  1526. }
  1527. }
  1528. //
  1529. // Check if some requests got queued while we were in there.
  1530. //
  1531. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1532. NDIS_LOCK(&glData.RequestListLock);
  1533. if (!IsListEmpty(&glData.gRequestList)) {
  1534. pLinkage = RemoveHeadList(&glData.gRequestList);
  1535. NDIS_UNLOCK(&glData.RequestListLock);
  1536. pRequest = CONTAINING_RECORD(pLinkage, REQUEST_BLOCK, Linkage);
  1537. NdisSetEvent(&pRequest->RequestEvent);
  1538. } else {
  1539. NDIS_UNLOCK(&glData.RequestListLock);
  1540. }
  1541. return Status;
  1542. }
  1543. /*
  1544. ************************************************************************
  1545. GpcAddCfInfoNotifyComplete -
  1546. A completion routine that the client will call after the GPC called into
  1547. the client's ClAddCfInfoNotify handler, but returned PENDING.
  1548. After all the clients have completed, a callback to the calling client's
  1549. ClAddCfInfoComplete is done to complete the GpcAddCfInfo call.
  1550. Arguments
  1551. ClientHandle - client handle
  1552. GpcCfInfoHandle - the blob handle
  1553. Status - completion status
  1554. Returns
  1555. void
  1556. ************************************************************************
  1557. */
  1558. VOID
  1559. GpcAddCfInfoNotifyComplete(
  1560. IN GPC_HANDLE ClientHandle,
  1561. IN GPC_HANDLE GpcCfInfoHandle,
  1562. IN GPC_STATUS Status,
  1563. IN GPC_CLIENT_HANDLE ClientCfInfoContext
  1564. )
  1565. {
  1566. PCLIENT_BLOCK pClient, pNotifyClient, pFirstClient;
  1567. PBLOB_BLOCK pBlob;
  1568. //GPC_CLIENT_HANDLE ClientCtx;
  1569. //ULONG cd;
  1570. int i;
  1571. GPC_STATUS LastStatus, Status1;
  1572. TRACE(BLOB, GpcCfInfoHandle, Status, "GpcAddCfInfoNotifyComplete");
  1573. //VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  1574. //VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
  1575. pClient = (PCLIENT_BLOCK)ClientHandle;
  1576. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1577. ASSERT(pBlob);
  1578. ASSERT(pClient);
  1579. ASSERT(Status != GPC_STATUS_PENDING);
  1580. ASSERT(pBlob->ClientStatusCountDown > 0);
  1581. if (NT_SUCCESS(Status)) {
  1582. //
  1583. // success reported, save the reporting client handle
  1584. // so we can notify him to remove the blob in case of an error
  1585. // down the road by another client for the same blob
  1586. //
  1587. ASSERT(pBlob->arpClientStatus[pClient->AssignedIndex] == NULL);
  1588. pBlob->arpClientStatus[pClient->AssignedIndex] = pClient;
  1589. } else {
  1590. //
  1591. // error reported, update the last status code.
  1592. //
  1593. pBlob->LastStatus = Status;
  1594. }
  1595. if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
  1596. //
  1597. // all clients have reported
  1598. //
  1599. //
  1600. // save the client's blob data, cuz it might get deleted
  1601. //
  1602. //ClientCtx = pBlob->arClientCtx[pClient->AssignedIndex];
  1603. LastStatus = pBlob->LastStatus;
  1604. pFirstClient = pBlob->pOwnerClient;
  1605. if (NT_ERROR(LastStatus)) {
  1606. //
  1607. // error has been previously reported by a client
  1608. // tell each client that reported success to remove
  1609. // the blob (sorry...)
  1610. //
  1611. #if 0
  1612. NDIS_LOCK(&pBlob->pOwnerClient->pCfBlock->Lock);
  1613. GpcRemoveEntryList(&pBlob->CfLinkage);
  1614. NDIS_DPR_LOCK(&pBlob->pOwnerClient->Lock);
  1615. GpcRemoveEntryList(&pBlob->ClientLinkage);
  1616. NDIS_DPR_UNLOCK(&pBlob->pOwnerClient->Lock);
  1617. NDIS_UNLOCK(&pBlob->pOwnerClient->pCfBlock->Lock);
  1618. #endif
  1619. CTEInitBlockStruc(&pBlob->WaitBlockAddFailed);
  1620. Status1 = GPC_STATUS_SUCCESS;
  1621. for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
  1622. //
  1623. // only clients with none zero entries
  1624. // have succefully installed the blob
  1625. //
  1626. if (pNotifyClient = pBlob->arpClientStatus[i]) {
  1627. //
  1628. // notify each client to remove the blob
  1629. //
  1630. if (ClientRemoveCfInfo
  1631. (
  1632. pNotifyClient,
  1633. pBlob,
  1634. pBlob->arClientCtx[pNotifyClient->AssignedIndex]
  1635. ) == GPC_STATUS_PENDING)
  1636. {
  1637. Status1 = GPC_STATUS_PENDING;
  1638. } else {
  1639. //DereferenceClient(pNotifyClient);
  1640. }
  1641. }
  1642. } // for
  1643. if (Status1 == GPC_STATUS_PENDING) {
  1644. //
  1645. // Block on completion of all removals...
  1646. //
  1647. Status1 = CTEBlock(&pBlob->WaitBlockAddFailed);
  1648. }
  1649. } else { // if (NT_ERROR(LastStats))...
  1650. //
  1651. // store the returned client context, since the call can be completed
  1652. // before the notification handler returns.
  1653. //
  1654. pBlob->arClientCtx[pClient->AssignedIndex] = ClientCfInfoContext;
  1655. //
  1656. // add the blob to the CF and client lists
  1657. //
  1658. GpcInterlockedInsertTailList(&pBlob->pOwnerClient->BlobList,
  1659. &pBlob->ClientLinkage,
  1660. &pBlob->pOwnerClient->Lock
  1661. );
  1662. GpcInterlockedInsertTailList(&pBlob->pOwnerClient->pCfBlock->BlobList,
  1663. &pBlob->CfLinkage,
  1664. &pBlob->pOwnerClient->pCfBlock->Lock
  1665. );
  1666. }
  1667. //
  1668. // complete the request to the client
  1669. //
  1670. ClientAddCfInfoComplete(
  1671. pFirstClient, // first guy who made the call
  1672. pBlob, // completing blob
  1673. LastStatus // status
  1674. );
  1675. }
  1676. //
  1677. // this will be done after the last client completes
  1678. //
  1679. //DereferenceClient(pClient);
  1680. }
  1681. /*
  1682. ************************************************************************
  1683. GpcModifyCfInfo -
  1684. The client calls this to modify a blob. Each other client on the CF will
  1685. get notified. This routine returns PENDING and starts a working thread
  1686. to do the main job.
  1687. Arguments
  1688. ClientHandle - client handle
  1689. GpcCfInfoHandle - the handle of the blob to modify
  1690. CfInfoSize - new blob size
  1691. pClientCfInfo - new blob data pointer
  1692. Returns
  1693. GPC_STATUS, PENDING is valid
  1694. ************************************************************************
  1695. */
  1696. GPC_STATUS
  1697. GpcModifyCfInfo(
  1698. IN GPC_HANDLE ClientHandle,
  1699. IN GPC_HANDLE GpcCfInfoHandle,
  1700. IN ULONG CfInfoSize,
  1701. IN PVOID pClientCfInfoPtr
  1702. )
  1703. {
  1704. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  1705. GPC_STATUS Status1;
  1706. PCLIENT_BLOCK pClient;
  1707. PCLIENT_BLOCK pNotifyClient;
  1708. PCLIENT_BLOCK pNotifyClient2;
  1709. PBLOB_BLOCK pBlob;
  1710. PCF_BLOCK pCf;
  1711. PLIST_ENTRY pEntry, pHead;
  1712. int i;
  1713. KIRQL irql;
  1714. TRACE(BLOB, ClientHandle, GpcCfInfoHandle, "GpcModifyCfInfo");
  1715. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  1716. //VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
  1717. ASSERT(pClientCfInfoPtr);
  1718. //
  1719. // cast the client handle to the block
  1720. //
  1721. pClient = (PCLIENT_BLOCK)ClientHandle;
  1722. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1723. pCf = pClient->pCfBlock;
  1724. ASSERT(pClient);
  1725. ASSERT(pBlob);
  1726. NDIS_LOCK(&pBlob->Lock);
  1727. if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
  1728. NDIS_UNLOCK(&pBlob->Lock);
  1729. return GPC_STATUS_INVALID_PARAMETER;
  1730. }
  1731. //
  1732. // check the blob is in READY state and change it to MODIFY state
  1733. //
  1734. if (pBlob->State != GPC_STATE_READY) {
  1735. NDIS_UNLOCK(&pBlob->Lock);
  1736. return GPC_STATUS_NOTREADY;
  1737. }
  1738. //
  1739. // allocate private memory in the GPC to copy the client's data
  1740. // into
  1741. //
  1742. GpcAllocMem(&pBlob->pNewClientData, CfInfoSize, CfInfoDataTag);
  1743. if (pBlob->pNewClientData == NULL) {
  1744. NDIS_UNLOCK(&pBlob->Lock);
  1745. return GPC_STATUS_RESOURCES;
  1746. }
  1747. pBlob->NewClientDataSize = CfInfoSize;
  1748. pBlob->State = GPC_STATE_MODIFY;
  1749. //
  1750. // we set the calling client here so we can notify it when the
  1751. // the modification is completed
  1752. //
  1753. pBlob->pCallingClient = pClient;
  1754. NDIS_UNLOCK(&pBlob->Lock);
  1755. #if NO_USER_PENDING
  1756. //
  1757. // this will be only required until we implement the user level
  1758. // pending report
  1759. //
  1760. CTEInitBlockStruc(&pBlob->WaitBlock);
  1761. #endif
  1762. //
  1763. // copy the memory
  1764. //
  1765. RtlMoveMemory(pBlob->pNewClientData, pClientCfInfoPtr, CfInfoSize);
  1766. //
  1767. // init the client status array to keep track
  1768. // of how many client have succeeded so far
  1769. //
  1770. //RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
  1771. pBlob->ClientStatusCountDown = 0;
  1772. pBlob->LastStatus = GPC_STATUS_SUCCESS;
  1773. //
  1774. // notify each client
  1775. //
  1776. //NDIS_LOCK(&pCf->Lock);
  1777. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1778. pHead = &pCf->ClientList;
  1779. pEntry = pHead->Flink;
  1780. while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
  1781. Status == GPC_STATUS_PENDING)) {
  1782. //
  1783. // get the notified client block
  1784. //
  1785. pNotifyClient = CONTAINING_RECORD(pEntry, CLIENT_BLOCK, ClientLinkage);
  1786. if (pNotifyClient != pClient
  1787. &&
  1788. pBlob->arpClientStatus[pNotifyClient->AssignedIndex]
  1789. &&
  1790. !IS_USERMODE_CLIENT(pNotifyClient) ) {
  1791. //
  1792. // don't notify the caller
  1793. //
  1794. REFADD(&pNotifyClient->RefCount, 'CFMF');
  1795. //
  1796. // okay, we have bumped the ref count for this
  1797. // client. No need to keep the lock
  1798. //
  1799. //NDIS_UNLOCK(&pCf->Lock);
  1800. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1801. //
  1802. // increase number of count down clients,
  1803. // so we keep track how many clients are still
  1804. // pending. We do it *before* the call, since
  1805. // the completion might be called before the notification
  1806. // returns.
  1807. //
  1808. Status1 = ClientModifyCfInfo
  1809. (pNotifyClient,
  1810. pBlob,
  1811. CfInfoSize,
  1812. pBlob->pNewClientData
  1813. );
  1814. TRACE(BLOB, pBlob, Status1, "GpcModifyCfInfo: (client)");
  1815. //
  1816. // grab the lock again since we're walking the list
  1817. //
  1818. //NDIS_LOCK(&pCf->Lock);
  1819. //
  1820. // now we check the Status1 code
  1821. // the rules are:
  1822. // we stop on failure
  1823. // ignore GPC_STATUS_IGNORE
  1824. // and save PENDING status
  1825. //
  1826. if (Status1 == GPC_STATUS_PENDING
  1827. &&
  1828. !NT_SUCCESS(pBlob->LastStatus)) {
  1829. //
  1830. // we've got back pending, but the client
  1831. // actually completed the request
  1832. // behind our back
  1833. //
  1834. Status = GPC_STATUS_PENDING;
  1835. REFDEL(&pNotifyClient->RefCount, 'CFMF');
  1836. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1837. break;
  1838. } else if (!NT_SUCCESS(Status1)) {
  1839. //
  1840. // don't notify other clients
  1841. //
  1842. pBlob->LastStatus = Status = Status1;
  1843. REFDEL(&pNotifyClient->RefCount, 'CFMF');
  1844. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1845. break;
  1846. } else if (Status1 == GPC_STATUS_SUCCESS
  1847. ||
  1848. Status1 == GPC_STATUS_PENDING) {
  1849. pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
  1850. pNotifyClient;
  1851. if (Status1 == GPC_STATUS_PENDING) {
  1852. Status = GPC_STATUS_PENDING;
  1853. }
  1854. }
  1855. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1856. pEntry = pEntry->Flink;
  1857. if (pEntry != pHead) {
  1858. pNotifyClient2 = CONTAINING_RECORD(pEntry,
  1859. CLIENT_BLOCK,
  1860. ClientLinkage);
  1861. REFADD(&pNotifyClient2->RefCount, 'CFMF');
  1862. }
  1863. //
  1864. // release the list lock since the next call will try to get it
  1865. //
  1866. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1867. REFDEL(&pNotifyClient->RefCount, 'CFMF');
  1868. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  1869. if (pEntry != pHead) {
  1870. //
  1871. // safe to do since the list is locked
  1872. //
  1873. REFDEL(&pNotifyClient2->RefCount, 'CFMF');
  1874. }
  1875. } else { // if (pNotifyClient != pClient)
  1876. //
  1877. // grab the next client block,
  1878. //
  1879. pEntry = pEntry->Flink;
  1880. }
  1881. } // while
  1882. //
  1883. // release the CF lock still got
  1884. //
  1885. //NDIS_UNLOCK(&pCf->Lock);
  1886. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  1887. //
  1888. // Status code should be either:
  1889. //
  1890. // GPC_STATUS_SUCCESS - all clients have been notified and returned SUCCESS
  1891. // GPC_STATUS_PENDING - all clients have been notified, at least one
  1892. // return PENDING
  1893. // Error code - at least one client failed
  1894. //
  1895. if (Status != GPC_STATUS_PENDING) {
  1896. //
  1897. // Note: the status here can be either FAILED or SUCCESS
  1898. //
  1899. // no client has been pending, so we complete the modification
  1900. // back to the clients (except the caling client)
  1901. //
  1902. ModifyCompleteClients(pClient, pBlob);
  1903. //
  1904. // restore READY state
  1905. //
  1906. pBlob->State = GPC_STATE_READY;
  1907. }
  1908. TRACE(BLOB, pBlob, Status, "GpcModifyCfInfo==>");
  1909. if (NT_SUCCESS(Status)) {
  1910. CfStatInc(pCf->AssignedIndex,ModifiedBlobs);
  1911. }
  1912. return Status;
  1913. }
  1914. /*
  1915. ************************************************************************
  1916. GpcModifyCfInfoNotifyComplete -
  1917. Called by clients to complete a previous call to ClModifyCfInfoNotify
  1918. made by the GPC.
  1919. Arguments
  1920. ClientHandle - client handle
  1921. GpcCfInfoHandle - the blob handle
  1922. Status - completion status
  1923. Returns
  1924. GPC_STATUS
  1925. ************************************************************************
  1926. */
  1927. VOID
  1928. GpcModifyCfInfoNotifyComplete(
  1929. IN GPC_HANDLE ClientHandle,
  1930. IN GPC_HANDLE GpcCfInfoHandle,
  1931. IN GPC_STATUS Status
  1932. )
  1933. {
  1934. PCLIENT_BLOCK pClient, pNotifyClient;
  1935. PBLOB_BLOCK pBlob;
  1936. TRACE(BLOB, GpcCfInfoHandle, Status, "GpcModifyCfInfoNotifyComplete");
  1937. //VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  1938. //VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
  1939. pClient = (PCLIENT_BLOCK)ClientHandle;
  1940. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  1941. ASSERT(pBlob);
  1942. ASSERT(pClient);
  1943. ASSERT(Status != GPC_STATUS_PENDING);
  1944. ASSERT(pBlob->ClientStatusCountDown > 0);
  1945. if (NT_SUCCESS(Status)) {
  1946. //
  1947. // success reported, save the reporting client handle
  1948. // so we can notify him to remove the blob in case of an error
  1949. // down the road by another client for the same blob
  1950. //
  1951. ASSERT(pBlob->arpClientStatus[pClient->AssignedIndex] == pClient);
  1952. //pBlob->arpClientStatus[pClient->AssignedIndex] = pClient;
  1953. } else {
  1954. //
  1955. // error reported, update the last status code.
  1956. //
  1957. pBlob->LastStatus = Status;
  1958. }
  1959. if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
  1960. //
  1961. // all clients have reported
  1962. //
  1963. ModifyCompleteClients(pClient, pBlob);
  1964. #if NO_USER_PENDING
  1965. //
  1966. // the user is blocking on this call
  1967. //
  1968. CTESignal(&pBlob->WaitBlock, Status);
  1969. #else
  1970. //
  1971. // now, complete the call back to the calling client
  1972. //
  1973. ClientModifyCfInfoComplete(
  1974. pBlob->pCallingClient,
  1975. pBlob,
  1976. pBlob->LastStatus
  1977. );
  1978. pBlob->State = GPC_STATE_READY;
  1979. #endif
  1980. }
  1981. TRACE(BLOB, pClient, Status, "GpcModifyCfInfoNotifyComplete==>");
  1982. }
  1983. /*
  1984. ************************************************************************
  1985. privateGpcRemoveCfInfo -
  1986. Remove a blob from GPC.
  1987. Arguments
  1988. ClientHandle - client handle
  1989. GpcCfInfoHandle - blob handle
  1990. Returns
  1991. GPC_STATUS
  1992. ************************************************************************
  1993. */
  1994. GPC_STATUS
  1995. privateGpcRemoveCfInfo(
  1996. IN GPC_HANDLE ClientHandle,
  1997. IN GPC_HANDLE GpcCfInfoHandle,
  1998. IN ULONG Flags
  1999. )
  2000. {
  2001. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  2002. GPC_STATUS Status1;
  2003. PCLIENT_BLOCK pClient;
  2004. PCLIENT_BLOCK pNotifyClient;
  2005. PCLIENT_BLOCK pNotifyClient2;
  2006. PBLOB_BLOCK pBlob;
  2007. PCF_BLOCK pCf;
  2008. PPATTERN_BLOCK pPattern;
  2009. PLIST_ENTRY pHead, pEntry;
  2010. KIRQL irql;
  2011. PPROTOCOL_BLOCK pProtocol;
  2012. ULONG cClientRef;
  2013. TRACE(BLOB, ClientHandle, GpcCfInfoHandle, "privateGpcRemoveCfInfo");
  2014. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  2015. pClient = (PCLIENT_BLOCK)ClientHandle;
  2016. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  2017. pCf = pClient->pCfBlock;
  2018. NDIS_LOCK(&pBlob->Lock);
  2019. if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
  2020. NDIS_UNLOCK(&pBlob->Lock);
  2021. return GPC_STATUS_INVALID_PARAMETER;
  2022. }
  2023. if (pBlob->State != GPC_STATE_READY) {
  2024. if ((pBlob->pCallingClient2) || (IS_USERMODE_CLIENT_EX(pClient))){
  2025. //
  2026. // Can't handle more than 2 removals for the
  2027. // same flow.
  2028. // another client has already requested the removal of
  2029. // this flow, we should fail here
  2030. //
  2031. // Also dont pend requests from user mode clients using the new IOCTL
  2032. // interface
  2033. NDIS_UNLOCK(&pBlob->Lock);
  2034. TRACE(BLOB, GPC_STATUS_NOTREADY, 0, "privateGpcRemoveCfInfo==>");
  2035. return GPC_STATUS_NOTREADY;
  2036. }
  2037. //
  2038. // the flow is being removed when another client
  2039. // requested its removal. we save this client handle
  2040. // and we'll coplete it later
  2041. //
  2042. pBlob->pCallingClient2 = pClient;
  2043. NDIS_UNLOCK(&pBlob->Lock);
  2044. TRACE(BLOB, GPC_STATUS_PENDING, 0, "privateGpcRemoveCfInfo==>");
  2045. return GPC_STATUS_PENDING;
  2046. }
  2047. //
  2048. // remove the supported patterns on the cfinfo
  2049. // there are two cases:
  2050. //
  2051. // 1. from a user - traffic.dll requires that ALL the filters
  2052. // would have been deleted, therefore this case is a nop.
  2053. //
  2054. // 2. from a kernel client - in this case we MUST remove the
  2055. // patterns before proceesing to delete the cfinfo,
  2056. // since we can't rely on traffic.dll to do it
  2057. //
  2058. //
  2059. // grab a refcount on this blob so it doesn't go away due
  2060. // to some funky client that decides to complete before
  2061. // it return any status code (and most of them do!)
  2062. // this should be released before we exit the routine,
  2063. // so that the blob may actually go away on the last deref
  2064. //
  2065. REFADD(&pBlob->RefCount, 'RMCF');
  2066. //
  2067. // set the removing client
  2068. //
  2069. pBlob->pCallingClient = pClient;
  2070. //
  2071. // don't allow the user mode owner client to remove this flow
  2072. // if there are any patterns on it....
  2073. // ...unless the REMOVE_CB_BLOB bit ahs been set,
  2074. // for example: when the calling process dies
  2075. //
  2076. if (!IsListEmpty(&pBlob->PatternList) &&
  2077. TEST_BIT_ON(pClient->Flags, GPC_FLAGS_USERMODE_CLIENT) &&
  2078. (pClient == pBlob->pOwnerClient) &&
  2079. TEST_BIT_OFF(pBlob->Flags, PATTERN_REMOVE_CB_BLOB)
  2080. )
  2081. {
  2082. NDIS_UNLOCK(&pBlob->Lock);
  2083. return GPC_STATUS_NOT_EMPTY;
  2084. } else {
  2085. //
  2086. // Since we have decided to remove the patterns, we should
  2087. // mark this as invalid
  2088. //
  2089. pBlob->ObjectType = GPC_ENUM_INVALID;
  2090. }
  2091. while (!IsListEmpty(&pBlob->PatternList)) {
  2092. pPattern = CONTAINING_RECORD(pBlob->PatternList.Flink,
  2093. PATTERN_BLOCK,
  2094. BlobLinkage[pCf->AssignedIndex]);
  2095. NDIS_DPR_LOCK(&pPattern->Lock);
  2096. REFADD(&pPattern->RefCount, 'RMCF');
  2097. pPattern->State = GPC_STATE_FORCE_REMOVE;
  2098. //
  2099. // If it is an AUTO PATTERN, remove it from the list and
  2100. // unset the flag.
  2101. //
  2102. if (TEST_BIT_ON( pPattern->Flags, PATTERN_AUTO)) {
  2103. pProtocol = &glData.pProtocols[pPattern->ProtocolTemplate];
  2104. pPattern->Flags |= ~PATTERN_AUTO;
  2105. NDIS_DPR_LOCK(&pProtocol->PatternTimerLock[pPattern->WheelIndex]);
  2106. GpcRemoveEntryList(&pPattern->TimerLinkage);
  2107. NDIS_DPR_UNLOCK(&pProtocol->PatternTimerLock[pPattern->WheelIndex]);
  2108. InitializeListHead(&pPattern->TimerLinkage);
  2109. NDIS_DPR_UNLOCK(&pPattern->Lock);
  2110. NDIS_UNLOCK(&pBlob->Lock);
  2111. privateGpcRemovePattern(ClientHandle, (GPC_HANDLE)pPattern, TRUE, FALSE);
  2112. InterlockedDecrement(&pProtocol->AutoSpecificPatternCount);
  2113. } else {
  2114. NDIS_DPR_UNLOCK(&pPattern->Lock);
  2115. NDIS_UNLOCK(&pBlob->Lock);
  2116. }
  2117. privateGpcRemovePattern(ClientHandle, (GPC_HANDLE)pPattern, TRUE , FALSE);
  2118. REFDEL(&pPattern->RefCount, 'RMCF');
  2119. NDIS_LOCK(&pBlob->Lock);
  2120. }
  2121. //
  2122. // set the state
  2123. //
  2124. pBlob->State = GPC_STATE_REMOVE;
  2125. NDIS_UNLOCK(&pBlob->Lock);
  2126. #if NO_USER_PENDING
  2127. //
  2128. // this will be only required until we implement the user level
  2129. // pending report
  2130. //
  2131. CTEInitBlockStruc(&pBlob->WaitBlock);
  2132. #endif
  2133. SuspendHandle(pBlob->ClHandle);
  2134. //
  2135. // init the client status array to keep track
  2136. // of how many client have succeeded so far
  2137. //
  2138. //RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
  2139. pBlob->ClientStatusCountDown = 0;
  2140. pBlob->LastStatus = GPC_STATUS_SUCCESS;
  2141. //
  2142. // notify each client
  2143. //
  2144. NDIS_LOCK(&pCf->Lock);
  2145. GpcRemoveEntryList(&pBlob->CfLinkage);
  2146. NDIS_UNLOCK(&pCf->Lock);
  2147. //NDIS_LOCK(&pClient->Lock);
  2148. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  2149. NDIS_LOCK(&pClient->Lock);
  2150. GpcRemoveEntryList(&pBlob->ClientLinkage);
  2151. NDIS_UNLOCK(&pClient->Lock);
  2152. //NDIS_UNLOCK(&pClient->Lock);
  2153. //
  2154. // the blob is not on the CF or on the client list
  2155. // okay to change the object type so further handle lookup will fail
  2156. //
  2157. pHead = &pCf->ClientList;
  2158. pEntry = pHead->Flink;
  2159. while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
  2160. Status == GPC_STATUS_PENDING)) {
  2161. //
  2162. // get the notified client block
  2163. //
  2164. pNotifyClient = CONTAINING_RECORD(pEntry, CLIENT_BLOCK, ClientLinkage);
  2165. if (pNotifyClient != pClient
  2166. &&
  2167. pBlob->arpClientStatus[pNotifyClient->AssignedIndex] ) {
  2168. //
  2169. // don't notify the caller
  2170. //
  2171. REFADD(&pNotifyClient->RefCount, 'PRCF');
  2172. //NDIS_UNLOCK(&pCf->Lock);
  2173. RSC_READ_UNLOCK(&pCf->ClientSync, &irql);
  2174. Status1 = ClientRemoveCfInfo
  2175. (pNotifyClient,
  2176. pBlob,
  2177. pBlob->arClientCtx[pNotifyClient->AssignedIndex]
  2178. );
  2179. TRACE(BLOB, pBlob, Status, "privateGpcRemoveCfInfo: (client)");
  2180. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  2181. if (Status1 == GPC_STATUS_PENDING) {
  2182. Status = GPC_STATUS_PENDING;
  2183. } else {
  2184. if (NT_ERROR(Status1)) {
  2185. Status = pBlob->LastStatus = Status1;
  2186. } else {
  2187. //
  2188. // status success
  2189. //
  2190. pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
  2191. pNotifyClient;
  2192. NDIS_DPR_LOCK(&pBlob->Lock);
  2193. if (pNotifyClient == pBlob->pNotifiedClient) {
  2194. pBlob->pNotifiedClient = NULL;
  2195. pBlob->NotifiedClientCtx = NULL;
  2196. }
  2197. NDIS_DPR_UNLOCK(&pBlob->Lock);
  2198. }
  2199. //
  2200. // not pending - no need to hold the ref count to this client
  2201. //
  2202. //DereferenceClient(pNotifyClient);
  2203. }
  2204. //
  2205. // advance to the next client block, and release the ref count
  2206. // for this client
  2207. //
  2208. //NDIS_LOCK(&pCf->Lock);
  2209. pEntry = pEntry->Flink;
  2210. if (pEntry != pHead) {
  2211. pNotifyClient2 = CONTAINING_RECORD(pEntry,
  2212. CLIENT_BLOCK,
  2213. ClientLinkage);
  2214. REFADD(&pNotifyClient2->RefCount, 'PRCF');
  2215. }
  2216. //
  2217. // release the list lock since the next call will try to get it
  2218. //
  2219. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  2220. REFDEL(&pNotifyClient->RefCount, 'PRCF');
  2221. RSC_READ_LOCK(&pCf->ClientSync, &irql);
  2222. if (pEntry != pHead) {
  2223. //
  2224. // safe to do since the list is locked
  2225. //
  2226. REFDEL(&pNotifyClient2->RefCount, 'PRCF');
  2227. }
  2228. } else { // if (pNotifyClient != pClient)
  2229. pEntry = pEntry->Flink;
  2230. }
  2231. } // while
  2232. //NDIS_UNLOCK(&pCf->Lock);
  2233. RSC_READ_UNLOCK(&pCf->ClientSync, irql);
  2234. if (Status != GPC_STATUS_PENDING) {
  2235. NDIS_LOCK(&pBlob->Lock);
  2236. //
  2237. // notify any pending client about the status
  2238. //
  2239. if (pClient = pBlob->pCallingClient2) {
  2240. pClient = pBlob->pCallingClient2;
  2241. pBlob->pCallingClient2 = NULL;
  2242. NDIS_UNLOCK(&pBlob->Lock);
  2243. //
  2244. // complete the request to this client
  2245. //
  2246. ClientRemoveCfInfoComplete
  2247. (
  2248. pClient, // the guy who made the call
  2249. pBlob, // completing blob
  2250. Status // status
  2251. );
  2252. //pBlob->pCallingClient2 = NULL;
  2253. } else {
  2254. NDIS_UNLOCK(&pBlob->Lock);
  2255. }
  2256. if (Status != GPC_STATUS_SUCCESS) {
  2257. //
  2258. // failed to remove the blob
  2259. //
  2260. pBlob->State = GPC_STATE_READY;
  2261. pBlob->ObjectType = GPC_ENUM_CFINFO_TYPE;
  2262. //
  2263. // resume the suspended handle
  2264. //
  2265. ResumeHandle(pBlob->ClHandle);
  2266. }
  2267. }
  2268. if (Status == GPC_STATUS_SUCCESS) {
  2269. //
  2270. // release the mapping handle
  2271. //
  2272. FreeHandle(pBlob->ClHandle);
  2273. //
  2274. // all done, we can remove the blob from memory
  2275. //
  2276. REFDEL(&pBlob->RefCount, 'BLOB');
  2277. CfStatInc(pCf->AssignedIndex,DeletedBlobs);
  2278. CfStatDec(pCf->AssignedIndex,CurrentBlobs);
  2279. }
  2280. //
  2281. // release the extra refcount we got in the begining
  2282. // this is to avoid the problem of the blob going away,
  2283. // since some clients may complete the remove before we get
  2284. // here, and this will cause the blob structure to be released
  2285. // it's not a pretty sight....
  2286. //
  2287. REFDEL(&pBlob->RefCount, 'RMCF');
  2288. TRACE(BLOB, Status, 0, "privateGpcRemoveCfInfo==>");
  2289. return Status;
  2290. }
  2291. /*
  2292. ************************************************************************
  2293. GpcRemoveCfInfo -
  2294. This must have been called from kernel. We simply pass the call
  2295. to the private routine with Flags=0.
  2296. Arguments
  2297. ClientHandle - client handle
  2298. GpcCfInfoHandle - blob handle
  2299. Returns
  2300. GPC_STATUS
  2301. ************************************************************************
  2302. */
  2303. GPC_STATUS
  2304. GpcRemoveCfInfo(
  2305. IN GPC_HANDLE ClientHandle,
  2306. IN GPC_HANDLE GpcCfInfoHandle
  2307. )
  2308. {
  2309. return privateGpcRemoveCfInfo(
  2310. ClientHandle,
  2311. GpcCfInfoHandle,
  2312. 0
  2313. );
  2314. }
  2315. /*
  2316. ************************************************************************
  2317. GpcRemoveCfInfoNotifyComplete -
  2318. Called by clients who are completing a ClRemoveCfInfoNotify that was PENDING.
  2319. This may have been called for two reasons:
  2320. 1. A client issued a GpcRemoveCfInfo request.
  2321. 2. A client issued a GpcAddCfInfo request, but one of the other clients
  2322. failed, so we are removing the successfully installed blobs.
  2323. Arguments
  2324. ClientHandle - client handle
  2325. GpcCfInfoHandle - the blob handle
  2326. Status - completion status
  2327. Returns
  2328. void
  2329. ************************************************************************
  2330. */
  2331. VOID
  2332. GpcRemoveCfInfoNotifyComplete(
  2333. IN GPC_HANDLE ClientHandle,
  2334. IN GPC_HANDLE GpcCfInfoHandle,
  2335. IN GPC_STATUS Status
  2336. )
  2337. {
  2338. PCLIENT_BLOCK pClient;
  2339. PBLOB_BLOCK pBlob;
  2340. PCLIENT_BLOCK pClient2;
  2341. TRACE(BLOB, GpcCfInfoHandle, Status, "GpcRemoveCfInfoNotifyComplete");
  2342. //VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  2343. //VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
  2344. pClient = (PCLIENT_BLOCK)ClientHandle;
  2345. pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
  2346. ASSERT(pBlob);
  2347. ASSERT(pClient);
  2348. ASSERT(Status != GPC_STATUS_PENDING);
  2349. ASSERT(pBlob->ClientStatusCountDown > 0);
  2350. if (!NT_ERROR(pBlob->LastStatus) || NT_ERROR(Status)) {
  2351. //
  2352. // save the last error code
  2353. //
  2354. pBlob->LastStatus = Status;
  2355. }
  2356. NDIS_LOCK(&pBlob->Lock);
  2357. if (Status == GPC_STATUS_SUCCESS && pClient == pBlob->pNotifiedClient) {
  2358. pBlob->pNotifiedClient = NULL;
  2359. pBlob->NotifiedClientCtx = NULL;
  2360. }
  2361. NDIS_UNLOCK(&pBlob->Lock);
  2362. if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
  2363. if (pBlob->State == GPC_STATE_REMOVE) {
  2364. if (pBlob->pCallingClient->State == GPC_STATE_READY) {
  2365. //
  2366. // complete the request to the client
  2367. //
  2368. ClientRemoveCfInfoComplete
  2369. (
  2370. pBlob->pCallingClient, // first guy who made the call
  2371. pBlob, // completing blob
  2372. pBlob->LastStatus // status
  2373. );
  2374. NDIS_LOCK(&pBlob->Lock);
  2375. //
  2376. // notify any pending client about the status
  2377. //
  2378. if (pClient2 = pBlob->pCallingClient2) {
  2379. pBlob->pCallingClient2 = NULL;
  2380. NDIS_UNLOCK(&pBlob->Lock);
  2381. //
  2382. // complete the request to this client
  2383. //
  2384. ClientRemoveCfInfoComplete
  2385. (
  2386. pClient2, // the guy who made the call
  2387. pBlob, // completing blob
  2388. pBlob->LastStatus // status
  2389. );
  2390. } else {
  2391. NDIS_UNLOCK(&pBlob->Lock);
  2392. }
  2393. //pBlob->State = GPC_STATE_READY;
  2394. if (pBlob->LastStatus == GPC_STATUS_SUCCESS) {
  2395. //
  2396. // release the mapping handle
  2397. //
  2398. FreeHandle(pBlob->ClHandle);
  2399. //
  2400. // all clients have reported
  2401. // remove the blob
  2402. //
  2403. REFDEL(&pBlob->RefCount, 'BLOB');
  2404. //DereferenceBlob(&pBlob);
  2405. } else {
  2406. //
  2407. // blob not removed - restore the object type
  2408. //
  2409. pBlob->ObjectType = GPC_ENUM_CFINFO_TYPE;
  2410. //
  2411. // resume the mapping handle
  2412. //
  2413. ResumeHandle(pBlob->ClHandle);
  2414. }
  2415. }
  2416. } else { // if (pBlob->State....)
  2417. //
  2418. // we are removing the blob since we failed to add it
  2419. // to ALL clients.
  2420. //
  2421. ASSERT(pBlob->State == GPC_STATE_ADD);
  2422. //
  2423. // Release the AddFailed block so that the AddComplete
  2424. // will resume
  2425. //
  2426. CTESignal(&pBlob->WaitBlockAddFailed, pBlob->LastStatus);
  2427. }
  2428. }
  2429. //
  2430. // release the one we got earlier
  2431. //
  2432. //DereferenceClient(pClient);
  2433. TRACE(BLOB, 0, 0, "GpcRemoveCfInfoNotifyComplete==>");
  2434. }
  2435. /*
  2436. ************************************************************************
  2437. GpcRemovePattern -
  2438. Called by the client to remove a pattern from the database.
  2439. Arguments
  2440. ClientHandle - client handle
  2441. GpcPatternHandle - pattern handle
  2442. Returns
  2443. GPC_STATUS
  2444. ************************************************************************
  2445. */
  2446. GPC_STATUS
  2447. GpcRemovePattern(
  2448. IN GPC_HANDLE ClientHandle,
  2449. IN GPC_HANDLE GpcPatternHandle
  2450. )
  2451. {
  2452. return(privateGpcRemovePattern(
  2453. ClientHandle,
  2454. GpcPatternHandle,
  2455. FALSE, FALSE
  2456. ));
  2457. }
  2458. /*
  2459. ************************************************************************
  2460. privateGpcRemovePattern -
  2461. Internal call in the GPC to indicate whether this is forceful removal.
  2462. Arguments
  2463. ClientHandle - client handle
  2464. GpcPatternHandle - pattern handle
  2465. Returns
  2466. GPC_STATUS
  2467. ************************************************************************
  2468. */
  2469. GPC_STATUS
  2470. privateGpcRemovePattern(
  2471. IN GPC_HANDLE ClientHandle,
  2472. IN GPC_HANDLE GpcPatternHandle,
  2473. IN BOOLEAN ForceRemoval ,
  2474. IN BOOLEAN DbLocked
  2475. )
  2476. {
  2477. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  2478. PPATTERN_BLOCK pPattern;
  2479. PCLIENT_BLOCK pClient;
  2480. PPROTOCOL_BLOCK pProtocol;
  2481. ULONG Flags;
  2482. ULONG CfIndex;
  2483. ULONG ProtocolId;
  2484. TRACE(PATTERN, ClientHandle, GpcPatternHandle, "GpcRemovePattern");
  2485. DBGPRINT(PATTERN, ("GpcRemovePattern: Client=%X Pattern=%X\n",
  2486. ClientHandle, GpcPatternHandle));
  2487. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  2488. VERIFY_OBJECT(GpcPatternHandle, GPC_ENUM_PATTERN_TYPE);
  2489. pClient = (PCLIENT_BLOCK)ClientHandle;
  2490. pPattern = (PPATTERN_BLOCK)GpcPatternHandle;
  2491. ASSERT(pClient);
  2492. ASSERT(pPattern);
  2493. CfIndex = pClient->pCfBlock->AssignedIndex;
  2494. ProtocolId = pPattern->ProtocolTemplate;
  2495. pProtocol = &glData.pProtocols[ProtocolId];
  2496. //
  2497. // If the pattern has already been removed by the ADAPTER (mostly WAN link)
  2498. // going down, just return with an error. The memory is valid since the
  2499. // ProxyRemovePattern function added a REF.
  2500. //
  2501. NDIS_LOCK(&pPattern->Lock);
  2502. if (!ForceRemoval && (pPattern->State != GPC_STATE_READY)) {
  2503. NDIS_UNLOCK(&pPattern->Lock);
  2504. return GPC_STATUS_INVALID_HANDLE;
  2505. } else {
  2506. NDIS_UNLOCK(&pPattern->Lock);
  2507. }
  2508. //
  2509. // determine weather its a specific or generic pattern
  2510. //
  2511. Flags = pPattern->Flags;
  2512. if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
  2513. //
  2514. // this is a specific pattern, call the appropriate routine
  2515. // to remove from db
  2516. //
  2517. Status = RemoveSpecificPattern(
  2518. pClient,
  2519. pProtocol,
  2520. pPattern,
  2521. ForceRemoval,
  2522. DbLocked
  2523. );
  2524. } else {
  2525. //
  2526. // this is a generic pattern, call the appropriate routine
  2527. // to remove from db
  2528. //
  2529. Status = RemoveGenericPattern(
  2530. pClient,
  2531. pProtocol,
  2532. pPattern
  2533. );
  2534. }
  2535. TRACE(PATTERN, Status, 0, "GpcRemovePattern==>");
  2536. if (NT_SUCCESS(Status)) {
  2537. if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
  2538. ProtocolStatInc(ProtocolId,DeletedSp);
  2539. ProtocolStatDec(ProtocolId,CurrentSp);
  2540. NdisInterlockedDecrement(&pProtocol->SpecificPatternCount);
  2541. } else {
  2542. ProtocolStatInc(ProtocolId,DeletedGp);
  2543. ProtocolStatDec(ProtocolId,CurrentGp);
  2544. NdisInterlockedDecrement(&pProtocol->GenericPatternCount);
  2545. }
  2546. }
  2547. DBGPRINT(PATTERN, ("GpcRemovePattern: Client=%X Pattern=%X, Status=%X\n",
  2548. ClientHandle, GpcPatternHandle,Status));
  2549. return Status;
  2550. }
  2551. /*
  2552. ************************************************************************
  2553. GpcClassifyPattern -
  2554. Called by the client to classify a pattern and get back a client blob
  2555. context and a classification handle.
  2556. Arguments
  2557. ClientHandle - client handle
  2558. ProtocolTemplate - the protocol template to use
  2559. pPattern - pointer to pattern
  2560. pClientCfInfoContext - OUT, the client's blob context
  2561. pClassificationHandle - OUT, classification handle
  2562. Returns
  2563. GPC_STATUS: GPC_STATUS_NOT_FOUND
  2564. ************************************************************************
  2565. */
  2566. GPC_STATUS
  2567. GpcClassifyPattern(
  2568. IN GPC_HANDLE ClientHandle,
  2569. IN ULONG ProtocolTemplate,
  2570. IN PVOID pPattern,
  2571. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, // optional
  2572. IN OUT PCLASSIFICATION_HANDLE pClassificationHandle,
  2573. IN ULONG Offset,
  2574. IN PULONG pValue,
  2575. IN BOOLEAN bNoCache
  2576. )
  2577. {
  2578. GPC_STATUS Status;
  2579. PPATTERN_BLOCK pPatternBlock;
  2580. PCLIENT_BLOCK pClient;
  2581. PPROTOCOL_BLOCK pProtocol;
  2582. PGPC_IP_PATTERN pIp = (PGPC_IP_PATTERN)pPattern;
  2583. KIRQL CHirql;
  2584. PBLOB_BLOCK pBlob;
  2585. TRACE(CLASSIFY, ClientHandle, *pClassificationHandle, "GpcClassifyPattern<==");
  2586. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  2587. ASSERT(ClientHandle);
  2588. ASSERT(pPattern);
  2589. //ASSERT(pClientCfInfoContext);
  2590. ASSERT(pClassificationHandle);
  2591. Status = GPC_STATUS_SUCCESS;
  2592. if (ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX) {
  2593. return GPC_STATUS_INVALID_PARAMETER;
  2594. }
  2595. pProtocol = &glData.pProtocols[ProtocolTemplate];
  2596. //
  2597. // Optimization - check if there are any patterns installed
  2598. //
  2599. if (pProtocol->SpecificPatternCount == 0
  2600. &&
  2601. pProtocol->GenericPatternCount == 0 ) {
  2602. if (pClientCfInfoContext) {
  2603. *pClientCfInfoContext = NULL;
  2604. }
  2605. *pClassificationHandle = (CLASSIFICATION_HANDLE)0;
  2606. DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X no patterns returned %X\n",
  2607. ClientHandle, GPC_STATUS_NOT_FOUND));
  2608. TRACE(CLASSIFY, ClientHandle, GPC_STATUS_NOT_FOUND, "GpcClassifyPattern (1)" );
  2609. return GPC_STATUS_NOT_FOUND;
  2610. }
  2611. pClient = (PCLIENT_BLOCK)ClientHandle;
  2612. if (ProtocolTemplate == GPC_PROTOCOL_TEMPLATE_IP) {
  2613. pIp = (PGPC_IP_PATTERN)pPattern;
  2614. pIp->Reserved[0] = pIp->Reserved[1] = pIp->Reserved[2] = 0;
  2615. DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X, CH=%d\n",
  2616. ClientHandle, *pClassificationHandle));
  2617. DBGPRINT(CLASSIFY, ("IP: ifc={%d,%d} src=%08X:%04x, dst=%08X:%04x, prot=%d rsv=%x,%x,%x\n",
  2618. pIp->InterfaceId.InterfaceId,
  2619. pIp->InterfaceId.LinkId,
  2620. pIp->SrcAddr,
  2621. pIp->gpcSrcPort,
  2622. pIp->DstAddr,
  2623. pIp->gpcDstPort,
  2624. pIp->ProtocolId,
  2625. pIp->Reserved[0],
  2626. pIp->Reserved[1],
  2627. pIp->Reserved[2]
  2628. ));
  2629. }
  2630. ProtocolStatInc(ProtocolTemplate, ClassificationRequests);
  2631. //
  2632. // verify the classification handle, if it's valid, simply return
  2633. //
  2634. if (*pClassificationHandle && (pClientCfInfoContext || pValue)) {
  2635. Status = GetClientCtxAndUlongFromCfInfo(ClientHandle,
  2636. pClassificationHandle,
  2637. pClientCfInfoContext,
  2638. Offset,
  2639. pValue
  2640. );
  2641. ProtocolStatInc(ProtocolTemplate, PatternsClassified);
  2642. DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X returned immediate CH %d\n",
  2643. pClient, *pClassificationHandle));
  2644. TRACE(CLASSIFY, pClient, *pClassificationHandle, "GpcClassifyPattern (2)" );
  2645. return Status;
  2646. }
  2647. //
  2648. // there pattern needs to be classified
  2649. // this should find the classification handle
  2650. //
  2651. Status = InternalSearchPattern(
  2652. pClient,
  2653. pProtocol,
  2654. pPattern,
  2655. &pPatternBlock,
  2656. pClassificationHandle,
  2657. bNoCache
  2658. );
  2659. if (*pClassificationHandle && (pClientCfInfoContext || pValue)) {
  2660. Status = GetClientCtxAndUlongFromCfInfo(ClientHandle,
  2661. pClassificationHandle,
  2662. pClientCfInfoContext,
  2663. Offset,
  2664. pValue
  2665. );
  2666. } else if ((!NT_SUCCESS(Status)) &&
  2667. pPatternBlock &&
  2668. pClientCfInfoContext) {
  2669. // it is likely that we could not allocate the Auto Specific pattern
  2670. // just try to send the context anyway.
  2671. READ_LOCK(&glData.ChLock, &CHirql);
  2672. pBlob = GetBlobFromPattern(pPatternBlock, GetCFIndexFromClient(ClientHandle));
  2673. if(pBlob) {
  2674. *pClientCfInfoContext = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
  2675. } else {
  2676. Status = GPC_STATUS_NOT_FOUND;
  2677. }
  2678. READ_UNLOCK(&glData.ChLock, CHirql);
  2679. } else if (!*pClassificationHandle) {
  2680. //
  2681. // none found,
  2682. //
  2683. if (pClientCfInfoContext) {
  2684. *pClientCfInfoContext = NULL;
  2685. }
  2686. Status = GPC_STATUS_NOT_FOUND;
  2687. } else {
  2688. Status = GPC_STATUS_SUCCESS;
  2689. }
  2690. if (pPatternBlock) {
  2691. //DereferencePattern(pPatternBlock, pClient->pCfBlock);
  2692. ProtocolStatInc(ProtocolTemplate, PatternsClassified);
  2693. }
  2694. TRACE(CLASSIFY, pPatternBlock, Status, "GpcClassifyPattern==>");
  2695. DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X returned Pattern=%X, CH=%d, Status=%X\n",
  2696. pClient, pPattern, *pClassificationHandle, Status));
  2697. return Status;
  2698. }
  2699. /*
  2700. ************************************************************************
  2701. GpcClassifyPacket -
  2702. Called by the client to classify a packet and get back a client blob
  2703. context and a classification handle.
  2704. Content is extracted from the packet and placed into a protocol specific
  2705. structure (IP).
  2706. For IP, if fragmentation is ON for the client:
  2707. o First fragment will create a hash table entry
  2708. o Other fragments will be looked in the hash by the packet ID
  2709. o Last fragment will cause entry to be deleted.
  2710. Arguments
  2711. ClientHandle - client handle
  2712. ProtocolTemplate - the protocol template
  2713. pNdisPacket - ndis packet
  2714. TransportHeaderOffset - byte offset of the start of the transport
  2715. header from the beginning of the packet
  2716. pClientCfInfoContext - OUT, client blob context
  2717. pClassificationHandle - OUT, classification handle
  2718. Returns
  2719. GPC_STATUS
  2720. ************************************************************************
  2721. */
  2722. GPC_STATUS
  2723. GpcClassifyPacket(
  2724. IN GPC_HANDLE ClientHandle,
  2725. IN ULONG ProtocolTemplate,
  2726. IN PVOID pPacket,
  2727. IN ULONG TransportHeaderOffset,
  2728. IN PTC_INTERFACE_ID pInterfaceId,
  2729. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, //optional
  2730. OUT PCLASSIFICATION_HANDLE pClassificationHandle
  2731. )
  2732. {
  2733. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  2734. PNDIS_PACKET pNdisPacket = NULL;
  2735. PCLIENT_BLOCK pClient;
  2736. PCF_BLOCK pCf;
  2737. PPATTERN_BLOCK pPattern = NULL;
  2738. PPROTOCOL_BLOCK pProtocol;
  2739. PBLOB_BLOCK pBlob = NULL;
  2740. ULONG CfIndex;
  2741. int i;
  2742. GPC_IP_PATTERN IpPattern;
  2743. GPC_IPX_PATTERN IpxPattern;
  2744. PVOID pKey = NULL;
  2745. PVOID pAddr;
  2746. UINT Len, Tot;
  2747. PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
  2748. PIP_HEADER pIpHdr;
  2749. PIPX_HEADER pIpxHdr;
  2750. USHORT PacketId;
  2751. USHORT FragOffset;
  2752. UINT IpHdrLen;
  2753. PUDP_HEADER pUDPHdr;
  2754. UCHAR PktProtocol;
  2755. BOOLEAN bFragment = FALSE;
  2756. BOOLEAN bLastFragment = FALSE;
  2757. BOOLEAN bFirstFragment = FALSE;
  2758. TRACE(CLASSIFY, ClientHandle, pNdisPacket, "GpcClassifyPacket");
  2759. DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X CH=%d\n",
  2760. ClientHandle, *pClassificationHandle));
  2761. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  2762. ASSERT(pPacket);
  2763. ASSERT(ClientHandle);
  2764. //ASSERT(pClientCfInfoContext);
  2765. ASSERT(pClassificationHandle);
  2766. if (ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX) {
  2767. return GPC_STATUS_INVALID_PARAMETER;
  2768. }
  2769. pProtocol = &glData.pProtocols[ProtocolTemplate];
  2770. //
  2771. // Optimization - check if there are any patterns installed
  2772. //
  2773. if (pProtocol->SpecificPatternCount == 0
  2774. &&
  2775. pProtocol->GenericPatternCount == 0 ) {
  2776. if (pClientCfInfoContext) {
  2777. *pClientCfInfoContext = NULL;
  2778. }
  2779. *pClassificationHandle = 0;
  2780. DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X no patterns returned %X\n",
  2781. ClientHandle, GPC_STATUS_NOT_FOUND));
  2782. return GPC_STATUS_NOT_FOUND;
  2783. }
  2784. pClient = (PCLIENT_BLOCK)ClientHandle;
  2785. pNdisPacket = (PNDIS_PACKET)pPacket;
  2786. //
  2787. // get the classification handle from the packet
  2788. // if there - extract the blob pointer and the client blob context
  2789. // directly and return
  2790. //
  2791. //
  2792. // o/w, we need to look inside the packet
  2793. // Parse the packet into a pattern and make a db search
  2794. // first match a specific pattern, and then search the generic
  2795. // database(s) for the given CF
  2796. //
  2797. pCf = pClient->pCfBlock;
  2798. CfIndex = pCf->AssignedIndex;
  2799. ProtocolStatInc(ProtocolTemplate,ClassificationRequests);
  2800. *pClassificationHandle = 0;
  2801. //
  2802. // get the pattern from the packet
  2803. //
  2804. //
  2805. // get the first NDIS buffer - assuming it is a MAC header
  2806. //
  2807. NdisGetFirstBufferFromPacket(pNdisPacket,
  2808. &pNdisBuf1, // Ndis buffer 1 desc.
  2809. &pAddr, // buffer VA
  2810. &Len, // buffer length
  2811. &Tot // total length (all buffs)
  2812. );
  2813. ASSERT(Tot > TransportHeaderOffset);
  2814. while (Len <= TransportHeaderOffset) {
  2815. //
  2816. // Transport header is not in this buffer,
  2817. // try the next buffer
  2818. //
  2819. TransportHeaderOffset -= Len;
  2820. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  2821. ASSERT(pNdisBuf2); // should never happen!!
  2822. NdisQueryBuffer(pNdisBuf2, &pAddr, &Len);
  2823. pNdisBuf1 = pNdisBuf2;
  2824. }
  2825. switch (ProtocolTemplate) {
  2826. case GPC_PROTOCOL_TEMPLATE_IP:
  2827. //
  2828. // fill the pattern with '0'
  2829. //
  2830. RtlZeroMemory(&IpPattern, sizeof(IpPattern));
  2831. //
  2832. // parse IP packet here...
  2833. //
  2834. pIpHdr = (PIP_HEADER)(((PUCHAR)pAddr) + TransportHeaderOffset);
  2835. IpHdrLen = (pIpHdr->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
  2836. FragOffset = pIpHdr->iph_offset & IP_OFFSET_MASK;
  2837. FragOffset = net_short(FragOffset) * 8;
  2838. PacketId = pIpHdr->iph_id;
  2839. //
  2840. // check for fragmentation
  2841. //
  2842. bFragment = (pIpHdr->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
  2843. bFirstFragment = bFragment && (FragOffset == 0);
  2844. bLastFragment = bFragment &&
  2845. TEST_BIT_OFF(pIpHdr->iph_offset, IP_MF_FLAG);
  2846. //
  2847. // sanity check - doesn't make sense to have a single fragment
  2848. //
  2849. ASSERT(!bFirstFragment || !bLastFragment);
  2850. if (TEST_BIT_ON(pClient->Flags, GPC_FLAGS_FRAGMENT) &&
  2851. (bFragment && ! bFirstFragment)) {
  2852. //
  2853. // client is interested in fragmentation and this is a
  2854. // a fragment, but not the first one.
  2855. // It will be handled later when we find the pattern
  2856. //
  2857. Status = HandleFragment(
  2858. pClient,
  2859. pProtocol,
  2860. bFirstFragment, // first frag
  2861. bLastFragment, // last frag
  2862. PacketId,
  2863. &pPattern,
  2864. &pBlob
  2865. );
  2866. } else {
  2867. //
  2868. // not a fragment, or is the first one - we have to search db
  2869. //
  2870. IpPattern.SrcAddr = pIpHdr->iph_src;
  2871. IpPattern.DstAddr = pIpHdr->iph_dest;
  2872. IpPattern.ProtocolId = pIpHdr->iph_protocol;
  2873. //
  2874. // case the ProtocolId and fill the appropriate union
  2875. //
  2876. switch (IpPattern.ProtocolId) {
  2877. case IPPROTO_IP:
  2878. //
  2879. // we have everything so far
  2880. //
  2881. break;
  2882. case IPPROTO_TCP:
  2883. case IPPROTO_UDP:
  2884. //
  2885. // need to get those port numbers
  2886. //
  2887. if (IpHdrLen < Len) {
  2888. //
  2889. // the UDP/TCP header is in the same buffer
  2890. //
  2891. pUDPHdr = (PUDP_HEADER)((PUCHAR)pIpHdr + IpHdrLen);
  2892. } else {
  2893. //
  2894. // get the next buffer
  2895. //
  2896. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  2897. ASSERT(pNdisBuf2);
  2898. if (IpHdrLen > Len) {
  2899. //
  2900. // There is an optional header buffer, so get the next
  2901. // buffer to reach the udp/tcp header
  2902. //
  2903. pNdisBuf1 = pNdisBuf2;
  2904. NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
  2905. ASSERT(pNdisBuf2);
  2906. }
  2907. NdisQueryBuffer(pNdisBuf2, &pUDPHdr, &Len);
  2908. }
  2909. IpPattern.gpcSrcPort = pUDPHdr->uh_src;
  2910. IpPattern.gpcDstPort = pUDPHdr->uh_dest;
  2911. #if INTERFACE_ID
  2912. IpPattern.InterfaceId.InterfaceId = pInterfaceId->InterfaceId;
  2913. IpPattern.InterfaceId.LinkId = pInterfaceId->LinkId;
  2914. #endif
  2915. break;
  2916. case IPPROTO_ICMP:
  2917. case IPPROTO_IGMP:
  2918. default:
  2919. //
  2920. // The default will cover all IP_PROTO_RAW packets. Note that in this case, all we care about
  2921. // is the InterfaceID
  2922. //
  2923. #if INTERFACE_ID
  2924. IpPattern.InterfaceId.InterfaceId = pInterfaceId->InterfaceId;
  2925. IpPattern.InterfaceId.LinkId = pInterfaceId->LinkId;
  2926. #endif
  2927. break;
  2928. case IPPROTO_IPSEC:
  2929. pKey = NULL;
  2930. Status = GPC_STATUS_NOT_SUPPORTED;
  2931. }
  2932. pKey = &IpPattern;
  2933. break;
  2934. }
  2935. DBGPRINT(CLASSIFY, ("IP: ifc={%d,%d} src=%X:%x, dst=%X:%x, prot=%x, rsv=%x,%x,%x \n",
  2936. IpPattern.InterfaceId.InterfaceId,
  2937. IpPattern.InterfaceId.LinkId,
  2938. IpPattern.SrcAddr,
  2939. IpPattern.gpcSrcPort,
  2940. IpPattern.DstAddr,
  2941. IpPattern.gpcDstPort,
  2942. IpPattern.ProtocolId,
  2943. IpPattern.Reserved[0],
  2944. IpPattern.Reserved[1],
  2945. IpPattern.Reserved[2]
  2946. ));
  2947. break;
  2948. case GPC_PROTOCOL_TEMPLATE_IPX:
  2949. //
  2950. // fill the pattern with '0'
  2951. //
  2952. RtlZeroMemory(&IpxPattern, sizeof(IpxPattern));
  2953. //
  2954. // parse IPX packet here...
  2955. //
  2956. pIpxHdr = (PIPX_HEADER)(((PUCHAR)pAddr) + TransportHeaderOffset);
  2957. //
  2958. // source
  2959. //
  2960. IpxPattern.Src.NetworkAddress = *(ULONG *)pIpxHdr->SourceNetwork;
  2961. RtlMoveMemory(IpxPattern.Src.NodeAddress, pIpxHdr->SourceNode,6);
  2962. IpxPattern.Src.Socket = pIpxHdr->SourceSocket;
  2963. //
  2964. // destination
  2965. //
  2966. IpxPattern.Dest.NetworkAddress = *(ULONG *)pIpxHdr->DestinationNetwork;
  2967. RtlMoveMemory(IpxPattern.Dest.NodeAddress, pIpxHdr->DestinationNode,6);
  2968. IpxPattern.Dest.Socket = pIpxHdr->DestinationSocket;
  2969. pKey = &IpxPattern;
  2970. break;
  2971. default:
  2972. Status = GPC_STATUS_INVALID_PARAMETER;
  2973. }
  2974. if (NT_SUCCESS(Status) && pPattern == NULL) {
  2975. //
  2976. // no failure so far but no pattern found either
  2977. // search for the pattern
  2978. //
  2979. ASSERT(pKey);
  2980. //
  2981. // if there is a match, the pattern ref count will be bumped
  2982. // up and we need to release it when we're done.
  2983. //
  2984. Status = InternalSearchPattern(
  2985. pClient,
  2986. pProtocol,
  2987. pKey,
  2988. &pPattern,
  2989. pClassificationHandle,
  2990. FALSE
  2991. );
  2992. }
  2993. if (*pClassificationHandle) {
  2994. if (pClientCfInfoContext) {
  2995. Status = GpcGetCfInfoClientContext(ClientHandle,
  2996. *pClassificationHandle,
  2997. pClientCfInfoContext);
  2998. }
  2999. ProtocolStatInc(ProtocolTemplate, PacketsClassified);
  3000. } else {
  3001. //ASSERT(pBlob == NULL);
  3002. //
  3003. // none found, or some other error occured.
  3004. //
  3005. if (pClientCfInfoContext) {
  3006. *pClientCfInfoContext = NULL;
  3007. }
  3008. *pClassificationHandle = 0;
  3009. Status = GPC_STATUS_NOT_FOUND;
  3010. }
  3011. TRACE(CLASSIFY, pPattern, Status, "GpcClassifyPacket==>");
  3012. DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X returned Pattern=%X, CH=%d, Status=%X\n",
  3013. pClient, pPattern, *pClassificationHandle, Status));
  3014. return Status;
  3015. }
  3016. /*
  3017. ************************************************************************
  3018. GpcEnumCfInfo -
  3019. Called to enumerate CfInfo's (and attached filters).
  3020. For each CfInfo, GPC will return the CfInfo blob and the list of
  3021. pattern attached to it.
  3022. Arguments
  3023. ClientHandle - the calling client
  3024. pBlob - the next cfinfo to enumerate, NULL for the first
  3025. pBlobCount - in: requested; out: returned
  3026. pBufferSize - in: allocated; out: bytes returned
  3027. Buffer - output buffer
  3028. Returns
  3029. GPC_STATUS
  3030. ************************************************************************
  3031. */
  3032. GPC_STATUS
  3033. GpcEnumCfInfo(
  3034. IN GPC_HANDLE ClientHandle,
  3035. IN OUT PHANDLE pCfInfoHandle,
  3036. OUT PHANDLE pCfInfoMapHandle,
  3037. IN OUT PULONG pCfInfoCount,
  3038. IN OUT PULONG pBufferSize,
  3039. IN PGPC_ENUM_CFINFO_BUFFER Buffer
  3040. )
  3041. {
  3042. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  3043. GPC_STATUS st;
  3044. PBLOB_BLOCK pBlob = NULL;
  3045. PCF_BLOCK pCf;
  3046. PLIST_ENTRY pEntry, pHead;
  3047. PPATTERN_BLOCK pPattern;
  3048. ULONG cCfInfo = 0;
  3049. ULONG cTotalBytes = 0;
  3050. ULONG cPatterns, cValidPatterns;
  3051. ULONG size, cValidSize;
  3052. ULONG PatternMaskLen;
  3053. ULONG PatternSize;
  3054. ULONG i;
  3055. PCHAR p, q;
  3056. PGENERIC_PATTERN_DB pGenDb;
  3057. UNICODE_STRING CfInfoName;
  3058. PGPC_GEN_PATTERN pGenPattern;
  3059. BOOLEAN bEnum;
  3060. KIRQL ReadIrql;
  3061. KIRQL irql;
  3062. PCLIENT_BLOCK pNotifiedClient;
  3063. GPC_CLIENT_HANDLE NotifiedClientCtx;
  3064. BOOLEAN found = FALSE;
  3065. UNICODE_STRING UniStr;
  3066. //
  3067. // debug checks
  3068. //
  3069. ASSERT(ClientHandle);
  3070. ASSERT(pCfInfoHandle);
  3071. ASSERT(pCfInfoMapHandle);
  3072. ASSERT(pCfInfoCount);
  3073. ASSERT(pBufferSize);
  3074. ASSERT(Buffer);
  3075. cValidPatterns = 0;
  3076. VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
  3077. pCf = ((PCLIENT_BLOCK)ClientHandle)->pCfBlock;
  3078. //NDIS_LOCK(&pCf->Lock);
  3079. RSC_WRITE_LOCK(&pCf->ClientSync, &irql);
  3080. //
  3081. // check if we start from a previous blob
  3082. //
  3083. if (*pCfInfoHandle) {
  3084. pBlob = (PBLOB_BLOCK)*pCfInfoHandle;
  3085. NDIS_LOCK(&pBlob->Lock);
  3086. if (pBlob->State == GPC_STATE_REMOVE) {
  3087. //
  3088. // the blob has been marked for removal
  3089. //
  3090. NDIS_UNLOCK(&pBlob->Lock);
  3091. //NDIS_UNLOCK(&pCf->Lock);
  3092. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  3093. *pCfInfoMapHandle = NULL;
  3094. return STATUS_DATA_ERROR;
  3095. }
  3096. //NDIS_UNLOCK(&pBlob->Lock);
  3097. } else {
  3098. //
  3099. // find the first (good) blob to enumerate.
  3100. //
  3101. //
  3102. // Need to take pCf->Lock to manipulate or
  3103. // traverse the Blobs on it
  3104. //
  3105. NDIS_LOCK(&pCf->Lock);
  3106. if (IsListEmpty(&pCf->BlobList)) {
  3107. //
  3108. // no blobs to enumerate
  3109. //
  3110. *pCfInfoCount = 0;
  3111. *pBufferSize = 0;
  3112. *pCfInfoMapHandle = NULL;
  3113. //NDIS_UNLOCK(&pCf->Lock);
  3114. NDIS_UNLOCK(&pCf->Lock);
  3115. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  3116. return GPC_STATUS_SUCCESS;
  3117. } else {
  3118. //
  3119. // Find a good Blob (something that's not getting deleted)
  3120. //
  3121. pEntry = pCf->BlobList.Flink;
  3122. while (&pCf->BlobList != pEntry) {
  3123. pBlob = CONTAINING_RECORD(pEntry, BLOB_BLOCK, CfLinkage);
  3124. NDIS_LOCK(&pBlob->Lock);
  3125. if ((pBlob->State == GPC_STATE_READY) &&
  3126. (pBlob->ObjectType != GPC_ENUM_INVALID)) {
  3127. found = TRUE;
  3128. break;
  3129. } else {
  3130. //Aha! The first Blob is bad!!
  3131. pEntry = pEntry->Flink;
  3132. NDIS_UNLOCK(&pBlob->Lock);
  3133. }
  3134. }
  3135. //
  3136. // Couldn't find anything to enumerate.
  3137. if (!found) {
  3138. //No Blobs to enumerate
  3139. *pCfInfoCount = 0;
  3140. *pBufferSize = 0;
  3141. *pCfInfoMapHandle = NULL;
  3142. NDIS_UNLOCK(&pCf->Lock);
  3143. //NDIS_UNLOCK(&pCf->Lock);
  3144. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  3145. return GPC_STATUS_SUCCESS;
  3146. }
  3147. }
  3148. NDIS_UNLOCK(&pCf->Lock);
  3149. }
  3150. ASSERT(pBlob);
  3151. *pCfInfoMapHandle = pBlob->ClHandle;
  3152. //
  3153. // at this point, we should have a blob pointer that we can
  3154. // start enumerating. The CF is still lock, so we can safely
  3155. // walk the BlobList
  3156. // The blob lock is also taken so we can scan the pattern list
  3157. //
  3158. for ( ; ; ) { // we'll break out from this
  3159. //NDIS_LOCK(&pBlob->Lock);
  3160. //NdisInterlockedIncrement(&pBlob->RefCount);
  3161. //ASSERT (pBlob->State != GPC_STATE_REMOVE);
  3162. //NDIS_UNLOCK(&pBlob->Lock);
  3163. pHead = &pBlob->PatternList;
  3164. pEntry = pHead->Flink;
  3165. //
  3166. // Calculate how much space is needed for just one CfInfo
  3167. // and all of its filters
  3168. //
  3169. size = sizeof(GPC_ENUM_CFINFO_BUFFER) + pBlob->ClientDataSize;
  3170. //
  3171. // patterns might become invalid while we try to enum the CF, so we set cValidSize here
  3172. // we have to align cValidSize so that the next CfInfo starts at a word boundary.
  3173. //
  3174. size = ((size + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
  3175. cValidSize = size;
  3176. //
  3177. // Count the patterns
  3178. //
  3179. for (cPatterns = 0, PatternMaskLen = 0;
  3180. pHead != pEntry;
  3181. cPatterns++, pEntry = pEntry->Flink) {
  3182. pPattern = CONTAINING_RECORD(pEntry,
  3183. PATTERN_BLOCK,
  3184. BlobLinkage[pCf->AssignedIndex]);
  3185. PatternMaskLen += (sizeof(GPC_GEN_PATTERN) +
  3186. 2 * glData.pProtocols[pPattern->ProtocolTemplate].PatternSize);
  3187. }
  3188. //
  3189. // check if we have enough buffer space
  3190. //
  3191. size += PatternMaskLen;
  3192. cValidPatterns = 0;
  3193. if ((cTotalBytes + size) <= *pBufferSize) {
  3194. //
  3195. // yes, we can squeeze one more...
  3196. //
  3197. pEntry = pHead->Flink;
  3198. pGenPattern = &Buffer->GenericPattern[0];
  3199. for (i = 0;
  3200. ((i < cPatterns) && (pEntry != pHead));
  3201. i++, pEntry = pEntry->Flink) {
  3202. //
  3203. // fill all the patterns + masks in
  3204. //
  3205. pPattern = CONTAINING_RECORD(pEntry,
  3206. PATTERN_BLOCK,
  3207. BlobLinkage[pCf->AssignedIndex] );
  3208. NDIS_LOCK(&pPattern->Lock);
  3209. // Check for pattern's state...
  3210. //
  3211. if (GPC_STATE_READY != pPattern->State) {
  3212. // don't try to list it out if its being removed!
  3213. NDIS_UNLOCK(&pPattern->Lock);
  3214. continue;
  3215. }
  3216. cValidSize += (sizeof(GPC_GEN_PATTERN) +
  3217. 2 * glData.pProtocols[pPattern->ProtocolTemplate].PatternSize);
  3218. PatternSize = glData.pProtocols[pPattern->ProtocolTemplate].PatternSize;
  3219. pGenPattern->ProtocolId = pPattern->ProtocolTemplate;
  3220. pGenPattern->PatternSize = PatternSize;
  3221. pGenPattern->PatternOffset = sizeof(GPC_GEN_PATTERN);
  3222. pGenPattern->MaskOffset = pGenPattern->PatternOffset + PatternSize;
  3223. p = ((PUCHAR)pGenPattern) + pGenPattern->PatternOffset;
  3224. cValidPatterns++;
  3225. //
  3226. // get the pattern and mask bits
  3227. //
  3228. if (TEST_BIT_ON(pPattern->Flags, PATTERN_SPECIFIC)) {
  3229. //
  3230. // this is a specific pattern
  3231. //
  3232. READ_LOCK(&glData.pProtocols[pPattern->ProtocolTemplate].SpecificDb.Lock, &ReadIrql);
  3233. ASSERT(pPattern->DbCtx);
  3234. q = GetKeyPtrFromSpecificPatternHandle
  3235. (((SpecificPatternHandle)pPattern->DbCtx));
  3236. RtlMoveMemory(p, q, PatternSize);
  3237. p += PatternSize;
  3238. //
  3239. // that's a specific pattern, remember?
  3240. //
  3241. NdisFillMemory(p, PatternSize, (CHAR)0xff);
  3242. READ_UNLOCK(&glData.pProtocols[pPattern->ProtocolTemplate].SpecificDb.Lock, ReadIrql);
  3243. } else {
  3244. pGenDb = &pCf->arpGenericDb[pPattern->ProtocolTemplate][pPattern->Priority];
  3245. READ_LOCK(&pGenDb->Lock, &ReadIrql);
  3246. //
  3247. // generic pattern
  3248. //
  3249. ASSERT(pPattern->DbCtx);
  3250. q = GetKeyPtrFromPatternHandle(pGenDb->pRhizome,
  3251. pPattern->DbCtx);
  3252. RtlMoveMemory(p, q, PatternSize);
  3253. p += PatternSize;
  3254. //
  3255. // mask
  3256. //
  3257. q = GetMaskPtrFromPatternHandle(pGenDb->pRhizome,
  3258. pPattern->DbCtx);
  3259. RtlMoveMemory(p, q, PatternSize);
  3260. READ_UNLOCK(&pGenDb->Lock, ReadIrql);
  3261. }
  3262. p += PatternSize;
  3263. pGenPattern = (PGPC_GEN_PATTERN)p;
  3264. NDIS_UNLOCK(&pPattern->Lock);
  3265. } // for (i = 0; ...)
  3266. //
  3267. // we can now fill the CfInfo data.
  3268. // 'pGenPattern' now points to the place where we can safely
  3269. // store the CfInfo structure, and update the pointer
  3270. //
  3271. Buffer->InstanceNameLength = 0;
  3272. pNotifiedClient = pBlob->pNotifiedClient;
  3273. NotifiedClientCtx = pBlob->NotifiedClientCtx;
  3274. st = GPC_STATUS_FAILURE;
  3275. if (pNotifiedClient) {
  3276. if (pNotifiedClient->FuncList.ClGetCfInfoName &&
  3277. NotifiedClientCtx) {
  3278. st = pNotifiedClient->FuncList.ClGetCfInfoName(
  3279. pNotifiedClient->ClientCtx,
  3280. NotifiedClientCtx,
  3281. &CfInfoName
  3282. );
  3283. if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
  3284. CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
  3285. //
  3286. // RajeshSu claims this can never happen.
  3287. //
  3288. ASSERT(NT_SUCCESS(st));
  3289. }
  3290. }
  3291. if (NT_SUCCESS(st)) {
  3292. //
  3293. // copy the instance name
  3294. //
  3295. Buffer->InstanceNameLength = CfInfoName.Length;
  3296. RtlMoveMemory(Buffer->InstanceName,
  3297. CfInfoName.Buffer,
  3298. CfInfoName.Length
  3299. );
  3300. } else {
  3301. //
  3302. // generate a default name
  3303. //
  3304. if (NotifiedClientCtx) {
  3305. RtlInitUnicodeString(&UniStr, L"Flow <ClientNotified>");
  3306. } else {
  3307. RtlInitUnicodeString(&UniStr, L"Flow <unknown name>");
  3308. }
  3309. RtlCopyMemory(Buffer->InstanceName, UniStr.Buffer, UniStr.Length);
  3310. Buffer->InstanceNameLength = UniStr.Length;
  3311. }
  3312. Buffer->InstanceName[Buffer->InstanceNameLength/sizeof(WCHAR)] = L'\0';
  3313. //
  3314. // 'pGenPattern' should point to the location right after the last
  3315. // mask, so we fill the CfInfo data there
  3316. //
  3317. //NDIS_LOCK(&pBlob->Lock);
  3318. RtlMoveMemory(pGenPattern,
  3319. pBlob->pClientData,
  3320. pBlob->ClientDataSize);
  3321. Buffer->Length = cValidSize;
  3322. Buffer->CfInfoSize = pBlob->ClientDataSize;
  3323. Buffer->CfInfoOffset = (ULONG)((PCHAR)pGenPattern
  3324. - (PCHAR)Buffer); // offset to structure
  3325. Buffer->PatternCount = cValidPatterns;
  3326. Buffer->PatternMaskLen = PatternMaskLen;
  3327. Buffer->OwnerClientCtx = pBlob->pOwnerClient->ClientCtx;
  3328. //
  3329. // release the blob lock we've got earlier
  3330. //
  3331. NDIS_UNLOCK(&pBlob->Lock);
  3332. //
  3333. // update total counts
  3334. //
  3335. cCfInfo++;
  3336. cTotalBytes += cValidSize;
  3337. Buffer = (PGPC_ENUM_CFINFO_BUFFER)((PCHAR)Buffer + cValidSize);
  3338. pEntry = pBlob->CfLinkage.Flink;
  3339. //
  3340. // advance to the next blob in the list
  3341. //
  3342. if (pEntry == &pCf->BlobList) {
  3343. //
  3344. // end of blob list, reset the blob to NULL and return
  3345. //
  3346. pBlob = NULL;
  3347. *pCfInfoMapHandle = NULL;
  3348. break;
  3349. }
  3350. pBlob = CONTAINING_RECORD(pEntry,
  3351. BLOB_BLOCK,
  3352. CfLinkage);
  3353. *pCfInfoMapHandle = pBlob->ClHandle;
  3354. if (cCfInfo == *pCfInfoCount) {
  3355. //
  3356. // enough CfInfo's filled
  3357. //
  3358. break;
  3359. }
  3360. //
  3361. // lock the blob for the next cycle
  3362. //
  3363. NDIS_LOCK(&pBlob->Lock);
  3364. } else { // if (cTotalBytes + size <= *pBufferSize)...
  3365. //
  3366. // size is too small, set return values and break
  3367. //
  3368. //DereferenceBlob(&pBlob);
  3369. if (cCfInfo == 0) {
  3370. Status = GPC_STATUS_INSUFFICIENT_BUFFER;
  3371. }
  3372. //
  3373. // release the blob lock we've got earlier
  3374. //
  3375. NDIS_UNLOCK(&pBlob->Lock);
  3376. break;
  3377. }
  3378. } // for (;;")
  3379. //NDIS_UNLOCK(&pCf->Lock);
  3380. RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
  3381. *pCfInfoHandle = (GPC_HANDLE)pBlob;
  3382. *pCfInfoCount = cCfInfo;
  3383. *pBufferSize = cTotalBytes;
  3384. return Status;
  3385. }