--- /dev/null
+/*++
+
+Copyright(c) 1992-2000 Microsoft Corporation
+
+Module Name:
+
+ protocol.c
+
+Abstract:
+
+ Ndis Intermediate Miniport driver sample. This is a passthru driver.
+
+Author:
+
+Environment:
+
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define MAX_PACKET_POOL_SIZE 0x0000FFFF
+#define MIN_PACKET_POOL_SIZE 0x000000FF
+
+//
+// NDIS version as 0xMMMMmmmm, where M=Major/m=minor (0x00050001 = 5.1);
+// initially unknown (0)
+//
+ULONG NdisDotSysVersion = 0x0;
+
+
+#define NDIS_SYS_VERSION_51 0x00050001
+
+
+VOID
+PtBindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE BindContext,
+ IN PNDIS_STRING DeviceName,
+ IN PVOID SystemSpecific1,
+ IN PVOID SystemSpecific2
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS to bind to a miniport below.
+
+Arguments:
+
+ Status - Return status of bind here.
+ BindContext - Can be passed to NdisCompleteBindAdapter if this call is pended.
+ DeviceName - Device name to bind to. This is passed to NdisOpenAdapter.
+ SystemSpecific1 - Can be passed to NdisOpenProtocolConfiguration to read per-binding information
+ SystemSpecific2 - Unused
+
+Return Value:
+
+ NDIS_STATUS_PENDING if this call is pended. In this case call NdisCompleteBindAdapter
+ to complete.
+ Anything else Completes this call synchronously
+
+--*/
+{
+ NDIS_HANDLE ConfigHandle = NULL;
+ PNDIS_CONFIGURATION_PARAMETER Param;
+ NDIS_STRING DeviceStr = NDIS_STRING_CONST("UpperBindings");
+ NDIS_STRING NdisVersionStr = NDIS_STRING_CONST("NdisVersion");
+ PADAPT pAdapt = NULL;
+ NDIS_STATUS Sts;
+ UINT MediumIndex;
+ ULONG TotalSize;
+ BOOLEAN NoCleanUpNeeded = FALSE;
+
+
+ UNREFERENCED_PARAMETER(BindContext);
+ UNREFERENCED_PARAMETER(SystemSpecific2);
+
+ DBGPRINT(("==> Protocol BindAdapter\n"));
+
+ do
+ {
+ //
+ // Access the configuration section for our binding-specific
+ // parameters.
+ //
+ NdisOpenProtocolConfiguration(Status,
+ &ConfigHandle,
+ SystemSpecific1);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ if (NdisDotSysVersion == 0)
+ {
+ NdisReadConfiguration(Status,
+ &Param,
+ ConfigHandle,
+ &NdisVersionStr, // "NdisVersion"
+ NdisParameterInteger);
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ NdisDotSysVersion = Param->ParameterData.IntegerData;
+ }
+
+
+ //
+ // Read the "UpperBindings" reserved key that contains a list
+ // of device names representing our miniport instances corresponding
+ // to this lower binding. Since this is a 1:1 IM driver, this key
+ // contains exactly one name.
+ //
+ // If we want to implement a N:1 mux driver (N adapter instances
+ // over a single lower binding), then UpperBindings will be a
+ // MULTI_SZ containing a list of device names - we would loop through
+ // this list, calling NdisIMInitializeDeviceInstanceEx once for
+ // each name in it.
+ //
+ NdisReadConfiguration(Status,
+ &Param,
+ ConfigHandle,
+ &DeviceStr,
+ NdisParameterString);
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Allocate memory for the Adapter structure. This represents both the
+ // protocol context as well as the adapter structure when the miniport
+ // is initialized.
+ //
+ // In addition to the base structure, allocate space for the device
+ // instance string.
+ //
+ TotalSize = sizeof(ADAPT) + Param->ParameterData.StringData.MaximumLength;
+
+ NdisAllocateMemoryWithTag(&pAdapt, TotalSize, TAG);
+
+ if (pAdapt == NULL)
+ {
+ *Status = NDIS_STATUS_RESOURCES;
+ break;
+ }
+
+ //
+ // Initialize the adapter structure. We copy in the IM device
+ // name as well, because we may need to use it in a call to
+ // NdisIMCancelInitializeDeviceInstance. The string returned
+ // by NdisReadConfiguration is active (i.e. available) only
+ // for the duration of this call to our BindAdapter handler.
+ //
+ NdisZeroMemory(pAdapt, TotalSize);
+ pAdapt->DeviceName.MaximumLength = Param->ParameterData.StringData.MaximumLength;
+ pAdapt->DeviceName.Length = Param->ParameterData.StringData.Length;
+ pAdapt->DeviceName.Buffer = (PWCHAR)((ULONG_PTR)pAdapt + sizeof(ADAPT));
+ NdisMoveMemory(pAdapt->DeviceName.Buffer,
+ Param->ParameterData.StringData.Buffer,
+ Param->ParameterData.StringData.MaximumLength);
+
+
+
+ NdisInitializeEvent(&pAdapt->Event);
+ NdisAllocateSpinLock(&pAdapt->Lock);
+
+ //
+ // Allocate a packet pool for sends. We need this to pass sends down.
+ // We cannot use the same packet descriptor that came down to our send
+ // handler (see also NDIS 5.1 packet stacking).
+ //
+ NdisAllocatePacketPoolEx(Status,
+ &pAdapt->SendPacketPoolHandle,
+ MIN_PACKET_POOL_SIZE,
+ MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
+ sizeof(SEND_RSVD));
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Allocate a packet pool for receives. We need this to indicate receives.
+ // Same consideration as sends (see also NDIS 5.1 packet stacking).
+ //
+ NdisAllocatePacketPoolEx(Status,
+ &pAdapt->RecvPacketPoolHandle,
+ MIN_PACKET_POOL_SIZE,
+ MAX_PACKET_POOL_SIZE - MIN_PACKET_POOL_SIZE,
+ PROTOCOL_RESERVED_SIZE_IN_PACKET);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+
+ //
+ // Now open the adapter below and complete the initialization
+ //
+ NdisOpenAdapter(Status,
+ &Sts,
+ &pAdapt->BindingHandle,
+ &MediumIndex,
+ MediumArray,
+ sizeof(MediumArray)/sizeof(NDIS_MEDIUM),
+ ProtHandle,
+ pAdapt,
+ DeviceName,
+ 0,
+ NULL);
+
+ if (*Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pAdapt->Event, 0);
+ *Status = pAdapt->Status;
+ }
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ break;
+ }
+ PtReferenceAdapt(pAdapt);
+
+#pragma prefast(suppress: __WARNING_POTENTIAL_BUFFER_OVERFLOW, "Ndis guarantees MediumIndex to be within bounds");
+ pAdapt->Medium = MediumArray[MediumIndex];
+
+ //
+ // Now ask NDIS to initialize our miniport (upper) edge.
+ // Set the flag below to synchronize with a possible call
+ // to our protocol Unbind handler that may come in before
+ // our miniport initialization happens.
+ //
+ pAdapt->MiniportInitPending = TRUE;
+ NdisInitializeEvent(&pAdapt->MiniportInitEvent);
+
+ PtReferenceAdapt(pAdapt);
+
+ *Status = NdisIMInitializeDeviceInstanceEx(DriverHandle,
+ &pAdapt->DeviceName,
+ pAdapt);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pAdapt->MiniportIsHalted == TRUE)
+ {
+ NoCleanUpNeeded = TRUE;
+ }
+
+ DBGPRINT(("BindAdapter: Adapt %p, IMInitializeDeviceInstance error %x\n",
+ pAdapt, *Status));
+
+ if (PtDereferenceAdapt(pAdapt))
+ {
+ pAdapt = NULL;
+ }
+
+ break;
+ }
+
+ PtDereferenceAdapt(pAdapt);
+
+ } while(FALSE);
+
+ //
+ // Close the configuration handle now - see comments above with
+ // the call to NdisIMInitializeDeviceInstanceEx.
+ //
+ if (ConfigHandle != NULL)
+ {
+ NdisCloseConfiguration(ConfigHandle);
+ }
+
+ if ((*Status != NDIS_STATUS_SUCCESS) && (NoCleanUpNeeded == FALSE))
+ {
+ if (pAdapt != NULL)
+ {
+ if (pAdapt->BindingHandle != NULL)
+ {
+ NDIS_STATUS LocalStatus;
+
+ //
+ // Close the binding we opened above.
+ //
+
+ NdisResetEvent(&pAdapt->Event);
+
+ NdisCloseAdapter(&LocalStatus, pAdapt->BindingHandle);
+ pAdapt->BindingHandle = NULL;
+
+ if (LocalStatus == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pAdapt->Event, 0);
+ LocalStatus = pAdapt->Status;
+
+
+ }
+ if (PtDereferenceAdapt(pAdapt))
+ {
+ pAdapt = NULL;
+ }
+ }
+ }
+ }
+
+
+ DBGPRINT(("<== Protocol BindAdapter: pAdapt %p, Status %x\n", pAdapt, *Status));
+}
+
+
+VOID
+PtOpenAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status,
+ IN NDIS_STATUS OpenErrorStatus
+ )
+/*++
+
+Routine Description:
+
+ Completion routine for NdisOpenAdapter issued from within the PtBindAdapter. Simply
+ unblock the caller.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter
+ Status Status of the NdisOpenAdapter call
+ OpenErrorStatus Secondary status(ignored by us).
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+
+ UNREFERENCED_PARAMETER(OpenErrorStatus);
+
+ DBGPRINT(("==> PtOpenAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+ pAdapt->Status = Status;
+ NdisSetEvent(&pAdapt->Event);
+}
+
+
+VOID
+PtUnbindAdapter(
+ OUT PNDIS_STATUS Status,
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE UnbindContext
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS when we are required to unbind to the adapter below.
+ This functions shares functionality with the miniport's HaltHandler.
+ The code should ensure that NdisCloseAdapter and NdisFreeMemory is called
+ only once between the two functions
+
+Arguments:
+
+ Status Placeholder for return status
+ ProtocolBindingContext Pointer to the adapter structure
+ UnbindContext Context for NdisUnbindComplete() if this pends
+
+Return Value:
+
+ Status for NdisIMDeinitializeDeviceContext
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ NDIS_STATUS LocalStatus;
+
+ UNREFERENCED_PARAMETER(UnbindContext);
+
+ DBGPRINT(("==> PtUnbindAdapter: Adapt %p\n", pAdapt));
+
+ //
+ // Set the flag that the miniport below is unbinding, so the request handlers will
+ // fail any request comming later
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ pAdapt->UnbindingInProcess = TRUE;
+ if (pAdapt->QueuedRequest == TRUE)
+ {
+ pAdapt->QueuedRequest = FALSE;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ PtRequestComplete(pAdapt,
+ &pAdapt->Request,
+ NDIS_STATUS_FAILURE );
+
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ }
+#ifndef WIN9X
+ //
+ // Check if we had called NdisIMInitializeDeviceInstanceEx and
+ // we are awaiting a call to MiniportInitialize.
+ //
+ if (pAdapt->MiniportInitPending == TRUE)
+ {
+ //
+ // Try to cancel the pending IMInit process.
+ //
+ LocalStatus = NdisIMCancelInitializeDeviceInstance(
+ DriverHandle,
+ &pAdapt->DeviceName);
+
+ if (LocalStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Successfully cancelled IM Initialization; our
+ // Miniport Initialize routine will not be called
+ // for this device.
+ //
+ pAdapt->MiniportInitPending = FALSE;
+ ASSERT(pAdapt->MiniportHandle == NULL);
+ }
+ else
+ {
+ //
+ // Our Miniport Initialize routine will be called
+ // (may be running on another thread at this time).
+ // Wait for it to finish.
+ //
+ NdisWaitEvent(&pAdapt->MiniportInitEvent, 0);
+ ASSERT(pAdapt->MiniportInitPending == FALSE);
+ }
+
+ }
+#endif // !WIN9X
+
+ //
+ // Call NDIS to remove our device-instance. We do most of the work
+ // inside the HaltHandler.
+ //
+ // The Handle will be NULL if our miniport Halt Handler has been called or
+ // if the IM device was never initialized
+ //
+
+ if (pAdapt->MiniportHandle != NULL)
+ {
+ *Status = NdisIMDeInitializeDeviceInstance(pAdapt->MiniportHandle);
+
+ if (*Status != NDIS_STATUS_SUCCESS)
+ {
+ *Status = NDIS_STATUS_FAILURE;
+ }
+ }
+ else
+ {
+ //
+ // We need to do some work here.
+ // Close the binding below us
+ // and release the memory allocated.
+ //
+
+ if(pAdapt->BindingHandle != NULL)
+ {
+ NdisResetEvent(&pAdapt->Event);
+
+ NdisCloseAdapter(Status, pAdapt->BindingHandle);
+
+ //
+ // Wait for it to complete
+ //
+ if(*Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pAdapt->Event, 0);
+ *Status = pAdapt->Status;
+ }
+ pAdapt->BindingHandle = NULL;
+ }
+ else
+ {
+ //
+ // Both Our MiniportHandle and Binding Handle should not be NULL.
+ //
+ *Status = NDIS_STATUS_FAILURE;
+ ASSERT(0);
+ }
+
+ //
+ // Free the memory here, if was not released earlier(by calling the HaltHandler)
+ //
+ MPFreeAllPacketPools(pAdapt);
+ NdisFreeSpinLock(&pAdapt->Lock);
+ NdisFreeMemory(pAdapt, 0, 0);
+ }
+
+ DBGPRINT(("<== PtUnbindAdapter: Adapt %p\n", pAdapt));
+}
+
+VOID
+PtUnloadProtocol(
+ VOID
+)
+{
+ NDIS_STATUS Status;
+
+ if (ProtHandle != NULL)
+ {
+ NdisDeregisterProtocol(&Status, ProtHandle);
+ ProtHandle = NULL;
+ }
+
+ DBGPRINT(("PtUnloadProtocol: done!\n"));
+}
+
+
+
+VOID
+PtCloseAdapterComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion for the CloseAdapter call.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ Status Completion status
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+
+ DBGPRINT(("CloseAdapterComplete: Adapt %p, Status %x\n", pAdapt, Status));
+ pAdapt->Status = Status;
+ NdisSetEvent(&pAdapt->Event);
+}
+
+
+VOID
+PtResetComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion for the reset.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ Status Completion status
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER(ProtocolBindingContext);
+ UNREFERENCED_PARAMETER(Status);
+ //
+ // We never issue a reset, so we should not be here.
+ //
+ ASSERT(0);
+}
+
+
+VOID
+PtRequestComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_REQUEST NdisRequest,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Completion handler for the previously posted request. All OIDS
+ are completed by and sent to the same miniport that they were requested for.
+ If Oid == OID_PNP_QUERY_POWER then the data structure needs to returned with all entries =
+ NdisDeviceStateUnspecified
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ NdisRequest The posted request
+ Status Completion status
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ NDIS_OID Oid = pAdapt->Request.DATA.SET_INFORMATION.Oid ;
+
+ //
+ // Since our request is not outstanding anymore
+ //
+ ASSERT(pAdapt->OutstandingRequests == TRUE);
+
+ pAdapt->OutstandingRequests = FALSE;
+
+ //
+ // Complete the Set or Query, and fill in the buffer for OID_PNP_CAPABILITIES, if need be.
+ //
+ switch (NdisRequest->RequestType)
+ {
+ case NdisRequestQueryInformation:
+
+ //
+ // We never pass OID_PNP_QUERY_POWER down.
+ //
+ ASSERT(Oid != OID_PNP_QUERY_POWER);
+
+ if ((Oid == OID_PNP_CAPABILITIES) && (Status == NDIS_STATUS_SUCCESS))
+ {
+ MPQueryPNPCapabilities(pAdapt, &Status);
+ }
+ *pAdapt->BytesReadOrWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
+ *pAdapt->BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
+
+ if (((Oid == OID_GEN_MAC_OPTIONS)
+ && (Status == NDIS_STATUS_SUCCESS))
+ && (NdisDotSysVersion >= NDIS_SYS_VERSION_51))
+ {
+ //
+ // Only do this on Windows XP or greater (NDIS.SYS v 5.1);
+ // do not do in Windows 2000 (NDIS.SYS v 5.0))
+ //
+
+ //
+ // Remove the no-loopback bit from mac-options. In essence we are
+ // telling NDIS that we can handle loopback. We don't, but the
+ // interface below us does. If we do not do this, then loopback
+ // processing happens both below us and above us. This is wasteful
+ // at best and if Netmon is running, it will see multiple copies
+ // of loopback packets when sniffing above us.
+ //
+ // Only the lowest miniport is a stack of layered miniports should
+ // ever report this bit set to NDIS.
+ //
+ *(PULONG)NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
+ }
+
+ NdisMQueryInformationComplete(pAdapt->MiniportHandle,
+ Status);
+ break;
+
+ case NdisRequestSetInformation:
+
+ ASSERT( Oid != OID_PNP_SET_POWER);
+
+ *pAdapt->BytesReadOrWritten = NdisRequest->DATA.SET_INFORMATION.BytesRead;
+ *pAdapt->BytesNeeded = NdisRequest->DATA.SET_INFORMATION.BytesNeeded;
+ NdisMSetInformationComplete(pAdapt->MiniportHandle,
+ Status);
+ break;
+
+ default:
+ ASSERT(0);
+ break;
+ }
+
+}
+
+
+VOID
+PtStatus(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_STATUS GeneralStatus,
+ IN PVOID StatusBuffer,
+ IN UINT StatusBufferSize
+ )
+/*++
+
+Routine Description:
+
+ Status handler for the lower-edge(protocol).
+
+Arguments:
+
+ ProtocolBindingContext Pointer to the adapter structure
+ GeneralStatus Status code
+ StatusBuffer Status buffer
+ StatusBufferSize Size of the status buffer
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+
+ //
+ // Pass up this indication only if the upper edge miniport is initialized
+ // and powered on. Also ignore indications that might be sent by the lower
+ // miniport when it isn't at D0.
+ //
+ if ((pAdapt->MiniportHandle != NULL) &&
+ (pAdapt->MPDeviceState == NdisDeviceStateD0) &&
+ (pAdapt->PTDeviceState == NdisDeviceStateD0))
+ {
+ if ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
+ (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT))
+ {
+
+ pAdapt->LastIndicatedStatus = GeneralStatus;
+ }
+ NdisMIndicateStatus(pAdapt->MiniportHandle,
+ GeneralStatus,
+ StatusBuffer,
+ StatusBufferSize);
+ }
+ //
+ // Save the last indicated media status
+ //
+ else
+ {
+ if ((pAdapt->MiniportHandle != NULL) &&
+ ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) ||
+ (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT)))
+ {
+ pAdapt->LatestUnIndicateStatus = GeneralStatus;
+ }
+ }
+
+}
+
+
+VOID
+PtStatusComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+
+ //
+ // Pass up this indication only if the upper edge miniport is initialized
+ // and powered on. Also ignore indications that might be sent by the lower
+ // miniport when it isn't at D0.
+ //
+ if ((pAdapt->MiniportHandle != NULL) &&
+ (pAdapt->MPDeviceState == NdisDeviceStateD0) &&
+ (pAdapt->PTDeviceState == NdisDeviceStateD0))
+ {
+ NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
+ }
+}
+
+
+VOID
+PtSendComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Called by NDIS when the miniport below had completed a send. We should
+ complete the corresponding upper-edge send this represents.
+
+Arguments:
+
+ ProtocolBindingContext - Points to ADAPT structure
+ Packet - Low level packet being completed
+ Status - status of send
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ PNDIS_PACKET Pkt;
+ NDIS_HANDLE PoolHandle;
+
+#ifdef NDIS51
+ //
+ // Packet stacking:
+ //
+ // Determine if the packet we are completing is the one we allocated. If so, then
+ // get the original packet from the reserved area and completed it and free the
+ // allocated packet. If this is the packet that was sent down to us, then just
+ // complete it
+ //
+ PoolHandle = NdisGetPoolFromPacket(Packet);
+ if (PoolHandle != pAdapt->SendPacketPoolHandle)
+ {
+ //
+ // We had passed down a packet belonging to the protocol above us.
+ //
+ // DBGPRINT(("PtSendComp: Adapt %p, Stacked Packet %p\n", pAdapt, Packet));
+
+ NdisMSendComplete(pAdapt->MiniportHandle,
+ Packet,
+ Status);
+ }
+ else
+#endif // NDIS51
+ {
+ PSEND_RSVD SendRsvd;
+
+ SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
+ Pkt = SendRsvd->OriginalPkt;
+
+#if 1 // IPFW - new code
+ //DbgPrint("SendComplete: packet %p pkt %p\n", Packet, Pkt);
+ if (Pkt == NULL) { //this is a reinjected packet, with no 'father'
+ CleanupReinjected(Packet, SendRsvd->pMbuf, pAdapt);
+ return;
+ }
+#endif /* IPFW */
+
+#ifndef WIN9X
+ NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
+#endif
+
+ NdisDprFreePacket(Packet);
+
+ NdisMSendComplete(pAdapt->MiniportHandle,
+ Pkt,
+ Status);
+ }
+ //
+ // Decrease the outstanding send count
+ //
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+}
+
+
+VOID
+PtTransferDataComplete(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet,
+ IN NDIS_STATUS Status,
+ IN UINT BytesTransferred
+ )
+/*++
+
+Routine Description:
+
+ Entry point called by NDIS to indicate completion of a call by us
+ to NdisTransferData.
+
+ See notes under SendComplete.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+
+ if(pAdapt->MiniportHandle)
+ {
+ NdisMTransferDataComplete(pAdapt->MiniportHandle,
+ Packet,
+ Status,
+ BytesTransferred);
+ }
+}
+
+
+NDIS_STATUS
+PtReceive(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN NDIS_HANDLE MacReceiveContext,
+ IN PVOID HeaderBuffer,
+ IN UINT HeaderBufferSize,
+ IN PVOID LookAheadBuffer,
+ IN UINT LookAheadBufferSize,
+ IN UINT PacketSize
+ )
+/*++
+
+Routine Description:
+
+ Handle receive data indicated up by the miniport below. We pass
+ it along to the protocol above us.
+
+ If the miniport below indicates packets, NDIS would more
+ likely call us at our ReceivePacket handler. However we
+ might be called here in certain situations even though
+ the miniport below has indicated a receive packet, e.g.
+ if the miniport had set packet status to NDIS_STATUS_RESOURCES.
+
+Arguments:
+
+ <see DDK ref page for ProtocolReceive>
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS if we processed the receive successfully,
+ NDIS_STATUS_XXX error code if we discarded it.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)ProtocolBindingContext;
+ PNDIS_PACKET MyPacket, Packet = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ ULONG Proc = KeGetCurrentProcessorNumber();
+
+ if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState > NdisDeviceStateD0))
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+ else do
+ {
+ //
+ // Get at the packet, if any, indicated up by the miniport below.
+ //
+ Packet = NdisGetReceivedPacket(pAdapt->BindingHandle, MacReceiveContext);
+ if (Packet != NULL)
+ {
+ //
+ // The miniport below did indicate up a packet. Use information
+ // from that packet to construct a new packet to indicate up.
+ //
+
+#ifdef NDIS51
+ //
+ // NDIS 5.1 NOTE: Do not reuse the original packet in indicating
+ // up a receive, even if there is sufficient packet stack space.
+ // If we had to do so, we would have had to overwrite the
+ // status field in the original packet to NDIS_STATUS_RESOURCES,
+ // and it is not allowed for protocols to overwrite this field
+ // in received packets.
+ //
+#endif // NDIS51
+
+ //
+ // Get a packet off the pool and indicate that up
+ //
+ NdisDprAllocatePacket(&Status,
+ &MyPacket,
+ pAdapt->RecvPacketPoolHandle);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // Make our packet point to data from the original
+ // packet. NOTE: this works only because we are
+ // indicating a receive directly from the context of
+ // our receive indication. If we need to queue this
+ // packet and indicate it from another thread context,
+ // we will also have to allocate a new buffer and copy
+ // over the packet contents, OOB data and per-packet
+ // information. This is because the packet data
+ // is available only for the duration of this
+ // receive indication call.
+ //
+ NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
+ NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
+
+ //
+ // Get the original packet (it could be the same packet as the
+ // one received or a different one based on the number of layered
+ // miniports below) and set it on the indicated packet so the OOB
+ // data is visible correctly at protocols above. If the IM driver
+ // modifies the packet in any way it should not set the new packet's
+ // original packet equal to the original packet of the packet that
+ // was indicated to it from the underlying driver, in this case, the
+ // IM driver should also ensure that the related per packet info should
+ // be copied to the new packet.
+ // we can set the original packet to the original packet of the packet
+ // indicated from the underlying driver because the driver doesn't modify
+ // the data content in the packet.
+ //
+ NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
+ NDIS_SET_PACKET_HEADER_SIZE(MyPacket, HeaderBufferSize);
+
+ //
+ // Copy packet flags.
+ //
+ NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
+
+ //
+ // Force protocols above to make a copy if they want to hang
+ // on to data in this packet. This is because we are in our
+ // Receive handler (not ReceivePacket) and we can't return a
+ // ref count from here.
+ //
+ NDIS_SET_PACKET_STATUS(MyPacket, NDIS_STATUS_RESOURCES);
+
+ //
+ // By setting NDIS_STATUS_RESOURCES, we also know that we can reclaim
+ // this packet as soon as the call to NdisMIndicateReceivePacket
+ // returns.
+ //
+
+ if (pAdapt->MiniportHandle != NULL)
+ {
+#if 1 /* IPFW: query the firewall */
+ int ret;
+ ret = ipfw2_qhandler_w32(MyPacket, INCOMING,
+ ProtocolBindingContext);
+ if (ret != PASS)
+ return 0; //otherwise simply continue
+#endif /* end of IPFW code */
+ NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
+ }
+
+ //
+ // Reclaim the indicated packet. Since we had set its status
+ // to NDIS_STATUS_RESOURCES, we are guaranteed that protocols
+ // above are done with it.
+ //
+ NdisDprFreePacket(MyPacket);
+
+ break;
+ }
+ }
+ else
+ {
+ //
+ // The miniport below us uses the old-style (not packet)
+ // receive indication. Fall through.
+ //
+ }
+
+ //
+ // Fall through if the miniport below us has either not
+ // indicated a packet or we could not allocate one
+ //
+ pAdapt->ReceivedIndicationFlags[Proc] = TRUE;
+ if (pAdapt->MiniportHandle == NULL)
+ {
+ break;
+ }
+ switch (pAdapt->Medium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ //DbgPrint("EthIndicateReceive context %p, header at %p len %u, lookahead at %p len %u, packetsize %u\n",ProtocolBindingContext,HeaderBuffer,HeaderBufferSize,LookAheadBuffer,LookAheadBufferSize,PacketSize);
+ //hexdump(HeaderBuffer,HeaderBufferSize+LookAheadBufferSize,"EthIndicateReceive");
+ {
+ int ret = ipfw2_qhandler_w32_oldstyle(INCOMING, ProtocolBindingContext, HeaderBuffer, HeaderBufferSize, LookAheadBuffer, LookAheadBufferSize, PacketSize);
+ if (ret != PASS)
+ return NDIS_STATUS_SUCCESS;
+ }
+ NdisMEthIndicateReceive(pAdapt->MiniportHandle,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookAheadBuffer,
+ LookAheadBufferSize,
+ PacketSize);
+ break;
+
+ case NdisMedium802_5:
+ NdisMTrIndicateReceive(pAdapt->MiniportHandle,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookAheadBuffer,
+ LookAheadBufferSize,
+ PacketSize);
+ break;
+
+#if FDDI
+ case NdisMediumFddi:
+ NdisMFddiIndicateReceive(pAdapt->MiniportHandle,
+ MacReceiveContext,
+ HeaderBuffer,
+ HeaderBufferSize,
+ LookAheadBuffer,
+ LookAheadBufferSize,
+ PacketSize);
+ break;
+#endif
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ } while(FALSE);
+
+ return Status;
+}
+
+
+VOID
+PtReceiveComplete(
+ IN NDIS_HANDLE ProtocolBindingContext
+ )
+/*++
+
+Routine Description:
+
+ Called by the adapter below us when it is done indicating a batch of
+ received packets.
+
+Arguments:
+
+ ProtocolBindingContext Pointer to our adapter structure.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ ULONG Proc = KeGetCurrentProcessorNumber();
+
+ /* Warning: this is a poor implementation of the PtReceiveComplete
+ * made by MS, and it's a well known (but never fixed) issue.
+ * Since the ProcessorNumber here can be different from the one
+ * that processed the PtReceive, sometimes NdisMEthIndicateReceiveComplete
+ * will not be called, causing poor performance in the incoming traffic.
+ * In our driver, PtReceive is called for IP packets ONLY by particulary
+ * old NIC drivers, and the poor performance can be seen even
+ * in traffic not handled by ipfw or dummynet.
+ * Fortunately, this is quite rare, all the incoming IP packets
+ * will arrive through PtReceivePacket, and this callback will never
+ * be called. For reinjected traffic, a workaround is done
+ * commuting the ReceivedIndicationFlag and calling
+ * NdisMEthIndicateReceiveComplete manually for each packet.
+ */
+
+ if (((pAdapt->MiniportHandle != NULL)
+ && (pAdapt->MPDeviceState == NdisDeviceStateD0))
+ && (pAdapt->ReceivedIndicationFlags[Proc]))
+ {
+ switch (pAdapt->Medium)
+ {
+ case NdisMedium802_3:
+ case NdisMediumWan:
+ NdisMEthIndicateReceiveComplete(pAdapt->MiniportHandle);
+ break;
+
+ case NdisMedium802_5:
+ NdisMTrIndicateReceiveComplete(pAdapt->MiniportHandle);
+ break;
+#if FDDI
+ case NdisMediumFddi:
+ NdisMFddiIndicateReceiveComplete(pAdapt->MiniportHandle);
+ break;
+#endif
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+ }
+
+ pAdapt->ReceivedIndicationFlags[Proc] = FALSE;
+}
+
+
+INT
+PtReceivePacket(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ ReceivePacket handler. Called by NDIS if the miniport below supports
+ NDIS 4.0 style receives. Re-package the buffer chain in a new packet
+ and indicate the new packet to protocols above us. Any context for
+ packets indicated up must be kept in the MiniportReserved field.
+
+ NDIS 5.1 - packet stacking - if there is sufficient "stack space" in
+ the packet passed to us, we can use the same packet in a receive
+ indication.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to our adapter structure.
+ Packet - Pointer to the packet
+
+Return Value:
+
+ == 0 -> We are done with the packet
+ != 0 -> We will keep the packet and call NdisReturnPackets() this
+ many times when done.
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ NDIS_STATUS Status;
+ PNDIS_PACKET MyPacket;
+ BOOLEAN Remaining;
+
+ //
+ // Drop the packet silently if the upper miniport edge isn't initialized or
+ // the miniport edge is in low power state
+ //
+ if ((!pAdapt->MiniportHandle) || (pAdapt->MPDeviceState > NdisDeviceStateD0))
+ {
+ return 0;
+ }
+
+#ifdef NDIS51
+ //
+ // Check if we can reuse the same packet for indicating up.
+ // See also: PtReceive().
+ //
+ (VOID)NdisIMGetCurrentPacketStack(Packet, &Remaining);
+ if (0 && Remaining)
+ {
+ //
+ // We can reuse "Packet". Indicate it up and be done with it.
+ //
+ Status = NDIS_GET_PACKET_STATUS(Packet);
+ NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &Packet, 1);
+ return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
+ }
+#endif // NDIS51
+
+ //
+ // Get a packet off the pool and indicate that up
+ //
+ NdisDprAllocatePacket(&Status,
+ &MyPacket,
+ pAdapt->RecvPacketPoolHandle);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PRECV_RSVD RecvRsvd;
+
+ RecvRsvd = (PRECV_RSVD)(MyPacket->MiniportReserved);
+ RecvRsvd->OriginalPkt = Packet;
+
+ NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
+ NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
+
+ //
+ // Get the original packet (it could be the same packet as the one
+ // received or a different one based on the number of layered miniports
+ // below) and set it on the indicated packet so the OOB data is visible
+ // correctly to protocols above us.
+ //
+ NDIS_SET_ORIGINAL_PACKET(MyPacket, NDIS_GET_ORIGINAL_PACKET(Packet));
+
+ //
+ // Set Packet Flags
+ //
+ NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
+
+ Status = NDIS_GET_PACKET_STATUS(Packet);
+
+ NDIS_SET_PACKET_STATUS(MyPacket, Status);
+ NDIS_SET_PACKET_HEADER_SIZE(MyPacket, NDIS_GET_PACKET_HEADER_SIZE(Packet));
+
+ if (pAdapt->MiniportHandle != NULL)
+ {
+#if 1 /* IPFW: query the firewall */
+ int ret;
+ ret = ipfw2_qhandler_w32(MyPacket, INCOMING,
+ ProtocolBindingContext);
+ if (ret != PASS)
+ return 0; //otherwise simply continue
+#endif /* end of IPFW code */
+ NdisMIndicateReceivePacket(pAdapt->MiniportHandle, &MyPacket, 1);
+ }
+
+ //
+ // Check if we had indicated up the packet with NDIS_STATUS_RESOURCES
+ // NOTE -- do not use NDIS_GET_PACKET_STATUS(MyPacket) for this since
+ // it might have changed! Use the value saved in the local variable.
+ //
+ if (Status == NDIS_STATUS_RESOURCES)
+ {
+ //
+ // Our ReturnPackets handler will not be called for this packet.
+ // We should reclaim it right here.
+ //
+ NdisDprFreePacket(MyPacket);
+ }
+
+ return((Status != NDIS_STATUS_RESOURCES) ? 1 : 0);
+ }
+ else
+ {
+ //
+ // We are out of packets. Silently drop it.
+ //
+ return(0);
+ }
+}
+
+
+NDIS_STATUS
+PtPNPHandler(
+ IN NDIS_HANDLE ProtocolBindingContext,
+ IN PNET_PNP_EVENT pNetPnPEvent
+ )
+
+/*++
+Routine Description:
+
+ This is called by NDIS to notify us of a PNP event related to a lower
+ binding. Based on the event, this dispatches to other helper routines.
+
+ NDIS 5.1: forward this event to the upper protocol(s) by calling
+ NdisIMNotifyPnPEvent.
+
+Arguments:
+
+ ProtocolBindingContext - Pointer to our adapter structure. Can be NULL
+ for "global" notifications
+
+ pNetPnPEvent - Pointer to the PNP event to be processed.
+
+Return Value:
+
+ NDIS_STATUS code indicating status of event processing.
+
+--*/
+{
+ PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ DBGPRINT(("PtPnPHandler: Adapt %p, Event %d\n", pAdapt, pNetPnPEvent->NetEvent));
+
+ switch (pNetPnPEvent->NetEvent)
+ {
+ case NetEventSetPower:
+ Status = PtPnPNetEventSetPower(pAdapt, pNetPnPEvent);
+ break;
+
+ case NetEventReconfigure:
+ Status = PtPnPNetEventReconfigure(pAdapt, pNetPnPEvent);
+ break;
+
+ default:
+#ifdef NDIS51
+ //
+ // Pass on this notification to protocol(s) above, before
+ // doing anything else with it.
+ //
+ if (pAdapt && pAdapt->MiniportHandle)
+ {
+ Status = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
+ }
+#else
+ Status = NDIS_STATUS_SUCCESS;
+
+#endif // NDIS51
+
+ break;
+ }
+
+ return Status;
+}
+
+
+NDIS_STATUS
+PtPnPNetEventReconfigure(
+ IN PADAPT pAdapt,
+ IN PNET_PNP_EVENT pNetPnPEvent
+ )
+/*++
+Routine Description:
+
+ This routine is called from NDIS to notify our protocol edge of a
+ reconfiguration of parameters for either a specific binding (pAdapt
+ is not NULL), or global parameters if any (pAdapt is NULL).
+
+Arguments:
+
+ pAdapt - Pointer to our adapter structure.
+ pNetPnPEvent - the reconfigure event
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS
+
+--*/
+{
+ NDIS_STATUS ReconfigStatus = NDIS_STATUS_SUCCESS;
+ NDIS_STATUS ReturnStatus = NDIS_STATUS_SUCCESS;
+
+ do
+ {
+ //
+ // Is this is a global reconfiguration notification ?
+ //
+ if (pAdapt == NULL)
+ {
+ //
+ // An important event that causes this notification to us is if
+ // one of our upper-edge miniport instances was enabled after being
+ // disabled earlier, e.g. from Device Manager in Win2000. Note that
+ // NDIS calls this because we had set up an association between our
+ // miniport and protocol entities by calling NdisIMAssociateMiniport.
+ //
+ // Since we would have torn down the lower binding for that miniport,
+ // we need NDIS' assistance to re-bind to the lower miniport. The
+ // call to NdisReEnumerateProtocolBindings does exactly that.
+ //
+ NdisReEnumerateProtocolBindings (ProtHandle);
+
+ break;
+ }
+
+#ifdef NDIS51
+ //
+ // Pass on this notification to protocol(s) above before doing anything
+ // with it.
+ //
+ if (pAdapt->MiniportHandle)
+ {
+ ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
+ }
+#endif // NDIS51
+
+ ReconfigStatus = NDIS_STATUS_SUCCESS;
+
+ } while(FALSE);
+
+ DBGPRINT(("<==PtPNPNetEventReconfigure: pAdapt %p\n", pAdapt));
+
+#ifdef NDIS51
+ //
+ // Overwrite status with what upper-layer protocol(s) returned.
+ //
+ ReconfigStatus = ReturnStatus;
+#endif
+
+ return ReconfigStatus;
+}
+
+
+NDIS_STATUS
+PtPnPNetEventSetPower(
+ IN PADAPT pAdapt,
+ IN PNET_PNP_EVENT pNetPnPEvent
+ )
+/*++
+Routine Description:
+
+ This is a notification to our protocol edge of the power state
+ of the lower miniport. If it is going to a low-power state, we must
+ wait here for all outstanding sends and requests to complete.
+
+ NDIS 5.1: Since we use packet stacking, it is not sufficient to
+ check usage of our local send packet pool to detect whether or not
+ all outstanding sends have completed. For this, use the new API
+ NdisQueryPendingIOCount.
+
+ NDIS 5.1: Use the 5.1 API NdisIMNotifyPnPEvent to pass on PnP
+ notifications to upper protocol(s).
+
+Arguments:
+
+ pAdapt - Pointer to the adpater structure
+ pNetPnPEvent - The Net Pnp Event. this contains the new device state
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS or the status returned by upper-layer protocols.
+
+--*/
+{
+ PNDIS_DEVICE_POWER_STATE pDeviceState =(PNDIS_DEVICE_POWER_STATE)(pNetPnPEvent->Buffer);
+ NDIS_DEVICE_POWER_STATE PrevDeviceState = pAdapt->PTDeviceState;
+ NDIS_STATUS Status;
+ NDIS_STATUS ReturnStatus;
+
+ ReturnStatus = NDIS_STATUS_SUCCESS;
+
+ //
+ // Set the Internal Device State, this blocks all new sends or receives
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ pAdapt->PTDeviceState = *pDeviceState;
+
+ //
+ // Check if the miniport below is going to a low power state.
+ //
+ if (pAdapt->PTDeviceState > NdisDeviceStateD0)
+ {
+ //
+ // If the miniport below is going to standby, fail all incoming requests
+ //
+ if (PrevDeviceState == NdisDeviceStateD0)
+ {
+ pAdapt->StandingBy = TRUE;
+ }
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+#ifdef NDIS51
+ //
+ // Notify upper layer protocol(s) first.
+ //
+ if (pAdapt->MiniportHandle != NULL)
+ {
+ ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
+ }
+#endif // NDIS51
+
+ //
+ // Wait for outstanding sends and requests to complete.
+ //
+ while (pAdapt->OutstandingSends != 0)
+ {
+ NdisMSleep(2);
+ }
+
+ while (pAdapt->OutstandingRequests == TRUE)
+ {
+ //
+ // sleep till outstanding requests complete
+ //
+ NdisMSleep(2);
+ }
+
+ //
+ // If the below miniport is going to low power state, complete the queued request
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->QueuedRequest)
+ {
+ pAdapt->QueuedRequest = FALSE;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ PtRequestComplete(pAdapt, &pAdapt->Request, NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ }
+
+
+ ASSERT(NdisPacketPoolUsage(pAdapt->SendPacketPoolHandle) == 0);
+ ASSERT(pAdapt->OutstandingRequests == FALSE);
+ }
+ else
+ {
+ //
+ // If the physical miniport is powering up (from Low power state to D0),
+ // clear the flag
+ //
+ if (PrevDeviceState > NdisDeviceStateD0)
+ {
+ pAdapt->StandingBy = FALSE;
+ }
+ //
+ // The device below is being turned on. If we had a request
+ // pending, send it down now.
+ //
+ if (pAdapt->QueuedRequest == TRUE)
+ {
+ pAdapt->QueuedRequest = FALSE;
+
+ pAdapt->OutstandingRequests = TRUE;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ NdisRequest(&Status,
+ pAdapt->BindingHandle,
+ &pAdapt->Request);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ PtRequestComplete(pAdapt,
+ &pAdapt->Request,
+ Status);
+
+ }
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ }
+
+
+#ifdef NDIS51
+ //
+ // Pass on this notification to protocol(s) above
+ //
+ if (pAdapt->MiniportHandle)
+ {
+ ReturnStatus = NdisIMNotifyPnPEvent(pAdapt->MiniportHandle, pNetPnPEvent);
+ }
+#endif // NDIS51
+
+ }
+
+ return ReturnStatus;
+}
+
+VOID
+PtReferenceAdapt(
+ IN PADAPT pAdapt
+ )
+{
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ ASSERT(pAdapt->RefCount >= 0);
+
+ pAdapt->RefCount ++;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+}
+
+
+BOOLEAN
+PtDereferenceAdapt(
+ IN PADAPT pAdapt
+ )
+{
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ ASSERT(pAdapt->RefCount > 0);
+
+ pAdapt->RefCount--;
+
+ if (pAdapt->RefCount == 0)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ //
+ // Free all resources on this adapter structure.
+ //
+ MPFreeAllPacketPools (pAdapt);;
+ NdisFreeSpinLock(&pAdapt->Lock);
+ NdisFreeMemory(pAdapt, 0 , 0);
+
+ return TRUE;
+
+ }
+ else
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ return FALSE;
+ }
+}
+
+