mirror of
https://github.com/espressif/openthread.git
synced 2026-10-18 05:28:10 +00:00
Add Windows Tunnel Mode Miniport Driver (ottmp) (#993)
* Add Windows Tunnel Mode Miniport Driver (ottmp)
This commit is contained in:
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This module implements code to manage the NETADAPTER object for the
|
||||
* network adapter.
|
||||
*/
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "adapter.tmh"
|
||||
|
||||
PAGED
|
||||
_IRQL_requires_max_(PASSIVE_LEVEL)
|
||||
NDIS_STATUS
|
||||
AdapterInitialize(
|
||||
_In_ NDIS_HANDLE MiniportAdapterHandle,
|
||||
_In_ POTTMP_ADAPTER_CONTEXT AdapterContext
|
||||
)
|
||||
/*++
|
||||
Routine Description:
|
||||
|
||||
AdapterInitialize function is called to initialize the Network Adapter
|
||||
at the time of Pnp Add device.
|
||||
|
||||
This routine initializes the context of the adapter object
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterHandle - Handle to the NDIS Miniport Adapter object.
|
||||
|
||||
AdapterContext - The context associated with the adapter
|
||||
|
||||
Return Value:
|
||||
|
||||
NTSTATUS - A failure here will indicate a fatal error in the driver.
|
||||
|
||||
--*/
|
||||
{
|
||||
NDIS_STATUS Status;
|
||||
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
do
|
||||
{
|
||||
NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES AdapterRegistration = { 0 };
|
||||
NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES AdapterGeneral = { 0 };
|
||||
NDIS_PM_CAPABILITIES PmCapabilities = { 0 };
|
||||
|
||||
//
|
||||
// First, set the registration attributes.
|
||||
//
|
||||
AdapterRegistration.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
|
||||
AdapterRegistration.Header.Size = sizeof(AdapterRegistration);
|
||||
AdapterRegistration.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_2;
|
||||
|
||||
AdapterRegistration.MiniportAdapterContext = AdapterContext;
|
||||
AdapterRegistration.AttributeFlags = NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK | NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM | NDIS_MINIPORT_ATTRIBUTES_NO_PAUSE_ON_SUSPEND;
|
||||
AdapterRegistration.InterfaceType = NdisInterfacePNPBus;
|
||||
|
||||
NDIS_DECLARE_MINIPORT_ADAPTER_CONTEXT(_OTTMP_ADAPTER_CONTEXT);
|
||||
Status = NdisMSetMiniportAttributes(
|
||||
MiniportAdapterHandle,
|
||||
(PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterRegistration);
|
||||
|
||||
if (NDIS_STATUS_SUCCESS != Status)
|
||||
{
|
||||
LogError(DRIVER_DEFAULT, "[%p] NdisSetOptionalHandlers Status %!NDIS_STATUS!", AdapterContext, Status);
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
// Next, set the general attributes.
|
||||
//
|
||||
|
||||
AdapterGeneral.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
|
||||
AdapterGeneral.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
|
||||
AdapterGeneral.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_2;
|
||||
|
||||
//
|
||||
// Specify the medium type that the NIC can support but not
|
||||
// necessarily the medium type that the NIC currently uses.
|
||||
//
|
||||
AdapterGeneral.MediaType = NIC_MEDIUM_TYPE;
|
||||
|
||||
//
|
||||
// Specifiy medium type that the NIC currently uses.
|
||||
//
|
||||
AdapterGeneral.PhysicalMediumType = NdisPhysicalMediumNative802_15_4;
|
||||
|
||||
//
|
||||
// We have to lie about the MTU, so that TCPIP will bind to us.
|
||||
// Specifically, we have to rely that the ThreadLwf will fragment
|
||||
// the packets appropriately.
|
||||
//
|
||||
AdapterGeneral.MtuSize = HW_MAX_FRAME_SIZE;
|
||||
AdapterGeneral.MaxXmitLinkSpeed = NIC_RECV_XMIT_SPEED;
|
||||
AdapterGeneral.XmitLinkSpeed = NIC_RECV_XMIT_SPEED;
|
||||
AdapterGeneral.MaxRcvLinkSpeed = NIC_RECV_XMIT_SPEED;
|
||||
AdapterGeneral.RcvLinkSpeed = NIC_RECV_XMIT_SPEED;
|
||||
AdapterGeneral.MediaConnectState = MediaConnectStateConnected;
|
||||
AdapterGeneral.MediaDuplexState = MediaDuplexStateFull;
|
||||
|
||||
//
|
||||
// The maximum number of bytes the NIC can provide as lookahead data.
|
||||
// If that value is different from the size of the lookahead buffer
|
||||
// supported by bound protocols, NDIS will call MiniportOidRequest to
|
||||
// set the size of the lookahead buffer provided by the miniport driver
|
||||
// to the minimum of the miniport driver and protocol(s) values. If the
|
||||
// driver always indicates up full packets with
|
||||
// NdisMIndicateReceiveNetBufferLists, it should set this value to the
|
||||
// maximum total frame size, which excludes the header.
|
||||
//
|
||||
// Upper-layer drivers examine lookahead data to determine whether a
|
||||
// packet that is associated with the lookahead data is intended for
|
||||
// one or more of their clients. If the underlying driver supports
|
||||
// multipacket receive indications, bound protocols are given full net
|
||||
// packets on every indication. Consequently, this value is identical
|
||||
// to that returned for OID_GEN_RECEIVE_BLOCK_SIZE.
|
||||
//
|
||||
AdapterGeneral.LookaheadSize = HW_MAX_FRAME_SIZE;
|
||||
AdapterGeneral.PowerManagementCapabilities = NULL;
|
||||
AdapterGeneral.MacOptions = NIC_MAC_OPTIONS;
|
||||
AdapterGeneral.SupportedPacketFilters = NIC_SUPPORTED_FILTERS;
|
||||
|
||||
//
|
||||
// The maximum number of multicast addresses the NIC driver can manage.
|
||||
// This list is global for all protocols bound to (or above) the NIC.
|
||||
// Consequently, a protocol can receive NDIS_STATUS_MULTICAST_FULL from
|
||||
// the NIC driver when attempting to set the multicast address list,
|
||||
// even if the number of elements in the given list is less than the
|
||||
// number originally returned for this query.
|
||||
//
|
||||
AdapterGeneral.MaxMulticastListSize = NIC_MAX_MCAST_LIST;
|
||||
AdapterGeneral.MacAddressLength = NIC_MACADDR_SIZE;
|
||||
|
||||
//
|
||||
// Return the MAC address of the NIC burnt in the hardware.
|
||||
//
|
||||
memcpy(AdapterGeneral.PermanentMacAddress, &AdapterContext->ExtendedAddress, sizeof(AdapterContext->ExtendedAddress));
|
||||
memcpy(AdapterGeneral.CurrentMacAddress, &AdapterContext->ExtendedAddress, sizeof(AdapterContext->ExtendedAddress));
|
||||
|
||||
AdapterGeneral.RecvScaleCapabilities = NULL;
|
||||
AdapterGeneral.AccessType = NET_IF_ACCESS_BROADCAST;
|
||||
AdapterGeneral.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
|
||||
AdapterGeneral.ConnectionType = NET_IF_CONNECTION_DEDICATED;
|
||||
AdapterGeneral.IfType = IF_TYPE_IEEE802154;
|
||||
AdapterGeneral.IfConnectorPresent = TRUE;
|
||||
AdapterGeneral.SupportedStatistics = NIC_SUPPORTED_STATISTICS;
|
||||
AdapterGeneral.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
|
||||
AdapterGeneral.DataBackFillSize = 0;
|
||||
AdapterGeneral.ContextBackFillSize = 0;
|
||||
|
||||
//
|
||||
// The SupportedOidList is an array of OIDs for objects that the
|
||||
// underlying driver or its NIC supports. Objects include general,
|
||||
// media-specific, and implementation-specific objects. NDIS forwards a
|
||||
// subset of the returned list to protocols that make this query. That
|
||||
// is, NDIS filters any supported statistics OIDs out of the list
|
||||
// because protocols never make statistics queries.
|
||||
//
|
||||
AdapterGeneral.SupportedOidList = NICSupportedOids;
|
||||
AdapterGeneral.SupportedOidListLength = SizeOfNICSupportedOids;
|
||||
AdapterGeneral.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
|
||||
|
||||
//
|
||||
// Set the power management capabilities. All 0 basically means we don't
|
||||
// support Dx for anything.
|
||||
//
|
||||
|
||||
PmCapabilities.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
|
||||
PmCapabilities.Header.Size = NDIS_SIZEOF_NDIS_PM_CAPABILITIES_REVISION_2;
|
||||
PmCapabilities.Header.Revision = NDIS_PM_CAPABILITIES_REVISION_2;
|
||||
|
||||
AdapterGeneral.PowerManagementCapabilitiesEx = &PmCapabilities;
|
||||
|
||||
Status = NdisMSetMiniportAttributes(
|
||||
MiniportAdapterHandle,
|
||||
(PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&AdapterGeneral);
|
||||
|
||||
if (NDIS_STATUS_SUCCESS != Status)
|
||||
{
|
||||
LogError(DRIVER_DEFAULT, "[%p] NdisSetOptionalHandlers failed %!NDIS_STATUS!", AdapterContext, Status);
|
||||
break;
|
||||
}
|
||||
|
||||
} while (FALSE);
|
||||
|
||||
LogFuncExitNDIS(DRIVER_DEFAULT, Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
PAGED
|
||||
_IRQL_requires_(PASSIVE_LEVEL)
|
||||
VOID
|
||||
AdapterUninitialize(
|
||||
_In_ POTTMP_ADAPTER_CONTEXT AdapterContext
|
||||
)
|
||||
{
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
SerialUninitialize(AdapterContext);
|
||||
|
||||
if (AdapterContext->Device)
|
||||
{
|
||||
WdfObjectDelete(AdapterContext->Device);
|
||||
AdapterContext->Device = nullptr;
|
||||
}
|
||||
|
||||
NdisFreeMemory(AdapterContext, 0, 0);
|
||||
|
||||
LogFuncExit(DRIVER_DEFAULT);
|
||||
}
|
||||
|
||||
PAGED
|
||||
_IRQL_requires_( PASSIVE_LEVEL )
|
||||
_Function_class_( MINIPORT_RESTART )
|
||||
NDIS_STATUS
|
||||
MPRestart(
|
||||
_In_ NDIS_HANDLE MiniportAdapterContext,
|
||||
_In_ PNDIS_MINIPORT_RESTART_PARAMETERS /* RestartParameters */
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
When a miniport receives a restart request, it enters into a Restarting
|
||||
state. The miniport may begin indicating received data (e.g., using
|
||||
NdisMIndicateReceiveNetBufferLists), handling status indications, and
|
||||
processing OID requests in the Restarting state. However, no sends will be
|
||||
requested while the miniport is in the Restarting state.
|
||||
|
||||
Once the miniport is ready to send data, it has entered the Running state.
|
||||
The miniport informs NDIS that it is in the Running state by returning
|
||||
NDIS_STATUS_SUCCESS from this MiniportRestart function; or if this function
|
||||
has already returned NDIS_STATUS_PENDING, by calling NdisMRestartComplete.
|
||||
|
||||
|
||||
MiniportRestart runs at IRQL = PASSIVE_LEVEL.
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterContext Pointer to the Adapter
|
||||
RestartParameters Additional information about the restart operation
|
||||
|
||||
Return Value:
|
||||
|
||||
If the miniport is able to immediately enter the Running state, it should
|
||||
return NDIS_STATUS_SUCCESS.
|
||||
|
||||
If the miniport is still in the Restarting state, it should return
|
||||
NDIS_STATUS_PENDING now, and call NdisMRestartComplete when the miniport
|
||||
has entered the Running state.
|
||||
|
||||
Other NDIS_STATUS codes indicate errors. If an error is encountered, the
|
||||
miniport must return to the Paused state (i.e., stop indicating receives).
|
||||
|
||||
--*/
|
||||
|
||||
{
|
||||
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
||||
POTTMP_ADAPTER_CONTEXT AdapterContext = (POTTMP_ADAPTER_CONTEXT)MiniportAdapterContext;
|
||||
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Set the running flag
|
||||
AdapterContext->IsRunning = true;
|
||||
|
||||
LogFuncExitNDIS(DRIVER_DEFAULT, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
PAGED
|
||||
_IRQL_requires_( PASSIVE_LEVEL )
|
||||
_Function_class_( MINIPORT_PAUSE )
|
||||
NDIS_STATUS
|
||||
MPPause(
|
||||
_In_ NDIS_HANDLE MiniportAdapterContext,
|
||||
_In_ PNDIS_MINIPORT_PAUSE_PARAMETERS /* MiniportPauseParameters */
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
When a miniport receives a pause request, it enters into a Pausing state.
|
||||
The miniport should not indicate up any more network data. Any pending
|
||||
send requests must be completed, and new requests must be rejected with
|
||||
NDIS_STATUS_PAUSED.
|
||||
|
||||
Once all sends have been completed and all recieve NBLs have returned to
|
||||
the miniport, the miniport enters the Paused state.
|
||||
|
||||
While paused, the miniport can still service interrupts from the hardware
|
||||
(to, for example, continue to indicate NDIS_STATUS_MEDIA_CONNECT
|
||||
notifications).
|
||||
|
||||
The miniport must continue to be able to handle status indications and OID
|
||||
requests. MiniportPause is different from MiniportHalt because, in
|
||||
general, the MiniportPause operation won't release any resources.
|
||||
MiniportPause must not attempt to acquire any resources where allocation
|
||||
can fail, since MiniportPause itself must not fail.
|
||||
|
||||
|
||||
MiniportPause runs at IRQL = PASSIVE_LEVEL.
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterContext Pointer to the Adapter
|
||||
MiniportPauseParameters Additional information about the pause operation
|
||||
|
||||
Return Value:
|
||||
|
||||
If the miniport is able to immediately enter the Paused state, it should
|
||||
return NDIS_STATUS_SUCCESS.
|
||||
|
||||
If the miniport must wait for send completions or pending receive NBLs, it
|
||||
should return NDIS_STATUS_PENDING now, and call NDISMPauseComplete when the
|
||||
miniport has entered the Paused state.
|
||||
|
||||
No other return value is permitted. The pause operation must not fail.
|
||||
|
||||
--*/
|
||||
{
|
||||
NDIS_STATUS status = NDIS_STATUS_SUCCESS;
|
||||
POTTMP_ADAPTER_CONTEXT AdapterContext = (POTTMP_ADAPTER_CONTEXT)MiniportAdapterContext;
|
||||
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
// Clear the flag to indicate we are no longer running
|
||||
AdapterContext->IsRunning = false;
|
||||
|
||||
LogFuncExitNDIS(DRIVER_DEFAULT, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID
|
||||
MPSendNetBufferLists(
|
||||
_In_ NDIS_HANDLE MiniportAdapterContext,
|
||||
_In_ PNET_BUFFER_LIST NetBufferLists,
|
||||
_In_ NDIS_PORT_NUMBER /* PortNumber */,
|
||||
_In_ ULONG SendFlags
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
Send Packet Array handler. Called by NDIS whenever a protocol
|
||||
bound to our miniport sends one or more packets.
|
||||
|
||||
The input packet descriptor pointers have been ordered according
|
||||
to the order in which the packets should be sent over the network
|
||||
by the protocol driver that set up the packet array. The NDIS
|
||||
library preserves the protocol-determined ordering when it submits
|
||||
each packet array to MiniportSendPackets
|
||||
|
||||
As a deserialized driver, we are responsible for holding incoming send
|
||||
packets in our internal queue until they can be transmitted over the
|
||||
network and for preserving the protocol-determined ordering of packet
|
||||
descriptors incoming to its MiniportSendPackets function.
|
||||
A deserialized miniport driver must complete each incoming send packet
|
||||
with NdisMSendComplete, and it cannot call NdisMSendResourcesAvailable.
|
||||
|
||||
Runs at IRQL <= DISPATCH_LEVEL
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterContext Pointer to our adapter
|
||||
NetBufferLists Head of a list of NBLs to send
|
||||
PortNumber A miniport adapter port. Default is 0.
|
||||
SendFlags Additional flags for the send operation
|
||||
|
||||
Return Value:
|
||||
|
||||
None. Write status directly into each NBL with the NET_BUFFER_LIST_STATUS
|
||||
macro.
|
||||
|
||||
--*/
|
||||
{
|
||||
POTTMP_ADAPTER_CONTEXT AdapterContext = (POTTMP_ADAPTER_CONTEXT)MiniportAdapterContext;
|
||||
PNET_BUFFER_LIST FailedNbls = NULL;
|
||||
|
||||
LogFuncEntryMsg(DRIVER_DEFAULT, "NetBufferList: %p", NetBufferLists);
|
||||
|
||||
PNET_BUFFER_LIST CurrNbl = NetBufferLists;
|
||||
while (CurrNbl)
|
||||
{
|
||||
PNET_BUFFER_LIST NextNbl = CurrNbl->Next;
|
||||
CurrNbl->Next = NULL;
|
||||
|
||||
// Only allow one NB per NBL
|
||||
if (CurrNbl->FirstNetBuffer == NULL ||
|
||||
CurrNbl->FirstNetBuffer->Next != NULL)
|
||||
{
|
||||
CurrNbl->Status = STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to queue up for send
|
||||
NTSTATUS status = SerialSendData(AdapterContext, CurrNbl);
|
||||
|
||||
if (!NT_SUCCESS(status)) {
|
||||
CurrNbl->Status = status;
|
||||
}
|
||||
else {
|
||||
CurrNbl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// If we still have the CurrNbl, it failed, so move it to the failure list
|
||||
if (CurrNbl) {
|
||||
CurrNbl->Next = FailedNbls;
|
||||
FailedNbls = CurrNbl;
|
||||
}
|
||||
|
||||
CurrNbl = NextNbl;
|
||||
}
|
||||
|
||||
// Complete any failures
|
||||
if (FailedNbls) {
|
||||
NdisMSendNetBufferListsComplete(AdapterContext->Adapter, FailedNbls, (SendFlags & NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL));
|
||||
}
|
||||
|
||||
LogFuncExit(DRIVER_DEFAULT);
|
||||
}
|
||||
|
||||
VOID
|
||||
MPCancelSend(
|
||||
_In_ NDIS_HANDLE /* MiniportAdapterContext */,
|
||||
_In_ PVOID /* CancelId */
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
MiniportCancelSend cancels the transmission of all NET_BUFFER_LISTs that
|
||||
are marked with a specified cancellation identifier. Miniport drivers
|
||||
that queue send packets for more than one second should export this
|
||||
handler. When a protocol driver or intermediate driver calls the
|
||||
NdisCancelSendNetBufferLists function, NDIS calls the MiniportCancelSend
|
||||
function of the appropriate lower-level driver (miniport driver or
|
||||
intermediate driver) on the binding.
|
||||
|
||||
Runs at IRQL <= DISPATCH_LEVEL.
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterContext Pointer to our adapter
|
||||
CancelId All the packets with this Id should be cancelled
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
LogFuncExit(DRIVER_DEFAULT);
|
||||
}
|
||||
|
||||
VOID
|
||||
MPReturnNetBufferLists(
|
||||
_In_ NDIS_HANDLE /* MiniportAdapterContext */,
|
||||
_In_ PNET_BUFFER_LIST NetBufferLists,
|
||||
_In_ ULONG /* ReturnFlags */
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
NDIS Miniport entry point called whenever protocols are done with one or
|
||||
NBLs that we indicated up with NdisMIndicateReceiveNetBufferLists.
|
||||
|
||||
Note that the list of NBLs may be chained together from multiple separate
|
||||
lists that were indicated up individually.
|
||||
|
||||
Arguments:
|
||||
|
||||
MiniportAdapterContext Pointer to our adapter
|
||||
NetBufferLists NBLs being returned
|
||||
ReturnFlags May contain the NDIS_RETURN_FLAGS_DISPATCH_LEVEL
|
||||
flag, which if is set, indicates we can get a
|
||||
small perf win by not checking or raising the
|
||||
IRQL
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
LogFuncEntry(DRIVER_DEFAULT);
|
||||
|
||||
// Iterate through all the NetBufferLists
|
||||
for (PNET_BUFFER_LIST pNblNext, pNbl = NetBufferLists; pNbl; pNbl = pNblNext)
|
||||
{
|
||||
// Save next to temporary and clear member variable
|
||||
pNblNext = NET_BUFFER_LIST_NEXT_NBL(pNbl);
|
||||
NET_BUFFER_LIST_NEXT_NBL(pNbl) = NULL;
|
||||
|
||||
// Iterate through all the Netbuffers
|
||||
for (PNET_BUFFER pNbNext, pNb = NET_BUFFER_LIST_FIRST_NB(pNbl); pNb; pNb = pNbNext)
|
||||
{
|
||||
pNbNext = NET_BUFFER_NEXT_NB(pNb);
|
||||
NdisFreeNetBuffer(pNb);
|
||||
}
|
||||
|
||||
NdisFreeNetBufferList(pNbl);
|
||||
}
|
||||
|
||||
LogFuncExit(DRIVER_DEFAULT);
|
||||
}
|
||||
Reference in New Issue
Block a user