sync with trunk r46493
[reactos.git] / drivers / network / afd / afd / connect.c
index 77d9f0a..3f47a05 100644 (file)
 #include "tdiconn.h"
 #include "debug.h"
 
+NTSTATUS NTAPI
+AfdGetConnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                 PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (FCB->ConnectOptionsSize == 0)
+        return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
+
+    ASSERT(FCB->ConnectOptions);
+
+    if (FCB->FilledConnectOptions < BufferSize) BufferSize = FCB->FilledConnectOptions;
+
+    RtlCopyMemory(Irp->UserBuffer,
+                  FCB->ConnectOptions,
+                  BufferSize);
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
+}
+
+NTSTATUS
+NTAPI
+AfdSetConnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                  PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    PVOID ConnectOptions = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    UINT ConnectOptionsSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (FCB->ConnectOptions)
+    {
+        ExFreePool(FCB->ConnectOptions);
+        FCB->ConnectOptions = NULL;
+        FCB->ConnectOptionsSize = 0;
+        FCB->FilledConnectOptions = 0;
+    }
+
+    FCB->ConnectOptions = ExAllocatePool(PagedPool, ConnectOptionsSize);
+    if (!FCB->ConnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+    RtlCopyMemory(FCB->ConnectOptions,
+                  ConnectOptions,
+                  ConnectOptionsSize);
+
+    FCB->ConnectOptionsSize = ConnectOptionsSize;
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS
+NTAPI
+AfdSetConnectOptionsSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                      PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    PUINT ConnectOptionsSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (BufferSize < sizeof(UINT))
+        return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
+
+    if (FCB->ConnectOptions)
+    {
+        ExFreePool(FCB->ConnectOptions);
+        FCB->ConnectOptionsSize = 0;
+        FCB->FilledConnectOptions = 0;
+    }
+
+    FCB->ConnectOptions = ExAllocatePool(PagedPool, *ConnectOptionsSize);
+    if (!FCB->ConnectOptions) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+    FCB->ConnectOptionsSize = *ConnectOptionsSize;
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS NTAPI
+AfdGetConnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                 PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    UINT BufferSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (FCB->ConnectDataSize == 0)
+        return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
+
+    ASSERT(FCB->ConnectData);
+
+    if (FCB->FilledConnectData < BufferSize) BufferSize = FCB->FilledConnectData;
+
+    RtlCopyMemory(Irp->UserBuffer,
+                  FCB->ConnectData,
+                  BufferSize);
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, BufferSize);
+}
+
+NTSTATUS
+NTAPI
+AfdSetConnectData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                  PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    PVOID ConnectData = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    UINT ConnectDataSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (FCB->ConnectData)
+    {
+        ExFreePool(FCB->ConnectData);
+        FCB->ConnectData = NULL;
+        FCB->ConnectDataSize = 0;
+        FCB->FilledConnectData = 0;
+    }
+
+    FCB->ConnectData = ExAllocatePool(PagedPool, ConnectDataSize);
+    if (!FCB->ConnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+    RtlCopyMemory(FCB->ConnectData,
+                  ConnectData,
+                  ConnectDataSize);
+
+    FCB->ConnectDataSize = ConnectDataSize;
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+NTSTATUS
+NTAPI
+AfdSetConnectDataSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
+                      PIO_STACK_LOCATION IrpSp)
+{
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    PAFD_FCB FCB = FileObject->FsContext;
+    PUINT ConnectDataSize = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    UINT BufferSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+
+    if (!SocketAcquireStateLock(FCB)) return LostSocket(Irp);
+
+    if (BufferSize < sizeof(UINT))
+        return UnlockAndMaybeComplete(FCB, STATUS_BUFFER_TOO_SMALL, Irp, 0);
+
+    if (FCB->ConnectData)
+    {
+        ExFreePool(FCB->ConnectData);
+        FCB->ConnectDataSize = 0;
+        FCB->FilledConnectData = 0;
+    }
+
+    FCB->ConnectData = ExAllocatePool(PagedPool, *ConnectDataSize);
+    if (!FCB->ConnectData) return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
+
+    FCB->ConnectDataSize = *ConnectDataSize;
+
+    return UnlockAndMaybeComplete(FCB, STATUS_SUCCESS, Irp, 0);
+}
+
+
 NTSTATUS WarmSocketForConnection( PAFD_FCB FCB ) {
     NTSTATUS Status;
 
@@ -35,32 +208,48 @@ NTSTATUS WarmSocketForConnection( PAFD_FCB FCB ) {
 NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB ) {
     NTSTATUS Status;
 
+    ASSERT(!FCB->Recv.Window);
+    ASSERT(!FCB->Send.Window);
+
+    Status = TdiQueryMaxDatagramLength(FCB->Connection.Object,
+                                       &FCB->Send.Size);
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    FCB->Recv.Size = FCB->Send.Size;
+
     /* Allocate the receive area and start receiving */
     FCB->Recv.Window =
-       ExAllocatePool( NonPagedPool, FCB->Recv.Size );
+       ExAllocatePool( PagedPool, FCB->Recv.Size );
 
     if( !FCB->Recv.Window ) return STATUS_NO_MEMORY;
 
     FCB->Send.Window =
-       ExAllocatePool( NonPagedPool, FCB->Send.Size );
+       ExAllocatePool( PagedPool, FCB->Send.Size );
 
     if( !FCB->Send.Window ) {
-       ExFreePool( FCB->Recv.Window ); 
+       ExFreePool( FCB->Recv.Window );
+       FCB->Recv.Window = NULL;
        return STATUS_NO_MEMORY;
     }
 
     FCB->State = SOCKET_STATE_CONNECTED;
 
     Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
-                        FCB->Connection.Object,
-                        TDI_RECEIVE_NORMAL,
-                        FCB->Recv.Window,
-                        FCB->Recv.Size,
-                        &FCB->ReceiveIrp.Iosb,
-                        ReceiveComplete,
-                        FCB );
+                        FCB->Connection.Object,
+                        TDI_RECEIVE_NORMAL,
+                        FCB->Recv.Window,
+                        FCB->Recv.Size,
+                        &FCB->ReceiveIrp.Iosb,
+                        ReceiveComplete,
+                        FCB );
 
-    return Status;
+   if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
+
+   FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
+   PollReeval( FCB->DeviceExt, FCB->FileObject );
+
+   return Status;
 }
 
 static NTSTATUS NTAPI StreamSocketConnectComplete
@@ -77,21 +266,34 @@ static NTSTATUS NTAPI StreamSocketConnectComplete
 
     /* I was wrong about this before as we can have pending writes to a not
      * yet connected socket */
-    if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
+    if( !SocketAcquireStateLock( FCB ) )
+        return STATUS_FILE_CLOSED;
 
     AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
                            Irp->IoStatus.Status));
 
-    if( NT_SUCCESS(Irp->IoStatus.Status) ) {
-       FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
-       FCB->State = SOCKET_STATE_CONNECTED;
-       AFD_DbgPrint(MID_TRACE,("Going to connected state %d\n", FCB->State));
-       PollReeval( FCB->DeviceExt, FCB->FileObject );
-    } else {
-       FCB->PollState |= AFD_EVENT_CONNECT_FAIL | AFD_EVENT_RECEIVE;
+    FCB->ConnectIrp.InFlightRequest = NULL;
+
+    if( FCB->State == SOCKET_STATE_CLOSED ) {
+        /* Cleanup our IRP queue because the FCB is being destroyed */
+        while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
+              NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
+              NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
+              NextIrp->IoStatus.Status = STATUS_FILE_CLOSED;
+              NextIrp->IoStatus.Information = 0;
+              if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+               (void)IoSetCancelRoutine(NextIrp, NULL);
+              IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
+        }
+       SocketStateUnlock( FCB );
+       return STATUS_FILE_CLOSED;
+    }
+
+    if( !NT_SUCCESS(Irp->IoStatus.Status) ) {
+       FCB->PollState |= AFD_EVENT_CONNECT_FAIL;
        AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
        FCB->State = SOCKET_STATE_BOUND;
-       PollReeval( FCB->DeviceExt, FCB->FileObject );
+        PollReeval( FCB->DeviceExt, FCB->FileObject );
     }
 
     /* Succeed pending irps on the FUNCTION_CONNECT list */
@@ -100,15 +302,35 @@ static NTSTATUS NTAPI StreamSocketConnectComplete
        NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
        AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
        NextIrp->IoStatus.Status = Status;
-       NextIrp->IoStatus.Information = 0;
+       NextIrp->IoStatus.Information = NT_SUCCESS(Status) ? ((ULONG_PTR)FCB->Connection.Handle) : 0;
        if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
+        (void)IoSetCancelRoutine(NextIrp, NULL);
        IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
     }
 
     if( NT_SUCCESS(Status) ) {
        Status = MakeSocketIntoConnection( FCB );
 
-       if( !NT_SUCCESS(Status) ) return Status;
+       if( !NT_SUCCESS(Status) ) {
+           SocketStateUnlock( FCB );
+           return Status;
+       }
+
+        FCB->FilledConnectData = MIN(FCB->ConnectInfo->UserDataLength, FCB->ConnectDataSize);
+        if (FCB->FilledConnectData)
+        {
+            RtlCopyMemory(FCB->ConnectData,
+                          FCB->ConnectInfo->UserData,
+                          FCB->FilledConnectData);
+        }
+
+        FCB->FilledConnectOptions = MIN(FCB->ConnectInfo->OptionsLength, FCB->ConnectOptionsSize);
+        if (FCB->FilledConnectOptions)
+        {
+            RtlCopyMemory(FCB->ConnectOptions,
+                          FCB->ConnectInfo->Options,
+                          FCB->FilledConnectOptions);
+        }
 
        if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
            NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
@@ -135,20 +357,20 @@ static NTSTATUS NTAPI StreamSocketConnectComplete
 
 /* Return the socket object for ths request only if it is a connected or
    stream type. */
-NTSTATUS STDCALL
+NTSTATUS NTAPI
 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
                       PIO_STACK_LOCATION IrpSp) {
     NTSTATUS Status = STATUS_INVALID_PARAMETER;
-    PTDI_CONNECTION_INFORMATION TargetAddress;
     PFILE_OBJECT FileObject = IrpSp->FileObject;
     PAFD_FCB FCB = FileObject->FsContext;
     PAFD_CONNECT_INFO ConnectReq;
+    PTDI_CONNECTION_INFORMATION TargetAddress;
     AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
 
     if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
     if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
        return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
-                                      0, NULL );
+                                      0 );
 
     AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
 #if 0
@@ -157,6 +379,20 @@ AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
          IrpSp->Parameters.DeviceIoControl.InputBufferLength );
 #endif
 
+   if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
+   {
+       if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
+       FCB->RemoteAddress =
+           TaCopyTransportAddress( &ConnectReq->RemoteAddress );
+
+       if( !FCB->RemoteAddress )
+           Status = STATUS_NO_MEMORY;
+       else
+           Status = STATUS_SUCCESS;
+
+       return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
+   }
+
     switch( FCB->State ) {
     case SOCKET_STATE_CONNECTED:
        Status = STATUS_SUCCESS;
@@ -166,39 +402,30 @@ AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
        return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
 
     case SOCKET_STATE_CREATED:
+       if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
        FCB->LocalAddress =
            TaCopyTransportAddress( &ConnectReq->RemoteAddress );
 
        if( FCB->LocalAddress ) {
-           RtlZeroMemory( FCB->LocalAddress,
-                          TaLengthOfTransportAddress
-                          ( &ConnectReq->RemoteAddress ) );
-
-           FCB->LocalAddress->TAAddressCount = 1;
-           FCB->LocalAddress->Address[0].AddressType =
-               ConnectReq->RemoteAddress.Address[0].AddressType;
-           FCB->LocalAddress->Address[0].AddressLength =
-               ConnectReq->RemoteAddress.Address[0].AddressLength;
-
            Status = WarmSocketForBind( FCB );
 
            if( NT_SUCCESS(Status) )
                FCB->State = SOCKET_STATE_BOUND;
            else
-               return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL );
+               return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
        } else
            return UnlockAndMaybeComplete
-               ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL );
+               ( FCB, STATUS_NO_MEMORY, Irp, 0 );
     
     /* Drop through to SOCKET_STATE_BOUND */
 
     case SOCKET_STATE_BOUND:
+       if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
        FCB->RemoteAddress =
            TaCopyTransportAddress( &ConnectReq->RemoteAddress );
 
-       if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
-       {
-           Status = STATUS_SUCCESS;
+       if( !FCB->RemoteAddress ) {
+           Status = STATUS_NO_MEMORY;
            break;
        }
 
@@ -207,27 +434,39 @@ AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
        if( !NT_SUCCESS(Status) )
            break;
 
-       FCB->State = SOCKET_STATE_CONNECTING;
-
-       TdiBuildConnectionInfo
-           ( &TargetAddress,
+       Status = TdiBuildConnectionInfo
+           ( &FCB->ConnectInfo,
              &ConnectReq->RemoteAddress );
 
-       if( TargetAddress ) {
+        if( NT_SUCCESS(Status) )
+            Status = TdiBuildConnectionInfo(&TargetAddress,
+                                           &ConnectReq->RemoteAddress);
+        else break;
+
+
+       if( NT_SUCCESS(Status) ) {
+            TargetAddress->UserData = FCB->ConnectData;
+            TargetAddress->UserDataLength = FCB->ConnectDataSize;
+            TargetAddress->Options = FCB->ConnectOptions;
+            TargetAddress->OptionsLength = FCB->ConnectOptionsSize;
+
            Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
                                 FCB->Connection.Object,
                                 TargetAddress,
+                                FCB->ConnectInfo,
                                 &FCB->ConnectIrp.Iosb,
                                 StreamSocketConnectComplete,
                                 FCB );
 
-           ExFreePool( TargetAddress );
+            ExFreePool(TargetAddress);
 
            AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
 
-           if( Status == STATUS_PENDING )
+           if( Status == STATUS_PENDING ) {
+                FCB->State = SOCKET_STATE_CONNECTING;
                return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
-       } else Status = STATUS_NO_MEMORY;
+            }
+       }
        break;
 
     default:
@@ -236,5 +475,5 @@ AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
        break;
     }
 
-    return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL );
+    return UnlockAndMaybeComplete( FCB, Status, Irp, 0 );
 }