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.

3012 lines
88 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. fsd.c
  5. Abstract:
  6. This module implements the File System Driver for the LAN Manager
  7. server.
  8. Author:
  9. Chuck Lenzmeier (chuckl) 22-Sep-1989
  10. Revision History:
  11. --*/
  12. //
  13. // This module is laid out as follows:
  14. // Includes
  15. // Local #defines
  16. // Local type definitions
  17. // Forward declarations of local functions
  18. // Device driver entry points
  19. // Server I/O completion routine
  20. // Server transport event handlers
  21. // SMB processing support routines
  22. //
  23. #include "precomp.h"
  24. #include "fsd.tmh"
  25. #pragma hdrstop
  26. #define BugCheckFileId SRV_FILE_FSD
  27. #define LOOPBACK_IP_ADDRESS 0x0100007f
  28. extern UNICODE_STRING SrvDeviceName;
  29. extern UNICODE_STRING SrvRegistryPath;
  30. // We allow a connection a couple extra work contexts to cover the MAILSLOT and ECHO operation cases
  31. #define MAX_MPX_MARGIN 10
  32. //
  33. // Forward declarations
  34. //
  35. NTSTATUS
  36. DriverEntry (
  37. IN PDRIVER_OBJECT DriverObject,
  38. IN PUNICODE_STRING RegistryPath
  39. );
  40. VOID
  41. UnloadServer (
  42. IN PDRIVER_OBJECT DriverObject
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text( INIT, DriverEntry )
  46. #pragma alloc_text( PAGE, UnloadServer )
  47. #pragma alloc_text( PAGE, SrvPnpBindingHandler )
  48. #pragma alloc_text( PAGE8FIL, SrvFsdOplockCompletionRoutine )
  49. #pragma alloc_text( PAGE8FIL, SrvFsdRestartSendOplockIItoNone )
  50. #endif
  51. #if 0
  52. NOT PAGEABLE -- SrvFsdIoCompletionRoutine
  53. NOT PAGEABLE -- SrvFsdSendCompletionRoutine
  54. NOT PAGEABLE -- SrvFsdTdiConnectHandler
  55. NOT PAGEABLE -- SrvFsdTdiDisconnectHandler
  56. NOT PAGEABLE -- SrvFsdTdiReceiveHandler
  57. NOT PAGEABLE -- SrvFsdGetReceiveWorkItem
  58. NOT PAGEABLE -- SrvFsdRestartSmbComplete
  59. NOT PAGEABLE -- SrvFsdRestartSmbAtSendCompletion
  60. NOT PAGEABLE -- SrvFsdServiceNeedResourceQueue
  61. NOT PAGEABLE -- SrvAddToNeedResourceQueue
  62. #endif
  63. #if SRVDBG_STATS2
  64. ULONG IndicationsCopied = 0;
  65. ULONG IndicationsNotCopied = 0;
  66. #endif
  67. extern BOOLEAN RunSuspectConnectionAlgorithm;
  68. NTSTATUS
  69. DriverEntry (
  70. IN PDRIVER_OBJECT DriverObject,
  71. IN PUNICODE_STRING RegistryPath
  72. )
  73. /*++
  74. Routine Description:
  75. This is the initialization routine for the LAN Manager server file
  76. system driver. This routine creates the device object for the
  77. LanmanServer device and performs all other driver initialization.
  78. Arguments:
  79. DriverObject - Pointer to driver object created by the system.
  80. Return Value:
  81. The function value is the final status from the initialization operation.
  82. --*/
  83. {
  84. NTSTATUS status;
  85. CLONG i;
  86. PAGED_CODE( );
  87. //
  88. // Make sure we haven't messed up the size of a WORK_QUEUE structure.
  89. // Really needs to be a multiple of CACHE_LINE_SIZE bytes to get
  90. // proper performance on MP systems.
  91. //
  92. // This code gets optimized out when the size is correct.
  93. //
  94. if( sizeof( WORK_QUEUE ) & (CACHE_LINE_SIZE-1) ) {
  95. KdPrint(( "sizeof(WORK_QUEUE) == %d!\n", sizeof( WORK_QUEUE )));
  96. KdPrint(("Fix the WORK_QUEUE structure to be multiple of CACHE_LINE_SIZE!\n" ));
  97. #if DBG
  98. DbgBreakPoint();
  99. #endif
  100. }
  101. #if SRVDBG_BREAK
  102. KdPrint(( "SRV: At DriverEntry\n" ));
  103. DbgBreakPoint( );
  104. #endif
  105. #if 0
  106. SrvDebug.QuadPart = DEBUG_ERRORS | DEBUG_SMB_ERRORS | DEBUG_TDI | DEBUG_PNP;
  107. #endif
  108. IF_DEBUG(FSD1) KdPrint(( "SrvFsdInitialize entered\n" ));
  109. #ifdef MEMPRINT
  110. //
  111. // Initialize in-memory printing.
  112. //
  113. MemPrintInitialize( );
  114. #endif
  115. //
  116. // Create the device object. (IoCreateDevice zeroes the memory
  117. // occupied by the object.)
  118. //
  119. // !!! Apply an ACL to the device object.
  120. //
  121. RtlInitUnicodeString(& SrvDeviceName, StrServerDevice);
  122. status = IoCreateDevice(
  123. DriverObject, // DriverObject
  124. sizeof(DEVICE_EXTENSION), // DeviceExtension
  125. & SrvDeviceName, // DeviceName
  126. FILE_DEVICE_NETWORK, // DeviceType
  127. 0, // DeviceCharacteristics
  128. FALSE, // Exclusive
  129. &SrvDeviceObject // DeviceObject
  130. );
  131. if ( !NT_SUCCESS(status) ) {
  132. INTERNAL_ERROR(
  133. ERROR_LEVEL_EXPECTED,
  134. "SrvFsdInitialize: Unable to create device object: %X",
  135. status,
  136. NULL
  137. );
  138. SrvLogError(
  139. DriverObject,
  140. EVENT_SRV_CANT_CREATE_DEVICE,
  141. status,
  142. NULL,
  143. 0,
  144. NULL,
  145. 0
  146. );
  147. return status;
  148. }
  149. IF_DEBUG(FSD1) {
  150. KdPrint(( " Server device object: 0x%p\n", SrvDeviceObject ));
  151. }
  152. //
  153. // Initialize the driver object for this file system driver.
  154. //
  155. DriverObject->DriverUnload = UnloadServer;
  156. for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
  157. DriverObject->MajorFunction[i] = SrvFsdDispatch;
  158. }
  159. //
  160. // Initialize global data fields.
  161. //
  162. SrvInitializeData( );
  163. // Remember registry path
  164. //
  165. SrvRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
  166. SrvRegistryPath.Buffer = ExAllocatePool(PagedPool,
  167. SrvRegistryPath.MaximumLength);
  168. if (SrvRegistryPath.Buffer != NULL) {
  169. RtlCopyUnicodeString(& SrvRegistryPath, RegistryPath);
  170. }
  171. else {
  172. SrvRegistryPath.Length = SrvRegistryPath.MaximumLength = 0;
  173. }
  174. IF_DEBUG(FSD1) KdPrint(( "SrvFsdInitialize complete\n" ));
  175. return (status);
  176. } // DriverEntry
  177. VOID
  178. UnloadServer (
  179. IN PDRIVER_OBJECT DriverObject
  180. )
  181. /*++
  182. Routine Description:
  183. This is the unload routine for the server driver.
  184. Arguments:
  185. DriverObject - Pointer to server driver object.
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. PAGED_CODE( );
  191. if (SrvRegistryPath.Buffer != NULL ) ExFreePool(SrvRegistryPath.Buffer);
  192. //
  193. // If we are using a smart card to accelerate direct host IPX clients,
  194. // let it know we are going away.
  195. //
  196. if( SrvIpxSmartCard.DeRegister ) {
  197. IF_DEBUG( SIPX ) {
  198. KdPrint(("Calling Smart Card DeRegister\n" ));
  199. }
  200. SrvIpxSmartCard.DeRegister();
  201. }
  202. //
  203. // Clean up global data structures.
  204. //
  205. SrvTerminateData( );
  206. //
  207. // Delete the server's device object.
  208. //
  209. IoDeleteDevice( SrvDeviceObject );
  210. return;
  211. } // UnloadServer
  212. NTSTATUS
  213. SrvFsdIoCompletionRoutine (
  214. IN PDEVICE_OBJECT DeviceObject,
  215. IN PIRP Irp,
  216. IN PVOID Context
  217. )
  218. /*++
  219. Routine Description:
  220. This is the I/O completion routine for the server. It is specified
  221. as the completion routine for asynchronous I/O requests issued by
  222. the server. It simply calls the restart routine specified for the
  223. work item when the asynchronous request was started.
  224. Arguments:
  225. DeviceObject - Pointer to target device object for the request.
  226. Irp - Pointer to I/O request packet
  227. Context - Caller-specified context parameter associated with IRP.
  228. This is actually a pointer to a Work Context block.
  229. Return Value:
  230. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  231. completion processing by IoCompleteRequest terminates its
  232. operation. Otherwise, IoCompleteRequest continues with I/O
  233. completion.
  234. --*/
  235. {
  236. KIRQL oldIrql;
  237. DeviceObject; // prevent compiler warnings
  238. IF_DEBUG(FSD2) {
  239. KdPrint(( "SrvFsdIoCompletionRoutine entered for IRP 0x%p\n", Irp ));
  240. }
  241. #if DBG
  242. if( Irp->Type != (CSHORT) IO_TYPE_IRP ) {
  243. DbgPrint( "SRV: Irp->Type = %u!\n", Irp->Type );
  244. DbgBreakPoint();
  245. }
  246. #endif
  247. //
  248. // Reset the IRP cancelled bit.
  249. //
  250. Irp->Cancel = FALSE;
  251. //
  252. // Call the restart routine associated with the work item.
  253. //
  254. IF_DEBUG(FSD2) {
  255. KdPrint(( "FSD working on work context 0x%p", Context ));
  256. }
  257. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  258. ((PWORK_CONTEXT)Context)->FsdRestartRoutine( (PWORK_CONTEXT)Context );
  259. KeLowerIrql( oldIrql );
  260. //
  261. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  262. // will stop working on the IRP.
  263. //
  264. return STATUS_MORE_PROCESSING_REQUIRED;
  265. } // SrvFsdIoCompletionRoutine
  266. NTSTATUS
  267. SrvFsdSendCompletionRoutine (
  268. IN PDEVICE_OBJECT DeviceObject,
  269. IN PIRP Irp,
  270. IN PVOID Context
  271. )
  272. /*++
  273. Routine Description:
  274. This is the TDI send completion routine for the server. It simply
  275. calls the restart routine specified for the work item when the
  276. send request was started.
  277. !!! This routine does the exact same thing as SrvFsdIoCompletionRoutine.
  278. It offers, however, a convienient network debugging routine since
  279. it completes only sends.
  280. Arguments:
  281. DeviceObject - Pointer to target device object for the request.
  282. Irp - Pointer to I/O request packet
  283. Context - Caller-specified context parameter associated with IRP.
  284. This is actually a pointer to a Work Context block.
  285. Return Value:
  286. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  287. completion processing by IoCompleteRequest terminates its
  288. operation. Otherwise, IoCompleteRequest continues with I/O
  289. completion.
  290. --*/
  291. {
  292. KIRQL oldIrql;
  293. PWORK_CONTEXT WorkContext = (PWORK_CONTEXT)(Context);
  294. DeviceObject; // prevent compiler warnings
  295. IF_DEBUG(FSD2) {
  296. KdPrint(( "SrvFsdSendCompletionRoutine entered for IRP 0x%p\n", Irp ));
  297. }
  298. //
  299. // Check the status of the send completion.
  300. //
  301. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  302. //
  303. // Reset the IRP cancelled bit.
  304. //
  305. Irp->Cancel = FALSE;
  306. //
  307. // Call the restart routine associated with the work item.
  308. //
  309. IF_DEBUG(FSD2) {
  310. KdPrint(( "FSD working on work context 0x%p", Context ));
  311. }
  312. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  313. ((PWORK_CONTEXT)Context)->FsdRestartRoutine( (PWORK_CONTEXT)Context );
  314. KeLowerIrql( oldIrql );
  315. //
  316. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  317. // will stop working on the IRP.
  318. //
  319. return STATUS_MORE_PROCESSING_REQUIRED;
  320. } // SrvFsdSendCompletionRoutine
  321. NTSTATUS
  322. SrvFsdOplockCompletionRoutine (
  323. IN PDEVICE_OBJECT DeviceObject,
  324. IN PIRP Irp,
  325. IN PVOID Context
  326. )
  327. /*++
  328. Routine Description:
  329. This is the I/O completion routine oplock requests.
  330. Arguments:
  331. DeviceObject - Pointer to target device object for the request.
  332. Irp - Pointer to I/O request packet
  333. Context - A pointer to the oplock context block.
  334. Return Value:
  335. NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
  336. completion processing by IoCompleteRequest terminates its
  337. operation. Otherwise, IoCompleteRequest continues with I/O
  338. completion.
  339. --*/
  340. {
  341. PRFCB rfcb = Context;
  342. UNLOCKABLE_CODE( 8FIL );
  343. DeviceObject; // prevent compiler warnings
  344. IF_DEBUG(FSD2) {
  345. KdPrint(( "SrvFsdOplockCompletionRoutine entered for IRP 0x%p\n", Irp ));
  346. }
  347. //
  348. // Queue the oplock context to the FSP work queue, except in the
  349. // following special case: If a level I oplock request failed, and
  350. // we want to retry for level II, simply set the oplock retry event
  351. // and dismiss IRP processing. This is useful because it eliminates
  352. // a trip to an FSP thread and necessary in order to avoid a
  353. // deadlock where all of the FSP threads are waiting for their
  354. // oplock retry events.
  355. //
  356. IF_DEBUG(FSD2) {
  357. KdPrint(( "FSD working on work context 0x%p", Context ));
  358. }
  359. if ( (rfcb->RetryOplockRequest != NULL) &&
  360. !NT_SUCCESS(Irp->IoStatus.Status) ) {
  361. //
  362. // Set the event that tells the oplock request routine that it
  363. // is OK to retry the request.
  364. //
  365. IF_DEBUG(OPLOCK) {
  366. KdPrint(( "SrvFsdOplockCompletionRoutine: oplock retry event "
  367. "set for RFCB %p\n", rfcb ));
  368. }
  369. KeSetEvent(
  370. rfcb->RetryOplockRequest,
  371. EVENT_INCREMENT,
  372. FALSE );
  373. return STATUS_MORE_PROCESSING_REQUIRED;
  374. }
  375. //
  376. // Insert the RFCB at the tail of the nonblocking work queue.
  377. //
  378. rfcb->FspRestartRoutine = SrvOplockBreakNotification;
  379. SrvInsertWorkQueueTail(
  380. rfcb->Connection->PreferredWorkQueue,
  381. (PQUEUEABLE_BLOCK_HEADER)rfcb
  382. );
  383. //
  384. // Return STATUS_MORE_PROCESSING_REQUIRED so that IoCompleteRequest
  385. // will stop working on the IRP.
  386. //
  387. return STATUS_MORE_PROCESSING_REQUIRED;
  388. } // SrvFsdOplockCompletionRoutine
  389. NTSTATUS
  390. SrvFsdTdiConnectHandler(
  391. IN PVOID TdiEventContext,
  392. IN int RemoteAddressLength,
  393. IN PVOID RemoteAddress,
  394. IN int UserDataLength,
  395. IN PVOID UserData,
  396. IN int OptionsLength,
  397. IN PVOID Options,
  398. OUT CONNECTION_CONTEXT *ConnectionContext,
  399. OUT PIRP *AcceptIrp
  400. )
  401. /*++
  402. Routine Description:
  403. This is the transport connect event handler for the server. It is
  404. specified as the connect handler for all endpoints opened by the
  405. server. It attempts to dequeue a free connection from a list
  406. anchored in the endpoint. If successful, it returns the connection
  407. to the transport. Otherwise, the connection is rejected.
  408. Arguments:
  409. TdiEventContext -
  410. RemoteAddressLength -
  411. RemoteAddress -
  412. UserDataLength -
  413. UserData -
  414. OptionsLength -
  415. Options -
  416. ConnectionContext -
  417. Return Value:
  418. NTSTATUS - !!! (apparently ignored by transport driver)
  419. --*/
  420. {
  421. PENDPOINT endpoint;
  422. PLIST_ENTRY listEntry;
  423. PCONNECTION connection;
  424. PWORK_CONTEXT workContext;
  425. PTA_NETBIOS_ADDRESS address;
  426. KIRQL oldIrql;
  427. PWORK_QUEUE queue = PROCESSOR_TO_QUEUE();
  428. UserDataLength, UserData; // avoid compiler warnings
  429. OptionsLength, Options;
  430. endpoint = (PENDPOINT)TdiEventContext;
  431. IF_DEBUG(FSD2) {
  432. KdPrint(( "SrvFsdTdiConnectHandler entered for endpoint 0x%p\n",
  433. endpoint ));
  434. }
  435. if( SrvCompletedPNPRegistration == FALSE ) {
  436. //
  437. // Do not become active on any single transport until all of the
  438. // transports have been registered
  439. //
  440. return STATUS_REQUEST_NOT_ACCEPTED;
  441. }
  442. //
  443. // Take a receive work item off the free list.
  444. //
  445. ALLOCATE_WORK_CONTEXT( queue, &workContext );
  446. if ( workContext == NULL ) {
  447. //
  448. // We're out of WorkContext structures, and we aren't able to allocate
  449. // any more just now. Let's at least cause a worker thread to allocate some more
  450. // by incrementing the NeedWorkItem counter. This will cause the next
  451. // freed WorkContext structure to get dispatched to SrvServiceWorkItemShortage.
  452. // While SrvServiceWorkItemShortage probably won't find any work to do, it will
  453. // allocate more WorkContext structures if it can. Clients generally retry
  454. // on connection attempts -- perhaps we'll have a free WorkItem structure next time.
  455. //
  456. InterlockedIncrement( &queue->NeedWorkItem );
  457. // Set it up to refill the connection cache
  458. // We need to do this because previous attempts could have failed due to
  459. // out-of-memory, leaving us in a state where we don't try to refill anymore
  460. if( GET_BLOCK_STATE(endpoint) == BlockStateActive )
  461. {
  462. SrvResourceAllocConnection = TRUE;
  463. SrvFsdQueueExWorkItem(
  464. &SrvResourceAllocThreadWorkItem,
  465. &SrvResourceAllocThreadRunning,
  466. CriticalWorkQueue
  467. );
  468. }
  469. INTERNAL_ERROR(
  470. ERROR_LEVEL_EXPECTED,
  471. "SrvFsdTdiConnectHandler: no work item available",
  472. NULL,
  473. NULL
  474. );
  475. return STATUS_INSUFFICIENT_RESOURCES;
  476. }
  477. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  478. ACQUIRE_DPC_GLOBAL_SPIN_LOCK( Fsd );
  479. //
  480. // Take a connection off the endpoint's free connection list.
  481. //
  482. // *** Note that all of the modifications done to the connection
  483. // block are done with the spin lock held. This ensures that
  484. // closing of the endpoint's connections will work properly
  485. // if it happens simultaneously. Note that we assume that the
  486. // endpoint is active here. When the TdiAccept completes, we
  487. // check the endpoint state.
  488. //
  489. listEntry = RemoveHeadList( &endpoint->FreeConnectionList );
  490. if ( listEntry == &endpoint->FreeConnectionList ) {
  491. //
  492. // Unable to get a free connection.
  493. //
  494. // Dereference the work item manually. We cannot call
  495. // SrvDereferenceWorkItem from here.
  496. //
  497. RELEASE_DPC_GLOBAL_SPIN_LOCK( Fsd );
  498. KeLowerIrql( oldIrql );
  499. ASSERT( workContext->BlockHeader.ReferenceCount == 1 );
  500. workContext->BlockHeader.ReferenceCount = 0;
  501. RETURN_FREE_WORKITEM( workContext );
  502. IF_DEBUG(TDI) {
  503. KdPrint(( "SrvFsdTdiConnectHandler: no connection available\n" ));
  504. }
  505. SrvOutOfFreeConnectionCount++;
  506. // Set it up to refill the connection cache
  507. // We need to do this because previous attempts could have failed due to
  508. // out-of-memory, leaving us in a state where we don't try to refill anymore
  509. if( GET_BLOCK_STATE(endpoint) == BlockStateActive )
  510. {
  511. SrvResourceAllocConnection = TRUE;
  512. SrvFsdQueueExWorkItem(
  513. &SrvResourceAllocThreadWorkItem,
  514. &SrvResourceAllocThreadRunning,
  515. CriticalWorkQueue
  516. );
  517. }
  518. return STATUS_INSUFFICIENT_RESOURCES;
  519. }
  520. endpoint->FreeConnectionCount--;
  521. //
  522. // Wake up the resource thread to create a new free connection for
  523. // the endpoint.
  524. //
  525. if ( (endpoint->FreeConnectionCount < SrvFreeConnectionMinimum) &&
  526. (GET_BLOCK_STATE(endpoint) == BlockStateActive) ) {
  527. SrvResourceAllocConnection = TRUE;
  528. SrvFsdQueueExWorkItem(
  529. &SrvResourceAllocThreadWorkItem,
  530. &SrvResourceAllocThreadRunning,
  531. CriticalWorkQueue
  532. );
  533. }
  534. RELEASE_DPC_GLOBAL_SPIN_LOCK( Fsd );
  535. //
  536. // Reference the connection twice -- once to account for its being
  537. // "open", and once to account for the Accept request we're about
  538. // to issue.
  539. //
  540. connection = CONTAINING_RECORD(
  541. listEntry,
  542. CONNECTION,
  543. EndpointFreeListEntry
  544. );
  545. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  546. #if SRVDBG29
  547. if ( GET_BLOCK_STATE(connection) == BlockStateActive ) {
  548. KdPrint(( "SRV: Connection %x is ACTIVE on free connection list!\n", connection ));
  549. DbgBreakPoint( );
  550. }
  551. if ( connection->BlockHeader.ReferenceCount != 0 ) {
  552. KdPrint(( "SRV: Connection %x has nonzero refcnt on free connection list!\n", connection ));
  553. DbgBreakPoint( );
  554. }
  555. UpdateConnectionHistory( "CONN", endpoint, connection );
  556. #endif
  557. SrvReferenceConnectionLocked( connection );
  558. SrvReferenceConnectionLocked( connection );
  559. //
  560. // Indicate that we are a VC-oriented connection
  561. //
  562. connection->DirectHostIpx = FALSE;
  563. //
  564. // Set the processor affinity
  565. //
  566. connection->PreferredWorkQueue = queue;
  567. connection->CurrentWorkQueue = queue;
  568. InterlockedIncrement( &queue->CurrentClients );
  569. #if MULTIPROCESSOR
  570. //
  571. // Get this client onto the best processor
  572. //
  573. SrvBalanceLoad( connection );
  574. #endif
  575. //
  576. // Initialize the SMB security signature handling
  577. //
  578. connection->SmbSecuritySignatureActive = FALSE;
  579. //
  580. // Put the work item on the in-progress list.
  581. //
  582. SrvInsertTailList(
  583. &connection->InProgressWorkItemList,
  584. &workContext->InProgressListEntry
  585. );
  586. connection->InProgressWorkContextCount++;
  587. //
  588. // Set the last used timestamp for this connection
  589. //
  590. GET_SERVER_TIME( connection->CurrentWorkQueue, &connection->LastRequestTime );
  591. //
  592. // Mark the connection active.
  593. //
  594. SET_BLOCK_STATE( connection, BlockStateActive );
  595. //
  596. // Now we can release the spin lock.
  597. //
  598. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  599. //
  600. // Save the client's address/name in the connection block.
  601. //
  602. // *** This code only handles NetBIOS names!
  603. //
  604. address = (PTA_NETBIOS_ADDRESS)RemoteAddress;
  605. ASSERT( address->TAAddressCount == 1 );
  606. ASSERT( address->Address[0].AddressType == TDI_ADDRESS_TYPE_NETBIOS );
  607. ASSERT( address->Address[0].AddressLength == sizeof(TDI_ADDRESS_NETBIOS) );
  608. ASSERT( address->Address[0].Address[0].NetbiosNameType ==
  609. TDI_ADDRESS_NETBIOS_TYPE_UNIQUE );
  610. //
  611. // Copy the oem name at this time. We convert it to unicode when
  612. // we get to the fsp.
  613. //
  614. {
  615. ULONG len;
  616. PCHAR oemClientName = address->Address[0].Address[0].NetbiosName;
  617. ULONG oemClientNameLength =
  618. (MIN( RemoteAddressLength, COMPUTER_NAME_LENGTH ));
  619. PCHAR clientMachineName = connection->OemClientMachineName;
  620. RtlCopyMemory(
  621. clientMachineName,
  622. oemClientName,
  623. oemClientNameLength
  624. );
  625. clientMachineName[oemClientNameLength] = '\0';
  626. //
  627. // Determine the number of characters that aren't blanks. This is
  628. // used by the session APIs to simplify their processing.
  629. //
  630. for ( len = oemClientNameLength;
  631. len > 0 &&
  632. (clientMachineName[len-1] == ' ' ||
  633. clientMachineName[len-1] == '\0');
  634. len-- ) ;
  635. connection->OemClientMachineNameString.Length = (USHORT)len;
  636. }
  637. IF_DEBUG(TDI) {
  638. KdPrint(( "SrvFsdTdiConnectHandler accepting connection from %z on connection %p\n",
  639. (PCSTRING)&connection->OemClientMachineNameString, connection ));
  640. }
  641. //
  642. // Convert the prebuilt TdiReceive request into a TdiAccept request.
  643. //
  644. workContext->Connection = connection;
  645. workContext->Endpoint = endpoint;
  646. (VOID)SrvBuildIoControlRequest(
  647. workContext->Irp, // input IRP address
  648. connection->FileObject, // target file object address
  649. workContext, // context
  650. IRP_MJ_INTERNAL_DEVICE_CONTROL, // major function
  651. TDI_ACCEPT, // minor function
  652. NULL, // input buffer address
  653. 0, // input buffer length
  654. NULL, // output buffer address
  655. 0, // output buffer length
  656. NULL, // MDL address
  657. NULL // completion routine
  658. );
  659. //
  660. // Make the next stack location current. Normally IoCallDriver would
  661. // do this, but since we're bypassing that, we do it directly.
  662. //
  663. IoSetNextIrpStackLocation( workContext->Irp );
  664. //
  665. // Set up the restart routine. This routine will verify that the
  666. // endpoint is active when the TdiAccept completes; if it isn't, the
  667. // connection will be closed at that time.
  668. //
  669. workContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  670. workContext->FspRestartRoutine = SrvRestartAccept;
  671. //
  672. // Return the connection context (the connection address) to the
  673. // transport. Return a pointer to the Accept IRP. Indicate that
  674. // the Connect event has been handled.
  675. //
  676. *ConnectionContext = connection;
  677. *AcceptIrp = workContext->Irp;
  678. KeLowerIrql( oldIrql );
  679. return STATUS_MORE_PROCESSING_REQUIRED;
  680. } // SrvFsdTdiConnectHandler
  681. NTSTATUS
  682. SrvFsdTdiDisconnectHandler(
  683. IN PVOID TdiEventContext,
  684. IN CONNECTION_CONTEXT ConnectionContext,
  685. IN int DisconnectDataLength,
  686. IN PVOID DisconnectData,
  687. IN int DisconnectInformationLength,
  688. IN PVOID DisconnectInformation,
  689. IN ULONG DisconnectFlags
  690. )
  691. /*++
  692. Routine Description:
  693. This is the transport disconnect event handler for the server. It
  694. is specified as the disconnect handler for all endpoints opened by
  695. the server. It attempts to dequeue a preformatted receive item from
  696. a list anchored in the device object. If successful, it turns this
  697. receive item into a disconnect item and queues it to the FSP work
  698. queue. Otherwise, the resource thread is started to format
  699. additional work items and service pended (dis)connections.
  700. Arguments:
  701. TransportEndpoint - Pointer to file object for receiving endpoint
  702. ConnectionContext - Value associated with endpoint by owner. For
  703. the server, this points to a Connection block maintained in
  704. nonpaged pool.
  705. DisconnectIndicators - Set of flags indicating the status of the
  706. disconnect
  707. Return Value:
  708. NTSTATUS - !!! (apparently ignored by transport driver)
  709. --*/
  710. {
  711. PCONNECTION connection;
  712. KIRQL oldIrql;
  713. TdiEventContext, DisconnectDataLength, DisconnectData;
  714. DisconnectInformationLength, DisconnectInformation, DisconnectFlags;
  715. if( DisconnectFlags & TDI_DISCONNECT_ABORT ) {
  716. SrvAbortiveDisconnects++;
  717. }
  718. connection = (PCONNECTION)ConnectionContext;
  719. #if SRVDBG29
  720. UpdateConnectionHistory( "DISC", connection->Endpoint, connection );
  721. #endif
  722. IF_DEBUG(FSD2) {
  723. KdPrint(( "SrvFsdTdiDisconnectHandler entered for endpoint 0x%p, connection 0x%p\n", TdiEventContext, connection ));
  724. }
  725. IF_DEBUG(TDI) {
  726. KdPrint(( "SrvFsdTdiDisconnectHandler received disconnect from %z on connection %p\n",
  727. (PCSTRING)&connection->OemClientMachineNameString, connection ));
  728. }
  729. //
  730. // Mark the connection and wake up the resource thread so that it
  731. // can service the pending (dis)connections.
  732. //
  733. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  734. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  735. //
  736. // If the connection is already closing, don't bother queueing it to
  737. // the disconnect queue.
  738. //
  739. if ( GET_BLOCK_STATE(connection) != BlockStateActive ) {
  740. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  741. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  742. return STATUS_SUCCESS;
  743. }
  744. if ( connection->DisconnectPending ) {
  745. //
  746. // Error! Error! Error! This connection is already on
  747. // a queue for processing. Ignore the disconnect request.
  748. //
  749. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  750. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  751. INTERNAL_ERROR(
  752. ERROR_LEVEL_UNEXPECTED,
  753. "SrvFsdTdiDisconnectHandler: Received unexpected disconnect"
  754. "indication",
  755. NULL,
  756. NULL
  757. );
  758. SrvLogSimpleEvent( EVENT_SRV_UNEXPECTED_DISC, STATUS_SUCCESS );
  759. return STATUS_SUCCESS;
  760. }
  761. connection->DisconnectPending = TRUE;
  762. if ( connection->OnNeedResourceQueue ) {
  763. //
  764. // This connection is waiting for a resource. Take it
  765. // off the need resource queue before putting it on the
  766. // disconnect queue.
  767. //
  768. // *** Note that the connection has already been referenced to
  769. // account for its being on the need-resource queue, so we
  770. // don't reference it again here.
  771. //
  772. SrvRemoveEntryList(
  773. &SrvNeedResourceQueue,
  774. &connection->ListEntry
  775. );
  776. connection->OnNeedResourceQueue = FALSE;
  777. DEBUG connection->ReceivePending = FALSE;
  778. } else {
  779. //
  780. // The connection isn't already on the need-resource queue, so
  781. // we need to reference it before we put it on the disconnect
  782. // queue. This is necessary in order to make the code in
  783. // scavengr.c that removes things from the queue work right.
  784. //
  785. SrvReferenceConnectionLocked( connection );
  786. }
  787. connection->DisconnectReason = DisconnectTransportIssuedDisconnect;
  788. SrvInsertTailList(
  789. &SrvDisconnectQueue,
  790. &connection->ListEntry
  791. );
  792. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  793. SrvResourceDisconnectPending = TRUE;
  794. SrvFsdQueueExWorkItem(
  795. &SrvResourceThreadWorkItem,
  796. &SrvResourceThreadRunning,
  797. CriticalWorkQueue
  798. );
  799. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  800. return STATUS_SUCCESS;
  801. } // SrvFsdTdiDisconnectHandler
  802. BOOLEAN
  803. SrvFsdAcceptReceive(
  804. PCONNECTION Connection,
  805. PBYTE Data,
  806. ULONG BytesIndicated,
  807. ULONG BytesAvailible
  808. )
  809. /*++
  810. Routine Description:
  811. This routine allows us to trivially reject a receive if we don't think its valid.
  812. This can be expanded later to include maintaining a list of bad IP addresses and other
  813. such DoS schemes to help protect us more.
  814. Arguments:
  815. Connection - the connection this was received on
  816. Data - Pointer to the availible data
  817. BytesIndicated - the total size of the receive
  818. Bytes Availible - How much is currently pointed at by the Data pointer.
  819. Return Value:
  820. TRUE - Accept receive, FALSE = reject receive
  821. --*/
  822. {
  823. PSMB_HEADER pHeader = (PSMB_HEADER)Data;
  824. //
  825. // Trivially reject certain packets
  826. //
  827. if( BytesIndicated < sizeof(SMB_HEADER)+sizeof(BYTE) )
  828. {
  829. return FALSE;
  830. }
  831. if( BytesAvailible > sizeof(SMB_HEADER) )
  832. {
  833. if( SmbGetUlong(Data) != SMB_HEADER_PROTOCOL )
  834. {
  835. return FALSE;
  836. }
  837. if( Connection->SmbDialect == SmbDialectIllegal &&
  838. pHeader->Command != SMB_COM_NEGOTIATE )
  839. {
  840. return FALSE;
  841. }
  842. else if( Connection->SmbDialect != SmbDialectIllegal &&
  843. pHeader->Command == SMB_COM_NEGOTIATE )
  844. {
  845. return FALSE;
  846. }
  847. if( SrvSmbIndexTable[pHeader->Command] == ISrvSmbIllegalCommand )
  848. {
  849. return FALSE;
  850. }
  851. }
  852. return TRUE;
  853. } // SrvFsdAcceptReceive
  854. NTSTATUS
  855. SrvFsdTdiReceiveHandler (
  856. IN PVOID TdiEventContext,
  857. IN CONNECTION_CONTEXT ConnectionContext,
  858. IN ULONG ReceiveFlags,
  859. IN ULONG BytesIndicated,
  860. IN ULONG BytesAvailable,
  861. OUT ULONG *BytesTaken,
  862. IN PVOID Tsdu,
  863. OUT PIRP *IoRequestPacket
  864. )
  865. /*++
  866. Routine Description:
  867. This is the transport receive event handler for the server. It is
  868. specified as the receive handler for all endpoints opened by the
  869. server. It attempts to dequeue a preformatted work item from a list
  870. anchored in the device object. If this is successful, it returns
  871. the IRP associated with the work item to the transport provider to
  872. be used to receive the data. Otherwise, the resource thread is
  873. awakened to format additional receive work items and service pended
  874. connections.
  875. Arguments:
  876. TransportEndpoint - Pointer to file object for receiving endpoint
  877. ConnectionContext - Value associated with endpoint by owner. For
  878. the server, this points to a Connection block maintained in
  879. nonpaged pool.
  880. ReceiveIndicators - Set of flags indicating the status of the
  881. received message
  882. Tsdu - Pointer to received data.
  883. Irp - Returns a pointer to I/O request packet, if the returned
  884. status is STATUS_MORE_PROCESSING_REQUIRED. This IRP is
  885. made the 'current' Receive for the connection.
  886. Return Value:
  887. NTSTATUS - If STATUS_SUCCESS, the receive handler completely
  888. processed the request. If STATUS_MORE_PROCESSING_REQUIRED,
  889. the Irp parameter points to a formatted Receive request to
  890. be used to receive the data. If STATUS_DATA_NOT_ACCEPTED,
  891. no IRP is returned, but the transport provider should check
  892. for previously queued Receive requests.
  893. --*/
  894. {
  895. NTSTATUS status;
  896. PCONNECTION connection;
  897. PWORK_CONTEXT workContext;
  898. PIRP irp;
  899. PIO_STACK_LOCATION irpSp;
  900. PWORK_QUEUE queue;
  901. ULONG receiveLength;
  902. LONG OplocksInProgress;
  903. PMDL mdl;
  904. PSMB_HEADER pHeader = (PSMB_HEADER)Tsdu;
  905. KIRQL oldIrql;
  906. TdiEventContext; // prevent compiler warnings
  907. connection = (PCONNECTION)ConnectionContext;
  908. IF_DEBUG(FSD2) {
  909. KdPrint(( "SrvFsdTdiReceiveHandler entered for endpoint 0x%p, "
  910. "connection 0x%p\n", TdiEventContext, connection ));
  911. }
  912. //
  913. // If the connection is closing, don't bother servicing this
  914. // indication.
  915. //
  916. if ( GET_BLOCK_STATE(connection) == BlockStateActive ) {
  917. // See if we can trivially reject this receive
  918. if( !SrvFsdAcceptReceive( connection, Tsdu, BytesIndicated, BytesAvailable ) )
  919. {
  920. // Mark them as suspect. If a DoS is triggered, they will be nuked first.
  921. connection->IsConnectionSuspect = TRUE;
  922. return STATUS_DATA_NOT_ACCEPTED;
  923. }
  924. //
  925. // Set the last used timestamp for this connection
  926. //
  927. GET_SERVER_TIME( connection->CurrentWorkQueue, &connection->LastRequestTime );
  928. if ( !(ReceiveFlags & TDI_RECEIVE_AT_DISPATCH_LEVEL) ) {
  929. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  930. }
  931. #if MULTIPROCESSOR
  932. //
  933. // See if it's time to home this connection to another
  934. // processor
  935. //
  936. if( --(connection->BalanceCount) == 0 ) {
  937. SrvBalanceLoad( connection );
  938. }
  939. #endif
  940. queue = connection->CurrentWorkQueue;
  941. //
  942. // We're going to either get a free work item and point it to
  943. // the connection, or put the connection on the need-resource
  944. // queue, so we'll need to reference the connection block.
  945. //
  946. // *** Note that we are able to access the connection block
  947. // because it's in nonpaged pool. Referencing the
  948. // connection block here accounts for the I/O request we're
  949. // 'starting', and prevents the block from being deleted
  950. // until the FSP processes the completed Receive. To make
  951. // all this work right, the transport provider must
  952. // guarantee that it won't deliver any events after it
  953. // delivers a Disconnect event or completes a client-issued
  954. // Disconnect request.
  955. //
  956. // *** Note that we don't reference the endpoint file object
  957. // directly. The connection block, which we do reference,
  958. // references an endpoint block, which in turn references
  959. // the file object.
  960. //
  961. //
  962. // Try to dequeue a work item from the free list.
  963. //
  964. // Make sure we're not trying to do too much
  965. // Note the 2x in this calculation. The reason for this is that if you have a fast client and a busy server,
  966. // the client can actually turn around and re-use the MID for an operation while the completion call for this
  967. // operation is still stuck in our queue. This means that it is possible for the client to legally have up to
  968. // 2x MpxCt items in our queue. This is an upper-bound to ensure compatibility. Note that this is only the first
  969. // line of defense against DoS, so it is not too bad to allow this many ops through. If they actually get multiple
  970. // connections going and run us out of resources, we will kick in and start aggressively disconnecting suspicious
  971. // connections.
  972. if( (connection->InProgressWorkContextCount > 2*(SrvMaxMpxCount + MAX_MPX_MARGIN)) && !SrvDisableDoSChecking )
  973. {
  974. PSMB_HEADER SmbHeader = (PSMB_HEADER)Tsdu;
  975. // We normally don't overrun the above bounds. If we do, lets validate that we are truly exceeding our
  976. // bounds including oplock breaks. Still no good way to include Mailslot operations and echos, so we have a fudge factor.
  977. // Note that the need to do 2x covers this too.
  978. OplocksInProgress = InterlockedCompareExchange( &connection->OplockBreaksInProgress, 0, 0 );
  979. if( !(connection->InProgressWorkContextCount > 2*(SrvMaxMpxCount + OplocksInProgress + MAX_MPX_MARGIN)) )
  980. {
  981. goto abort_dos;
  982. }
  983. if( connection->ClientIPAddress == LOOPBACK_IP_ADDRESS )
  984. {
  985. // The loopback transport is very bad about getting us send completions in a timely manner. Thus
  986. // we don't enforce this portion of the DoS detection against a loopback connection.
  987. goto abort_dos;
  988. }
  989. // We're going to enforce the max number of work-items a single client can claim
  990. INTERNAL_ERROR(
  991. ERROR_LEVEL_EXPECTED,
  992. "SrvFsdTdiReceiveHandler: client overruning their WorkItem limit",
  993. NULL,
  994. NULL
  995. );
  996. connection->IsConnectionSuspect = TRUE;
  997. RunSuspectConnectionAlgorithm = TRUE;
  998. status = STATUS_DATA_NOT_ACCEPTED;
  999. }
  1000. else
  1001. {
  1002. abort_dos:
  1003. ALLOCATE_WORK_CONTEXT( queue, &workContext );
  1004. if ( workContext != NULL ) {
  1005. //
  1006. // We found a work item to handle this receive. Reference
  1007. // the connection. Put the work item on the in-progress
  1008. // list. Save the connection and endpoint block addresses
  1009. // in the work context block.
  1010. //
  1011. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1012. SrvReferenceConnectionLocked( connection );
  1013. SrvInsertTailList(
  1014. &connection->InProgressWorkItemList,
  1015. &workContext->InProgressListEntry
  1016. );
  1017. connection->InProgressWorkContextCount++;
  1018. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1019. //
  1020. // Keep track of the amount of data that was indicated
  1021. //
  1022. workContext->BytesAvailable = BytesAvailable;
  1023. irp = workContext->Irp;
  1024. workContext->Connection = connection;
  1025. workContext->Endpoint = connection->Endpoint;
  1026. if( connection->SmbSecuritySignatureActive &&
  1027. BytesIndicated >= FIELD_OFFSET( SMB_HEADER, Command ) ) {
  1028. //
  1029. // Save this security signature index
  1030. //
  1031. workContext->SmbSecuritySignatureIndex =
  1032. connection->SmbSecuritySignatureIndex++;
  1033. //
  1034. // And if we don't have a CANCEL smb, save the response
  1035. // security signature index. We skip this for CANCEL, because
  1036. // CANCEL has no response SMB
  1037. //
  1038. if( ((PSMB_HEADER)Tsdu)->Command != SMB_COM_NT_CANCEL ) {
  1039. workContext->ResponseSmbSecuritySignatureIndex =
  1040. connection->SmbSecuritySignatureIndex++;
  1041. }
  1042. }
  1043. //
  1044. // If the entire SMB has been received, and it is completely
  1045. // within the indicated data, copy it directly into the
  1046. // buffer, avoiding the overhead of passing an IRP down to
  1047. // the transport.
  1048. //
  1049. if ( ((ReceiveFlags & TDI_RECEIVE_ENTIRE_MESSAGE) != 0) &&
  1050. (BytesIndicated == BytesAvailable) &&
  1051. BytesAvailable <= workContext->RequestBuffer->BufferLength ) {
  1052. TdiCopyLookaheadData(
  1053. workContext->RequestBuffer->Buffer,
  1054. Tsdu,
  1055. BytesIndicated,
  1056. ReceiveFlags
  1057. );
  1058. #if SRVDBG_STATS2
  1059. IndicationsCopied++;
  1060. #endif
  1061. //
  1062. // Pretend the transport completed an IRP by doing what
  1063. // the restart routine, which is known to be
  1064. // SrvQueueWorkToFspAtDpcLevel, would do.
  1065. //
  1066. irp->IoStatus.Status = STATUS_SUCCESS;
  1067. irp->IoStatus.Information = BytesIndicated;
  1068. irp->Cancel = FALSE;
  1069. IF_DEBUG(FSD2) {
  1070. KdPrint(( "FSD working on work context 0x%p", workContext ));
  1071. }
  1072. ASSERT( workContext->FsdRestartRoutine == SrvQueueWorkToFspAtDpcLevel );
  1073. //
  1074. // *** THE FOLLOWING IS COPIED FROM SrvQueueWorkToFspAtDpcLevel.
  1075. //
  1076. // Increment the processing count.
  1077. //
  1078. workContext->ProcessingCount++;
  1079. //
  1080. // Insert the work item at the tail of the nonblocking
  1081. // work queue.
  1082. //
  1083. SrvInsertWorkQueueTail(
  1084. workContext->CurrentWorkQueue,
  1085. (PQUEUEABLE_BLOCK_HEADER)workContext
  1086. );
  1087. //
  1088. // Tell the transport that we copied the data.
  1089. //
  1090. *BytesTaken = BytesIndicated;
  1091. *IoRequestPacket = NULL;
  1092. status = STATUS_SUCCESS;
  1093. } else {
  1094. PTDI_REQUEST_KERNEL_RECEIVE parameters;
  1095. #if SRVDBG_STATS2
  1096. IndicationsNotCopied++;
  1097. #endif
  1098. *BytesTaken = 0;
  1099. receiveLength = workContext->RequestBuffer->BufferLength;
  1100. mdl = workContext->RequestBuffer->Mdl;
  1101. //
  1102. // We can't copy the indicated data. Set up the receive
  1103. // IRP.
  1104. //
  1105. irp->Tail.Overlay.OriginalFileObject = NULL;
  1106. irp->Tail.Overlay.Thread = queue->IrpThread;
  1107. DEBUG irp->RequestorMode = KernelMode;
  1108. //
  1109. // Get a pointer to the next stack location. This one is used to
  1110. // hold the parameters for the device I/O control request.
  1111. //
  1112. irpSp = IoGetNextIrpStackLocation( irp );
  1113. //
  1114. // Set up the completion routine.
  1115. //
  1116. IoSetCompletionRoutine(
  1117. irp,
  1118. SrvFsdIoCompletionRoutine,
  1119. workContext,
  1120. TRUE,
  1121. TRUE,
  1122. TRUE
  1123. );
  1124. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1125. irpSp->MinorFunction = (UCHAR)TDI_RECEIVE;
  1126. //
  1127. // Copy the caller's parameters to the service-specific portion of the
  1128. // IRP for those parameters that are the same for all three methods.
  1129. //
  1130. parameters = (PTDI_REQUEST_KERNEL_RECEIVE)&irpSp->Parameters;
  1131. parameters->ReceiveLength = receiveLength;
  1132. parameters->ReceiveFlags = 0;
  1133. irp->MdlAddress = mdl;
  1134. irp->AssociatedIrp.SystemBuffer = NULL;
  1135. //
  1136. // Make the next stack location current. Normally
  1137. // IoCallDriver would do this, but since we're bypassing
  1138. // that, we do it directly. Load the target device
  1139. // object address into the stack location. This
  1140. // especially important because the server likes to
  1141. // reuse IRPs.
  1142. //
  1143. irpSp->Flags = 0;
  1144. irpSp->DeviceObject = connection->DeviceObject;
  1145. irpSp->FileObject = connection->FileObject;
  1146. IoSetNextIrpStackLocation( irp );
  1147. ASSERT( irp->StackCount >= irpSp->DeviceObject->StackSize );
  1148. //
  1149. // Return STATUS_MORE_PROCESSING_REQUIRED so that the
  1150. // transport provider will use our IRP to service the
  1151. // receive.
  1152. //
  1153. *IoRequestPacket = irp;
  1154. status = STATUS_MORE_PROCESSING_REQUIRED;
  1155. }
  1156. } else {
  1157. //
  1158. // No preformatted work items are available. Mark the
  1159. // connection, put it on a queue of connections waiting for
  1160. // work items, and wake up the resource thread so that it
  1161. // can format some more work items and service pended
  1162. // connections.
  1163. //
  1164. INTERNAL_ERROR(
  1165. ERROR_LEVEL_EXPECTED,
  1166. "SrvFsdTdiReceiveHandler: no receive work items available",
  1167. NULL,
  1168. NULL
  1169. );
  1170. connection->NoResponseSignatureIndex =
  1171. (((PSMB_HEADER)Tsdu)->Command == SMB_COM_NT_CANCEL);
  1172. //
  1173. // Remember the amount of data available, so we can set it
  1174. // in the workcontext when we eventually find one to use
  1175. //
  1176. connection->BytesAvailable = BytesAvailable;
  1177. // If we've been under DOS attacks recently, queue a tear-down
  1178. if( SrvDoSWorkItemTearDown > SRV_DOS_TEARDOWN_MIN )
  1179. {
  1180. SrvCheckForAndQueueDoS( queue );
  1181. }
  1182. (VOID)SrvAddToNeedResourceQueue( connection, ReceivePending, NULL );
  1183. status = STATUS_DATA_NOT_ACCEPTED;
  1184. }
  1185. }
  1186. if ( !(ReceiveFlags & TDI_RECEIVE_AT_DISPATCH_LEVEL) ) {
  1187. KeLowerIrql( oldIrql );
  1188. }
  1189. } else {
  1190. //
  1191. // The connection is not active. Ignore this message.
  1192. //
  1193. status = STATUS_DATA_NOT_ACCEPTED;
  1194. }
  1195. return status;
  1196. } // SrvFsdTdiReceiveHandler
  1197. VOID
  1198. SrvPnpBindingHandler(
  1199. IN TDI_PNP_OPCODE PnPOpcode,
  1200. IN PUNICODE_STRING DeviceName,
  1201. IN PWSTR MultiSZBindList
  1202. )
  1203. {
  1204. KAPC_STATE ApcState;
  1205. BOOLEAN Attached = FALSE;
  1206. PAGED_CODE();
  1207. switch( PnPOpcode ) {
  1208. case TDI_PNP_OP_DEL:
  1209. case TDI_PNP_OP_ADD:
  1210. case TDI_PNP_OP_UPDATE:
  1211. IF_DEBUG( PNP ) {
  1212. KdPrint(("SRV: SrvPnpBindingHandler( %wZ, %u ) entered\n", DeviceName, PnPOpcode ));
  1213. }
  1214. if( IoGetCurrentProcess() != SrvServerProcess ) {
  1215. IF_DEBUG( PNP ) {
  1216. KdPrint(("SRV: attach to system process\n" ));
  1217. }
  1218. FsRtlEnterFileSystem();
  1219. KeStackAttachProcess( SrvServerProcess, &ApcState );
  1220. Attached = TRUE;
  1221. }
  1222. if ((PnPOpcode == TDI_PNP_OP_DEL) ||
  1223. (PnPOpcode == TDI_PNP_OP_ADD)) {
  1224. SrvXsPnpOperation( DeviceName, (BOOLEAN)(PnPOpcode == TDI_PNP_OP_ADD) );
  1225. }
  1226. SrvpNotifyChangesToNetBt(PnPOpcode,DeviceName,MultiSZBindList);
  1227. if( Attached == TRUE ) {
  1228. KeUnstackDetachProcess( &ApcState );
  1229. FsRtlExitFileSystem();
  1230. }
  1231. IF_DEBUG( PNP ) {
  1232. KdPrint(("SRV: SrvPnpBindingHandler( %p, %u ) returning\n", DeviceName, PnPOpcode ));
  1233. }
  1234. break;
  1235. default:
  1236. break;
  1237. }
  1238. }
  1239. //
  1240. // This routine can not be pageable, since the set power state calls can
  1241. // come through with the disk already disabled. We need to make sure that
  1242. // no pageable code is invoked. Fortunately, we don't need to do anything
  1243. // on a set power state
  1244. //
  1245. NTSTATUS
  1246. SrvPnpPowerHandler(
  1247. IN PUNICODE_STRING DeviceName,
  1248. IN PNET_PNP_EVENT PnPEvent,
  1249. IN PTDI_PNP_CONTEXT Context1,
  1250. IN PTDI_PNP_CONTEXT Context2
  1251. )
  1252. {
  1253. NET_DEVICE_POWER_STATE powerState;
  1254. NTSTATUS status = STATUS_SUCCESS;
  1255. PLIST_ENTRY listEntry;
  1256. IF_DEBUG( PNP ) {
  1257. KdPrint(( "SRV: SrvPnpPowerHandler( %wZ, %u )\n", DeviceName, PnPEvent->NetEvent ));
  1258. }
  1259. switch( PnPEvent->NetEvent ) {
  1260. case NetEventQueryPower:
  1261. if( PnPEvent->BufferLength != sizeof( powerState ) ) {
  1262. IF_DEBUG( ERRORS ) {
  1263. KdPrint(( "SRV: NetEventQueryPower BufferLength %u (should be %u)\n",
  1264. PnPEvent->BufferLength, sizeof( powerState ) ));
  1265. }
  1266. break;
  1267. }
  1268. powerState = *(PNET_DEVICE_POWER_STATE)(PnPEvent->Buffer);
  1269. //
  1270. // Powering up is always OK!
  1271. //
  1272. if( powerState == NetDeviceStateD0 ) {
  1273. break;
  1274. }
  1275. //
  1276. // Lack of break is intentional
  1277. //
  1278. case NetEventQueryRemoveDevice:
  1279. //
  1280. // The following code is disabled, because we couldn't come up with a reasonable
  1281. // way to present UI to the user on failure. We know this leg of the code is only
  1282. // executed when the user specifically wants to standby the system or remove a device.
  1283. // The analogy is that of a TV set -- if the user wants to turn off the system, then who
  1284. // are we to say "no"?
  1285. //
  1286. // If this is really the decision, then IMHO the system shouldn't even ask us. But
  1287. // that's a battle long lost.
  1288. //
  1289. #if 0
  1290. //
  1291. // Run through the endpoints using this device. If any clients are
  1292. // connected, refuse the change.
  1293. //
  1294. ACQUIRE_LOCK( &SrvEndpointLock );
  1295. listEntry = SrvEndpointList.ListHead.Flink;
  1296. while( listEntry != &SrvEndpointList.ListHead ) {
  1297. PENDPOINT endpoint = CONTAINING_RECORD( listEntry,
  1298. ENDPOINT,
  1299. GlobalEndpointListEntry
  1300. );
  1301. if( GET_BLOCK_STATE( endpoint ) == BlockStateActive &&
  1302. RtlEqualUnicodeString( DeviceName, &endpoint->TransportName, TRUE ) ) {
  1303. USHORT index = (USHORT)-1;
  1304. PCONNECTION connection = WalkConnectionTable( endpoint, &index );
  1305. if( connection != NULL ) {
  1306. IF_DEBUG( PNP ) {
  1307. KdPrint((" Endpoint %X, Connection %X\n", endpoint, connection ));
  1308. KdPrint((" SRV rejects power down request!\n" ));
  1309. }
  1310. //
  1311. // We have found a connected client. Cannot allow powerdown.
  1312. //
  1313. SrvDereferenceConnection( connection );
  1314. status = STATUS_UNSUCCESSFUL;
  1315. break;
  1316. }
  1317. }
  1318. listEntry = listEntry->Flink;
  1319. }
  1320. RELEASE_LOCK( &SrvEndpointLock );
  1321. #endif
  1322. break;
  1323. }
  1324. IF_DEBUG( PNP ) {
  1325. KdPrint(( " SrvPnpPowerHandler status %X\n", status ));
  1326. }
  1327. return status;
  1328. }
  1329. PWORK_CONTEXT SRVFASTCALL
  1330. SrvFsdGetReceiveWorkItem (
  1331. IN PWORK_QUEUE queue
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This function removes a receive work item from the free queue. It can
  1336. be called at either Passive or DPC level
  1337. Arguments:
  1338. None.
  1339. Return Value:
  1340. PWORK_CONTEXT - A pointer to a WORK_CONTEXT structure,
  1341. or NULL if none exists.
  1342. --*/
  1343. {
  1344. PSLIST_ENTRY listEntry;
  1345. PWORK_CONTEXT workContext;
  1346. ULONG i;
  1347. KIRQL oldIrql;
  1348. NTSTATUS Status;
  1349. BOOLEAN AllocFailed = FALSE;
  1350. ASSERT( queue >= SrvWorkQueues && queue < eSrvWorkQueues );
  1351. //
  1352. // Try to get a work context block from the initial work queue first.
  1353. // If this fails, try the normal work queue. If this fails, try to allocate
  1354. // one. If we still failed, schedule a worker thread to allocate some later.
  1355. //
  1356. listEntry = ExInterlockedPopEntrySList( &queue->InitialWorkItemList, &queue->SpinLock );
  1357. if ( listEntry == NULL ) {
  1358. listEntry = ExInterlockedPopEntrySList( &queue->NormalWorkItemList, &queue->SpinLock );
  1359. if( listEntry == NULL ) {
  1360. IF_DEBUG( WORKITEMS ) {
  1361. KdPrint(("No workitems for queue %p\n", (PVOID)(queue-SrvWorkQueues) ));
  1362. }
  1363. Status = SrvAllocateNormalWorkItem( &workContext, queue );
  1364. if( workContext != NULL ) {
  1365. IF_DEBUG( WORKITEMS ) {
  1366. KdPrint(("SrvFsdGetReceiveWorkItem: new work context %p\n",
  1367. workContext ));
  1368. }
  1369. SrvPrepareReceiveWorkItem( workContext, FALSE );
  1370. INITIALIZE_WORK_CONTEXT( queue, workContext );
  1371. return workContext;
  1372. }
  1373. else
  1374. {
  1375. if( Status == STATUS_INSUFFICIENT_RESOURCES )
  1376. {
  1377. AllocFailed = TRUE;
  1378. }
  1379. }
  1380. //
  1381. // Before we steal from another processor, ensure that
  1382. // we're setup to replenish this exhausted free list
  1383. //
  1384. ACQUIRE_SPIN_LOCK( &queue->SpinLock, &oldIrql );
  1385. if( queue->AllocatedWorkItems < queue->MaximumWorkItems &&
  1386. GET_BLOCK_TYPE(&queue->CreateMoreWorkItems) == BlockTypeGarbage ) {
  1387. SET_BLOCK_TYPE( &queue->CreateMoreWorkItems, BlockTypeWorkContextSpecial );
  1388. queue->CreateMoreWorkItems.FspRestartRoutine = SrvServiceWorkItemShortage;
  1389. SrvInsertWorkQueueHead( queue, &queue->CreateMoreWorkItems );
  1390. }
  1391. RELEASE_SPIN_LOCK( &queue->SpinLock, oldIrql );
  1392. #if MULTIPROCESSOR
  1393. //
  1394. // We couldn't find a work item on our processor's free queue.
  1395. // See if we can steal one from another processor
  1396. //
  1397. IF_DEBUG( WORKITEMS ) {
  1398. KdPrint(("Looking for workitems on other processors\n" ));
  1399. }
  1400. //
  1401. // Look around for a workitem we can borrow
  1402. //
  1403. for( i = SrvNumberOfProcessors; i > 1; --i ) {
  1404. if( ++queue == eSrvWorkQueues )
  1405. queue = SrvWorkQueues;
  1406. listEntry = ExInterlockedPopEntrySList( &queue->InitialWorkItemList,
  1407. &queue->SpinLock );
  1408. if( listEntry == NULL ) {
  1409. listEntry = ExInterlockedPopEntrySList( &queue->NormalWorkItemList,
  1410. &queue->SpinLock );
  1411. if( listEntry == NULL ) {
  1412. Status = SrvAllocateNormalWorkItem( &workContext, queue );
  1413. if( workContext != NULL ) {
  1414. //
  1415. // Got a workItem from another processor's queue!
  1416. //
  1417. ++(queue->StolenWorkItems);
  1418. IF_DEBUG( WORKITEMS ) {
  1419. KdPrint(("SrvFsdGetReceiveWorkItem: new work context %p\n",
  1420. workContext ));
  1421. }
  1422. SrvPrepareReceiveWorkItem( workContext, FALSE );
  1423. INITIALIZE_WORK_CONTEXT( queue, workContext );
  1424. return workContext;
  1425. }
  1426. else
  1427. {
  1428. if( Status == STATUS_INSUFFICIENT_RESOURCES )
  1429. {
  1430. AllocFailed = TRUE;
  1431. }
  1432. }
  1433. //
  1434. // Make sure this processor knows it is low on workitems
  1435. //
  1436. ACQUIRE_SPIN_LOCK( &queue->SpinLock, &oldIrql );
  1437. if( queue->AllocatedWorkItems < queue->MaximumWorkItems &&
  1438. GET_BLOCK_TYPE(&queue->CreateMoreWorkItems) == BlockTypeGarbage ) {
  1439. SET_BLOCK_TYPE( &queue->CreateMoreWorkItems,
  1440. BlockTypeWorkContextSpecial );
  1441. queue->CreateMoreWorkItems.FspRestartRoutine
  1442. = SrvServiceWorkItemShortage;
  1443. SrvInsertWorkQueueHead( queue, &queue->CreateMoreWorkItems );
  1444. }
  1445. RELEASE_SPIN_LOCK( &queue->SpinLock, oldIrql );
  1446. continue;
  1447. }
  1448. }
  1449. //
  1450. // Got a workItem from another processor's queue!
  1451. //
  1452. ++(queue->StolenWorkItems);
  1453. break;
  1454. }
  1455. #endif
  1456. if( listEntry == NULL ) {
  1457. //
  1458. // We didn't have any free workitems on our queue, and
  1459. // we couldn't borrow a workitem from another processor.
  1460. // Give up!
  1461. //
  1462. IF_DEBUG( WORKITEMS ) {
  1463. KdPrint(("No workitems anywhere!\n" ));
  1464. }
  1465. ++SrvStatistics.WorkItemShortages;
  1466. if( !AllocFailed )
  1467. {
  1468. SrvCheckForAndQueueDoS( queue );
  1469. }
  1470. return NULL;
  1471. }
  1472. }
  1473. }
  1474. //
  1475. // We've successfully gotten a free workitem of a processor's queue.
  1476. // (it may not be our processor).
  1477. //
  1478. IF_DEBUG( WORKITEMS ) {
  1479. if( queue != PROCESSOR_TO_QUEUE() ) {
  1480. KdPrint(("\tGot WORK_ITEM from processor %p\n" , (PVOID)(queue - SrvWorkQueues) ));
  1481. }
  1482. }
  1483. //
  1484. // Decrement the count of free receive work items.
  1485. //
  1486. InterlockedDecrement( &queue->FreeWorkItems );
  1487. if( queue->FreeWorkItems < queue->MinFreeWorkItems &&
  1488. queue->AllocatedWorkItems < queue->MaximumWorkItems &&
  1489. GET_BLOCK_TYPE(&queue->CreateMoreWorkItems) == BlockTypeGarbage ) {
  1490. ACQUIRE_SPIN_LOCK( &queue->SpinLock, &oldIrql );
  1491. if( queue->FreeWorkItems < queue->MinFreeWorkItems &&
  1492. queue->AllocatedWorkItems < queue->MaximumWorkItems &&
  1493. GET_BLOCK_TYPE(&queue->CreateMoreWorkItems) == BlockTypeGarbage ) {
  1494. //
  1495. // We're running short of free workitems. Queue a request to
  1496. // allocate more of them.
  1497. //
  1498. SET_BLOCK_TYPE( &queue->CreateMoreWorkItems, BlockTypeWorkContextSpecial );
  1499. queue->CreateMoreWorkItems.FspRestartRoutine = SrvServiceWorkItemShortage;
  1500. SrvInsertWorkQueueHead( queue, &queue->CreateMoreWorkItems );
  1501. }
  1502. RELEASE_SPIN_LOCK( &queue->SpinLock, oldIrql );
  1503. }
  1504. workContext = CONTAINING_RECORD( listEntry, WORK_CONTEXT, SingleListEntry );
  1505. ASSERT( workContext->BlockHeader.ReferenceCount == 0 );
  1506. ASSERT( workContext->CurrentWorkQueue != NULL );
  1507. INITIALIZE_WORK_CONTEXT( queue, workContext );
  1508. return workContext;
  1509. } // SrvFsdGetReceiveWorkItem
  1510. VOID SRVFASTCALL
  1511. SrvFsdRequeueReceiveWorkItem (
  1512. IN OUT PWORK_CONTEXT WorkContext
  1513. )
  1514. /*++
  1515. Routine Description:
  1516. This routine requeues a Receive work item to the queue in the server
  1517. FSD device object. This routine is called when processing of a
  1518. receive work item is done.
  1519. Arguments:
  1520. WorkContext - Supplies a pointer to the work context block associated
  1521. with the receive buffer and IRP. The following fields must be
  1522. valid:
  1523. Connection
  1524. TdiRequest
  1525. Irp
  1526. RequestBuffer
  1527. RequestBuffer->BufferLength
  1528. RequestBuffer->Mdl
  1529. Return Value:
  1530. None.
  1531. --*/
  1532. {
  1533. PCONNECTION connection;
  1534. PSMB_HEADER header;
  1535. KIRQL oldIrql;
  1536. PBUFFER requestBuffer;
  1537. IF_DEBUG(TRACE2) KdPrint(( "SrvFsdRequeueReceiveWorkItem entered\n" ));
  1538. IF_DEBUG(NET2) {
  1539. KdPrint(( " Work context %p, request buffer %p\n",
  1540. WorkContext, WorkContext->RequestBuffer ));
  1541. KdPrint(( " IRP %p, MDL %p\n",
  1542. WorkContext->Irp, WorkContext->RequestBuffer->Mdl ));
  1543. }
  1544. //
  1545. // Save the connection pointer before reinitializing the work item.
  1546. //
  1547. connection = WorkContext->Connection;
  1548. ASSERT( connection != NULL );
  1549. ASSERT( WorkContext->Share == NULL );
  1550. ASSERT( WorkContext->Session == NULL );
  1551. ASSERT( WorkContext->TreeConnect == NULL );
  1552. ASSERT( WorkContext->Rfcb == NULL );
  1553. //
  1554. // Reset the IRP cancelled bit, in case it was set during
  1555. // operation.
  1556. //
  1557. WorkContext->Irp->Cancel = FALSE;
  1558. //
  1559. // Set up the restart routine in the work context.
  1560. //
  1561. WorkContext->FsdRestartRoutine = SrvQueueWorkToFspAtDpcLevel;
  1562. WorkContext->FspRestartRoutine = SrvRestartReceive;
  1563. //
  1564. // Make sure the length specified in the MDL is correct -- it may
  1565. // have changed while sending a response to the previous request.
  1566. // Call an I/O subsystem routine to build the I/O request packet.
  1567. //
  1568. requestBuffer = WorkContext->RequestBuffer;
  1569. requestBuffer->Mdl->ByteCount = requestBuffer->BufferLength;
  1570. //
  1571. // Replace the Response buffer.
  1572. //
  1573. WorkContext->ResponseBuffer = requestBuffer;
  1574. header = (PSMB_HEADER)requestBuffer->Buffer;
  1575. //WorkContext->RequestHeader = header;
  1576. ASSERT( WorkContext->RequestHeader == header );
  1577. WorkContext->ResponseHeader = header;
  1578. WorkContext->ResponseParameters = (PVOID)(header + 1);
  1579. WorkContext->RequestParameters = (PVOID)(header + 1);
  1580. //
  1581. // Initialize this to zero so this will not be mistakenly cancelled
  1582. // by SrvSmbNtCancel.
  1583. //
  1584. SmbPutAlignedUshort( &WorkContext->RequestHeader->Uid, (USHORT)0 );
  1585. //
  1586. // Remove the work item from the in-progress list.
  1587. //
  1588. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1589. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1590. SrvRemoveEntryList(
  1591. &connection->InProgressWorkItemList,
  1592. &WorkContext->InProgressListEntry
  1593. );
  1594. connection->InProgressWorkContextCount--;
  1595. //
  1596. // Attempt to dereference the connection.
  1597. //
  1598. if ( --connection->BlockHeader.ReferenceCount == 0 ) {
  1599. //
  1600. // The refcount went to zero. We can't handle this with the
  1601. // spin lock held. Reset the refcount, then release the lock,
  1602. // then check to see whether we can continue here.
  1603. //
  1604. connection->BlockHeader.ReferenceCount++;
  1605. //
  1606. // We're in the FSD, so we can't do this here. We need
  1607. // to tell our caller this.
  1608. //
  1609. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1610. //
  1611. // orphaned. Send to Boys Town.
  1612. //
  1613. DispatchToOrphanage( (PVOID)connection );
  1614. connection = NULL;
  1615. } else {
  1616. UPDATE_REFERENCE_HISTORY( connection, TRUE );
  1617. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock );
  1618. }
  1619. KeLowerIrql( oldIrql );
  1620. //
  1621. // Requeue the work item.
  1622. //
  1623. RETURN_FREE_WORKITEM( WorkContext );
  1624. return;
  1625. } // SrvFsdRequeueReceiveWorkItem
  1626. NTSTATUS
  1627. SrvFsdRestartSendOplockIItoNone(
  1628. IN PDEVICE_OBJECT DeviceObject,
  1629. IN PIRP Irp,
  1630. IN OUT PWORK_CONTEXT WorkContext
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This routine is the send completion routine for oplock breaks from
  1635. II to None. This is handled differently from other oplock breaks
  1636. in that we don't queue it to the OplockBreaksInProgressList but
  1637. increment our count so we will not have raw reads while this is
  1638. being sent.
  1639. This is done in such a manner as to be safe at DPC level.
  1640. Arguments:
  1641. DeviceObject - Pointer to target device object for the request.
  1642. Irp - Pointer to I/O request packet
  1643. WorkContext - Caller-specified context parameter associated with IRP.
  1644. This is actually a pointer to a Work Context block.
  1645. Return Value:
  1646. None.
  1647. --*/
  1648. {
  1649. KIRQL oldIrql;
  1650. PCONNECTION connection;
  1651. UNLOCKABLE_CODE( 8FIL );
  1652. IF_DEBUG(OPLOCK) {
  1653. KdPrint(("SrvFsdRestartSendOplockIItoNone: Oplock send complete.\n"));
  1654. }
  1655. //
  1656. // Check the status of the send completion.
  1657. //
  1658. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  1659. //
  1660. // Reset the IRP cancelled bit.
  1661. //
  1662. Irp->Cancel = FALSE;
  1663. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1664. //
  1665. // Mark the connection to indicate that we just sent a break II to
  1666. // none. If the next SMB received is a raw read, we will return a
  1667. // zero-byte send. This is necessary because the client doesn't
  1668. // respond to this break, so we don't really know when they've
  1669. // received it. But when we receive an SMB, we know that they've
  1670. // gotten it. Note that a non-raw SMB could be on its way when we
  1671. // send the break, and we'll clear the flag, but since the client
  1672. // needs to lock the VC to do the raw read, it must receive the SMB
  1673. // response (and hence the oplock break) before it can send the raw
  1674. // read. If a raw read crosses with the oplock break, it will be
  1675. // rejected because the OplockBreaksInProgress count is nonzero.
  1676. //
  1677. connection = WorkContext->Connection;
  1678. connection->BreakIIToNoneJustSent = TRUE;
  1679. ExInterlockedAddUlong(
  1680. &connection->OplockBreaksInProgress,
  1681. (ULONG)-1,
  1682. connection->EndpointSpinLock
  1683. );
  1684. SrvFsdRestartSmbComplete( WorkContext );
  1685. KeLowerIrql( oldIrql );
  1686. return(STATUS_MORE_PROCESSING_REQUIRED);
  1687. } // SrvFsdRestartSendOplockIItoNone
  1688. VOID SRVFASTCALL
  1689. SrvFsdRestartSmbComplete (
  1690. IN OUT PWORK_CONTEXT WorkContext
  1691. )
  1692. /*++
  1693. Routine Description:
  1694. This routine is called when all request processing on an SMB is
  1695. complete, including sending a response, if any. This routine
  1696. dereferences control blocks and requeues the work item to the
  1697. receive work item list.
  1698. This is done in such a manner as to be safe at DPC level.
  1699. Arguments:
  1700. WorkContext - Supplies a pointer to the work context block
  1701. containing information about the SMB.
  1702. Return Value:
  1703. None.
  1704. --*/
  1705. {
  1706. PRFCB rfcb;
  1707. ULONG oldCount;
  1708. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  1709. IF_DEBUG(FSD2) KdPrint(( "SrvFsdRestartSmbComplete entered\n" ));
  1710. //
  1711. // If we may have backlogged oplock breaks to send, do the work
  1712. // in the FSP.
  1713. //
  1714. if ( WorkContext->OplockOpen ) {
  1715. goto queueToFsp;
  1716. }
  1717. //
  1718. // Attempt to dereference the file block.
  1719. //
  1720. rfcb = WorkContext->Rfcb;
  1721. if ( rfcb != NULL ) {
  1722. oldCount = ExInterlockedAddUlong(
  1723. &rfcb->BlockHeader.ReferenceCount,
  1724. (ULONG)-1,
  1725. &rfcb->Connection->SpinLock
  1726. );
  1727. UPDATE_REFERENCE_HISTORY( rfcb, TRUE );
  1728. if ( oldCount == 1 ) {
  1729. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  1730. (VOID) ExInterlockedAddUlong(
  1731. &rfcb->BlockHeader.ReferenceCount,
  1732. (ULONG) 1,
  1733. &rfcb->Connection->SpinLock
  1734. );
  1735. goto queueToFsp;
  1736. }
  1737. WorkContext->Rfcb = NULL;
  1738. }
  1739. //
  1740. // If this was a blocking operation, update the blocking i/o count.
  1741. //
  1742. if ( WorkContext->BlockingOperation ) {
  1743. InterlockedDecrement( &SrvBlockingOpsInProgress );
  1744. WorkContext->BlockingOperation = FALSE;
  1745. }
  1746. //
  1747. // !!! Need to handle failure of response send -- kill connection?
  1748. //
  1749. //
  1750. // Attempt to dereference the work item. This will fail (and
  1751. // automatically be queued to the FSP) if it cannot be done from
  1752. // within the FSD.
  1753. //
  1754. SrvFsdDereferenceWorkItem( WorkContext );
  1755. return;
  1756. queueToFsp:
  1757. //
  1758. // We were unable to do all the necessary cleanup at DPC level.
  1759. // Queue the work item to the FSP.
  1760. //
  1761. WorkContext->FspRestartRoutine = SrvRestartFsdComplete;
  1762. SrvQueueWorkToFspAtDpcLevel( WorkContext );
  1763. IF_DEBUG(FSD2) KdPrint(( "SrvFsdRestartSmbComplete complete\n" ));
  1764. return;
  1765. } // SrvFsdRestartSmbComplete
  1766. NTSTATUS
  1767. SrvFsdRestartSmbAtSendCompletion (
  1768. IN PDEVICE_OBJECT DeviceObject OPTIONAL,
  1769. IN PIRP Irp,
  1770. IN PWORK_CONTEXT WorkContext
  1771. )
  1772. /*++
  1773. Routine Description:
  1774. Send completion routine for all request processing on an SMB is
  1775. complete, including sending a response, if any. This routine
  1776. dereferences control blocks and requeues the work item to the
  1777. receive work item list.
  1778. This is done in such a manner as to be safe at DPC level.
  1779. Arguments:
  1780. DeviceObject - Pointer to target device object for the request.
  1781. Irp - Pointer to I/O request packet
  1782. WorkContext - Caller-specified context parameter associated with IRP.
  1783. This is actually a pointer to a Work Context block.
  1784. Return Value:
  1785. None.
  1786. --*/
  1787. {
  1788. PRFCB rfcb;
  1789. KIRQL oldIrql;
  1790. ULONG oldCount;
  1791. IF_DEBUG(FSD2)KdPrint(( "SrvFsdRestartSmbComplete entered\n" ));
  1792. //
  1793. // Check the status of the send completion.
  1794. //
  1795. CHECK_SEND_COMPLETION_STATUS( Irp->IoStatus.Status );
  1796. //
  1797. // Reset the IRP cancelled bit.
  1798. //
  1799. Irp->Cancel = FALSE;
  1800. //
  1801. // Free any associated buffers
  1802. //
  1803. if( Irp->AssociatedIrp.SystemBuffer != NULL &&
  1804. (Irp->Flags & IRP_DEALLOCATE_BUFFER) ) {
  1805. ExFreePool( Irp->AssociatedIrp.SystemBuffer );
  1806. Irp->AssociatedIrp.SystemBuffer = NULL;
  1807. Irp->Flags &= ~IRP_DEALLOCATE_BUFFER;
  1808. }
  1809. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1810. //
  1811. // If we may have backlogged oplock breaks to send, do the work
  1812. // in the FSP.
  1813. //
  1814. if ( WorkContext->OplockOpen ) {
  1815. goto queueToFsp;
  1816. }
  1817. //
  1818. // Attempt to dereference the file block. We can do this without acquiring
  1819. // SrvFsdSpinlock around the decrement/increment pair since the ref
  1820. // count cannot be zero unless the rfcb is closed and we are the last
  1821. // reference to it. None of our code references the rfcb when it has been
  1822. // closed.
  1823. //
  1824. rfcb = WorkContext->Rfcb;
  1825. if ( rfcb != NULL ) {
  1826. oldCount = ExInterlockedAddUlong(
  1827. &rfcb->BlockHeader.ReferenceCount,
  1828. (ULONG)-1,
  1829. &rfcb->Connection->SpinLock
  1830. );
  1831. UPDATE_REFERENCE_HISTORY( rfcb, TRUE );
  1832. if ( oldCount == 1 ) {
  1833. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  1834. (VOID) ExInterlockedAddUlong(
  1835. &rfcb->BlockHeader.ReferenceCount,
  1836. (ULONG) 1,
  1837. &rfcb->Connection->SpinLock
  1838. );
  1839. goto queueToFsp;
  1840. }
  1841. WorkContext->Rfcb = NULL;
  1842. }
  1843. //
  1844. // If this was a blocking operation, update the blocking i/o count.
  1845. //
  1846. if ( WorkContext->BlockingOperation ) {
  1847. InterlockedDecrement( &SrvBlockingOpsInProgress );
  1848. WorkContext->BlockingOperation = FALSE;
  1849. }
  1850. //
  1851. // !!! Need to handle failure of response send -- kill connection?
  1852. //
  1853. //
  1854. // Attempt to dereference the work item. This will fail (and
  1855. // automatically be queued to the FSP) if it cannot be done from
  1856. // within the FSD.
  1857. //
  1858. SrvFsdDereferenceWorkItem( WorkContext );
  1859. KeLowerIrql( oldIrql );
  1860. return(STATUS_MORE_PROCESSING_REQUIRED);
  1861. queueToFsp:
  1862. //
  1863. // We were unable to do all the necessary cleanup at DPC level.
  1864. // Queue the work item to the FSP.
  1865. //
  1866. WorkContext->FspRestartRoutine = SrvRestartFsdComplete;
  1867. SrvQueueWorkToFspAtDpcLevel( WorkContext );
  1868. KeLowerIrql( oldIrql );
  1869. IF_DEBUG(FSD2) KdPrint(( "SrvFsdRestartSmbComplete complete\n" ));
  1870. return(STATUS_MORE_PROCESSING_REQUIRED);
  1871. } // SrvFsdRestartSmbAtSendCompletion
  1872. VOID
  1873. SrvFsdServiceNeedResourceQueue (
  1874. IN PWORK_CONTEXT *WorkContext,
  1875. IN PKIRQL OldIrql
  1876. )
  1877. /*++
  1878. Routine Description:
  1879. This function attempts to service a receive pending by creating
  1880. a new SMB buffer and passing it on to the transport provider.
  1881. *** SrvFsdSpinLock held when called. Held on exit ***
  1882. *** EndpointSpinLock held when called. Held on exit ***
  1883. Arguments:
  1884. WorkContext - A pointer to the work context block that will be used
  1885. to service the connection. If the work context supplied
  1886. was used, a null will be returned here.
  1887. *** The workcontext block must be referencing the
  1888. connection on entry. ***
  1889. OldIrql -
  1890. Return Value:
  1891. TRUE, if there is still work left for this connection.
  1892. FALSE, otherwise.
  1893. --*/
  1894. {
  1895. PIO_STACK_LOCATION irpSp;
  1896. PIRP irp;
  1897. PWORK_CONTEXT workContext = *WorkContext;
  1898. PCONNECTION connection = workContext->Connection;
  1899. IF_DEBUG( OPLOCK ) {
  1900. KdPrint(("SrvFsdServiceNeedResourceQueue: entered. WorkContext %p , Connection = %p.\n", workContext, connection ));
  1901. }
  1902. //
  1903. // If there are any oplock break sends pending, supply the WCB.
  1904. //
  1905. restart:
  1906. if ( !IsListEmpty( &connection->OplockWorkList ) ) {
  1907. PLIST_ENTRY listEntry;
  1908. PRFCB rfcb;
  1909. //
  1910. // Dequeue the oplock context from the list of pending oplock
  1911. // sends.
  1912. //
  1913. listEntry = RemoveHeadList( &connection->OplockWorkList );
  1914. rfcb = CONTAINING_RECORD( listEntry, RFCB, ListEntry );
  1915. #if DBG
  1916. rfcb->ListEntry.Flink = rfcb->ListEntry.Blink = NULL;
  1917. #endif
  1918. IF_DEBUG( OPLOCK ) {
  1919. KdPrint(("SrvFsdServiceNeedResourceQueue: rfcb %p removed from OplockWorkList.\n", rfcb ));
  1920. }
  1921. //
  1922. // The connection spinlock guards the rfcb block header.
  1923. //
  1924. ACQUIRE_DPC_SPIN_LOCK( &connection->SpinLock);
  1925. if ( GET_BLOCK_STATE( rfcb ) != BlockStateActive ) {
  1926. //
  1927. // This file is closing, don't bother send the oplock break
  1928. //
  1929. // Attempt to dereference the file block.
  1930. //
  1931. IF_DEBUG( OPLOCK ) {
  1932. KdPrint(("SrvFsdServiceNeedResourceQueue: rfcb %p closing.\n", rfcb));
  1933. }
  1934. UPDATE_REFERENCE_HISTORY( rfcb, TRUE );
  1935. connection->OplockBreaksInProgress--;
  1936. if ( --rfcb->BlockHeader.ReferenceCount == 0 ) {
  1937. //
  1938. // Put the work item on the in-progress list.
  1939. //
  1940. SrvInsertTailList(
  1941. &connection->InProgressWorkItemList,
  1942. &workContext->InProgressListEntry
  1943. );
  1944. connection->InProgressWorkContextCount++;
  1945. UPDATE_REFERENCE_HISTORY( rfcb, FALSE );
  1946. rfcb->BlockHeader.ReferenceCount++;
  1947. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock);
  1948. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock);
  1949. RELEASE_GLOBAL_SPIN_LOCK( Fsd, *OldIrql );
  1950. //
  1951. // Send this to the Fsp
  1952. //
  1953. workContext->Rfcb = rfcb;
  1954. workContext->FspRestartRoutine = SrvRestartFsdComplete;
  1955. SrvQueueWorkToFsp( workContext );
  1956. goto exit_used;
  1957. } else {
  1958. //
  1959. // Before we get rid of the workcontext block, see
  1960. // if we need to do more work for this connection.
  1961. //
  1962. if ( !IsListEmpty(&connection->OplockWorkList) ||
  1963. connection->ReceivePending) {
  1964. IF_DEBUG( OPLOCK ) {
  1965. KdPrint(("SrvFsdServiceNeedResourceQueue: Reusing WorkContext block %p.\n", workContext ));
  1966. }
  1967. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock);
  1968. goto restart;
  1969. }
  1970. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock);
  1971. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock);
  1972. RELEASE_GLOBAL_SPIN_LOCK( Fsd, *OldIrql );
  1973. IF_DEBUG( OPLOCK ) {
  1974. KdPrint(("SrvFsdServiceNeedResourceQueue: WorkContext block not used.\n"));
  1975. }
  1976. SrvDereferenceConnection( connection );
  1977. workContext->Connection = NULL;
  1978. workContext->Endpoint = NULL;
  1979. goto exit_not_used;
  1980. }
  1981. }
  1982. RELEASE_DPC_SPIN_LOCK( &connection->SpinLock);
  1983. //
  1984. // Put the work item on the in-progress list.
  1985. //
  1986. SrvInsertTailList(
  1987. &connection->InProgressWorkItemList,
  1988. &workContext->InProgressListEntry
  1989. );
  1990. connection->InProgressWorkContextCount++;
  1991. //
  1992. // Copy the oplock work queue RFCB reference to the work
  1993. // context block. There is no need to re-reference the RFCB.
  1994. //
  1995. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock);
  1996. RELEASE_GLOBAL_SPIN_LOCK( Fsd, *OldIrql );
  1997. workContext->Rfcb = rfcb;
  1998. IF_DEBUG( OPLOCK ) {
  1999. KdPrint(("SrvFsdServiceNeedResourceQueue: Sending oplock break.\n"));
  2000. }
  2001. SrvRestartOplockBreakSend( workContext );
  2002. } else {
  2003. IF_DEBUG( OPLOCK ) {
  2004. KdPrint(("SrvFsdServiceNeedResourceQueue: Have ReceivePending.\n"));
  2005. }
  2006. //
  2007. // Offer the newly free, or newly created, SMB buffer to the
  2008. // transport to complete the receive.
  2009. //
  2010. // *** Note that the connection has already been referenced in
  2011. // SrvFsdTdiReceiveHandler.
  2012. //
  2013. connection->ReceivePending = FALSE;
  2014. //
  2015. // Check the request security signature, and calculate the response signature
  2016. //
  2017. if( connection->SmbSecuritySignatureActive ) {
  2018. //
  2019. // Save this security signature index
  2020. //
  2021. workContext->SmbSecuritySignatureIndex =
  2022. connection->SmbSecuritySignatureIndex++;
  2023. //
  2024. // Save the response signature index, if we require one
  2025. //
  2026. if( connection->NoResponseSignatureIndex == FALSE ) {
  2027. workContext->ResponseSmbSecuritySignatureIndex =
  2028. connection->SmbSecuritySignatureIndex++;
  2029. }
  2030. }
  2031. SET_OPERATION_START_TIME( &workContext );
  2032. //
  2033. // Put the work item on the in-progress list.
  2034. //
  2035. SrvInsertTailList(
  2036. &connection->InProgressWorkItemList,
  2037. &workContext->InProgressListEntry
  2038. );
  2039. connection->InProgressWorkContextCount++;
  2040. //
  2041. // Remember the amount of data that is avilable, in case it
  2042. // turns out to be a LargeIndication.
  2043. //
  2044. workContext->BytesAvailable = connection->BytesAvailable;
  2045. //
  2046. // Finish setting up the IRP. This involves putting the
  2047. // file object and device object addresses in the IRP.
  2048. //
  2049. RELEASE_DPC_SPIN_LOCK( connection->EndpointSpinLock);
  2050. RELEASE_GLOBAL_SPIN_LOCK( Fsd, *OldIrql );
  2051. irp = workContext->Irp;
  2052. //
  2053. // Build the receive irp
  2054. //
  2055. (VOID)SrvBuildIoControlRequest(
  2056. irp, // input IRP address
  2057. NULL, // target file object address
  2058. workContext, // context
  2059. IRP_MJ_INTERNAL_DEVICE_CONTROL, // major function
  2060. TDI_RECEIVE, // minor function
  2061. NULL, // input buffer address
  2062. 0, // input buffer length
  2063. workContext->RequestBuffer->Buffer, // output buffer address
  2064. workContext->RequestBuffer->BufferLength, // output buffer length
  2065. workContext->RequestBuffer->Mdl, // MDL address
  2066. NULL // completion routine
  2067. );
  2068. //
  2069. // Get a pointer to the next stack location. This one is used to
  2070. // hold the parameters for the receive request.
  2071. //
  2072. irpSp = IoGetNextIrpStackLocation( irp );
  2073. irpSp->Flags = 0;
  2074. irpSp->DeviceObject = connection->DeviceObject;
  2075. irpSp->FileObject = connection->FileObject;
  2076. ASSERT( irp->StackCount >= irpSp->DeviceObject->StackSize );
  2077. //
  2078. // Pass the SMB buffer to the driver.
  2079. //
  2080. IoCallDriver( irpSp->DeviceObject, irp );
  2081. }
  2082. exit_used:
  2083. //
  2084. // We made good use of the work context block.
  2085. //
  2086. *WorkContext = NULL;
  2087. IF_DEBUG( OPLOCK ) {
  2088. KdPrint(("SrvFsdServiceNeedResourceQueue: WorkContext block used.\n"));
  2089. }
  2090. exit_not_used:
  2091. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, OldIrql );
  2092. ACQUIRE_DPC_SPIN_LOCK( connection->EndpointSpinLock);
  2093. return;
  2094. } // SrvFsdServiceNeedResourceQueue
  2095. BOOLEAN
  2096. SrvAddToNeedResourceQueue(
  2097. IN PCONNECTION Connection,
  2098. IN RESOURCE_TYPE ResourceType,
  2099. IN PRFCB Rfcb OPTIONAL
  2100. )
  2101. /*++
  2102. Routine Description:
  2103. This function appends a connection to the need resource queue.
  2104. The connection is marked indicating what resource is needed,
  2105. and the resource thread is started to do the work.
  2106. Arguments:
  2107. Connection - The connection that need a resource.
  2108. Resource - The resource that is needed.
  2109. Rfcb - A pointer to the RFCB that needs the resource.
  2110. Return Value:
  2111. None.
  2112. --*/
  2113. {
  2114. KIRQL oldIrql;
  2115. ACQUIRE_GLOBAL_SPIN_LOCK( Fsd, &oldIrql );
  2116. ACQUIRE_DPC_SPIN_LOCK( Connection->EndpointSpinLock );
  2117. IF_DEBUG( WORKITEMS ) {
  2118. KdPrint(("SrvAddToNeedResourceQueue entered. connection = %p, type %d\n", Connection, ResourceType));
  2119. }
  2120. //
  2121. // Check again to see if the connection is closing. If it is,
  2122. // don't bother putting it on the need resource queue.
  2123. //
  2124. // *** We have to do this while holding the need-resource queue
  2125. // spin lock in order to synchronize with
  2126. // SrvCloseConnection. We don't want to queue this
  2127. // connection after SrvCloseConnection tries to take it off
  2128. // the queue.
  2129. //
  2130. if ( GET_BLOCK_STATE(Connection) != BlockStateActive ||
  2131. Connection->DisconnectPending ) {
  2132. RELEASE_DPC_SPIN_LOCK( Connection->EndpointSpinLock );
  2133. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  2134. IF_DEBUG( WORKITEMS ) {
  2135. KdPrint(("SrvAddToNeedResourceQueue: connection closing. Not queued\n"));
  2136. }
  2137. return FALSE;
  2138. }
  2139. //
  2140. // Mark the connection so that the resource thread will know what to
  2141. // do with this connection.
  2142. //
  2143. switch ( ResourceType ) {
  2144. case ReceivePending:
  2145. ASSERT( !Connection->ReceivePending );
  2146. Connection->ReceivePending = TRUE;
  2147. break;
  2148. case OplockSendPending:
  2149. //
  2150. // Queue the context information to the connection, if necessary.
  2151. //
  2152. ASSERT( ARGUMENT_PRESENT( Rfcb ) );
  2153. SrvInsertTailList( &Connection->OplockWorkList, &Rfcb->ListEntry );
  2154. break;
  2155. }
  2156. //
  2157. // Put the connection on the need-resource queue and increment its
  2158. // reference count.
  2159. //
  2160. if( Connection->OnNeedResourceQueue == FALSE ) {
  2161. Connection->OnNeedResourceQueue = TRUE;
  2162. SrvInsertTailList(
  2163. &SrvNeedResourceQueue,
  2164. &Connection->ListEntry
  2165. );
  2166. SrvReferenceConnectionLocked( Connection );
  2167. IF_DEBUG( WORKITEMS ) {
  2168. KdPrint(("SrvAddToNeedResourceQueue: connection %p inserted on the queue.\n", Connection));
  2169. }
  2170. }
  2171. RELEASE_DPC_SPIN_LOCK( Connection->EndpointSpinLock );
  2172. RELEASE_GLOBAL_SPIN_LOCK( Fsd, oldIrql );
  2173. //
  2174. // Make sure we know that this connection needs a WorkItem
  2175. //
  2176. InterlockedIncrement( &Connection->CurrentWorkQueue->NeedWorkItem );
  2177. IF_DEBUG( WORKITEMS ) {
  2178. KdPrint(("SrvAddToNeedResourceQueue complete: NeedWorkItem = %d\n",
  2179. Connection->CurrentWorkQueue->NeedWorkItem ));
  2180. }
  2181. return TRUE;
  2182. } // SrvAddToNeedResourceQueue
  2183. VOID
  2184. SrvCheckForAndQueueDoS(
  2185. PWORK_QUEUE queue
  2186. )
  2187. {
  2188. KIRQL oldIrql;
  2189. LARGE_INTEGER CurrentTime;
  2190. BOOLEAN LogEvent = FALSE;
  2191. if( !SrvDisableDoSChecking &&
  2192. queue->AllocatedWorkItems >= queue->MaximumWorkItems )
  2193. {
  2194. // Potential DoS
  2195. SrvDoSDetected = TRUE;
  2196. // Make sure we only queue one of these at a time globally
  2197. if( SRV_DOS_CAN_START_TEARDOWN() )
  2198. {
  2199. KeQuerySystemTime( &CurrentTime );
  2200. if( CurrentTime.QuadPart > SrvDoSLastRan.QuadPart + SRV_DOS_MINIMUM_DOS_WAIT_PERIOD )
  2201. {
  2202. // Setup a refresher/DOS item
  2203. ACQUIRE_SPIN_LOCK( &queue->SpinLock, &oldIrql );
  2204. ACQUIRE_DPC_SPIN_LOCK( &SrvDosSpinLock );
  2205. if( GET_BLOCK_TYPE(&SrvDoSWorkItem) == BlockTypeGarbage ) {
  2206. SET_BLOCK_TYPE( &SrvDoSWorkItem, BlockTypeWorkContextSpecial );
  2207. if( SrvDoSLastRan.QuadPart + SRV_ONE_DAY < CurrentTime.QuadPart )
  2208. {
  2209. // Only log events when there has been no DoS for 24 hours
  2210. LogEvent = TRUE;
  2211. }
  2212. SrvDoSLastRan = CurrentTime;
  2213. SrvDoSWorkItem.FspRestartRoutine = SrvServiceDoSTearDown;
  2214. SrvDoSWorkItem.CurrentWorkQueue = queue;
  2215. SrvInsertWorkQueueHead( queue, &SrvDoSWorkItem );
  2216. }
  2217. else
  2218. {
  2219. // Some error occurred, leave the DoS for another queue
  2220. SRV_DOS_COMPLETE_TEARDOWN();
  2221. }
  2222. RELEASE_DPC_SPIN_LOCK( &SrvDosSpinLock );
  2223. RELEASE_SPIN_LOCK( &queue->SpinLock, oldIrql );
  2224. }
  2225. else
  2226. {
  2227. SRV_DOS_COMPLETE_TEARDOWN();
  2228. }
  2229. // Log the event if necessary
  2230. if( LogEvent )
  2231. {
  2232. SrvLogError(
  2233. SrvDeviceObject,
  2234. EVENT_SRV_OUT_OF_WORK_ITEM_DOS,
  2235. STATUS_ACCESS_DENIED,
  2236. NULL,
  2237. 0,
  2238. NULL,
  2239. 0
  2240. );
  2241. }
  2242. }
  2243. }
  2244. }