mirror of
https://github.com/espressif/openthread.git
synced 2026-07-04 19:30:22 +00:00
1d999ccea3
* Add Windows Tunnel Mode Miniport Driver (ottmp)
548 lines
19 KiB
C++
548 lines
19 KiB
C++
/*
|
|
* 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);
|
|
}
|