-/* $Id: select.c,v 1.5 2004/11/15 18:24:57 arty Exp $
+/* $Id$
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/net/afd/afd/select.c
#include "tdiconn.h"
#include "debug.h"
-VOID CopyBackStatus( PAFD_HANDLE HandleArray,
+static VOID PrintEvents( ULONG Events ) {
+#if DBG
+ char *events_list[] = { "AFD_EVENT_RECEIVE",
+ "AFD_EVENT_OOB_RECEIVE",
+ "AFD_EVENT_SEND",
+ "AFD_EVENT_DISCONNECT",
+ "AFD_EVENT_ABORT",
+ "AFD_EVENT_CLOSE",
+ "AFD_EVENT_CONNECT",
+ "AFD_EVENT_ACCEPT",
+ "AFD_EVENT_CONNECT_FAIL",
+ "AFD_EVENT_QOS",
+ "AFD_EVENT_GROUP_QOS",
+ NULL };
+ int i;
+
+ for( i = 0; events_list[i]; i++ )
+ if( Events & (1 << i) ) AFD_DbgPrint(MID_TRACE,("%s ", events_list[i] ));
+#endif
+}
+
+static VOID CopyBackStatus( PAFD_HANDLE HandleArray,
UINT HandleCount ) {
UINT i;
-
+
for( i = 0; i < HandleCount; i++ ) {
HandleArray[i].Events = HandleArray[i].Status;
HandleArray[i].Status = 0;
}
}
-VOID ZeroEvents( PAFD_HANDLE HandleArray,
+static VOID ZeroEvents( PAFD_HANDLE HandleArray,
UINT HandleCount ) {
UINT i;
-
- for( i = 0; i < HandleCount; i++ ) {
- HandleArray[i].Events = 0;
+
+ for( i = 0; i < HandleCount; i++ )
HandleArray[i].Status = 0;
- }
}
-NTSTATUS STDCALL
-ScanForImmediateTrigger( PAFD_HANDLE HandleArray,
- UINT HandleCount,
- PUINT HandlesSet ) {
- NTSTATUS Status = STATUS_SUCCESS;
- PFILE_OBJECT FileObject;
- PAFD_FCB FCB;
- UINT i;
- BOOLEAN ShouldReturnNow = FALSE;
-
- for( i = 0; i < HandleCount && NT_SUCCESS(Status); i++ ) {
- HandleArray[i].Status = 0;
- Status =
- ObReferenceObjectByHandle
- ( (PVOID)HandleArray[i].Handle,
- FILE_ALL_ACCESS,
- NULL,
- KernelMode,
- (PVOID*)&FileObject,
- NULL );
-
- if( NT_SUCCESS(Status) ) {
- FCB = FileObject->FsContext;
- /* Check select bits */
-
- AFD_DbgPrint(MID_TRACE,("Locking socket state\n"));
- if( !SocketAcquireStateLock( FCB ) ) {
- AFD_DbgPrint(MID_TRACE,("Failed to get a socket state\n"));
- Status = STATUS_UNSUCCESSFUL;
- } else {
- AFD_DbgPrint(MID_TRACE,("Got a socket state\n"));
- Status = STATUS_SUCCESS;
- HandleArray[i].Status =
- FCB->PollState & HandleArray[i].Events;
- if( HandleArray[i].Status ) ShouldReturnNow = TRUE;
- ObDereferenceObject( (PVOID)HandleArray[i].Handle );
- AFD_DbgPrint(MID_TRACE,("Unlocking\n"));
- SocketStateUnlock( FCB );
- AFD_DbgPrint(MID_TRACE,("Unlocked\n"));
- }
- }
+/* you must pass either Poll OR Irp */
+static VOID SignalSocket(
+ PAFD_ACTIVE_POLL Poll OPTIONAL,
+ PIRP _Irp OPTIONAL,
+ PAFD_POLL_INFO PollReq,
+ NTSTATUS Status
+ )
+{
+ UINT i;
+ PIRP Irp = _Irp ? _Irp : Poll->Irp;
+ AFD_DbgPrint(MID_TRACE,("Called (Status %x)\n", Status));
+
+ if (Poll)
+ {
+ KeCancelTimer( &Poll->Timer );
+ RemoveEntryList( &Poll->ListEntry );
+ ExFreePool( Poll );
+ }
+
+ Irp->IoStatus.Status = Status;
+ Irp->IoStatus.Information =
+ FIELD_OFFSET(AFD_POLL_INFO, Handles) + sizeof(AFD_HANDLE) * PollReq->HandleCount;
+ CopyBackStatus( PollReq->Handles,
+ PollReq->HandleCount );
+ for( i = 0; i < PollReq->HandleCount; i++ ) {
+ AFD_DbgPrint
+ (MAX_TRACE,
+ ("Handle(%x): Got %x,%x\n",
+ PollReq->Handles[i].Handle,
+ PollReq->Handles[i].Events,
+ PollReq->Handles[i].Status));
}
-
- if( !NT_SUCCESS(Status) || ShouldReturnNow ) return Status;
- else return STATUS_PENDING;
+ UnlockHandles( AFD_HANDLES(PollReq), PollReq->HandleCount );
+ AFD_DbgPrint(MID_TRACE,("Completing\n"));
+ IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+ AFD_DbgPrint(MID_TRACE,("Done\n"));
}
-VOID SelectTimeout( PKDPC Dpc,
+static VOID SelectTimeout( PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2 ) {
PAFD_ACTIVE_POLL Poll = DeferredContext;
PAFD_POLL_INFO PollReq;
- PAFD_DEVICE_EXTENSION DeviceExt;
PIRP Irp;
KIRQL OldIrql;
+ PAFD_DEVICE_EXTENSION DeviceExt;
+
+ AFD_DbgPrint(MID_TRACE,("Called\n"));
Irp = Poll->Irp;
DeviceExt = Poll->DeviceExt;
-
PollReq = Irp->AssociatedIrp.SystemBuffer;
+ ZeroEvents( PollReq->Handles, PollReq->HandleCount );
+
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
- RemoveEntryList( &Poll->ListEntry );
+ SignalSocket( Poll, NULL, PollReq, STATUS_TIMEOUT );
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
- ExFreePool( Poll );
+ AFD_DbgPrint(MID_TRACE,("Timeout\n"));
+}
- ZeroEvents( PollReq->Handles, PollReq->HandleCount );
+VOID KillSelectsForFCB( PAFD_DEVICE_EXTENSION DeviceExt,
+ PFILE_OBJECT FileObject,
+ BOOLEAN OnlyExclusive ) {
+ KIRQL OldIrql;
+ PLIST_ENTRY ListEntry;
+ PAFD_ACTIVE_POLL Poll;
+ PIRP Irp;
+ PAFD_POLL_INFO PollReq;
+ PAFD_HANDLE HandleArray;
+ UINT i;
+
+ AFD_DbgPrint(MID_TRACE,("Killing selects that refer to %x\n", FileObject));
+
+ KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+
+ ListEntry = DeviceExt->Polls.Flink;
+ while ( ListEntry != &DeviceExt->Polls ) {
+ Poll = CONTAINING_RECORD(ListEntry, AFD_ACTIVE_POLL, ListEntry);
+ ListEntry = ListEntry->Flink;
+ Irp = Poll->Irp;
+ PollReq = Irp->AssociatedIrp.SystemBuffer;
+ HandleArray = AFD_HANDLES(PollReq);
+
+ for( i = 0; i < PollReq->HandleCount; i++ ) {
+ AFD_DbgPrint(MAX_TRACE,("Req: %x, This %x\n",
+ HandleArray[i].Handle, FileObject));
+ if( (PVOID)HandleArray[i].Handle == FileObject &&
+ (!OnlyExclusive || (OnlyExclusive && Poll->Exclusive)) ) {
+ ZeroEvents( PollReq->Handles, PollReq->HandleCount );
+ SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
+ }
+ }
+ }
- Irp->IoStatus.Status = STATUS_TIMEOUT;
- Irp->IoStatus.Information = -1;
+ KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
- IoCompleteRequest( Irp, IO_NO_INCREMENT );
+ AFD_DbgPrint(MID_TRACE,("Done\n"));
}
NTSTATUS STDCALL
-AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+AfdSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp ) {
NTSTATUS Status = STATUS_NO_MEMORY;
+ PAFD_FCB FCB;
+ PFILE_OBJECT FileObject;
PAFD_POLL_INFO PollReq = Irp->AssociatedIrp.SystemBuffer;
PAFD_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension;
- PAFD_ACTIVE_POLL Poll = NULL;
UINT CopySize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
- UINT AllocSize =
+ UINT AllocSize =
CopySize + sizeof(AFD_ACTIVE_POLL) - sizeof(AFD_POLL_INFO);
KIRQL OldIrql;
- UINT HandlesSignalled;
+ UINT i, Signalled = 0;
+ ULONG Exclusive = PollReq->Exclusive;
- AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
+ AFD_DbgPrint(MID_TRACE,("Called (HandleCount %d Timeout %d)\n",
PollReq->HandleCount,
- (INT)(PollReq->Timeout.QuadPart * -1)));
+ (INT)(PollReq->Timeout.QuadPart)));
- Status = ScanForImmediateTrigger( PollReq->Handles,
- PollReq->HandleCount,
- &HandlesSignalled );
-
- if( Status == STATUS_PENDING ) {
- Poll = ExAllocatePool( NonPagedPool, AllocSize );
-
- if( Poll ) {
- KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
-
- KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
- (PKDEFERRED_ROUTINE)SelectTimeout,
- Poll );
- PollReq->Timeout.QuadPart *= -1;
- /* Negative values are relative */
- KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
- KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
-
- Poll->Irp = Irp;
- Poll->DeviceExt = DeviceExt;
-
- InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
- Status = STATUS_PENDING;
-
- KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
- } else Status = STATUS_NO_MEMORY;
- } else if( Status == STATUS_SUCCESS ) {
- CopyBackStatus( PollReq->Handles,
- PollReq->HandleCount );
- } else {
- ZeroEvents( PollReq->Handles,
- PollReq->HandleCount );
+ SET_AFD_HANDLES(PollReq,
+ LockHandles( PollReq->Handles, PollReq->HandleCount ));
+
+ if( !AFD_HANDLES(PollReq) ) {
+ Irp->IoStatus.Status = STATUS_NO_MEMORY;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+ return Irp->IoStatus.Status;
}
- AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
+ if( Exclusive ) {
+ for( i = 0; i < PollReq->HandleCount; i++ ) {
+ if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
- if( Status == STATUS_PENDING )
- IoMarkIrpPending( Irp );
- else {
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = HandlesSignalled;
- IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
+ KillSelectsForFCB( DeviceExt,
+ (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle,
+ TRUE );
+ }
}
+ ZeroEvents( PollReq->Handles,
+ PollReq->HandleCount );
+
+ KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+
+ for( i = 0; i < PollReq->HandleCount; i++ ) {
+ if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
+
+ FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
+ FCB = FileObject->FsContext;
+
+ if( (FCB->PollState & AFD_EVENT_CLOSE) ||
+ (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
+ AFD_HANDLES(PollReq)[i].Handle = 0;
+ PollReq->Handles[i].Events = 0;
+ PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
+ Signalled++;
+ } else {
+ AFD_DbgPrint(MID_TRACE, ("AFD: Select Events: "));
+ PrintEvents( PollReq->Handles[i].Events );
+ AFD_DbgPrint(MID_TRACE,("\n"));
+
+ PollReq->Handles[i].Status =
+ PollReq->Handles[i].Events & FCB->PollState;
+ if( PollReq->Handles[i].Status ) {
+ AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
+ FCB, FCB->PollState));
+ Signalled++;
+ }
+ }
+ }
+
+ if( Signalled ) {
+ Status = STATUS_SUCCESS;
+ Irp->IoStatus.Status = Status;
+ SignalSocket( NULL, Irp, PollReq, Status );
+ } else {
+
+ PAFD_ACTIVE_POLL Poll = NULL;
+
+ Poll = ExAllocatePool( NonPagedPool, AllocSize );
+
+ if (Poll){
+ Poll->Irp = Irp;
+ Poll->DeviceExt = DeviceExt;
+ Poll->Exclusive = Exclusive;
+
+ KeInitializeTimerEx( &Poll->Timer, NotificationTimer );
+
+ KeInitializeDpc( (PRKDPC)&Poll->TimeoutDpc,
+ (PKDEFERRED_ROUTINE)SelectTimeout,
+ Poll );
+
+ InsertTailList( &DeviceExt->Polls, &Poll->ListEntry );
+
+ KeSetTimer( &Poll->Timer, PollReq->Timeout, &Poll->TimeoutDpc );
+
+ Status = STATUS_PENDING;
+ IoMarkIrpPending( Irp );
+ } else {
+ AFD_DbgPrint(MAX_TRACE, ("FIXME: do something with the IRP!\n"));
+ Status = STATUS_NO_MEMORY;
+ }
+ }
+
+ KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+
+ AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
+
return Status;
}
-VOID SignalSocket( PAFD_ACTIVE_POLL Poll, PAFD_POLL_INFO PollReq, UINT i ) {
- /* One of the files was destroyed. We return now with error. */
- Poll->Irp->IoStatus.Status = STATUS_SUCCESS; /* XXX REVISIT */
- Poll->Irp->IoStatus.Information = 1;
- CopyBackStatus( PollReq->Handles,
- PollReq->HandleCount );
- IoCompleteRequest( Poll->Irp, IO_NETWORK_INCREMENT );
+NTSTATUS STDCALL
+AfdEventSelect( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp ) {
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ NTSTATUS Status = STATUS_NO_MEMORY;
+ PAFD_EVENT_SELECT_INFO EventSelectInfo =
+ (PAFD_EVENT_SELECT_INFO)LockRequest( Irp, IrpSp );
+ PAFD_FCB FCB = FileObject->FsContext;
+
+ AFD_DbgPrint(MID_TRACE,("Called (Event %x Triggers %x)\n",
+ EventSelectInfo->EventObject,
+ EventSelectInfo->Events));
+
+ if( !SocketAcquireStateLock( FCB ) ) {
+ UnlockRequest( Irp, IrpSp );
+ return LostSocket( Irp, FALSE );
+ }
+
+ FCB->EventSelectTriggers = FCB->EventsFired = 0;
+ if( FCB->EventSelect ) ObDereferenceObject( FCB->EventSelect );
+ FCB->EventSelect = NULL;
+
+ if( EventSelectInfo->EventObject && EventSelectInfo->Events ) {
+ Status = ObReferenceObjectByHandle( (PVOID)EventSelectInfo->
+ EventObject,
+ FILE_ALL_ACCESS,
+ NULL,
+ KernelMode,
+ (PVOID *)&FCB->EventSelect,
+ NULL );
+
+ if( !NT_SUCCESS(Status) )
+ FCB->EventSelect = NULL;
+ else
+ FCB->EventSelectTriggers = EventSelectInfo->Events;
+ } else /* Work done, cancelling select */
+ Status = STATUS_SUCCESS;
+
+ AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
+
+ return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
+ 0, NULL, TRUE );
}
-BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
+NTSTATUS STDCALL
+AfdEnumEvents( PDEVICE_OBJECT DeviceObject, PIRP Irp,
+ PIO_STACK_LOCATION IrpSp ) {
+ PFILE_OBJECT FileObject = IrpSp->FileObject;
+ PAFD_ENUM_NETWORK_EVENTS_INFO EnumReq =
+ (PAFD_ENUM_NETWORK_EVENTS_INFO)LockRequest( Irp, IrpSp );
+ PAFD_FCB FCB = FileObject->FsContext;
+
+ AFD_DbgPrint(MID_TRACE,("Called (FCB %x)\n", FCB));
+
+ if( !SocketAcquireStateLock( FCB ) ) {
+ UnlockRequest( Irp, IrpSp );
+ return LostSocket( Irp, FALSE );
+ }
+
+ EnumReq->PollEvents = FCB->PollState;
+ RtlZeroMemory( EnumReq->EventStatus, sizeof(EnumReq->EventStatus) );
+
+ return UnlockAndMaybeComplete( FCB, STATUS_SUCCESS, Irp,
+ 0, NULL, TRUE );
+}
+
+/* * * NOTE ALWAYS CALLED AT DISPATCH_LEVEL * * */
+static BOOLEAN UpdatePollWithFCB( PAFD_ACTIVE_POLL Poll, PFILE_OBJECT FileObject ) {
UINT i;
- NTSTATUS Status;
- PFILE_OBJECT TargetFile;
PAFD_FCB FCB;
+ UINT Signalled = 0;
PAFD_POLL_INFO PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
+ ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
+
for( i = 0; i < PollReq->HandleCount; i++ ) {
- Status =
- ObReferenceObjectByHandle
- ( (PVOID)PollReq->Handles[i].Handle,
- FILE_ALL_ACCESS,
- NULL,
- KernelMode,
- (PVOID*)&TargetFile,
- NULL );
-
- if( !NT_SUCCESS(Status) ) {
- PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
- SignalSocket( Poll, PollReq, i );
- return TRUE;
- } else {
- FCB = FileObject->FsContext;
+ if( !AFD_HANDLES(PollReq)[i].Handle ) continue;
- AFD_DbgPrint(MID_TRACE,("Locking socket state\n"));
+ FileObject = (PFILE_OBJECT)AFD_HANDLES(PollReq)[i].Handle;
+ FCB = FileObject->FsContext;
- if( !SocketAcquireStateLock( FCB ) ) {
- PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
- SignalSocket( Poll, PollReq, i );
- } else {
- PollReq->Handles[i].Status =
- PollReq->Handles[i].Events & FCB->PollState;
- if( PollReq->Handles[i].Status )
- SignalSocket( Poll, PollReq, i );
- SocketStateUnlock( FCB );
+ if( (FCB->PollState & AFD_EVENT_CLOSE) ||
+ (PollReq->Handles[i].Status & AFD_EVENT_CLOSE) ) {
+ AFD_HANDLES(PollReq)[i].Handle = 0;
+ PollReq->Handles[i].Events = 0;
+ PollReq->Handles[i].Status = AFD_EVENT_CLOSE;
+ Signalled++;
+ } else {
+ PollReq->Handles[i].Status =
+ PollReq->Handles[i].Events & FCB->PollState;
+ if( PollReq->Handles[i].Status ) {
+ AFD_DbgPrint(MID_TRACE,("Signalling %x with %x\n",
+ FCB, FCB->PollState));
+ Signalled++;
}
- return TRUE;
}
}
- return FALSE;
+ return Signalled ? 1 : 0;
}
VOID PollReeval( PAFD_DEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject ) {
PAFD_ACTIVE_POLL Poll = NULL;
PLIST_ENTRY ThePollEnt = NULL;
+ PAFD_FCB FCB;
KIRQL OldIrql;
+ PAFD_POLL_INFO PollReq;
+ PKEVENT EventSelect = NULL;
- AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
+ AFD_DbgPrint(MID_TRACE,("Called: DeviceExt %x FileObject %x\n",
DeviceExt, FileObject));
KeAcquireSpinLock( &DeviceExt->Lock, &OldIrql );
+ /* Take care of any event select signalling */
+ FCB = (PAFD_FCB)FileObject->FsContext;
+
+ /* Not sure if i can do this at DISPATCH_LEVEL ... try it at passive */
+ AFD_DbgPrint(MID_TRACE,("Current State: %x, Events Fired: %x, "
+ "Select Triggers %x\n",
+ FCB->PollState, FCB->EventsFired,
+ FCB->EventSelectTriggers));
+ if( FCB->PollState & ~FCB->EventsFired & FCB->EventSelectTriggers ) {
+ FCB->EventsFired |= FCB->PollState;
+ EventSelect = FCB->EventSelect;
+ }
+
+ if( !FCB ) {
+ KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+ return;
+ }
+
+ /* Now signal normal select irps */
ThePollEnt = DeviceExt->Polls.Flink;
while( ThePollEnt != &DeviceExt->Polls ) {
Poll = CONTAINING_RECORD( ThePollEnt, AFD_ACTIVE_POLL, ListEntry );
+ PollReq = Poll->Irp->AssociatedIrp.SystemBuffer;
+ AFD_DbgPrint(MID_TRACE,("Checking poll %x\n", Poll));
+
if( UpdatePollWithFCB( Poll, FileObject ) ) {
ThePollEnt = ThePollEnt->Flink;
- RemoveEntryList( &Poll->ListEntry );
- } else
+ AFD_DbgPrint(MID_TRACE,("Signalling socket\n"));
+ SignalSocket( Poll, NULL, PollReq, STATUS_SUCCESS );
+ } else
ThePollEnt = ThePollEnt->Flink;
}
KeReleaseSpinLock( &DeviceExt->Lock, OldIrql );
+ AFD_DbgPrint(MID_TRACE,("Setting event %x\n", EventSelect));
+ if( EventSelect ) KeSetEvent( EventSelect, IO_NETWORK_INCREMENT, FALSE );
+
AFD_DbgPrint(MID_TRACE,("Leaving\n"));
}