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.

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