[NDISUIO]
[reactos.git] / drivers / network / ndisuio / ioctl.c
index df3a638..774c20d 100644 (file)
@@ -8,9 +8,104 @@
 
 #include "ndisuio.h"
 
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
+static
+NTSTATUS
+WaitForBind(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+    /* I've seen several code samples that use this IOCTL but there's
+     * no official documentation on it. I'm just implementing it as a no-op
+     * right now because I don't see any reason we need it. We handle an open
+     * and bind just fine with IRP_MJ_CREATE and IOCTL_NDISUIO_OPEN_DEVICE */
+    DPRINT("Wait for bind complete\n");
+    
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+    
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    
+    return STATUS_SUCCESS;
+}
+
+static
+NTSTATUS
+QueryBinding(PIRP Irp, PIO_STACK_LOCATION IrpSp)
+{
+    PNDISUIO_ADAPTER_CONTEXT AdapterContext = NULL;
+    PNDISUIO_QUERY_BINDING QueryBinding = Irp->AssociatedIrp.SystemBuffer;
+    ULONG BindingLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+    NTSTATUS Status;
+    PLIST_ENTRY CurrentEntry;
+    KIRQL OldIrql;
+    ULONG i;
+    ULONG BytesCopied = 0;
+
+    if (QueryBinding && BindingLength >= sizeof(NDISUIO_QUERY_BINDING))
+    {
+        KeAcquireSpinLock(&GlobalAdapterListLock, &OldIrql);
+        i = 0;
+        CurrentEntry = GlobalAdapterList.Flink;
+        while (CurrentEntry != &GlobalAdapterList)
+        {
+            if (i == QueryBinding->BindingIndex)
+            {
+                AdapterContext = CONTAINING_RECORD(CurrentEntry, NDISUIO_ADAPTER_CONTEXT, ListEntry);
+                break;
+            }
+            i++;
+            CurrentEntry = CurrentEntry->Flink;
+        }
+        KeReleaseSpinLock(&GlobalAdapterListLock, OldIrql);
+        if (AdapterContext)
+        {
+            DPRINT("Query binding for index %d is adapter %wZ\n", i, &AdapterContext->DeviceName);
+            BytesCopied = sizeof(NDISUIO_QUERY_BINDING);
+            if (AdapterContext->DeviceName.Length <= BindingLength - BytesCopied)
+            {
+                QueryBinding->DeviceNameOffset = BytesCopied;
+                QueryBinding->DeviceNameLength = AdapterContext->DeviceName.Length;
+                RtlCopyMemory((PUCHAR)QueryBinding + QueryBinding->DeviceNameOffset,
+                              AdapterContext->DeviceName.Buffer,
+                              QueryBinding->DeviceNameLength);
+                BytesCopied += AdapterContext->DeviceName.Length;
+
+                /* FIXME: Copy description too */
+                QueryBinding->DeviceDescrOffset = BytesCopied;
+                QueryBinding->DeviceDescrLength = 0;
+                
+                /* Successful */
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                /* Not enough buffer space */
+                Status = STATUS_BUFFER_TOO_SMALL;
+            }
+        }
+        else
+        {
+            /* Invalid index */
+            Status = STATUS_NO_MORE_ENTRIES;
+        }
+    }
+    else
+    {
+        /* Invalid parameters */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+    
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = BytesCopied;
+    
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    
+    return Status;
+}
+
+#if 0
+static
 NTSTATUS
 CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
 {
@@ -24,7 +119,7 @@ CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     {
         PacketEntry->PacketLength = 0;
         
-        ExInterlockedInsertTailList(&AdapterContext->PacketList,
+        ExInterlockedInsertHeadList(&AdapterContext->PacketList,
                                     &PacketEntry->ListEntry,
                                     &AdapterContext->Spinlock);
         
@@ -44,32 +139,36 @@ CancelPacketRead(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     
     return Status;
 }
+#endif
 
+static
 NTSTATUS
 SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
 {
     PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
     PNDISUIO_SET_OID SetOidRequest;
-    NDIS_REQUEST NdisRequest;
+    NDIS_REQUEST Request;
     ULONG RequestLength;
     NDIS_STATUS Status;
     
     Irp->IoStatus.Information = 0;
     
-    SetOidRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    SetOidRequest = Irp->AssociatedIrp.SystemBuffer;
     RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
-    if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
+    if (SetOidRequest && RequestLength >= sizeof(NDIS_OID))
     {
         /* Setup the NDIS request */
-        NdisRequest.RequestType = NdisRequestSetInformation;
-        NdisRequest.Oid = SetOidRequest->Oid;
-        NdisRequest.InformationBuffer = SetOidRequest->Data;
-        NdisRequest.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+        Request.RequestType = NdisRequestSetInformation;
+        Request.DATA.SET_INFORMATION.Oid = SetOidRequest->Oid;
+        Request.DATA.SET_INFORMATION.InformationBuffer = SetOidRequest->Data;
+        Request.DATA.SET_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+
+        DPRINT("Setting OID 0x%x on adapter %wZ\n", SetOidRequest->Oid, &AdapterContext->DeviceName);
 
         /* Dispatch the request */
         NdisRequest(&Status,
                     AdapterContext->BindingHandle,
-                    &NdisRequest);
+                    &Request);
 
         /* Wait for the request */
         if (Status == NDIS_STATUS_PENDING)
@@ -83,7 +182,7 @@ SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
         }
 
         /* Return the bytes read */
-        if (NT_SUCCESS(Status)) Irp->IoStatus.Information = NdisRequest.BytesRead;
+        if (NT_SUCCESS(Status)) Irp->IoStatus.Information = Request.DATA.SET_INFORMATION.BytesRead;
     }
     else
     {
@@ -98,31 +197,34 @@ SetAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     return Status;
 }
 
+static
 NTSTATUS
 QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
 {
     PNDISUIO_ADAPTER_CONTEXT AdapterContext = IrpSp->FileObject->FsContext;
     PNDISUIO_QUERY_OID QueryOidRequest;
-    NDIS_REQUEST NdisRequest;
+    NDIS_REQUEST Request;
     ULONG RequestLength;
     NDIS_STATUS Status;
 
     Irp->IoStatus.Information = 0;
 
-    QueryOidRequest = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+    QueryOidRequest = Irp->AssociatedIrp.SystemBuffer;
     RequestLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
     if (QueryOidRequest && RequestLength >= sizeof(NDIS_OID))
     {
         /* Setup the NDIS request */
-        NdisRequest.RequestType = NdisRequestQueryInformation;
-        NdisRequest.Oid = QueryOidRequest->Oid;
-        NdisRequest.InformationBuffer = QueryOidRequest->Data;
-        NdisRequest.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+        Request.RequestType = NdisRequestQueryInformation;
+        Request.DATA.QUERY_INFORMATION.Oid = QueryOidRequest->Oid;
+        Request.DATA.QUERY_INFORMATION.InformationBuffer = QueryOidRequest->Data;
+        Request.DATA.QUERY_INFORMATION.InformationBufferLength = RequestLength - sizeof(NDIS_OID);
+        
+        DPRINT("Querying OID 0x%x on adapter %wZ\n", QueryOidRequest->Oid, &AdapterContext->DeviceName);
         
         /* Dispatch the request */
         NdisRequest(&Status,
                     AdapterContext->BindingHandle,
-                    &NdisRequest);
+                    &Request);
         
         /* Wait for the request */
         if (Status == NDIS_STATUS_PENDING)
@@ -136,7 +238,7 @@ QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
         }
 
         /* Return the bytes written */
-        if (NT_SUCCESS(Status)) Irp->IoStatus.Information = NdisRequest.BytesWritten;
+        if (NT_SUCCESS(Status)) Irp->IoStatus.Information = Request.DATA.QUERY_INFORMATION.BytesWritten;
     }
     else
     {
@@ -151,6 +253,7 @@ QueryAdapterOid(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     return Status;
 }
 
+static
 NTSTATUS
 OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
 {
@@ -166,16 +269,29 @@ OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     if (NameLength != 0)
     {
         DeviceName.MaximumLength = DeviceName.Length = NameLength;
-        DeviceName.Buffer = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+        DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
 
         /* Check if this already has a context */
         AdapterContext = FindAdapterContextByName(&DeviceName);
         if (AdapterContext != NULL)
         {
+            DPRINT("Binding file object 0x%x to device %wZ\n", FileObject, &AdapterContext->DeviceName);
+
             /* Reference the adapter context */
             KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
-            ReferenceAdapterContext(AdapterContext);
-            Status = STATUS_SUCCESS;
+            if (AdapterContext->OpenCount != 0)
+            {
+                /* An open for read-write is exclusive,
+                 * so we can't have any other open handles */
+                KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+                Status = STATUS_INVALID_PARAMETER;
+            }
+            else
+            {
+                /* Add a reference */
+                ReferenceAdapterContext(AdapterContext);
+                Status = STATUS_SUCCESS;
+            }
         }
         else
         {
@@ -191,6 +307,9 @@ OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
             {
                 /* Set the file object pointer */
                 OpenEntry->FileObject = FileObject;
+                
+                /* Set the permissions */
+                OpenEntry->WriteOnly = FALSE;
 
                 /* Associate this FO with the adapter */
                 FileObject->FsContext = AdapterContext;
@@ -208,7 +327,7 @@ OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
             {
                 /* Remove the reference we added */
                 KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
-                DereferenceAdapterContext(AdapterContext, NULL);
+                DereferenceAdapterContextWithOpenEntry(AdapterContext, NULL);
                 Status = STATUS_NO_MEMORY;
             }
         }
@@ -227,12 +346,87 @@ OpenDeviceReadWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
     return Status;
 }
 
+#if 0
+static
 NTSTATUS
 OpenDeviceWrite(PIRP Irp, PIO_STACK_LOCATION IrpSp)
 {
-    /* FIXME: Handle this correctly */
-    return OpenDeviceReadWrite(Irp, IrpSp);
+    PFILE_OBJECT FileObject = IrpSp->FileObject;
+    UNICODE_STRING DeviceName;
+    ULONG NameLength;
+    NTSTATUS Status;
+    PNDISUIO_ADAPTER_CONTEXT AdapterContext;
+    PNDISUIO_OPEN_ENTRY OpenEntry;
+    KIRQL OldIrql;
+    
+    NameLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+    if (NameLength != 0)
+    {
+        DeviceName.MaximumLength = DeviceName.Length = NameLength;
+        DeviceName.Buffer = Irp->AssociatedIrp.SystemBuffer;
+        
+        /* Check if this already has a context */
+        AdapterContext = FindAdapterContextByName(&DeviceName);
+        if (AdapterContext != NULL)
+        {
+            /* Reference the adapter context */
+            KeAcquireSpinLock(&AdapterContext->Spinlock, &OldIrql);
+            ReferenceAdapterContext(AdapterContext);
+            Status = STATUS_SUCCESS;
+        }
+        else
+        {
+            /* Invalid device name */
+            Status = STATUS_INVALID_PARAMETER;
+        }
+        
+        /* Check that the bind succeeded */
+        if (NT_SUCCESS(Status))
+        {
+            OpenEntry = ExAllocatePool(NonPagedPool, sizeof(*OpenEntry));
+            if (OpenEntry)
+            {
+                /* Set the file object pointer */
+                OpenEntry->FileObject = FileObject;
+                
+                /* Associate this FO with the adapter */
+                FileObject->FsContext = AdapterContext;
+                FileObject->FsContext2 = OpenEntry;
+                
+                /* Set permissions */
+                OpenEntry->WriteOnly = TRUE;
+                
+                /* Add it to the adapter's list */
+                InsertTailList(&AdapterContext->OpenEntryList,
+                               &OpenEntry->ListEntry);
+                
+                /* Success */
+                KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+                Status = STATUS_SUCCESS;
+            }
+            else
+            {
+                /* Remove the reference we added */
+                KeReleaseSpinLock(&AdapterContext->Spinlock, OldIrql);
+                DereferenceAdapterContext(AdapterContext, NULL);
+                Status = STATUS_NO_MEMORY;
+            }
+        }
+    }
+    else
+    {
+        /* Invalid device name */
+        Status = STATUS_INVALID_PARAMETER;
+    }
+    
+    Irp->IoStatus.Status = Status;
+    Irp->IoStatus.Information = 0;
+    
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    
+    return Status;
 }
+#endif
 
 NTSTATUS
 NTAPI
@@ -240,6 +434,7 @@ NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
                          PIRP Irp)
 {
     PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    PNDISUIO_OPEN_ENTRY OpenEntry;
     
     ASSERT(DeviceObject == GlobalDeviceObject);
 
@@ -248,9 +443,15 @@ NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
     {
         case IOCTL_NDISUIO_OPEN_DEVICE:
             return OpenDeviceReadWrite(Irp, IrpSp);
-
+#if 0
         case IOCTL_NDISUIO_OPEN_WRITE_DEVICE:
             return OpenDeviceWrite(Irp, IrpSp);
+#endif
+        case IOCTL_NDISUIO_BIND_WAIT:
+            return WaitForBind(Irp, IrpSp);
+            
+        case IOCTL_NDISUIO_QUERY_BINDING:
+            return QueryBinding(Irp, IrpSp);
 
         default:
             /* Fail if this file object has no adapter associated */
@@ -263,24 +464,41 @@ NduDispatchDeviceControl(PDEVICE_OBJECT DeviceObject,
                 return STATUS_INVALID_PARAMETER;
             }
 
-            /* Now handle other IOCTLs */
+            /* Now handle write IOCTLs */
             switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
             {
-                case IOCTL_CANCEL_READ:
-                    return CancelPacketRead(Irp, IrpSp);
-
-                case IOCTL_NDISUIO_QUERY_OID_VALUE:
-                    return QueryAdapterOid(Irp, IrpSp);
-
                 case IOCTL_NDISUIO_SET_OID_VALUE:
                     return SetAdapterOid(Irp, IrpSp);
 
                 default:
-                    DPRINT1("Unimplemented\n");
-                    Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
-                    Irp->IoStatus.Information = 0;
-                    IoCompleteRequest(Irp, IO_NO_INCREMENT);
-                    break;
+                    /* Check that we have read permissions */
+                    OpenEntry = IrpSp->FileObject->FsContext2;
+                    if (OpenEntry->WriteOnly)
+                    {
+                        Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
+                        Irp->IoStatus.Information = 0;
+                        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                        
+                        return STATUS_INVALID_PARAMETER;
+                    }
+
+                    switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
+                    {
+#if 0
+                        case IOCTL_CANCEL_READ:
+                            return CancelPacketRead(Irp, IrpSp);
+#endif
+                        
+                        case IOCTL_NDISUIO_QUERY_OID_VALUE:
+                            return QueryAdapterOid(Irp, IrpSp);
+                        
+                        default:
+                            DPRINT1("Unimplemented\n");
+                            Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
+                            Irp->IoStatus.Information = 0;
+                            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+                            return STATUS_NOT_IMPLEMENTED;
+                    }
             }
             break;
     }