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.

448 lines
10 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. notify.c
  5. Abstract:
  6. This module contains code related to the NAT's notification-management.
  7. Notification may be requested by a NAT user- or kernel-mode client,
  8. by making an I/O control request which will complete when
  9. (a) the requested event occurs, or
  10. (b) the client's file-object is cleaned up, or
  11. (c) the NAT is shutting down.
  12. In the meantime, the I/O request packets are held on a list of pending
  13. notification-requests.
  14. Author:
  15. Abolade Gbadegesin (aboladeg) July-26-1998
  16. Revision History:
  17. --*/
  18. #include "precomp.h"
  19. #pragma hdrstop
  20. LIST_ENTRY NotificationList;
  21. KSPIN_LOCK NotificationLock;
  22. //
  23. // FORWARD DECLARATIONS
  24. //
  25. VOID
  26. NatpNotificationCancelRoutine(
  27. PDEVICE_OBJECT DeviceObject,
  28. PIRP Irp
  29. );
  30. PIRP
  31. NatpDequeueNotification(
  32. IP_NAT_NOTIFICATION Code
  33. );
  34. VOID
  35. NatCleanupAnyAssociatedNotification(
  36. PFILE_OBJECT FileObject
  37. )
  38. /*++
  39. Routine Description:
  40. This routine is invoked to cleanup any notifications associated with
  41. the client whose file-object has just been closed.
  42. Arguments:
  43. FileObject - the client's file-object
  44. Return Value:
  45. none.
  46. --*/
  47. {
  48. PIRP Irp;
  49. KIRQL Irql;
  50. PLIST_ENTRY Link;
  51. CALLTRACE(("NatCleanupAnyAssociatedNotification\n"));
  52. KeAcquireSpinLock(&NotificationLock, &Irql);
  53. for (Link = NotificationList.Flink;
  54. Link != &NotificationList;
  55. Link = Link->Flink
  56. ) {
  57. Irp = CONTAINING_RECORD(Link, IRP, Tail.Overlay.ListEntry);
  58. if (Irp->Tail.Overlay.DriverContext[0] != FileObject) { continue; }
  59. if (NULL == IoSetCancelRoutine(Irp, NULL)) {
  60. //
  61. // This IRP has been canceled. It will be completed in
  62. // our cancel routine
  63. //
  64. continue;
  65. }
  66. //
  67. // The IRP is now uncancellable. Take it off the list.
  68. //
  69. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  70. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  71. KeReleaseSpinLockFromDpcLevel(&NotificationLock);
  72. //
  73. // Complete the IRP
  74. //
  75. Irp->IoStatus.Status = STATUS_CANCELLED;
  76. Irp->IoStatus.Information = 0;
  77. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  78. DEREFERENCE_NAT();
  79. //
  80. // Continue the search, starting over since we dropped the list lock
  81. //
  82. KeAcquireSpinLockAtDpcLevel(&NotificationLock);
  83. Link = &NotificationList;
  84. }
  85. KeReleaseSpinLock(&NotificationLock, Irql);
  86. } // NatCleanupAnyAssociatedNotification
  87. VOID
  88. NatInitializeNotificationManagement(
  89. VOID
  90. )
  91. /*++
  92. Routine Description:
  93. This routine is called to initialize the notification-management module.
  94. Arguments:
  95. none.
  96. Return Value:
  97. none.
  98. --*/
  99. {
  100. CALLTRACE(("NatInitializeNotificationManagement\n"));
  101. InitializeListHead(&NotificationList);
  102. KeInitializeSpinLock(&NotificationLock);
  103. } // NatInitializeNotificationManagement
  104. PIRP
  105. NatpDequeueNotification(
  106. IP_NAT_NOTIFICATION Code
  107. )
  108. /*++
  109. Routine Description:
  110. This routine is invoked to dequeue a pending notification request IRP
  111. of the given type. If one is found, it is removed from the list
  112. and returned to the caller.
  113. Arguments:
  114. Code - the notification code for which an IRP is required
  115. Return Value:
  116. PIRP - the notification IRP, if any
  117. Environment:
  118. Invoked with 'NotificationLock' held by the caller.
  119. --*/
  120. {
  121. PIRP Irp;
  122. PLIST_ENTRY Link;
  123. PIP_NAT_REQUEST_NOTIFICATION RequestNotification;
  124. CALLTRACE(("NatpDequeueNotification\n"));
  125. for (Link = NotificationList.Flink;
  126. Link != &NotificationList;
  127. Link = Link->Flink
  128. ) {
  129. Irp = CONTAINING_RECORD(Link, IRP, Tail.Overlay.ListEntry);
  130. RequestNotification =
  131. (PIP_NAT_REQUEST_NOTIFICATION)Irp->AssociatedIrp.SystemBuffer;
  132. if (RequestNotification->Code != Code) { continue; }
  133. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  134. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  135. return Irp;
  136. }
  137. return NULL;
  138. } // NatpDequeueNotification
  139. VOID
  140. NatpNotificationCancelRoutine(
  141. PDEVICE_OBJECT DeviceObject,
  142. PIRP Irp
  143. )
  144. /*++
  145. Routine Description:
  146. This routine is invoked by the I/O manager upon cancellation of an IRP
  147. that is associated with a notification.
  148. Arguments:
  149. DeviceObject - the NAT's device-object
  150. Irp - the IRP to be cancelled
  151. Return Value:
  152. none.
  153. Environment:
  154. Invoked with the cancel spin-lock held by the I/O manager.
  155. It is this routine's responsibility to release the lock.
  156. --*/
  157. {
  158. KIRQL Irql;
  159. CALLTRACE(("NatpNotificationCancelRoutine\n"));
  160. IoReleaseCancelSpinLock(Irp->CancelIrql);
  161. //
  162. // Take the IRP off our list
  163. //
  164. KeAcquireSpinLock(&NotificationLock, &Irql);
  165. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  166. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  167. KeReleaseSpinLock(&NotificationLock, Irql);
  168. //
  169. // Complete the IRP
  170. //
  171. Irp->IoStatus.Status = STATUS_CANCELLED;
  172. Irp->IoStatus.Information = 0;
  173. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  174. DEREFERENCE_NAT();
  175. } // NatpNotificationCancelRoutine
  176. NTSTATUS
  177. NatRequestNotification(
  178. PIP_NAT_REQUEST_NOTIFICATION RequestNotification,
  179. PIRP Irp,
  180. PFILE_OBJECT FileObject
  181. )
  182. /*++
  183. Routine Description:
  184. This routine is invoked upon receipt of a notification-request
  185. from a client.
  186. Arguments:
  187. RequeustNotification - describes the notification
  188. Irp - the associated IRP
  189. FileObject - the client's file-object
  190. Return Value:
  191. NTSTATUS - status code.
  192. --*/
  193. {
  194. KIRQL CancelIrql;
  195. PIO_STACK_LOCATION IrpSp;
  196. CALLTRACE(("NatRequestNotification\n"));
  197. //
  198. // Check the size of the supplied output-buffer
  199. //
  200. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  201. if (RequestNotification->Code == NatRoutingFailureNotification) {
  202. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  203. sizeof(IP_NAT_ROUTING_FAILURE_NOTIFICATION)) {
  204. return STATUS_INVALID_BUFFER_SIZE;
  205. }
  206. } else {
  207. return STATUS_INVALID_PARAMETER;
  208. }
  209. //
  210. // Attempt to queue the IRP for later completion.
  211. // If the IRP is already cancelled, though, do nothing
  212. //
  213. IoAcquireCancelSpinLock(&CancelIrql);
  214. KeAcquireSpinLockAtDpcLevel(&NotificationLock);
  215. if (Irp->Cancel || !REFERENCE_NAT()) {
  216. KeReleaseSpinLockFromDpcLevel(&NotificationLock);
  217. IoReleaseCancelSpinLock(CancelIrql);
  218. return STATUS_CANCELLED;
  219. }
  220. //
  221. // Put the IRP on the list and remember its file-object
  222. //
  223. InsertTailList(&NotificationList, &Irp->Tail.Overlay.ListEntry);
  224. Irp->Tail.Overlay.DriverContext[0] = FileObject;
  225. KeReleaseSpinLockFromDpcLevel(&NotificationLock);
  226. //
  227. // Install our cancel-routine
  228. //
  229. IoMarkIrpPending(Irp);
  230. IoSetCancelRoutine(Irp, NatpNotificationCancelRoutine);
  231. IoReleaseCancelSpinLock(CancelIrql);
  232. return STATUS_PENDING;
  233. } // NatRequestNotification
  234. VOID
  235. NatSendRoutingFailureNotification(
  236. ULONG DestinationAddress,
  237. ULONG SourceAddress
  238. )
  239. /*++
  240. Routine Description:
  241. This routine is invoked to notify any clients that a routing failure has
  242. occurred.
  243. Arguments:
  244. DestinationAddress - the destination address of the unroutable packet
  245. SourceAddress - the source address of the unroutable packet
  246. Return Value:
  247. none.
  248. --*/
  249. {
  250. PIRP Irp;
  251. KIRQL Irql;
  252. PIP_NAT_ROUTING_FAILURE_NOTIFICATION RoutingFailureNotification;
  253. CALLTRACE(("NatSendRoutingFailureNotification\n"));
  254. //
  255. // See if any client wants routing-failure notification
  256. //
  257. KeAcquireSpinLock(&NotificationLock, &Irql);
  258. if (!(Irp = NatpDequeueNotification(NatRoutingFailureNotification))) {
  259. KeReleaseSpinLock(&NotificationLock, Irql);
  260. return;
  261. }
  262. KeReleaseSpinLock(&NotificationLock, Irql);
  263. //
  264. // Make the IRP uncancellable so we can complete it.
  265. //
  266. if (NULL == IoSetCancelRoutine(Irp, NULL)) {
  267. //
  268. // The IO manager canceled this IRP. It will be completed
  269. // in the cancel routine
  270. //
  271. return;
  272. }
  273. //
  274. // Fill in the notification information
  275. //
  276. RoutingFailureNotification =
  277. (PIP_NAT_ROUTING_FAILURE_NOTIFICATION)Irp->AssociatedIrp.SystemBuffer;
  278. RoutingFailureNotification->DestinationAddress = DestinationAddress;
  279. RoutingFailureNotification->SourceAddress = SourceAddress;
  280. //
  281. // Complete the IRP
  282. //
  283. Irp->IoStatus.Status = STATUS_SUCCESS;
  284. Irp->IoStatus.Information = sizeof(*RoutingFailureNotification);
  285. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  286. DEREFERENCE_NAT();
  287. } // NatSendRoutingFailureNotification
  288. VOID
  289. NatShutdownNotificationManagement(
  290. VOID
  291. )
  292. /*++
  293. Routine Description:
  294. This routine is invoked to shut down the module.
  295. All outstanding notifications are cancelled.
  296. Arguments:
  297. none.
  298. Return Value:
  299. none.
  300. --*/
  301. {
  302. PIRP Irp;
  303. PLIST_ENTRY Link;
  304. KIRQL Irql;
  305. CALLTRACE(("NatShutdownNotificationManagement\n"));
  306. KeAcquireSpinLock(&NotificationLock, &Irql);
  307. while (!IsListEmpty(&NotificationList)) {
  308. //
  309. // Take the next IRP off the list
  310. //
  311. Irp =
  312. CONTAINING_RECORD(
  313. NotificationList.Flink, IRP, Tail.Overlay.ListEntry
  314. );
  315. RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
  316. InitializeListHead(&Irp->Tail.Overlay.ListEntry);
  317. //
  318. // Cancel it if necessary
  319. //
  320. if (NULL != IoSetCancelRoutine(Irp, NULL)) {
  321. KeReleaseSpinLockFromDpcLevel(&NotificationLock);
  322. //
  323. // Complete the IRP
  324. //
  325. Irp->IoStatus.Status = STATUS_CANCELLED;
  326. Irp->IoStatus.Information = 0;
  327. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  328. DEREFERENCE_NAT();
  329. //
  330. // Resume emptying the list
  331. //
  332. KeAcquireSpinLockAtDpcLevel(&NotificationLock);
  333. }
  334. }
  335. KeReleaseSpinLock(&NotificationLock, Irql);
  336. } // NatShutdownNotificationManagement