4.4 Sending Packets

A miniport can use either of two ways to send packets:

  1. A miniport supplies a MiniportSendPackets function. In this case, the miniport is passed one or more packets at a time, passed in as an array of pointers to the packet descriptors.

  2. A miniport supplies a MiniportSend function. In this case, MiniportSend is always passed a single packet descriptor.

If a miniport registers both a MiniportSendPackets function and a MiniportSend function with NdisMRegisterMiniport, NDIS will call only MiniportSendPackets.

Multipacket Sends

The miniport that supports multipacket sends declares the following miniport function.

VOID
MiniportSendPackets(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PPNDIS_PACKET  PacketArray,
    IN UINT  NumberofPackets
    );

Each PacketArray is a pointer to an array of pointers to one or more packet descriptors. Each packet descriptor has associated OOB data, as described in Section 4.3. The OOB block allows a protocol driver to specify a time-to-send to a cooperating miniport (TimeToSend) that supports priority sends. The Status member of the OOB block is set by a miniport before returning from MiniportSendPackets to indicate the return value of the call. The other members of the NDIS_PACKET_OOB_DATA block are read-only to a miniport.

Any miniport that provides MiniportSendPackets and returns NDIS_STATUS_PENDING for any packet, must save the pointers to the individual packets for which it returns this pending status. When MiniportSendPackets returns, the array containing the pointers will be returned to the caller.

A miniport that does not have resources to send a packet can set the Status member to NDIS_STATUS_RESOURCES. In this case, NDIS will queue the packet(s) and then resubmit the packet(s) to the miniport when it completes a send by calling NdisMSendComplete or calls NdisMSendResourcesAvailable, whichever is called first.

The miniport sets the Status field of every packet before it returns from MiniportSendPackets, whether the packet is completed synchronously or asynchronously.

If the miniport completes the send synchronously, it should set the Status member of the OOB data in the packet with the status of the send, which is either NDIS_STATUS_SUCCESS, NDIS_STATUS_FAILURE, NDIS_STATUS_RESOURCES or a miniport-determined status. The miniport sets the Status member to NDIS_STATUS_PENDING if it keeps the packet and will complete the send later. If the miniport returns a status of NDIS_STATUS_RESOURCES for a packet in the array, NDIS will re-queue that packet and any following packets in the array and submit them later when the miniport indicates that it has available resource.

After MiniportSendPackets returns, the Status field of the OOB data is off-limits. This means that when the miniport later completes a packet for which it returned NDIS_STATUS_PENDING, that miniport must return the status of the send in the Status parameter of its call to NdisMSendComplete. The miniport must not write the Status member of the OOB data for any packets that are completed by calling NdisMSendComplete.

Single-Packet Sends

For a single packet send, a miniport NIC driver declares the following function.

NDIS_STATUS
MiniportSend(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET  Packet,
    IN UINT  Flags
    );

The Flags parameter has meaning as defined by cooperating protocol drivers and miniports; NDIS does not define nor make any assumptions about this parameter. However, NDIS provides a function, NdisGetPacketFlags, that is called by the miniport to retrieve the flags value. The miniport retains the packet until the send completes.

If a miniport can complete the send immediately, it returns NDIS_STATUS_SUCCESS, (or NDIS_STATUS_FAILURE if the send failed for any reason, or possibly a miniport-determined failure status) and relinquishes ownership of the packet back to the sender. The miniport always returns the send status as the status of MiniportSend; it never sets the Status member of the OOB data block for such a packet.

If a miniport cannot complete the send immediately, it returns NDIS_STATUS_PENDING. In this case, the miniport retains ownership of the packet until the send completes. For instance, the miniport might have queued the packet internally or started but not completed the send before returning a pending status. When the send completes, the miniport must call NdisMSendComplete passing a pointer to the packet descriptor that has been sent and relinquishing ownership of the packet resources back to the sender for reuse or to be freed.

Alternatively, if the miniport does not have resources for the send, it can return NDIS_STATUS_RESOURCES, in which case NDIS will queue the packet and resend it to MiniportSend later when the miniport calls NdisMSendResourcesAvailable or NdisMSendComplete indicating that it can now accept packets.