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.

1095 lines
28 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. spxdrvr.c
  5. Abstract:
  6. This module contains the DriverEntry and other initialization
  7. code for the SPX/SPXII module of the ISN transport.
  8. Author:
  9. Adam Barr (adamba) Original Version
  10. Nikhil Kamkolkar (nikhilk) 11-November-1993
  11. Environment:
  12. Kernel mode
  13. Revision History:
  14. Sanjay Anand (SanjayAn) 14-July-1995
  15. Bug fixes - tagged [SA]
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. // Define module number for event logging entries
  20. #define FILENUM SPXDRVR
  21. // Forward declaration of various routines used in this module.
  22. NTSTATUS
  23. DriverEntry(
  24. IN PDRIVER_OBJECT DriverObject,
  25. IN PUNICODE_STRING RegistryPath);
  26. NTSTATUS
  27. SpxDispatchOpenClose(
  28. IN PDEVICE_OBJECT DeviceObject,
  29. IN PIRP Irp);
  30. NTSTATUS
  31. SpxDeviceControl(
  32. IN PDEVICE_OBJECT DeviceObject,
  33. IN PIRP Irp);
  34. NTSTATUS
  35. SpxDispatchInternal (
  36. IN PDEVICE_OBJECT DeviceObject,
  37. IN PIRP Irp);
  38. NTSTATUS
  39. SpxDispatch(
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp);
  42. VOID
  43. SpxUnload(
  44. IN PDRIVER_OBJECT DriverObject);
  45. VOID
  46. SpxTdiCancel(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp);
  49. #ifdef ALLOC_PRAGMA
  50. #pragma alloc_text(INIT, DriverEntry)
  51. #pragma alloc_text(PAGE, SpxUnload)
  52. #pragma alloc_text(PAGE, SpxDispatch)
  53. #pragma alloc_text(PAGE, SpxDeviceControl)
  54. #pragma alloc_text(PAGE, SpxUnload)
  55. #endif
  56. NTSTATUS
  57. DriverEntry(
  58. IN PDRIVER_OBJECT DriverObject,
  59. IN PUNICODE_STRING RegistryPath
  60. )
  61. /*++
  62. Routine Description:
  63. This routine performs initialization of the SPX ISN module.
  64. It creates the device objects for the transport
  65. provider and performs other driver initialization.
  66. Arguments:
  67. DriverObject - Pointer to driver object created by the system.
  68. RegistryPath - The name of ST's node in the registry.
  69. Return Value:
  70. The function value is the final status from the initialization operation.
  71. --*/
  72. {
  73. UNICODE_STRING deviceName;
  74. NTSTATUS status = STATUS_SUCCESS;
  75. BOOLEAN BoundToIpx = FALSE;
  76. // DBGBRK(FATAL);
  77. // Initialize the Common Transport Environment.
  78. if (CTEInitialize() == 0) {
  79. return (STATUS_UNSUCCESSFUL);
  80. }
  81. // We have this #define'd. Ugh, but CONTAINING_RECORD has problem owise.
  82. //CTEAssert(NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
  83. // Create the device object. (IoCreateDevice zeroes the memory
  84. // occupied by the object.)
  85. RtlInitUnicodeString(&deviceName, SPX_DEVICE_NAME);
  86. status = SpxInitCreateDevice(
  87. DriverObject,
  88. &deviceName);
  89. if (!NT_SUCCESS(status))
  90. {
  91. return(status);
  92. }
  93. do
  94. {
  95. CTEInitLock (&SpxGlobalInterlock);
  96. CTEInitLock (&SpxGlobalQInterlock);
  97. //
  98. // We need the following locks for the NDIS_PACKETPOOL changes [MS]
  99. //
  100. CTEInitLock(&SendHeaderLock);
  101. CTEInitLock(&RecvHeaderLock);
  102. ExInitializeSListHead(&SendPacketList);
  103. ExInitializeSListHead(&RecvPacketList);
  104. // Initialize the unload event
  105. KeInitializeEvent(
  106. &SpxUnloadEvent,
  107. NotificationEvent,
  108. FALSE);
  109. // !!!The device is created at this point!!!
  110. // Get information from the registry.
  111. status = SpxInitGetConfiguration(
  112. RegistryPath,
  113. &SpxDevice->dev_ConfigInfo);
  114. if (!NT_SUCCESS(status))
  115. {
  116. break;
  117. }
  118. #if defined(_PNP_POWER)
  119. //
  120. // Make Tdi ready for pnp notifications before binding
  121. // to IPX
  122. //
  123. TdiInitialize();
  124. // Initialize the timer system. This should be done before
  125. // binding to ipx because we should have timers intialized
  126. // before ipx calls our pnp indications.
  127. if (!NT_SUCCESS(status = SpxTimerInit()))
  128. {
  129. break;
  130. }
  131. #endif _PNP_POWER
  132. // Bind to the IPX transport.
  133. if (!NT_SUCCESS(status = SpxInitBindToIpx()))
  134. {
  135. // Have ipx name here as second string
  136. LOG_ERROR(
  137. EVENT_TRANSPORT_BINDING_FAILED,
  138. status,
  139. NULL,
  140. NULL,
  141. 0);
  142. break;
  143. }
  144. BoundToIpx = TRUE;
  145. #if !defined(_PNP_POWER)
  146. // Initialize the timer system
  147. if (!NT_SUCCESS(status = SpxTimerInit()))
  148. {
  149. break;
  150. }
  151. #endif !_PNP_POWER
  152. // Initialize the block manager
  153. if (!NT_SUCCESS(status = SpxInitMemorySystem(SpxDevice)))
  154. {
  155. // Stop the timer subsystem
  156. SpxTimerFlushAndStop();
  157. break;
  158. }
  159. // Initialize the driver object with this driver's entry points.
  160. DriverObject->MajorFunction [IRP_MJ_CREATE] = SpxDispatchOpenClose;
  161. DriverObject->MajorFunction [IRP_MJ_CLOSE] = SpxDispatchOpenClose;
  162. DriverObject->MajorFunction [IRP_MJ_CLEANUP] = SpxDispatchOpenClose;
  163. DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL]
  164. = SpxDispatch;
  165. DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]
  166. = SpxDispatchInternal;
  167. DriverObject->DriverUnload = SpxUnload;
  168. // Initialize the provider info
  169. SpxQueryInitProviderInfo(&SpxDevice->dev_ProviderInfo);
  170. SpxDevice->dev_CurrentSocket = (USHORT)PARAM(CONFIG_SOCKET_RANGE_START);
  171. // We are open now.
  172. SpxDevice->dev_State = DEVICE_STATE_OPEN;
  173. // Set the window size in statistics
  174. SpxDevice->dev_Stat.MaximumSendWindow =
  175. SpxDevice->dev_Stat.AverageSendWindow = PARAM(CONFIG_WINDOW_SIZE) *
  176. IpxLineInfo.MaximumSendSize;
  177. #if defined(_PNP_POWER)
  178. if ( DEVICE_STATE_CLOSED == SpxDevice->dev_State ) {
  179. SpxDevice->dev_State = DEVICE_STATE_LOADED;
  180. }
  181. #endif _PNP_POWER
  182. } while (FALSE);
  183. DBGPRINT(DEVICE, INFO,
  184. ("SpxInitCreateDevice - Create device %ws\n", deviceName.Buffer));
  185. // Create the device object for the sample transport, allowing
  186. // room at the end for the device name to be stored (for use
  187. // in logging errors).
  188. status = IoCreateDevice(
  189. DriverObject,
  190. 0, //DeviceSize,
  191. &deviceName,
  192. FILE_DEVICE_TRANSPORT,
  193. FILE_DEVICE_SECURE_OPEN,
  194. FALSE,
  195. &SpxDevice->dev_DevObj);
  196. if (!NT_SUCCESS(status)) {
  197. DBGPRINT(DEVICE, ERR, ("IoCreateDevice failed\n"));
  198. //
  199. // We're outta here forever.
  200. //
  201. ExFreePool(SpxDevice);
  202. return status;
  203. }
  204. SpxDevice->dev_DevObj->Flags |= DO_DIRECT_IO;
  205. if (!NT_SUCCESS(status) )
  206. {
  207. // Delete the device and any associated resources created.
  208. if( BoundToIpx ) {
  209. SpxDerefDevice(SpxDevice);
  210. }
  211. SpxDestroyDevice(SpxDevice);
  212. }
  213. return (status);
  214. }
  215. VOID
  216. SpxUnload(
  217. IN PDRIVER_OBJECT DriverObject
  218. )
  219. /*++
  220. Routine Description:
  221. This routine unloads the sample transport driver. The I/O system will not
  222. call us until nobody above has ST open.
  223. Arguments:
  224. DriverObject - Pointer to driver object created by the system.
  225. Return Value:
  226. None. When the function returns, the driver is unloaded.
  227. --*/
  228. {
  229. UNREFERENCED_PARAMETER (DriverObject);
  230. // Stop the timer subsystem
  231. SpxTimerFlushAndStop();
  232. CTEFreeMem(SpxDevice->dev_ConfigInfo);
  233. RtlFreeUnicodeString (&IpxDeviceName);
  234. // Remove creation reference count on the IPX device object.
  235. SpxDerefDevice(SpxDevice);
  236. // Wait on the unload event.
  237. KeWaitForSingleObject(
  238. &SpxUnloadEvent,
  239. Executive,
  240. KernelMode,
  241. TRUE,
  242. (PLARGE_INTEGER)NULL);
  243. // if the device is in a open state - deregister the device object
  244. // with TDI before going away!
  245. //
  246. // if (SpxDevice->dev_State == DEVICE_STATE_OPEN) {
  247. // if (STATUS_SUCCESS != TdiDeregisterDeviceObject(SpxDevice->dev_TdiRegistrationHandle )) {
  248. // DBGPRINT("Cant deregisterdevice object\n");
  249. //}
  250. //}
  251. // Release the block memory stuff
  252. SpxDeInitMemorySystem(SpxDevice);
  253. SpxDestroyDevice(SpxDevice);
  254. return;
  255. }
  256. NTSTATUS
  257. SpxDispatch(
  258. IN PDEVICE_OBJECT DeviceObject,
  259. IN PIRP Irp
  260. )
  261. /*++
  262. Routine Description:
  263. This routine is the main dispatch routine for the ST device driver.
  264. It accepts an I/O Request Packet, performs the request, and then
  265. returns with the appropriate status.
  266. Arguments:
  267. DeviceObject - Pointer to the device object for this driver.
  268. Irp - Pointer to the request packet representing the I/O request.
  269. Return Value:
  270. The function value is the status of the operation.
  271. --*/
  272. {
  273. NTSTATUS Status;
  274. PDEVICE Device = SpxDevice; // (PDEVICE)DeviceObject;
  275. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  276. if (Device->dev_State != DEVICE_STATE_OPEN) {
  277. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  278. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  279. return STATUS_INVALID_DEVICE_STATE;
  280. }
  281. // Make sure status information is consistent every time.
  282. IoMarkIrpPending (Irp);
  283. Irp->IoStatus.Status = STATUS_PENDING;
  284. Irp->IoStatus.Information = 0;
  285. // Case on the function that is being performed by the requestor. If the
  286. // operation is a valid one for this device, then make it look like it was
  287. // successfully completed, where possible.
  288. switch (IrpSp->MajorFunction) {
  289. case IRP_MJ_DEVICE_CONTROL:
  290. Status = SpxDeviceControl (DeviceObject, Irp);
  291. break;
  292. default:
  293. Status = STATUS_INVALID_DEVICE_REQUEST;
  294. //
  295. // Complete the Irp here instead of below.
  296. //
  297. IrpSp->Control &= ~SL_PENDING_RETURNED;
  298. Irp->IoStatus.Status = Status;
  299. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  300. } // major function switch
  301. /* Commented out and re-located to the default case above.
  302. if (Status != STATUS_PENDING) {
  303. IrpSp->Control &= ~SL_PENDING_RETURNED;
  304. Irp->IoStatus.Status = Status;
  305. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  306. }
  307. */
  308. // Return the immediate status code to the caller.
  309. return Status;
  310. } // SpxDispatch
  311. VOID
  312. SpxAssignControlChannelId(
  313. IN PDEVICE Device,
  314. IN PIRP Request
  315. )
  316. /*++
  317. Routine Description:
  318. This routine is required to ensure that the Device lock (to protect the ControlChannelId in the Device)
  319. is not taken in a pageable routine (SpxDispatchOpenClose).
  320. NOTE: SPX returns the ControlChannelId in the Request, but never uses it later when it comes down in a
  321. close/cleanup. The CCID is a ULONG; in future, if we start using this field (as in IPX which uses these Ids
  322. to determine lineup Irps to complete), then we may run out of numbers (since we monotonically increase the CCID);
  323. though there is a low chance of that since we will probably run out of memory before that! Anyhow, if that
  324. happens, one solution (used in IPX) is to make the CCID into a Large Integer and pack the values into the
  325. REQUEST_OPEN_TYPE(Irp) too.
  326. Arguments:
  327. Device - Pointer to the device object for this driver.
  328. Request - Pointer to the request packet representing the I/O request.
  329. Return Value:
  330. None.
  331. --*/
  332. {
  333. CTELockHandle LockHandle;
  334. CTEGetLock (&Device->dev_Lock, &LockHandle);
  335. REQUEST_OPEN_CONTEXT(Request) = UlongToPtr(Device->dev_CcId);
  336. ++Device->dev_CcId;
  337. if (Device->dev_CcId == 0) {
  338. Device->dev_CcId = 1;
  339. }
  340. CTEFreeLock (&Device->dev_Lock, LockHandle);
  341. }
  342. NTSTATUS
  343. SpxDispatchOpenClose(
  344. IN PDEVICE_OBJECT DeviceObject,
  345. IN PIRP Irp
  346. )
  347. /*++
  348. Routine Description:
  349. This routine is the main dispatch routine for the ST device driver.
  350. It accepts an I/O Request Packet, performs the request, and then
  351. returns with the appropriate status.
  352. Arguments:
  353. DeviceObject - Pointer to the device object for this driver.
  354. Irp - Pointer to the request packet representing the I/O request.
  355. Return Value:
  356. The function value is the status of the operation.
  357. --*/
  358. {
  359. PDEVICE Device = SpxDevice; // (PDEVICE)DeviceObject;
  360. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  361. BOOLEAN found;
  362. PREQUEST Request;
  363. UINT i;
  364. PFILE_FULL_EA_INFORMATION openType;
  365. CONNECTION_CONTEXT connCtx;
  366. #if !defined(_PNP_POWER)
  367. if (Device->dev_State != DEVICE_STATE_OPEN) {
  368. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  369. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  370. return STATUS_INVALID_DEVICE_STATE;
  371. }
  372. #endif !_PNP_POWER
  373. // Allocate a request to track this IRP.
  374. Request = SpxAllocateRequest (Device, Irp);
  375. IF_NOT_ALLOCATED(Request) {
  376. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  377. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  378. return STATUS_INVALID_DEVICE_STATE;
  379. }
  380. // Make sure status information is consistent every time.
  381. MARK_REQUEST_PENDING(Request);
  382. REQUEST_STATUS(Request) = STATUS_PENDING;
  383. REQUEST_INFORMATION(Request) = 0;
  384. // Case on the function that is being performed by the requestor. If the
  385. // operation is a valid one for this device, then make it look like it was
  386. // successfully completed, where possible.
  387. switch (REQUEST_MAJOR_FUNCTION(Request)) {
  388. // The Create function opens a transport object (either address or
  389. // connection). Access checking is performed on the specified
  390. // address to ensure security of transport-layer addresses.
  391. case IRP_MJ_CREATE:
  392. #if defined(_PNP_POWER)
  393. if (Device->dev_State != DEVICE_STATE_OPEN) {
  394. Status = STATUS_INVALID_DEVICE_STATE;
  395. break;
  396. }
  397. #endif _PNP_POWER
  398. openType = OPEN_REQUEST_EA_INFORMATION(Request);
  399. if (openType != NULL) {
  400. found = TRUE;
  401. //DbgPrint("EA:%d, TdiTransportAddress Length : %d \n", openType->EaNameLength, TDI_TRANSPORT_ADDRESS_LENGTH);
  402. for (i = 0; i < openType->EaNameLength && i < TDI_TRANSPORT_ADDRESS_LENGTH; i++) {
  403. if (openType->EaName[i] == TdiTransportAddress[i]) {
  404. continue;
  405. } else {
  406. found = FALSE;
  407. break;
  408. }
  409. }
  410. if (found) {
  411. Status = SpxAddrOpen (Device, Request);
  412. break;
  413. }
  414. // Connection?
  415. found = TRUE;
  416. for (i=0;i<openType->EaNameLength && i < TDI_CONNECTION_CONTEXT_LENGTH;i++) {
  417. if (openType->EaName[i] == TdiConnectionContext[i]) {
  418. continue;
  419. } else {
  420. found = FALSE;
  421. break;
  422. }
  423. }
  424. if (found) {
  425. if (openType->EaValueLength < sizeof(CONNECTION_CONTEXT))
  426. {
  427. DBGPRINT(CREATE, ERR,
  428. ("Create: Context size %d\n", openType->EaValueLength));
  429. Status = STATUS_EA_LIST_INCONSISTENT;
  430. break;
  431. }
  432. connCtx =
  433. *((CONNECTION_CONTEXT UNALIGNED *)
  434. &openType->EaName[openType->EaNameLength+1]);
  435. Status = SpxConnOpen(
  436. Device,
  437. connCtx,
  438. Request);
  439. break;
  440. }
  441. } else {
  442. //
  443. // Takes a lock in a Pageable routine - call another (non-paged) function to do that.
  444. //
  445. if (Device->dev_State != DEVICE_STATE_OPEN) {
  446. DBGPRINT(TDI, ERR, ("DEVICE NOT OPEN - letting thru control channel only\n"))
  447. }
  448. SpxAssignControlChannelId(Device, Request);
  449. REQUEST_OPEN_TYPE(Request) = UlongToPtr(SPX_FILE_TYPE_CONTROL);
  450. Status = STATUS_SUCCESS;
  451. }
  452. break;
  453. case IRP_MJ_CLOSE:
  454. #if defined(_PNP_POWER)
  455. if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
  456. Status = STATUS_INVALID_DEVICE_STATE;
  457. break;
  458. }
  459. #endif _PNP_POWER
  460. // The Close function closes a transport endpoint, terminates
  461. // all outstanding transport activity on the endpoint, and unbinds
  462. // the endpoint from its transport address, if any. If this
  463. // is the last transport endpoint bound to the address, then
  464. // the address is removed from the provider.
  465. switch ((ULONG_PTR)REQUEST_OPEN_TYPE(Request)) {
  466. case TDI_TRANSPORT_ADDRESS_FILE:
  467. Status = SpxAddrFileClose(Device, Request);
  468. break;
  469. case TDI_CONNECTION_FILE:
  470. Status = SpxConnClose(Device, Request);
  471. break;
  472. case SPX_FILE_TYPE_CONTROL:
  473. Status = STATUS_SUCCESS;
  474. break;
  475. default:
  476. Status = STATUS_INVALID_HANDLE;
  477. }
  478. break;
  479. case IRP_MJ_CLEANUP:
  480. #if defined(_PNP_POWER)
  481. if ((Device->dev_State != DEVICE_STATE_OPEN) && ( Device->dev_State != DEVICE_STATE_LOADED )) {
  482. Status = STATUS_INVALID_DEVICE_STATE;
  483. break;
  484. }
  485. #endif _PNP_POWER
  486. // Handle the two stage IRP for a file close operation. When the first
  487. // stage hits, run down all activity on the object of interest. This
  488. // do everything to it but remove the creation hold. Then, when the
  489. // CLOSE irp hits, actually close the object.
  490. switch ((ULONG_PTR)REQUEST_OPEN_TYPE(Request)) {
  491. case TDI_TRANSPORT_ADDRESS_FILE:
  492. Status = SpxAddrFileCleanup(Device, Request);
  493. break;
  494. case TDI_CONNECTION_FILE:
  495. Status = SpxConnCleanup(Device, Request);
  496. break;
  497. case SPX_FILE_TYPE_CONTROL:
  498. Status = STATUS_SUCCESS;
  499. break;
  500. default:
  501. Status = STATUS_INVALID_HANDLE;
  502. }
  503. break;
  504. default:
  505. Status = STATUS_INVALID_DEVICE_REQUEST;
  506. } // major function switch
  507. if (Status != STATUS_PENDING) {
  508. UNMARK_REQUEST_PENDING(Request);
  509. REQUEST_STATUS(Request) = Status;
  510. SpxCompleteRequest (Request);
  511. SpxFreeRequest (Device, Request);
  512. }
  513. // Return the immediate status code to the caller.
  514. return Status;
  515. } // SpxDispatchOpenClose
  516. NTSTATUS
  517. SpxDeviceControl(
  518. IN PDEVICE_OBJECT DeviceObject,
  519. IN PIRP Irp
  520. )
  521. /*++
  522. Routine Description:
  523. This routine dispatches TDI request types to different handlers based
  524. on the minor IOCTL function code in the IRP's current stack location.
  525. In addition to cracking the minor function code, this routine also
  526. reaches into the IRP and passes the packetized parameters stored there
  527. as parameters to the various TDI request handlers so that they are
  528. not IRP-dependent.
  529. Arguments:
  530. DeviceObject - Pointer to the device object for this driver.
  531. Irp - Pointer to the request packet representing the I/O request.
  532. Return Value:
  533. The function value is the status of the operation.
  534. --*/
  535. {
  536. NTSTATUS Status;
  537. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
  538. // Convert the user call to the proper internal device call.
  539. Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
  540. if (Status == STATUS_SUCCESS) {
  541. // If TdiMapUserRequest returns SUCCESS then the IRP
  542. // has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
  543. // IRP, so we dispatch it as usual. The IRP will
  544. // be completed by this call.
  545. Status = SpxDispatchInternal (DeviceObject, Irp);
  546. //
  547. // Return the proper error code here. If SpxDispatchInternal returns an error,
  548. // then we used to map it to pending below; this is wrong since the client above
  549. // us could wait for ever since the IO subsystem does not set the event if an
  550. // error is returned and the Irp is not marked pending.
  551. //
  552. // Status = STATUS_PENDING;
  553. } else {
  554. DBGPRINT(TDI, DBG,
  555. ("Unknown Tdi code in Irp: %lx\n", Irp));
  556. //
  557. // Complete the Irp....
  558. //
  559. IrpSp->Control &= ~SL_PENDING_RETURNED;
  560. Irp->IoStatus.Status = Status;
  561. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  562. }
  563. return Status;
  564. } // SpxDeviceControl
  565. NTSTATUS
  566. SpxDispatchInternal (
  567. IN PDEVICE_OBJECT DeviceObject,
  568. IN PIRP Irp
  569. )
  570. /*++
  571. Routine Description:
  572. This routine dispatches TDI request types to different handlers based
  573. on the minor IOCTL function code in the IRP's current stack location.
  574. In addition to cracking the minor function code, this routine also
  575. reaches into the IRP and passes the packetized parameters stored there
  576. as parameters to the various TDI request handlers so that they are
  577. not IRP-dependent.
  578. Arguments:
  579. DeviceObject - Pointer to the device object for this driver.
  580. Irp - Pointer to the request packet representing the I/O request.
  581. Return Value:
  582. The function value is the status of the operation.
  583. --*/
  584. {
  585. PREQUEST Request;
  586. KIRQL oldIrql;
  587. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  588. PDEVICE Device = SpxDevice; // (PDEVICE)DeviceObject;
  589. BOOLEAN CompleteIrpIfCancel = FALSE;
  590. //
  591. // AFD asks SPX about its provider info before SPX is out of driver entry.
  592. // We need work around this by letting TDI_QUERY_INFORMATION through. [Shreem]
  593. //
  594. if (Device->dev_State != DEVICE_STATE_OPEN)
  595. {
  596. if ((TDI_QUERY_INFORMATION == (IoGetCurrentIrpStackLocation(Irp))->MinorFunction) &&
  597. (TDI_QUERY_PROVIDER_INFO == ((PTDI_REQUEST_KERNEL_QUERY_INFORMATION)REQUEST_PARAMETERS(Irp))->QueryType))
  598. {
  599. DBGPRINT(TDI, ERR,
  600. ("SpxDispatchIoctl: Letting through since it is a QueryProviderInformation\n"));
  601. }
  602. else
  603. {
  604. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  605. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  606. return STATUS_INVALID_DEVICE_STATE;
  607. }
  608. }
  609. // Allocate a request to track this IRP.
  610. Request = SpxAllocateRequest (Device, Irp);
  611. IF_NOT_ALLOCATED(Request)
  612. {
  613. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  614. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  615. return STATUS_INVALID_DEVICE_STATE;
  616. }
  617. // Make sure status information is consistent every time.
  618. MARK_REQUEST_PENDING(Request);
  619. REQUEST_STATUS(Request) = STATUS_PENDING;
  620. REQUEST_INFORMATION(Request) = 0;
  621. // Cancel irp
  622. IoAcquireCancelSpinLock(&oldIrql);
  623. if (!Irp->Cancel)
  624. {
  625. IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)SpxTdiCancel);
  626. } else {
  627. CompleteIrpIfCancel = TRUE;
  628. }
  629. IoReleaseCancelSpinLock(oldIrql);
  630. if (Irp->Cancel) {
  631. if (CompleteIrpIfCancel) {
  632. // We only want to complete the irp if we didn't register our cancel routine.
  633. // Assume the SpxTdiCancel will complete the irp, we don't want to complete it twice.
  634. Irp->IoStatus.Status = STATUS_CANCELLED;
  635. DBGPRINT(TDI, DBG,
  636. ("SpxDispatchInternal: Completing IRP with Ipr->Cancel = True\n"));
  637. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  638. }
  639. return STATUS_CANCELLED;
  640. }
  641. // Branch to the appropriate request handler. Preliminary checking of
  642. // the size of the request block is performed here so that it is known
  643. // in the handlers that the minimum input parameters are readable. It
  644. // is *not* determined here whether variable length input fields are
  645. // passed correctly; this is a check which must be made within each routine.
  646. switch (REQUEST_MINOR_FUNCTION(Request))
  647. {
  648. case TDI_ACCEPT:
  649. Status = SpxConnAccept(
  650. Device,
  651. Request);
  652. break;
  653. case TDI_SET_EVENT_HANDLER:
  654. Status = SpxAddrSetEventHandler(
  655. Device,
  656. Request);
  657. break;
  658. case TDI_RECEIVE:
  659. Status = SpxConnRecv(
  660. Device,
  661. Request);
  662. break;
  663. case TDI_SEND:
  664. Status = SpxConnSend(
  665. Device,
  666. Request);
  667. break;
  668. case TDI_ACTION:
  669. Status = SpxConnAction(
  670. Device,
  671. Request);
  672. break;
  673. case TDI_ASSOCIATE_ADDRESS:
  674. Status = SpxConnAssociate(
  675. Device,
  676. Request);
  677. break;
  678. case TDI_DISASSOCIATE_ADDRESS:
  679. Status = SpxConnDisAssociate(
  680. Device,
  681. Request);
  682. break;
  683. case TDI_CONNECT:
  684. Status = SpxConnConnect(
  685. Device,
  686. Request);
  687. break;
  688. case TDI_DISCONNECT:
  689. Status = SpxConnDisconnect(
  690. Device,
  691. Request);
  692. break;
  693. case TDI_LISTEN:
  694. Status = SpxConnListen(
  695. Device,
  696. Request);
  697. break;
  698. case TDI_QUERY_INFORMATION:
  699. Status = SpxTdiQueryInformation(
  700. Device,
  701. Request);
  702. break;
  703. case TDI_SET_INFORMATION:
  704. Status = SpxTdiSetInformation(
  705. Device,
  706. Request);
  707. break;
  708. // Something we don't know about was submitted.
  709. default:
  710. Status = STATUS_INVALID_DEVICE_REQUEST;
  711. break;
  712. }
  713. if (Status != STATUS_PENDING)
  714. {
  715. UNMARK_REQUEST_PENDING(Request);
  716. REQUEST_STATUS(Request) = Status;
  717. IoAcquireCancelSpinLock(&oldIrql);
  718. IoSetCancelRoutine(Irp, (PDRIVER_CANCEL)NULL);
  719. IoReleaseCancelSpinLock(oldIrql);
  720. SpxCompleteRequest (Request);
  721. SpxFreeRequest (Device, Request);
  722. }
  723. // Return the immediate status code to the caller.
  724. return Status;
  725. } // SpxDispatchInternal
  726. VOID
  727. SpxTdiCancel(
  728. IN PDEVICE_OBJECT DeviceObject,
  729. IN PIRP Irp
  730. )
  731. /*++
  732. Routine Description:
  733. This routine handles cancellation of IO requests
  734. Arguments:
  735. Return Value:
  736. --*/
  737. {
  738. PREQUEST Request;
  739. PSPX_ADDR_FILE pSpxAddrFile;
  740. PSPX_ADDR pSpxAddr;
  741. PDEVICE Device = SpxDevice; // (PDEVICE)DeviceObject;
  742. CTELockHandle connectIrql;
  743. CTELockHandle TempIrql;
  744. PSPX_CONN_FILE pSpxConnFile;
  745. Request = SpxAllocateRequest (Device, Irp);
  746. IF_NOT_ALLOCATED(Request)
  747. {
  748. return;
  749. }
  750. DBGPRINT(TDI, ERR,
  751. ("SpxTdiCancel: ------ !!! Cancel irp called %lx.%lx.%lx\n",
  752. Irp, REQUEST_OPEN_CONTEXT(Request), REQUEST_OPEN_TYPE(Request)));
  753. switch ((ULONG_PTR)REQUEST_OPEN_TYPE(Request))
  754. {
  755. case TDI_CONNECTION_FILE:
  756. pSpxConnFile = (PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request);
  757. CTEGetLock(&pSpxConnFile->scf_Lock, &connectIrql);
  758. //
  759. // Swap the irql
  760. //
  761. TempIrql = connectIrql;
  762. connectIrql = Irp->CancelIrql;
  763. Irp->CancelIrql = TempIrql;
  764. IoReleaseCancelSpinLock (Irp->CancelIrql);
  765. if (!SPX_CONN_FLAG(pSpxConnFile, SPX_CONNFILE_STOPPING))
  766. {
  767. if (!SPX_CONN_IDLE(pSpxConnFile))
  768. {
  769. //
  770. // This releases the lock
  771. //
  772. spxConnAbortiveDisc(
  773. pSpxConnFile,
  774. STATUS_LOCAL_DISCONNECT,
  775. SPX_CALL_TDILEVEL,
  776. connectIrql,
  777. FALSE); // [SA] bug #15249
  778. }
  779. }
  780. // SpxConnStop((PSPX_CONN_FILE)REQUEST_OPEN_CONTEXT(Request));
  781. break;
  782. case TDI_TRANSPORT_ADDRESS_FILE:
  783. IoReleaseCancelSpinLock (Irp->CancelIrql);
  784. pSpxAddrFile = (PSPX_ADDR_FILE)REQUEST_OPEN_CONTEXT(Request);
  785. pSpxAddr = pSpxAddrFile->saf_Addr;
  786. SpxAddrFileStop(pSpxAddrFile, pSpxAddr);
  787. break;
  788. default:
  789. IoReleaseCancelSpinLock (Irp->CancelIrql);
  790. break;
  791. }
  792. }