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.

1632 lines
40 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dispatch.c
  5. Abstract:
  6. Dispatch routines for the Cluster Network Driver.
  7. Author:
  8. Mike Massa (mikemas) January 3, 1997
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. mikemas 01-03-97 created
  13. Notes:
  14. --*/
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. //
  18. // Data
  19. //
  20. PCN_FSCONTEXT CnExclusiveChannel = NULL;
  21. //
  22. // Un-exported Prototypes
  23. //
  24. NTSYSAPI
  25. NTSTATUS
  26. NTAPI
  27. ZwOpenProcess (
  28. OUT PHANDLE ProcessHandle,
  29. IN ACCESS_MASK DesiredAccess,
  30. IN POBJECT_ATTRIBUTES ObjectAttributes,
  31. IN PCLIENT_ID ClientId OPTIONAL
  32. );
  33. //
  34. // Local Prototypes
  35. //
  36. FILE_FULL_EA_INFORMATION UNALIGNED *
  37. CnFindEA(
  38. PFILE_FULL_EA_INFORMATION StartEA,
  39. CHAR *TargetName,
  40. USHORT TargetNameLength
  41. );
  42. NTSTATUS
  43. CnCreate(
  44. IN PDEVICE_OBJECT DeviceObject,
  45. IN PIRP Irp,
  46. IN PIO_STACK_LOCATION IrpSp
  47. );
  48. NTSTATUS
  49. CnCleanup(
  50. IN PDEVICE_OBJECT DeviceObject,
  51. IN PIRP Irp,
  52. IN PIO_STACK_LOCATION IrpSp
  53. );
  54. NTSTATUS
  55. CnClose(
  56. IN PDEVICE_OBJECT DeviceObject,
  57. IN PIRP Irp,
  58. IN PIO_STACK_LOCATION IrpSp
  59. );
  60. NTSTATUS
  61. CnEnableShutdownOnClose(
  62. PIRP Irp
  63. );
  64. //
  65. // Mark pageable code.
  66. //
  67. #ifdef ALLOC_PRAGMA
  68. #pragma alloc_text(PAGE, CnDispatchDeviceControl)
  69. #pragma alloc_text(PAGE, CnFindEA)
  70. #pragma alloc_text(PAGE, CnCreate)
  71. #pragma alloc_text(PAGE, CnEnableShutdownOnClose)
  72. #endif // ALLOC_PRAGMA
  73. //
  74. // Function definitions
  75. //
  76. VOID
  77. CnDereferenceFsContext(
  78. PCN_FSCONTEXT FsContext
  79. )
  80. {
  81. LONG newValue = InterlockedDecrement(&(FsContext->ReferenceCount));
  82. CnAssert(newValue >= 0);
  83. if (newValue != 0) {
  84. return;
  85. }
  86. //
  87. // Set the cleanup event.
  88. //
  89. KeSetEvent(&(FsContext->CleanupEvent), 0, FALSE);
  90. return;
  91. } // CnDereferenceFsContext
  92. NTSTATUS
  93. CnMarkRequestPending(
  94. PIRP Irp,
  95. PIO_STACK_LOCATION IrpSp,
  96. PDRIVER_CANCEL CancelRoutine
  97. )
  98. /*++
  99. Notes:
  100. Called with IoCancelSpinLock held.
  101. --*/
  102. {
  103. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  104. CN_IRQL oldIrql;
  105. //
  106. // Set up for cancellation
  107. //
  108. CnAssert(Irp->CancelRoutine == NULL);
  109. if (!Irp->Cancel) {
  110. IoMarkIrpPending(Irp);
  111. IoSetCancelRoutine(Irp, CancelRoutine);
  112. CnReferenceFsContext(fsContext);
  113. IF_CNDBG(CN_DEBUG_IRP) {
  114. CNPRINT((
  115. "[Clusnet] Pending irp %p fileobj %p.\n",
  116. Irp,
  117. IrpSp->FileObject
  118. ));
  119. }
  120. return(STATUS_SUCCESS);
  121. }
  122. //
  123. // The IRP has already been cancelled.
  124. //
  125. IF_CNDBG(CN_DEBUG_IRP) {
  126. CNPRINT(("[Clusnet] irp %p already cancelled.\n", Irp));
  127. }
  128. return(STATUS_CANCELLED);
  129. } // CnPrepareIrpForCancel
  130. VOID
  131. CnCompletePendingRequest(
  132. IN PIRP Irp,
  133. IN NTSTATUS Status,
  134. IN ULONG BytesReturned
  135. )
  136. /*++
  137. Routine Description:
  138. Completes a pending request.
  139. Arguments:
  140. Irp - A pointer to the IRP for this request.
  141. Status - The final status of the request.
  142. BytesReturned - Bytes sent/received information.
  143. Return Value:
  144. None.
  145. Notes:
  146. Called with IoCancelSpinLock held. Lock Irql is stored in Irp->CancelIrql.
  147. Releases IoCancelSpinLock before returning.
  148. --*/
  149. {
  150. PIO_STACK_LOCATION irpSp;
  151. PCN_FSCONTEXT fsContext;
  152. irpSp = IoGetCurrentIrpStackLocation(Irp);
  153. fsContext = (PCN_FSCONTEXT) irpSp->FileObject->FsContext;
  154. IoSetCancelRoutine(Irp, NULL);
  155. CnDereferenceFsContext(fsContext);
  156. IF_CNDBG(CN_DEBUG_IRP) {
  157. CNPRINT((
  158. "[Clusnet] Completing irp %p fileobj %p, status %lx\n",
  159. Irp,
  160. irpSp->FileObject,
  161. Status
  162. ));
  163. }
  164. if (Irp->Cancel || fsContext->CancelIrps) {
  165. IF_CNDBG(CN_DEBUG_IRP) {
  166. CNPRINT(("[Clusnet] Completed irp %p was cancelled\n", Irp));
  167. }
  168. Status = (NTSTATUS) STATUS_CANCELLED;
  169. BytesReturned = 0;
  170. }
  171. CnReleaseCancelSpinLock(Irp->CancelIrql);
  172. Irp->IoStatus.Status = (NTSTATUS) Status;
  173. Irp->IoStatus.Information = BytesReturned;
  174. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  175. return;
  176. } // CnCompletePendingRequest
  177. PFILE_OBJECT
  178. CnBeginCancelRoutine(
  179. IN PIRP Irp
  180. )
  181. /*++
  182. Routine Description:
  183. Performs common bookkeeping for irp cancellation.
  184. Arguments:
  185. Irp - Pointer to I/O request packet
  186. Return Value:
  187. A pointer to the file object on which the irp was submitted.
  188. This value must be passed to CnEndCancelRequest().
  189. Notes:
  190. Called with cancel spinlock held.
  191. --*/
  192. {
  193. PIO_STACK_LOCATION irpSp;
  194. PCN_FSCONTEXT fsContext;
  195. NTSTATUS status = STATUS_SUCCESS;
  196. PFILE_OBJECT fileObject;
  197. CnAssert(Irp->Cancel);
  198. irpSp = IoGetCurrentIrpStackLocation(Irp);
  199. fileObject = irpSp->FileObject;
  200. fsContext = (PCN_FSCONTEXT) fileObject->FsContext;
  201. IoSetCancelRoutine(Irp, NULL);
  202. //
  203. // Add a reference so the object can't be closed while the cancel routine
  204. // is executing.
  205. //
  206. CnReferenceFsContext(fsContext);
  207. IF_CNDBG(CN_DEBUG_IRP) {
  208. CNPRINT((
  209. "[Clusnet] Cancelling irp %p fileobj %p\n",
  210. Irp,
  211. fileObject
  212. ));
  213. }
  214. return(fileObject);
  215. } // CnBeginCancelRoutine
  216. VOID
  217. CnEndCancelRoutine(
  218. PFILE_OBJECT FileObject
  219. )
  220. /*++
  221. Routine Description:
  222. Performs common bookkeeping for irp cancellation.
  223. Arguments:
  224. Return Value:
  225. Notes:
  226. Called with cancel spinlock held.
  227. --*/
  228. {
  229. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) FileObject->FsContext;
  230. //
  231. // Remove the reference placed on the endpoint by the cancel routine.
  232. //
  233. CnDereferenceFsContext(fsContext);
  234. IF_CNDBG(CN_DEBUG_IRP) {
  235. CNPRINT((
  236. "[Clusnet] Finished cancelling, fileobj %p\n",
  237. FileObject
  238. ));
  239. }
  240. return;
  241. } // CnEndCancelRoutine
  242. NTSTATUS
  243. CnDispatchInternalDeviceControl(
  244. IN PDEVICE_OBJECT DeviceObject,
  245. IN PIRP Irp
  246. )
  247. /*++
  248. Routine Description:
  249. This is the dispatch routine for Internal Device Control IRPs.
  250. This is the hot path for kernel-mode TDI clients.
  251. Arguments:
  252. DeviceObject - Pointer to device object for target device
  253. Irp - Pointer to I/O request packet
  254. Return Value:
  255. An NT status code.
  256. --*/
  257. {
  258. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  259. NTSTATUS status = STATUS_SUCCESS;
  260. ULONG fileType = (ULONG)((ULONG_PTR)irpSp->FileObject->FsContext2);
  261. #if DBG
  262. KIRQL entryIrql = KeGetCurrentIrql();
  263. #endif // DBG
  264. Irp->IoStatus.Information = 0;
  265. if (DeviceObject == CdpDeviceObject) {
  266. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  267. if (irpSp->MinorFunction == TDI_SEND_DATAGRAM) {
  268. status = CxSendDatagram(Irp, irpSp);
  269. #if DBG
  270. CnAssert(entryIrql == KeGetCurrentIrql());
  271. #endif // DBG
  272. return(status);
  273. }
  274. else if (irpSp->MinorFunction == TDI_RECEIVE_DATAGRAM) {
  275. status = CxReceiveDatagram(Irp, irpSp);
  276. #if DBG
  277. CnAssert(entryIrql == KeGetCurrentIrql());
  278. #endif // DBG
  279. return(status);
  280. }
  281. else if (irpSp->MinorFunction == TDI_SET_EVENT_HANDLER) {
  282. status = CxSetEventHandler(Irp, irpSp);
  283. #if DBG
  284. CnAssert(entryIrql == KeGetCurrentIrql());
  285. #endif // DBG
  286. return(status);
  287. }
  288. //
  289. // Fall through to common code.
  290. //
  291. }
  292. //
  293. // These functions are common to all endpoint types.
  294. //
  295. switch(irpSp->MinorFunction) {
  296. case TDI_QUERY_INFORMATION:
  297. status = CxQueryInformation(Irp, irpSp);
  298. break;
  299. case TDI_SET_INFORMATION:
  300. case TDI_ACTION:
  301. CNPRINT((
  302. "[Clusnet] Call to unimplemented TDI function 0x%x\n",
  303. irpSp->MinorFunction
  304. ));
  305. status = STATUS_NOT_IMPLEMENTED;
  306. break;
  307. default:
  308. CNPRINT((
  309. "[Clusnet] Call to invalid TDI function 0x%x\n",
  310. irpSp->MinorFunction
  311. ));
  312. status = STATUS_INVALID_DEVICE_REQUEST;
  313. }
  314. }
  315. else {
  316. CNPRINT((
  317. "[Clusnet] Invalid internal device control function 0x%x on device %ws\n",
  318. irpSp->MinorFunction,
  319. DD_CLUSNET_DEVICE_NAME
  320. ));
  321. status = STATUS_INVALID_DEVICE_REQUEST;
  322. }
  323. Irp->IoStatus.Status = status;
  324. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  325. #if DBG
  326. CnAssert(entryIrql == KeGetCurrentIrql());
  327. #endif // DBG
  328. return(status);
  329. } // CnDispatchInternalDeviceControl
  330. NTSTATUS
  331. CnDispatchDeviceControl(
  332. IN PDEVICE_OBJECT DeviceObject,
  333. IN PIRP Irp
  334. )
  335. /*++
  336. Routine Description:
  337. This is the top-level dispatch routine for Device Control IRPs.
  338. Arguments:
  339. DeviceObject - Pointer to device object for target device
  340. Irp - Pointer to I/O request packet
  341. Return Value:
  342. An NT status code.
  343. Notes:
  344. This routine completes any IRPs for which the return code is not
  345. STATUS_PENDING.
  346. --*/
  347. {
  348. NTSTATUS status;
  349. CCHAR ioIncrement = IO_NO_INCREMENT;
  350. BOOLEAN resourceAcquired = FALSE;
  351. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  352. ULONG ioControlCode =
  353. irpSp->Parameters.DeviceIoControl.IoControlCode;
  354. ULONG fileType =
  355. (ULONG) ((ULONG_PTR) irpSp->FileObject->FsContext2);
  356. PAGED_CODE();
  357. //
  358. // Set this in advance. Any subsequent dispatch routine that cares
  359. // about it will modify it itself.
  360. //
  361. Irp->IoStatus.Information = 0;
  362. //
  363. // The following commands are valid on only TDI address objects.
  364. //
  365. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  366. if (ioControlCode == IOCTL_CX_IGNORE_NODE_STATE) {
  367. status = CxDispatchDeviceControl(Irp, irpSp);
  368. }
  369. else {
  370. //
  371. // Not handled. Return an error.
  372. //
  373. status = STATUS_INVALID_DEVICE_REQUEST;
  374. }
  375. goto complete_request;
  376. }
  377. //
  378. // The remaining commands are valid for control channels.
  379. //
  380. CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
  381. //
  382. // The following set of commands affect only this file object and
  383. // can be issued at any time. We do not need to hold the CnResource
  384. // in order to process them. Nor do we need to be in the initialized.
  385. // state.
  386. //
  387. switch(ioControlCode) {
  388. case IOCTL_CLUSNET_SET_EVENT_MASK:
  389. {
  390. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  391. PCLUSNET_SET_EVENT_MASK_REQUEST request;
  392. ULONG requestSize;
  393. request = (PCLUSNET_SET_EVENT_MASK_REQUEST)
  394. Irp->AssociatedIrp.SystemBuffer;
  395. requestSize =
  396. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  397. if (requestSize >= sizeof(CLUSNET_SET_EVENT_MASK_REQUEST))
  398. {
  399. //
  400. // Kernel mode callers must supply a callback.
  401. // User mode callers must not.
  402. //
  403. if ( !( (Irp->RequestorMode == KernelMode) &&
  404. (request->KmodeEventCallback == NULL)
  405. )
  406. &&
  407. !( (Irp->RequestorMode == UserMode) &&
  408. (request->KmodeEventCallback != NULL)
  409. )
  410. )
  411. {
  412. status = CnSetEventMask( fsContext, request );
  413. }
  414. else {
  415. status = STATUS_INVALID_PARAMETER;
  416. }
  417. }
  418. else {
  419. status = STATUS_INVALID_PARAMETER;
  420. }
  421. }
  422. goto complete_request;
  423. case IOCTL_CLUSNET_GET_NEXT_EVENT:
  424. {
  425. PCLUSNET_EVENT_RESPONSE response;
  426. ULONG responseSize;
  427. responseSize =
  428. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  429. if ( (responseSize < sizeof(CLUSNET_EVENT_RESPONSE))) {
  430. status = STATUS_INVALID_PARAMETER;
  431. }
  432. else {
  433. status = CnGetNextEvent( Irp, irpSp );
  434. ioIncrement = IO_NETWORK_INCREMENT;
  435. }
  436. }
  437. goto complete_request;
  438. } // end of switch
  439. //
  440. // Not handled yet. Fall through.
  441. //
  442. if (ClusnetIsGeneralIoctl(ioControlCode)) {
  443. if (!ClusnetIsNTEIoctl(ioControlCode)) {
  444. //
  445. // The following commands require exclusive access to CnResource.
  446. //
  447. resourceAcquired = CnAcquireResourceExclusive(
  448. CnResource,
  449. TRUE
  450. );
  451. if (!resourceAcquired) {
  452. CnAssert(resourceAcquired == TRUE);
  453. status = STATUS_UNSUCCESSFUL;
  454. goto complete_request;
  455. }
  456. switch(ioControlCode) {
  457. case IOCTL_CLUSNET_INITIALIZE:
  458. if (CnState == CnStateShutdown) {
  459. PCLUSNET_INITIALIZE_REQUEST request;
  460. ULONG requestSize;
  461. request = (PCLUSNET_INITIALIZE_REQUEST)
  462. Irp->AssociatedIrp.SystemBuffer;
  463. requestSize =
  464. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  465. if (requestSize < sizeof(CLUSNET_INITIALIZE_REQUEST)) {
  466. status = STATUS_INVALID_PARAMETER;
  467. }
  468. else {
  469. status = CnInitialize(
  470. request->LocalNodeId,
  471. request->MaxNodes
  472. );
  473. }
  474. }
  475. else {
  476. status = STATUS_INVALID_DEVICE_REQUEST;
  477. }
  478. goto complete_request;
  479. case IOCTL_CLUSNET_ENABLE_SHUTDOWN_ON_CLOSE:
  480. status = CnEnableShutdownOnClose(Irp);
  481. goto complete_request;
  482. case IOCTL_CLUSNET_DISABLE_SHUTDOWN_ON_CLOSE:
  483. {
  484. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  485. fsContext->ShutdownOnClose = FALSE;
  486. if ( ClussvcProcessHandle ) {
  487. CnCloseProcessHandle( &ClussvcProcessHandle );
  488. ClussvcProcessHandle = NULL;
  489. }
  490. status = STATUS_SUCCESS;
  491. }
  492. goto complete_request;
  493. case IOCTL_CLUSNET_HALT:
  494. status = CnShutdown();
  495. CnReleaseResourceForThread(
  496. CnResource,
  497. (ERESOURCE_THREAD) PsGetCurrentThread()
  498. );
  499. resourceAcquired = FALSE;
  500. //
  501. // Issue a Halt event. If clusdisk still has a handle
  502. // to clusnet, then it will release its reservations.
  503. //
  504. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  505. goto complete_request;
  506. case IOCTL_CLUSNET_SHUTDOWN:
  507. status = CnShutdown();
  508. goto complete_request;
  509. case IOCTL_CLUSNET_SET_MEMORY_LOGGING:
  510. {
  511. PCLUSNET_SET_MEM_LOGGING_REQUEST request;
  512. ULONG requestSize;
  513. request = (PCLUSNET_SET_MEM_LOGGING_REQUEST)
  514. Irp->AssociatedIrp.SystemBuffer;
  515. requestSize =
  516. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  517. if ( (requestSize < sizeof(CLUSNET_SET_MEM_LOGGING_REQUEST))) {
  518. status = STATUS_INVALID_PARAMETER;
  519. }
  520. else {
  521. status = CnSetMemLogging( request );
  522. }
  523. }
  524. goto complete_request;
  525. #if DBG
  526. case IOCTL_CLUSNET_SET_DEBUG_MASK:
  527. {
  528. PCLUSNET_SET_DEBUG_MASK_REQUEST request;
  529. ULONG requestSize;
  530. request = (PCLUSNET_SET_DEBUG_MASK_REQUEST)
  531. Irp->AssociatedIrp.SystemBuffer;
  532. requestSize =
  533. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  534. if (requestSize < sizeof(CLUSNET_SET_DEBUG_MASK_REQUEST)) {
  535. status = STATUS_INVALID_PARAMETER;
  536. }
  537. else {
  538. CnDebug = request->DebugMask;
  539. status = STATUS_SUCCESS;
  540. }
  541. }
  542. goto complete_request;
  543. #endif // DBG
  544. } // end switch
  545. } else {
  546. //
  547. // The following commands are only valid if we are
  548. // in the initialized state. The resource is
  549. // acquired to start the operation in the proper
  550. // state; however, the dispatched routines are
  551. // reentrant, so the resource can be released before
  552. // the IRPs complete.
  553. //
  554. resourceAcquired = CnAcquireResourceShared(
  555. CnResource,
  556. TRUE
  557. );
  558. if (!resourceAcquired) {
  559. CnAssert(resourceAcquired == TRUE);
  560. status = STATUS_UNSUCCESSFUL;
  561. goto complete_request;
  562. }
  563. if (CnState != CnStateInitialized) {
  564. status = STATUS_DEVICE_NOT_READY;
  565. goto complete_request;
  566. }
  567. switch(ioControlCode) {
  568. case IOCTL_CLUSNET_ADD_NTE:
  569. status = IpaAddNTE(Irp, irpSp);
  570. goto complete_request;
  571. case IOCTL_CLUSNET_DELETE_NTE:
  572. status = IpaDeleteNTE(Irp, irpSp);
  573. goto complete_request;
  574. case IOCTL_CLUSNET_SET_NTE_ADDRESS:
  575. status = IpaSetNTEAddress(Irp, irpSp);
  576. goto complete_request;
  577. case IOCTL_CLUSNET_ADD_NBT_INTERFACE:
  578. {
  579. PNETBT_ADD_DEL_IF request;
  580. ULONG requestSize;
  581. PNETBT_ADD_DEL_IF response;
  582. ULONG responseSize;
  583. request = (PNETBT_ADD_DEL_IF)
  584. Irp->AssociatedIrp.SystemBuffer;
  585. requestSize =
  586. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  587. responseSize =
  588. irpSp->Parameters.DeviceIoControl.OutputBufferLength;
  589. response = (PNETBT_ADD_DEL_IF) request;
  590. if ( (requestSize < sizeof(NETBT_ADD_DEL_IF)) ||
  591. (responseSize < sizeof(NETBT_ADD_DEL_IF))
  592. )
  593. {
  594. status = STATUS_INVALID_PARAMETER;
  595. }
  596. else {
  597. status = NbtAddIf(
  598. request,
  599. requestSize,
  600. response,
  601. &responseSize
  602. );
  603. CnAssert(status != STATUS_PENDING);
  604. if (NT_SUCCESS(status)) {
  605. Irp->IoStatus.Information = responseSize;
  606. }
  607. }
  608. }
  609. goto complete_request;
  610. case IOCTL_CLUSNET_DEL_NBT_INTERFACE:
  611. {
  612. PNETBT_ADD_DEL_IF request;
  613. ULONG requestSize;
  614. request = (PNETBT_ADD_DEL_IF)
  615. Irp->AssociatedIrp.SystemBuffer;
  616. requestSize =
  617. irpSp->Parameters.DeviceIoControl.InputBufferLength;
  618. if (requestSize < sizeof(NETBT_ADD_DEL_IF)) {
  619. status = STATUS_INVALID_PARAMETER;
  620. }
  621. else {
  622. status = NbtDeleteIf(request, requestSize);
  623. CnAssert(status != STATUS_PENDING);
  624. }
  625. }
  626. goto complete_request;
  627. } // end switch
  628. }
  629. //
  630. // Not handled. Return an error.
  631. //
  632. status = STATUS_INVALID_DEVICE_REQUEST;
  633. goto complete_request;
  634. }
  635. else {
  636. //
  637. // The following commands require shared access to CnResource.
  638. // They are only valid in the initialized state.
  639. //
  640. resourceAcquired = CnAcquireResourceShared(CnResource, TRUE);
  641. if (!resourceAcquired) {
  642. CnAssert(resourceAcquired == TRUE);
  643. status = STATUS_UNSUCCESSFUL;
  644. goto complete_request;
  645. }
  646. if (CnState == CnStateInitialized) {
  647. if (ClusnetIsTransportIoctl(ioControlCode)) {
  648. status = CxDispatchDeviceControl(Irp, irpSp);
  649. }
  650. else {
  651. //
  652. // Not handled. Return an error.
  653. //
  654. status = STATUS_INVALID_DEVICE_REQUEST;
  655. }
  656. }
  657. else {
  658. //
  659. // We haven't been initialized yet. Return an error.
  660. //
  661. status = STATUS_DEVICE_NOT_READY;
  662. }
  663. }
  664. complete_request:
  665. if (resourceAcquired) {
  666. CnReleaseResourceForThread(
  667. CnResource,
  668. (ERESOURCE_THREAD) PsGetCurrentThread()
  669. );
  670. }
  671. if (status != STATUS_PENDING) {
  672. Irp->IoStatus.Status = status;
  673. IoCompleteRequest(Irp, ioIncrement);
  674. }
  675. return(status);
  676. } // CnDispatchDeviceControl
  677. NTSTATUS
  678. CnDispatch(
  679. IN PDEVICE_OBJECT DeviceObject,
  680. IN PIRP Irp
  681. )
  682. /*++
  683. Routine Description:
  684. This is the generic dispatch routine for the driver.
  685. Arguments:
  686. DeviceObject - Pointer to device object for target device
  687. Irp - Pointer to I/O request packet
  688. Return Value:
  689. An NT status code.
  690. --*/
  691. {
  692. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  693. NTSTATUS status = STATUS_SUCCESS;
  694. #if DBG
  695. KIRQL entryIrql = KeGetCurrentIrql();
  696. #endif // DBG
  697. PAGED_CODE();
  698. CnAssert(irpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
  699. switch (irpSp->MajorFunction) {
  700. case IRP_MJ_CREATE:
  701. status = CnCreate(DeviceObject, Irp, irpSp);
  702. break;
  703. case IRP_MJ_CLEANUP:
  704. status = CnCleanup(DeviceObject, Irp, irpSp);
  705. break;
  706. case IRP_MJ_CLOSE:
  707. status = CnClose(DeviceObject, Irp, irpSp);
  708. break;
  709. case IRP_MJ_SHUTDOWN:
  710. IF_CNDBG(CN_DEBUG_INIT) {
  711. CNPRINT(("[ClusNet] Processing shutdown notification...\n"));
  712. }
  713. {
  714. BOOLEAN acquired = CnAcquireResourceExclusive(
  715. CnResource,
  716. TRUE
  717. );
  718. CnAssert(acquired == TRUE);
  719. (VOID) CnShutdown();
  720. if (acquired) {
  721. CnReleaseResourceForThread(
  722. CnResource,
  723. (ERESOURCE_THREAD) PsGetCurrentThread()
  724. );
  725. }
  726. //
  727. // Issue a Halt event. If clusdisk still has a handle
  728. // to clusnet, then it will release its reservations
  729. //
  730. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  731. status = STATUS_SUCCESS;
  732. }
  733. IF_CNDBG(CN_DEBUG_INIT) {
  734. CNPRINT(("[ClusNet] Shutdown processing complete.\n"));
  735. }
  736. break;
  737. default:
  738. IF_CNDBG(CN_DEBUG_IRP) {
  739. CNPRINT((
  740. "[ClusNet] Received IRP with unsupported "
  741. "major function 0x%lx\n",
  742. irpSp->MajorFunction
  743. ));
  744. }
  745. status = STATUS_INVALID_DEVICE_REQUEST;
  746. break;
  747. }
  748. CnAssert(status != STATUS_PENDING);
  749. Irp->IoStatus.Status = status;
  750. Irp->IoStatus.Information = 0;
  751. IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
  752. #if DBG
  753. CnAssert(entryIrql == KeGetCurrentIrql());
  754. #endif // DBG
  755. return(status);
  756. } // CnDispatch
  757. NTSTATUS
  758. CnCreate(
  759. IN PDEVICE_OBJECT DeviceObject,
  760. IN PIRP Irp,
  761. IN PIO_STACK_LOCATION IrpSp
  762. )
  763. /*++
  764. Routine Description:
  765. Handler for create IRPs.
  766. Arguments:
  767. DeviceObject - Pointer to the device object for this request.
  768. Irp - Pointer to I/O request packet
  769. Return Value:
  770. An NT status code.
  771. Notes:
  772. This routine never returns STATUS_PENDING.
  773. The calling routine must complete the IRP.
  774. --*/
  775. {
  776. PCN_FSCONTEXT fsContext;
  777. FILE_FULL_EA_INFORMATION *ea;
  778. FILE_FULL_EA_INFORMATION UNALIGNED *targetEA;
  779. NTSTATUS status;
  780. PAGED_CODE();
  781. //
  782. // Reject unathorized opens
  783. //
  784. if ( (IrpSp->FileObject->RelatedFileObject != NULL) ||
  785. (IrpSp->FileObject->FileName.Length != 0)
  786. )
  787. {
  788. return(STATUS_ACCESS_DENIED);
  789. }
  790. ea = (PFILE_FULL_EA_INFORMATION) Irp->AssociatedIrp.SystemBuffer;
  791. if ((DeviceObject == CdpDeviceObject) && (ea != NULL)) {
  792. IF_CNDBG(CN_DEBUG_OPEN) {
  793. CNPRINT((
  794. "[ClusNet] Opening address object, file object %p\n",
  795. IrpSp->FileObject
  796. ));
  797. }
  798. //
  799. // This is the CDP device. This should be an address object open.
  800. //
  801. targetEA = CnFindEA(
  802. ea,
  803. TdiTransportAddress,
  804. TDI_TRANSPORT_ADDRESS_LENGTH
  805. );
  806. if (targetEA != NULL) {
  807. IrpSp->FileObject->FsContext2 = (PVOID)
  808. TDI_TRANSPORT_ADDRESS_FILE;
  809. //
  810. // Open an address object. This will also allocate the common
  811. // file object context structure.
  812. //
  813. status = CxOpenAddress(
  814. &fsContext,
  815. (TRANSPORT_ADDRESS UNALIGNED *)
  816. &(targetEA->EaName[targetEA->EaNameLength + 1]),
  817. targetEA->EaValueLength
  818. );
  819. }
  820. else {
  821. IF_CNDBG(CN_DEBUG_OPEN) {
  822. CNPRINT((
  823. "[ClusNet] No transport address in EA!\n"
  824. ));
  825. }
  826. status = STATUS_INVALID_PARAMETER;
  827. }
  828. }
  829. else {
  830. //
  831. // This is a control channel open.
  832. //
  833. IF_CNDBG(CN_DEBUG_OPEN) {
  834. IF_CNDBG(CN_DEBUG_OPEN) {
  835. CNPRINT((
  836. "[ClusNet] Opening control channel, file object %p\n",
  837. IrpSp->FileObject
  838. ));
  839. }
  840. }
  841. //
  842. // Allocate our common file object context structure.
  843. //
  844. fsContext = CnAllocatePool(sizeof(CN_FSCONTEXT));
  845. if (fsContext != NULL) {
  846. IrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
  847. CN_INIT_SIGNATURE(fsContext, CN_CONTROL_CHANNEL_SIG);
  848. //
  849. // Check the sharing flags. If this is an exclusive open, check
  850. // to make sure there isn't already an exclusive open outstanding.
  851. //
  852. if (IrpSp->Parameters.Create.ShareAccess == 0) {
  853. BOOLEAN acquired = CnAcquireResourceExclusive(
  854. CnResource,
  855. TRUE
  856. );
  857. CnAssert(acquired == TRUE);
  858. if (CnExclusiveChannel == NULL) {
  859. CnExclusiveChannel = fsContext;
  860. status = STATUS_SUCCESS;
  861. }
  862. else {
  863. CnFreePool(fsContext);
  864. status = STATUS_SHARING_VIOLATION;
  865. }
  866. if (acquired) {
  867. CnReleaseResourceForThread(
  868. CnResource,
  869. (ERESOURCE_THREAD) PsGetCurrentThread()
  870. );
  871. }
  872. }
  873. else {
  874. status = STATUS_SUCCESS;
  875. }
  876. }
  877. else {
  878. status = STATUS_INSUFFICIENT_RESOURCES;
  879. }
  880. }
  881. if (status == STATUS_SUCCESS) {
  882. IrpSp->FileObject->FsContext = fsContext;
  883. fsContext->FileObject = IrpSp->FileObject;
  884. fsContext->ReferenceCount = 1;
  885. fsContext->CancelIrps = FALSE;
  886. fsContext->ShutdownOnClose = FALSE;
  887. KeInitializeEvent(
  888. &(fsContext->CleanupEvent),
  889. SynchronizationEvent,
  890. FALSE
  891. );
  892. //
  893. // init the Event list stuff. We use the empty list test on the
  894. // Linkage field to see if this context block is already been linked
  895. // to the event file object list
  896. //
  897. fsContext->EventMask = 0;
  898. InitializeListHead( &fsContext->EventList );
  899. InitializeListHead( &fsContext->Linkage );
  900. fsContext->EventIrp = NULL;
  901. }
  902. return(status);
  903. } // CnCreate
  904. NTSTATUS
  905. CnCleanup(
  906. IN PDEVICE_OBJECT DeviceObject,
  907. IN PIRP Irp,
  908. IN PIO_STACK_LOCATION IrpSp
  909. )
  910. /*++
  911. Routine Description:
  912. Cancels all outstanding Irps on a device object and waits for them to be
  913. completed before returning.
  914. Arguments:
  915. DeviceObject - Pointer to the device object on which the Irp was received.
  916. Irp - Pointer to I/O request packet
  917. IrpSp - Pointer to the current stack location in the Irp.
  918. Return Value:
  919. An NT status code.
  920. Notes:
  921. This routine may block.
  922. This routine never returns STATUS_PENDING.
  923. The calling routine must complete the IRP.
  924. --*/
  925. {
  926. CN_IRQL oldIrql;
  927. NTSTATUS status;
  928. ULONG fileType =
  929. (ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
  930. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  931. PLIST_ENTRY EventEntry;
  932. PIRP eventIrp;
  933. if (fileType == TDI_TRANSPORT_ADDRESS_FILE) {
  934. //
  935. // This is an address object.
  936. //
  937. CnAssert(DeviceObject == CdpDeviceObject);
  938. status = CxCloseAddress(fsContext);
  939. }
  940. else {
  941. //
  942. // This is a control channel.
  943. //
  944. CnAssert(fileType == TDI_CONTROL_CHANNEL_FILE);
  945. //
  946. // If this channel has a shutdown trigger enabled,
  947. // shutdown the driver.
  948. //
  949. if (fsContext->ShutdownOnClose) {
  950. BOOLEAN shutdownScheduled;
  951. //
  952. // Bug 303422: CnShutdown closes handles that were opened
  953. // in the context of the system process. However, attaching
  954. // to the system process during shutdown can cause a
  955. // bugcheck under certain conditions. The only alternative
  956. // is to defer executing of CnShutdown to a system worker
  957. // thread.
  958. //
  959. // Rather than creating a new event object, leverage the
  960. // cleanup event in the fscontext. It is reset before use
  961. // below.
  962. //
  963. KeClearEvent(&(fsContext->CleanupEvent));
  964. shutdownScheduled = CnHaltOperation(&(fsContext->CleanupEvent));
  965. if (shutdownScheduled) {
  966. status = KeWaitForSingleObject(
  967. &(fsContext->CleanupEvent),
  968. (Irp->RequestorMode == KernelMode
  969. ? Executive : UserRequest),
  970. KernelMode,
  971. FALSE,
  972. NULL
  973. );
  974. CnAssert(NT_SUCCESS(status));
  975. status = STATUS_SUCCESS;
  976. }
  977. //
  978. // issue a Halt event. If clusdisk still has a handle
  979. // to clusnet, then it will release its reservations
  980. //
  981. CnIssueEvent( ClusnetEventHalt, 0, 0 );
  982. }
  983. //
  984. // if this guy forgot to clear the event mask before
  985. // closing the handle, do the appropriate cleanup
  986. // now.
  987. //
  988. if ( fsContext->EventMask ) {
  989. CLUSNET_SET_EVENT_MASK_REQUEST EventRequest;
  990. EventRequest.EventMask = 0;
  991. //
  992. // cannot proceed if CnSetEventMask returns a timeout
  993. // error. this indicates that the fsContext has not
  994. // been removed from the EventFileHandles list because
  995. // of lock starvation.
  996. do {
  997. status = CnSetEventMask( fsContext, &EventRequest );
  998. } while ( status == STATUS_TIMEOUT );
  999. CnAssert( status == STATUS_SUCCESS );
  1000. }
  1001. CnAcquireCancelSpinLock( &oldIrql );
  1002. CnAcquireLockAtDpc( &EventLock );
  1003. if ( fsContext->EventIrp != NULL ) {
  1004. eventIrp = fsContext->EventIrp;
  1005. fsContext->EventIrp = NULL;
  1006. CnReleaseLockFromDpc( &EventLock );
  1007. eventIrp->CancelIrql = oldIrql;
  1008. CnCompletePendingRequest(eventIrp, STATUS_CANCELLED, 0);
  1009. } else {
  1010. CnReleaseLockFromDpc( &EventLock );
  1011. CnReleaseCancelSpinLock( oldIrql );
  1012. }
  1013. }
  1014. //
  1015. // Remove the initial reference and wait for all pending work
  1016. // to complete.
  1017. //
  1018. fsContext->CancelIrps = TRUE;
  1019. KeResetEvent(&(fsContext->CleanupEvent));
  1020. CnDereferenceFsContext(fsContext);
  1021. IF_CNDBG(CN_DEBUG_CLEANUP) {
  1022. CNPRINT((
  1023. "[ClusNet] Waiting for completion of Irps on file object %p\n",
  1024. IrpSp->FileObject
  1025. ));
  1026. }
  1027. status = KeWaitForSingleObject(
  1028. &(fsContext->CleanupEvent),
  1029. (Irp->RequestorMode == KernelMode ? Executive : UserRequest),
  1030. KernelMode,
  1031. FALSE,
  1032. NULL
  1033. );
  1034. CnAssert(NT_SUCCESS(status));
  1035. status = STATUS_SUCCESS;
  1036. IF_CNDBG(CN_DEBUG_CLEANUP) {
  1037. CNPRINT((
  1038. "[Clusnet] Wait on file object %p finished\n",
  1039. IrpSp->FileObject
  1040. ));
  1041. }
  1042. return(status);
  1043. } // CnCleanup
  1044. NTSTATUS
  1045. CnClose(
  1046. IN PDEVICE_OBJECT DeviceObject,
  1047. IN PIRP Irp,
  1048. IN PIO_STACK_LOCATION IrpSp
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Dispatch routine for MJ_CLOSE IRPs. Performs final cleanup of the
  1053. open file object.
  1054. Arguments:
  1055. DeviceObject - Pointer to the device object on which the Irp was received.
  1056. Irp - Pointer to I/O request packet
  1057. IrpSp - Pointer to the current stack location in the Irp.
  1058. Return Value:
  1059. An NT status code.
  1060. Notes:
  1061. This routine never returns STATUS_PENDING.
  1062. The calling routine must complete the IRP.
  1063. --*/
  1064. {
  1065. BOOLEAN acquired;
  1066. PCN_FSCONTEXT fsContext = (PCN_FSCONTEXT) IrpSp->FileObject->FsContext;
  1067. ULONG fileType =
  1068. (ULONG)((ULONG_PTR)IrpSp->FileObject->FsContext2);
  1069. CnAssert(fsContext->ReferenceCount == 0);
  1070. CnAssert(IsListEmpty(&(fsContext->EventList)));
  1071. if (fileType == TDI_CONTROL_CHANNEL_FILE) {
  1072. acquired = CnAcquireResourceExclusive(
  1073. CnResource,
  1074. TRUE
  1075. );
  1076. CnAssert(acquired == TRUE);
  1077. if (CnExclusiveChannel == fsContext) {
  1078. CnExclusiveChannel = NULL;
  1079. }
  1080. if (acquired) {
  1081. CnReleaseResourceForThread(
  1082. CnResource,
  1083. (ERESOURCE_THREAD) PsGetCurrentThread()
  1084. );
  1085. }
  1086. }
  1087. IF_CNDBG(CN_DEBUG_CLOSE) {
  1088. CNPRINT((
  1089. "[ClusNet] Close on file object %p\n",
  1090. IrpSp->FileObject
  1091. ));
  1092. }
  1093. CnFreePool(fsContext);
  1094. return(STATUS_SUCCESS);
  1095. } // CnClose
  1096. FILE_FULL_EA_INFORMATION UNALIGNED *
  1097. CnFindEA(
  1098. PFILE_FULL_EA_INFORMATION StartEA,
  1099. CHAR *TargetName,
  1100. USHORT TargetNameLength
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. Parses and extended attribute list for a given target attribute.
  1105. Arguments:
  1106. StartEA - the first extended attribute in the list.
  1107. TargetName - the name of the target attribute.
  1108. TargetNameLength - the length of the name of the target attribute.
  1109. Return Value:
  1110. A pointer to the requested attribute or NULL if the target wasn't found.
  1111. --*/
  1112. {
  1113. USHORT i;
  1114. BOOLEAN found;
  1115. FILE_FULL_EA_INFORMATION UNALIGNED * CurrentEA;
  1116. FILE_FULL_EA_INFORMATION UNALIGNED * NextEA;
  1117. PAGED_CODE();
  1118. NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *) StartEA;
  1119. do {
  1120. found = TRUE;
  1121. CurrentEA = NextEA;
  1122. NextEA = (FILE_FULL_EA_INFORMATION UNALIGNED *)
  1123. ( ((PUCHAR) StartEA) + CurrentEA->NextEntryOffset);
  1124. if (CurrentEA->EaNameLength != TargetNameLength) {
  1125. continue;
  1126. }
  1127. for (i=0; i < CurrentEA->EaNameLength; i++) {
  1128. if (CurrentEA->EaName[i] == TargetName[i]) {
  1129. continue;
  1130. }
  1131. found = FALSE;
  1132. break;
  1133. }
  1134. if (found) {
  1135. return(CurrentEA);
  1136. }
  1137. } while(CurrentEA->NextEntryOffset != 0);
  1138. return(NULL);
  1139. } // CnFindEA
  1140. NTSTATUS
  1141. CnEnableShutdownOnClose(
  1142. PIRP Irp
  1143. )
  1144. {
  1145. NTSTATUS status;
  1146. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
  1147. PCN_FSCONTEXT fsContext = irpSp->FileObject->FsContext;
  1148. ULONG requestSize;
  1149. CLIENT_ID ClientId;
  1150. OBJECT_ATTRIBUTES ObjAttributes;
  1151. PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST request;
  1152. PAGED_CODE();
  1153. request = (PCLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
  1154. Irp->AssociatedIrp.SystemBuffer;
  1155. requestSize = irpSp->Parameters.DeviceIoControl.InputBufferLength;
  1156. if ( requestSize >= sizeof(CLUSNET_SHUTDOWN_ON_CLOSE_REQUEST)
  1157. )
  1158. {
  1159. //
  1160. // illegal for kernel mode
  1161. //
  1162. if ( Irp->RequestorMode != KernelMode ) {
  1163. //
  1164. // Get a handle to the cluster service process.
  1165. // This is used to kill the service if a poison
  1166. // pkt is received. Since a kernel worker thread
  1167. // is used to kill the cluster service, we need
  1168. // to acquire the handle in the system process.
  1169. //
  1170. IF_CNDBG(CN_DEBUG_INIT) {
  1171. CNPRINT(("[Clusnet] Acquiring process handle\n"));
  1172. }
  1173. if (ClussvcProcessHandle == NULL) {
  1174. KeAttachProcess( CnSystemProcess );
  1175. ClientId.UniqueThread = (HANDLE)NULL;
  1176. ClientId.UniqueProcess = UlongToHandle(request->ProcessId);
  1177. InitializeObjectAttributes(
  1178. &ObjAttributes,
  1179. NULL,
  1180. 0,
  1181. (HANDLE) NULL,
  1182. (PSECURITY_DESCRIPTOR) NULL
  1183. );
  1184. status = ZwOpenProcess(
  1185. &ClussvcProcessHandle,
  1186. 0,
  1187. &ObjAttributes,
  1188. &ClientId
  1189. );
  1190. KeDetachProcess();
  1191. if ( NT_SUCCESS( status )) {
  1192. fsContext->ShutdownOnClose = TRUE;
  1193. } else {
  1194. IF_CNDBG(CN_DEBUG_INIT) {
  1195. CNPRINT((
  1196. "[Clusnet] ZwOpenProcess failed. status = %08X\n",
  1197. status
  1198. ));
  1199. }
  1200. }
  1201. }
  1202. else {
  1203. status = STATUS_INVALID_DEVICE_REQUEST;
  1204. }
  1205. }
  1206. else {
  1207. status = STATUS_INVALID_PARAMETER_MIX;
  1208. }
  1209. }
  1210. else {
  1211. status = STATUS_INVALID_PARAMETER;
  1212. }
  1213. return(status);
  1214. } // CnEnableShutdownOnClose