Intermediate Driver Packet Management (NDIS 5.1)
Note NDIS 5. x has been deprecated and is superseded by NDIS 6. x. For new NDIS driver development, see Network Drivers Starting with Windows Vista. For information about porting NDIS 5. x drivers to NDIS 6. x, see Porting NDIS 5.x Drivers to NDIS 6.0.An intermediate driver receives a packet descriptor with one or more chained buffers of data from a higher-level driver to send over the network. The intermediate driver can pass the packet through to the underlying driver by calling NdisSend or NdisSendPackets if the driver has a connectionless lower edge, or by calling NdisCoSendPackets if the driver has a connection-oriented lower edge. Alternatively the intermediate driver can take some actions to modify either the contents of the chained buffers or perhaps the ordering or timing of the incoming packets relative to other transmissions.
NDIS 4.0 and 5.0 intermediate drivers must allocate a new NDIS_PACKET to encapsulate data that they pass on. These intermediate drivers must also copy any out-of-band (OOB) data to the new packet. Even if the intermediate driver does nothing other than simply pass on incoming packets -- for example, if it simply counts the packets -- it must allocate a fresh packet descriptor and manage some or all of a new packet structure.
NDIS 5.1 intermediate drivers that support packet stacking avoid this extra data handling in most common cases. Each NDIS_PACKET allocated includes "stacks", where each stack is an NDIS_PACKET_STACK structure.
NDIS 5.1 intermediate drivers call the NdisIMGetCurrentPacketStack function to access the IMReserved member in the NDIS_PACKET_STACK structure. This member can be used by an NDIS 5.1 intermediate driver to store its context information, if any, for the packet. NDIS 4.0 and 5.0 intermediate drivers use the ProtocolReserved and MiniportReserved members, for sent and received packets, in the NDIS_PACKET structure. If a call to NdisIMGetCurrentPacketStack indicates *StacksRemaining is FALSE, the NDIS 5.1 intermediate driver must revert to the NDIS 5.0 packet handling model.
Every NDIS 4.0 and 5.0 intermediate driver must allocate new packet descriptors to replace those of the overlying driver. If an intermediate driver converts the packet from one format to another, it also can allocate buffer descriptors to map intermediate-allocated buffers into which the converted data is copied. If there is OOB data associated with the packet descriptor being copied, this data can be copied to the new OOB block associated with the intermediate-allocated packet descriptor, using the macro NDIS_OOB_DATA_FROM_PACKET, to obtain a pointer to the OOB data area and, then, calling NdisMoveMemoryto move the contents into the OOB area associated with the new packet descriptor. Alternatively, such an intermediate driver can use the NDIS_GET_PACKET_ XXX and NDIS_SET_PACKET_XXX macros to read specific items from the OOB data associated with the old packet descriptor and to write the OOB data for the new packet descriptor.
Depending on the purpose of the intermediate driver, such a driver can repackage buffers that are chained to incoming packet descriptors. For example, an intermediate driver allocates buffer pool and repackages incoming packet data in the following circumstances:
The intermediate driver receives a larger data buffer from an overlying protocol driver than can be sent in a single buffer over the underlying medium. Consequently, the intermediate driver must divide the incoming data into smaller buffers.
The intermediate driver changes the length or content of the packet data by compressing or encrypting the data before forwarding each send to the underlying driver.
For Information about creating packet and buffer pools, see Allocating Packet Pools and Buffer Pools in a Protocol Driver.
Packet descriptors to meet typical needs can be allocated as needed, at driver initialization time, or in the ProtocolBindAdapterfunction. An intermediate driver developer can, if necessary and for performance reasons, allocate a number of packet descriptors and possibly buffers mapped by buffer descriptors at initialization time so that ProtocolReceivehas preallocated resources into which to copy incoming data for indicating to a higher-level driver, and so that MiniportSendor MiniportSendPacketshas available descriptors (and possibly buffers) to pass incoming send packets on to the next lower driver.
If an intermediate driver copies send data or received data to a new buffer or buffers, and the length of actual data in the last buffer is less than the allocated length of the buffer, the intermediate driver calls NdisAdjustBufferLengthto adjust the buffer descriptor to the actual length of the data. When the packet is returned to the intermediate driver, it should again make this call to readjust the length to the full length of its buffer.
An intermediate driver with a connectionless lower edge can receive incoming data from an underlying miniport driver by:
the data can be indicated to its ProtocolReceive function and copied into an intermediate-driver-supplied packet.
An intermediate driver with a connection-oriented lower edge always receives incoming data from an underlying miniport driver as a complete packet from its ProtocolCoReceivePacketfunction.
An intermediate driver can retain ownership of a received packet in the following circumstances:
When an intermediate driver with a connectionless lower edge has a complete packet indicated to its ProtocolReceivePacket function
When an intermediate driver with a connection-oriented lower edge has a packet indicated to its ProtocolCoReceivePacket function with the Status member of NDIS_PACKET_OOB_DATA set to anything other than NDIS_STATUS_RESOURCES
In these cases, the driver can retain ownership of the packet descriptor and the resources that it describes until the received data is consumed and return these resources to the underlying driver later by calling NdisReturnPackets. If ProtocolReceivePacketpasses the packets that it received to a higher-level driver, it must, at a minimum, replace the input packet descriptor with one that the intermediate driver has allocated.
Depending on an intermediate driver's purpose when it receives a full packet from an underlying driver, several packet-management strategies are possible. For example, it can do either of the following:
Copy the buffered contents into an intermediate driver-allocated buffer mapped and chained to a fresh packet descriptor, return the input packet descriptor to the underlying driver, and then indicate the new packet to the higher-level driver.
Create a new packet descriptor and chain the buffers from the indicated packet descriptor to this new descriptor. This new packet descriptor can then be indicated up to the higher-level driver. When this higher-level driver returns the packet descriptor, the intermediate driver must unchain the buffers from its packet descriptor, chain them to the packet descriptor it originally received from the underlying driver, and return the original packet descriptor and the resources that it describes to the underlying driver.
Even if an intermediate driver with a connectionless lower edge has a ProtocolReceivePacketfunction, it must also have a ProtocolReceivefunction. NDIS calls ProtocolReceivewhenever the underlying driver will not relinquish ownership of the resources it indicates with a packet descriptor, and the intermediate driver must copy the received data into its own buffers when such an indication occurs. If the underlying driver also indicates out-of-band data with receives, ProtocolReceivecan call NdisGetReceivedPacketand NDIS_GET_ORIGINAL_PACKETto get the per-packet information associated with the receive indication.
When an underlying connection-oriented miniport driver will not relinquish ownership of the resources that it indicates with a packet descriptor, it sets the Statusmember of the packet's NDIS_PACKET_OOB_DATA to NDIS_STATUS_RESOURCES. The ProtocolCoReceivePacketfunction of the intermediate driver then must copy the received data into its own buffers.
After NDIS returns an intermediate-driver-allocated packet descriptor to the intermediate driver by calling ProtocolSendComplete, ProtocolCoSendComplete, or by calling MiniportReturnPacket, the intermediate driver owns the packet descriptor and all the resources that it describes. If a higher-level or lower-level driver supplied the buffers chained to such a returned packet descriptor, the intermediate driver should return these resources back to the allocating driver promptly.
If the intermediate driver originally allocated the packet descriptor and/or the chained buffers, it can reclaim its resources and reuse them. For additional information about reusing packets, see Packet Reuse in a Protocol Driver.