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.

1272 lines
30 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. NwPnP.c
  5. Abstract:
  6. This module implements the routines related to NwRdr PnP
  7. and PM functionality.
  8. Author:
  9. Cory West [CoryWest] 10-Feb-1997
  10. Anoop Anantha [AnoopA] 24-Jun-1998
  11. Revision History:
  12. --*/
  13. #include "procs.h"
  14. #define Dbg ( DEBUG_TRACE_PNP )
  15. #ifdef _PNP_POWER_
  16. #pragma alloc_text( PAGE, StartRedirector )
  17. #pragma alloc_text( PAGE, StopRedirector )
  18. #pragma alloc_text( PAGE, RegisterTdiPnPEventHandlers )
  19. #pragma alloc_text( PAGE, NwFsdProcessPnpIrp )
  20. #pragma alloc_text( PAGE, NwCommonProcessPnpIrp )
  21. HANDLE TdiBindingHandle = NULL;
  22. WCHAR IpxDevice[] = L"\\Device\\NwlnkIpx";
  23. #define IPX_DEVICE_BYTES 32
  24. extern BOOLEAN WorkerRunning; // From timer.c
  25. //
  26. // We assume that some devices are active at boot,
  27. // even if we don't get notified.
  28. //
  29. BOOLEAN fSomePMDevicesAreActive = TRUE;
  30. NTSTATUS
  31. StartRedirector(
  32. PIRP_CONTEXT IrpContext
  33. )
  34. /*++
  35. Routine Description:
  36. This routine starts the redirector.
  37. Arguments:
  38. None.
  39. Return Value:
  40. NTSTATUS - The status of the operation.
  41. --*/
  42. {
  43. NTSTATUS Status;
  44. PAGED_CODE();
  45. //
  46. // We need to be in the FSP to Register the MUP.
  47. //
  48. if ( FlagOn( IrpContext->Flags, IRP_FLAG_IN_FSD ) ) {
  49. //
  50. // Check to make sure the caller is allowed to do this operation
  51. //
  52. // if ( !SeSinglePrivilegeCheck( RtlConvertLongToLuid (SE_TCB_PRIVILEGE),
  53. // IrpContext->pOriginalIrp->RequestorMode) ) {
  54. if ( ! IsSystemLuid()) {
  55. return( STATUS_ACCESS_DENIED );
  56. }
  57. Status = NwPostToFsp( IrpContext, TRUE );
  58. return( Status );
  59. }
  60. NwRcb.State = RCB_STATE_STARTING;
  61. FspProcess = PsGetCurrentProcess();
  62. #ifdef QFE_BUILD
  63. StartTimer() ;
  64. #endif
  65. //
  66. // Now connect to the MUP.
  67. //
  68. RegisterWithMup();
  69. KeQuerySystemTime( &Stats.StatisticsStartTime );
  70. NwRcb.State = RCB_STATE_NEED_BIND;
  71. return( STATUS_SUCCESS );
  72. }
  73. NTSTATUS
  74. StopRedirector(
  75. PIRP_CONTEXT IrpContext
  76. )
  77. /*++
  78. Routine Description:
  79. This routine shuts down the redirector.
  80. Arguments:
  81. None.
  82. Return Value:
  83. NTSTATUS - The status of the operation.
  84. --*/
  85. {
  86. NTSTATUS Status;
  87. PLIST_ENTRY LogonListEntry;
  88. ULONG ActiveHandles;
  89. ULONG RcbOpenCount;
  90. PAGED_CODE();
  91. //
  92. // We need to be in the FSP to Deregister the MUP.
  93. //
  94. if ( FlagOn( IrpContext->Flags, IRP_FLAG_IN_FSD ) ) {
  95. //
  96. // Check to make sure the caller is allowed to do this operation
  97. //
  98. // if ( !SeSinglePrivilegeCheck( RtlConvertLongToLuid (SE_TCB_PRIVILEGE),
  99. // IrpContext->pOriginalIrp->RequestorMode) ) {
  100. if ( ! IsSystemLuid()) {
  101. return( STATUS_ACCESS_DENIED );
  102. }
  103. Status = NwPostToFsp( IrpContext, TRUE );
  104. return( Status );
  105. }
  106. //
  107. // Unregister the bind handler with tdi.
  108. //
  109. if ( TdiBindingHandle != NULL ) {
  110. TdiDeregisterPnPHandlers( TdiBindingHandle );
  111. TdiBindingHandle = NULL;
  112. }
  113. NwRcb.State = RCB_STATE_SHUTDOWN;
  114. //
  115. // Invalid all ICBs
  116. //
  117. SetFlag( IrpContext->Flags, IRP_FLAG_SEND_ALWAYS );
  118. ActiveHandles = NwInvalidateAllHandles(NULL, IrpContext);
  119. //
  120. // To expedite shutdown, set retry count down to 2.
  121. //
  122. DefaultRetryCount = 2;
  123. //
  124. // Close all VCBs
  125. //
  126. NwCloseAllVcbs( IrpContext );
  127. //
  128. // Logoff and disconnect from all servers.
  129. //
  130. NwLogoffAllServers( IrpContext, NULL );
  131. while ( !IsListEmpty( &LogonList ) ) {
  132. LogonListEntry = RemoveHeadList( &LogonList );
  133. FreeLogon(CONTAINING_RECORD( LogonListEntry, LOGON, Next ));
  134. }
  135. InsertTailList( &LogonList, &Guest.Next ); // just in-case we don't unload.
  136. StopTimer();
  137. IpxClose();
  138. //
  139. // Remember the open count before calling DeristerWithMup since this
  140. // will asynchronously cause handle count to get decremented.
  141. //
  142. RcbOpenCount = NwRcb.OpenCount;
  143. DeregisterWithMup( );
  144. DebugTrace(0, Dbg, "StopRedirector: Active handle count = %d\n", ActiveHandles );
  145. //
  146. // On shutdown, we need 0 remote handles and 2 open handles to
  147. // the redir (one for the service, and one for the MUP) and the timer stopped.
  148. //
  149. if ( ActiveHandles == 0 && RcbOpenCount <= 2 ) {
  150. return( STATUS_SUCCESS );
  151. } else {
  152. return( STATUS_REDIRECTOR_HAS_OPEN_HANDLES );
  153. }
  154. }
  155. VOID
  156. BindToTransport(
  157. )
  158. /*+++
  159. Description: This function binds us to IPX.
  160. ---*/
  161. {
  162. NTSTATUS Status;
  163. PIRP_CONTEXT IrpContext = NULL;
  164. PIRP pIrp = NULL;
  165. UNICODE_STRING DeviceName;
  166. PAGED_CODE();
  167. //
  168. // Make sure we aren't already bound.
  169. //
  170. if ( ( NwRcb.State != RCB_STATE_NEED_BIND ) ||
  171. ( IpxHandle != NULL ) ) {
  172. DebugTrace( 0, Dbg, "Discarding duplicate PnP bind request.\n", 0 );
  173. return;
  174. }
  175. ASSERT( IpxTransportName.Buffer == NULL );
  176. ASSERT( pIpxDeviceObject == NULL );
  177. RtlInitUnicodeString( &DeviceName, IpxDevice );
  178. Status = DuplicateUnicodeStringWithString ( &IpxTransportName,
  179. &DeviceName,
  180. PagedPool );
  181. if ( !NT_SUCCESS( Status ) ) {
  182. DebugTrace( 0, Dbg, "Failing IPX bind: Can't set device name.\n", 0 );
  183. return;
  184. }
  185. //
  186. // Open IPX.
  187. //
  188. Status = IpxOpen();
  189. if ( !NT_SUCCESS( Status ) ) {
  190. goto ExitWithCleanup;
  191. }
  192. //
  193. // Verify that have a large enough stack size.
  194. //
  195. if ( pIpxDeviceObject->StackSize >= FileSystemDeviceObject->StackSize ) {
  196. Status = STATUS_INVALID_PARAMETER;
  197. goto ExitWithCleanup;
  198. }
  199. //
  200. // Submit a line change request.
  201. //
  202. SubmitLineChangeRequest();
  203. //
  204. // Allocate an irp and irp context. AllocateIrpContext may raise status.
  205. //
  206. pIrp = ALLOCATE_IRP( pIpxDeviceObject->StackSize, FALSE );
  207. if ( pIrp == NULL ) {
  208. Status = STATUS_INSUFFICIENT_RESOURCES;
  209. goto ExitWithCleanup;
  210. }
  211. try {
  212. IrpContext = AllocateIrpContext( pIrp );
  213. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  214. Status = STATUS_INSUFFICIENT_RESOURCES;
  215. goto ExitWithCleanup;
  216. }
  217. ASSERT( IrpContext != NULL );
  218. //
  219. // Open a handle to IPX for the permanent scb.
  220. //
  221. NwPermanentNpScb.Server.Socket = 0;
  222. Status = IPX_Open_Socket( IrpContext, &NwPermanentNpScb.Server );
  223. if ( !NT_SUCCESS( Status ) ) {
  224. goto ExitWithCleanup;
  225. }
  226. Status = SetEventHandler (
  227. IrpContext,
  228. &NwPermanentNpScb.Server,
  229. TDI_EVENT_RECEIVE_DATAGRAM,
  230. &ServerDatagramHandler,
  231. &NwPermanentNpScb );
  232. if ( !NT_SUCCESS( Status ) ) {
  233. goto ExitWithCleanup;
  234. }
  235. IrpContext->pNpScb = &NwPermanentNpScb;
  236. NwRcb.State = RCB_STATE_RUNNING;
  237. DebugTrace( 0, Dbg, "Opened IPX for NwRdr.\n", 0 );
  238. Status = STATUS_SUCCESS;
  239. ExitWithCleanup:
  240. if ( !NT_SUCCESS( Status ) ) {
  241. //
  242. // If we failed, clean up our globals.
  243. //
  244. if ( pIpxDeviceObject != NULL ) {
  245. IpxClose();
  246. pIpxDeviceObject = NULL;
  247. }
  248. IpxHandle = NULL;
  249. if ( IpxTransportName.Buffer != NULL ) {
  250. FREE_POOL( IpxTransportName.Buffer );
  251. IpxTransportName.Buffer = NULL;
  252. }
  253. DebugTrace( 0, Dbg, "Failing IPX bind request.\n", 0 );
  254. }
  255. if ( pIrp != NULL ) {
  256. FREE_IRP( pIrp );
  257. }
  258. if ( IrpContext != NULL ) {
  259. IrpContext->pOriginalIrp = NULL; // Avoid FreeIrpContext modifying freed Irp.
  260. FreeIrpContext( IrpContext );
  261. }
  262. return;
  263. }
  264. VOID
  265. UnbindFromTransport(
  266. )
  267. /*+++
  268. Description: This function unbinds us from IPX.
  269. ---*/
  270. {
  271. PIRP_CONTEXT pIrpContext;
  272. BOOLEAN fAllocatedIrpContext = FALSE;
  273. ULONG ActiveHandles;
  274. PNONPAGED_SCB pNpScb;
  275. DebugTrace( 0, Dbg,"Unbind called\n", 0);
  276. //
  277. // Throttle the RCB.
  278. //
  279. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  280. NwRcb.State = RCB_STATE_NEED_BIND;
  281. NwReleaseRcb( &NwRcb );
  282. //
  283. // Get a nearby server to figure out how much
  284. // IRP stack space we need for IPX.
  285. //
  286. NwReferenceUnlockableCodeSection ();
  287. pNpScb = SelectConnection( NULL );
  288. if ( pNpScb != NULL ) {
  289. //
  290. // If there was a connection, then we have to throttle
  291. // things back before unbinding the transport.
  292. //
  293. fAllocatedIrpContext =
  294. NwAllocateExtraIrpContext( &pIrpContext, pNpScb );
  295. if ( fAllocatedIrpContext ) {
  296. pIrpContext->pNpScb = pNpScb;
  297. //
  298. // Flush all cache data.
  299. //
  300. FlushAllBuffers( pIrpContext );
  301. NwDereferenceScb( pNpScb );
  302. //
  303. // Invalid all ICBs.
  304. //
  305. SetFlag( pIrpContext->Flags, IRP_FLAG_SEND_ALWAYS );
  306. // Lock down so that we can send a packet.
  307. NwReferenceUnlockableCodeSection();
  308. ActiveHandles = NwInvalidateAllHandles(NULL, pIrpContext);
  309. DebugTrace(0, Dbg, "Unbind: Active handle count = %d\n", ActiveHandles );
  310. //
  311. // Close all VCBs.
  312. //
  313. NwCloseAllVcbs( pIrpContext );
  314. //
  315. // Logoff and disconnect from all servers.
  316. //
  317. NwLogoffAllServers( pIrpContext, NULL );
  318. NwDereferenceUnlockableCodeSection ();
  319. //
  320. // Free the irp context.
  321. //
  322. NwFreeExtraIrpContext( pIrpContext );
  323. } else {
  324. NwDereferenceScb( pNpScb );
  325. }
  326. }
  327. //
  328. // Don't stop the DPC timer so the stale SCBs will get scavenged.
  329. // Don't deregister with the MUP so that we're still visible.
  330. //
  331. IpxClose();
  332. NwDereferenceUnlockableCodeSection ();
  333. return;
  334. }
  335. VOID
  336. TdiPnpBindHandler(
  337. IN TDI_PNP_OPCODE PnPOpcode,
  338. IN PUNICODE_STRING DeviceName,
  339. IN PWSTR MultiSZBindList
  340. ) {
  341. DebugTrace( 0, Dbg, "TdiPnpBindHandler...\n", 0 );
  342. DebugTrace( 0, Dbg, " OpCode %d\n", PnPOpcode );
  343. DebugTrace( 0, Dbg, " DeviceName %wZ\n", DeviceName );
  344. DebugTrace( 0, Dbg, " MultiSzBindList %08lx\n", MultiSZBindList );
  345. if (DeviceName == NULL) {
  346. return;
  347. }
  348. if ( ( DeviceName->Length != IPX_DEVICE_BYTES ) ||
  349. ( RtlCompareMemory( DeviceName->Buffer,
  350. IpxDevice,
  351. IPX_DEVICE_BYTES ) != IPX_DEVICE_BYTES ) ) {
  352. DebugTrace( 0, Dbg, "Skipping bind for unknown device.\n", 0 );
  353. return;
  354. }
  355. //
  356. // If we get an add or a non-null update, we make sure that
  357. // we are bound. We don't have to check the bindings because
  358. // we only support binding to one transport.
  359. //
  360. // Duplicate calls to bind or unbind have no effect.
  361. //
  362. FsRtlEnterFileSystem();
  363. if ( ( PnPOpcode == TDI_PNP_OP_ADD ) ||
  364. ( ( PnPOpcode == TDI_PNP_OP_UPDATE ) &&
  365. ( MultiSZBindList != NULL ) ) ) {
  366. BindToTransport( );
  367. } else if ( ( PnPOpcode == TDI_PNP_OP_DEL ) ||
  368. ( ( PnPOpcode == TDI_PNP_OP_UPDATE ) &&
  369. ( MultiSZBindList == NULL ) ) ) {
  370. UnbindFromTransport( );
  371. } else {
  372. DebugTrace( 0, Dbg, "No known action for binding call.\n", 0 );
  373. }
  374. FsRtlExitFileSystem();
  375. return;
  376. }
  377. NTSTATUS
  378. TdiPnpPowerEvent(
  379. IN PUNICODE_STRING DeviceName,
  380. IN PNET_PNP_EVENT PnPEvent,
  381. IN PTDI_PNP_CONTEXT Context1,
  382. IN PTDI_PNP_CONTEXT Context2
  383. ) {
  384. NTSTATUS Status;
  385. DebugTrace( 0, Dbg, "TdiPnPPowerEvent...\n", 0 );
  386. //
  387. // Check to see if we care about this PnP/PM event.
  388. //
  389. if ( ( DeviceName->Length != IPX_DEVICE_BYTES ) ||
  390. ( RtlCompareMemory( DeviceName->Buffer,
  391. IpxDevice,
  392. IPX_DEVICE_BYTES ) != IPX_DEVICE_BYTES ) ) {
  393. DebugTrace( 0, Dbg, "Skipping PnP/PM event for unknown device.\n", 0 );
  394. return STATUS_SUCCESS;
  395. }
  396. FsRtlEnterFileSystem();
  397. //
  398. // Dispatch the event.
  399. //
  400. switch ( PnPEvent->NetEvent ) {
  401. case NetEventSetPower:
  402. Status = PnPSetPower( PnPEvent, Context1, Context2 );
  403. break;
  404. case NetEventQueryPower:
  405. Status = PnPQueryPower( PnPEvent, Context1, Context2 );
  406. break;
  407. case NetEventQueryRemoveDevice:
  408. Status = PnPQueryRemove( PnPEvent, Context1, Context2 );
  409. break;
  410. case NetEventCancelRemoveDevice:
  411. Status = PnPCancelRemove( PnPEvent, Context1, Context2 );
  412. break;
  413. }
  414. FsRtlExitFileSystem();
  415. return Status;
  416. }
  417. NTSTATUS
  418. RegisterTdiPnPEventHandlers(
  419. IN PIRP_CONTEXT IrpContext
  420. )
  421. /*++
  422. Routine Description:
  423. This routine records the name of the transport to be used and
  424. initialises the PermanentScb.
  425. Arguments:
  426. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  427. Return Value:
  428. NTSTATUS
  429. --*/
  430. {
  431. NTSTATUS Status;
  432. TDI_CLIENT_INTERFACE_INFO ClientInfo;
  433. UNICODE_STRING ClientName;
  434. WCHAR ClientNameBuffer[] = L"NWCWorkstation";
  435. PAGED_CODE();
  436. DebugTrace( 0 , Dbg, "Register TDI PnP handlers.\n", 0 );
  437. //
  438. // Don't re-register if we have already registered.
  439. //
  440. if ( TdiBindingHandle != NULL ) {
  441. return STATUS_SUCCESS;
  442. }
  443. ClientInfo.MajorTdiVersion = 2;
  444. ClientInfo.MinorTdiVersion = 0;
  445. RtlInitUnicodeString( &ClientName, ClientNameBuffer );
  446. ClientInfo.ClientName = &ClientName;
  447. ClientInfo.BindingHandler = TdiPnpBindHandler;
  448. //
  449. // We don't support add or delete address handlers. This will
  450. // never be a problem unless the user adds multiple net cards
  451. // and doesn't have their IPX internal net number set correctly
  452. // beforehand. We also don't support this in NT4 Net PnP.
  453. //
  454. ClientInfo.AddAddressHandler = NULL;
  455. ClientInfo.DelAddressHandler = NULL;
  456. ClientInfo.PnPPowerHandler = TdiPnpPowerEvent;
  457. TdiInitialize();
  458. return TdiRegisterPnPHandlers( &ClientInfo,
  459. sizeof( TDI_CLIENT_INTERFACE_INFO ),
  460. &TdiBindingHandle );
  461. }
  462. NTSTATUS
  463. PnPSetPower(
  464. PNET_PNP_EVENT pEvent,
  465. PTDI_PNP_CONTEXT pContext1,
  466. PTDI_PNP_CONTEXT pContext2
  467. ) {
  468. NET_DEVICE_POWER_STATE PowerState;
  469. PIRP_CONTEXT pIrpContext;
  470. PNONPAGED_SCB pNpScb;
  471. BOOLEAN fAllocatedIrpContext = FALSE;
  472. NTSTATUS Status;
  473. PIRP_CONTEXT IrpContext = NULL;
  474. PIRP pIrp = NULL;
  475. //
  476. // Dig out the power state that the device is going to.
  477. //
  478. ASSERT( pEvent->BufferLength == sizeof( NET_DEVICE_POWER_STATE ) );
  479. PowerState = *((PNET_DEVICE_POWER_STATE) pEvent->Buffer);
  480. DebugTrace( 0, Dbg, "PnPSetPower came in with power state %d\n", PowerState);
  481. //
  482. // If we are not powering down, bring the status back to normal, else, we
  483. // are all ready to go to sleep.
  484. //
  485. if ( PowerState == NetDeviceStateD0 ) {
  486. //
  487. // UnThrottle the RCB.
  488. //
  489. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  490. NwRcb.State = RCB_STATE_RUNNING;
  491. NwReleaseRcb( &NwRcb );
  492. //
  493. // Restart the timer so that the scavenger thread gets back to
  494. // work;
  495. //
  496. StartTimer();
  497. //
  498. // We can let the worker thread do it's job.
  499. //
  500. ASSERT( fPoweringDown == TRUE );
  501. fPoweringDown = FALSE;
  502. }
  503. if ( ( pContext2->ContextType == TDI_PNP_CONTEXT_TYPE_FIRST_OR_LAST_IF ) &&
  504. ( pContext2->ContextData ) ) {
  505. if ( PowerState == NetDeviceStateD0 ) {
  506. //
  507. // This is the first device coming online.
  508. //
  509. fSomePMDevicesAreActive = TRUE;
  510. } else {
  511. //
  512. // This is the last device going offline.
  513. //
  514. fSomePMDevicesAreActive = FALSE;
  515. }
  516. }
  517. DebugTrace( 0, Dbg, "NwRdr::SetPower = %08lx\n", STATUS_SUCCESS );
  518. return STATUS_SUCCESS;
  519. }
  520. NTSTATUS
  521. PnPQueryPower(
  522. PNET_PNP_EVENT pEvent,
  523. PTDI_PNP_CONTEXT pContext1,
  524. PTDI_PNP_CONTEXT pContext2
  525. ) {
  526. NTSTATUS Status = STATUS_SUCCESS;
  527. NET_DEVICE_POWER_STATE PowerState;
  528. ULONG ActiveHandles;
  529. PIRP_CONTEXT pIrpContext;
  530. BOOLEAN fAllocatedIrpContext = FALSE;
  531. PNONPAGED_SCB pNpScb;
  532. //
  533. // Dig out the power state that the stack wants to go to.
  534. //
  535. ASSERT( pEvent->BufferLength == sizeof( NET_DEVICE_POWER_STATE ) );
  536. PowerState = *((PNET_DEVICE_POWER_STATE) pEvent->Buffer);
  537. DebugTrace( 0, Dbg, "PnPQueryPower came in with power state %d\n", PowerState);
  538. //
  539. // We have to cover going from the powered state
  540. // to the unpowered state only. All other transitions
  541. // will be allowed regardless of our state.
  542. //
  543. if ( ( fSomePMDevicesAreActive ) &&
  544. ( PowerState != NetDeviceStateD0 ) ) {
  545. ActiveHandles = PnPCountActiveHandles();
  546. if (( ActiveHandles ) || ( WorkerRunning == TRUE )) {
  547. Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
  548. } else {
  549. //
  550. // We are saying ok to a possible hibernate state. We have
  551. // to ensure that the scavenger thread doesn't start. Also,
  552. // we have to flush buffers.
  553. //
  554. fPoweringDown = TRUE;
  555. pNpScb = SelectConnection( NULL );
  556. if ( pNpScb != NULL ) {
  557. fAllocatedIrpContext =
  558. NwAllocateExtraIrpContext( &pIrpContext, pNpScb );
  559. NwDereferenceScb( pNpScb );
  560. if ( fAllocatedIrpContext ) {
  561. FlushAllBuffers( pIrpContext );
  562. NwFreeExtraIrpContext( pIrpContext );
  563. }
  564. }
  565. //
  566. // Throttle down the RCB.
  567. //
  568. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  569. NwRcb.State = RCB_STATE_NEED_BIND;
  570. NwReleaseRcb( &NwRcb );
  571. //
  572. // The TimerDPC will not fire if we stop the timer.
  573. //
  574. StopTimer();
  575. }
  576. }
  577. DebugTrace( 0, Dbg, "NwRdr::QueryPower. New State = %d\n", PowerState );
  578. DebugTrace( 0, Dbg, "NwRdr::QueryPower = %08lx\n", Status );
  579. return Status;
  580. }
  581. NTSTATUS
  582. PnPQueryRemove(
  583. PNET_PNP_EVENT pEvent,
  584. PTDI_PNP_CONTEXT pContext1,
  585. PTDI_PNP_CONTEXT pContext2
  586. ) {
  587. NTSTATUS Status = STATUS_SUCCESS;
  588. ULONG ActiveHandles;
  589. //
  590. // We might want to flush all the buffers here, though
  591. // it should be true that this is followed by an unbind if the
  592. // device is going to be removed and the unbind will flush all
  593. // the buffers.
  594. //
  595. ActiveHandles = PnPCountActiveHandles();
  596. if ( ActiveHandles ) {
  597. Status = STATUS_REDIRECTOR_HAS_OPEN_HANDLES;
  598. }
  599. //
  600. // I think we need to throttle back new creates
  601. // until we get the unbind or the CancelRemove call.
  602. //
  603. DebugTrace( 0, Dbg, "PnPQueryRemove returned with status %d\n", Status);
  604. DebugTrace( 0, Dbg, "NwRdr::QueryRemove = %08lx\n", Status );
  605. return Status;
  606. }
  607. NTSTATUS
  608. PnPCancelRemove(
  609. PNET_PNP_EVENT pEvent,
  610. PTDI_PNP_CONTEXT pContext1,
  611. PTDI_PNP_CONTEXT pContext2
  612. ) {
  613. //
  614. // We don't do anything for a cancel remove
  615. // because we don't throttle back the redirector
  616. // on a query remove call.
  617. //
  618. DebugTrace( 0, Dbg, "NwRdr::CancelRemove = %08lx\n", STATUS_SUCCESS );
  619. DebugTrace( 0, Dbg,"PnPCancelRemove returned with status %d\n", STATUS_SUCCESS);
  620. return STATUS_SUCCESS;
  621. }
  622. ULONG
  623. PnPCountActiveHandles(
  624. VOID
  625. )
  626. /*+++
  627. This routine counts the number of active handles in the
  628. redirector and returns the count to the caller.
  629. ---*/
  630. {
  631. PNONPAGED_SCB pNpScb;
  632. PSCB pScb;
  633. PVCB pVcb;
  634. KIRQL OldIrql;
  635. PLIST_ENTRY ScbQueueEntry, NextScbQueueEntry;
  636. PLIST_ENTRY VcbQueueEntry;
  637. PLIST_ENTRY NextVcbQueueEntry;
  638. ULONG OpenFileCount = 0;
  639. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  640. //
  641. // Walk the SCB list and check for open files.
  642. //
  643. for ( ScbQueueEntry = ScbQueue.Flink ;
  644. ScbQueueEntry != &ScbQueue ;
  645. ScbQueueEntry = NextScbQueueEntry ) {
  646. pNpScb = CONTAINING_RECORD( ScbQueueEntry, NONPAGED_SCB, ScbLinks );
  647. pScb = pNpScb->pScb;
  648. if ( pScb != NULL ) {
  649. //
  650. // Release the SCB spin lock as we are about
  651. // to touch nonpaged pool.
  652. //
  653. NwReferenceScb( pNpScb );
  654. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  655. //
  656. // Grab the RCB so we can walk the VCB list and
  657. // check the OpenFileCount.
  658. //
  659. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  660. OpenFileCount += pScb->OpenFileCount;
  661. //
  662. // Subtract off the open counts for explicitly
  663. // connected VCBs; we can shut down with these.
  664. //
  665. for ( VcbQueueEntry = pScb->ScbSpecificVcbQueue.Flink ;
  666. VcbQueueEntry != &pScb->ScbSpecificVcbQueue;
  667. VcbQueueEntry = NextVcbQueueEntry ) {
  668. pVcb = CONTAINING_RECORD( VcbQueueEntry, VCB, VcbListEntry );
  669. NextVcbQueueEntry = VcbQueueEntry->Flink;
  670. if ( BooleanFlagOn( pVcb->Flags, VCB_FLAG_EXPLICIT_CONNECTION ) ) {
  671. OpenFileCount -= 1;
  672. }
  673. }
  674. NwReleaseRcb( &NwRcb );
  675. KeAcquireSpinLock( &ScbSpinLock, &OldIrql );
  676. NwDereferenceScb( pNpScb );
  677. }
  678. NextScbQueueEntry = pNpScb->ScbLinks.Flink;
  679. }
  680. KeReleaseSpinLock( &ScbSpinLock, OldIrql );
  681. DebugTrace( 0, Dbg, "PnPCountActiveHandles: %d\n", OpenFileCount );
  682. return OpenFileCount;
  683. }
  684. NTSTATUS
  685. NwFsdProcessPnpIrp(
  686. IN PDEVICE_OBJECT DeviceObject,
  687. IN PIRP Irp
  688. )
  689. /*++
  690. Routine Description:
  691. This routine is the FSD routine that handles the PNP IRP
  692. Arguments:
  693. DeviceObject - Supplies the device object for the write function.
  694. Irp - Supplies the IRP to process.
  695. Return Value:
  696. NTSTATUS - The result status.
  697. Notes:
  698. The query target device relation is the only call that is implemented
  699. currently. This is done by returing the PDO associated with the transport
  700. connection object. In any case this routine assumes the responsibility of
  701. completing the IRP and return STATUS_PENDING.
  702. --*/
  703. {
  704. PIRP_CONTEXT pIrpContext = NULL;
  705. NTSTATUS Status;
  706. BOOLEAN TopLevel;
  707. PAGED_CODE();
  708. DebugTrace(+1, DEBUG_TRACE_ALWAYS, "NwFsdProcessPnpIrp \n", 0);
  709. //
  710. // Call the common write routine.
  711. //
  712. FsRtlEnterFileSystem();
  713. TopLevel = NwIsIrpTopLevel( Irp );
  714. try {
  715. pIrpContext = AllocateIrpContext( Irp );
  716. Status = NwCommonProcessPnpIrp( pIrpContext );
  717. } except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
  718. if ( pIrpContext == NULL ) {
  719. //
  720. // If we couldn't allocate an irp context, just complete
  721. // irp without any fanfare.
  722. //
  723. Status = STATUS_INSUFFICIENT_RESOURCES;
  724. Irp->IoStatus.Status = Status;
  725. Irp->IoStatus.Information = 0;
  726. IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
  727. } else {
  728. //
  729. // We had some trouble trying to perform the requested
  730. // operation, so we'll abort the I/O request with
  731. // the error Status that we get back from the
  732. // execption code
  733. //
  734. Status = NwProcessException( pIrpContext, GetExceptionCode() );
  735. }
  736. }
  737. if ( pIrpContext ) {
  738. NwCompleteRequest(pIrpContext, Status);
  739. }
  740. if ( TopLevel ) {
  741. NwSetTopLevelIrp( NULL );
  742. }
  743. FsRtlExitFileSystem();
  744. //
  745. // Return to the caller.
  746. //
  747. DebugTrace(-1, DEBUG_TRACE_ALWAYS, "NwFsdFsdProcessPnpIrp -> %08lx\n", STATUS_PENDING);
  748. return Status;
  749. }
  750. NTSTATUS
  751. NwCommonProcessPnpIrp (
  752. IN PIRP_CONTEXT IrpContext
  753. )
  754. /*++
  755. Routine Description:
  756. Arguments:
  757. IrpContext - Supplies the request being processed.
  758. Return Value:
  759. The status of the operation.
  760. --*/
  761. {
  762. PIRP Irp;
  763. PIO_STACK_LOCATION IrpSp;
  764. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  765. PFCB Fcb;
  766. PICB Icb;
  767. NODE_TYPE_CODE NodeTypeCode;
  768. PVOID FsContext;
  769. PAGED_CODE();
  770. DebugTrace(0, DEBUG_TRACE_ALWAYS, "NwCommonProcessPnpIrp...\n", 0);
  771. //
  772. // Get the current stack location
  773. //
  774. Irp = IrpContext->pOriginalIrp;
  775. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  776. DebugTrace( 0, DEBUG_TRACE_ALWAYS, "Irp = %08lx\n", (ULONG_PTR)Irp);
  777. switch (IrpSp->MinorFunction) {
  778. case IRP_MN_QUERY_DEVICE_RELATIONS:
  779. if (IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation) {
  780. PIRP pAssociatedIrp = NULL;
  781. if (pIpxFileObject != NULL) {
  782. PDEVICE_OBJECT pRelatedDeviceObject;
  783. PIO_STACK_LOCATION pIrpStackLocation,
  784. pAssociatedIrpStackLocation;
  785. ObReferenceObject( pIpxFileObject );
  786. pRelatedDeviceObject = IoGetRelatedDeviceObject( pIpxFileObject );
  787. pAssociatedIrp = ALLOCATE_IRP( pRelatedDeviceObject->StackSize,
  788. FALSE);
  789. if (pAssociatedIrp != NULL) {
  790. KEVENT CompletionEvent;
  791. KeInitializeEvent( &CompletionEvent,
  792. SynchronizationEvent,
  793. FALSE );
  794. //
  795. // tommye - MS bug 37033/ MCS 270
  796. //
  797. // Set the Status to STATUS_NOT_SUPPORTED
  798. //
  799. pAssociatedIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  800. //
  801. // Fill up the associated IRP and call the underlying driver.
  802. //
  803. pAssociatedIrpStackLocation = IoGetNextIrpStackLocation(pAssociatedIrp);
  804. pIrpStackLocation = IoGetCurrentIrpStackLocation(Irp);
  805. *pAssociatedIrpStackLocation = *pIrpStackLocation;
  806. pAssociatedIrpStackLocation->FileObject = pIpxFileObject;
  807. pAssociatedIrpStackLocation->DeviceObject = pRelatedDeviceObject;
  808. IoSetCompletionRoutine(
  809. pAssociatedIrp,
  810. PnpIrpCompletion,
  811. &CompletionEvent,
  812. TRUE,TRUE,TRUE);
  813. Status = IoCallDriver( pRelatedDeviceObject, pAssociatedIrp );
  814. if (Status == STATUS_PENDING) {
  815. (VOID) KeWaitForSingleObject(
  816. &CompletionEvent,
  817. Executive,
  818. KernelMode,
  819. FALSE,
  820. (PLARGE_INTEGER) NULL );
  821. }
  822. Irp->IoStatus = pAssociatedIrp->IoStatus;
  823. Status = Irp->IoStatus.Status;
  824. if (!NT_SUCCESS(Status)) {
  825. Error(EVENT_NWRDR_NETWORK_ERROR,
  826. Status,
  827. IpxTransportName.Buffer,
  828. IpxTransportName.Length,
  829. 0);
  830. }
  831. ObDereferenceObject( pIpxFileObject );
  832. FREE_IRP(pAssociatedIrp);
  833. } else {
  834. Status = STATUS_INSUFFICIENT_RESOURCES;
  835. ObDereferenceObject( pIpxFileObject );
  836. }
  837. }
  838. }
  839. break;
  840. default:
  841. Status = STATUS_INVALID_DEVICE_REQUEST;
  842. break;
  843. }
  844. return Status;
  845. }
  846. NTSTATUS
  847. PnpIrpCompletion(
  848. PDEVICE_OBJECT pDeviceObject,
  849. PIRP pIrp,
  850. PVOID pContext)
  851. /*++
  852. Routine Description:
  853. This routine completes the PNP irp.
  854. Arguments:
  855. DeviceObject - Supplies the device object for the packet being processed.
  856. pIrp - Supplies the Irp being processed
  857. pContext - the completion context
  858. --*/
  859. {
  860. PKEVENT pCompletionEvent = pContext;
  861. KeSetEvent(
  862. pCompletionEvent,
  863. IO_NO_INCREMENT,
  864. FALSE);
  865. return STATUS_MORE_PROCESSING_REQUIRED;
  866. }
  867. #endif