[NDIS]
[reactos.git] / reactos / drivers / network / ndis / ndis / miniport.c
index 05c750d..7a2f61e 100644 (file)
@@ -12,9 +12,6 @@
  */
 
 #include "ndissys.h"
-#include "efilter.h"
-
-#include <buffer.h>
 
 /*
  * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
@@ -248,7 +245,44 @@ MiniIndicateData(
   NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
 }
 
-\f
+/*
+ * @implemented
+ */
+VOID
+EXPORT
+NdisReturnPackets(
+    IN  PNDIS_PACKET    *PacketsToReturn,
+    IN  UINT            NumberOfPackets)
+/*
+ * FUNCTION: Releases ownership of one or more packets
+ * ARGUMENTS:
+ *     PacketsToReturn = Pointer to an array of pointers to packet descriptors
+ *     NumberOfPackets = Number of pointers in descriptor pointer array
+ */
+{
+    UINT i;
+    PLOGICAL_ADAPTER Adapter;
+    KIRQL OldIrql;
+
+    NDIS_DbgPrint(MID_TRACE, ("Returning %d packets\n", NumberOfPackets));
+
+    for (i = 0; i < NumberOfPackets; i++)
+    {
+        PacketsToReturn[i]->WrapperReserved[0]--;
+        if (PacketsToReturn[i]->WrapperReserved[0] == 0)
+        {
+            Adapter = (PVOID)(ULONG_PTR)PacketsToReturn[i]->Reserved[1];
+
+            NDIS_DbgPrint(MAX_TRACE, ("Freeing packet %d (adapter = 0x%p)\n", i, Adapter));
+
+            KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+            Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ReturnPacketHandler(
+                  Adapter->NdisMiniportBlock.MiniportAdapterContext,
+                  PacketsToReturn[i]);
+            KeLowerIrql(OldIrql);
+        }
+    }
+}\f
 VOID NTAPI
 MiniIndicateReceivePacket(
     IN  NDIS_HANDLE    MiniportAdapterHandle,
@@ -263,86 +297,139 @@ MiniIndicateReceivePacket(
  *
  */
 {
-  PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
-  PLIST_ENTRY CurrentEntry;
-  PADAPTER_BINDING AdapterBinding;
-  KIRQL OldIrql;
-  UINT i;
-
-  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
-
-  CurrentEntry = Adapter->ProtocolListHead.Flink;
-
-  while (CurrentEntry != &Adapter->ProtocolListHead)
-  {
-      AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
-
-      for (i = 0; i < NumberOfPackets; i++)
-      {
-           if (AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler &&
-               NDIS_GET_PACKET_STATUS(PacketArray[i]) != NDIS_STATUS_RESOURCES)
-           {
-              (*AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler)(
-               AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-               PacketArray[i]);
-           }
-           else
-           {
-              UINT FirstBufferLength, TotalBufferLength, LookAheadSize, HeaderSize;
-              PNDIS_BUFFER NdisBuffer;
-              PVOID NdisBufferVA, LookAheadBuffer;
-              NDIS_STATUS NdisStatus;
+    PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
+    PLIST_ENTRY CurrentEntry;
+    PADAPTER_BINDING AdapterBinding;
+    KIRQL OldIrql;
+    UINT i;
 
+    KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
 
-              NdisGetFirstBufferFromPacket(PacketArray[i],
-                                           &NdisBuffer,
-                                           &NdisBufferVA,
-                                           &FirstBufferLength,
-                                           &TotalBufferLength);
+    CurrentEntry = Adapter->ProtocolListHead.Flink;
 
-              HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
+    while (CurrentEntry != &Adapter->ProtocolListHead)
+    {
+        AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
 
-              if (Adapter->NdisMiniportBlock.CurrentLookahead < (TotalBufferLength - HeaderSize))
-              {
-                  LookAheadSize = Adapter->NdisMiniportBlock.CurrentLookahead;
-              }
-              else
-              {
-                  LookAheadSize = TotalBufferLength - HeaderSize;
-              }
+        for (i = 0; i < NumberOfPackets; i++)
+        {
+            /* Store the indicating miniport in the packet */
+            PacketArray[i]->Reserved[1] = (ULONG_PTR)Adapter;
 
+            if (AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler &&
+                NDIS_GET_PACKET_STATUS(PacketArray[i]) != NDIS_STATUS_RESOURCES)
+            {
+                NDIS_DbgPrint(MID_TRACE, ("Indicating packet to protocol's ReceivePacket handler\n"));
+                PacketArray[i]->WrapperReserved[0] += (*AdapterBinding->ProtocolBinding->Chars.ReceivePacketHandler)(
+                                                       AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+                                                       PacketArray[i]);
+                NDIS_DbgPrint(MID_TRACE, ("Protocol is holding %d references to the packet\n", PacketArray[i]->WrapperReserved[0]));
+            }
+            else
+            {
+                UINT FirstBufferLength, TotalBufferLength, LookAheadSize, HeaderSize;
+                PNDIS_BUFFER NdisBuffer;
+                PVOID NdisBufferVA, LookAheadBuffer;
+
+                NdisGetFirstBufferFromPacket(PacketArray[i],
+                                             &NdisBuffer,
+                                             &NdisBufferVA,
+                                             &FirstBufferLength,
+                                             &TotalBufferLength);
+                
+                HeaderSize = NDIS_GET_PACKET_HEADER_SIZE(PacketArray[i]);
+
+                if (Adapter->NdisMiniportBlock.CurrentLookahead < (TotalBufferLength - HeaderSize))
+                {
+                    LookAheadSize = Adapter->NdisMiniportBlock.CurrentLookahead;
+                }
+                else
+                {
+                    LookAheadSize = TotalBufferLength - HeaderSize;
+                }
 
-              LookAheadBuffer = ExAllocatePool(NonPagedPool, LookAheadSize);
-              if (!LookAheadBuffer)
-              {
-                  NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
-                  return;
-              }
+                LookAheadBuffer = ExAllocatePool(NonPagedPool, LookAheadSize);
+                if (!LookAheadBuffer)
+                {
+                    NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate lookahead buffer!\n"));
+                    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+                    return;
+                }
+                
+                CopyBufferChainToBuffer(LookAheadBuffer,
+                                        NdisBuffer,
+                                        HeaderSize,
+                                        LookAheadSize);
+                
+                NDIS_DbgPrint(MID_TRACE, ("Indicating packet to protocol's legacy Receive handler\n"));
+                (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
+                     AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
+                     AdapterBinding->NdisOpenBlock.MacHandle,
+                     NdisBufferVA,
+                     HeaderSize,
+                     LookAheadBuffer,
+                     LookAheadSize,
+                     TotalBufferLength - HeaderSize);
+                
+                ExFreePool(LookAheadBuffer);
+            }
+        }
 
-              CopyBufferChainToBuffer(LookAheadBuffer,
-                                      NdisBuffer,
-                                      HeaderSize,
-                                      LookAheadSize);
+        CurrentEntry = CurrentEntry->Flink;
+    }
 
-              NdisStatus = (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
-                            AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
-                            AdapterBinding->NdisOpenBlock.MacHandle,
-                            NdisBufferVA,
-                            HeaderSize,
-                            LookAheadBuffer,
-                            LookAheadSize,
-                            TotalBufferLength - HeaderSize);
+    /* Loop the packet array to get everything
+     * set up for return the packets to the miniport */
+    for (i = 0; i < NumberOfPackets; i++)
+    {
+        /* First, check the initial packet status */
+        if (NDIS_GET_PACKET_STATUS(PacketArray[i]) == NDIS_STATUS_RESOURCES)
+        {
+            /* The miniport driver gets it back immediately so nothing to do here */
+            NDIS_DbgPrint(MID_TRACE, ("Miniport needs the packet back immediately\n"));
+            continue;
+        }
 
-              NDIS_SET_PACKET_STATUS(PacketArray[i], NdisStatus);
+        /* Different behavior depending on whether it's serialized or not */
+        if (Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
+        {
+            /* We need to check the reference count */
+            if (PacketArray[i]->WrapperReserved[0] == 0)
+            {
+                /* NOTE: Unlike serialized miniports, this is REQUIRED to be called for each
+                 * packet received that can be reused immediately, it is not implied! */
+                Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ReturnPacketHandler(
+                      Adapter->NdisMiniportBlock.MiniportAdapterContext,
+                      PacketArray[i]);
+                NDIS_DbgPrint(MID_TRACE, ("Packet has been returned to miniport (Deserialized)\n"));
+            }
+            else
+            {
+                /* Packet will be returned by the protocol's call to NdisReturnPackets */
+                NDIS_DbgPrint(MID_TRACE, ("Packet will be returned to miniport later (Deserialized)\n"));
+            }
+        }
+        else
+        {
+            /* Check the reference count */
+            if (PacketArray[i]->WrapperReserved[0] == 0)
+            {
+                /* NDIS_STATUS_SUCCESS means the miniport can have the packet back immediately */
+                NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_SUCCESS);
 
-              ExFreePool(LookAheadBuffer);
-          }
-      }
+                NDIS_DbgPrint(MID_TRACE, ("Packet has been returned to miniport (Serialized)\n"));
+            }
+            else
+            {
+                /* NDIS_STATUS_PENDING means the miniport needs to wait for MiniportReturnPacket */
+                NDIS_SET_PACKET_STATUS(PacketArray[i], NDIS_STATUS_PENDING);
 
-      CurrentEntry = CurrentEntry->Flink;
-  }
+                NDIS_DbgPrint(MID_TRACE, ("Packet will be returned to miniport later (Serialized)\n"));
+            }
+        }
+    }
 
-  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+    KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
 }
 
 \f
@@ -365,6 +452,15 @@ MiniResetComplete(
 
     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
 
+    if (Adapter->NdisMiniportBlock.ResetStatus != NDIS_STATUS_PENDING)
+    {
+        KeBugCheckEx(BUGCODE_ID_DRIVER,
+                     (ULONG_PTR)MiniportAdapterHandle,
+                     (ULONG_PTR)Status,
+                     (ULONG_PTR)AddressingReset,
+                     0);
+    }
+
     Adapter->NdisMiniportBlock.ResetStatus = Status;
 
     CurrentEntry = Adapter->ProtocolListHead.Flink;
@@ -501,7 +597,7 @@ MiniTransferDataComplete(
     KeLowerIrql(OldIrql);
 }
 
-\f
+
 BOOLEAN
 MiniAdapterHasAddress(
     PLOGICAL_ADAPTER Adapter,
@@ -515,68 +611,67 @@ MiniAdapterHasAddress(
  *     TRUE if the destination address is that of the adapter, FALSE if not
  */
 {
-  UINT Length;
-  PUCHAR Start1;
-  PUCHAR Start2;
-  PNDIS_BUFFER NdisBuffer;
-  UINT BufferLength;
+    UINT Length;
+    PUCHAR Start1;
+    PUCHAR Start2;
+    PNDIS_BUFFER NdisBuffer;
+    UINT BufferLength;
 
-  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
 #if DBG
-  if(!Adapter)
+    if(!Adapter)
     {
-      NDIS_DbgPrint(MIN_TRACE, ("Adapter object was null\n"));
-      return FALSE;
+        NDIS_DbgPrint(MIN_TRACE, ("Adapter object was null\n"));
+        return FALSE;
     }
 
-  if(!Packet)
+    if(!Packet)
     {
-      NDIS_DbgPrint(MIN_TRACE, ("Packet was null\n"));
-      return FALSE;
+        NDIS_DbgPrint(MIN_TRACE, ("Packet was null\n"));
+        return FALSE;
     }
 #endif
 
-  NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
+    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
 
-  if (!NdisBuffer)
+    if (!NdisBuffer)
     {
-      NDIS_DbgPrint(MIN_TRACE, ("Packet contains no buffers.\n"));
-      return FALSE;
+        NDIS_DbgPrint(MIN_TRACE, ("Packet contains no buffers.\n"));
+        return FALSE;
     }
 
-  NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
+    NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
 
-  /* FIXME: Should handle fragmented packets */
+    /* FIXME: Should handle fragmented packets */
 
-  switch (Adapter->NdisMiniportBlock.MediaType)
+    switch (Adapter->NdisMiniportBlock.MediaType)
     {
-      case NdisMedium802_3:
-        Length = ETH_LENGTH_OF_ADDRESS;
-        /* Destination address is the first field */
-        break;
+        case NdisMedium802_3:
+            Length = ETH_LENGTH_OF_ADDRESS;
+            /* Destination address is the first field */
+            break;
 
-      default:
-        NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
-        return FALSE;
+        default:
+            NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
+            return FALSE;
     }
 
-  if (BufferLength < Length)
+    if (BufferLength < Length)
     {
         NDIS_DbgPrint(MIN_TRACE, ("Buffer is too small.\n"));
         return FALSE;
     }
 
-  Start1 = (PUCHAR)&Adapter->Address;
-  NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
-      *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
-      *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5))
-  );
+    Start1 = (PUCHAR)&Adapter->Address;
+    NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
+                              *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
+                              *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5)));
 
-  return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
+    return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
 }
 
-\f
+
 PLOGICAL_ADAPTER
 MiniLocateDevice(
     PNDIS_STRING AdapterName)
@@ -590,55 +685,57 @@ MiniLocateDevice(
  *     is responsible for dereferencing after use
  */
 {
-  KIRQL OldIrql;
-  PLIST_ENTRY CurrentEntry;
-  PLOGICAL_ADAPTER Adapter = 0;
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PLOGICAL_ADAPTER Adapter = 0;
 
-  ASSERT(AdapterName);
+    ASSERT(AdapterName);
 
-  NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
+    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
 
-  if(IsListEmpty(&AdapterListHead))
+    if(IsListEmpty(&AdapterListHead))
     {
-      NDIS_DbgPrint(MIN_TRACE, ("No registered miniports for protocol to bind to\n"));
-      return NULL;
+        NDIS_DbgPrint(MIN_TRACE, ("No registered miniports for protocol to bind to\n"));
+        return NULL;
     }
 
-  KeAcquireSpinLock(&AdapterListLock, &OldIrql);
-    {
-      CurrentEntry = AdapterListHead.Flink;
+    NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
 
-      while (CurrentEntry != &AdapterListHead)
+    KeAcquireSpinLock(&AdapterListLock, &OldIrql);
+    {
+        CurrentEntry = AdapterListHead.Flink;
+        
+        while (CurrentEntry != &AdapterListHead)
         {
-         Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
+            Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
 
-         ASSERT(Adapter);
+            ASSERT(Adapter);
 
-         NDIS_DbgPrint(DEBUG_MINIPORT, ("Examining adapter 0x%lx\n", Adapter));
-         NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
-         NDIS_DbgPrint(DEBUG_MINIPORT, ("DeviceName = %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
+            NDIS_DbgPrint(DEBUG_MINIPORT, ("Examining adapter 0x%lx\n", Adapter));
 
-         if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
-           {
-             break;
-           }
+            /* We're technically not allowed to call this above PASSIVE_LEVEL, but it doesn't break
+             * right now and I'd rather use a working API than reimplement it here */
+            if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
+            {
+                break;
+            }
 
-         Adapter = NULL;
-         CurrentEntry = CurrentEntry->Flink;
+            Adapter = NULL;
+            CurrentEntry = CurrentEntry->Flink;
         }
     }
-  KeReleaseSpinLock(&AdapterListLock, OldIrql);
+    KeReleaseSpinLock(&AdapterListLock, OldIrql);
 
-  if(Adapter)
+    if(Adapter)
     {
-      NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
+        NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
     }
-  else
+    else
     {
-      NDIS_DbgPrint(MIN_TRACE, ("Leaving (adapter not found for %wZ).\n", AdapterName));
+        NDIS_DbgPrint(MIN_TRACE, ("Leaving (adapter not found for %wZ).\n", AdapterName));
     }
 
-  return Adapter;
+    return Adapter;
 }
 
 NDIS_STATUS
@@ -1590,7 +1687,7 @@ NdisMRegisterAdapterShutdownHandler(
   KeInitializeCallbackRecord(BugcheckContext->CallbackRecord);
 
   KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
-      BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
+      BugcheckContext, sizeof(*BugcheckContext), (PUCHAR)"Ndis Miniport");
 
   IoRegisterShutdownNotification(Adapter->NdisMiniportBlock.DeviceObject);
 }
@@ -1722,6 +1819,20 @@ NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
   return Status;
 }
 
+NTSTATUS
+NTAPI
+NdisICreateClose(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN PIRP Irp)
+{
+  Irp->IoStatus.Status = STATUS_SUCCESS;
+  Irp->IoStatus.Information = 0;
+
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+  return STATUS_SUCCESS;
+}
+
 \f
 NTSTATUS
 NTAPI
@@ -1755,6 +1866,8 @@ NdisIPnPStartDevice(
   LARGE_INTEGER Timeout;
   UINT MaxMulticastAddresses;
   ULONG BytesWritten;
+  PLIST_ENTRY CurrentEntry;
+  PPROTOCOL_BINDING ProtocolBinding;
 
   /*
    * Prepare wrapper context used by HW and configuration routines.
@@ -1945,6 +2058,22 @@ NdisIPnPStartDevice(
     {
       NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
       ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
+      if (Adapter->NdisMiniportBlock.Interrupt)
+      {
+          KeBugCheckEx(BUGCODE_ID_DRIVER,
+                       (ULONG_PTR)Adapter,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.Interrupt,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.TimerQueue,
+                       1);
+      }
+      if (Adapter->NdisMiniportBlock.TimerQueue)
+      {
+          KeBugCheckEx(BUGCODE_ID_DRIVER,
+                       (ULONG_PTR)Adapter,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.Interrupt,
+                       (ULONG_PTR)Adapter->NdisMiniportBlock.TimerQueue,
+                       1);
+      }
       return NdisStatus;
     }
 
@@ -2017,6 +2146,17 @@ NdisIPnPStartDevice(
   /* Put adapter in adapter list for this miniport */
   ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
 
+  /* Refresh bindings for all protocols */
+  CurrentEntry = ProtocolListHead.Flink;
+  while (CurrentEntry != &ProtocolListHead)
+  {
+      ProtocolBinding = CONTAINING_RECORD(CurrentEntry, PROTOCOL_BINDING, ListEntry);
+
+      ndisBindMiniportsToProtocol(&NdisStatus, ProtocolBinding);
+
+      CurrentEntry = CurrentEntry->Flink;
+  }
+
   return STATUS_SUCCESS;
 }
 
@@ -2109,6 +2249,7 @@ NdisIDeviceIoControl(
   PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
   PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
   NDIS_STATUS Status = STATUS_NOT_SUPPORTED;
+  ULONG Written;
 
   Irp->IoStatus.Information = 0;
 
@@ -2121,7 +2262,8 @@ NdisIDeviceIoControl(
                                     *(PNDIS_OID)Irp->AssociatedIrp.SystemBuffer,
                                     Stack->Parameters.DeviceIoControl.OutputBufferLength,
                                     MmGetSystemAddressForMdl(Irp->MdlAddress),
-                                    &Irp->IoStatus.Information);
+                                    &Written);
+      Irp->IoStatus.Information = Written;
       break;
 
     default:
@@ -2163,48 +2305,54 @@ NdisIDispatchPnp(
               NDIS_DbgPrint(MIN_TRACE, ("Lower driver failed device start\n"));
         Irp->IoStatus.Status = Status;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        break;
+        return Status;
 
       case IRP_MN_STOP_DEVICE:
-        Status = NdisIForwardIrpAndWait(Adapter, Irp);
-        if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
-          {
-            Status = NdisIPnPStopDevice(DeviceObject, Irp);
-          }
-          else
-            NDIS_DbgPrint(MIN_TRACE, ("Lower driver failed device stop\n"));
-        Irp->IoStatus.Status = Status;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        Status = NdisIPnPStopDevice(DeviceObject, Irp);
+        if (!NT_SUCCESS(Status))
+            NDIS_DbgPrint(MIN_TRACE, ("WARNING: Ignoring halt device failure! Passing the IRP down anyway\n"));
+        Irp->IoStatus.Status = STATUS_SUCCESS;
         break;
 
       case IRP_MN_QUERY_REMOVE_DEVICE:
       case IRP_MN_QUERY_STOP_DEVICE:
         Status = NdisIPnPQueryStopDevice(DeviceObject, Irp);
         Irp->IoStatus.Status = Status;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+        if (Status != STATUS_SUCCESS)
+        {
+            IoCompleteRequest(Irp, IO_NO_INCREMENT);
+            NDIS_DbgPrint(MIN_TRACE, ("Failing miniport halt request\n"));
+            return Status;
+        }
         break;
 
       case IRP_MN_CANCEL_REMOVE_DEVICE:
       case IRP_MN_CANCEL_STOP_DEVICE:
-        Status = NdisIPnPCancelStopDevice(DeviceObject, Irp);
+        Status = NdisIForwardIrpAndWait(Adapter, Irp);
+        if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
+        {
+            Status = NdisIPnPCancelStopDevice(DeviceObject, Irp);
+        }
+        else
+        {
+            NDIS_DbgPrint(MIN_TRACE, ("Lower driver failed cancel stop/remove request\n"));
+        }
         Irp->IoStatus.Status = Status;
         IoCompleteRequest(Irp, IO_NO_INCREMENT);
-        break;
+        return Status;
 
       case IRP_MN_QUERY_PNP_DEVICE_STATE:
         Status = NDIS_STATUS_SUCCESS;
         Irp->IoStatus.Status = Status;
         Irp->IoStatus.Information |= Adapter->NdisMiniportBlock.PnPFlags;
-        IoCompleteRequest(Irp, IO_NO_INCREMENT);
         break;
 
       default:
-        IoSkipCurrentIrpStackLocation(Irp);
-        Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
         break;
     }
 
-  return Status;
+  IoSkipCurrentIrpStackLocation(Irp);
+  return IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
 }
 
 \f
@@ -2400,7 +2548,20 @@ NdisMRegisterMiniport(
         break;
 
       case 0x05:
-        MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
+        switch (MiniportCharacteristics->MinorNdisVersion)
+        {
+            case 0x00:
+                MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
+                break;
+                
+            case 0x01:
+                MinSize = sizeof(NDIS51_MINIPORT_CHARACTERISTICS);
+                break;
+                
+            default:
+                NDIS_DbgPrint(MIN_TRACE, ("Bad 5.x minor characteristics version.\n"));
+                return NDIS_STATUS_BAD_VERSION;
+        }
         break;
 
       default:
@@ -2478,8 +2639,6 @@ NdisMRegisterMiniport(
         }
     }
 
-  /* TODO: verify NDIS5 and NDIS5.1 */
-
   RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
 
   /*
@@ -2497,6 +2656,8 @@ NdisMRegisterMiniport(
 
   *MiniportPtr = Miniport;
 
+  Miniport->DriverObject->MajorFunction[IRP_MJ_CREATE] = NdisICreateClose;
+  Miniport->DriverObject->MajorFunction[IRP_MJ_CLOSE] = NdisICreateClose;
   Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
   Miniport->DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = NdisIShutdown;
   Miniport->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisIDeviceIoControl;
@@ -2632,8 +2793,9 @@ NdisMSetAttributesEx(
   if (CheckForHangTimeInSeconds > 0)
       Adapter->NdisMiniportBlock.CheckForHangSeconds = CheckForHangTimeInSeconds;
   if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
-    NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
+    NDIS_DbgPrint(MIN_TRACE, ("Intermediate drivers not supported yet.\n"));
 
+  NDIS_DbgPrint(MIN_TRACE, ("Miniport attribute flags: 0x%x\n", AttributeFlags));
 
   if (Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.AdapterShutdownHandler)
   {
@@ -2958,6 +3120,12 @@ NdisMRegisterDevice(
 
     DriverBlock->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
 
+    if (!DriverBlock->DriverObject->MajorFunction[IRP_MJ_CREATE])
+        DriverBlock->DriverObject->MajorFunction[IRP_MJ_CREATE] = NdisICreateClose;
+
+    if (!DriverBlock->DriverObject->MajorFunction[IRP_MJ_CLOSE])
+        DriverBlock->DriverObject->MajorFunction[IRP_MJ_CLOSE] = NdisICreateClose;
+
     DeviceBlock->DeviceObject = DeviceObject;
     DeviceBlock->SymbolicName = SymbolicName;