- Merge aicom-network-fixes up to r36740
[reactos.git] / reactos / drivers / network / ndis / ndis / protocol.c
index 1891b66..f487402 100644 (file)
@@ -43,6 +43,8 @@ NdisCompleteBindAdapter(
 {
   PROTOCOL_BINDING *Protocol = (PROTOCOL_BINDING *)BindAdapterContext;
 
+  if (!NT_SUCCESS(Status)) return;
+
   /* Put protocol binding struct on global list */
   ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
 }
@@ -63,9 +65,9 @@ ProIndicatePacket(
  *     - XXX ATM, this only handles loopback packets - is that its designed function?
  */
 {
-  KIRQL OldIrql;
   UINT BufferedLength;
   UINT PacketLength;
+  KIRQL OldIrql;
 
   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
@@ -120,8 +122,6 @@ ProRequest(
  */
 {
   KIRQL OldIrql;
-  BOOLEAN QueueWorkItem = FALSE;
-  NDIS_STATUS NdisStatus;
   PADAPTER_BINDING AdapterBinding;
   PLOGICAL_ADAPTER Adapter;
   PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)NdisRequest->MacReserved;
@@ -142,45 +142,15 @@ ProRequest(
   NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
   KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
     {
-      if(Adapter->MiniportBusy)
-        QueueWorkItem = TRUE;
-      else
-        {
-          NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to busy\n"));
-          Adapter->MiniportBusy = TRUE;
-        }
-    }
-
-  /* MiniQueueWorkItem must be called at IRQL >= DISPATCH_LEVEL */
-  if (QueueWorkItem)
-    {
-      MiniQueueWorkItem(Adapter, NdisWorkItemRequest, (PVOID)NdisRequest);
-      KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
-      return NDIS_STATUS_PENDING;
+      if (Adapter->MiniportBusy) {
+          MiniQueueWorkItem(Adapter, NdisWorkItemRequest, (PVOID)NdisRequest);
+          KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
+          return NDIS_STATUS_PENDING;
+      }
     }
-
   KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
 
-  /* MiniportQueryInformation (called by MiniDoRequest) runs at DISPATCH_LEVEL */
-  /* TODO (?): move the irql raise into MiniDoRequest */
-  KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
-    {
-      NdisStatus = MiniDoRequest(&Adapter->NdisMiniportBlock, NdisRequest);
-
-      NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
-      KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
-        {
-          NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to free\n"));
-          Adapter->MiniportBusy = FALSE;
-
-          if (Adapter->WorkQueueHead)
-            KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
-        }
-      KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
-    }
-  KeLowerIrql(OldIrql);
-
-  return NdisStatus;
+  return MiniDoRequest(Adapter, NdisRequest);
 }
 
 \f
@@ -204,21 +174,17 @@ ProSend(
  *     MacBindingHandle = Adapter binding handle
  *     Packet           = Pointer to NDIS packet descriptor
  * RETURNS:
- *     NDIS_STATUS_SUCCESS always
+ *     NDIS_STATUS_SUCCESS if the packet was successfully sent
+ *     NDIS_STATUS_PENDING if the miniport was busy or a serialized miniport returned NDIS_STATUS_RESOURCES
  * NOTES:
  * TODO:
- *     - Fix return values
- *     - Should queue packet if miniport returns NDIS_STATUS_RESOURCES
- *     - Queue packets directly on the adapters when possible (i.e.
- *       when miniports not busy)
  *     - Break this up
  */
 {
-  KIRQL RaiseOldIrql, SpinOldIrql;
-  BOOLEAN QueueWorkItem = FALSE;
-  NDIS_STATUS NdisStatus;
+  KIRQL SpinOldIrql, RaiseOldIrql;
   PADAPTER_BINDING AdapterBinding;
   PLOGICAL_ADAPTER Adapter;
+  NDIS_STATUS NdisStatus;
 
   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
@@ -236,30 +202,6 @@ ProSend(
   /* XXX what is this crazy black magic? */
   Packet->Reserved[0] = (ULONG_PTR)MacBindingHandle;
 
-  /*
-   * Acquire this lock in order to see if the miniport is busy.
-   * If it is not busy, we mark it as busy and release the lock.
-   * Else we don't do anything because we have to queue a workitem
-   * anyway.
-   */
-  NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
-  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
-    {
-      /*
-       * if the miniport is marked as busy, we queue the packet as a work item,
-       * else we send the packet directly to the miniport.  Sending to the miniport
-       * makes it busy.
-       */
-      if (Adapter->MiniportBusy)
-        QueueWorkItem = TRUE;
-      else
-        {
-          NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to busy\n"));
-          Adapter->MiniportBusy = TRUE;
-        }
-    }
-  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
-
   /*
    * Test the packet to see if it is a MAC loopback.
    *
@@ -267,127 +209,84 @@ ProSend(
    * If dest MAC address of packet == MAC address of adapter,
    * this is a loopback frame.
    */
+
+  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
+
   if ((Adapter->NdisMiniportBlock.MacOptions & NDIS_MAC_OPTION_NO_LOOPBACK) &&
       MiniAdapterHasAddress(Adapter, Packet))
     {
-      NDIS_DbgPrint(MIN_TRACE, ("Looping packet.\n"));
-
-      if (QueueWorkItem)
-        {
-          MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, (PVOID)Packet);
-          return NDIS_STATUS_PENDING;
+        if(Adapter->MiniportBusy) {
+           MiniQueueWorkItem(Adapter, NdisWorkItemSendLoopback, Packet);
+           KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
+           return NDIS_STATUS_PENDING;
         }
 
-      KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
-        {
-          /*
-           * atm this *only* handles loopback packets - it calls MiniIndicateData to
-           * send back to the protocol.  FIXME: this will need to be adjusted a bit.
-           * Also, I'm not sure you really have to be at dispatch level for this.  It
-           * might use a ReceivePackets handler, which can run <= DISPATCH_LEVEL.
-           */
-          NdisStatus = ProIndicatePacket(Adapter, Packet);
-
-          NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
-          KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
-            {
-              NDIS_DbgPrint(MAX_TRACE, ("Setting adapter 0x%x to free\n"));
-              Adapter->MiniportBusy = FALSE;
-
-              if (Adapter->WorkQueueHead)
-                KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
-              else
-                NDIS_DbgPrint(MID_TRACE,("Failed to insert packet into work queue\n"));
-            }
-          KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
-        }
-      KeLowerIrql(RaiseOldIrql);
-
-      return NdisStatus;
-    }
-  else
-    NDIS_DbgPrint(MID_TRACE,("Not a loopback packet\n"));
-
-  /* This is a normal send packet, not a loopback packet. */
-  if (QueueWorkItem)
-    {
-      MiniQueueWorkItem(Adapter, NdisWorkItemSend, (PVOID)Packet);
-      NDIS_DbgPrint(MAX_TRACE, ("Queued a work item and returning\n"));
-      return NDIS_STATUS_PENDING;
-    }
-
-  ASSERT(Adapter->NdisMiniportBlock.DriverHandle);
+        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
 
-  /*
-   * Call the appropriate send handler
-   *
-   * If a miniport provides a SendPackets handler, we always call it.  If not, we call the
-   * Send handler.
-   */
-  if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
-    {
-      if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
-        {
-          NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
-          (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
-        }
-      else
-        {
-          /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
-          KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
-            {
-              NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
-              (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
-                Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
-            }
-          KeLowerIrql(RaiseOldIrql);
+        return ProIndicatePacket(Adapter, Packet);
+    } else {
+        if(Adapter->MiniportBusy) {
+           MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet);
+           KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
+           return NDIS_STATUS_PENDING;
         }
 
-      /* SendPackets handlers return void - they always "succeed" */
-      NdisStatus = NDIS_STATUS_SUCCESS;
-    }
-  else
-    {
-      /* XXX FIXME THIS IS WRONG */
-      /* uh oh... forgot why i thought that... */
-      if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
-        {
-          NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
-          NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, 0);
-          NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
-        }
-      else
-        {
-          /* Send handlers always run at DISPATCH_LEVEL so we raise here */
-          KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
-
-          NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
-          NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
-            Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, 0);
-          NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
-         if( NdisStatus != NDIS_STATUS_PENDING ) {
-             Adapter->MiniportBusy = FALSE;
-         }
-          KeLowerIrql(RaiseOldIrql);
-        }
-    }
+        KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
 
-  /* XXX why the hell do we do this? */
-  NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
-  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
-    {
-      if (Adapter->WorkQueueHead)
+        if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
         {
-          KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
-          NDIS_DbgPrint(MAX_TRACE, ("MiniportDpc queued; returning NDIS_STATUS_SUCCESS\n"));
-        }
-    }
-  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
-
-  NDIS_DbgPrint(MAX_TRACE, ("returning 0x%x\n", NdisStatus));
-  return NdisStatus;
+           if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
+           {
+               NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
+               (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
+                Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
+                NdisStatus = NDIS_GET_PACKET_STATUS(Packet);
+           } else {
+               /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
+               KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
+               {
+                  NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
+                  (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
+                   Adapter->NdisMiniportBlock.MiniportAdapterContext, &Packet, 1);
+               }
+               KeLowerIrql(RaiseOldIrql);
+
+               NdisStatus = NDIS_GET_PACKET_STATUS(Packet);
+               if( NdisStatus == NDIS_STATUS_RESOURCES ) {
+                   KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
+                   MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet);
+                   KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
+                   NdisStatus = NDIS_STATUS_PENDING;
+               }
+           }
+
+           return NdisStatus;
+         } else {
+           if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
+           {
+              NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
+              NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
+                            Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, 0);
+              NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
+           } else {
+              /* Send is called at DISPATCH_LEVEL for all serialized miniports */
+              KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
+              NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
+              NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
+                            Adapter->NdisMiniportBlock.MiniportAdapterContext, Packet, 0);
+              NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
+              KeLowerIrql(RaiseOldIrql);
+              if( NdisStatus == NDIS_STATUS_RESOURCES ) {
+                  KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &SpinOldIrql);
+                  MiniQueueWorkItem(Adapter, NdisWorkItemSend, Packet);
+                  KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, SpinOldIrql);
+                  NdisStatus = NDIS_STATUS_PENDING;
+              }
+           }
+
+           return NdisStatus;
+         }
+     }
 }
 
 \f
@@ -422,6 +321,8 @@ ProTransferData(
 {
     PADAPTER_BINDING AdapterBinding = GET_ADAPTER_BINDING(MacBindingHandle);
     PLOGICAL_ADAPTER Adapter        = AdapterBinding->Adapter;
+    NDIS_STATUS Status;
+    KIRQL OldIrql;
 
     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
@@ -440,13 +341,19 @@ ProTransferData(
         return NDIS_STATUS_SUCCESS;
     }
 
-    return (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+    Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.TransferDataHandler)(
         Packet,
         BytesTransferred,
         Adapter->NdisMiniportBlock.MiniportAdapterContext,
         MacReceiveContext,
         ByteOffset,
         BytesToTransfer);
+
+    KeLowerIrql(OldIrql);
+
+    return Status;
 }
 
 
@@ -680,6 +587,8 @@ NdisRegisterProtocol(
 
   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
 
+  *NdisProtocolHandle = NULL;
+
   /* first validate the PROTOCOL_CHARACTERISTICS */
   switch (ProtocolCharacteristics->MajorNdisVersion)
     {
@@ -787,7 +696,7 @@ NdisRegisterProtocol(
     RtlInitUnicodeString(&ValueName, L"Bind");
 
     NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, NULL, 0, &ResultLength);
-    if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL)
+    if(NtStatus != STATUS_BUFFER_OVERFLOW && NtStatus != STATUS_BUFFER_TOO_SMALL && NtStatus != STATUS_SUCCESS)
       {
         NDIS_DbgPrint(MID_TRACE, ("Unable to query the Bind value for size\n"));
         ZwClose(DriverKeyHandle);
@@ -809,10 +718,11 @@ NdisRegisterProtocol(
     NtStatus = ZwQueryValueKey(DriverKeyHandle, &ValueName, KeyValuePartialInformation, KeyInformation,
         sizeof(KEY_VALUE_PARTIAL_INFORMATION) + ResultLength, &ResultLength);
 
+    ZwClose(DriverKeyHandle);
+
     if(!NT_SUCCESS(NtStatus))
       {
         NDIS_DbgPrint(MIN_TRACE, ("Unable to query the Bind value\n"));
-        ZwClose(DriverKeyHandle);
         ExFreePool(KeyInformation);
         ExFreePool(Protocol);
         *Status = NDIS_STATUS_FAILURE;
@@ -888,16 +798,17 @@ NdisRegisterProtocol(
           /* Put protocol binding struct on global list */
           ExInterlockedInsertTailList(&ProtocolListHead, &Protocol->ListEntry, &ProtocolListLock);
         }
-
-      /*
       else if(*Status != NDIS_STATUS_PENDING)
         {
-          // what to do here?
+          ExFreePool(Protocol);
+          ExFreePool(KeyInformation);
+          *NdisProtocolHandle = NULL;
+          return;
         }
-       */
     }
 
-  *Status             = NDIS_STATUS_SUCCESS;
+  ExFreePool(KeyInformation);
+  *Status = NDIS_STATUS_SUCCESS;
 }
 
 \f