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.

348 lines
9.6 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. request.c
  5. Abstract:
  6. Worker thread for the automatic connection driver.
  7. Author:
  8. Anthony Discolo (adiscolo) 17-Apr-1995
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. --*/
  13. #include <ndis.h>
  14. #include <cxport.h>
  15. #include <tdi.h>
  16. #include <tdikrnl.h>
  17. #include <tdistat.h>
  18. #include <tdiinfo.h>
  19. #include <acd.h>
  20. #include "acdapi.h"
  21. #include "acddefs.h"
  22. #include "mem.h"
  23. #include "debug.h"
  24. //
  25. // External declarations
  26. //
  27. VOID AcdPrintAddress(
  28. IN PACD_ADDR pAddr
  29. );
  30. extern LONG lOutstandingRequestsG;
  31. VOID
  32. ProcessCompletion(
  33. IN PACD_COMPLETION pCompletion,
  34. IN KIRQL irqlCancel,
  35. IN KIRQL irqlLock
  36. )
  37. {
  38. PLIST_ENTRY pHead;
  39. KIRQL irql;
  40. PIRP pIrp;
  41. PIO_STACK_LOCATION pIrpSp;
  42. PACD_NOTIFICATION pNotification;
  43. ASSERT(!IsListEmpty(&AcdNotificationQueueG));
  44. //
  45. // Complete the next irp in the
  46. // AcdNotificationQueueG queue. These
  47. // represent the ioctl completions the
  48. // system service has posted. Completing
  49. // this request will start the system service
  50. // to create a new RAS connection.
  51. // Logically, there is always just one.
  52. //
  53. pHead = RemoveHeadList(&AcdNotificationQueueG);
  54. pIrp = CONTAINING_RECORD(pHead, IRP, Tail.Overlay.ListEntry);
  55. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  56. //
  57. // Disable the irp's cancel routine.
  58. //
  59. IoSetCancelRoutine(pIrp, NULL);
  60. //
  61. // The irp thats being completed below will always be
  62. // from a 64bit process. We are doing the check below
  63. // to protect against some penetration program trying
  64. // to break this code.
  65. //
  66. #if defined (_WIN64)
  67. if(IoIs32bitProcess(pIrp))
  68. {
  69. ACD_NOTIFICATION_32 *pNotification32 =
  70. (PACD_NOTIFICATION_32) pIrp->AssociatedIrp.SystemBuffer;
  71. RtlCopyMemory(
  72. &pNotification32->addr,
  73. &pCompletion->notif.addr,
  74. sizeof(ACD_ADDR));
  75. RtlCopyMemory(
  76. &pNotification32->adapter,
  77. &pCompletion->notif.adapter,
  78. sizeof(ACD_ADAPTER));
  79. pNotification32->ulFlags = pCompletion->notif.ulFlags;
  80. pNotification32->Pid = (VOID * POINTER_32) HandleToUlong(
  81. pCompletion->notif.Pid);
  82. }
  83. else
  84. #endif
  85. {
  86. //
  87. // Copy the success flag and the address into the
  88. // system buffer. This will get copied into the
  89. // user's buffer on return.
  90. //
  91. pNotification = (PACD_NOTIFICATION)pIrp->AssociatedIrp.SystemBuffer;
  92. RtlCopyMemory(
  93. pNotification,
  94. &pCompletion->notif,
  95. sizeof (ACD_NOTIFICATION));
  96. IF_ACDDBG(ACD_DEBUG_WORKER) {
  97. AcdPrint(("AcdNotificationRequestThread: "));
  98. AcdPrintAddress(&pCompletion->notif.addr);
  99. AcdPrint((", ulFlags=0x%x\n", pCompletion->notif.ulFlags));
  100. }
  101. }
  102. //
  103. // We can release both the cancel lock
  104. // and our lock now.
  105. //
  106. KeReleaseSpinLock(&AcdSpinLockG, irqlLock);
  107. IoReleaseCancelSpinLock(irqlCancel);
  108. //
  109. // Set the status code and the number
  110. // of bytes to be copied back to the user
  111. // buffer.
  112. //
  113. pIrp->IoStatus.Status = STATUS_SUCCESS;
  114. pIrp->IoStatus.Information = sizeof (ACD_NOTIFICATION);
  115. //
  116. // Complete the irp.
  117. //
  118. IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  119. } // ProcessCompletion
  120. VOID
  121. AcdNotificationRequestThread(
  122. PVOID context
  123. )
  124. /*++
  125. DESCRIPTION
  126. This thread handles the notification that an automatic
  127. connection may need to be initiated. This needs to
  128. happen in a separate thread, because the notification
  129. may occur at DPC irql.
  130. ARGUMENTS
  131. None.
  132. RETURN VALUE
  133. None.
  134. --*/
  135. {
  136. KIRQL irql, irql2;
  137. PLIST_ENTRY pEntry, pEntry2;
  138. PACD_CONNECTION pConnection;
  139. PACD_COMPLETION pCompletion;
  140. BOOLEAN bStartTimer, bStopTimer;
  141. UNREFERENCED_PARAMETER(context);
  142. IoStartTimer(pAcdDeviceObjectG);
  143. for (;;) {
  144. bStartTimer = bStopTimer = FALSE;
  145. //
  146. // Acquire our lock.
  147. //
  148. IoAcquireCancelSpinLock(&irql);
  149. KeAcquireSpinLock(&AcdSpinLockG, &irql2);
  150. //
  151. // If there are no irps to complete,
  152. // then go back to sleep.
  153. //
  154. if (IsListEmpty(&AcdNotificationQueueG)) {
  155. IF_ACDDBG(ACD_DEBUG_WORKER) {
  156. AcdPrint(("AcdNotificationRequestThread: no ioctl to complete\n"));
  157. }
  158. KeReleaseSpinLock(&AcdSpinLockG, irql2);
  159. IoReleaseCancelSpinLock(irql);
  160. goto again;
  161. }
  162. //
  163. // Search for connections that haven't
  164. // been processed yet.
  165. //
  166. for (pEntry = AcdConnectionQueueG.Flink;
  167. pEntry != &AcdConnectionQueueG;
  168. pEntry = pEntry->Flink)
  169. {
  170. pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);
  171. //
  172. // Don't issue a request to the service
  173. // for more than one simultaneous connection.
  174. //
  175. IF_ACDDBG(ACD_DEBUG_WORKER) {
  176. AcdPrint((
  177. "AcdNotificationRequestThread: pConnection=0x%x, fNotif=%d, fCompleting=%d\n",
  178. pConnection,
  179. pConnection->fNotif,
  180. pConnection->fCompleting));
  181. }
  182. if (pConnection->fNotif)
  183. break;
  184. //
  185. // Skip all connections that are in
  186. // the process of being completed.
  187. //
  188. if (pConnection->fCompleting)
  189. continue;
  190. //
  191. // Make sure there is at least one
  192. // request in this connection that
  193. // hasn't been canceled.
  194. //
  195. for (pEntry2 = pConnection->CompletionList.Flink;
  196. pEntry2 != &pConnection->CompletionList;
  197. pEntry2 = pEntry2->Flink)
  198. {
  199. pCompletion = CONTAINING_RECORD(pEntry2, ACD_COMPLETION, ListEntry);
  200. if (!pCompletion->fCanceled) {
  201. IF_ACDDBG(ACD_DEBUG_WORKER) {
  202. AcdPrint((
  203. "AcdNotificationRequestThread: starting pConnection=0x%x, pCompletion=0x%x\n",
  204. pConnection,
  205. pCompletion));
  206. }
  207. pConnection->fNotif = TRUE;
  208. //
  209. // This call releases both the cancel lock
  210. // and our lock.
  211. //
  212. ProcessCompletion(pCompletion, irql, irql2);
  213. //
  214. // Start the connection timer.
  215. //
  216. bStartTimer = TRUE;
  217. //
  218. // We can only process one completion
  219. // at a time.
  220. //
  221. goto again;
  222. }
  223. }
  224. }
  225. //
  226. // Complete other requests.
  227. //
  228. if (!IsListEmpty(&AcdCompletionQueueG)) {
  229. pEntry = RemoveHeadList(&AcdCompletionQueueG);
  230. pCompletion = CONTAINING_RECORD(pEntry, ACD_COMPLETION, ListEntry);
  231. IF_ACDDBG(ACD_DEBUG_WORKER) {
  232. AcdPrint((
  233. "AcdNotificationRequestThread: starting pCompletion=0x%x\n",
  234. pCompletion));
  235. }
  236. lOutstandingRequestsG--;
  237. //
  238. // This call releases both the cancel lock
  239. // and our lock.
  240. //
  241. ProcessCompletion(pCompletion, irql, irql2);
  242. //
  243. // We are done with the completion,
  244. // so we can free the memory now.
  245. //
  246. FREE_MEMORY(pCompletion);
  247. //
  248. // We can only process one completion
  249. // at a time.
  250. //
  251. goto again;
  252. }
  253. //
  254. // If there are no connections pending,
  255. // then stop the connection timer.
  256. //
  257. if (IsListEmpty(&AcdConnectionQueueG))
  258. bStopTimer = TRUE;
  259. //
  260. // Release our lock.
  261. //
  262. KeReleaseSpinLock(&AcdSpinLockG, irql2);
  263. IoReleaseCancelSpinLock(irql);
  264. again:
  265. //
  266. // Start or stop the timer, depending
  267. // on what we found while we had the
  268. // spinlock. We can't hold our spin
  269. // lock when we call the Io*Timer
  270. // routines.
  271. //
  272. #ifdef notdef
  273. if (bStopTimer)
  274. IoStopTimer(pAcdDeviceObjectG);
  275. else if (bStartTimer)
  276. IoStartTimer(pAcdDeviceObjectG);
  277. #endif
  278. //
  279. // Unload is telling us to stop. Exit
  280. //
  281. if (AcdStopThread == TRUE) {
  282. break;
  283. }
  284. //
  285. // Wait for something to do. This event
  286. // will be signaled by AcdSignalNotification().
  287. //
  288. IF_ACDDBG(ACD_DEBUG_WORKER) {
  289. AcdPrint(("AcdNotificationRequestThread: waiting on AcdPendingCompletionEventG\n"));
  290. }
  291. KeWaitForSingleObject(
  292. &AcdRequestThreadEventG,
  293. Executive,
  294. KernelMode,
  295. FALSE,
  296. NULL);
  297. KeClearEvent(&AcdRequestThreadEventG);
  298. IF_ACDDBG(ACD_DEBUG_WORKER) {
  299. AcdPrint(("AcdNotificationRequestThread: AcdPendingCompletionEventG signalled\n"));
  300. }
  301. }
  302. } // AcdNotificationRequestThread