[AFD]
[reactos.git] / reactos / drivers / network / afd / afd / read.c
index 039a8ec..3c6ddaa 100644 (file)
 #include "tdiconn.h"
 #include "debug.h"
 
-static BOOLEAN CantReadMore( PAFD_FCB FCB ) {
-    UINT BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
+static NTSTATUS RefillSocketBuffer( PAFD_FCB FCB ) {
+       NTSTATUS Status = STATUS_PENDING;
 
-    return !BytesAvailable &&
-        (FCB->PollState & (AFD_EVENT_CLOSE | AFD_EVENT_DISCONNECT));
-}
-
-static VOID HandleEOFOnIrp( PAFD_FCB FCB, NTSTATUS Status, UINT Information ) {
-    if( Status == STATUS_SUCCESS && Information == 0 ) {
-        AFD_DbgPrint(MID_TRACE,("Looks like an EOF\n"));
-        FCB->PollState |= AFD_EVENT_DISCONNECT;
+       if( !FCB->ReceiveIrp.InFlightRequest ) {
+               AFD_DbgPrint(MID_TRACE,("Replenishing buffer\n"));
+
+               Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
+                                                        FCB->Connection.Object,
+                                                        TDI_RECEIVE_NORMAL,
+                                                        FCB->Recv.Window,
+                                                        FCB->Recv.Size,
+                                                        &FCB->ReceiveIrp.Iosb,
+                                                        ReceiveComplete,
+                                                        FCB );
+
+        if( ( Status == STATUS_SUCCESS && !FCB->ReceiveIrp.Iosb.Information ) ||
+            ( !NT_SUCCESS( Status ) ) )
+        {
+            /* The socket has been closed */
+            FCB->PollState |= AFD_EVENT_DISCONNECT;
+            FCB->Overread = TRUE;
+            Status = STATUS_FILE_CLOSED;
+        }
+        else if( Status == STATUS_SUCCESS )
+        {
+            FCB->Recv.Content = FCB->ReceiveIrp.Iosb.Information;
+            FCB->PollState |= AFD_EVENT_RECEIVE;
+        }
         PollReeval( FCB->DeviceExt, FCB->FileObject );
-    }
+       }
+
+       return Status;
 }
 
 static NTSTATUS TryToSatisfyRecvRequestFromBuffer( PAFD_FCB FCB,
-                                           PAFD_RECV_INFO RecvReq,
-                                           PUINT TotalBytesCopied ) {
+                                                                                                  PAFD_RECV_INFO RecvReq,
+                                                                                                  PUINT TotalBytesCopied ) {
     UINT i, BytesToCopy = 0,
-       BytesAvailable =
-       FCB->Recv.Content - FCB->Recv.BytesUsed;
+               BytesAvailable =
+               FCB->Recv.Content - FCB->Recv.BytesUsed;
     PAFD_MAPBUF Map;
     NTSTATUS Status;
     *TotalBytesCopied = 0;
 
 
     AFD_DbgPrint(MID_TRACE,("Called, BytesAvailable = %d\n",
-                           BytesAvailable));
+                                                       BytesAvailable));
+
+       if( FCB->Overread ) return STATUS_FILE_CLOSED;
+    if( !BytesAvailable ) {
+        FCB->Recv.Content = FCB->Recv.BytesUsed = 0;
+               Status = RefillSocketBuffer( FCB );
+               if ( Status != STATUS_SUCCESS )
+                       return Status;
+
+        /* If RefillSocketBuffer returns STATUS_SUCCESS, we're good to go
+         * If RefillSocketBuffer returns STATUS_PENDING, then it's waiting on the transport for data
+         * If RefillSocketBuffer returns STATUS_FILE_CLOSED, then the connection was terminated
+         */
 
-    if( CantReadMore(FCB) ) return STATUS_SUCCESS;
-    if( !BytesAvailable ) return STATUS_PENDING;
+        /* Recalculate BytesAvailable based on new data */
+        BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
+        ASSERT(BytesAvailable);
+    }
 
     Map = (PAFD_MAPBUF)(RecvReq->BufferArray + RecvReq->BufferCount);
 
     AFD_DbgPrint(MID_TRACE,("Buffer Count: %d @ %x\n",
-                           RecvReq->BufferCount,
-                           RecvReq->BufferArray));
+                                                       RecvReq->BufferCount,
+                                                       RecvReq->BufferArray));
     for( i = 0;
-        RecvReq->BufferArray &&
-            BytesAvailable &&
-            i < RecvReq->BufferCount;
-        i++ ) {
-       BytesToCopy =
-           MIN( RecvReq->BufferArray[i].len, BytesAvailable );
-
-       if( Map[i].Mdl ) {
-           Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode );
-
-           AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
-                                   i,
-                                   Map[i].BufferAddress,
-                                   BytesToCopy));
-
-           RtlCopyMemory( Map[i].BufferAddress,
-                          FCB->Recv.Window + FCB->Recv.BytesUsed,
-                          BytesToCopy );
-
-           MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
-
-           FCB->Recv.BytesUsed += BytesToCopy;
-           *TotalBytesCopied += BytesToCopy;
-           BytesAvailable -= BytesToCopy;
-       }
+                RecvReq->BufferArray &&
+                        BytesAvailable &&
+                        i < RecvReq->BufferCount;
+                i++ ) {
+               BytesToCopy =
+                       MIN( RecvReq->BufferArray[i].len, BytesAvailable );
+
+               if( Map[i].Mdl ) {
+                       Map[i].BufferAddress = MmMapLockedPages( Map[i].Mdl, KernelMode );
+
+                       AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
+                                                                       i,
+                                                                       Map[i].BufferAddress,
+                                                                       BytesToCopy));
+
+                       RtlCopyMemory( Map[i].BufferAddress,
+                                                  FCB->Recv.Window + FCB->Recv.BytesUsed,
+                                                  BytesToCopy );
+
+                       MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
+
+            *TotalBytesCopied += BytesToCopy;
+
+            if (!(RecvReq->TdiFlags & TDI_RECEIVE_PEEK)) {
+                FCB->Recv.BytesUsed += BytesToCopy;
+                BytesAvailable -= BytesToCopy;
+            }
+               }
     }
 
     /* If there's nothing left in our buffer start a new request */
     if( FCB->Recv.BytesUsed == FCB->Recv.Content ) {
-       FCB->Recv.BytesUsed = FCB->Recv.Content = 0;
+               FCB->Recv.BytesUsed = FCB->Recv.Content = 0;
         FCB->PollState &= ~AFD_EVENT_RECEIVE;
 
-       if( !FCB->ReceiveIrp.InFlightRequest ) {
-           AFD_DbgPrint(MID_TRACE,("Replenishing buffer\n"));
-
-           SocketCalloutEnter( FCB );
-
-           Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
-                                FCB->Connection.Object,
-                                TDI_RECEIVE_NORMAL,
-                                FCB->Recv.Window,
-                                FCB->Recv.Size,
-                                &FCB->ReceiveIrp.Iosb,
-                                ReceiveComplete,
-                                FCB );
-
-           SocketCalloutLeave( FCB );
-
-            if( Status == STATUS_SUCCESS )
-                FCB->Recv.Content = FCB->ReceiveIrp.Iosb.Information;
-            HandleEOFOnIrp( FCB, Status, FCB->ReceiveIrp.Iosb.Information );
-       }
+        RefillSocketBuffer( FCB );
     }
 
     return STATUS_SUCCESS;
@@ -126,88 +143,65 @@ static NTSTATUS ReceiveActivity( PAFD_FCB FCB, PIRP Irp ) {
     PIRP NextIrp;
     PIO_STACK_LOCATION NextIrpSp;
     PAFD_RECV_INFO RecvReq;
-    UINT TotalBytesCopied = 0;
+    UINT TotalBytesCopied = 0, RetBytesCopied = 0;
     NTSTATUS Status = STATUS_SUCCESS, RetStatus = STATUS_PENDING;
 
     AFD_DbgPrint(MID_TRACE,("%x %x\n", FCB, Irp));
 
-    if( CantReadMore( FCB ) ) {
-        /* Success here means that we got an EOF.  Complete a pending read
-         * with zero bytes if we haven't yet overread, then kill the others.
-         */
-        while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
-            NextIrpEntry =
-                RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
-            NextIrp =
-                CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
-            NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
-            RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
-
-            AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
-                                    TotalBytesCopied));
-            UnlockBuffers( RecvReq->BufferArray,
-                           RecvReq->BufferCount, FALSE );
-            Status = NextIrp->IoStatus.Status =
-                FCB->Overread ? STATUS_END_OF_FILE : STATUS_SUCCESS;
-            NextIrp->IoStatus.Information = 0;
-            if( NextIrp == Irp ) RetStatus = Status;
-            IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
-            FCB->Overread = TRUE;
-            //FCB->PollState |= AFD_EVENT_DISCONNECT;
-            PollReeval( FCB->DeviceExt, FCB->FileObject );
-        }
-    } else {
-       /* Kick the user that receive would be possible now */
-       /* XXX Not implemented yet */
+    /* Kick the user that receive would be possible now */
+    /* XXX Not implemented yet */
 
-       AFD_DbgPrint(MID_TRACE,("FCB %x Receive data waiting %d\n",
-                               FCB, FCB->Recv.Content));
-       /*OskitDumpBuffer( FCB->Recv.Window, FCB->Recv.Content );*/
+    AFD_DbgPrint(MID_TRACE,("FCB %x Receive data waiting %d\n",
+                                               FCB, FCB->Recv.Content));
 
-       Status = STATUS_SUCCESS;
+    /* Try to clear some requests */
+    while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
+          NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
+          NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
+          NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
+          RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
 
-       /* Try to clear some requests */
-       while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) &&
-              NT_SUCCESS(Status) ) {
-           NextIrpEntry =
-               RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
-           NextIrp =
-               CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
-           NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
-           RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+          AFD_DbgPrint(MID_TRACE,("RecvReq @ %x\n", RecvReq));
 
-           AFD_DbgPrint(MID_TRACE,("RecvReq @ %x\n", RecvReq));
+          Status = TryToSatisfyRecvRequestFromBuffer( FCB, RecvReq, &TotalBytesCopied );
 
-           Status = TryToSatisfyRecvRequestFromBuffer
-               ( FCB, RecvReq, &TotalBytesCopied );
-
-           if( Status == STATUS_PENDING ) {
+          if( Status == STATUS_PENDING ) {
                AFD_DbgPrint(MID_TRACE,("Ran out of data for %x\n", NextIrp));
                InsertHeadList(&FCB->PendingIrpList[FUNCTION_RECV],
-                              &NextIrp->Tail.Overlay.ListEntry);
+                                          &NextIrp->Tail.Overlay.ListEntry);
                break;
-           } else {
+          } else {
                AFD_DbgPrint(MID_TRACE,("Completing recv %x (%d)\n", NextIrp,
-                                       TotalBytesCopied));
+                                                               TotalBytesCopied));
                UnlockBuffers( RecvReq->BufferArray,
-                              RecvReq->BufferCount, FALSE );
+                                          RecvReq->BufferCount, FALSE );
                NextIrp->IoStatus.Status = Status;
                NextIrp->IoStatus.Information = TotalBytesCopied;
-                if( NextIrp == Irp ) RetStatus = Status;
+               if( NextIrp == Irp ) { 
+                       RetStatus = Status;
+                       RetBytesCopied = TotalBytesCopied;
+               }
+               if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+                (void)IoSetCancelRoutine(NextIrp, NULL);
                IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
-           }
-       }
+          }
     }
 
-    if( FCB->Recv.Content ) {
-       FCB->PollState |= AFD_EVENT_RECEIVE;
+    if( !FCB->Recv.Content ) {
+               FCB->PollState |= AFD_EVENT_RECEIVE;
     } else
-       FCB->PollState &= ~AFD_EVENT_RECEIVE;
+               FCB->PollState &= ~AFD_EVENT_RECEIVE;
 
     PollReeval( FCB->DeviceExt, FCB->FileObject );
 
     AFD_DbgPrint(MID_TRACE,("RetStatus for irp %x is %x\n", Irp, RetStatus));
 
+    /* Sometimes we're called with a NULL Irp */
+    if( Irp ) {
+        Irp->IoStatus.Status = RetStatus;
+        Irp->IoStatus.Information = RetBytesCopied;
+    }
+
     return RetStatus;
 }
 
@@ -215,46 +209,55 @@ NTSTATUS NTAPI ReceiveComplete
 ( PDEVICE_OBJECT DeviceObject,
   PIRP Irp,
   PVOID Context ) {
-    NTSTATUS Status = Irp->IoStatus.Status;
     PAFD_FCB FCB = (PAFD_FCB)Context;
+    PLIST_ENTRY NextIrpEntry;
+    PIRP NextIrp;
+    PAFD_RECV_INFO RecvReq;
+    PIO_STACK_LOCATION NextIrpSp;
 
     AFD_DbgPrint(MID_TRACE,("Called\n"));
 
-    ASSERT_IRQL(APC_LEVEL);
-
-    if( !SocketAcquireStateLock( FCB ) ) return Status;
+    if( !SocketAcquireStateLock( FCB ) )
+        return STATUS_FILE_CLOSED;
 
     FCB->ReceiveIrp.InFlightRequest = NULL;
+
     FCB->Recv.Content = Irp->IoStatus.Information;
     FCB->Recv.BytesUsed = 0;
 
     if( FCB->State == SOCKET_STATE_CLOSED ) {
-        AFD_DbgPrint(MIN_TRACE,("!!! CLOSED SOCK GOT A RECEIVE COMPLETE !!!\n"));
+        AFD_DbgPrint(MIN_TRACE,("!!! CLOSING SOCK GOT A RECEIVE COMPLETE !!!\n"));
+        /* Cleanup our IRP queue because the FCB is being destroyed */
+        while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
+              NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
+              NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
+               NextIrpSp = IoGetCurrentIrpStackLocation(NextIrp);
+               RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+              NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
+              NextIrp->IoStatus.Information = 0;
+              UnlockBuffers(RecvReq->BufferArray, RecvReq->BufferCount, FALSE);
+              if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+               (void)IoSetCancelRoutine(NextIrp, NULL);
+              IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
+        }
        SocketStateUnlock( FCB );
-       DestroySocket( FCB );
-       return STATUS_SUCCESS;
+       return STATUS_FILE_CLOSED;
     } else if( FCB->State == SOCKET_STATE_LISTENING ) {
         AFD_DbgPrint(MIN_TRACE,("!!! LISTENER GOT A RECEIVE COMPLETE !!!\n"));
         SocketStateUnlock( FCB );
-        return STATUS_UNSUCCESSFUL;
+        return STATUS_INVALID_PARAMETER;
     }
 
-    HandleEOFOnIrp( FCB, Irp->IoStatus.Status, Irp->IoStatus.Information );
-
-    ReceiveActivity( FCB, NULL );
-
-    PollReeval( FCB->DeviceExt, FCB->FileObject );
-
+       ReceiveActivity( FCB, NULL );
+               
     SocketStateUnlock( FCB );
 
-    AFD_DbgPrint(MID_TRACE,("Returned %x\n", Status));
-
     return STATUS_SUCCESS;
 }
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
-                          PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
+                                                  PIO_STACK_LOCATION IrpSp, BOOLEAN Short) {
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
     PFILE_OBJECT FileObject = IrpSp->FileObject;
     PAFD_FCB FCB = FileObject->FsContext;
@@ -263,40 +266,37 @@ AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
 
     AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
 
-    if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
+    if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
 
     if( FCB->State != SOCKET_STATE_CONNECTED &&
         FCB->State != SOCKET_STATE_CONNECTING ) {
         AFD_DbgPrint(MID_TRACE,("Called recv on wrong kind of socket (s%x)\n",
                                 FCB->State));
-        return UnlockAndMaybeComplete( FCB, STATUS_UNSUCCESSFUL,
-                                      Irp, 0, NULL, FALSE );
+        return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER,
+                                                                          Irp, 0 );
     }
 
     if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
     {
-       AFD_DbgPrint(MID_TRACE,("Receive on connection-less sockets not implemented\n"));
-       return UnlockAndMaybeComplete( FCB, STATUS_NOT_IMPLEMENTED,
-                                      Irp, 0, NULL, FALSE );
+               AFD_DbgPrint(MID_TRACE,("Receive on connection-less sockets not implemented\n"));
+               return UnlockAndMaybeComplete( FCB, STATUS_NOT_IMPLEMENTED,
+                                                                          Irp, 0 );
     }
 
-    FCB->EventsFired &= ~AFD_EVENT_RECEIVE;
-    PollReeval( FCB->DeviceExt, FCB->FileObject );
-
     if( !(RecvReq = LockRequest( Irp, IrpSp )) )
-       return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY,
-                                      Irp, 0, NULL, FALSE );
+               return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY,
+                                                                          Irp, 0 );
 
     AFD_DbgPrint(MID_TRACE,("Recv flags %x\n", RecvReq->AfdFlags));
 
     RecvReq->BufferArray = LockBuffers( RecvReq->BufferArray,
-                                       RecvReq->BufferCount,
-                                       NULL, NULL,
-                                       TRUE, FALSE );
+                                                                               RecvReq->BufferCount,
+                                                                               NULL, NULL,
+                                                                               TRUE, FALSE );
 
     if( !RecvReq->BufferArray ) {
         return UnlockAndMaybeComplete( FCB, STATUS_ACCESS_VIOLATION,
-                                       Irp, 0, NULL, FALSE );
+                                       Irp, 0 );
     }
 
     Irp->IoStatus.Status = STATUS_PENDING;
@@ -309,17 +309,18 @@ AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
 
     Status = ReceiveActivity( FCB, Irp );
 
-    if( Status == STATUS_PENDING && RecvReq->AfdFlags & AFD_IMMEDIATE ) {
+    if( Status == STATUS_PENDING && (RecvReq->AfdFlags & AFD_IMMEDIATE) ) {
         AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
         Status = STATUS_CANT_WAIT;
         TotalBytesCopied = 0;
         RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
         UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, FALSE );
         return UnlockAndMaybeComplete( FCB, Status, Irp,
-                                       TotalBytesCopied, NULL, TRUE );
+                                       TotalBytesCopied );
     } else if( Status == STATUS_PENDING ) {
         AFD_DbgPrint(MID_TRACE,("Leaving read irp\n"));
         IoMarkIrpPending( Irp );
+        (void)IoSetCancelRoutine(Irp, AfdCancelHandler);
     } else {
         AFD_DbgPrint(MID_TRACE,("Completed with status %x\n", Status));
     }
@@ -329,84 +330,87 @@ AfdConnectedSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
 }
 
 
-static NTSTATUS STDCALL
+static NTSTATUS NTAPI
 SatisfyPacketRecvRequest( PAFD_FCB FCB, PIRP Irp,
-                         PAFD_STORED_DATAGRAM DatagramRecv,
-                         PUINT TotalBytesCopied ) {
+                                                 PAFD_STORED_DATAGRAM DatagramRecv,
+                                                 PUINT TotalBytesCopied ) {
     NTSTATUS Status = STATUS_SUCCESS;
     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
     PAFD_RECV_INFO RecvReq =
-       IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+               IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
     UINT BytesToCopy = 0, BytesAvailable = DatagramRecv->Len, AddrLen = 0;
     PAFD_MAPBUF Map;
 
     Map = (PAFD_MAPBUF)(RecvReq->BufferArray +
-                       RecvReq->BufferCount +
-                       EXTRA_LOCK_BUFFERS);
+                                               RecvReq->BufferCount +
+                                               EXTRA_LOCK_BUFFERS);
 
     BytesToCopy =
-       MIN( RecvReq->BufferArray[0].len, BytesAvailable );
+               MIN( RecvReq->BufferArray[0].len, BytesAvailable );
 
     AFD_DbgPrint(MID_TRACE,("BytesToCopy: %d len %d\n", BytesToCopy,
-                           RecvReq->BufferArray[0].len));
+                                                       RecvReq->BufferArray[0].len));
 
     if( Map[0].Mdl ) {
-       /* Copy the address */
-       if( Map[1].Mdl && Map[2].Mdl ) {
-           AFD_DbgPrint(MID_TRACE,("Checking TAAddressCount\n"));
+               /* Copy the address */
+               if( Map[1].Mdl && Map[2].Mdl ) {
+                       AFD_DbgPrint(MID_TRACE,("Checking TAAddressCount\n"));
 
-           if( DatagramRecv->Address->TAAddressCount != 1 ) {
-               AFD_DbgPrint
-                   (MID_TRACE,
-                    ("Wierd address count %d\n",
-                     DatagramRecv->Address->TAAddressCount));
-           }
+                       if( DatagramRecv->Address->TAAddressCount != 1 ) {
+                               AFD_DbgPrint
+                                       (MID_TRACE,
+                                        ("Wierd address count %d\n",
+                                         DatagramRecv->Address->TAAddressCount));
+                       }
 
-           AFD_DbgPrint(MID_TRACE,("Computing addr len\n"));
+                       AFD_DbgPrint(MID_TRACE,("Computing addr len\n"));
 
-           AddrLen = MIN(DatagramRecv->Address->Address->AddressLength +
-                         sizeof(USHORT),
-                         RecvReq->BufferArray[1].len);
+                       AddrLen = MIN(DatagramRecv->Address->Address->AddressLength +
+                                                 sizeof(USHORT),
+                                                 RecvReq->BufferArray[1].len);
 
-           AFD_DbgPrint(MID_TRACE,("Copying %d bytes of address\n", AddrLen));
+                       AFD_DbgPrint(MID_TRACE,("Copying %d bytes of address\n", AddrLen));
 
-           Map[1].BufferAddress = MmMapLockedPages( Map[1].Mdl, KernelMode );
+                       Map[1].BufferAddress = MmMapLockedPages( Map[1].Mdl, KernelMode );
 
-           AFD_DbgPrint(MID_TRACE,("Done mapping, copying address\n"));
+                       AFD_DbgPrint(MID_TRACE,("Done mapping, copying address\n"));
 
-           RtlCopyMemory( Map[1].BufferAddress,
-                          &DatagramRecv->Address->Address->AddressType,
-                          AddrLen );
+                       RtlCopyMemory( Map[1].BufferAddress,
+                                                  &DatagramRecv->Address->Address->AddressType,
+                                                  AddrLen );
 
-           MmUnmapLockedPages( Map[1].BufferAddress, Map[1].Mdl );
+                       MmUnmapLockedPages( Map[1].BufferAddress, Map[1].Mdl );
 
-           AFD_DbgPrint(MID_TRACE,("Copying address len\n"));
+                       AFD_DbgPrint(MID_TRACE,("Copying address len\n"));
 
-           Map[2].BufferAddress = MmMapLockedPages( Map[2].Mdl, KernelMode );
-           *((PINT)Map[2].BufferAddress) = AddrLen;
-           MmUnmapLockedPages( Map[2].BufferAddress, Map[2].Mdl );
-       }
+                       Map[2].BufferAddress = MmMapLockedPages( Map[2].Mdl, KernelMode );
+                       *((PINT)Map[2].BufferAddress) = AddrLen;
+                       MmUnmapLockedPages( Map[2].BufferAddress, Map[2].Mdl );
+               }
+
+               AFD_DbgPrint(MID_TRACE,("Mapping data buffer pages\n"));
 
-       AFD_DbgPrint(MID_TRACE,("Mapping data buffer pages\n"));
+               Map[0].BufferAddress = MmMapLockedPages( Map[0].Mdl, KernelMode );
 
-       Map[0].BufferAddress = MmMapLockedPages( Map[0].Mdl, KernelMode );
+               AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
+                                                               0,
+                                                               Map[0].BufferAddress,
+                                                               BytesToCopy));
 
-       AFD_DbgPrint(MID_TRACE,("Buffer %d: %x:%d\n",
-                               0,
-                               Map[0].BufferAddress,
-                               BytesToCopy));
+               /* OskitDumpBuffer
+                  ( FCB->Recv.Window + FCB->Recv.BytesUsed, BytesToCopy ); */
 
-       /* OskitDumpBuffer
-          ( FCB->Recv.Window + FCB->Recv.BytesUsed, BytesToCopy ); */
+               RtlCopyMemory( Map[0].BufferAddress,
+                                          FCB->Recv.Window + FCB->Recv.BytesUsed,
+                                          BytesToCopy );
 
-       RtlCopyMemory( Map[0].BufferAddress,
-                      FCB->Recv.Window + FCB->Recv.BytesUsed,
-                      BytesToCopy );
+               MmUnmapLockedPages( Map[0].BufferAddress, Map[0].Mdl );
 
-       MmUnmapLockedPages( Map[0].BufferAddress, Map[0].Mdl );
+        *TotalBytesCopied = BytesToCopy;
 
-       FCB->Recv.BytesUsed = 0;
-       *TotalBytesCopied = BytesToCopy;
+        if (!(RecvReq->TdiFlags & TDI_RECEIVE_PEEK)) {
+            FCB->Recv.BytesUsed = 0;
+        }
     }
 
     Status = Irp->IoStatus.Status = STATUS_SUCCESS;
@@ -421,9 +425,9 @@ SatisfyPacketRecvRequest( PAFD_FCB FCB, PIRP Irp,
 
 NTSTATUS NTAPI
 PacketSocketRecvComplete(
-  PDEVICE_OBJECT DeviceObject,
-  PIRP Irp,
-  PVOID Context ) {
+       PDEVICE_OBJECT DeviceObject,
+       PIRP Irp,
+       PVOID Context ) {
     NTSTATUS Status = STATUS_SUCCESS;
     PAFD_FCB FCB = Context;
     PIRP NextIrp;
@@ -432,94 +436,125 @@ PacketSocketRecvComplete(
     PAFD_RECV_INFO RecvReq;
     PAFD_STORED_DATAGRAM DatagramRecv;
     UINT DGSize = Irp->IoStatus.Information + sizeof( AFD_STORED_DATAGRAM );
+    PLIST_ENTRY NextIrpEntry, DatagramRecvEntry;
 
     AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
 
-    if( !SocketAcquireStateLock( FCB ) ) return STATUS_UNSUCCESSFUL;
+    if( !SocketAcquireStateLock( FCB ) )
+        return STATUS_FILE_CLOSED;
 
     FCB->ReceiveIrp.InFlightRequest = NULL;
 
     if( FCB->State == SOCKET_STATE_CLOSED ) {
+        /* Cleanup our IRP queue because the FCB is being destroyed */
+        while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
+              NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
+              NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
+              NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
+              RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+              NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
+              NextIrp->IoStatus.Information = 0;
+              UnlockBuffers(RecvReq->BufferArray, RecvReq->BufferCount, FALSE);
+              if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+               (void)IoSetCancelRoutine(NextIrp, NULL);
+              IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
+        }
+
+        /* Free all items on the datagram list */
+        while( !IsListEmpty( &FCB->DatagramList ) ) {
+               DatagramRecvEntry = RemoveHeadList(&FCB->DatagramList);
+               DatagramRecv = CONTAINING_RECORD(DatagramRecvEntry, AFD_STORED_DATAGRAM, ListEntry);
+               ExFreePool( DatagramRecv->Address );
+               ExFreePool( DatagramRecv );
+        }
+
        SocketStateUnlock( FCB );
-       DestroySocket( FCB );
-       return STATUS_SUCCESS;
+       return STATUS_FILE_CLOSED;
     }
 
     DatagramRecv = ExAllocatePool( NonPagedPool, DGSize );
 
     if( DatagramRecv ) {
-       DatagramRecv->Len = Irp->IoStatus.Information;
-       RtlCopyMemory( DatagramRecv->Buffer, FCB->Recv.Window,
-                      DatagramRecv->Len );
-       AFD_DbgPrint(MID_TRACE,("Received (A %x)\n",
-                               FCB->AddressFrom->RemoteAddress));
-       DatagramRecv->Address =
-           TaCopyTransportAddress( FCB->AddressFrom->RemoteAddress );
-
-       InsertTailList( &FCB->DatagramList, &DatagramRecv->ListEntry );
+               DatagramRecv->Len = Irp->IoStatus.Information;
+               RtlCopyMemory( DatagramRecv->Buffer, FCB->Recv.Window,
+                                          DatagramRecv->Len );
+               AFD_DbgPrint(MID_TRACE,("Received (A %x)\n",
+                                                               FCB->AddressFrom->RemoteAddress));
+               DatagramRecv->Address =
+                       TaCopyTransportAddress( FCB->AddressFrom->RemoteAddress );
+
+               if( !DatagramRecv->Address ) Status = STATUS_NO_MEMORY;
+
     } else Status = STATUS_NO_MEMORY;
 
+    if( !NT_SUCCESS( Status ) ) {
+               if( DatagramRecv ) ExFreePool( DatagramRecv );
+               SocketStateUnlock( FCB );
+               return Status;
+    } else {
+               InsertTailList( &FCB->DatagramList, &DatagramRecv->ListEntry );
+    }
+
     /* Satisfy as many requests as we can */
 
-    while( NT_SUCCESS(Status) &&
-          !IsListEmpty( &FCB->DatagramList ) &&
-          !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
-       AFD_DbgPrint(MID_TRACE,("Looping trying to satisfy request\n"));
-       ListEntry = RemoveHeadList( &FCB->DatagramList );
-       DatagramRecv = CONTAINING_RECORD( ListEntry, AFD_STORED_DATAGRAM,
-                                         ListEntry );
-       ListEntry = RemoveHeadList( &FCB->PendingIrpList[FUNCTION_RECV] );
-       NextIrp = CONTAINING_RECORD( ListEntry, IRP, Tail.Overlay.ListEntry );
-       NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
-       RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
-
-       AFD_DbgPrint(MID_TRACE,("RecvReq: %x, DatagramRecv: %x\n",
-                               RecvReq, DatagramRecv));
-
-       if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
-           !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
-           InsertHeadList( &FCB->DatagramList,
-                           &DatagramRecv->ListEntry );
-           Status = NextIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-           NextIrp->IoStatus.Information = DatagramRecv->Len;
-           UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
-           IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
-       } else {
-           AFD_DbgPrint(MID_TRACE,("Satisfying\n"));
-           Status = SatisfyPacketRecvRequest
-               ( FCB, NextIrp, DatagramRecv,
-                 (PUINT)&NextIrp->IoStatus.Information );
-           AFD_DbgPrint(MID_TRACE,("Unlocking\n"));
-           UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
-           AFD_DbgPrint(MID_TRACE,("Completing\n"));
-           IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
-       }
+    while( !IsListEmpty( &FCB->DatagramList ) &&
+                  !IsListEmpty( &FCB->PendingIrpList[FUNCTION_RECV] ) ) {
+               AFD_DbgPrint(MID_TRACE,("Looping trying to satisfy request\n"));
+               ListEntry = RemoveHeadList( &FCB->DatagramList );
+               DatagramRecv = CONTAINING_RECORD( ListEntry, AFD_STORED_DATAGRAM,
+                                                                                 ListEntry );
+               ListEntry = RemoveHeadList( &FCB->PendingIrpList[FUNCTION_RECV] );
+               NextIrp = CONTAINING_RECORD( ListEntry, IRP, Tail.Overlay.ListEntry );
+               NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
+               RecvReq = NextIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+
+               AFD_DbgPrint(MID_TRACE,("RecvReq: %x, DatagramRecv: %x\n",
+                                                               RecvReq, DatagramRecv));
+
+               if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
+                       !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
+                       InsertHeadList( &FCB->DatagramList,
+                                                       &DatagramRecv->ListEntry );
+                       Status = NextIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       NextIrp->IoStatus.Information = DatagramRecv->Len;
+                       UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
+            if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+                        (void)IoSetCancelRoutine(NextIrp, NULL);
+                       IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
+               } else {
+                       AFD_DbgPrint(MID_TRACE,("Satisfying\n"));
+                       Status = SatisfyPacketRecvRequest
+                               ( FCB, NextIrp, DatagramRecv,
+                                 (PUINT)&NextIrp->IoStatus.Information );
+                       AFD_DbgPrint(MID_TRACE,("Unlocking\n"));
+                       UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
+            if ( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+                       AFD_DbgPrint(MID_TRACE,("Completing\n"));
+                        (void)IoSetCancelRoutine(NextIrp, NULL);
+                       IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
+               }
     }
 
     if( !IsListEmpty( &FCB->DatagramList ) ) {
-       AFD_DbgPrint(MID_TRACE,("Signalling\n"));
-       FCB->PollState |= AFD_EVENT_RECEIVE;
+               AFD_DbgPrint(MID_TRACE,("Signalling\n"));
+               FCB->PollState |= AFD_EVENT_RECEIVE;
     } else
-       FCB->PollState &= ~AFD_EVENT_RECEIVE;
+               FCB->PollState &= ~AFD_EVENT_RECEIVE;
 
     PollReeval( FCB->DeviceExt, FCB->FileObject );
 
     if( NT_SUCCESS(Irp->IoStatus.Status) ) {
-       /* Now relaunch the datagram request */
-       SocketCalloutEnter( FCB );
-
-       Status = TdiReceiveDatagram
-           ( &FCB->ReceiveIrp.InFlightRequest,
-             FCB->AddressFile.Object,
-             0,
-             FCB->Recv.Window,
-             FCB->Recv.Size,
-             FCB->AddressFrom,
-             &FCB->ReceiveIrp.Iosb,
-             PacketSocketRecvComplete,
-             FCB );
-
-       SocketCalloutLeave( FCB );
+               /* Now relaunch the datagram request */
+               Status = TdiReceiveDatagram
+                       ( &FCB->ReceiveIrp.InFlightRequest,
+                         FCB->AddressFile.Object,
+                         0,
+                         FCB->Recv.Window,
+                         FCB->Recv.Size,
+                         FCB->AddressFrom,
+                         &FCB->ReceiveIrp.Iosb,
+                         PacketSocketRecvComplete,
+                         FCB );
     }
 
     SocketStateUnlock( FCB );
@@ -527,9 +562,9 @@ PacketSocketRecvComplete(
     return STATUS_SUCCESS;
 }
 
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 AfdPacketSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
-                       PIO_STACK_LOCATION IrpSp ) {
+                                               PIO_STACK_LOCATION IrpSp ) {
     NTSTATUS Status = STATUS_SUCCESS;
     PFILE_OBJECT FileObject = IrpSp->FileObject;
     PAFD_FCB FCB = FileObject->FsContext;
@@ -539,73 +574,78 @@ AfdPacketSocketReadData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
 
     AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
 
-    if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp, FALSE );
-
-    FCB->EventsFired &= ~AFD_EVENT_RECEIVE;
+    if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
 
     /* Check that the socket is bound */
     if( FCB->State != SOCKET_STATE_BOUND )
-       return UnlockAndMaybeComplete
-           ( FCB, STATUS_UNSUCCESSFUL, Irp, 0, NULL, FALSE );
+               return UnlockAndMaybeComplete
+                       ( FCB, STATUS_INVALID_PARAMETER, Irp, 0 );
     if( !(RecvReq = LockRequest( Irp, IrpSp )) )
-       return UnlockAndMaybeComplete
-           ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL, FALSE );
+               return UnlockAndMaybeComplete
+                       ( FCB, STATUS_NO_MEMORY, Irp, 0 );
 
     AFD_DbgPrint(MID_TRACE,("Recv flags %x\n", RecvReq->AfdFlags));
 
     RecvReq->BufferArray = LockBuffers( RecvReq->BufferArray,
-                                       RecvReq->BufferCount,
-                                       RecvReq->Address,
-                                       RecvReq->AddressLength,
-                                       TRUE, TRUE );
+                                                                               RecvReq->BufferCount,
+                                                                               RecvReq->Address,
+                                                                               RecvReq->AddressLength,
+                                                                               TRUE, TRUE );
 
     if( !RecvReq->BufferArray ) { /* access violation in userspace */
-       return UnlockAndMaybeComplete
-           ( FCB, STATUS_ACCESS_VIOLATION, Irp, 0, NULL, FALSE );
+           return UnlockAndMaybeComplete
+                       ( FCB, STATUS_ACCESS_VIOLATION, Irp, 0 );
     }
 
     if( !IsListEmpty( &FCB->DatagramList ) ) {
-       ListEntry = RemoveHeadList( &FCB->DatagramList );
-       DatagramRecv = CONTAINING_RECORD
-           ( ListEntry, AFD_STORED_DATAGRAM, ListEntry );
-       if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
-           !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
-           InsertHeadList( &FCB->DatagramList,
-                           &DatagramRecv->ListEntry );
-           Status = Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
-           Irp->IoStatus.Information = DatagramRecv->Len;
-
-           if( IsListEmpty( &FCB->DatagramList ) )
-               FCB->PollState &= ~AFD_EVENT_RECEIVE;
-           else
-               FCB->PollState |= AFD_EVENT_RECEIVE;
-
-           PollReeval( FCB->DeviceExt, FCB->FileObject );
-
-           return UnlockAndMaybeComplete
-               ( FCB, Status, Irp, RecvReq->BufferArray[0].len, NULL, TRUE );
-       } else {
-           Status = SatisfyPacketRecvRequest
-               ( FCB, Irp, DatagramRecv,
-                 (PUINT)&Irp->IoStatus.Information );
-
-           if( IsListEmpty( &FCB->DatagramList ) )
-               FCB->PollState &= ~AFD_EVENT_RECEIVE;
-           else
-               FCB->PollState |= AFD_EVENT_RECEIVE;
-
-           PollReeval( FCB->DeviceExt, FCB->FileObject );
-
-           return UnlockAndMaybeComplete
-               ( FCB, Status, Irp, Irp->IoStatus.Information, NULL, TRUE );
-       }
+               ListEntry = RemoveHeadList( &FCB->DatagramList );
+               DatagramRecv = CONTAINING_RECORD
+                       ( ListEntry, AFD_STORED_DATAGRAM, ListEntry );
+               if( DatagramRecv->Len > RecvReq->BufferArray[0].len &&
+                       !(RecvReq->TdiFlags & TDI_RECEIVE_PARTIAL) ) {
+                       InsertHeadList( &FCB->DatagramList,
+                                                       &DatagramRecv->ListEntry );
+                       Status = Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
+                       Irp->IoStatus.Information = DatagramRecv->Len;
+
+                       if( IsListEmpty( &FCB->DatagramList ) )
+                               FCB->PollState &= ~AFD_EVENT_RECEIVE;
+                       else
+                               FCB->PollState |= AFD_EVENT_RECEIVE;
+
+                       PollReeval( FCB->DeviceExt, FCB->FileObject );
+
+                       UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
+
+                       return UnlockAndMaybeComplete
+                               ( FCB, Status, Irp, Irp->IoStatus.Information );
+               } else {
+                       Status = SatisfyPacketRecvRequest
+                               ( FCB, Irp, DatagramRecv,
+                                 (PUINT)&Irp->IoStatus.Information );
+
+                       if( IsListEmpty( &FCB->DatagramList ) )
+                               FCB->PollState &= ~AFD_EVENT_RECEIVE;
+                       else
+                               FCB->PollState |= AFD_EVENT_RECEIVE;
+
+                       PollReeval( FCB->DeviceExt, FCB->FileObject );
+
+                       UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
+
+                       return UnlockAndMaybeComplete
+                               ( FCB, Status, Irp, Irp->IoStatus.Information );
+               }
     } else if( RecvReq->AfdFlags & AFD_IMMEDIATE ) {
-       AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
-       Status = STATUS_CANT_WAIT;
-       PollReeval( FCB->DeviceExt, FCB->FileObject );
-       return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL, TRUE );
+               AFD_DbgPrint(MID_TRACE,("Nonblocking\n"));
+               Status = STATUS_CANT_WAIT;
+               FCB->PollState &= ~AFD_EVENT_RECEIVE;
+               PollReeval( FCB->DeviceExt, FCB->FileObject );
+               UnlockBuffers( RecvReq->BufferArray, RecvReq->BufferCount, TRUE );
+               return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
     } else {
-       PollReeval( FCB->DeviceExt, FCB->FileObject );
-       return LeaveIrpUntilLater( FCB, Irp, FUNCTION_RECV );
+               FCB->PollState &= ~AFD_EVENT_RECEIVE;
+               PollReeval( FCB->DeviceExt, FCB->FileObject );
+               return LeaveIrpUntilLater( FCB, Irp, FUNCTION_RECV );
     }
 }