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

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