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
565 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
eventsel.c
|
|
|
|
Abstract:
|
|
|
|
This module contains routines for supporting the WinSock 2.0
|
|
WSAEventSelect() and WSAEnumNetworkEvents() APIs.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 02-Aug-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "afdp.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGEAFD, AfdEventSelect )
|
|
#pragma alloc_text( PAGEAFD, AfdEnumNetworkEvents )
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS
|
|
AfdEventSelect (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG IoctlCode,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG_PTR Information
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Associates an event object with the socket such that the event object
|
|
will be signalled when any of the specified network events becomes
|
|
active.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the APC was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PAFD_ENDPOINT endpoint;
|
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|
PKEVENT eventObject;
|
|
ULONG eventMask;
|
|
AFD_EVENT_SELECT_INFO eventInfo;
|
|
ULONG previousRecord = 0;
|
|
BOOLEAN countsUpdated = FALSE;
|
|
|
|
UNREFERENCED_PARAMETER (IoctlCode);
|
|
UNREFERENCED_PARAMETER (OutputBuffer);
|
|
UNREFERENCED_PARAMETER (OutputBufferLength);
|
|
|
|
*Information = 0;
|
|
AFD_W4_INIT status = STATUS_SUCCESS;
|
|
try {
|
|
#ifdef _WIN64
|
|
if (IoIs32bitProcess (NULL)) {
|
|
|
|
PAFD_EVENT_SELECT_INFO32 eventInfo32 = InputBuffer;
|
|
|
|
if( InputBufferLength < sizeof(*eventInfo32)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Validate the input structure if it comes from the user mode
|
|
// application
|
|
//
|
|
|
|
if (RequestorMode != KernelMode ) {
|
|
ProbeForReadSmallStructure (InputBuffer,
|
|
sizeof (*eventInfo32),
|
|
PROBE_ALIGNMENT32(AFD_EVENT_SELECT_INFO32));
|
|
}
|
|
|
|
//
|
|
// Make local copies of the embeded pointer and parameters
|
|
// that we will be using more than once in case malicios
|
|
// application attempts to change them while we are
|
|
// validating
|
|
//
|
|
|
|
eventInfo.Event = eventInfo32->Event;
|
|
eventInfo.PollEvents = eventInfo32->PollEvents;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
|
|
if(InputBufferLength < sizeof(eventInfo)) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (RequestorMode != KernelMode ) {
|
|
ProbeForReadSmallStructure (InputBuffer,
|
|
sizeof (eventInfo),
|
|
PROBE_ALIGNMENT(AFD_EVENT_SELECT_INFO));
|
|
}
|
|
|
|
//
|
|
// Make local copies of the embeded pointer and parameters
|
|
// that we will be using more than once in case malicios
|
|
// application attempts to change them while we are
|
|
// validating
|
|
//
|
|
|
|
eventInfo = *((PAFD_EVENT_SELECT_INFO)InputBuffer);
|
|
}
|
|
}
|
|
except (AFD_EXCEPTION_FILTER (status)) {
|
|
ASSERT (NT_ERROR (status));
|
|
return status;
|
|
}
|
|
|
|
if ( eventInfo.Event == NULL &&
|
|
eventInfo.PollEvents != 0 ) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Grab the endpoint from the socket handle.
|
|
//
|
|
|
|
endpoint = FileObject->FsContext;
|
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|
|
|
//
|
|
// Reference the target event object.
|
|
//
|
|
|
|
|
|
eventObject = NULL;
|
|
|
|
if( eventInfo.Event != NULL ) {
|
|
|
|
status = AfdReferenceEventObjectByHandle(
|
|
eventInfo.Event,
|
|
RequestorMode,
|
|
(PVOID *)&eventObject
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
ASSERT( eventObject != NULL );
|
|
|
|
if (IS_SAN_ENDPOINT (endpoint)) {
|
|
//
|
|
// Inform the switch that select is active on this endpoint.
|
|
//
|
|
status = AfdSanPollBegin (endpoint, eventInfo.PollEvents);
|
|
|
|
if (!NT_SUCCESS (status)) {
|
|
ObDereferenceObject (eventObject);
|
|
return status;
|
|
}
|
|
countsUpdated = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Acquire the spinlock protecting the endpoint.
|
|
//
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
//
|
|
// If this endpoint has an active EventSelect, dereference the
|
|
// associated event object.
|
|
//
|
|
|
|
if( endpoint->EventObject != NULL ) {
|
|
|
|
ObDereferenceObject( endpoint->EventObject );
|
|
|
|
if (IS_SAN_ENDPOINT (endpoint)) {
|
|
previousRecord = endpoint->EventsEnabled;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Fill in the info.
|
|
//
|
|
|
|
endpoint->EventObject = eventObject;
|
|
endpoint->EventsEnabled = eventInfo.PollEvents;
|
|
|
|
if (countsUpdated) {
|
|
endpoint->EventsEnabled |= AFD_POLL_SANCOUNTS_UPDATED;
|
|
//
|
|
// AfdSanPollBegin puts latest events into
|
|
// Endpoint->Common.SanEndp.SelectEventsActive. This is fine for
|
|
// select/AsyncSelect, but not for EventSelect. So, if being called
|
|
// for the first time, then read current active events from there.
|
|
//
|
|
if (!(previousRecord & AFD_POLL_SANCOUNTS_UPDATED)) {
|
|
endpoint->EventsActive = endpoint->Common.SanEndp.SelectEventsActive;
|
|
}
|
|
}
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdEventSelect: Endpoint-%p, eventOb-%p, enabled-%lx, active-%lx\n",
|
|
endpoint,
|
|
eventObject,
|
|
endpoint->EventsEnabled,
|
|
endpoint->EventsActive
|
|
));
|
|
}
|
|
|
|
//
|
|
// While we've got the spinlock held, determine if any conditions
|
|
// are met, and if so, signal the event object.
|
|
//
|
|
|
|
eventMask = endpoint->EventsActive & endpoint->EventsEnabled;
|
|
|
|
if( eventMask != 0 && eventObject != NULL ) {
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdEventSelect: Setting event %p\n",
|
|
eventObject
|
|
));
|
|
}
|
|
|
|
KeSetEvent(
|
|
eventObject,
|
|
AfdPriorityBoost,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
//
|
|
// Release the spin lock and return.
|
|
//
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
if (previousRecord & AFD_POLL_SANCOUNTS_UPDATED) {
|
|
AfdSanPollEnd (endpoint, previousRecord);
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // AfdEventSelect
|
|
|
|
|
|
NTSTATUS
|
|
AfdEnumNetworkEvents (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN ULONG IoctlCode,
|
|
IN KPROCESSOR_MODE RequestorMode,
|
|
IN PVOID InputBuffer,
|
|
IN ULONG InputBufferLength,
|
|
IN PVOID OutputBuffer,
|
|
IN ULONG OutputBufferLength,
|
|
OUT PULONG_PTR Information
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves event select information from the socket.
|
|
|
|
Arguments:
|
|
|
|
Irp - Pointer to I/O request packet.
|
|
|
|
IrpSp - pointer to the IO stack location to use for this request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS -- Indicates whether the APC was successfully queued.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PAFD_ENDPOINT endpoint;
|
|
AFD_ENUM_NETWORK_EVENTS_INFO eventInfo;
|
|
AFD_LOCK_QUEUE_HANDLE lockHandle;
|
|
PKEVENT eventObject;
|
|
ULONG pollEvents;
|
|
|
|
UNREFERENCED_PARAMETER (IoctlCode);
|
|
UNREFERENCED_PARAMETER (InputBufferLength);
|
|
|
|
*Information = 0;
|
|
|
|
//
|
|
// Validate the parameters.
|
|
//
|
|
|
|
if(OutputBufferLength < sizeof(eventInfo) ) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
//
|
|
// Reference the target event object.
|
|
//
|
|
|
|
eventObject = NULL;
|
|
|
|
if( InputBuffer != NULL ) {
|
|
|
|
status = AfdReferenceEventObjectByHandle(
|
|
InputBuffer,
|
|
RequestorMode,
|
|
(PVOID *)&eventObject
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
ASSERT( eventObject != NULL );
|
|
|
|
}
|
|
|
|
//
|
|
// Grab the endpoint from the socket handle.
|
|
//
|
|
|
|
endpoint = FileObject->FsContext;
|
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|
|
|
//
|
|
// Acquire the spinlock protecting the endpoint.
|
|
//
|
|
|
|
AfdAcquireSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdEnumNetworkEvents: endp-%p, eventobj-%p, enabled-%lx, active-%lx\n",
|
|
endpoint,
|
|
eventObject,
|
|
endpoint->EventsEnabled,
|
|
endpoint->EventsActive
|
|
));
|
|
}
|
|
|
|
//
|
|
// Copy the data to the user's structure.
|
|
//
|
|
|
|
pollEvents = endpoint->EventsActive & endpoint->EventsEnabled;
|
|
eventInfo.PollEvents = pollEvents;
|
|
|
|
RtlCopyMemory(
|
|
eventInfo.EventStatus,
|
|
endpoint->EventStatus,
|
|
sizeof(eventInfo.EventStatus)
|
|
);
|
|
|
|
//
|
|
// If there was an event object handle passed in with this
|
|
// request, reset and dereference it.
|
|
//
|
|
|
|
if( eventObject != NULL ) {
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdEnumNetworkEvents: Resetting event %p\n",
|
|
eventObject
|
|
));
|
|
}
|
|
|
|
KeResetEvent( eventObject );
|
|
ObDereferenceObject( eventObject );
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Reset internal event record for all the events that
|
|
// we could potentially report to the application
|
|
//
|
|
|
|
endpoint->EventsActive &= ~(endpoint->EventsEnabled);
|
|
|
|
//
|
|
// Release the spin lock and return.
|
|
//
|
|
|
|
AfdReleaseSpinLock( &endpoint->SpinLock, &lockHandle );
|
|
|
|
AFD_W4_INIT status = STATUS_SUCCESS;
|
|
try {
|
|
//
|
|
// Validate the output structure if it comes from the user mode
|
|
// application
|
|
//
|
|
|
|
if (RequestorMode != KernelMode ) {
|
|
ProbeForWrite (OutputBuffer,
|
|
sizeof (eventInfo),
|
|
PROBE_ALIGNMENT (AFD_ENUM_NETWORK_EVENTS_INFO));
|
|
}
|
|
|
|
//
|
|
// Copy parameters back to application's memory
|
|
//
|
|
|
|
*((PAFD_ENUM_NETWORK_EVENTS_INFO)OutputBuffer) = eventInfo;
|
|
|
|
} except( AFD_EXCEPTION_FILTER(status) ) {
|
|
ASSERT (NT_ERROR (status));
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Before returning, tell the I/O subsystem how may bytes to copy
|
|
// to the user's output buffer.
|
|
//
|
|
|
|
*Information = sizeof(eventInfo);
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // AfdEnumNetworkEvents
|
|
|
|
|
|
VOID
|
|
AfdIndicateEventSelectEvent (
|
|
IN PAFD_ENDPOINT Endpoint,
|
|
IN ULONG PollEventMask,
|
|
IN NTSTATUS Status
|
|
)
|
|
{
|
|
ULONG oldEventsActive;
|
|
ULONG eventBit;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
ASSERT( IS_AFD_ENDPOINT_TYPE( Endpoint ) );
|
|
ASSERT (PollEventMask!=0);
|
|
ASSERT (((~((1<<AFD_NUM_POLL_EVENTS)-1)) & PollEventMask)==0);
|
|
ASSERT( KeGetCurrentIrql() >= DISPATCH_LEVEL );
|
|
|
|
//
|
|
// Note that AFD_POLL_ABORT implies AFD_POLL_SEND.
|
|
//
|
|
if( PollEventMask & AFD_POLL_ABORT ) {
|
|
PollEventMask |= AFD_POLL_SEND;
|
|
}
|
|
|
|
//
|
|
// Special handling of send event. Don't record if not enabled
|
|
// and disable further indication upon recording (it is only enabled
|
|
// after we fail non-blocking send
|
|
//
|
|
|
|
//
|
|
// Update the counts for the polls that were issued before
|
|
// the endpoint was converted to SAN.
|
|
//
|
|
if ( IS_SAN_ENDPOINT (Endpoint) &&
|
|
!(Endpoint->EventsEnabled & AFD_POLL_SANCOUNTS_UPDATED) &&
|
|
Endpoint->Common.SanEndp.LocalContext!=NULL) {
|
|
AfdSanPollUpdate (Endpoint, Endpoint->EventsEnabled);
|
|
Endpoint->EventsEnabled |= AFD_POLL_SANCOUNTS_UPDATED;
|
|
}
|
|
|
|
if (PollEventMask&AFD_POLL_SEND) {
|
|
if (Endpoint->EnableSendEvent) {
|
|
Endpoint ->EnableSendEvent = FALSE;
|
|
}
|
|
else {
|
|
PollEventMask &= (~AFD_POLL_SEND);
|
|
if (PollEventMask==0) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Calculate the actual event bit.
|
|
//
|
|
|
|
oldEventsActive = Endpoint->EventsActive;
|
|
Endpoint->EventsActive |= PollEventMask;
|
|
for (eventBit=0; eventBit<AFD_NUM_POLL_EVENTS; eventBit++) {
|
|
if ((1<<eventBit) & PollEventMask) {
|
|
Endpoint->EventStatus[eventBit] = Status;
|
|
}
|
|
}
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdIndicateEventSelectEvent: endp-%p, eventobj-%p, enabled-%lx, active-%lx, indicated-%lx\n",
|
|
Endpoint,
|
|
Endpoint->EventObject,
|
|
Endpoint->EventsEnabled,
|
|
Endpoint->EventsActive,
|
|
PollEventMask
|
|
));
|
|
}
|
|
|
|
//
|
|
// Only signal the endpoint's event object if the current event
|
|
// is enabled, AND the current event was not already active, AND
|
|
// there is an event object associated with this endpoint.
|
|
//
|
|
|
|
PollEventMask &= Endpoint->EventsEnabled & ~oldEventsActive;
|
|
|
|
if( PollEventMask != 0 && Endpoint->EventObject != NULL ) {
|
|
|
|
IF_DEBUG(EVENT_SELECT) {
|
|
KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_TRACE_LEVEL,
|
|
"AfdIndicateEventSelectEvent: Setting event %p\n",
|
|
Endpoint->EventObject
|
|
));
|
|
}
|
|
|
|
KeSetEvent(
|
|
Endpoint->EventObject,
|
|
AfdPriorityBoost,
|
|
FALSE
|
|
);
|
|
|
|
}
|
|
|
|
} // AfdIndicateEventSelectEvent
|
|
|