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.

559 lines
13 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. eventsel.c
  5. Abstract:
  6. This module contains routines for supporting the WinSock 2.0
  7. WSAEventSelect() and WSAEnumNetworkEvents() APIs.
  8. Author:
  9. Keith Moore (keithmo) 02-Aug-1995
  10. Revision History:
  11. --*/
  12. #include "afdp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text( PAGEAFD, AfdEventSelect )
  15. #pragma alloc_text( PAGEAFD, AfdEnumNetworkEvents )
  16. #endif
  17. NTSTATUS
  18. AfdEventSelect (
  19. IN PFILE_OBJECT FileObject,
  20. IN ULONG IoctlCode,
  21. IN KPROCESSOR_MODE RequestorMode,
  22. IN PVOID InputBuffer,
  23. IN ULONG InputBufferLength,
  24. IN PVOID OutputBuffer,
  25. IN ULONG OutputBufferLength,
  26. OUT PUINT_PTR Information
  27. )
  28. /*++
  29. Routine Description:
  30. Associates an event object with the socket such that the event object
  31. will be signalled when any of the specified network events becomes
  32. active.
  33. Arguments:
  34. Irp - Pointer to I/O request packet.
  35. IrpSp - pointer to the IO stack location to use for this request.
  36. Return Value:
  37. NTSTATUS -- Indicates whether the APC was successfully queued.
  38. --*/
  39. {
  40. NTSTATUS status;
  41. PAFD_ENDPOINT endpoint;
  42. AFD_LOCK_QUEUE_HANDLE lockHandle;
  43. PKEVENT eventObject;
  44. ULONG eventMask;
  45. AFD_EVENT_SELECT_INFO eventInfo;
  46. ULONG previousRecord = 0;
  47. BOOLEAN countsUpdated = FALSE;
  48. *Information = 0;
  49. status = STATUS_SUCCESS;
  50. try {
  51. #ifdef _WIN64
  52. if (IoIs32bitProcess (NULL)) {
  53. PAFD_EVENT_SELECT_INFO32 eventInfo32 = InputBuffer;
  54. if( InputBufferLength < sizeof(*eventInfo32)) {
  55. return STATUS_INVALID_PARAMETER;
  56. }
  57. //
  58. // Validate the input structure if it comes from the user mode
  59. // application
  60. //
  61. if (RequestorMode != KernelMode ) {
  62. ProbeForRead (InputBuffer,
  63. sizeof (*eventInfo32),
  64. PROBE_ALIGNMENT32(AFD_EVENT_SELECT_INFO32));
  65. }
  66. //
  67. // Make local copies of the embeded pointer and parameters
  68. // that we will be using more than once in case malicios
  69. // application attempts to change them while we are
  70. // validating
  71. //
  72. eventInfo.Event = eventInfo32->Event;
  73. eventInfo.PollEvents = eventInfo32->PollEvents;
  74. }
  75. else
  76. #endif
  77. {
  78. if(InputBufferLength < sizeof(eventInfo)) {
  79. return STATUS_INVALID_PARAMETER;
  80. }
  81. if (RequestorMode != KernelMode ) {
  82. ProbeForRead (InputBuffer,
  83. sizeof (eventInfo),
  84. PROBE_ALIGNMENT(AFD_EVENT_SELECT_INFO));
  85. }
  86. //
  87. // Make local copies of the embeded pointer and parameters
  88. // that we will be using more than once in case malicios
  89. // application attempts to change them while we are
  90. // validating
  91. //
  92. eventInfo = *((PAFD_EVENT_SELECT_INFO)InputBuffer);
  93. }
  94. }
  95. except (AFD_EXCEPTION_FILTER (&status)) {
  96. return status;
  97. }
  98. if ( eventInfo.Event == NULL &&
  99. eventInfo.PollEvents != 0 ) {
  100. return STATUS_INVALID_PARAMETER;
  101. }
  102. //
  103. // Grab the endpoint from the socket handle.
  104. //
  105. endpoint = FileObject->FsContext;
  106. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  107. //
  108. // Reference the target event object.
  109. //
  110. eventObject = NULL;
  111. if( eventInfo.Event != NULL ) {
  112. status = AfdReferenceEventObjectByHandle(
  113. eventInfo.Event,
  114. RequestorMode,
  115. (PVOID *)&eventObject
  116. );
  117. if( !NT_SUCCESS(status) ) {
  118. return status;
  119. }
  120. ASSERT( eventObject != NULL );
  121. if (IS_SAN_ENDPOINT (endpoint)) {
  122. //
  123. // Inform the switch that select is active on this endpoint.
  124. //
  125. status = AfdSanPollBegin (endpoint, eventInfo.PollEvents);
  126. if (!NT_SUCCESS (status)) {
  127. ObDereferenceObject (eventObject);
  128. return status;
  129. }
  130. countsUpdated = TRUE;
  131. }
  132. }
  133. //
  134. // Acquire the spinlock protecting the endpoint.
  135. //
  136. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  137. //
  138. // If this endpoint has an active EventSelect, dereference the
  139. // associated event object.
  140. //
  141. if( endpoint->EventObject != NULL ) {
  142. ObDereferenceObject( endpoint->EventObject );
  143. if (IS_SAN_ENDPOINT (endpoint)) {
  144. previousRecord = endpoint->EventsEnabled;
  145. }
  146. }
  147. //
  148. // Fill in the info.
  149. //
  150. endpoint->EventObject = eventObject;
  151. endpoint->EventsEnabled = eventInfo.PollEvents;
  152. if (countsUpdated) {
  153. endpoint->EventsEnabled |= AFD_POLL_SANCOUNTS_UPDATED;
  154. //
  155. // AfdSanPollBegin puts latest events into
  156. // Endpoint->Common.SanEndp.SelectEventsActive. This is fine for
  157. // select/AsyncSelect, but not for EventSelect. So, if being called
  158. // for the first time, then read current active events from there.
  159. //
  160. if (!(previousRecord & AFD_POLL_SANCOUNTS_UPDATED)) {
  161. endpoint->EventsActive = endpoint->Common.SanEndp.SelectEventsActive;
  162. }
  163. }
  164. IF_DEBUG(EVENT_SELECT) {
  165. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  166. "AfdEventSelect: Endpoint-%p, eventOb-%p, enabled-%lx, active-%lx\n",
  167. endpoint,
  168. eventObject,
  169. endpoint->EventsEnabled,
  170. endpoint->EventsActive
  171. ));
  172. }
  173. //
  174. // While we've got the spinlock held, determine if any conditions
  175. // are met, and if so, signal the event object.
  176. //
  177. eventMask = endpoint->EventsActive & endpoint->EventsEnabled;
  178. if( eventMask != 0 && eventObject != NULL ) {
  179. IF_DEBUG(EVENT_SELECT) {
  180. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  181. "AfdEventSelect: Setting event %p\n",
  182. eventObject
  183. ));
  184. }
  185. KeSetEvent(
  186. eventObject,
  187. AfdPriorityBoost,
  188. FALSE
  189. );
  190. }
  191. //
  192. // Release the spin lock and return.
  193. //
  194. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  195. if (previousRecord & AFD_POLL_SANCOUNTS_UPDATED) {
  196. AfdSanPollEnd (endpoint, previousRecord);
  197. }
  198. return STATUS_SUCCESS;
  199. } // AfdEventSelect
  200. NTSTATUS
  201. AfdEnumNetworkEvents (
  202. IN PFILE_OBJECT FileObject,
  203. IN ULONG IoctlCode,
  204. IN KPROCESSOR_MODE RequestorMode,
  205. IN PVOID InputBuffer,
  206. IN ULONG InputBufferLength,
  207. IN PVOID OutputBuffer,
  208. IN ULONG OutputBufferLength,
  209. OUT PUINT_PTR Information
  210. )
  211. /*++
  212. Routine Description:
  213. Retrieves event select information from the socket.
  214. Arguments:
  215. Irp - Pointer to I/O request packet.
  216. IrpSp - pointer to the IO stack location to use for this request.
  217. Return Value:
  218. NTSTATUS -- Indicates whether the APC was successfully queued.
  219. --*/
  220. {
  221. NTSTATUS status;
  222. PAFD_ENDPOINT endpoint;
  223. AFD_ENUM_NETWORK_EVENTS_INFO eventInfo;
  224. AFD_LOCK_QUEUE_HANDLE lockHandle;
  225. PKEVENT eventObject;
  226. ULONG pollEvents;
  227. status = STATUS_SUCCESS;
  228. *Information = 0;
  229. //
  230. // Validate the parameters.
  231. //
  232. if(OutputBufferLength < sizeof(eventInfo) ) {
  233. return STATUS_INVALID_PARAMETER;
  234. }
  235. //
  236. // Reference the target event object.
  237. //
  238. eventObject = NULL;
  239. if( InputBuffer != NULL ) {
  240. status = AfdReferenceEventObjectByHandle(
  241. InputBuffer,
  242. RequestorMode,
  243. (PVOID *)&eventObject
  244. );
  245. if( !NT_SUCCESS(status) ) {
  246. return status;
  247. }
  248. ASSERT( eventObject != NULL );
  249. }
  250. //
  251. // Grab the endpoint from the socket handle.
  252. //
  253. endpoint = FileObject->FsContext;
  254. ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
  255. //
  256. // Acquire the spinlock protecting the endpoint.
  257. //
  258. AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
  259. IF_DEBUG(EVENT_SELECT) {
  260. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  261. "AfdEnumNetworkEvents: endp-%p, eventobj-%p, enabled-%lx, active-%lx\n",
  262. endpoint,
  263. eventObject,
  264. endpoint->EventsEnabled,
  265. endpoint->EventsActive
  266. ));
  267. }
  268. //
  269. // Copy the data to the user's structure.
  270. //
  271. pollEvents = endpoint->EventsActive & endpoint->EventsEnabled;
  272. eventInfo.PollEvents = pollEvents;
  273. RtlCopyMemory(
  274. eventInfo.EventStatus,
  275. endpoint->EventStatus,
  276. sizeof(eventInfo.EventStatus)
  277. );
  278. //
  279. // If there was an event object handle passed in with this
  280. // request, reset and dereference it.
  281. //
  282. if( eventObject != NULL ) {
  283. IF_DEBUG(EVENT_SELECT) {
  284. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  285. "AfdEnumNetworkEvents: Resetting event %p\n",
  286. eventObject
  287. ));
  288. }
  289. KeResetEvent( eventObject );
  290. ObDereferenceObject( eventObject );
  291. }
  292. //
  293. // Reset internal event record for all the events that
  294. // we could potentially report to the application
  295. //
  296. endpoint->EventsActive &= ~(endpoint->EventsEnabled);
  297. //
  298. // Release the spin lock and return.
  299. //
  300. AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
  301. try {
  302. //
  303. // Validate the output structure if it comes from the user mode
  304. // application
  305. //
  306. if (RequestorMode != KernelMode ) {
  307. ProbeForWrite (OutputBuffer,
  308. sizeof (eventInfo),
  309. PROBE_ALIGNMENT (AFD_ENUM_NETWORK_EVENTS_INFO));
  310. }
  311. //
  312. // Copy parameters back to application's memory
  313. //
  314. *((PAFD_ENUM_NETWORK_EVENTS_INFO)OutputBuffer) = eventInfo;
  315. } except( AFD_EXCEPTION_FILTER(&status) ) {
  316. return status;
  317. }
  318. //
  319. // Before returning, tell the I/O subsystem how may bytes to copy
  320. // to the user's output buffer.
  321. //
  322. *Information = sizeof(eventInfo);
  323. return STATUS_SUCCESS;
  324. } // AfdEnumNetworkEvents
  325. VOID
  326. AfdIndicateEventSelectEvent (
  327. IN PAFD_ENDPOINT Endpoint,
  328. IN ULONG PollEventMask,
  329. IN NTSTATUS Status
  330. )
  331. {
  332. ULONG oldEventsActive;
  333. ULONG eventBit;
  334. //
  335. // Sanity check.
  336. //
  337. ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
  338. ASSERT (PollEventMask!=0);
  339. ASSERT (((~((1<<AFD_NUM_POLL_EVENTS)-1)) & PollEventMask)==0);
  340. ASSERT( KeGetCurrentIrql() >= DISPATCH_LEVEL );
  341. //
  342. // Note that AFD_POLL_ABORT implies AFD_POLL_SEND.
  343. //
  344. if( PollEventMask & AFD_POLL_ABORT ) {
  345. PollEventMask |= AFD_POLL_SEND;
  346. }
  347. //
  348. // Special handling of send event. Don't record if not enabled
  349. // and disable further indication upon recording (it is only enabled
  350. // after we fail non-blocking send
  351. //
  352. //
  353. // Update the counts for the polls that were issued before
  354. // the endpoint was converted to SAN.
  355. //
  356. if ( IS_SAN_ENDPOINT (Endpoint) &&
  357. !(Endpoint->EventsEnabled & AFD_POLL_SANCOUNTS_UPDATED) &&
  358. Endpoint->Common.SanEndp.LocalContext!=NULL) {
  359. AfdSanPollUpdate (Endpoint, Endpoint->EventsEnabled);
  360. Endpoint->EventsEnabled |= AFD_POLL_SANCOUNTS_UPDATED;
  361. }
  362. if (PollEventMask&AFD_POLL_SEND) {
  363. if (Endpoint->EnableSendEvent) {
  364. Endpoint ->EnableSendEvent = FALSE;
  365. }
  366. else {
  367. PollEventMask &= (~AFD_POLL_SEND);
  368. if (PollEventMask==0) {
  369. return;
  370. }
  371. }
  372. }
  373. //
  374. // Calculate the actual event bit.
  375. //
  376. oldEventsActive = Endpoint->EventsActive;
  377. Endpoint->EventsActive |= PollEventMask;
  378. for (eventBit=0; eventBit<AFD_NUM_POLL_EVENTS; eventBit++) {
  379. if ((1<<eventBit) & PollEventMask) {
  380. Endpoint->EventStatus[eventBit] = Status;
  381. }
  382. }
  383. IF_DEBUG(EVENT_SELECT) {
  384. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  385. "AfdIndicateEventSelectEvent: endp-%p, eventobj-%p, enabled-%lx, active-%lx, indicated-%lx\n",
  386. Endpoint,
  387. Endpoint->EventObject,
  388. Endpoint->EventsEnabled,
  389. Endpoint->EventsActive,
  390. PollEventMask
  391. ));
  392. }
  393. //
  394. // Only signal the endpoint's event object if the current event
  395. // is enabled, AND the current event was not already active, AND
  396. // there is an event object associated with this endpoint.
  397. //
  398. PollEventMask &= Endpoint->EventsEnabled & ~oldEventsActive;
  399. if( PollEventMask != 0 && Endpoint->EventObject != NULL ) {
  400. IF_DEBUG(EVENT_SELECT) {
  401. KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
  402. "AfdIndicateEventSelectEvent: Setting event %p\n",
  403. Endpoint->EventObject
  404. ));
  405. }
  406. KeSetEvent(
  407. Endpoint->EventObject,
  408. AfdPriorityBoost,
  409. FALSE
  410. );
  411. }
  412. } // AfdIndicateEventSelectEvent