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.

477 lines
11 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. dlccncl.c
  5. Abstract:
  6. This module contains functions which handle IRP cancellations for DLC
  7. commands
  8. Contents:
  9. SetIrpCancelRoutine
  10. DlcCancelIrp
  11. CancelCommandIrp
  12. CancelTransmitIrp
  13. (MapIoctlCode)
  14. Author:
  15. Richard L Firth (rfirth) 22-Mar-1993
  16. Environment:
  17. kernel mode only
  18. Revision History:
  19. 22-Mar-1993 rfirth
  20. Created
  21. --*/
  22. #include "dlc.h"
  23. VOID
  24. CancelCommandIrp(
  25. IN PIRP Irp,
  26. IN PDLC_FILE_CONTEXT pFileContext,
  27. IN PLIST_ENTRY Queue
  28. );
  29. VOID
  30. CancelTransmitIrp(
  31. IN PIRP pIrp,
  32. IN PDLC_FILE_CONTEXT pFileContext
  33. );
  34. #if DBG
  35. PSTR MapIoctlCode(ULONG);
  36. //BOOLEAN DebugCancel = TRUE;
  37. BOOLEAN DebugCancel = FALSE;
  38. #endif
  39. VOID
  40. SetIrpCancelRoutine(
  41. IN PIRP Irp,
  42. IN BOOLEAN Set
  43. )
  44. /*++
  45. Routine Description:
  46. Sets or resets the cancel routine in a cancellable IRP. We MUST NOT be
  47. holding the driver spinlock when we call this function - if another thread
  48. is cancelling an IRP we will deadlock - exactly the reason why we now only
  49. have a single spinlock for the DLC driver!
  50. Arguments:
  51. Irp - pointer to cancellable IRP
  52. Set - TRUE if the cancel routine in the IRP is to be set to DlcCancelIrp
  53. else the cancel routine is set to NULL (no longer cancellable)
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. KIRQL irql;
  59. IoAcquireCancelSpinLock(&irql);
  60. if (!Irp->Cancel) {
  61. IoSetCancelRoutine(Irp, Set ? DlcCancelIrp : NULL);
  62. }
  63. IoReleaseCancelSpinLock(irql);
  64. }
  65. VOID
  66. DlcCancelIrp(
  67. IN PDEVICE_OBJECT DeviceObject,
  68. IN PIRP Irp
  69. )
  70. /*++
  71. Routine Description:
  72. This function is set as the cancel function in all cancellable DLC IRPs -
  73. TRANSMIT, RECEIVE and READ
  74. NB: !!! IopCancelSpinLock is held when this function is called !!!
  75. Arguments:
  76. DeviceObject - pointer to DEVICE_OBJECT
  77. Irp - pointer to IRP being cancelled
  78. Return Value:
  79. None.
  80. --*/
  81. {
  82. PIO_STACK_LOCATION irpStack;
  83. ULONG command;
  84. PDLC_FILE_CONTEXT pFileContext;
  85. PLIST_ENTRY queue;
  86. IoSetCancelRoutine(Irp, NULL);
  87. irpStack = IoGetCurrentIrpStackLocation(Irp);
  88. #if DBG
  89. if (DebugCancel) {
  90. DbgPrint("DlcCancelIrp. IRP @ %08X Type = %08X [%s]\n",
  91. Irp,
  92. irpStack->Parameters.DeviceIoControl.IoControlCode,
  93. MapIoctlCode(irpStack->Parameters.DeviceIoControl.IoControlCode)
  94. );
  95. }
  96. #endif
  97. pFileContext = irpStack->FileObject->FsContext;
  98. command = irpStack->Parameters.DeviceIoControl.IoControlCode;
  99. IoReleaseCancelSpinLock(Irp->CancelIrql);
  100. ACQUIRE_DRIVER_LOCK();
  101. ENTER_DLC(pFileContext);
  102. switch (command) {
  103. case IOCTL_DLC_READ:
  104. case IOCTL_DLC_READ2:
  105. queue = &pFileContext->CommandQueue;
  106. break;
  107. case IOCTL_DLC_RECEIVE:
  108. case IOCTL_DLC_RECEIVE2:
  109. queue = &pFileContext->ReceiveQueue;
  110. break;
  111. case IOCTL_DLC_TRANSMIT:
  112. case IOCTL_DLC_TRANSMIT2:
  113. CancelTransmitIrp(Irp, pFileContext);
  114. queue = NULL;
  115. break;
  116. default:
  117. #if DBG
  118. DbgPrint("DlcCancelIrp: didn't expect to cancel %s: add handler!\n", MapIoctlCode(command));
  119. #endif
  120. queue = NULL;
  121. }
  122. if (queue) {
  123. CancelCommandIrp(Irp, pFileContext, queue);
  124. }
  125. LEAVE_DLC(pFileContext);
  126. RELEASE_DRIVER_LOCK();
  127. }
  128. VOID
  129. CancelCommandIrp(
  130. IN PIRP Irp,
  131. IN PDLC_FILE_CONTEXT pFileContext,
  132. IN PLIST_ENTRY Queue
  133. )
  134. /*++
  135. Routine Description:
  136. Cancels a pending I/O request. Typically, this will be one of the DLC requests
  137. which stays pending for a long time e.g. READ or RECEIVE
  138. Arguments:
  139. Irp - IRP to cancel
  140. pFileContext - file context owning command to cancel
  141. Queue - pointer to command queue from which to delete
  142. Return Value:
  143. None.
  144. --*/
  145. {
  146. PDLC_COMMAND pCmdPacket;
  147. PVOID searchHandle;
  148. BOOLEAN IsReceive;
  149. USHORT StationId;
  150. PDLC_OBJECT pAbortedObject = NULL;
  151. #if DBG
  152. if (DebugCancel) {
  153. DbgPrint("CancelCommandIrp\n");
  154. }
  155. #endif
  156. //
  157. // the thing to search for is the address of the CCB
  158. //
  159. searchHandle = ((PNT_DLC_PARMS)Irp->AssociatedIrp.SystemBuffer)->Async.Ccb.pCcbAddress;
  160. if (((PNT_DLC_PARMS)Irp->AssociatedIrp.SystemBuffer)->Async.Ccb.uchDlcCommand == LLC_RECEIVE) {
  161. StationId = ((PNT_DLC_PARMS)Irp->AssociatedIrp.SystemBuffer)->Async.Parms.Receive.usStationId;
  162. GetStation(pFileContext, StationId, &pAbortedObject);
  163. IsReceive = TRUE;
  164. } else {
  165. IsReceive = FALSE;
  166. }
  167. //
  168. // remove the command info from this file context's command queue
  169. //
  170. pCmdPacket = SearchAndRemoveSpecificCommand(Queue, searchHandle);
  171. if (pCmdPacket) {
  172. //
  173. // if we are cancelling a RECEIVE which has a non-NULL data completion
  174. // flag then we also need to dissociate the receive parameters (the
  175. // address of the system buffer in the IRP being cancelled)
  176. //
  177. if (IsReceive
  178. && pAbortedObject
  179. && pCmdPacket->pIrp->AssociatedIrp.SystemBuffer == pAbortedObject->pRcvParms) {
  180. pAbortedObject->pRcvParms = NULL;
  181. }
  182. //
  183. // increment file context reference count; CompleteAsyncCommand will
  184. // dereference the file context
  185. //
  186. ReferenceFileContext(pFileContext);
  187. CompleteAsyncCommand(pFileContext,
  188. DLC_STATUS_CANCELLED_BY_SYSTEM_ACTION,
  189. Irp,
  190. NULL, // pointer for pNext field
  191. TRUE // called on cancel path
  192. );
  193. DEALLOCATE_PACKET_DLC_PKT(pFileContext->hPacketPool, pCmdPacket);
  194. DereferenceFileContext(pFileContext);
  195. } else {
  196. //
  197. // race condition?: the command completed before we got chance to cancel it
  198. //
  199. #if DBG
  200. DbgPrint("DLC.CancelCommandIrp: Command NOT located. CCB=%08X\n", searchHandle);
  201. #endif
  202. }
  203. }
  204. VOID
  205. CancelTransmitIrp(
  206. IN PIRP Irp,
  207. IN PDLC_FILE_CONTEXT pFileContext
  208. )
  209. /*++
  210. Routine Description:
  211. Cancels a pending transmit command. We are only interested in I-Frame
  212. transmit requests since these only complete when a corresponding ACK is
  213. received from the remote station. U-Frame transmissions don't get retried
  214. so will normally complete virtually immediately
  215. This routine currently does nothing in the retail version, and just
  216. complains about things in the debug version.
  217. Cancel transmit is not defined in the IBM LAN Reference, nor is it
  218. defined for NT DLC. This is only called by the IO subsystem when
  219. somebody terminates a thread or process with outstanding IO requests
  220. that include a DLC transmit request.
  221. For application termination, this is not really a problem since eventually
  222. the termination process will close the application's FileContext(s) and
  223. all SAPs, link stations, etc. belonging to the application will get closed
  224. down anyway.
  225. For thread termination, it is a real problem if an application abandons
  226. a transmit (usually Transmit I-Frame) by closing the thread that
  227. requested the transmit. DLC has no defined course of action to toss
  228. the transmit, without changing the associated link station state. This
  229. happened with hpmon.dll when the remote station (printer) got jammed
  230. and sent Receiver Not Ready in response to attempts to give it the
  231. frame. When something like this happens, it is up to the application
  232. to reset or close the link station, or wait, and not rely on thread
  233. termination to do the right thing here (because it won't).
  234. Arguments:
  235. Irp - pointer to IRP to cancel
  236. pFileContext - pointer to owning file context
  237. Return Value:
  238. None.
  239. --*/
  240. {
  241. PIO_STACK_LOCATION irpStack;
  242. PNT_DLC_CCB pCcb;
  243. #if DBG
  244. irpStack = IoGetCurrentIrpStackLocation(Irp);
  245. pCcb = &((PNT_DLC_PARMS)Irp->AssociatedIrp.SystemBuffer)->Async.Ccb;
  246. #endif
  247. #if DBG
  248. DbgPrint("DLC.CancelTransmitIrp: Cancel %s not supported! CCB %08X\n",
  249. pCcb->uchDlcCommand == LLC_TRANSMIT_FRAMES ? "TRANSMIT_FRAMES"
  250. : pCcb->uchDlcCommand == LLC_TRANSMIT_DIR_FRAME ? "TRANSMIT_DIR_FRAME"
  251. : pCcb->uchDlcCommand == LLC_TRANSMIT_UI_FRAME ? "TRANSMIT_UI_FRAME"
  252. : pCcb->uchDlcCommand == LLC_TRANSMIT_XID_CMD ? "TRANSMIT_XID_CMD"
  253. : pCcb->uchDlcCommand == LLC_TRANSMIT_XID_RESP_FINAL ? "TRANSMIT_XID_RESP_FINAL"
  254. : pCcb->uchDlcCommand == LLC_TRANSMIT_XID_RESP_NOT_FINAL ? "TRANSMIT_XID_RESP_NOT_FINAL"
  255. : pCcb->uchDlcCommand == LLC_TRANSMIT_TEST_CMD ? "TRANSMIT_TEST_CMD"
  256. : pCcb->uchDlcCommand == LLC_TRANSMIT_I_FRAME ? "TRANSMIT_I_FRAME"
  257. : "UNKNOWN TRANSMIT COMMAND!",
  258. pCcb
  259. );
  260. ASSERT ( pCcb->uchDlcCommand != LLC_TRANSMIT_I_FRAME );
  261. #endif
  262. }
  263. #if DBG
  264. PSTR MapIoctlCode(ULONG IoctlCode) {
  265. switch (IoctlCode) {
  266. case IOCTL_DLC_READ:
  267. return "READ";
  268. case IOCTL_DLC_RECEIVE:
  269. return "RECEIVE";
  270. case IOCTL_DLC_TRANSMIT:
  271. return "TRANSMIT";
  272. case IOCTL_DLC_BUFFER_FREE:
  273. return "BUFFER_FREE";
  274. case IOCTL_DLC_BUFFER_GET:
  275. return "BUFFER_GET";
  276. case IOCTL_DLC_BUFFER_CREATE:
  277. return "BUFFER_CREATE";
  278. case IOCTL_DLC_SET_EXCEPTION_FLAGS:
  279. return "SET_EXCEPTION_FLAGS";
  280. case IOCTL_DLC_CLOSE_STATION:
  281. return "CLOSE_STATION";
  282. case IOCTL_DLC_CONNECT_STATION:
  283. return "CONNECT_STATION";
  284. case IOCTL_DLC_FLOW_CONTROL:
  285. return "FLOW_CONTROL";
  286. case IOCTL_DLC_OPEN_STATION:
  287. return "OPEN_STATION";
  288. case IOCTL_DLC_RESET:
  289. return "RESET";
  290. case IOCTL_DLC_READ_CANCEL:
  291. return "READ_CANCEL";
  292. case IOCTL_DLC_RECEIVE_CANCEL:
  293. return "RECEIVE_CANCEL";
  294. case IOCTL_DLC_QUERY_INFORMATION:
  295. return "QUERY_INFORMATION";
  296. case IOCTL_DLC_SET_INFORMATION:
  297. return "SET_INFORMATION";
  298. case IOCTL_DLC_TIMER_CANCEL:
  299. return "TIMER_CANCEL";
  300. case IOCTL_DLC_TIMER_CANCEL_GROUP:
  301. return "TIMER_CANCEL_GROUP";
  302. case IOCTL_DLC_TIMER_SET:
  303. return "TIMER_SET";
  304. case IOCTL_DLC_OPEN_SAP:
  305. return "OPEN_SAP";
  306. case IOCTL_DLC_CLOSE_SAP:
  307. return "CLOSE_SAP";
  308. case IOCTL_DLC_OPEN_DIRECT:
  309. return "OPEN_DIRECT";
  310. case IOCTL_DLC_CLOSE_DIRECT:
  311. return "CLOSE_DIRECT";
  312. case IOCTL_DLC_OPEN_ADAPTER:
  313. return "OPEN_ADAPTER";
  314. case IOCTL_DLC_CLOSE_ADAPTER:
  315. return "CLOSE_ADAPTER";
  316. case IOCTL_DLC_REALLOCTE_STATION:
  317. return "REALLOCTE_STATION";
  318. case IOCTL_DLC_READ2:
  319. return "READ2";
  320. case IOCTL_DLC_RECEIVE2:
  321. return "RECEIVE2";
  322. case IOCTL_DLC_TRANSMIT2:
  323. return "TRANSMIT2";
  324. case IOCTL_DLC_COMPLETE_COMMAND:
  325. return "COMPLETE_COMMAND";
  326. case IOCTL_DLC_TRACE_INITIALIZE:
  327. return "TRACE_INITIALIZE";
  328. }
  329. return "*** UNKNOWN IOCTL CODE ***";
  330. }
  331. #endif