4.6.1 Multipacket Receives
A miniport can allocate and manage an array of packet descriptors, fill the
chained buffers with incoming data and then pass pointers to the filled in
packets to interested protocol drivers by calling NdisMIndicateReceivePacket.
Support of NdisMIndicateReceivePacket requires that the miniport
allocate and set up packet descriptor for a full network packet, rather than a
lookahead buffer.
The miniport passes status, possibly the time a packet is received, possibly
the time the packet was sent, and possibly other media-specific infomation to
upper-layers by setting members in the OOB data block associated with each
packet descriptor. The miniport must set the Status member of the OOB
block to either NDIS_STATUS_SUCCESS, if the miniport is willing to allow a
protocol to keep the packet and return it later to MiniportReturnPacket, or to
NDIS_STATUS_RESOURCES if the miniport is running short of free packet
descriptors or buffers and wants to force any interested upper layer driver to
copy the packet data before NdisMIndicateReceivePacket returns. See Section
4.3 for details.
When NdisMIndicateReceivePacket returns:
-
If the Status member in the OOB block associated with a packet is
anything except NDIS_STATUS_PENDING, the packet descriptor and all the
resources it describes are returned to the miniport.
-
If the Status member is NDIS_STATUS_PENDING, ownership of the
miniport-allocated packet resources transfers to the protocol driver or
possibly intermediate protocol driver until the packet descriptor is returned
to the miniport’s MiniportReturnPacket function.
-
If the miniport set the Status member for any packet in the array to
NDIS_STATUS_RESOURCES before calling NdisMIndicateReceivePacket, that
packet and any subsequent packets in the array will be returned to the
miniport when higher level drivers have copied the indicated packet(s) data.
The Status member for all such packets will be set to
NDIS_STATUS_SUCCESS.
A miniport that manages a busmaster DMA adapter will typically indicate
packets by calling NdisMIndicateReceivePacket because such a miniport’s
NIC usually has sufficient ring buffer space to receive multiple packets. The
miniport can get a performance boost processing several packets at a time.
Usually, a miniport for any other type of device, such as a PIO device or an
adapter-shared-memory device, calls NdisMIndicateReceivePacket only if
it needs to pass priority, media-specific information or receive-time. NonDMA
NICs typically only receive one packet at a time and must be reset between
single receives. Such a miniport may only indicate up one packet at a time
with NdisMIndicateReceivePacket.
Because the miniport passes ownership of the packet(s) up when it calls NdisMIndicateReceivePacket,
such a miniport must practice a reasonable buffer-management strategy to
insure that it has available buffers when new data arrives on the network.
Typically, the miniport preallocates a set of buffers in MiniportInitialize
the size of its ring plus perhaps a few extra, and allocates sufficient buffer
descriptors to map these buffers plus a few packet descriptors for making
subsequent receive indications.
If a miniport determines that it is running low on receive buffer space, it
can use either of the following two strategies.
-
When it calls NdisMIndicateReceivePacket, the miniport should set the Status
member of the OOB block for the first packet descriptor it indicates up that
it does not want the protocol(s) to keep to NDIS_STATUS_RESOURCES. This tells
NDIS that the miniport is not willing to give up ownership of this
packet's resources, nor of any subsequent packets in the array, to the
protocol driver to whom the packet is indicated. NDIS will ensure that the
packet is copied by the protocol driver rather than passed to the protocol
driver. That is, NDIS calls ProtocolReceive rather than ProtocolReceivePacket,
forcing the protocol driver to transfer the data immediately. Since the
miniport does not have to provide a MiniportTransferData function if it
supports the multipacket receive paradigm described here, NDIS intercepts the
protocol driver’s transfer request and performs the transfer.
-
Or, the miniport maintains a high water mark and low water mark for its set of
free buffers. When the number of buffers approaches the low-water mark, the
miniport calls NdisMAllocateSharedMemoryAsync
to allocate more buffers and NdisAllocateBuffer to allocate buffer
descriptors to map these buffers. This NDIS function can be called at IRQL
DISPATCH_LEVEL, even in the MiniportHandleInterrupt function for instance,
unlike NdisMAllocateSharedMemory
which can be called only at IRQL < DISPATCH_LEVEL, for instance, in the
MiniportInitialize function. When the set of free buffers exceeds the
high-water mark, the miniport returns excess buffers by calling NdisMFreeSharedMemory
to free the buffers and NdisFreeBuffer to free the buffer descriptors
that map these buffers.