--- /dev/null
+/*++
+
+Copyright (c) 1992-2000 Microsoft Corporation
+
+Module Name:
+
+ miniport.c
+
+Abstract:
+
+ Ndis Intermediate Miniport driver sample. This is a passthru driver.
+
+Author:
+
+Environment:
+
+
+Revision History:
+
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+
+NDIS_STATUS
+MPInitialize(
+ OUT PNDIS_STATUS OpenErrorStatus,
+ OUT PUINT SelectedMediumIndex,
+ IN PNDIS_MEDIUM MediumArray,
+ IN UINT MediumArraySize,
+ IN NDIS_HANDLE MiniportAdapterHandle,
+ IN NDIS_HANDLE WrapperConfigurationContext
+ )
+/*++
+
+Routine Description:
+
+ This is the initialize handler which gets called as a result of
+ the BindAdapter handler calling NdisIMInitializeDeviceInstanceEx.
+ The context parameter which we pass there is the adapter structure
+ which we retrieve here.
+
+ Arguments:
+
+ OpenErrorStatus Not used by us.
+ SelectedMediumIndex Place-holder for what media we are using
+ MediumArray Array of ndis media passed down to us to pick from
+ MediumArraySize Size of the array
+ MiniportAdapterHandle The handle NDIS uses to refer to us
+ WrapperConfigurationContext For use by NdisOpenConfiguration
+
+Return Value:
+
+ NDIS_STATUS_SUCCESS unless something goes wrong
+
+--*/
+{
+ UINT i;
+ PADAPT pAdapt;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+ NDIS_MEDIUM Medium;
+
+ UNREFERENCED_PARAMETER(WrapperConfigurationContext);
+
+ do
+ {
+ //
+ // Start off by retrieving our adapter context and storing
+ // the Miniport handle in it.
+ //
+ pAdapt = NdisIMGetDeviceContext(MiniportAdapterHandle);
+ pAdapt->MiniportIsHalted = FALSE;
+
+ DBGPRINT(("==> Miniport Initialize: Adapt %p\n", pAdapt));
+
+ //
+ // Usually we export the medium type of the adapter below as our
+ // virtual miniport's medium type. However if the adapter below us
+ // is a WAN device, then we claim to be of medium type 802.3.
+ //
+ Medium = pAdapt->Medium;
+
+ if (Medium == NdisMediumWan)
+ {
+ Medium = NdisMedium802_3;
+ }
+
+ for (i = 0; i < MediumArraySize; i++)
+ {
+ if (MediumArray[i] == Medium)
+ {
+ *SelectedMediumIndex = i;
+ break;
+ }
+ }
+
+ if (i == MediumArraySize)
+ {
+ Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
+ break;
+ }
+
+
+ //
+ // Set the attributes now. NDIS_ATTRIBUTE_DESERIALIZE enables us
+ // to make up-calls to NDIS without having to call NdisIMSwitchToMiniport
+ // or NdisIMQueueCallBack. This also forces us to protect our data using
+ // spinlocks where appropriate. Also in this case NDIS does not queue
+ // packets on our behalf. Since this is a very simple pass-thru
+ // miniport, we do not have a need to protect anything. However in
+ // a general case there will be a need to use per-adapter spin-locks
+ // for the packet queues at the very least.
+ //
+ NdisMSetAttributesEx(MiniportAdapterHandle,
+ pAdapt,
+ 0, // CheckForHangTimeInSeconds
+ NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
+ NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT|
+ NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
+ NDIS_ATTRIBUTE_DESERIALIZE |
+ NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
+ 0);
+
+ pAdapt->MiniportHandle = MiniportAdapterHandle;
+ //
+ // Initialize LastIndicatedStatus to be NDIS_STATUS_MEDIA_CONNECT
+ //
+ pAdapt->LastIndicatedStatus = NDIS_STATUS_MEDIA_CONNECT;
+
+ //
+ // Initialize the power states for both the lower binding (PTDeviceState)
+ // and our miniport edge to Powered On.
+ //
+ pAdapt->MPDeviceState = NdisDeviceStateD0;
+ pAdapt->PTDeviceState = NdisDeviceStateD0;
+
+ //
+ // Add this adapter to the global pAdapt List
+ //
+ NdisAcquireSpinLock(&GlobalLock);
+
+ pAdapt->Next = pAdaptList;
+ pAdaptList = pAdapt;
+
+ NdisReleaseSpinLock(&GlobalLock);
+
+ //
+ // Create an ioctl interface
+ //
+ (VOID)PtRegisterDevice();
+
+ Status = NDIS_STATUS_SUCCESS;
+ }
+ while (FALSE);
+
+ //
+ // If we had received an UnbindAdapter notification on the underlying
+ // adapter, we would have blocked that thread waiting for the IM Init
+ // process to complete. Wake up any such thread.
+ //
+ ASSERT(pAdapt->MiniportInitPending == TRUE);
+ pAdapt->MiniportInitPending = FALSE;
+ NdisSetEvent(&pAdapt->MiniportInitEvent);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PtReferenceAdapt(pAdapt);
+ }
+
+ DBGPRINT(("<== Miniport Initialize: Adapt %p, Status %x\n", pAdapt, Status));
+
+ *OpenErrorStatus = Status;
+
+
+ return Status;
+}
+
+
+NDIS_STATUS
+MPSend(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet,
+ IN UINT Flags
+ )
+/*++
+
+Routine Description:
+
+ Send Packet handler. Either this or our SendPackets (array) handler is called
+ based on which one is enabled in our Miniport Characteristics.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter
+ Packet Packet to send
+ Flags Unused, passed down below
+
+Return Value:
+
+ Return code from NdisSend
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status;
+ PNDIS_PACKET MyPacket;
+ PVOID MediaSpecificInfo = NULL;
+ ULONG MediaSpecificInfoSize = 0;
+
+ //
+ // The driver should fail the send if the virtual miniport is in low
+ // power state
+ //
+ if (pAdapt->MPDeviceState > NdisDeviceStateD0)
+ {
+ return NDIS_STATUS_FAILURE;
+ }
+
+#ifdef NDIS51
+ //
+ // Use NDIS 5.1 packet stacking:
+ //
+ if (0) // XXX IPFW - make sure we don't go in here
+ {
+ PNDIS_PACKET_STACK pStack;
+ BOOLEAN Remaining;
+
+ //
+ // Packet stacks: Check if we can use the same packet for sending down.
+ //
+
+ pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
+ if (Remaining)
+ {
+ //
+ // We can reuse "Packet".
+ //
+ // NOTE: if we needed to keep per-packet information in packets
+ // sent down, we can use pStack->IMReserved[].
+ //
+ ASSERT(pStack);
+ //
+ // If the below miniport is going to low power state, stop sending down any packet.
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->PTDeviceState > NdisDeviceStateD0)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ return NDIS_STATUS_FAILURE;
+ }
+ pAdapt->OutstandingSends++;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ NdisSend(&Status,
+ pAdapt->BindingHandle,
+ Packet);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ }
+
+ return(Status);
+ }
+ }
+#endif // NDIS51
+
+ //
+ // We are either not using packet stacks, or there isn't stack space
+ // in the original packet passed down to us. Allocate a new packet
+ // to wrap the data with.
+ //
+ //
+ // If the below miniport is going to low power state, stop sending down any packet.
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->PTDeviceState > NdisDeviceStateD0)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ return NDIS_STATUS_FAILURE;
+
+ }
+ pAdapt->OutstandingSends++;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ NdisAllocatePacket(&Status,
+ &MyPacket,
+ pAdapt->SendPacketPoolHandle);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PSEND_RSVD SendRsvd;
+
+ //
+ // Save a pointer to the original packet in our reserved
+ // area in the new packet. This is needed so that we can
+ // get back to the original packet when the new packet's send
+ // is completed.
+ //
+ SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
+ SendRsvd->OriginalPkt = Packet;
+
+ NdisGetPacketFlags(MyPacket) = Flags;
+
+ //
+ // Set up the new packet so that it describes the same
+ // data as the original 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);
+#ifdef WIN9X
+ //
+ // Work around the fact that NDIS does not initialize this
+ // to FALSE on Win9x.
+ //
+ NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE;
+#endif
+
+ //
+ // Copy the OOB Offset from the original packet to the new
+ // packet.
+ //
+ NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
+ NDIS_OOB_DATA_FROM_PACKET(Packet),
+ sizeof(NDIS_PACKET_OOB_DATA));
+
+#ifndef WIN9X
+ //
+ // Copy the right parts of per packet info into the new packet.
+ // This API is not available on Win9x since task offload is
+ // not supported on that platform.
+ //
+ NdisIMCopySendPerPacketInfo(MyPacket, Packet);
+#endif
+
+ //
+ // Copy the Media specific information
+ //
+ NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
+ &MediaSpecificInfo,
+ &MediaSpecificInfoSize);
+
+ if (MediaSpecificInfo || MediaSpecificInfoSize)
+ {
+ NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
+ MediaSpecificInfo,
+ MediaSpecificInfoSize);
+ }
+#if 1 /* IPFW: query the firewall */
+ /* if dummynet keeps the packet, we mimic success.
+ * otherwise continue as usual.
+ */
+ {
+ int ret = ipfw2_qhandler_w32(MyPacket, OUTGOING,
+ MiniportAdapterContext);
+ if (ret != PASS) {
+ if (ret == DROP)
+ return NDIS_STATUS_FAILURE;
+ else { //dummynet kept the packet
+#ifndef WIN9X
+ NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
+#endif
+ return NDIS_STATUS_SUCCESS; //otherwise simply continue
+ }
+ }
+ }
+#endif /* end of IPFW code */
+
+ NdisSend(&Status,
+ pAdapt->BindingHandle,
+ MyPacket);
+
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+#ifndef WIN9X
+ NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
+#endif
+ NdisFreePacket(MyPacket);
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ }
+ }
+ else
+ {
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ //
+ // We are out of packets. Silently drop it. Alternatively we can deal with it:
+ // - By keeping separate send and receive pools
+ // - Dynamically allocate more pools as needed and free them when not needed
+ //
+ }
+
+ return(Status);
+}
+
+
+VOID
+MPSendPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PPNDIS_PACKET PacketArray,
+ IN UINT NumberOfPackets
+ )
+/*++
+
+Routine Description:
+
+ Send Packet Array handler. Either this or our SendPacket handler is called
+ based on which one is enabled in our Miniport Characteristics.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to our adapter
+ PacketArray Set of packets to send
+ NumberOfPackets Self-explanatory
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status;
+ UINT i;
+ PVOID MediaSpecificInfo = NULL;
+ UINT MediaSpecificInfoSize = 0;
+
+
+ for (i = 0; i < NumberOfPackets; i++)
+ {
+ PNDIS_PACKET Packet, MyPacket;
+
+ Packet = PacketArray[i];
+ //
+ // The driver should fail the send if the virtual miniport is in low
+ // power state
+ //
+ if (pAdapt->MPDeviceState > NdisDeviceStateD0)
+ {
+ NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
+ Packet,
+ NDIS_STATUS_FAILURE);
+ continue;
+ }
+
+#ifdef NDIS51
+
+ //
+ // Use NDIS 5.1 packet stacking:
+ //
+ {
+ PNDIS_PACKET_STACK pStack;
+ BOOLEAN Remaining;
+
+ //
+ // Packet stacks: Check if we can use the same packet for sending down.
+ //
+ pStack = NdisIMGetCurrentPacketStack(Packet, &Remaining);
+ if (Remaining)
+ {
+ //
+ // We can reuse "Packet".
+ //
+ // NOTE: if we needed to keep per-packet information in packets
+ // sent down, we can use pStack->IMReserved[].
+ //
+ ASSERT(pStack);
+ //
+ // If the below miniport is going to low power state, stop sending down any packet.
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->PTDeviceState > NdisDeviceStateD0)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
+ Packet,
+ NDIS_STATUS_FAILURE);
+ }
+ else
+ {
+ pAdapt->OutstandingSends++;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ NdisSend(&Status,
+ pAdapt->BindingHandle,
+ Packet);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
+ Packet,
+ Status);
+
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ }
+ }
+ continue;
+ }
+ }
+#endif
+ do
+ {
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ //
+ // If the below miniport is going to low power state, stop sending down any packet.
+ //
+ if (pAdapt->PTDeviceState > NdisDeviceStateD0)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ pAdapt->OutstandingSends++;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ NdisAllocatePacket(&Status,
+ &MyPacket,
+ pAdapt->SendPacketPoolHandle);
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ PSEND_RSVD SendRsvd;
+
+ SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
+ SendRsvd->OriginalPkt = Packet;
+
+ NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(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);
+#ifdef WIN9X
+ //
+ // Work around the fact that NDIS does not initialize this
+ // to FALSE on Win9x.
+ //
+ NDIS_PACKET_VALID_COUNTS(MyPacket) = FALSE;
+#endif // WIN9X
+
+ //
+ // Copy the OOB data from the original packet to the new
+ // packet.
+ //
+ NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
+ NDIS_OOB_DATA_FROM_PACKET(Packet),
+ sizeof(NDIS_PACKET_OOB_DATA));
+ //
+ // Copy relevant parts of the per packet info into the new packet
+ //
+#ifndef WIN9X
+ NdisIMCopySendPerPacketInfo(MyPacket, Packet);
+#endif
+
+ //
+ // Copy the Media specific information
+ //
+ NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
+ &MediaSpecificInfo,
+ &MediaSpecificInfoSize);
+
+ if (MediaSpecificInfo || MediaSpecificInfoSize)
+ {
+ NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
+ MediaSpecificInfo,
+ MediaSpecificInfoSize);
+ }
+
+ NdisSend(&Status,
+ pAdapt->BindingHandle,
+ MyPacket);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+#ifndef WIN9X
+ NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
+#endif
+ NdisFreePacket(MyPacket);
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ }
+ }
+ else
+ {
+ //
+ // The driver cannot allocate a packet.
+ //
+ ADAPT_DECR_PENDING_SENDS(pAdapt);
+ }
+ }
+ while (FALSE);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
+ Packet,
+ Status);
+ }
+ }
+}
+
+
+NDIS_STATUS
+MPQueryInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesWritten,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+ Entry point called by NDIS to query for the value of the specified OID.
+ Typical processing is to forward the query down to the underlying miniport.
+
+ The following OIDs are filtered here:
+
+ OID_PNP_QUERY_POWER - return success right here
+
+ OID_GEN_SUPPORTED_GUIDS - do not forward, otherwise we will show up
+ multiple instances of private GUIDs supported by the underlying miniport.
+
+ OID_PNP_CAPABILITIES - we do send this down to the lower miniport, but
+ the values returned are postprocessed before we complete this request;
+ see PtRequestComplete.
+
+ NOTE on OID_TCP_TASK_OFFLOAD - if this IM driver modifies the contents
+ of data it passes through such that a lower miniport may not be able
+ to perform TCP task offload, then it should not forward this OID down,
+ but fail it here with the status NDIS_STATUS_NOT_SUPPORTED. This is to
+ avoid performing incorrect transformations on data.
+
+ If our miniport edge (upper edge) is at a low-power state, fail the request.
+
+ If our protocol edge (lower edge) has been notified of a low-power state,
+ we pend this request until the miniport below has been set to D0. Since
+ requests to miniports are serialized always, at most a single request will
+ be pended.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ Oid Oid for this query
+ InformationBuffer Buffer for information
+ InformationBufferLength Size of this buffer
+ BytesWritten Specifies how much info is written
+ BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed
+
+
+Return Value:
+
+ Return code from the NdisRequest below.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_FAILURE;
+
+ do
+ {
+ if (Oid == OID_PNP_QUERY_POWER)
+ {
+ //
+ // Do not forward this.
+ //
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+ }
+
+ if (Oid == OID_GEN_SUPPORTED_GUIDS)
+ {
+ //
+ // Do not forward this, otherwise we will end up with multiple
+ // instances of private GUIDs that the underlying miniport
+ // supports.
+ //
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Oid == OID_TCP_TASK_OFFLOAD)
+ {
+ //
+ // Fail this -if- this driver performs data transformations
+ // that can interfere with a lower driver's ability to offload
+ // TCP tasks.
+ //
+ // Status = NDIS_STATUS_NOT_SUPPORTED;
+ // break;
+ //
+ }
+ //
+ // If the miniport below is unbinding, just fail any request
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->UnbindingInProcess == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ //
+ // All other queries are failed, if the miniport is not at D0,
+ //
+ if (pAdapt->MPDeviceState > NdisDeviceStateD0)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ pAdapt->Request.RequestType = NdisRequestQueryInformation;
+ pAdapt->Request.DATA.QUERY_INFORMATION.Oid = Oid;
+ pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer = InformationBuffer;
+ pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pAdapt->BytesNeeded = BytesNeeded;
+ pAdapt->BytesReadOrWritten = BytesWritten;
+
+ //
+ // If the miniport below is binding, fail the request
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+
+ if (pAdapt->UnbindingInProcess == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ //
+ // If the Protocol device state is OFF, mark this request as being
+ // pended. We queue this until the device state is back to D0.
+ //
+ if ((pAdapt->PTDeviceState > NdisDeviceStateD0)
+ && (pAdapt->StandingBy == FALSE))
+ {
+ pAdapt->QueuedRequest = TRUE;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+ //
+ // This is in the process of powering down the system, always fail the request
+ //
+ if (pAdapt->StandingBy == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ pAdapt->OutstandingRequests = TRUE;
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+
+ //
+ // default case, most requests will be passed to the miniport below
+ //
+ NdisRequest(&Status,
+ pAdapt->BindingHandle,
+ &pAdapt->Request);
+
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ PtRequestComplete(pAdapt, &pAdapt->Request, Status);
+ Status = NDIS_STATUS_PENDING;
+ }
+
+ } while (FALSE);
+
+ return(Status);
+
+}
+
+
+VOID
+MPQueryPNPCapabilities(
+ IN OUT PADAPT pAdapt,
+ OUT PNDIS_STATUS pStatus
+ )
+/*++
+
+Routine Description:
+
+ Postprocess a request for OID_PNP_CAPABILITIES that was forwarded
+ down to the underlying miniport, and has been completed by it.
+
+Arguments:
+
+ pAdapt - Pointer to the adapter structure
+ pStatus - Place to return final status
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PNP_CAPABILITIES pPNPCapabilities;
+ PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
+
+ if (pAdapt->Request.DATA.QUERY_INFORMATION.InformationBufferLength >= sizeof(NDIS_PNP_CAPABILITIES))
+ {
+ pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)(pAdapt->Request.DATA.QUERY_INFORMATION.InformationBuffer);
+
+ //
+ // The following fields must be overwritten by an IM driver.
+ //
+ pPMstruct= & pPNPCapabilities->WakeUpCapabilities;
+ pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
+ pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
+ *pAdapt->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES);
+ *pAdapt->BytesNeeded = 0;
+
+
+ //
+ // Setting our internal flags
+ // Default, device is ON
+ //
+ pAdapt->MPDeviceState = NdisDeviceStateD0;
+ pAdapt->PTDeviceState = NdisDeviceStateD0;
+
+ *pStatus = NDIS_STATUS_SUCCESS;
+ }
+ else
+ {
+ *pAdapt->BytesNeeded= sizeof(NDIS_PNP_CAPABILITIES);
+ *pStatus = NDIS_STATUS_RESOURCES;
+ }
+}
+
+
+NDIS_STATUS
+MPSetInformation(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_OID Oid,
+ __in_bcount(InformationBufferLength) IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+
+ Miniport SetInfo handler.
+
+ In the case of OID_PNP_SET_POWER, record the power state and return the OID.
+ Do not pass below
+ If the device is suspended, do not block the SET_POWER_OID
+ as it is used to reactivate the Passthru miniport
+
+
+ PM- If the MP is not ON (DeviceState > D0) return immediately (except for 'query power' and 'set power')
+ If MP is ON, but the PT is not at D0, then queue the queue the request for later processing
+
+ Requests to miniports are always serialized
+
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the adapter structure
+ Oid Oid for this query
+ InformationBuffer Buffer for information
+ InformationBufferLength Size of this buffer
+ BytesRead Specifies how much info is read
+ BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed
+
+Return Value:
+
+ Return code from the NdisRequest below.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status;
+
+ Status = NDIS_STATUS_FAILURE;
+
+ do
+ {
+ //
+ // The Set Power should not be sent to the miniport below the Passthru, but is handled internally
+ //
+ if (Oid == OID_PNP_SET_POWER)
+ {
+ MPProcessSetPowerOid(&Status,
+ pAdapt,
+ InformationBuffer,
+ InformationBufferLength,
+ BytesRead,
+ BytesNeeded);
+ break;
+
+ }
+
+ //
+ // If the miniport below is unbinding, fail the request
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->UnbindingInProcess == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ //
+ // All other Set Information requests are failed, if the miniport is
+ // not at D0 or is transitioning to a device state greater than D0.
+ //
+ if (pAdapt->MPDeviceState > NdisDeviceStateD0)
+ {
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ // Set up the Request and return the result
+ pAdapt->Request.RequestType = NdisRequestSetInformation;
+ pAdapt->Request.DATA.SET_INFORMATION.Oid = Oid;
+ pAdapt->Request.DATA.SET_INFORMATION.InformationBuffer = InformationBuffer;
+ pAdapt->Request.DATA.SET_INFORMATION.InformationBufferLength = InformationBufferLength;
+ pAdapt->BytesNeeded = BytesNeeded;
+ pAdapt->BytesReadOrWritten = BytesRead;
+
+ //
+ // If the miniport below is unbinding, fail the request
+ //
+ NdisAcquireSpinLock(&pAdapt->Lock);
+ if (pAdapt->UnbindingInProcess == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // If the device below is at a low power state, we cannot send it the
+ // request now, and must pend it.
+ //
+ if ((pAdapt->PTDeviceState > NdisDeviceStateD0)
+ && (pAdapt->StandingBy == FALSE))
+ {
+ pAdapt->QueuedRequest = TRUE;
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_PENDING;
+ break;
+ }
+ //
+ // This is in the process of powering down the system, always fail the request
+ //
+ if (pAdapt->StandingBy == TRUE)
+ {
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ Status = NDIS_STATUS_FAILURE;
+ break;
+ }
+ pAdapt->OutstandingRequests = TRUE;
+
+ NdisReleaseSpinLock(&pAdapt->Lock);
+ //
+ // Forward the request to the device below.
+ //
+ NdisRequest(&Status,
+ pAdapt->BindingHandle,
+ &pAdapt->Request);
+
+ if (Status != NDIS_STATUS_PENDING)
+ {
+ *BytesRead = pAdapt->Request.DATA.SET_INFORMATION.BytesRead;
+ *BytesNeeded = pAdapt->Request.DATA.SET_INFORMATION.BytesNeeded;
+ pAdapt->OutstandingRequests = FALSE;
+ }
+
+ } while (FALSE);
+
+ return(Status);
+}
+
+
+VOID
+MPProcessSetPowerOid(
+ IN OUT PNDIS_STATUS pNdisStatus,
+ IN PADAPT pAdapt,
+ __in_bcount(InformationBufferLength) IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength,
+ OUT PULONG BytesRead,
+ OUT PULONG BytesNeeded
+ )
+/*++
+
+Routine Description:
+ This routine does all the procssing for a request with a SetPower Oid
+ The miniport shoud accept the Set Power and transition to the new state
+
+ The Set Power should not be passed to the miniport below
+
+ If the IM miniport is going into a low power state, then there is no guarantee if it will ever
+ be asked go back to D0, before getting halted. No requests should be pended or queued.
+
+
+Arguments:
+ pNdisStatus - Status of the operation
+ pAdapt - The Adapter structure
+ InformationBuffer - The New DeviceState
+ InformationBufferLength
+ BytesRead - No of bytes read
+ BytesNeeded - No of bytes needed
+
+
+Return Value:
+ Status - NDIS_STATUS_SUCCESS if all the wait events succeed.
+
+--*/
+{
+
+
+ NDIS_DEVICE_POWER_STATE NewDeviceState;
+
+ DBGPRINT(("==>MPProcessSetPowerOid: Adapt %p\n", pAdapt));
+
+ ASSERT (InformationBuffer != NULL);
+
+ *pNdisStatus = NDIS_STATUS_FAILURE;
+
+ do
+ {
+ //
+ // Check for invalid length
+ //
+ if (InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ *pNdisStatus = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+
+ NewDeviceState = (*(PNDIS_DEVICE_POWER_STATE)InformationBuffer);
+
+ //
+ // Check for invalid device state
+ //
+ if ((pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0))
+ {
+ //
+ // If the miniport is in a non-D0 state, the miniport can only receive a Set Power to D0
+ //
+ ASSERT (!(pAdapt->MPDeviceState > NdisDeviceStateD0) && (NewDeviceState != NdisDeviceStateD0));
+
+ *pNdisStatus = NDIS_STATUS_FAILURE;
+ break;
+ }
+
+ //
+ // Is the miniport transitioning from an On (D0) state to an Low Power State (>D0)
+ // If so, then set the StandingBy Flag - (Block all incoming requests)
+ //
+ if (pAdapt->MPDeviceState == NdisDeviceStateD0 && NewDeviceState > NdisDeviceStateD0)
+ {
+ pAdapt->StandingBy = TRUE;
+ }
+
+ //
+ // If the miniport is transitioning from a low power state to ON (D0), then clear the StandingBy flag
+ // All incoming requests will be pended until the physical miniport turns ON.
+ //
+ if (pAdapt->MPDeviceState > NdisDeviceStateD0 && NewDeviceState == NdisDeviceStateD0)
+ {
+ pAdapt->StandingBy = FALSE;
+ }
+
+ //
+ // Now update the state in the pAdapt structure;
+ //
+ pAdapt->MPDeviceState = NewDeviceState;
+
+ *pNdisStatus = NDIS_STATUS_SUCCESS;
+
+
+ } while (FALSE);
+
+ if (*pNdisStatus == NDIS_STATUS_SUCCESS)
+ {
+ //
+ // The miniport resume from low power state
+ //
+ if (pAdapt->StandingBy == FALSE)
+ {
+ //
+ // If we need to indicate the media connect state
+ //
+ if (pAdapt->LastIndicatedStatus != pAdapt->LatestUnIndicateStatus)
+ {
+ if (pAdapt->MiniportHandle != NULL)
+ {
+ NdisMIndicateStatus(pAdapt->MiniportHandle,
+ pAdapt->LatestUnIndicateStatus,
+ (PVOID)NULL,
+ 0);
+ NdisMIndicateStatusComplete(pAdapt->MiniportHandle);
+ pAdapt->LastIndicatedStatus = pAdapt->LatestUnIndicateStatus;
+ }
+ }
+ }
+ else
+ {
+ //
+ // Initialize LatestUnIndicatedStatus
+ //
+ pAdapt->LatestUnIndicateStatus = pAdapt->LastIndicatedStatus;
+ }
+ *BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+ *BytesNeeded = 0;
+ }
+ else
+ {
+ *BytesRead = 0;
+ *BytesNeeded = sizeof (NDIS_DEVICE_POWER_STATE);
+ }
+
+ DBGPRINT(("<==MPProcessSetPowerOid: Adapt %p\n", pAdapt));
+}
+
+
+VOID
+MPReturnPacket(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_PACKET Packet
+ )
+/*++
+
+Routine Description:
+
+ NDIS Miniport entry point called whenever protocols are done with
+ a packet that we had indicated up and they had queued up for returning
+ later.
+
+Arguments:
+
+ MiniportAdapterContext - pointer to ADAPT structure
+ Packet - packet being returned.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+
+#ifdef NDIS51
+ //
+ // Packet stacking: Check if this packet belongs to us.
+ //
+ if (NdisGetPoolFromPacket(Packet) != pAdapt->RecvPacketPoolHandle)
+ {
+ //
+ // We reused the original packet in a receive indication.
+ // Simply return it to the miniport below us.
+ //
+ NdisReturnPackets(&Packet, 1);
+ }
+ else
+#endif // NDIS51
+ {
+ //
+ // This is a packet allocated from this IM's receive packet pool.
+ // Reclaim our packet, and return the original to the driver below.
+ //
+
+ PNDIS_PACKET MyPacket;
+ PRECV_RSVD RecvRsvd;
+
+ RecvRsvd = (PRECV_RSVD)(Packet->MiniportReserved);
+ MyPacket = RecvRsvd->OriginalPkt;
+
+ NdisFreePacket(Packet);
+ NdisReturnPackets(&MyPacket, 1);
+ }
+}
+
+
+NDIS_STATUS
+MPTransferData(
+ OUT PNDIS_PACKET Packet,
+ OUT PUINT BytesTransferred,
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HANDLE MiniportReceiveContext,
+ IN UINT ByteOffset,
+ IN UINT BytesToTransfer
+ )
+/*++
+
+Routine Description:
+
+ Miniport's transfer data handler.
+
+Arguments:
+
+ Packet Destination packet
+ BytesTransferred Place-holder for how much data was copied
+ MiniportAdapterContext Pointer to the adapter structure
+ MiniportReceiveContext Context
+ ByteOffset Offset into the packet for copying data
+ BytesToTransfer How much to copy.
+
+Return Value:
+
+ Status of transfer
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status;
+
+ //
+ // Return, if the device is OFF
+ //
+
+ if (IsIMDeviceStateOn(pAdapt) == FALSE)
+ {
+ return NDIS_STATUS_FAILURE;
+ }
+
+ NdisTransferData(&Status,
+ pAdapt->BindingHandle,
+ MiniportReceiveContext,
+ ByteOffset,
+ BytesToTransfer,
+ Packet,
+ BytesTransferred);
+
+ return(Status);
+}
+
+VOID
+MPHalt(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ Halt handler. All the hard-work for clean-up is done here.
+
+Arguments:
+
+ MiniportAdapterContext Pointer to the Adapter
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+ NDIS_STATUS Status;
+ PADAPT *ppCursor;
+
+ DBGPRINT(("==>MiniportHalt: Adapt %p\n", pAdapt));
+
+ pAdapt->MiniportHandle = NULL;
+ pAdapt->MiniportIsHalted = TRUE;
+
+ //
+ // Remove this adapter from the global list
+ //
+ NdisAcquireSpinLock(&GlobalLock);
+
+ for (ppCursor = &pAdaptList; *ppCursor != NULL; ppCursor = &(*ppCursor)->Next)
+ {
+ if (*ppCursor == pAdapt)
+ {
+ *ppCursor = pAdapt->Next;
+ break;
+ }
+ }
+
+ NdisReleaseSpinLock(&GlobalLock);
+
+ //
+ // Delete the ioctl interface that was created when the miniport
+ // was created.
+ //
+ (VOID)PtDeregisterDevice();
+
+ //
+ // If we have a valid bind, close the miniport below the protocol
+ //
+#pragma prefast(suppress: __WARNING_DEREF_NULL_PTR, "pAdapt cannot be NULL")
+ if (pAdapt->BindingHandle != NULL)
+ {
+ //
+ // Close the binding below. and wait for it to complete
+ //
+ NdisResetEvent(&pAdapt->Event);
+
+ NdisCloseAdapter(&Status, pAdapt->BindingHandle);
+
+ if (Status == NDIS_STATUS_PENDING)
+ {
+ NdisWaitEvent(&pAdapt->Event, 0);
+ Status = pAdapt->Status;
+ }
+
+ ASSERT (Status == NDIS_STATUS_SUCCESS);
+
+ pAdapt->BindingHandle = NULL;
+
+ PtDereferenceAdapt(pAdapt);
+ }
+
+ if (PtDereferenceAdapt(pAdapt))
+ {
+ pAdapt = NULL;
+ }
+
+
+ DBGPRINT(("<== MiniportHalt: pAdapt %p\n", pAdapt));
+}
+
+
+#ifdef NDIS51_MINIPORT
+
+VOID
+MPCancelSendPackets(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID CancelId
+ )
+/*++
+
+Routine Description:
+
+ The miniport entry point to handle cancellation of all send packets
+ that match the given CancelId. If we have queued any packets that match
+ this, then we should dequeue them and call NdisMSendComplete for all
+ such packets, with a status of NDIS_STATUS_REQUEST_ABORTED.
+
+ We should also call NdisCancelSendPackets in turn, on each lower binding
+ that this adapter corresponds to. This is to let miniports below cancel
+ any matching packets.
+
+Arguments:
+
+ MiniportAdapterContext - pointer to ADAPT structure
+ CancelId - ID of packets to be cancelled.
+
+Return Value:
+
+ None
+
+--*/
+{
+ PADAPT pAdapt = (PADAPT)MiniportAdapterContext;
+
+ //
+ // If we queue packets on our adapter structure, this would be
+ // the place to acquire a spinlock to it, unlink any packets whose
+ // Id matches CancelId, release the spinlock and call NdisMSendComplete
+ // with NDIS_STATUS_REQUEST_ABORTED for all unlinked packets.
+ //
+
+ //
+ // Next, pass this down so that we let the miniport(s) below cancel
+ // any packets that they might have queued.
+ //
+ NdisCancelSendPackets(pAdapt->BindingHandle, CancelId);
+
+ return;
+}
+
+VOID
+MPDevicePnPEvent(
+ IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_DEVICE_PNP_EVENT DevicePnPEvent,
+ IN PVOID InformationBuffer,
+ IN ULONG InformationBufferLength
+ )
+/*++
+
+Routine Description:
+
+ This handler is called to notify us of PnP events directed to
+ our miniport device object.
+
+Arguments:
+
+ MiniportAdapterContext - pointer to ADAPT structure
+ DevicePnPEvent - the event
+ InformationBuffer - Points to additional event-specific information
+ InformationBufferLength - length of above
+
+Return Value:
+
+ None
+--*/
+{
+ // TBD - add code/comments about processing this.
+
+ UNREFERENCED_PARAMETER(MiniportAdapterContext);
+ UNREFERENCED_PARAMETER(DevicePnPEvent);
+ UNREFERENCED_PARAMETER(InformationBuffer);
+ UNREFERENCED_PARAMETER(InformationBufferLength);
+
+ return;
+}
+
+VOID
+MPAdapterShutdown(
+ IN NDIS_HANDLE MiniportAdapterContext
+ )
+/*++
+
+Routine Description:
+
+ This handler is called to notify us of an impending system shutdown.
+
+Arguments:
+
+ MiniportAdapterContext - pointer to ADAPT structure
+
+Return Value:
+
+ None
+--*/
+{
+ UNREFERENCED_PARAMETER(MiniportAdapterContext);
+
+ return;
+}
+
+#endif
+
+
+VOID
+MPFreeAllPacketPools(
+ IN PADAPT pAdapt
+ )
+/*++
+
+Routine Description:
+
+ Free all packet pools on the specified adapter.
+
+Arguments:
+
+ pAdapt - pointer to ADAPT structure
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (pAdapt->RecvPacketPoolHandle != NULL)
+ {
+ //
+ // Free the packet pool that is used to indicate receives
+ //
+ NdisFreePacketPool(pAdapt->RecvPacketPoolHandle);
+
+ pAdapt->RecvPacketPoolHandle = NULL;
+ }
+
+ if (pAdapt->SendPacketPoolHandle != NULL)
+ {
+
+ //
+ // Free the packet pool that is used to send packets below
+ //
+
+ NdisFreePacketPool(pAdapt->SendPacketPoolHandle);
+
+ pAdapt->SendPacketPoolHandle = NULL;
+
+ }
+}
+