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

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