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.

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