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

2804 lines
82 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. net\ip\fltrdrvr\driver.c
  5. Abstract:
  6. Revision History:
  7. --*/
  8. #include "globals.h"
  9. #include <ipinfo.h>
  10. #include <ntddtcp.h>
  11. #include <tdiinfo.h>
  12. #define DEFAULT_DIRECTORY L"DosDevices"
  13. #define DEFAULT_FLTRDRVR_NAME L"IPFILTERDRIVER"
  14. typedef enum
  15. {
  16. NULL_INTERFACE = 0,
  17. OLD_INTERFACE,
  18. NEW_INTERFACE
  19. } INTTYPE, *PINTTTYPE;
  20. FILTER_DRIVER g_filters;
  21. DWORD g_dwCacheSize;
  22. DWORD g_dwHashLists;
  23. BOOL g_bDriverRunning;
  24. KSPIN_LOCK g_lOutFilterLock;
  25. KSPIN_LOCK g_lInFilterLock;
  26. KSPIN_LOCK g_FcbSpin;
  27. MRSW_LOCK g_IpTableSpin;
  28. LIST_ENTRY g_freeOutFilters;
  29. LIST_ENTRY g_freeInFilters;
  30. LIST_ENTRY g_leFcbs;
  31. DWORD g_dwMakingNewTable;
  32. DWORD g_dwNumHitsDefaultIn;
  33. DWORD g_dwNumHitsDefaultOut;
  34. DWORD g_FragThresholdSize = MINIMUM_FRAGMENT_OFFSET;
  35. ULONG AddrModulus;
  36. IPAddrEntry *AddrTable;
  37. PADDRESSARRAY * AddrHashTable;
  38. PADDRESSARRAY * AddrSubnetHashTable;
  39. NPAGED_LOOKASIDE_LIST filter_slist;
  40. PAGED_LOOKASIDE_LIST paged_slist;
  41. ERESOURCE FilterAddressLock;
  42. #ifdef DRIVER_PERF
  43. DWORD g_dwNumPackets,g_dwFragments,g_dwCache1,g_dwCache2;
  44. DWORD g_dwWalk1,g_dwWalk2,g_dwForw,g_dwWalkCache;
  45. KSPIN_LOCK g_slPerfLock;
  46. LARGE_INTEGER g_liTotalTime;
  47. #endif
  48. //
  49. // Forward references.
  50. //
  51. NTSTATUS
  52. OpenNewHandle(PFILE_OBJECT FileObject);
  53. NTSTATUS
  54. CloseFcb(PPFFCB Fcb, PFILE_OBJECT FileObject);
  55. PPAGED_FILTER_INTERFACE
  56. FindInterfaceOnHandle(PFILE_OBJECT FileObject,
  57. PVOID pvValue);
  58. DWORD
  59. LocalIpLook(DWORD Addr);
  60. BOOLEAN
  61. PfFastIoDeviceControl (
  62. IN struct _FILE_OBJECT *FileObject,
  63. IN BOOLEAN Wait,
  64. IN PVOID InputBuffer OPTIONAL,
  65. IN ULONG InputBufferLength,
  66. OUT PVOID OutputBuffer OPTIONAL,
  67. IN ULONG OutputBufferLength,
  68. IN ULONG IoControlCode,
  69. OUT PIO_STATUS_BLOCK IoStatus,
  70. IN struct _DEVICE_OBJECT *DeviceObject
  71. );
  72. NTSTATUS
  73. LockFcb(
  74. IN struct _FILE_OBJECT *FileObject);
  75. VOID
  76. PFReadRegistryParameters(PUNICODE_STRING RegistryPath);
  77. VOID
  78. UnLockFcb(
  79. IN struct _FILE_OBJECT *FileObject);
  80. NTSTATUS
  81. GetSynCountTotal(PFILTER_DRIVER_GET_SYN_COUNT OutputBuffer);
  82. NTSTATUS
  83. DeleteByHandle(
  84. IN PPFFCB Fcb,
  85. IN PPAGED_FILTER_INTERFACE pPage,
  86. IN PVOID * ppHandles,
  87. IN DWORD dwLength);
  88. FAST_IO_DISPATCH PfFastIoDispatch =
  89. {
  90. 11,
  91. NULL,
  92. NULL,
  93. NULL,
  94. NULL,
  95. NULL,
  96. NULL,
  97. NULL,
  98. NULL,
  99. NULL,
  100. PfFastIoDeviceControl
  101. };
  102. #pragma alloc_text(PAGED, DoIpIoctl)
  103. //#pragma alloc_text(PAGED, OpenNewHandle)
  104. #pragma alloc_text(PAGED, FindInterfaceOnHandle)
  105. #pragma alloc_text(PAGED, PfFastIoDeviceControl)
  106. #pragma alloc_text(INIT, DriverEntry, PFReadRegistryParameters)
  107. VOID
  108. FcbLockDown(PPFFCB Fcb)
  109. {
  110. KIRQL kirql;
  111. KeAcquireSpinLock(&g_FcbSpin, &kirql);
  112. if(!(Fcb->dwFlags & PF_FCB_CLOSED))
  113. {
  114. InterlockedDecrement(&Fcb->UseCount);
  115. Fcb->dwFlags |= PF_FCB_CLOSED;
  116. }
  117. KeReleaseSpinLock(&g_FcbSpin, kirql);
  118. }
  119. NTSTATUS
  120. DriverEntry(
  121. IN PDRIVER_OBJECT DriverObject,
  122. IN PUNICODE_STRING RegistryPath
  123. )
  124. /*++
  125. Routine Description
  126. Called when the driver is loaded. It creates the device object and sets up the DOS name.
  127. Also does the initialization of standard entry points and its own global data
  128. Arguments
  129. DriverObject
  130. RegistryPath
  131. Return Value
  132. NTSTATUS
  133. --*/
  134. {
  135. INT i;
  136. PDEVICE_OBJECT deviceObject = NULL;
  137. NTSTATUS ntStatus;
  138. WCHAR deviceNameBuffer[] = DD_IPFLTRDRVR_DEVICE_NAME;
  139. UNICODE_STRING deviceNameUnicodeString;
  140. TRACE0("Filter Driver: Entering DriverEntry\n") ;
  141. //
  142. // Initialize the lock and the list
  143. //
  144. InitializeMRSWLock(&g_filters.ifListLock);
  145. InitializeListHead(&g_filters.leIfListHead);
  146. InitializeListHead(&g_leFcbs);
  147. g_filters.ppInCache = NULL;
  148. g_filters.ppOutCache = NULL;
  149. g_bDriverRunning = FALSE;
  150. InitializeMRSWLock(&g_IpTableSpin);
  151. KeInitializeSpinLock(&g_lOutFilterLock);
  152. KeInitializeSpinLock(&g_lInFilterLock);
  153. KeInitializeSpinLock(&g_FcbSpin);
  154. InitializeListHead(&g_freeOutFilters);
  155. InitializeListHead(&g_freeInFilters);
  156. g_dwNumHitsDefaultIn = g_dwNumHitsDefaultOut = 0;
  157. #ifdef DRIVER_PERF
  158. g_dwFragments = g_dwCache1 = g_dwCache2 = g_dwNumPackets = 0;
  159. g_dwWalk1 = g_dwWalk2 = g_dwForw = g_dwWalkCache = 0;
  160. g_liTotalTime.HighPart = g_liTotalTime.LowPart = 0;
  161. KeInitializeSpinLock(&g_slPerfLock);
  162. #endif
  163. //
  164. // Create a device object
  165. //
  166. RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
  167. __try
  168. {
  169. ntStatus = IoCreateDevice (DriverObject,
  170. 0,
  171. &deviceNameUnicodeString,
  172. FILE_DEVICE_NETWORK,
  173. 0,
  174. FALSE, // Exclusive
  175. &deviceObject
  176. );
  177. if (NT_SUCCESS(ntStatus))
  178. {
  179. //
  180. // Initialize the driver object
  181. //
  182. DriverObject->DriverUnload = FilterDriverUnload;
  183. DriverObject->FastIoDispatch = &PfFastIoDispatch;
  184. DriverObject->DriverStartIo = NULL;
  185. for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
  186. {
  187. DriverObject->MajorFunction[i] = FilterDriverDispatch;
  188. }
  189. }
  190. else
  191. {
  192. DbgPrint("Filter Driver: IoCreateDevice failed\n") ;
  193. __leave;
  194. }
  195. SetupExternalNaming (&deviceNameUnicodeString) ;
  196. }
  197. __finally
  198. {
  199. if(!NT_SUCCESS(ntStatus))
  200. {
  201. DbgPrint("Filter Driver: Error in DriverEntry routine\n");
  202. }
  203. else
  204. {
  205. ExInitializeResource ( &FilterListResourceLock );
  206. ExInitializeResource ( &FilterAddressLock );
  207. TRACE0("Filter Driver: DriverEntry routine successful\n");
  208. }
  209. if(NT_SUCCESS(ntStatus))
  210. {
  211. PFReadRegistryParameters(RegistryPath);
  212. }
  213. return ntStatus;
  214. }
  215. }
  216. NTSTATUS
  217. FilterDriverDispatch(
  218. IN PDEVICE_OBJECT DeviceObject,
  219. IN PIRP Irp
  220. )
  221. /*++
  222. Routine Description
  223. Dispatch Routine for the filter driver. Gets the current irp stack location, validates
  224. the parameters and calls the necessary routing (which is ioctl.c)
  225. Arguments
  226. DeviceObject
  227. Irp
  228. Return Value
  229. Status as returned by the worker functions
  230. --*/
  231. {
  232. PIO_STACK_LOCATION irpStack;
  233. PVOID pvIoBuffer;
  234. ULONG inputBufferLength;
  235. ULONG outputBufferLength;
  236. ULONG ioControlCode;
  237. NTSTATUS ntStatus;
  238. DWORD dwSize = 0;
  239. Irp->IoStatus.Status = STATUS_SUCCESS;
  240. Irp->IoStatus.Information = 0;
  241. //
  242. // Get a pointer to the current location in the Irp. This is where
  243. // the function codes and parameters are located.
  244. //
  245. irpStack = IoGetCurrentIrpStackLocation(Irp);
  246. //
  247. // Get the pointer to the input/output buffer and it's length
  248. //
  249. pvIoBuffer = Irp->AssociatedIrp.SystemBuffer;
  250. inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
  251. outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  252. TRACE0("FilterDriver: Request received\n");
  253. switch (irpStack->MajorFunction)
  254. {
  255. case IRP_MJ_CREATE:
  256. {
  257. TRACE0("FilterDriver: IRP_MJ_CREATE\n");
  258. //
  259. // Initialize the driver. The first time it gets a create IRP, it starts up the
  260. // filtering.
  261. //
  262. ntStatus = STATUS_SUCCESS;
  263. if(!g_bDriverRunning)
  264. {
  265. ExAcquireResourceExclusive( &FilterListResourceLock, TRUE);
  266. if (g_bDriverRunning || InitFilterDriver())
  267. {
  268. g_bDriverRunning = TRUE;
  269. }
  270. else
  271. {
  272. ntStatus = STATUS_UNSUCCESSFUL ;
  273. }
  274. ExReleaseResourceLite( &FilterListResourceLock );
  275. }
  276. if(NT_SUCCESS(ntStatus))
  277. {
  278. ntStatus = OpenNewHandle(irpStack->FileObject);
  279. }
  280. break;
  281. }
  282. case IRP_MJ_CLEANUP:
  283. {
  284. TRACE0("FilterDriver: IRP_MJ_CLEANUP\n");
  285. //
  286. // Closing the file handle to the driver doesnt shut the driver down
  287. //
  288. ntStatus = STATUS_SUCCESS;
  289. break;
  290. }
  291. case IRP_MJ_CLOSE:
  292. {
  293. //
  294. // All done with this file object and this FCB. Run
  295. // down the interfaces getting rid of them
  296. //
  297. ntStatus = LockFcb(irpStack->FileObject);
  298. if(NT_SUCCESS(ntStatus))
  299. {
  300. PPFFCB Fcb = irpStack->FileObject->FsContext2;
  301. FcbLockDown(Fcb);
  302. UnLockFcb(irpStack->FileObject);
  303. }
  304. break;
  305. }
  306. case IRP_MJ_DEVICE_CONTROL:
  307. {
  308. TRACE0("FilterDriver: IRP_MJ_DEVICE_CONTROL\n");
  309. ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  310. switch (ioControlCode)
  311. {
  312. #if FWPF
  313. case IOCTL_CLEAR_INTERFACE_BINDING:
  314. {
  315. PINTERFACEBINDING pBind;
  316. PPAGED_FILTER_INTERFACE pPage;
  317. TRACE0("FilterDriver: IOCTL_CLEAR_INTERFACE_BINDING called\n");
  318. dwSize = sizeof(*pBind);
  319. if(inputBufferLength < sizeof(*pBind))
  320. {
  321. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  322. break;
  323. }
  324. if(outputBufferLength < sizeof(*pBind))
  325. {
  326. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  327. break;
  328. }
  329. pBind = (PINTERFACEBINDING)pvIoBuffer;
  330. ntStatus = LockFcb(irpStack->FileObject);
  331. if(!NT_SUCCESS(ntStatus))
  332. {
  333. break;
  334. }
  335. pPage = FindInterfaceOnHandle(irpStack->FileObject,
  336. pBind->pvDriverContext);
  337. if(!pPage)
  338. {
  339. ntStatus = STATUS_INVALID_PARAMETER;
  340. }
  341. else
  342. {
  343. ntStatus = ClearInterfaceBinding(pPage, pBind);
  344. }
  345. UnLockFcb(irpStack->FileObject);
  346. break;
  347. }
  348. case IOCTL_SET_INTERFACE_BINDING:
  349. {
  350. PINTERFACEBINDING pBind;
  351. PPAGED_FILTER_INTERFACE pPage;
  352. TRACE0("FilterDriver: IOCTL_SET_INTERFACE_BINDING called\n");
  353. dwSize = sizeof(*pBind);
  354. if(inputBufferLength < sizeof(*pBind))
  355. {
  356. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  357. break;
  358. }
  359. if(outputBufferLength < sizeof(*pBind))
  360. {
  361. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  362. break;
  363. }
  364. pBind = (PINTERFACEBINDING)pvIoBuffer;
  365. ntStatus = LockFcb(irpStack->FileObject);
  366. if(!NT_SUCCESS(ntStatus))
  367. {
  368. break;
  369. }
  370. pPage = FindInterfaceOnHandle(irpStack->FileObject,
  371. pBind->pvDriverContext);
  372. if(!pPage)
  373. {
  374. ntStatus = STATUS_INVALID_PARAMETER;
  375. }
  376. else
  377. {
  378. ntStatus = SetInterfaceBinding(pBind, pPage);
  379. }
  380. UnLockFcb(irpStack->FileObject);
  381. break;
  382. }
  383. case IOCTL_PF_GET_INTERFACE_PARAMETERS:
  384. {
  385. PPFGETINTERFACEPARAMETERS pp;
  386. PPAGED_FILTER_INTERFACE pPage;
  387. TRACE0("FilterDriver: GET_INTERFACE_PARAMETERS called\n");
  388. dwSize = sizeof(*pp);
  389. if(inputBufferLength < (sizeof(*pp) - sizeof(FILTER_STATS_EX)))
  390. {
  391. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  392. break;
  393. }
  394. if(outputBufferLength < (sizeof(*pp) - sizeof(FILTER_STATS_EX)))
  395. {
  396. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  397. break;
  398. }
  399. pp = (PPFGETINTERFACEPARAMETERS)pvIoBuffer;
  400. ntStatus = LockFcb(irpStack->FileObject);
  401. if(!NT_SUCCESS(ntStatus))
  402. {
  403. break;
  404. }
  405. if(pp->dwFlags & GET_BY_INDEX)
  406. {
  407. pPage = 0;
  408. }
  409. else
  410. {
  411. pPage = FindInterfaceOnHandle(irpStack->FileObject,
  412. pp->pvDriverContext);
  413. if(!pPage)
  414. {
  415. ntStatus = STATUS_INVALID_PARAMETER;
  416. UnLockFcb(irpStack->FileObject);
  417. break;
  418. }
  419. }
  420. dwSize = outputBufferLength;
  421. ntStatus = GetInterfaceParameters(pPage,
  422. pp,
  423. &dwSize);
  424. UnLockFcb(irpStack->FileObject);
  425. break;
  426. }
  427. case IOCTL_PF_CREATE_AND_SET_INTERFACE_PARAMETERS:
  428. {
  429. //
  430. // create a new style interface.
  431. //
  432. PPFINTERFACEPARAMETERS pInfo;
  433. TRACE0("FilterDriver: IOCTL_CREATE_AND_SET called\n");
  434. dwSize = sizeof(PFINTERFACEPARAMETERS);
  435. //
  436. // Both input and output Buffer lengths should be the same a nd
  437. //
  438. if(inputBufferLength != dwSize)
  439. {
  440. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  441. break;
  442. }
  443. if(outputBufferLength != dwSize)
  444. {
  445. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  446. break;
  447. }
  448. pInfo = (PPFINTERFACEPARAMETERS)pvIoBuffer;
  449. //
  450. // now establish the interface
  451. //
  452. ntStatus = LockFcb(irpStack->FileObject);
  453. if(!NT_SUCCESS(ntStatus))
  454. {
  455. break;
  456. }
  457. ntStatus = AddNewInterface(pInfo,
  458. irpStack->FileObject->FsContext2);
  459. UnLockFcb(irpStack->FileObject);
  460. break;
  461. }
  462. case IOCTL_PF_CREATE_LOG:
  463. {
  464. PPFPAGEDLOG pPage;
  465. PPFLOG ppfLog;
  466. TRACE0("FilterDriver: IOCTL_PF_CREATE_LOG\n");
  467. //
  468. // Check the size
  469. //
  470. dwSize = sizeof(PFLOG);
  471. if((inputBufferLength < dwSize)
  472. ||
  473. (outputBufferLength < dwSize))
  474. {
  475. ntStatus = STATUS_BUFFER_TOO_SMALL;
  476. break;
  477. }
  478. ppfLog = (PPFLOG)pvIoBuffer;
  479. ntStatus = LockFcb(irpStack->FileObject);
  480. if(!NT_SUCCESS(ntStatus))
  481. {
  482. break;
  483. }
  484. ntStatus = PfLogCreateLog(
  485. ppfLog,
  486. irpStack->FileObject->FsContext2,
  487. Irp);
  488. UnLockFcb(irpStack->FileObject);
  489. break;
  490. }
  491. case IOCTL_PF_DELETE_LOG:
  492. {
  493. TRACE0("FilterDriver: IOCTL_PF_DELETE_LOG\n");
  494. //
  495. // Check the size
  496. //
  497. dwSize = sizeof(PFDELETELOG);
  498. if(inputBufferLength < dwSize)
  499. {
  500. ntStatus = STATUS_BUFFER_TOO_SMALL;
  501. break;
  502. }
  503. ntStatus = LockFcb(irpStack->FileObject);
  504. if(!NT_SUCCESS(ntStatus))
  505. {
  506. break;
  507. }
  508. ntStatus = PfDeleteLog(
  509. (PPFDELETELOG)pvIoBuffer,
  510. irpStack->FileObject->FsContext2);
  511. UnLockFcb(irpStack->FileObject);
  512. break;
  513. }
  514. case IOCTL_SET_LOG_BUFFER:
  515. {
  516. TRACE0("FilterDriver: IOCTL_SET_LOG_BUFFER\n");
  517. //
  518. // Check the size
  519. //
  520. dwSize = sizeof(PFSETBUFFER);
  521. if((inputBufferLength < dwSize)
  522. ||
  523. (outputBufferLength < dwSize))
  524. {
  525. ntStatus = STATUS_BUFFER_TOO_SMALL;
  526. break;
  527. }
  528. ntStatus = LockFcb(irpStack->FileObject);
  529. if(!NT_SUCCESS(ntStatus))
  530. {
  531. break;
  532. }
  533. ntStatus = PfLogSetBuffer(
  534. (PPFSETBUFFER)pvIoBuffer,
  535. irpStack->FileObject->FsContext2,
  536. Irp);
  537. UnLockFcb(irpStack->FileObject);
  538. break;
  539. }
  540. case IOCTL_PF_DELETE_BY_HANDLE:
  541. {
  542. PPAGED_FILTER_INTERFACE pPage;
  543. if(inputBufferLength < sizeof(PFDELETEBYHANDLE))
  544. {
  545. ntStatus = STATUS_BUFFER_TOO_SMALL;
  546. break;
  547. }
  548. ntStatus = LockFcb(irpStack->FileObject);
  549. if(!NT_SUCCESS(ntStatus))
  550. {
  551. break;
  552. }
  553. pPage = FindInterfaceOnHandle(
  554. irpStack->FileObject,
  555. ((PPFDELETEBYHANDLE)pvIoBuffer)->pvDriverContext);
  556. if(!pPage)
  557. {
  558. ntStatus = STATUS_INVALID_PARAMETER;
  559. }
  560. else
  561. {
  562. ntStatus = DeleteByHandle(
  563. (PPFFCB)irpStack->FileObject->FsContext2,
  564. pPage,
  565. &((PPFDELETEBYHANDLE)pvIoBuffer)->pvHandles[0],
  566. inputBufferLength - sizeof(PVOID));
  567. }
  568. UnLockFcb(irpStack->FileObject);
  569. break;
  570. }
  571. case IOCTL_DELETE_INTERFACE_FILTERS_EX:
  572. {
  573. PPAGED_FILTER_INTERFACE pPage;
  574. TRACE0("FilterDriver: IOCTL_UNSET_INTERFACE_FILTERSEX\n");
  575. //
  576. // The minimum size is without any TOCs
  577. //
  578. dwSize = sizeof(FILTER_DRIVER_SET_FILTERS) - sizeof(RTR_TOC_ENTRY);
  579. if(inputBufferLength < dwSize)
  580. {
  581. ntStatus = STATUS_BUFFER_TOO_SMALL;
  582. break;
  583. }
  584. ntStatus = LockFcb(irpStack->FileObject);
  585. if(!NT_SUCCESS(ntStatus))
  586. {
  587. break;
  588. }
  589. pPage = FindInterfaceOnHandle(
  590. irpStack->FileObject,
  591. ((PFILTER_DRIVER_SET_FILTERS)pvIoBuffer)->pvDriverContext);
  592. if(!pPage)
  593. {
  594. ntStatus = STATUS_INVALID_PARAMETER;
  595. }
  596. else
  597. {
  598. ntStatus = UnSetFiltersEx(
  599. (PPFFCB)irpStack->FileObject->FsContext2,
  600. pPage,
  601. inputBufferLength,
  602. (PFILTER_DRIVER_SET_FILTERS)pvIoBuffer);
  603. }
  604. UnLockFcb(irpStack->FileObject);
  605. break;
  606. }
  607. case IOCTL_SET_INTERFACE_FILTERS_EX:
  608. {
  609. PPAGED_FILTER_INTERFACE pPage;
  610. TRACE0("FilterDriver: IOCTL_SET_INTERFACE_FILTERSEX\n");
  611. //
  612. // The minimum size is without any TOCs
  613. //
  614. dwSize = sizeof(FILTER_DRIVER_SET_FILTERS) - sizeof(RTR_TOC_ENTRY);
  615. if(inputBufferLength < dwSize)
  616. {
  617. ntStatus = STATUS_BUFFER_TOO_SMALL;
  618. break;
  619. }
  620. ntStatus = LockFcb(irpStack->FileObject);
  621. if(!NT_SUCCESS(ntStatus))
  622. {
  623. break;
  624. }
  625. pPage = FindInterfaceOnHandle(
  626. irpStack->FileObject,
  627. ((PFILTER_DRIVER_SET_FILTERS)pvIoBuffer)->pvDriverContext);
  628. if(!pPage)
  629. {
  630. ntStatus = STATUS_INVALID_PARAMETER;
  631. }
  632. else
  633. {
  634. ntStatus = SetFiltersEx(
  635. (PPFFCB)irpStack->FileObject->FsContext2,
  636. pPage,
  637. inputBufferLength,
  638. (PFILTER_DRIVER_SET_FILTERS)pvIoBuffer);
  639. }
  640. UnLockFcb(irpStack->FileObject);
  641. break;
  642. }
  643. case IOCTL_DELETE_INTERFACEEX:
  644. {
  645. PFILTER_DRIVER_DELETE_INTERFACE pDel;
  646. PPAGED_FILTER_INTERFACE pPage;
  647. TRACE0("FilterDriver: IOCTL_DELETE_INTERFACE\n");
  648. pDel = (PFILTER_DRIVER_DELETE_INTERFACE)pvIoBuffer;
  649. dwSize = sizeof(FILTER_DRIVER_DELETE_INTERFACE);
  650. if(inputBufferLength != dwSize)
  651. {
  652. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  653. break;
  654. }
  655. ntStatus = LockFcb(irpStack->FileObject);
  656. if(!NT_SUCCESS(ntStatus))
  657. {
  658. break;
  659. }
  660. pPage = FindInterfaceOnHandle(irpStack->FileObject,
  661. pDel->pvDriverContext);
  662. if(pPage)
  663. {
  664. RemoveEntryList(&pPage->leIfLink);
  665. ntStatus = DeletePagedInterface(
  666. (PPFFCB)irpStack->FileObject->FsContext2,
  667. pPage);
  668. }
  669. else
  670. {
  671. ntStatus = STATUS_INVALID_PARAMETER;
  672. }
  673. UnLockFcb(irpStack->FileObject);
  674. break;
  675. }
  676. case IOCTL_SET_LATE_BOUND_FILTERSEX:
  677. {
  678. PFILTER_DRIVER_BINDING_INFO pBindInfo;
  679. PPAGED_FILTER_INTERFACE pPage;
  680. TRACE0("FilterDriver: IOCTL_SET_LATE_BOUND_FILTERS\n");
  681. pBindInfo = (PFILTER_DRIVER_BINDING_INFO)pvIoBuffer;
  682. dwSize = sizeof(FILTER_DRIVER_BINDING_INFO);
  683. if(inputBufferLength isnot dwSize)
  684. {
  685. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  686. break;
  687. }
  688. ntStatus = LockFcb(irpStack->FileObject);
  689. if(!NT_SUCCESS(ntStatus))
  690. {
  691. break;
  692. }
  693. pPage = FindInterfaceOnHandle(irpStack->FileObject,
  694. pBindInfo->pvDriverContext);
  695. if(pPage)
  696. {
  697. ntStatus = UpdateBindingInformationEx(pBindInfo,
  698. pPage);
  699. }
  700. else
  701. {
  702. ntStatus = STATUS_INVALID_PARAMETER;
  703. }
  704. UnLockFcb(irpStack->FileObject);
  705. break;
  706. }
  707. #endif // FWPF
  708. #if STEELHEAD
  709. case IOCTL_CREATE_INTERFACE:
  710. {
  711. //
  712. // the old style of creating an interface.
  713. // just pass it through to the underlying code
  714. //
  715. PFILTER_DRIVER_CREATE_INTERFACE pInfo;
  716. TRACE0("FilterDriver: IOCTL_CREATE_INTERFACE\n");
  717. dwSize = sizeof(FILTER_DRIVER_CREATE_INTERFACE);
  718. //
  719. // Both input and output Buffer lengths should be the same and
  720. //
  721. if(inputBufferLength != dwSize)
  722. {
  723. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  724. break;
  725. }
  726. if(outputBufferLength != dwSize)
  727. {
  728. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  729. break;
  730. }
  731. pInfo = (PFILTER_DRIVER_CREATE_INTERFACE)pvIoBuffer;
  732. ntStatus = AddInterface(
  733. pInfo->pvRtrMgrContext,
  734. pInfo->dwIfIndex,
  735. pInfo->dwAdapterId,
  736. irpStack->FileObject->FsContext2,
  737. &pInfo->pvDriverContext);
  738. if(NT_SUCCESS(ntStatus))
  739. {
  740. dwSize = sizeof(FILTER_DRIVER_CREATE_INTERFACE);
  741. }
  742. break;
  743. }
  744. case IOCTL_SET_INTERFACE_FILTERS:
  745. {
  746. TRACE0("FilterDriver: IOCTL_SET_INTERFACE_FILTERS\n");
  747. //
  748. // The minimum size is without any TOCs
  749. //
  750. dwSize = sizeof(FILTER_DRIVER_SET_FILTERS) - sizeof(RTR_TOC_ENTRY);
  751. if(inputBufferLength < dwSize)
  752. {
  753. ntStatus = STATUS_BUFFER_TOO_SMALL;
  754. break;
  755. }
  756. ntStatus = SetFilters((PFILTER_DRIVER_SET_FILTERS)pvIoBuffer);
  757. break;
  758. }
  759. case IOCTL_SET_LATE_BOUND_FILTERS:
  760. {
  761. PFILTER_DRIVER_BINDING_INFO pBindInfo;
  762. TRACE0("FilterDriver: IOCTL_SET_LATE_BOUND_FILTERS\n");
  763. pBindInfo = (PFILTER_DRIVER_BINDING_INFO)pvIoBuffer;
  764. dwSize = sizeof(FILTER_DRIVER_BINDING_INFO);
  765. if(inputBufferLength isnot dwSize)
  766. {
  767. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  768. break;
  769. }
  770. ntStatus = UpdateBindingInformation(pBindInfo,
  771. pBindInfo->pvDriverContext);
  772. break;
  773. }
  774. case IOCTL_DELETE_INTERFACE:
  775. {
  776. PFILTER_DRIVER_DELETE_INTERFACE pDel;
  777. TRACE0("FilterDriver: IOCTL_DELETE_INTERFACE\n");
  778. pDel = (PFILTER_DRIVER_DELETE_INTERFACE)pvIoBuffer;
  779. dwSize = sizeof(FILTER_DRIVER_DELETE_INTERFACE);
  780. if(inputBufferLength isnot dwSize)
  781. {
  782. ntStatus = STATUS_INVALID_BUFFER_SIZE;
  783. break;
  784. }
  785. ntStatus = DeleteInterface(pDel->pvDriverContext);
  786. break;
  787. }
  788. #endif // STEELHEAD
  789. case IOCTL_TEST_PACKET:
  790. {
  791. PFILTER_DRIVER_TEST_PACKET pPacketInfo;
  792. FORWARD_ACTION eaResult;
  793. UNALIGNED IPHeader *pHeader;
  794. DWORD dwSizeOfHeader;
  795. PBYTE pbRest;
  796. DWORD dwSizeOfData;
  797. TRACE0("FilterDriver: IOCTL_TEST_PACKET\n");
  798. pPacketInfo = (PFILTER_DRIVER_TEST_PACKET)pvIoBuffer;
  799. dwSize = sizeof(FILTER_DRIVER_TEST_PACKET);
  800. if(inputBufferLength < dwSize)
  801. {
  802. ntStatus = STATUS_BUFFER_TOO_SMALL;
  803. break;
  804. }
  805. if(outputBufferLength < dwSize)
  806. {
  807. ntStatus = STATUS_BUFFER_TOO_SMALL;
  808. break;
  809. }
  810. pHeader = (IPHeader*)(pPacketInfo->bIpPacket);
  811. dwSizeOfHeader = ((pHeader->iph_verlen)&0x0f)<<2;
  812. pbRest = (PBYTE)pHeader + dwSizeOfHeader;
  813. //
  814. // make sure the header fits
  815. //
  816. dwSizeOfData = inputBufferLength - sizeof(FILTER_DRIVER_TEST_PACKET) - 1;
  817. if(dwSizeOfData < dwSizeOfHeader)
  818. {
  819. ntStatus = STATUS_BUFFER_TOO_SMALL;
  820. break;
  821. }
  822. //
  823. // it does. Make sure the data fits
  824. //
  825. dwSizeOfData -= dwSizeOfHeader;
  826. if(dwSizeOfData < (UINT)pHeader->iph_length)
  827. {
  828. ntStatus = STATUS_BUFFER_TOO_SMALL;
  829. break;
  830. }
  831. eaResult = MatchFilter(pHeader,
  832. pbRest,
  833. (UINT)pHeader->iph_length,
  834. pPacketInfo->pvInInterfaceContext,
  835. pPacketInfo->pvOutInterfaceContext);
  836. ntStatus = STATUS_SUCCESS;
  837. pPacketInfo->eaResult = eaResult;
  838. //
  839. // We dont need to copy the full packet out
  840. //
  841. dwSize = sizeof(FILTER_DRIVER_TEST_PACKET);
  842. break;
  843. }
  844. #if STEELHEAD
  845. case IOCTL_GET_FILTER_INFO:
  846. {
  847. PFILTER_DRIVER_GET_FILTERS pInfo;
  848. PFILTER_INTERFACE pIf;
  849. KIRQL kIrql;
  850. TRACE0("FilterDriver: IOCTL_GET_FILTER_INFO\n");
  851. pInfo = (PFILTER_DRIVER_GET_FILTERS)pvIoBuffer;
  852. pIf = (PFILTER_INTERFACE)(pInfo->pvDriverContext);
  853. //
  854. // If we cant even report the number of filters, lets get out
  855. //
  856. if(inputBufferLength < (sizeof(FILTER_DRIVER_GET_FILTERS) - sizeof(FILTER_STATS)))
  857. {
  858. ntStatus = STATUS_BUFFER_TOO_SMALL;
  859. break;
  860. }
  861. if(outputBufferLength < (sizeof(FILTER_DRIVER_GET_FILTERS) - sizeof(FILTER_STATS)))
  862. {
  863. ntStatus = STATUS_BUFFER_TOO_SMALL;
  864. break;
  865. }
  866. //
  867. // Ok we have enough space to plug in the number of filters
  868. //
  869. AcquireReadLock(&g_filters.ifListLock,&kIrql);
  870. pInfo->interfaces.eaInAction = pIf->eaInAction;
  871. pInfo->interfaces.eaOutAction = pIf->eaOutAction;
  872. pInfo->interfaces.dwNumInFilters = pIf->dwNumInFilters;
  873. pInfo->interfaces.dwNumOutFilters = pIf->dwNumOutFilters;
  874. dwSize = SIZEOF_FILTERS(pIf);
  875. if(inputBufferLength < dwSize)
  876. {
  877. dwSize = sizeof(FILTER_DRIVER_GET_FILTERS) - sizeof(FILTER_STATS);
  878. ntStatus = STATUS_SUCCESS;
  879. ReleaseReadLock(&g_filters.ifListLock,kIrql);
  880. break;
  881. }
  882. if(outputBufferLength < dwSize)
  883. {
  884. dwSize = sizeof(FILTER_DRIVER_GET_FILTERS) - sizeof(FILTER_STATS);
  885. ntStatus = STATUS_SUCCESS;
  886. ReleaseReadLock(&g_filters.ifListLock,kIrql);
  887. break;
  888. }
  889. ntStatus = GetFilters(pIf,
  890. FALSE,
  891. &(pInfo->interfaces));
  892. pInfo->dwDefaultHitsIn = g_dwNumHitsDefaultIn;
  893. pInfo->dwDefaultHitsOut = g_dwNumHitsDefaultOut;
  894. ReleaseReadLock(&g_filters.ifListLock,kIrql);
  895. break;
  896. }
  897. #endif
  898. case IOCTL_GET_FILTER_TIMES:
  899. {
  900. PFILTER_DRIVER_GET_TIMES pInfo;
  901. PFILTER_INTERFACE pIf;
  902. KIRQL kIrql;
  903. TRACE0("FilterDriver: IOCTL_GET_FILTER_TIMES\n");
  904. dwSize = sizeof(FILTER_DRIVER_GET_TIMES);
  905. if(outputBufferLength < sizeof(FILTER_DRIVER_GET_TIMES))
  906. {
  907. ntStatus = STATUS_BUFFER_TOO_SMALL;
  908. break;
  909. }
  910. pInfo = (PFILTER_DRIVER_GET_TIMES)pvIoBuffer;
  911. #ifdef DRIVER_PERF
  912. pInfo->dwFragments = g_dwFragments;
  913. pInfo->dwCache1 = g_dwCache1;
  914. pInfo->dwCache2 = g_dwCache2;
  915. pInfo->dwNumPackets = g_dwNumPackets;
  916. pInfo->dwWalk1 = g_dwWalk1;
  917. pInfo->dwWalk2 = g_dwWalk2;
  918. pInfo->dwForw = g_dwForw;
  919. pInfo->dwWalkCache = g_dwWalkCache;
  920. pInfo->liTotalTime.HighPart = g_liTotalTime.HighPart;
  921. pInfo->liTotalTime.LowPart = g_liTotalTime.LowPart;
  922. #else
  923. pInfo->dwFragments = 0;
  924. pInfo->dwCache1 = 0;
  925. pInfo->dwCache2 = 0;
  926. pInfo->dwNumPackets = 0;
  927. pInfo->dwWalk1 = 0;
  928. pInfo->dwWalk2 = 0;
  929. pInfo->dwForw = 0;
  930. pInfo->dwWalkCache = 0;
  931. pInfo->liTotalTime.HighPart = 0;
  932. pInfo->liTotalTime.LowPart = 0;
  933. #endif
  934. ntStatus = STATUS_SUCCESS;
  935. break;
  936. }
  937. default:
  938. {
  939. DbgPrint ("Filter Driver: unknown IOCTL\n");
  940. ntStatus = STATUS_INVALID_PARAMETER;
  941. break;
  942. }
  943. }
  944. break ;
  945. }
  946. default:
  947. {
  948. DbgPrint ("Filter Driver: unknown IRP_MJ_XXX\n");
  949. ntStatus = STATUS_INVALID_PARAMETER;
  950. break;
  951. }
  952. }
  953. if(ntStatus != STATUS_PENDING)
  954. {
  955. Irp->IoStatus.Status = ntStatus;
  956. Irp->IoStatus.Information = dwSize;
  957. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  958. }
  959. return(ntStatus);
  960. }
  961. VOID
  962. FilterDriverUnload(
  963. IN PDRIVER_OBJECT DriverObject
  964. )
  965. /*++
  966. Routine Description
  967. Called when the driver is unloaded. This shuts down the filtering (if it hasnt been shut
  968. down already) and removes the DOS name
  969. Arguments
  970. DriverObject
  971. Return Value
  972. None
  973. --*/
  974. {
  975. TRACE0("Filter Driver: unloading\n");
  976. CloseFilterDriver();
  977. TearDownExternalNaming();
  978. IoDeleteDevice(DriverObject->DeviceObject);
  979. }
  980. VOID
  981. SetupExternalNaming (
  982. IN PUNICODE_STRING ntname
  983. )
  984. /*++
  985. Routine Description
  986. Inserts the input name as the DOS name
  987. Arguments
  988. ntname - Name of driver
  989. Return Value
  990. None
  991. --*/
  992. {
  993. UNICODE_STRING ObjectDirectory;
  994. UNICODE_STRING SymbolicLinkName;
  995. UNICODE_STRING fullLinkName;
  996. BYTE buffer[100] ;
  997. //
  998. // Form the full symbolic link name we wish to create.
  999. //
  1000. RtlInitUnicodeString (&fullLinkName, NULL);
  1001. RtlInitUnicodeString (&ObjectDirectory, DEFAULT_DIRECTORY);
  1002. RtlInitUnicodeString(&SymbolicLinkName, DEFAULT_FLTRDRVR_NAME);
  1003. fullLinkName.MaximumLength = (sizeof(L"\\")*2) + ObjectDirectory.Length
  1004. + SymbolicLinkName.Length + sizeof(WCHAR);
  1005. fullLinkName.Buffer = (WCHAR *)buffer ;
  1006. RtlZeroMemory (fullLinkName.Buffer, fullLinkName.MaximumLength);
  1007. RtlAppendUnicodeToString (&fullLinkName, L"\\");
  1008. RtlAppendUnicodeStringToString (&fullLinkName, &ObjectDirectory);
  1009. RtlAppendUnicodeToString (&fullLinkName, L"\\");
  1010. RtlAppendUnicodeStringToString (&fullLinkName, &SymbolicLinkName);
  1011. if (!NT_SUCCESS(IoCreateSymbolicLink (&fullLinkName, ntname)))
  1012. {
  1013. DbgPrint ("Filter Driver: ERROR win32 device name could not be created \n") ;
  1014. }
  1015. }
  1016. VOID
  1017. TearDownExternalNaming()
  1018. /*++
  1019. Routine Description
  1020. Removes the DOS name from the registry
  1021. Called when the driver is unloaded
  1022. Arguments
  1023. None
  1024. Return Value
  1025. None
  1026. --*/
  1027. {
  1028. UNICODE_STRING ObjectDirectory;
  1029. UNICODE_STRING SymbolicLinkName;
  1030. UNICODE_STRING fullLinkName;
  1031. BYTE buffer[100] ;
  1032. RtlInitUnicodeString (&fullLinkName, NULL);
  1033. RtlInitUnicodeString (&ObjectDirectory, DEFAULT_DIRECTORY);
  1034. RtlInitUnicodeString(&SymbolicLinkName, DEFAULT_FLTRDRVR_NAME);
  1035. fullLinkName.MaximumLength = (sizeof(L"\\")*2) + ObjectDirectory.Length
  1036. + SymbolicLinkName.Length + sizeof(WCHAR);
  1037. fullLinkName.Buffer = (WCHAR *)buffer ;
  1038. RtlZeroMemory (fullLinkName.Buffer, fullLinkName.MaximumLength);
  1039. RtlAppendUnicodeToString (&fullLinkName, L"\\");
  1040. RtlAppendUnicodeStringToString (&fullLinkName, &ObjectDirectory);
  1041. RtlAppendUnicodeToString (&fullLinkName, L"\\");
  1042. RtlAppendUnicodeStringToString (&fullLinkName, &SymbolicLinkName);
  1043. if (!NT_SUCCESS(IoDeleteSymbolicLink (&fullLinkName)))
  1044. {
  1045. DbgPrint ("Filter Driver: ERROR win32 device name could not be deleted\n") ;
  1046. }
  1047. }
  1048. BOOL
  1049. InitFilterDriver()
  1050. /*++
  1051. Routine Description
  1052. Starts the driver. Allocates memory for the cache and cache entries. Clears the entries
  1053. Sends an IOCTL to the Forwarder to set up its entry point (which starts the filtering
  1054. process in the forwarder)
  1055. Arguments
  1056. None
  1057. Return Value
  1058. TRUE if successful
  1059. --*/
  1060. {
  1061. NTSTATUS status;
  1062. BOOL bRet;
  1063. SYSTEM_BASIC_INFORMATION PerfInfo;
  1064. status = ZwQuerySystemInformation(
  1065. SystemBasicInformation,
  1066. &PerfInfo,
  1067. sizeof(PerfInfo),
  1068. NULL
  1069. );
  1070. //
  1071. // adjust cache and hash sizes based on the memory
  1072. //
  1073. if(PerfInfo.NumberOfPhysicalPages <= 8000)
  1074. {
  1075. //
  1076. // 32 MB or smaller. A very chincy server
  1077. //
  1078. g_dwCacheSize = 257;
  1079. g_dwHashLists = 127;
  1080. }
  1081. else if(PerfInfo.NumberOfPhysicalPages < 16000)
  1082. {
  1083. //
  1084. // 32-64 MB. Better.
  1085. //
  1086. g_dwCacheSize = 311;
  1087. g_dwHashLists = 311;
  1088. }
  1089. else if(PerfInfo.NumberOfPhysicalPages < 32000)
  1090. {
  1091. //
  1092. // 64 - 128 MB.
  1093. //
  1094. g_dwCacheSize = 511;
  1095. g_dwHashLists = 511;
  1096. }
  1097. else
  1098. {
  1099. //
  1100. // big machine
  1101. //
  1102. g_dwCacheSize = 511;
  1103. g_dwHashLists = 1023;
  1104. }
  1105. InitLogs();
  1106. __try
  1107. {
  1108. bRet = TRUE;
  1109. if(!AllocateCacheStructures())
  1110. {
  1111. DbgPrint("Couldnt allocate cache structures\n");
  1112. bRet = FALSE;
  1113. __leave;
  1114. }
  1115. //
  1116. // Clean the cache
  1117. //
  1118. ClearCache();
  1119. //
  1120. // Now send and Irp to IP Forwarder and give him our entry point
  1121. // Do it twice, once to make sure it is cleared and to
  1122. // erase any previous filter contexts and once to do what
  1123. // we want it to do.
  1124. //
  1125. status = SetForwarderEntryPoint(NULL);
  1126. status = SetForwarderEntryPoint(MatchFilter);
  1127. if(status isnot STATUS_SUCCESS)
  1128. {
  1129. DbgPrint("IOCTL to IP Forwarder failed - status \n",status);
  1130. bRet = FALSE;
  1131. __leave;
  1132. }
  1133. }
  1134. __finally
  1135. {
  1136. if(!bRet)
  1137. {
  1138. FreeExistingCache();
  1139. }
  1140. else
  1141. {
  1142. ExInitializeNPagedLookasideList(
  1143. &filter_slist,
  1144. ExAllocatePoolWithTag,
  1145. ExFreePool,
  1146. 0,
  1147. sizeof(FILTER),
  1148. (ULONG)'2liF',
  1149. 100);
  1150. ExInitializePagedLookasideList(
  1151. &paged_slist,
  1152. ExAllocatePoolWithTag,
  1153. ExFreePool,
  1154. 0,
  1155. sizeof(PAGED_FILTER),
  1156. (ULONG)'2liF',
  1157. 100);
  1158. }
  1159. return bRet;
  1160. }
  1161. }
  1162. BOOL
  1163. CloseFilterDriver()
  1164. /*++
  1165. Routine Description
  1166. Shuts down the driver.
  1167. Arguments
  1168. Return Value
  1169. --*/
  1170. {
  1171. NTSTATUS status;
  1172. KIRQL kIrql;
  1173. PLIST_ENTRY pleHead;
  1174. BOOL bStopForw = TRUE;
  1175. PFREEFILTER pFree, pFree1;
  1176. PPFFCB Fcb;
  1177. KIRQL kirql;
  1178. //
  1179. // The first thing to do is send an IOCTL to forwarder to tell him to stop sending
  1180. // us anymore packets.
  1181. //
  1182. status = SetForwarderEntryPoint(NULL);
  1183. if(!NT_SUCCESS(status))
  1184. {
  1185. //
  1186. // This means we could not tell IP Forwarder
  1187. // to stop filtering packets so we cant go away.
  1188. //
  1189. DbgPrint("Couldnt IOCTL IP Forwarder to stop filtering - cant unload\n");
  1190. bStopForw = FALSE;
  1191. }
  1192. //
  1193. // remove the FCBS
  1194. //
  1195. while(TRUE)
  1196. {
  1197. NTSTATUS ntStatus;
  1198. FILE_OBJECT fo;
  1199. KIRQL kirql;
  1200. BOOL fDone = TRUE;
  1201. KeAcquireSpinLock(&g_FcbSpin, &kirql);
  1202. for(pleHead = g_leFcbs.Flink;
  1203. pleHead != &g_leFcbs;
  1204. pleHead = pleHead->Flink)
  1205. {
  1206. Fcb = CONTAINING_RECORD(pleHead, PFFCB, leList);
  1207. //
  1208. // This can happen if some other thread is closing the FCB.
  1209. //
  1210. if(Fcb->dwFlags & PF_FCB_CLOSED)
  1211. {
  1212. continue;
  1213. }
  1214. KeReleaseSpinLock(&g_FcbSpin, kirql);
  1215. fDone = FALSE;
  1216. fo.FsContext2 = (PVOID)Fcb;
  1217. ntStatus = LockFcb(&fo);
  1218. if(!NT_SUCCESS(ntStatus))
  1219. {
  1220. break;
  1221. }
  1222. FcbLockDown(Fcb);
  1223. UnLockFcb(&fo);
  1224. break;
  1225. }
  1226. if(fDone)
  1227. {
  1228. KeReleaseSpinLock(&g_FcbSpin, kirql);
  1229. break;
  1230. }
  1231. }
  1232. ExDeleteResource ( &FilterListResourceLock );
  1233. ExDeleteResource ( &FilterAddressLock );
  1234. AcquireWriteLock(&(g_filters.ifListLock),&kIrql);
  1235. while(!IsListEmpty(&g_filters.leIfListHead))
  1236. {
  1237. PFILTER_INTERFACE pIf;
  1238. pleHead = g_filters.leIfListHead.Flink;
  1239. pIf = CONTAINING_RECORD(pleHead,FILTER_INTERFACE,leIfLink);
  1240. DeleteFilters(pIf,
  1241. IN_FILTER_SET);
  1242. DeleteFilters(pIf,
  1243. OUT_FILTER_SET);
  1244. //
  1245. // Set the number of filters to 0 and the default action to forward so
  1246. // that if we havent been able to stop the forwarder from calling us,
  1247. // atleast no packets get filtered
  1248. //
  1249. pIf->dwNumInFilters = 0;
  1250. pIf->dwNumOutFilters = 0;
  1251. pIf->eaInAction = FORWARD;
  1252. pIf->eaOutAction = FORWARD;
  1253. if(bStopForw)
  1254. {
  1255. //
  1256. // We could stop the forwarder so lets blow away the interface
  1257. //
  1258. RemoveHeadList(&g_filters.leIfListHead);
  1259. ExFreePool(pIf);
  1260. }
  1261. }
  1262. ClearCache();
  1263. if(bStopForw)
  1264. {
  1265. //
  1266. // If we could stop the forwarder, blow away the cache
  1267. //
  1268. FreeExistingCache();
  1269. }
  1270. ReleaseWriteLock(&g_filters.ifListLock,kIrql);
  1271. if(g_bDriverRunning)
  1272. {
  1273. ExDeleteNPagedLookasideList( &filter_slist );
  1274. ExDeletePagedLookasideList( &paged_slist );
  1275. }
  1276. if(AddrTable)
  1277. {
  1278. ExFreePool(AddrTable);
  1279. AddrTable = 0;
  1280. }
  1281. if(AddrHashTable)
  1282. {
  1283. ExFreePool(AddrHashTable);
  1284. AddrHashTable = 0;
  1285. }
  1286. if(AddrSubnetHashTable)
  1287. {
  1288. ExFreePool(AddrSubnetHashTable);
  1289. AddrSubnetHashTable = 0;
  1290. }
  1291. if(bStopForw)
  1292. {
  1293. return STATUS_SUCCESS;
  1294. }
  1295. else
  1296. {
  1297. return STATUS_UNSUCCESSFUL;
  1298. }
  1299. }
  1300. NTSTATUS
  1301. SetForwarderEntryPoint(
  1302. IN IPPacketFilterPtr pfnMatch
  1303. )
  1304. /*++
  1305. Routine Description
  1306. Sets the entry point to IP Forwarder. Used to start and stop the forwarding code in
  1307. the forwarder
  1308. Arguments
  1309. pfnMatch Pointer to the function that implements the filter matching code
  1310. NULL will stop forwarding, while any other value will cause the forwarder to
  1311. invoke the function pointed to. Thus if on stopping, the IOCTL to the
  1312. forwarder doesnt succeed, and the filter driver goes away, the system will
  1313. blue screen
  1314. Return Value
  1315. NTSTATUS
  1316. --*/
  1317. {
  1318. NTSTATUS status;
  1319. IP_SET_FILTER_HOOK_INFO functionInfo;
  1320. functionInfo.FilterPtr = pfnMatch;
  1321. status = DoIpIoctl(
  1322. DD_IP_DEVICE_NAME,
  1323. IOCTL_IP_SET_FILTER_POINTER,
  1324. (PVOID)&functionInfo,
  1325. sizeof(functionInfo),
  1326. NULL,
  1327. 0,
  1328. NULL);
  1329. return(status);
  1330. }
  1331. NTSTATUS
  1332. DoIpIoctl(
  1333. IN PWCHAR DriverName,
  1334. IN DWORD Ioctl,
  1335. IN PVOID pvInArg,
  1336. IN DWORD dwInSize,
  1337. IN PVOID pvOutArg,
  1338. IN DWORD dwOutSize,
  1339. OUT PDWORD pdwInfo OPTIONAL)
  1340. /*++
  1341. Routine Description:
  1342. Do an IOCTL to the stack. Used for a varity of purposes
  1343. --*/
  1344. {
  1345. NTSTATUS status;
  1346. UNICODE_STRING nameString;
  1347. OBJECT_ATTRIBUTES Atts;
  1348. IO_STATUS_BLOCK ioStatusBlock;
  1349. HANDLE Handle;
  1350. PAGED_CODE();
  1351. RtlInitUnicodeString(&nameString, DriverName);
  1352. InitializeObjectAttributes(&Atts,
  1353. &nameString,
  1354. OBJ_CASE_INSENSITIVE,
  1355. NULL,
  1356. NULL);
  1357. status = ZwCreateFile(&Handle,
  1358. SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
  1359. &Atts,
  1360. &ioStatusBlock,
  1361. NULL,
  1362. FILE_ATTRIBUTE_NORMAL,
  1363. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1364. FILE_OPEN_IF,
  1365. 0,
  1366. NULL,
  1367. 0);
  1368. if (!NT_SUCCESS(status))
  1369. {
  1370. DbgPrint("Couldnt open IP Forwarder - status %d\n",status);
  1371. return STATUS_UNSUCCESSFUL;
  1372. }
  1373. //
  1374. // Submit the request to the forwarder
  1375. //
  1376. status = ZwDeviceIoControlFile(
  1377. Handle,
  1378. NULL,
  1379. NULL,
  1380. NULL,
  1381. &ioStatusBlock,
  1382. Ioctl,
  1383. pvInArg,
  1384. dwInSize,
  1385. pvOutArg,
  1386. dwOutSize);
  1387. if(!NT_SUCCESS(status))
  1388. {
  1389. DbgPrint("IOCTL request failed - status %x\n",status);
  1390. }
  1391. else
  1392. {
  1393. if(pdwInfo)
  1394. {
  1395. *pdwInfo = ioStatusBlock.Information;
  1396. }
  1397. }
  1398. //
  1399. // Close the device.
  1400. //
  1401. ZwClose(Handle);
  1402. return status;
  1403. }
  1404. BOOL
  1405. AllocateCacheStructures()
  1406. /*++
  1407. Routine Description
  1408. Allocates the necessary memory for cache (which is an array of pointers to
  1409. cache entries)
  1410. Allocates necessary number of cache entries (but doesnt initialize them)
  1411. Allocates a small number of entries and puts them on the free list (doesnt
  1412. initialize these either)
  1413. Arguments
  1414. None
  1415. Return Value
  1416. True if the function completely succeeds, else FALSE. If FALSE, it is upto
  1417. the CALLER to do a rollback and clear any allocated memory
  1418. --*/
  1419. {
  1420. DWORD i;
  1421. TRACE0("Allocating cache\n");
  1422. g_filters.ppInCache = ExAllocatePoolWithTag(NonPagedPool,
  1423. g_dwCacheSize * sizeof(PFILTER_INCACHE),
  1424. 'hCnI');
  1425. if(g_filters.ppInCache is NULL)
  1426. {
  1427. DbgPrint("Couldnt allocate memory for Input Cache\n");
  1428. return FALSE;
  1429. }
  1430. g_filters.ppOutCache = ExAllocatePoolWithTag(NonPagedPool,
  1431. g_dwCacheSize * sizeof(PFILTER_OUTCACHE),
  1432. 'CtuO');
  1433. if(g_filters.ppOutCache is NULL)
  1434. {
  1435. DbgPrint("Couldnt allocate memory for Output Cache\n");
  1436. return FALSE;
  1437. }
  1438. for(i = 0; i < g_dwCacheSize; i++)
  1439. {
  1440. g_filters.ppInCache[i] = NULL;
  1441. g_filters.ppOutCache[i] = NULL;
  1442. }
  1443. for(i = 0; i < g_dwCacheSize; i++)
  1444. {
  1445. PFILTER_INCACHE pTemp1;
  1446. PFILTER_OUTCACHE pTemp2;
  1447. pTemp1 = ExAllocatePoolWithTag(NonPagedPool,
  1448. sizeof(FILTER_INCACHE),
  1449. 'NI');
  1450. if(pTemp1 is NULL)
  1451. {
  1452. return FALSE;
  1453. }
  1454. g_filters.ppInCache[i] = pTemp1;
  1455. pTemp2 = ExAllocatePoolWithTag(NonPagedPool,
  1456. sizeof(FILTER_OUTCACHE),
  1457. 'TUO');
  1458. if(pTemp2 is NULL)
  1459. {
  1460. return FALSE;
  1461. }
  1462. g_filters.ppOutCache[i] = pTemp2;
  1463. }
  1464. TRACE0("Allocated cache structures\n");
  1465. TRACE0("Creating in and out free list...");
  1466. for(i = 0; i < FREE_LIST_SIZE; i++)
  1467. {
  1468. PFILTER_INCACHE pTemp1;
  1469. PFILTER_OUTCACHE pTemp2;
  1470. pTemp1 = ExAllocatePoolWithTag(NonPagedPool,
  1471. sizeof(FILTER_INCACHE),
  1472. 'FNI');
  1473. if(pTemp1 is NULL)
  1474. {
  1475. return FALSE;
  1476. }
  1477. InitializeListHead(&pTemp1->leFreeLink);
  1478. InsertHeadList(&g_freeInFilters,&pTemp1->leFreeLink);
  1479. pTemp2 = ExAllocatePoolWithTag(NonPagedPool,
  1480. sizeof(FILTER_OUTCACHE),
  1481. 'FTUO');
  1482. if(pTemp2 is NULL)
  1483. {
  1484. return FALSE;
  1485. }
  1486. InitializeListHead(&pTemp2->leFreeLink);
  1487. InsertHeadList(&g_freeOutFilters,&pTemp2->leFreeLink);
  1488. }
  1489. TRACE0("Done\n");
  1490. return TRUE;
  1491. }
  1492. VOID
  1493. FreeExistingCache()
  1494. /*++
  1495. Routine Description
  1496. Frees all the cache entries, free entries and cache pointer array
  1497. Arguments
  1498. None
  1499. Return Value
  1500. None
  1501. --*/
  1502. {
  1503. DWORD i;
  1504. TRACE0("Freeing existing in cache...");
  1505. if(g_filters.ppInCache isnot NULL)
  1506. {
  1507. for(i = 0; i < g_dwCacheSize; i ++)
  1508. {
  1509. if(g_filters.ppInCache[i] isnot NULL)
  1510. {
  1511. ExFreePool(g_filters.ppInCache[i]);
  1512. }
  1513. }
  1514. ExFreePool(g_filters.ppInCache);
  1515. g_filters.ppInCache = NULL;
  1516. }
  1517. TRACE0("Done\n");
  1518. TRACE0("Freeing existing out cache...");
  1519. if(g_filters.ppOutCache isnot NULL)
  1520. {
  1521. for(i = 0; i < g_dwCacheSize; i ++)
  1522. {
  1523. if(g_filters.ppOutCache[i] isnot NULL)
  1524. {
  1525. ExFreePool(g_filters.ppOutCache[i]);
  1526. }
  1527. }
  1528. ExFreePool(g_filters.ppOutCache);
  1529. g_filters.ppOutCache = NULL;
  1530. }
  1531. TRACE0("Done\n");
  1532. TRACE0("Freeing existing in free list entries...");
  1533. while(!IsListEmpty(&g_freeInFilters))
  1534. {
  1535. PFILTER_INCACHE pIn;
  1536. PLIST_ENTRY pleHead;
  1537. pleHead = RemoveHeadList(&g_freeInFilters);
  1538. pIn = CONTAINING_RECORD(pleHead,FILTER_INCACHE,leFreeLink);
  1539. ExFreePool(pIn);
  1540. }
  1541. TRACE0("Done\n");
  1542. TRACE0("Freeing existing out free list entries...");
  1543. while(!IsListEmpty(&g_freeOutFilters))
  1544. {
  1545. PFILTER_OUTCACHE pOut;
  1546. PLIST_ENTRY pleHead;
  1547. pleHead = RemoveHeadList(&g_freeOutFilters);
  1548. pOut = CONTAINING_RECORD(pleHead,FILTER_OUTCACHE,leFreeLink);
  1549. ExFreePool(pOut);
  1550. }
  1551. TRACE0("Done\n");
  1552. }
  1553. NTSTATUS
  1554. OpenNewHandle(PFILE_OBJECT FileObject)
  1555. /*++
  1556. Routine Description:
  1557. Open a new handle to the driver. Allocate FCB from the paged pool
  1558. and initialize it. If no memory available, fail. If success
  1559. store the FCB pointer into the file object.
  1560. --*/
  1561. {
  1562. PPFFCB Fcb;
  1563. KIRQL kirql;
  1564. //
  1565. // Allocate an FCB for this handle.
  1566. //
  1567. Fcb = ExAllocatePoolWithTag(NonPagedPool,
  1568. sizeof(*Fcb),
  1569. 'pfFC');
  1570. if(Fcb)
  1571. {
  1572. FileObject->FsContext2 = (PVOID)Fcb;
  1573. Fcb->dwFlags = 0;
  1574. Fcb->UseCount = 1;
  1575. InitializeListHead(&Fcb->leInterfaces);
  1576. InitializeListHead(&Fcb->leLogs);
  1577. ExInitializeResource ( &Fcb->Resource );
  1578. ExAcquireSpinLock(&g_FcbSpin, &kirql);
  1579. InsertTailList(&g_leFcbs, &Fcb->leList);
  1580. ExReleaseSpinLock(&g_FcbSpin, kirql);
  1581. return(STATUS_SUCCESS);
  1582. }
  1583. return(STATUS_NO_MEMORY);
  1584. }
  1585. PPAGED_FILTER_INTERFACE
  1586. FindInterfaceOnHandle(PFILE_OBJECT FileObject,
  1587. DWORD dwValue)
  1588. /*++
  1589. Routine Description:
  1590. Find the paged interface for the call. If none found
  1591. return a NULL. Uses the caller-supplied DriverContext to
  1592. search the contexts on this handle. In general, there should
  1593. not be many such handles.
  1594. --*/
  1595. {
  1596. PPFFCB Fcb = FileObject->FsContext2;
  1597. PPAGED_FILTER_INTERFACE pPage;
  1598. PAGED_CODE();
  1599. for(pPage = (PPAGED_FILTER_INTERFACE)Fcb->leInterfaces.Flink;
  1600. (PLIST_ENTRY)pPage != &Fcb->leInterfaces;
  1601. pPage = (PPAGED_FILTER_INTERFACE)pPage->leIfLink.Flink)
  1602. {
  1603. if(pPage->pvDriverContext == pvValue)
  1604. {
  1605. return(pPage);
  1606. }
  1607. }
  1608. return(NULL);
  1609. }
  1610. NTSTATUS
  1611. CloseFcb(PPFFCB Fcb, PFILE_OBJECT FileObject)
  1612. /*++
  1613. Routine Description:
  1614. Called when an FCB has no more references. The caller must
  1615. have removed the FCB from the master list. It is immaterial whether
  1616. the CB resource is locked.
  1617. --*/
  1618. {
  1619. PPAGED_FILTER_INTERFACE pPage;
  1620. PFREEFILTER pList, pList1;
  1621. NTSTATUS ntStatus;
  1622. //
  1623. // First clean up the logs
  1624. //
  1625. while(!IsListEmpty(&Fcb->leLogs))
  1626. {
  1627. PFDELETELOG DelLog;
  1628. DelLog.pfLogId = (PFLOGGER)Fcb->leLogs.Flink;
  1629. (VOID)PfDeleteLog(&DelLog, Fcb);
  1630. }
  1631. //
  1632. // Next, clean up the interfaces
  1633. //
  1634. while(!IsListEmpty(&Fcb->leInterfaces))
  1635. {
  1636. pPage = (PPAGED_FILTER_INTERFACE)RemoveHeadList(&Fcb->leInterfaces);
  1637. (VOID)DeletePagedInterface(Fcb, pPage);
  1638. }
  1639. #if 0
  1640. //
  1641. // Can't do this because can't get the filter context from the stack.
  1642. //
  1643. if(Fcb->dwFlags & PF_FCB_OLD)
  1644. {
  1645. DeleteOldInterfaces(Fcb);
  1646. }
  1647. #endif
  1648. //
  1649. // Free the Fcb
  1650. //
  1651. ExDeleteResource ( &Fcb->Resource );
  1652. ExFreePool(Fcb);
  1653. if(FileObject)
  1654. {
  1655. FileObject->FsContext2 = NULL;
  1656. }
  1657. return(STATUS_SUCCESS);
  1658. }
  1659. DWORD
  1660. GetIpStackIndex(IPAddr Addr, BOOL fNew)
  1661. /*++
  1662. Routine Description:
  1663. Get the stack index for the corresponding address and mask
  1664. --*/
  1665. {
  1666. DWORD dwResult;
  1667. DWORD dwInBufLen;
  1668. DWORD dwOutBufLen;
  1669. TCP_REQUEST_QUERY_INFORMATION_EX trqiInBuf;
  1670. TDIObjectID *ID;
  1671. BYTE *Context;
  1672. NTSTATUS Status;
  1673. IPSNMPInfo IPSnmpInfo;
  1674. IPAddrEntry *AddrTable1;
  1675. DWORD dwSpace, dwIpIndex;
  1676. DWORD dwFinalAddrSize;
  1677. DWORD dwFinalSize, dwX;
  1678. PADDRESSARRAY pa;
  1679. KIRQL kirql;
  1680. ExAcquireResourceShared( &FilterAddressLock, TRUE);
  1681. if(!AddrTable || fNew)
  1682. {
  1683. ExReleaseResource(&FilterAddressLock );
  1684. ExAcquireResourceExclusive( &FilterAddressLock, TRUE);
  1685. if(fNew && AddrTable)
  1686. {
  1687. //
  1688. // acquire the spin lock to synchronize with Match
  1689. // code running at DPC so we can "lock out"
  1690. // the table while we do the rest of this. Note
  1691. // we can't hold a spin lock while building the table
  1692. // because the calls into the IP stack hit pageable
  1693. // code
  1694. //
  1695. AcquireWriteLock(&g_IpTableSpin, &kirql);
  1696. g_dwMakingNewTable = TRUE;
  1697. ReleaseWriteLock(&g_IpTableSpin, kirql);
  1698. ExFreePool( AddrTable );
  1699. AddrTable = 0;
  1700. }
  1701. }
  1702. if(!AddrTable)
  1703. {
  1704. dwInBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
  1705. dwOutBufLen = sizeof(IPSNMPInfo);
  1706. ID = &(trqiInBuf.ID);
  1707. ID->toi_entity.tei_entity = CL_NL_ENTITY;
  1708. ID->toi_entity.tei_instance = 0;
  1709. ID->toi_class = INFO_CLASS_PROTOCOL;
  1710. ID->toi_type = INFO_TYPE_PROVIDER;
  1711. ID->toi_id = IP_MIB_STATS_ID;
  1712. Context = &(trqiInBuf.Context[0]);
  1713. RtlZeroMemory(Context, CONTEXT_SIZE);
  1714. Status = DoIpIoctl(
  1715. DD_TCP_DEVICE_NAME,
  1716. IOCTL_TCP_QUERY_INFORMATION_EX,
  1717. (PVOID)&trqiInBuf,
  1718. sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
  1719. (PVOID)&IPSnmpInfo,
  1720. dwOutBufLen,
  1721. NULL);
  1722. if(NT_SUCCESS(Status))
  1723. {
  1724. //
  1725. // allocate some memory to fetch the address table.
  1726. //
  1727. dwSpace = IPSnmpInfo.ipsi_numaddr + 10;
  1728. dwOutBufLen = dwSpace * sizeof(IPAddrEntry);
  1729. if(!AddrHashTable)
  1730. {
  1731. //
  1732. // the hash table size was not specified in the
  1733. // registry. Compute it based on the number of
  1734. // addresses. Try to keep the hash table less than
  1735. // half full.
  1736. //
  1737. if(!AddrModulus)
  1738. {
  1739. if(IPSnmpInfo.ipsi_numaddr < ADDRHASHLOWLEVEL)
  1740. {
  1741. AddrModulus = ADDRHASHLOW;
  1742. }
  1743. else if(IPSnmpInfo.ipsi_numaddr < ADDRHASHMEDLEVEL)
  1744. {
  1745. AddrModulus = ADDRHASHMED;
  1746. }
  1747. else
  1748. {
  1749. AddrModulus = ADDRHASHHIGH;
  1750. }
  1751. }
  1752. AddrHashTable = (PADDRESSARRAY *)ExAllocatePoolWithTag(
  1753. NonPagedPool,
  1754. AddrModulus *
  1755. sizeof(PADDRESSARRAY),
  1756. 'pfAh');
  1757. if(!AddrHashTable)
  1758. {
  1759. DbgPrint("Could not allocate AddrHashTable");
  1760. g_dwMakingNewTable = FALSE;
  1761. ExReleaseResource(&FilterAddressLock );
  1762. return(UNKNOWN_IP_INDEX);
  1763. }
  1764. }
  1765. if(!AddrSubnetHashTable)
  1766. {
  1767. AddrSubnetHashTable = (PADDRESSARRAY *)ExAllocatePoolWithTag(
  1768. NonPagedPool,
  1769. AddrModulus *
  1770. sizeof(PADDRESSARRAY),
  1771. 'pfAh');
  1772. if(!AddrSubnetHashTable)
  1773. {
  1774. DbgPrint("Could not allocate AddrSubnetHashTable");
  1775. g_dwMakingNewTable = FALSE;
  1776. ExReleaseResource(&FilterAddressLock );
  1777. return(UNKNOWN_IP_INDEX);
  1778. }
  1779. }
  1780. RtlZeroMemory(AddrHashTable, AddrModulus * sizeof(PADDRESSARRAY));
  1781. RtlZeroMemory(AddrSubnetHashTable,
  1782. AddrModulus * sizeof(PADDRESSARRAY));
  1783. AddrTable = (IPAddrEntry *)ExAllocatePoolWithTag(
  1784. NonPagedPool,
  1785. dwOutBufLen,
  1786. 'pfAt');
  1787. if(!AddrTable)
  1788. {
  1789. DbgPrint("Could not allocate AddrTable of size %d\n",
  1790. dwSpace);
  1791. g_dwMakingNewTable = FALSE;
  1792. ExReleaseResource(&FilterAddressLock );
  1793. return(UNKNOWN_IP_INDEX);
  1794. }
  1795. }
  1796. ID->toi_type = INFO_TYPE_PROVIDER;
  1797. ID->toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
  1798. RtlZeroMemory( Context, CONTEXT_SIZE );
  1799. Status = DoIpIoctl(
  1800. DD_TCP_DEVICE_NAME,
  1801. IOCTL_TCP_QUERY_INFORMATION_EX,
  1802. (PVOID)&trqiInBuf,
  1803. dwInBufLen,
  1804. (PVOID)AddrTable,
  1805. dwOutBufLen,
  1806. &dwFinalAddrSize);
  1807. if(!NT_SUCCESS(Status))
  1808. {
  1809. DbgPrint("Reading IP addr table failed %x\n", Status);
  1810. ExFreePool(AddrTable);
  1811. AddrTable = 0;
  1812. g_dwMakingNewTable = FALSE;
  1813. ExReleaseResource(&FilterAddressLock );
  1814. return(UNKNOWN_IP_INDEX);
  1815. }
  1816. //
  1817. // Now to get sleazy. Convert each IPAddrEntry into an ADDRESSARRAY
  1818. // entry and hash it into the AddrHashTable. Note this depends
  1819. // on the structures having common definitions and on
  1820. // IPAddrEntry to be at least as large as ADDRESSARRAY. So be
  1821. // careful.
  1822. //
  1823. dwFinalSize = dwFinalAddrSize / sizeof(IPAddrEntry);
  1824. for(AddrTable1 = AddrTable;
  1825. dwFinalSize;
  1826. dwFinalSize--, AddrTable1++)
  1827. {
  1828. dwX = ADDRHASHX(AddrTable1->iae_addr);
  1829. pa = (PADDRESSARRAY)AddrTable1;
  1830. pa->ulSubnetBcastAddress = AddrTable1->iae_addr |
  1831. ~AddrTable1->iae_mask;
  1832. //
  1833. // Now hash it into the hash table
  1834. //
  1835. pa->pNext = AddrHashTable[dwX];
  1836. AddrHashTable[dwX] = pa;
  1837. //
  1838. // and do a hash on the subnet address as well
  1839. //
  1840. dwX = ADDRHASHX(pa->ulSubnetBcastAddress);
  1841. pa->pNextSubnet = AddrSubnetHashTable[dwX];
  1842. AddrSubnetHashTable[dwX] = pa;
  1843. }
  1844. //
  1845. // allow the DPC match code to use the table. Note
  1846. // this does not require interlocking since storing
  1847. // memory is atomic.
  1848. //
  1849. g_dwMakingNewTable = FALSE;
  1850. }
  1851. //
  1852. // search the table for the address.
  1853. //
  1854. dwIpIndex = LocalIpLook(Addr);
  1855. ExReleaseResource(&FilterAddressLock );
  1856. return(dwIpIndex);
  1857. }
  1858. BOOL
  1859. MatchLocalLook(DWORD Addr, DWORD dwIndex)
  1860. /*++
  1861. Routine Description:
  1862. Called from the Match code, probably at DPC level, to
  1863. check an address. If the address table is being rebuilt
  1864. just return success. See inner comment for more on this
  1865. --*/
  1866. {
  1867. BOOL fRet;
  1868. KIRQL kirql;
  1869. if(!BMAddress(Addr))
  1870. {
  1871. //
  1872. // Look it up. Note that if the table is being rebuilt,
  1873. // this succeeds. This is a security hole but it is very
  1874. // small and nearly impossible to exploit effectively and
  1875. // the alternative, denying this, is even worse.
  1876. // ArnoldM 19-Sept-1997.
  1877. //
  1878. AcquireReadLock(&g_IpTableSpin, &kirql);
  1879. if(AddrTable && !g_dwMakingNewTable)
  1880. {
  1881. DWORD dwLookupIndex = LocalIpLook(Addr);
  1882. //
  1883. // the address is acceptable if it belongs to
  1884. // the arriving interface or if it belongs to
  1885. // no interfaces. The latter is the route-through case.
  1886. //
  1887. if((dwIndex == dwLookupIndex)
  1888. ||
  1889. (dwLookupIndex == UNKNOWN_IP_INDEX) )
  1890. {
  1891. fRet = TRUE;
  1892. }
  1893. else
  1894. {
  1895. fRet = FALSE;
  1896. }
  1897. }
  1898. else
  1899. {
  1900. fRet = TRUE;
  1901. }
  1902. ReleaseReadLock(&g_IpTableSpin, kirql);
  1903. }
  1904. else
  1905. {
  1906. fRet = TRUE;
  1907. }
  1908. return(fRet);
  1909. }
  1910. DWORD
  1911. LocalIpLook(DWORD Addr)
  1912. /*++
  1913. Routine Description:
  1914. Called to lookup an address in the address hash tables. The caller
  1915. either must hold the g_IpTableSpin read sping lock or must hold
  1916. the FilterAddressLock resource. This should never be called
  1917. while the address table is being built and holding one of
  1918. these locks insures this.
  1919. --*/
  1920. {
  1921. DWORD dwIpIndex, dwX;
  1922. PADDRESSARRAY pa;
  1923. dwX = ADDRHASHX(Addr);
  1924. for(pa = AddrHashTable[dwX]; pa; pa = pa->pNext)
  1925. {
  1926. if(pa->ulAddress == Addr)
  1927. {
  1928. dwIpIndex = pa->ulIndex;
  1929. goto alldone; // ugly but faster than a break and another test.
  1930. }
  1931. }
  1932. for(pa = AddrSubnetHashTable[dwX]; pa; pa = pa->pNextSubnet)
  1933. {
  1934. if(pa->ulSubnetBcastAddress == Addr)
  1935. {
  1936. dwIpIndex = pa->ulIndex;
  1937. goto alldone;
  1938. }
  1939. }
  1940. //
  1941. // not found. Deliver the bad news.
  1942. //
  1943. dwIpIndex = UNKNOWN_IP_INDEX;
  1944. alldone:
  1945. return(dwIpIndex);
  1946. }
  1947. BOOLEAN
  1948. PfFastIoDeviceControl (
  1949. IN struct _FILE_OBJECT *FileObject,
  1950. IN BOOLEAN Wait,
  1951. IN PVOID InputBuffer OPTIONAL,
  1952. IN ULONG InputBufferLength,
  1953. OUT PVOID OutputBuffer OPTIONAL,
  1954. IN ULONG OutputBufferLength,
  1955. IN ULONG IoControlCode,
  1956. OUT PIO_STATUS_BLOCK IoStatus,
  1957. IN struct _DEVICE_OBJECT *DeviceObject
  1958. )
  1959. {
  1960. DWORD dwSize;
  1961. PPAGED_FILTER_INTERFACE pPage;
  1962. NTSTATUS ntStatus;
  1963. switch(IoControlCode)
  1964. {
  1965. default:
  1966. return(FALSE);
  1967. case IOCTL_PF_IP_ADDRESS_LOOKUP:
  1968. //
  1969. // do a dummy fetch to make it recompute.
  1970. //
  1971. if((InputBufferLength < sizeof(DWORD))
  1972. ||
  1973. (OutputBufferLength < sizeof(DWORD)) )
  1974. {
  1975. return(FALSE);
  1976. }
  1977. *(PDWORD)OutputBuffer = GetIpStackIndex(*(PDWORD)InputBuffer, TRUE);
  1978. ntStatus = STATUS_SUCCESS;
  1979. break;
  1980. case IOCTL_PF_DELETE_BY_HANDLE:
  1981. if(InputBufferLength < sizeof(PFDELETEBYHANDLE))
  1982. {
  1983. return(FALSE);
  1984. }
  1985. ntStatus = LockFcb(FileObject);
  1986. if(!NT_SUCCESS(ntStatus))
  1987. {
  1988. return(FALSE);
  1989. }
  1990. pPage = FindInterfaceOnHandle(
  1991. FileObject,
  1992. ((PPFDELETEBYHANDLE)InputBuffer)->pvDriverContext);
  1993. if(!pPage)
  1994. {
  1995. UnLockFcb(FileObject);
  1996. return(FALSE);
  1997. }
  1998. ntStatus = DeleteByHandle(
  1999. (PPFFCB)FileObject->FsContext2,
  2000. pPage,
  2001. &((PPFDELETEBYHANDLE)InputBuffer)->pvHandles[0],
  2002. InputBufferLength - sizeof(PVOID));
  2003. UnLockFcb(FileObject);
  2004. break;
  2005. case IOCTL_DELETE_INTERFACE_FILTERS_EX:
  2006. {
  2007. //
  2008. // The minimum size is without any TOCs
  2009. //
  2010. dwSize = sizeof(FILTER_DRIVER_SET_FILTERS) - sizeof(RTR_TOC_ENTRY);
  2011. if(InputBufferLength < dwSize)
  2012. {
  2013. return(FALSE);
  2014. }
  2015. ntStatus = LockFcb(FileObject);
  2016. if(!NT_SUCCESS(ntStatus))
  2017. {
  2018. return(FALSE);
  2019. }
  2020. pPage = FindInterfaceOnHandle(
  2021. FileObject,
  2022. ((PFILTER_DRIVER_SET_FILTERS)InputBuffer)->pvDriverContext);
  2023. if(!pPage)
  2024. {
  2025. UnLockFcb(FileObject);
  2026. return(FALSE);
  2027. }
  2028. ntStatus = UnSetFiltersEx(
  2029. (PPFFCB)FileObject->FsContext2,
  2030. pPage,
  2031. InputBufferLength,
  2032. (PFILTER_DRIVER_SET_FILTERS)InputBuffer);
  2033. UnLockFcb(FileObject);
  2034. break;
  2035. }
  2036. case IOCTL_GET_SYN_COUNTS:
  2037. {
  2038. if(OutputBufferLength < sizeof(FILTER_DRIVER_GET_SYN_COUNT))
  2039. {
  2040. return(FALSE);
  2041. }
  2042. ntStatus = GetSynCountTotal(
  2043. (PFILTER_DRIVER_GET_SYN_COUNT)OutputBuffer);
  2044. break;
  2045. }
  2046. case IOCTL_SET_INTERFACE_FILTERS_EX:
  2047. {
  2048. //
  2049. // Make sure the caller is using symmetric buffers. If not
  2050. // do it the slow way
  2051. //
  2052. if((InputBuffer != OutputBuffer)
  2053. ||
  2054. (InputBufferLength != OutputBufferLength))
  2055. {
  2056. return(FALSE);
  2057. }
  2058. //
  2059. // The minimum size is without any TOCs
  2060. //
  2061. dwSize = sizeof(FILTER_DRIVER_SET_FILTERS) - sizeof(RTR_TOC_ENTRY);
  2062. if(InputBufferLength < dwSize)
  2063. {
  2064. return(FALSE);
  2065. }
  2066. ntStatus = LockFcb(FileObject);
  2067. if(!NT_SUCCESS(ntStatus))
  2068. {
  2069. return(FALSE);
  2070. }
  2071. pPage = FindInterfaceOnHandle(
  2072. FileObject,
  2073. ((PFILTER_DRIVER_SET_FILTERS)InputBuffer)->pvDriverContext);
  2074. if(!pPage)
  2075. {
  2076. UnLockFcb(FileObject);
  2077. return(FALSE);
  2078. }
  2079. ntStatus = SetFiltersEx(
  2080. (PPFFCB)FileObject->FsContext2,
  2081. pPage,
  2082. InputBufferLength,
  2083. (PFILTER_DRIVER_SET_FILTERS)InputBuffer);
  2084. UnLockFcb(FileObject);
  2085. break;
  2086. }
  2087. }
  2088. IoStatus->Status = ntStatus;
  2089. IoStatus->Information = OutputBufferLength;
  2090. return(TRUE);
  2091. }
  2092. NTSTATUS
  2093. LockFcb(
  2094. IN struct _FILE_OBJECT *FileObject)
  2095. /*++
  2096. Routine Description:
  2097. Lock an FCB. Check if the FCB is on the master list and if
  2098. it is still valid. On success, returns with the FCB resource locked
  2099. and the FCB referenced.
  2100. --*/
  2101. {
  2102. PPFFCB Fcb = (PPFFCB)FileObject->FsContext2;
  2103. KIRQL kirql;
  2104. PLIST_ENTRY List;
  2105. PPFFCB Fcb1 = 0;
  2106. KeAcquireSpinLock(&g_FcbSpin, &kirql);
  2107. for(List = g_leFcbs.Flink;
  2108. List != &g_leFcbs;
  2109. List = List->Flink)
  2110. {
  2111. Fcb1 = CONTAINING_RECORD(List, PFFCB, leList);
  2112. //
  2113. // use it if it is not being closed
  2114. //
  2115. if(Fcb1 == Fcb)
  2116. {
  2117. if( !(Fcb->dwFlags & PF_FCB_CLOSED) )
  2118. {
  2119. InterlockedIncrement(&Fcb->UseCount);
  2120. }
  2121. else
  2122. {
  2123. Fcb1 = 0;
  2124. }
  2125. break;
  2126. }
  2127. }
  2128. KeReleaseSpinLock(&g_FcbSpin, kirql);
  2129. if(Fcb != Fcb1)
  2130. {
  2131. //
  2132. // didn't find it.
  2133. //
  2134. return(STATUS_INVALID_PARAMETER);
  2135. }
  2136. //
  2137. // found it. Lock it up.
  2138. //
  2139. ExAcquireResourceExclusive( &Fcb->Resource, TRUE );
  2140. //
  2141. // must look one more time to see if it has been closed. This can
  2142. // happen if the closer sneaked in. So we have to become the closer.
  2143. //
  2144. if(Fcb->dwFlags & PF_FCB_CLOSED)
  2145. {
  2146. //
  2147. // it was. Unlock it and return an error
  2148. //
  2149. UnLockFcb(FileObject);
  2150. return(STATUS_INVALID_PARAMETER);
  2151. }
  2152. return(STATUS_SUCCESS);
  2153. }
  2154. VOID
  2155. UnLockFcb(
  2156. IN struct _FILE_OBJECT *FileObject)
  2157. /*++
  2158. Routine Description:
  2159. Unlock and derefence an FCB. If the reference count becomes zero,
  2160. remove the FCB from the master list and close it.
  2161. --*/
  2162. {
  2163. PPFFCB Fcb = (PPFFCB)FileObject->FsContext2;
  2164. KIRQL kirql;
  2165. KeAcquireSpinLock(&g_FcbSpin, &kirql);
  2166. if(InterlockedDecrement(&Fcb->UseCount) <= 0)
  2167. {
  2168. ASSERT(Fcb->dwFlags & PF_FCB_CLOSED);
  2169. RemoveEntryList(&Fcb->leList);
  2170. KeReleaseSpinLock(&g_FcbSpin, kirql);
  2171. CloseFcb(Fcb, FileObject);
  2172. }
  2173. else
  2174. {
  2175. KeReleaseSpinLock(&g_FcbSpin, kirql);
  2176. ExReleaseResourceLite( &Fcb->Resource );
  2177. }
  2178. }
  2179. VOID
  2180. PFReadRegistryParameters(PUNICODE_STRING RegistryPath)
  2181. /*++
  2182. Routine Description:
  2183. Called when the driver is loaded. Reads registry paramters
  2184. for configuring the driver
  2185. --*/
  2186. {
  2187. OBJECT_ATTRIBUTES ObjectAttributes;
  2188. HANDLE PFHandle;
  2189. HANDLE PFParHandle;
  2190. NTSTATUS Status;
  2191. UNICODE_STRING UnicodeString;
  2192. ULONG Storage[8];
  2193. PKEY_VALUE_PARTIAL_INFORMATION Value =
  2194. (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
  2195. InitializeObjectAttributes(
  2196. &ObjectAttributes,
  2197. RegistryPath, // name
  2198. OBJ_CASE_INSENSITIVE, // attributes
  2199. NULL, // root
  2200. NULL // security descriptor
  2201. );
  2202. Status = ZwOpenKey (&PFHandle, KEY_READ, &ObjectAttributes);
  2203. RtlInitUnicodeString(&UnicodeString, L"Parameters");
  2204. if(NT_SUCCESS(Status))
  2205. {
  2206. InitializeObjectAttributes(
  2207. &ObjectAttributes,
  2208. &UnicodeString,
  2209. OBJ_CASE_INSENSITIVE,
  2210. PFHandle,
  2211. NULL
  2212. );
  2213. Status = ZwOpenKey (&PFParHandle, KEY_READ, &ObjectAttributes);
  2214. ZwClose(PFHandle);
  2215. if(NT_SUCCESS(Status))
  2216. {
  2217. ULONG BytesRead;
  2218. RtlInitUnicodeString(&UnicodeString, L"AddressHashSize");
  2219. Status = ZwQueryValueKey(
  2220. PFParHandle,
  2221. &UnicodeString,
  2222. KeyValuePartialInformation,
  2223. Value,
  2224. sizeof(Storage),
  2225. &BytesRead);
  2226. if(NT_SUCCESS(Status)
  2227. &&
  2228. (Value->Type == REG_DWORD) )
  2229. {
  2230. AddrModulus = *(PULONG)Value->Data;
  2231. }
  2232. RtlInitUnicodeString(&UnicodeString, L"FragmentThreshold");
  2233. Status = ZwQueryValueKey(
  2234. PFParHandle,
  2235. &UnicodeString,
  2236. KeyValuePartialInformation,
  2237. Value,
  2238. sizeof(Storage),
  2239. &BytesRead);
  2240. if(NT_SUCCESS(Status)
  2241. &&
  2242. (Value->Type == REG_DWORD) )
  2243. {
  2244. g_FragThresholdSize = *(PULONG)Value->Data;
  2245. }
  2246. ZwClose(PFParHandle);
  2247. }
  2248. }
  2249. }