[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH 3/3] Introduce VIF interface version 4



This greatly simplifies the interface with XENNET by queuing single packets
on both the transmit and receive side, negating the need for a shared packet
structures and bringing static hash calculation into XENVIF.
Crucially this also means that XENNET no longer needs to use the
XENBUS_CACHE interface which allows it to be patched to avoid the race
introduced by commit 026aa32c "Make sure XENBUS interfaces are released when
going into S4".

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/revision.h       |   5 +-
 include/vif_interface.h  | 243 ++++++++++-------
 src/xenvif/frontend.c    |   3 +
 src/xenvif/frontend.h    |   5 +
 src/xenvif/receiver.c    | 295 ++++++++++++++-------
 src/xenvif/receiver.h    |   8 +-
 src/xenvif/transmitter.c | 660 ++++++++++++++++++++++++++++++++---------------
 src/xenvif/transmitter.h |  27 +-
 src/xenvif/vif.c         | 211 ++++++++++++---
 src/xenvif/vif.h         |  24 +-
 10 files changed, 1041 insertions(+), 440 deletions(-)

diff --git a/include/revision.h b/include/revision.h
index 77d1405..eda8871 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -42,6 +42,9 @@
 #define DEFINE_REVISION_TABLE                       \
     DEFINE_REVISION(0x08000002,  1,  2,  0,  0),    \
     DEFINE_REVISION(0x08000003,  1,  3,  0,  0),    \
-    DEFINE_REVISION(0x08000004,  1,  3,  2,  1)
+    DEFINE_REVISION(0x08000004,  1,  3,  2,  1),    \
+    DEFINE_REVISION(0x08000006,  1,  4,  2,  1)
+
+// Revision 0x08000005 is already in use in the staging-8.1 branch.
 
 #endif  // _REVISION_H
diff --git a/include/vif_interface.h b/include/vif_interface.h
index f6b6298..27c5d2d 100644
--- a/include/vif_interface.h
+++ b/include/vif_interface.h
@@ -43,6 +43,28 @@
 #include <ifdef.h>
 #include <ethernet.h>
 
+/*! \enum _XENVIF_PACKET_HASH_ALGORITHM
+    \brief Hash algorithm
+*/
+typedef enum _XENVIF_PACKET_HASH_ALGORITHM {
+    /*! None (value should be ignored) */
+    XENVIF_PACKET_HASH_ALGORITHM_NONE = 0,
+    /*! Unspecified hash (value can be used) */
+    XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED
+} XENVIF_PACKET_HASH_ALGORITHM, *PXENVIF_PACKET_HASH_ALGORITHM;
+
+/*! \struct _XENVIF_PACKET_HASH_V1
+    \brief Hash information
+*/
+struct _XENVIF_PACKET_HASH_V1 {
+    /*! Hash algorithm used to calculate value */
+    XENVIF_PACKET_HASH_ALGORITHM    Algorithm;
+    /*! Calculated value */
+    ULONG                           Value;
+};
+
+typedef struct _XENVIF_PACKET_HASH_V1 XENVIF_PACKET_HASH, *PXENVIF_PACKET_HASH;
+
 /*! \struct _XENVIF_PACKET_HEADER_V1
     \brief Packet header information
 */
@@ -53,14 +75,25 @@ struct  _XENVIF_PACKET_HEADER_V1 {
     ULONG   Length;
 };
 
-/*! \struct _XENVIF_PACKET_INFO_V1
+struct _XENVIF_PACKET_INFO_V1 {
+    ULONG                           Length;
+    USHORT                          TagControlInformation;
+    BOOLEAN                         IsAFragment;
+    struct _XENVIF_PACKET_HEADER_V1 EthernetHeader;
+    struct _XENVIF_PACKET_HEADER_V1 LLCSnapHeader;
+    struct _XENVIF_PACKET_HEADER_V1 IpHeader;
+    struct _XENVIF_PACKET_HEADER_V1 IpOptions;
+    struct _XENVIF_PACKET_HEADER_V1 TcpHeader;
+    struct _XENVIF_PACKET_HEADER_V1 TcpOptions;
+    struct _XENVIF_PACKET_HEADER_V1 UdpHeader;
+};
+
+/*! \struct _XENVIF_PACKET_INFO_V2
     \brief Packet information
 */
-struct _XENVIF_PACKET_INFO_V1 {
+struct _XENVIF_PACKET_INFO_V2 {
     /*! Total length of all headers */
     ULONG                           Length;
-    /*! VLAN TCI if present (0 indicates not present) */
-    USHORT                          TagControlInformation;
     /*! TRUE if the packet is an IP fragment */
     BOOLEAN                         IsAFragment;
     /*! Ethernet header (stripped of any VLAN tag) */
@@ -79,7 +112,7 @@ struct _XENVIF_PACKET_INFO_V1 {
     struct _XENVIF_PACKET_HEADER_V1 UdpHeader;
 };
 
-typedef struct _XENVIF_PACKET_INFO_V1   XENVIF_PACKET_INFO, 
*PXENVIF_PACKET_INFO;
+typedef struct _XENVIF_PACKET_INFO_V2   XENVIF_PACKET_INFO, 
*PXENVIF_PACKET_INFO;
 
 #pragma warning(push)
 #pragma warning(disable:4214)   // nonstandard extension used : bit field 
types other than int
@@ -120,32 +153,18 @@ typedef struct _XENVIF_PACKET_CHECKSUM_FLAGS_V1 
XENVIF_PACKET_CHECKSUM_FLAGS, *P
 
 #pragma warning(pop)
 
-/*! \struct _XENVIF_RECEIVER_PACKET_V1
-    \brief Receive-side packet structure
-*/
 struct _XENVIF_RECEIVER_PACKET_V1 {
-    /*! List entry used for chaining packets together */
     LIST_ENTRY                              ListEntry;
-    /*! Pointer to packet information */
     struct _XENVIF_PACKET_INFO_V1           *Info;
-    /*! Offset of start of packet in MDL */
     ULONG                                   Offset;
-    /*! Total length of packet */
     ULONG                                   Length;
-    /*! Checksum flags */
     struct _XENVIF_PACKET_CHECKSUM_FLAGS_V1 Flags;
-    /*! TCP MSS if the packet contains a TCP large segment */
     USHORT                                  MaximumSegmentSize;
-    /*! Opaque cookie used to store context information for packet return */
     PVOID                                   Cookie;
-    /*! MDL referencing the initial buffer of the packet */
     MDL                                     Mdl;
-    /*! PFN information, which must always follow an MDL */
     PFN_NUMBER                              __Pfn;
 };
 
-typedef struct _XENVIF_RECEIVER_PACKET_V1 XENVIF_RECEIVER_PACKET, 
*PXENVIF_RECEIVER_PACKET;
-
 #pragma warning(push)
 #pragma warning(disable:4214)   // nonstandard extension used : bit field 
types other than int
 #pragma warning(disable:4201)   // nonstandard extension used : nameless 
struct/union
@@ -190,32 +209,18 @@ typedef struct _XENVIF_VIF_OFFLOAD_OPTIONS_V1 
XENVIF_VIF_OFFLOAD_OPTIONS, *PXENV
 
 #pragma pack(push, 1) 
 
-/*! \struct _XENVIF_TRANSMITTER_PACKET_SEND_INFO_V1
-    \brief Packet information passed from subscriber to provider on
-    transmit side packet send
-
-    To fit into the reserved space in NDIS_PACKET and NET_BUFFER structures
-    this structure must be at most the size of 3 pointer types.
-*/
 struct _XENVIF_TRANSMITTER_PACKET_SEND_INFO_V1 {
-    /*! Offload options for this packet */
     XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions;
-    /*! TCP MSS (used only if OffloadOptions.OffloadIpVersion[4|6]LargePacket 
is set) */
     USHORT                      MaximumSegmentSize;
-    /*! VLAN TCI (used only if OffloadOptions.OffloadTagManipulation is set) */
     USHORT                      TagControlInformation;
 };
 
-typedef struct _XENVIF_TRANSMITTER_PACKET_SEND_INFO_V1 
XENVIF_TRANSMITTER_PACKET_SEND_INFO, *PXENVIF_TRANSMITTER_PACKET_SEND_INFO;
-
 /*! \enum _XENVIF_TRANSMITTER_PACKET_STATUS
     \brief Transmit-side packet status
 */
 typedef enum _XENVIF_TRANSMITTER_PACKET_STATUS {
-    /*! Packet was queued for the backend */
-    XENVIF_TRANSMITTER_PACKET_PENDING = 1,
     /*! Packet has been successfully processed by the backend */
-    XENVIF_TRANSMITTER_PACKET_OK,
+    XENVIF_TRANSMITTER_PACKET_OK = 2,
     /*! Packet was dropped */
     XENVIF_TRANSMITTER_PACKET_DROPPED,
     /*! There was a problem handling the packet */
@@ -244,30 +249,17 @@ typedef struct 
_XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO_V1 XENVIF_TRANSMITTER_
 
 #pragma pack(pop) 
 
-/*! \struct _XENVIF_TRANSMITTER_PACKET_V2
-    \brief Transmit-side packet structure (v2)
-*/
 struct _XENVIF_TRANSMITTER_PACKET_V2 {
-    /*! List entry used for chaining packets together */
-    LIST_ENTRY                                  ListEntry;
-    /*! Opaque cookie used to store context information for packet return */
-    PVOID                                       Cookie;
-    /*! Hash value set by subscriber */
-    ULONG                                       Value;
-    /*! Packet information passed from subscriber to provider */
-    XENVIF_TRANSMITTER_PACKET_SEND_INFO         Send;
-    /*! Packet information passed from provider to subscriber on packet return 
*/
-    XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO   Completion;
-    /*! Packet data MDL */
-    PMDL                                        Mdl;
-    /*! Offset into MDL to start of packet */
-    ULONG                                       Offset;
-    /*! Packet length */
-    ULONG                                       Length;
+    LIST_ENTRY                                              ListEntry;
+    PVOID                                                   Cookie;
+    ULONG                                                   Value;
+    struct _XENVIF_TRANSMITTER_PACKET_SEND_INFO_V1          Send;
+    struct _XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO_V1    Completion;
+    PMDL                                                    Mdl;
+    ULONG                                                   Offset;
+    ULONG                                                   Length;
 };
 
-typedef struct _XENVIF_TRANSMITTER_PACKET_V2 XENVIF_TRANSMITTER_PACKET, 
*PXENVIF_TRANSMITTER_PACKET;
-
 /*! \enum _XENVIF_VIF_STATISTIC
     \brief Interface statistics
 */
@@ -327,10 +319,10 @@ typedef enum _XENVIF_MAC_FILTER_LEVEL {
     \brief Type of callback (see \ref XENVIF_VIF_CALLBACK)
 */
 typedef enum _XENVIF_VIF_CALLBACK_TYPE {
-    /*! Return transmit side packets to the subscriber */
-    XENVIF_TRANSMITTER_RETURN_PACKETS = 0,
-    /*! Queue receive side packets at the subscriber */
-    XENVIF_RECEIVER_QUEUE_PACKETS,
+    /*! Return a transmit side packet to the subscriber */
+    XENVIF_TRANSMITTER_RETURN_PACKET = 0,
+    /*! Queue a receive side packet at the subscriber */
+    XENVIF_RECEIVER_QUEUE_PACKET,
     /*! Notify the subscriber of a MAC (link) state has change */
     XENVIF_MAC_STATE_CHANGE
 } XENVIF_VIF_CALLBACK_TYPE, *PXENVIF_VIF_CALLBACK_TYPE;
@@ -362,11 +354,19 @@ typedef VOID
     \param Type The callback type
     \param ... Additional paramaters required by \a Type
 
-    \b XENVIF_TRANSMITTER_RETURN_PACKETS:
-    \param Head The head of a chain of XENVIF_TRANSMITTER_PACKET
+    \b XENVIF_TRANSMITTER_RETURN_PACKET:
+    \param Cookie Cookie supplied to XENVIF_TRANSMITTER_QUEUE_PACKET
+    \param Completion Packet completion information
 
-    \b XENVIF_RECEIVER_QUEUE_PACKETS:
-    \param List List of XENVIF_TRANSMITTER_PACKET
+    \b XENVIF_RECEIVER_QUEUE_PACKET:
+    \param Mdl The initial MDL of the packet
+    \param Offset The offset of the packet data in the initial MDL
+    \param Length The total length of the packet
+    \param Flags Packet checksum flags
+    \param MaximumSegmentSize The TCP MSS (used only if 
OffloadOptions.OffloadIpVersion[4|6]LargePacket is set)
+    \param TagControlInformation The VLAN TCI (used only if 
OffloadOptions.OffloadTagManipulation is set)
+    \param Info Header information for the packet
+    \param Cookie Cookie that should be passed to 
XENVIF_RECEIVER_RETURN_PACKET method
 
     \b XENVIF_MAC_STATE_CHANGE:
     No additional arguments
@@ -427,47 +427,65 @@ typedef NTSTATUS
     OUT PULONGLONG              Value
     );
 
-/*! \typedef XENVIF_VIF_RECEIVER_RETURN_PACKETS
-    \brief Return packets queues for receive by \ref XENVIF_VIF_CALLBACK
-    (Type = \ref XENVIF_RECEIVER_QUEUE_PACKETS)
-
-    \param Interface The interface header
-    \param List List of \ref _XENVIF_RECEIVER_PACKET_V1
-*/
 typedef VOID
-(*XENVIF_VIF_RECEIVER_RETURN_PACKETS)(
+(*XENVIF_VIF_RECEIVER_RETURN_PACKETS_V1)(
     IN  PINTERFACE  Interface,
     IN  PLIST_ENTRY List
     );
 
-/*! \typedef XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS
-    \brief Get the packet headers into supplied buffer
+/*! \typedef XENVIF_VIF_RECEIVER_RETURN_PACKET
+    \brief Return packets queued for receive by \ref XENVIF_VIF_CALLBACK
+    (Type = \ref XENVIF_RECEIVER_QUEUE_PACKET)
 
     \param Interface The interface header
-    \param Packet The packet to acquire headers for.
-    \param Headers The buffer to receive headers.
-    \param Info The offsets into Headers for relevant headers
+    \param Cookie Cookie passed to XENVIF_RECEIVER_QUEUE_PACKET callback
 */
-typedef NTSTATUS
-(*XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS)(
-    IN  PINTERFACE                  Interface,
-    IN  PXENVIF_TRANSMITTER_PACKET  Packet,
-    OUT PVOID                       Headers,
-    OUT PXENVIF_PACKET_INFO         Info
+typedef VOID
+(*XENVIF_VIF_RECEIVER_RETURN_PACKET)(
+    IN  PINTERFACE  Interface,
+    IN  PVOID       Cookie
     );
 
-/*! \typedef XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS
-    \brief Queue transmit side packets at the provider
+typedef NTSTATUS
+(*XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS_V2)(
+    IN  PINTERFACE                              Interface,
+    IN  struct _XENVIF_TRANSMITTER_PACKET_V2    *Packet,
+    OUT PVOID                                   Headers,
+    OUT PXENVIF_PACKET_INFO                     Info
+    );
 
-    \param Interface The interface header
-    \param List List of XENVIF_TRANSMITTER_PACKET
-*/
 typedef NTSTATUS
-(*XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS)(
+(*XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS_V2)(
     IN  PINTERFACE  Interface,
     IN  PLIST_ENTRY List
     );
 
+/*! \typedef XENVIF_VIF_TRANSMITTER_QUEUE_PACKET
+    \brief Queue a packet at the provider's transmit side
+
+    \param Interface The interface header
+    \param Mdl The initial MDL of the packet
+    \param Offset The offset of the packet data in the initial MDL
+    \param Length The total length of the packet
+    \param OffloadOptions The requested offload options for this packet
+    \param MaximumSegmentSize The TCP MSS (used only if 
OffloadOptions.OffloadIpVersion[4|6]LargePacket is set)
+    \param TagControlInformation The VLAN TCI (used only if 
OffloadOptions.OffloadTagManipulation is set)
+    \param Hash Hash information for the packet
+    \param Cookie A cookie specified by the caller that will be passed to the 
XENVIF_TRANSMITTER_RETURN_PACKET callback
+*/
+typedef VOID
+(*XENVIF_VIF_TRANSMITTER_QUEUE_PACKET)(
+    IN  PINTERFACE                  Interface,
+    IN  PMDL                        Mdl,
+    IN  ULONG                       Offset,
+    IN  ULONG                       Length,
+    IN  XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions,
+    IN  USHORT                      MaximumSegmentSize,
+    IN  USHORT                      TagControlInformation,
+    IN  PXENVIF_PACKET_HASH         Hash,
+    IN  PVOID                       Cookie
+    );
+
 /*! \typedef XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS
     \brief Query the available set of transmit side offload options
 
@@ -524,7 +542,7 @@ typedef VOID
 
 /*! \typedef XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE
     \brief Query the maximum number of transmit side packets that can
-    be queued in the shared ring between frontend and backend
+    be queued in each shared ring between frontend and backend
 
     \param Interface The interface header
     \param Size Buffer to receive the maximum number of packets
@@ -537,7 +555,7 @@ typedef VOID
 
 /*! \typedef XENVIF_VIF_RECEIVER_QUERY_RING_SIZE
     \brief Query the maximum number of receive side packets that can
-    be queued in the shared ring between backend and frontend
+    be queued in each shared ring between backend and frontend
 
     \param Interface The interface header
     \param Size Buffer to receive the maximum number of packets
@@ -685,11 +703,11 @@ struct _XENVIF_VIF_INTERFACE_V2 {
     XENVIF_VIF_ENABLE                               Enable;
     XENVIF_VIF_DISABLE                              Disable;
     XENVIF_VIF_QUERY_STATISTIC                      QueryStatistic;
-    XENVIF_VIF_RECEIVER_RETURN_PACKETS              ReceiverReturnPackets;
+    XENVIF_VIF_RECEIVER_RETURN_PACKETS_V1           
ReceiverReturnPacketsVersion1;
     XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS         ReceiverSetOffloadOptions;
     XENVIF_VIF_RECEIVER_QUERY_RING_SIZE             ReceiverQueryRingSize;
-    XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS       
TransmitterGetPacketHeaders;
-    XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS            TransmitterQueuePackets;
+    XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS_V2    
TransmitterGetPacketHeadersVersion2;
+    XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS_V2         
TransmitterQueuePacketsVersion2;
     XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS    
TransmitterQueryOffloadOptions;
     XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE  
TransmitterQueryLargePacketSize;
     XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE          TransmitterQueryRingSize;
@@ -714,12 +732,41 @@ struct _XENVIF_VIF_INTERFACE_V3 {
     XENVIF_VIF_ENABLE                               Enable;
     XENVIF_VIF_DISABLE                              Disable;
     XENVIF_VIF_QUERY_STATISTIC                      QueryStatistic;
-    XENVIF_VIF_RECEIVER_RETURN_PACKETS              ReceiverReturnPackets;
+    XENVIF_VIF_RECEIVER_RETURN_PACKETS_V1           
ReceiverReturnPacketsVersion1;
+    XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS         ReceiverSetOffloadOptions;
+    XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE           ReceiverSetBackfillSize;
+    XENVIF_VIF_RECEIVER_QUERY_RING_SIZE             ReceiverQueryRingSize;
+    XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS_V2    
TransmitterGetPacketHeadersVersion2;
+    XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS_V2         
TransmitterQueuePacketsVersion2;
+    XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS    
TransmitterQueryOffloadOptions;
+    XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE  
TransmitterQueryLargePacketSize;
+    XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE          TransmitterQueryRingSize;
+    XENVIF_VIF_MAC_QUERY_STATE                      MacQueryState;
+    XENVIF_VIF_MAC_QUERY_MAXIMUM_FRAME_SIZE         MacQueryMaximumFrameSize;
+    XENVIF_VIF_MAC_QUERY_PERMANENT_ADDRESS          MacQueryPermanentAddress;
+    XENVIF_VIF_MAC_QUERY_CURRENT_ADDRESS            MacQueryCurrentAddress;
+    XENVIF_VIF_MAC_QUERY_MULTICAST_ADDRESSES        MacQueryMulticastAddresses;
+    XENVIF_VIF_MAC_SET_MULTICAST_ADDRESSES          MacSetMulticastAddresses;
+    XENVIF_VIF_MAC_SET_FILTER_LEVEL                 MacSetFilterLevel;
+    XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
+};
+
+/*! \struct _XENVIF_VIF_INTERFACE_V4
+    \brief VIF interface version 4
+    \ingroup interfaces
+*/
+struct _XENVIF_VIF_INTERFACE_V4 {
+    INTERFACE                                       Interface;
+    XENVIF_VIF_ACQUIRE                              Acquire;
+    XENVIF_VIF_RELEASE                              Release;
+    XENVIF_VIF_ENABLE                               Enable;
+    XENVIF_VIF_DISABLE                              Disable;
+    XENVIF_VIF_QUERY_STATISTIC                      QueryStatistic;
+    XENVIF_VIF_RECEIVER_RETURN_PACKET               ReceiverReturnPacket;
     XENVIF_VIF_RECEIVER_SET_OFFLOAD_OPTIONS         ReceiverSetOffloadOptions;
     XENVIF_VIF_RECEIVER_SET_BACKFILL_SIZE           ReceiverSetBackfillSize;
     XENVIF_VIF_RECEIVER_QUERY_RING_SIZE             ReceiverQueryRingSize;
-    XENVIF_VIF_TRANSMITTER_GET_PACKET_HEADERS       
TransmitterGetPacketHeaders;
-    XENVIF_VIF_TRANSMITTER_QUEUE_PACKETS            TransmitterQueuePackets;
+    XENVIF_VIF_TRANSMITTER_QUEUE_PACKET             TransmitterQueuePacket;
     XENVIF_VIF_TRANSMITTER_QUERY_OFFLOAD_OPTIONS    
TransmitterQueryOffloadOptions;
     XENVIF_VIF_TRANSMITTER_QUERY_LARGE_PACKET_SIZE  
TransmitterQueryLargePacketSize;
     XENVIF_VIF_TRANSMITTER_QUERY_RING_SIZE          TransmitterQueryRingSize;
@@ -733,7 +780,7 @@ struct _XENVIF_VIF_INTERFACE_V3 {
     XENVIF_VIF_MAC_QUERY_FILTER_LEVEL               MacQueryFilterLevel;
 };
 
-typedef struct _XENVIF_VIF_INTERFACE_V3 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
+typedef struct _XENVIF_VIF_INTERFACE_V4 XENVIF_VIF_INTERFACE, 
*PXENVIF_VIF_INTERFACE;
 
 /*! \def XENVIF_VIF
     \brief Macro at assist in method invocation
@@ -744,6 +791,6 @@ typedef struct _XENVIF_VIF_INTERFACE_V3 
XENVIF_VIF_INTERFACE, *PXENVIF_VIF_INTER
 #endif  // _WINDLL
 
 #define XENVIF_VIF_INTERFACE_VERSION_MIN    2
-#define XENVIF_VIF_INTERFACE_VERSION_MAX    3
+#define XENVIF_VIF_INTERFACE_VERSION_MAX    4
 
 #endif  // _XENVIF_INTERFACE_H
diff --git a/src/xenvif/frontend.c b/src/xenvif/frontend.c
index b066d0b..a43a534 100644
--- a/src/xenvif/frontend.c
+++ b/src/xenvif/frontend.c
@@ -56,6 +56,7 @@ typedef struct _XENVIF_FRONTEND_STATISTICS {
     ULONGLONG   Value[XENVIF_VIF_STATISTIC_COUNT];
 } XENVIF_FRONTEND_STATISTICS, *PXENVIF_FRONTEND_STATISTICS;
 
+
 struct _XENVIF_FRONTEND {
     PXENVIF_PDO                 Pdo;
     PCHAR                       Path;
@@ -1898,6 +1899,7 @@ fail5:
 
     MacDisconnect(__FrontendGetMac(Frontend));
 
+    Frontend->Split = FALSE;
     Frontend->NumQueues = 0;
 
 fail4:
@@ -1938,6 +1940,7 @@ FrontendDisconnect(
     ReceiverDisconnect(__FrontendGetReceiver(Frontend));
     MacDisconnect(__FrontendGetMac(Frontend));
 
+    Frontend->Split = FALSE;
     Frontend->NumQueues = 0;
 
     XENBUS_DEBUG(Deregister,
diff --git a/src/xenvif/frontend.h b/src/xenvif/frontend.h
index eda9e3d..d90f977 100644
--- a/src/xenvif/frontend.h
+++ b/src/xenvif/frontend.h
@@ -127,6 +127,11 @@ FrontendIsSplit(
     IN  PXENVIF_FRONTEND    Frontend
     );
 
+extern BOOLEAN
+FrontendIsSplit(
+    IN  PXENVIF_FRONTEND    Frontend
+    );
+
 extern PCHAR
 FrontendFormatPath(
     IN  PXENVIF_FRONTEND    Frontend,
diff --git a/src/xenvif/receiver.c b/src/xenvif/receiver.c
index 030f84f..53f322f 100644
--- a/src/xenvif/receiver.c
+++ b/src/xenvif/receiver.c
@@ -105,6 +105,19 @@ typedef struct _XENVIF_RECEIVER_RING {
     LIST_ENTRY                  PacketList;
 } XENVIF_RECEIVER_RING, *PXENVIF_RECEIVER_RING;
 
+typedef struct _XENVIF_RECEIVER_PACKET {
+    LIST_ENTRY                      ListEntry;
+    XENVIF_PACKET_INFO              Info;
+    ULONG                           Offset;
+    ULONG                           Length;
+    XENVIF_PACKET_CHECKSUM_FLAGS    Flags;
+    USHORT                          MaximumSegmentSize;
+    USHORT                          TagControlInformation;
+    PXENVIF_RECEIVER_RING           Ring;
+    MDL                             Mdl;
+    PFN_NUMBER                      __Pfn;
+} XENVIF_RECEIVER_PACKET, *PXENVIF_RECEIVER_PACKET;
+
 struct _XENVIF_RECEIVER {
     PXENVIF_FRONTEND        Frontend;
     XENBUS_CACHE_INTERFACE  CacheInterface;
@@ -149,29 +162,19 @@ ReceiverPacketCtor(
     IN  PVOID               Object
     )
 {
+    PXENVIF_RECEIVER_RING   Ring = Argument;
     PXENVIF_RECEIVER_PACKET Packet = Object;
-    PXENVIF_PACKET_INFO     Info;
-    PMDL                           Mdl;
-    PUCHAR                     StartVa;
-    NTSTATUS                   status;
-
-    UNREFERENCED_PARAMETER(Argument);
+    PMDL                    Mdl;
+    PUCHAR                  StartVa;
+    NTSTATUS                status;
 
     ASSERT(IsZeroMemory(Packet, sizeof (XENVIF_RECEIVER_PACKET)));
 
-    Info = __ReceiverAllocate(sizeof (XENVIF_PACKET_INFO));
-
-    status = STATUS_NO_MEMORY;
-    if (Info == NULL)
-        goto fail1;
-
-    Packet->Info = Info;
-
     Mdl = __AllocatePage();
 
     status = STATUS_NO_MEMORY;
     if (Mdl == NULL)
-        goto fail2;
+        goto fail1;
 
     StartVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
     ASSERT(StartVa != NULL);
@@ -186,13 +189,9 @@ ReceiverPacketCtor(
 
     ExFreePool(Mdl);
 
-    return STATUS_SUCCESS;
+    Packet->Ring = Ring;
 
-fail2:
-    Error("fail2\n");
-
-    __ReceiverFree(Info);
-    Packet->Info = NULL;
+    return STATUS_SUCCESS;
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -208,11 +207,12 @@ ReceiverPacketDtor(
     IN  PVOID               Object
     )
 {
+    PXENVIF_RECEIVER_RING   Ring = Argument;
     PXENVIF_RECEIVER_PACKET Packet = Object;
     PMDL                    Mdl;
-    PXENVIF_PACKET_INFO     Info;
 
-    UNREFERENCED_PARAMETER(Argument);
+    ASSERT3P(Packet->Ring, ==, Ring);
+    Packet->Ring = NULL;
 
     Mdl = &Packet->Mdl;
 
@@ -222,11 +222,6 @@ ReceiverPacketDtor(
 
     RtlZeroMemory(Mdl, sizeof (MDL) + sizeof (PFN_NUMBER));
 
-    Info = Packet->Info;
-
-    __ReceiverFree(Info);
-    Packet->Info = NULL;
-
     ASSERT(IsZeroMemory(Packet, sizeof (XENVIF_RECEIVER_PACKET)));
 }
 
@@ -248,7 +243,7 @@ __ReceiverRingGetPacket(
                           Ring->PacketCache,
                           Locked);
 
-    ASSERT(IsZeroMemory(Packet->Info, sizeof (XENVIF_PACKET_INFO)));
+    ASSERT(IsZeroMemory(&Packet->Info, sizeof (XENVIF_PACKET_INFO)));
 
     return Packet;
 }
@@ -273,9 +268,9 @@ __ReceiverRingPutPacket(
     Packet->Length = 0;
     Packet->Flags.Value = 0;
     Packet->MaximumSegmentSize = 0;
-    Packet->Cookie = NULL;
+    Packet->TagControlInformation = 0;
 
-    RtlZeroMemory(Packet->Info, sizeof (XENVIF_PACKET_INFO));
+    RtlZeroMemory(&Packet->Info, sizeof (XENVIF_PACKET_INFO));
 
     Mdl->MappedSystemVa = Mdl->StartVa;
     Mdl->ByteOffset = 0;
@@ -395,7 +390,7 @@ ReceiverRingProcessTag(
     PETHERNET_HEADER             EthernetHeader;
     ULONG                        Offset;
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
 
     PayloadLength = Packet->Length - Info->Length;
 
@@ -410,7 +405,7 @@ ReceiverRingProcessTag(
         Ring->OffloadOptions.OffloadTagManipulation == 0)
         return;
 
-    Info->TagControlInformation = 
NTOHS(EthernetHeader->Tagged.Tag.ControlInformation);
+    Packet->TagControlInformation = 
NTOHS(EthernetHeader->Tagged.Tag.ControlInformation);
 
     Offset = FIELD_OFFSET(ETHERNET_TAGGED_HEADER, Tag);
     RtlMoveMemory((PUCHAR)EthernetHeader + sizeof (ETHERNET_TAG),
@@ -464,7 +459,7 @@ ReceiverRingProcessChecksum(
 
     Receiver = Ring->Receiver;
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
 
     Payload.Mdl = &Packet->Mdl;
     Payload.Offset = Packet->Offset + Info->Length;
@@ -478,8 +473,8 @@ ReceiverRingProcessChecksum(
         Payload.Offset = 0;
     }
 
-    flags = (uint16_t)(ULONG_PTR)Packet->Cookie;
-    ASSERT3U(Packet->Flags.Value, ==, 0);
+    flags = (uint16_t)Packet->Flags.Value;
+    Packet->Flags.Value = 0;
 
     if (Info->IpHeader.Length == 0)
         return;
@@ -743,7 +738,7 @@ __ReceiverRingBuildSegment(
 
     Receiver = Ring->Receiver;
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
 
     InfoVa = MmGetSystemAddressForMdlSafe(&Packet->Mdl, NormalPagePriority);
     ASSERT(InfoVa != NULL);
@@ -755,7 +750,11 @@ __ReceiverRingBuildSegment(
     if (Segment == NULL)
         goto fail1;
 
+    Segment->Info = Packet->Info;
     Segment->Offset = Packet->Offset;
+    Segment->Flags = Packet->Flags;
+    Segment->MaximumSegmentSize = Packet->MaximumSegmentSize;
+    Segment->TagControlInformation = Packet->TagControlInformation;
 
     Mdl = &Segment->Mdl;
 
@@ -769,9 +768,6 @@ __ReceiverRingBuildSegment(
     RtlCopyMemory(StartVa, InfoVa, Info->Length);
     Mdl->ByteCount += Info->Length;
 
-    *Segment->Info = *Packet->Info;
-    Segment->Cookie = Packet->Cookie;
-
     // Adjust the info for the next segment
     IpHeader = (PIP_HEADER)(InfoVa + Info->IpHeader.Offset);
     if (IpHeader->Version == 4) {
@@ -916,11 +912,11 @@ ReceiverRingProcessLargePacket(
     Receiver = Ring->Receiver;
     Frontend = Receiver->Frontend;
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
     ASSERT(Info->IpHeader.Offset != 0);
     ASSERT(Info->TcpHeader.Offset != 0);
     
-    flags = (uint16_t)(ULONG_PTR)Packet->Cookie;
+    flags = (uint16_t)Packet->Flags.Value;
     ASSERT(flags & NETRXF_csum_blank);
     ASSERT(flags & NETRXF_data_validated);
 
@@ -1089,7 +1085,7 @@ ReceiverRingProcessStandardPacket(
     Frontend = Receiver->Frontend;
     Mac = FrontendGetMac(Frontend);
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
 
     Payload.Mdl = Packet->Mdl.Next;
     Payload.Offset = 0;
@@ -1177,24 +1173,24 @@ fail1:
 
 static VOID
 ReceiverRingProcessPacket(
-    IN  PXENVIF_RECEIVER_RING   Ring,
-    IN  PXENVIF_RECEIVER_PACKET Packet,
-    OUT PLIST_ENTRY             List
+    IN  PXENVIF_RECEIVER_RING       Ring,
+    IN  PXENVIF_RECEIVER_PACKET     Packet,
+    OUT PLIST_ENTRY                 List
     )
 {
-    PXENVIF_RECEIVER            Receiver;
-    PXENVIF_FRONTEND            Frontend;
-    PXENVIF_MAC                 Mac;
-    ULONG                       Length;
-    USHORT                      MaximumSegmentSize;
-    PVOID                       Cookie;
-    XENVIF_PACKET_PAYLOAD       Payload;
-    PXENVIF_PACKET_INFO         Info;
-    PUCHAR                      StartVa;
-    PETHERNET_HEADER            EthernetHeader;
-    PETHERNET_ADDRESS           DestinationAddress;
-    ETHERNET_ADDRESS_TYPE       Type;
-    NTSTATUS                    status;
+    PXENVIF_RECEIVER                Receiver;
+    PXENVIF_FRONTEND                Frontend;
+    PXENVIF_MAC                     Mac;
+    ULONG                           Length;
+    XENVIF_PACKET_CHECKSUM_FLAGS    Flags;
+    USHORT                          MaximumSegmentSize;
+    XENVIF_PACKET_PAYLOAD           Payload;
+    PXENVIF_PACKET_INFO             Info;
+    PUCHAR                          StartVa;
+    PETHERNET_HEADER                EthernetHeader;
+    PETHERNET_ADDRESS               DestinationAddress;
+    ETHERNET_ADDRESS_TYPE           Type;
+    NTSTATUS                        status;
 
     Receiver = Ring->Receiver;
     Frontend = Receiver->Frontend;
@@ -1202,8 +1198,9 @@ ReceiverRingProcessPacket(
 
     ASSERT3U(Packet->Offset, ==, 0);
     Length = Packet->Length;
+    Flags = Packet->Flags;
     MaximumSegmentSize = Packet->MaximumSegmentSize;
-    Cookie = Packet->Cookie;
+    ASSERT3U(Packet->TagControlInformation, ==, 0);
 
     Payload.Mdl = &Packet->Mdl;
     Payload.Offset = 0;
@@ -1223,8 +1220,8 @@ ReceiverRingProcessPacket(
     // Copy in the extracted metadata
     Packet->Offset = Receiver->IpAlignOffset;
     Packet->Length = Length;
+    Packet->Flags = Flags;
     Packet->MaximumSegmentSize = MaximumSegmentSize;
-    Packet->Cookie = Cookie;
 
     StartVa = MmGetSystemAddressForMdlSafe(&Packet->Mdl, NormalPagePriority);
     ASSERT(StartVa != NULL);
@@ -1232,7 +1229,7 @@ ReceiverRingProcessPacket(
 
     Packet->Mdl.ByteCount = Packet->Offset;
 
-    Info = Packet->Info;
+    Info = &Packet->Info;
 
     status = ParsePacket(StartVa, ReceiverRingPullup, Ring, &Payload, Info);
     if (!NT_SUCCESS(status)) {
@@ -1361,8 +1358,6 @@ ReceiverRingProcessPackets(
         ReceiverRingProcessTag(Ring, Packet);
         ReceiverRingProcessChecksum(Ring, Packet);
 
-        Packet->Cookie = Ring;
-
         (*Count)++;
     }
 }
@@ -1378,6 +1373,79 @@ __ReceiverRingAcquireLock(
     KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
 }
 
+static FORCEINLINE VOID
+__ReceiverQueuePacketVersion1(
+    IN  PXENVIF_RECEIVER                Receiver,
+    IN  PMDL                            Mdl,
+    IN  ULONG                           Offset,
+    IN  ULONG                           Length,
+    IN  XENVIF_PACKET_CHECKSUM_FLAGS    Flags,
+    IN  USHORT                          MaximumSegmentSize,
+    IN  USHORT                          TagControlInformation,
+    IN  PXENVIF_PACKET_INFO             Info,
+    IN  PVOID                           Cookie
+    )
+{
+    struct _XENVIF_PACKET_INFO_V1       *InfoVersion1;
+    struct _XENVIF_RECEIVER_PACKET_V1   *PacketVersion1;
+    PXENVIF_FRONTEND                    Frontend;
+    PXENVIF_VIF_CONTEXT                 Context;
+    LIST_ENTRY                          List;
+    NTSTATUS                            status;
+
+    InfoVersion1 = __ReceiverAllocate(sizeof (struct _XENVIF_PACKET_INFO_V1));
+
+    status = STATUS_NO_MEMORY;
+    if (InfoVersion1 == NULL)
+        goto fail1;
+
+    InfoVersion1->Length = Info->Length;
+    InfoVersion1->TagControlInformation = TagControlInformation;
+    InfoVersion1->IsAFragment = Info->IsAFragment;
+    InfoVersion1->EthernetHeader = Info->EthernetHeader;
+    InfoVersion1->LLCSnapHeader = Info->LLCSnapHeader;
+    InfoVersion1->IpHeader = Info->IpHeader;
+    InfoVersion1->IpOptions = Info->IpOptions;
+    InfoVersion1->TcpHeader = Info->TcpHeader;
+    InfoVersion1->TcpOptions = Info->TcpOptions;
+    InfoVersion1->UdpHeader = Info->UdpHeader;
+
+    PacketVersion1 = __ReceiverAllocate(sizeof (struct 
_XENVIF_RECEIVER_PACKET_V1));
+
+    status = STATUS_NO_MEMORY;
+    if (PacketVersion1 == NULL)
+        goto fail2;
+
+    PacketVersion1->Info = InfoVersion1;
+    PacketVersion1->Offset = Offset;
+    PacketVersion1->Length = Length;
+    PacketVersion1->Flags = Flags;
+    PacketVersion1->MaximumSegmentSize = MaximumSegmentSize;
+    PacketVersion1->Cookie = Cookie;
+    PacketVersion1->Mdl = *Mdl;
+    PacketVersion1->__Pfn = MmGetMdlPfnArray(Mdl)[0];
+
+    Frontend = Receiver->Frontend;
+    Context = PdoGetVifContext(FrontendGetPdo(Frontend));
+
+    InitializeListHead(&List);
+
+    InsertTailList(&List, &PacketVersion1->ListEntry);
+
+    VifReceiverQueuePacketsVersion1(Context, &List);
+    ASSERT(IsListEmpty(&List));
+
+    return;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    ReceiverReturnPacket(Receiver, Cookie);
+}
+
 static DECLSPEC_NOINLINE VOID
 ReceiverRingAcquireLock(
     IN  PXENVIF_RECEIVER_RING   Ring
@@ -1393,12 +1461,18 @@ __ReceiverRingReleaseLock(
     )
 {
     PXENVIF_RECEIVER            Receiver;
+    PXENVIF_FRONTEND            Frontend;
+    PXENVIF_VIF_CONTEXT         Context;
+    ULONG                       Version;
     LIST_ENTRY                  List;
     ULONG                       Count;
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
     Receiver = Ring->Receiver;
+    Frontend = Receiver->Frontend;
+    Context = PdoGetVifContext(FrontendGetPdo(Frontend));
+    Version = VifGetVersion(Context);
 
     InitializeListHead(&List);
     Count = 0;
@@ -1415,13 +1489,39 @@ __ReceiverRingReleaseLock(
 #pragma prefast(disable:26110)
     KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
 
-    if (!IsListEmpty(&List)) {
-        PXENVIF_FRONTEND    Frontend;
+    while (!IsListEmpty(&List)) {
+        PLIST_ENTRY             ListEntry;
+        PXENVIF_RECEIVER_PACKET Packet;
 
-        Frontend = Receiver->Frontend;
+        ListEntry = RemoveHeadList(&List);
+        ASSERT3P(ListEntry, !=, &List);
 
-        VifReceiverQueuePackets(PdoGetVifContext(FrontendGetPdo(Frontend)),
-                                &List);
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        Packet = CONTAINING_RECORD(ListEntry,
+                                   XENVIF_RECEIVER_PACKET,
+                                   ListEntry);
+
+        if (Version < 4)
+            __ReceiverQueuePacketVersion1(Receiver,
+                                          &Packet->Mdl,
+                                          Packet->Offset,
+                                          Packet->Length,
+                                          Packet->Flags,
+                                          Packet->MaximumSegmentSize,
+                                          Packet->TagControlInformation,
+                                          &Packet->Info,
+                                          Packet);
+        else
+            VifReceiverQueuePacket(Context,
+                                   &Packet->Mdl,
+                                   Packet->Offset,
+                                   Packet->Length,
+                                   Packet->Flags,
+                                   Packet->MaximumSegmentSize,
+                                   Packet->TagControlInformation,
+                                   &Packet->Info,
+                                   Packet);
     }
 
     ASSERT(IsListEmpty(&List));
@@ -1902,7 +2002,6 @@ ReceiverRingPoll(
 
             if (~rsp->flags & NETRXF_more_data) {  // EOP
                 ASSERT(Packet != NULL);
-                ASSERT3P(Packet->Cookie, ==, NULL);
 
                 if (Error) {
                     FrontendIncrementStatistic(Frontend,
@@ -1916,7 +2015,7 @@ ReceiverRingPoll(
                         Packet->MaximumSegmentSize = MaximumSegmentSize;
                     }
 
-                    Packet->Cookie = (PVOID)(flags & (NETRXF_csum_blank | 
NETRXF_data_validated));
+                    Packet->Flags.Value = flags & (NETRXF_csum_blank | 
NETRXF_data_validated);
 
                     ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof 
(LIST_ENTRY)));
                     InsertTailList(&Ring->PacketList, &Packet->ListEntry);
@@ -3345,35 +3444,21 @@ ReceiverQueryRingSize(
 }
 
 VOID
-ReceiverReturnPackets(
+ReceiverReturnPacket(
     IN  PXENVIF_RECEIVER    Receiver,
-    IN  PLIST_ENTRY         List
+    IN  PVOID               Cookie
     )
 {
-    ULONG                   Count;
+    PXENVIF_RECEIVER_PACKET Packet = Cookie;
+    PXENVIF_RECEIVER_RING   Ring;
     LONG                    Loaned;
     LONG                    Returned;
 
-    Count = 0;
-    while (!IsListEmpty(List)) {
-        PLIST_ENTRY             ListEntry;
-        PXENVIF_RECEIVER_PACKET Packet;
-        PXENVIF_RECEIVER_RING   Ring;
-
-        ListEntry = RemoveHeadList(List);
-        ASSERT3P(ListEntry, !=, List);
-
-        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
-
-        Packet = CONTAINING_RECORD(ListEntry, XENVIF_RECEIVER_PACKET, 
ListEntry);
-
-        Ring = Packet->Cookie;
+    Ring = Packet->Ring;
 
-        __ReceiverRingReturnPacket(Ring, Packet, FALSE);
-        Count++;
-    }
+    __ReceiverRingReturnPacket(Ring, Packet, FALSE);
 
-    Returned = __InterlockedAdd(&Receiver->Returned, Count);
+    Returned = InterlockedIncrement(&Receiver->Returned);
 
     // Make sure Loaned is not sampled before Returned
     KeMemoryBarrier();
@@ -3386,6 +3471,32 @@ ReceiverReturnPackets(
 }
 
 VOID
+ReceiverReturnPacketsVersion1(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  PLIST_ENTRY         List
+    )
+{
+    while (!IsListEmpty(List)) {
+        PLIST_ENTRY                         ListEntry;
+        struct _XENVIF_RECEIVER_PACKET_V1   *PacketVersion1;
+
+        ListEntry = RemoveHeadList(List);
+        ASSERT3P(ListEntry, !=, List);
+
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        PacketVersion1 = CONTAINING_RECORD(ListEntry,
+                                           struct _XENVIF_RECEIVER_PACKET_V1,
+                                           ListEntry);
+
+        ReceiverReturnPacket(Receiver, PacketVersion1->Cookie);
+
+        __ReceiverFree(PacketVersion1->Info);
+        __ReceiverFree(PacketVersion1);
+    }
+}
+
+VOID
 ReceiverWaitForPackets(
     IN  PXENVIF_RECEIVER    Receiver
     )
diff --git a/src/xenvif/receiver.h b/src/xenvif/receiver.h
index e4ab7a7..042e1da 100644
--- a/src/xenvif/receiver.h
+++ b/src/xenvif/receiver.h
@@ -101,12 +101,18 @@ ReceiverSetBackfillSize(
     );
 
 extern VOID
-ReceiverReturnPackets(
+ReceiverReturnPacketsVersion1(
     IN  PXENVIF_RECEIVER    Receiver,
     IN  PLIST_ENTRY         List
     );
 
 extern VOID
+ReceiverReturnPacket(
+    IN  PXENVIF_RECEIVER    Receiver,
+    IN  PVOID               Cookie
+    );
+
+extern VOID
 ReceiverSend(
     IN  PXENVIF_RECEIVER    Receiver,
     IN  ULONG               Index
diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c
index 35ec80a..75bf5fe 100644
--- a/src/xenvif/transmitter.c
+++ b/src/xenvif/transmitter.c
@@ -64,6 +64,24 @@
 
 #define MAXNAMELEN  128
 
+#define XENVIF_TRANSMITTER_MAXIMUM_HEADER_LENGTH    512
+
+typedef struct _XENVIF_TRANSMITTER_PACKET {
+    LIST_ENTRY                                  ListEntry;
+    PVOID                                       Cookie;
+    ULONG                                       Reference;
+    XENVIF_VIF_OFFLOAD_OPTIONS                  OffloadOptions;
+    USHORT                                      MaximumSegmentSize;
+    USHORT                                      TagControlInformation;
+    XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO   Completion;
+    PMDL                                        Mdl;
+    ULONG                                       Offset;
+    ULONG                                       Length;
+    PUCHAR                                      Header;
+    XENVIF_PACKET_INFO                          Info;
+    XENVIF_PACKET_PAYLOAD                       Payload;
+} XENVIF_TRANSMITTER_PACKET, *PXENVIF_TRANSMITTER_PACKET;
+
 typedef struct _XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS {
     IPV4_ADDRESS    Address;
 } XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS, 
*PXENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS;
@@ -139,10 +157,6 @@ typedef struct _XENVIF_TRANSMITTER_FRAGMENT {
 
 typedef struct _XENVIF_TRANSMITTER_STATE {
     PXENVIF_TRANSMITTER_PACKET          Packet;
-    XENVIF_TRANSMITTER_PACKET_SEND_INFO Send;
-    PUCHAR                              StartVa;
-    XENVIF_PACKET_INFO                  Info;
-    XENVIF_PACKET_PAYLOAD               Payload;
     LIST_ENTRY                          List;
     ULONG                               Count;
 } XENVIF_TRANSMITTER_STATE, *PXENVIF_TRANSMITTER_STATE;
@@ -252,24 +266,54 @@ TransmitterPacketReleaseLock(
 
 static NTSTATUS
 TransmitterPacketCtor(
-    IN  PVOID   Argument,
-    IN  PVOID   Object
+    IN  PVOID                   Argument,
+    IN  PVOID                   Object
     )
 {
+    PXENVIF_TRANSMITTER_PACKET  Packet = Object;
+    PUCHAR                      Header;
+    NTSTATUS                    status;
+
     UNREFERENCED_PARAMETER(Argument);
-    UNREFERENCED_PARAMETER(Object);
+
+    ASSERT(IsZeroMemory(Packet, sizeof (XENVIF_TRANSMITTER_PACKET)));
+
+    Header = __TransmitterAllocate(XENVIF_TRANSMITTER_MAXIMUM_HEADER_LENGTH);
+
+    status = STATUS_NO_MEMORY;
+    if (Header == NULL)
+        goto fail1;
+
+    Packet->Header = Header;
 
     return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    ASSERT(IsZeroMemory(Packet, sizeof (XENVIF_TRANSMITTER_PACKET)));
+
+    return status;
 }
 
 static VOID
 TransmitterPacketDtor(
-    IN  PVOID   Argument,
-    IN  PVOID   Object
+    IN  PVOID                   Argument,
+    IN  PVOID                   Object
     )
 {
+    PXENVIF_TRANSMITTER_PACKET  Packet = Object;
+    PUCHAR                      Header;
+
     UNREFERENCED_PARAMETER(Argument);
-    UNREFERENCED_PARAMETER(Object);
+
+    Header = Packet->Header;
+    Packet->Header = NULL;
+
+    ASSERT(IsZeroMemory(Header, XENVIF_TRANSMITTER_MAXIMUM_HEADER_LENGTH));
+    __TransmitterFree(Header);
+
+    ASSERT(IsZeroMemory(Packet, sizeof (XENVIF_TRANSMITTER_PACKET)));
 }
 
 static FORCEINLINE PXENVIF_TRANSMITTER_PACKET
@@ -289,7 +333,21 @@ __TransmitterPutPacket(
     IN  PXENVIF_TRANSMITTER_PACKET  Packet
     )
 {
-    RtlZeroMemory(Packet, sizeof(XENVIF_TRANSMITTER_PACKET));
+    ASSERT(IsZeroMemory(&Packet->ListEntry, sizeof (LIST_ENTRY)));
+    ASSERT3U(Packet->Reference, ==, 0);
+
+    Packet->Mdl = NULL;
+    Packet->Offset = 0;
+    Packet->Length = 0;
+    Packet->OffloadOptions.Value = 0;
+    Packet->MaximumSegmentSize = 0;
+    Packet->TagControlInformation = 0;
+    RtlZeroMemory(&Packet->Completion, sizeof 
(XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO));
+    Packet->Cookie = NULL;
+
+    RtlZeroMemory(Packet->Header, XENVIF_TRANSMITTER_MAXIMUM_HEADER_LENGTH);
+    RtlZeroMemory(&Packet->Info, sizeof (XENVIF_PACKET_INFO));
+    RtlZeroMemory(&Packet->Payload, sizeof (XENVIF_PACKET_PAYLOAD));
 
     XENBUS_CACHE(Put,
                  &Transmitter->CacheInterface,
@@ -721,7 +779,7 @@ TransmitterRingDebugCallback(
 }
 
 static BOOLEAN
-TransmitterRingPullup(
+TransmitterPullup(
     IN      PVOID                   Argument,
     IN      PUCHAR                  DestinationVa,
     IN OUT  PXENVIF_PACKET_PAYLOAD  Payload,
@@ -800,10 +858,10 @@ __TransmitterRingCopyPayload(
 
     State = &Ring->State;
     Packet = State->Packet;
-    Payload = State->Payload;
+    Payload = Packet->Payload;
 
     ASSERT(Packet != NULL);
-    ASSERT3U(Packet->Value, ==, 1);
+    ASSERT3U(Packet->Reference, ==, 1);
 
     while (Payload.Length != 0) {
         PMDL        Mdl;
@@ -818,14 +876,14 @@ __TransmitterRingCopyPayload(
             goto fail1;
 
         Buffer->Context = Packet;
-        Packet->Value++;
+        Packet->Reference++;
 
         Mdl = Buffer->Mdl;
 
         Length = __min(Payload.Length, PAGE_SIZE);
 
         MdlMappedSystemVa = MmGetSystemAddressForMdlSafe(Mdl, 
NormalPagePriority);
-        TransmitterRingPullup(Ring, MdlMappedSystemVa, &Payload, Length);
+        (VOID) TransmitterPullup(Transmitter, MdlMappedSystemVa, &Payload, 
Length);
 
         Mdl->ByteCount = Length;
 
@@ -884,14 +942,14 @@ fail2:
     ASSERT3P(Buffer->Context, ==, Packet);
     Buffer->Context = NULL;        
 
-    Packet->Value--;
+    --Packet->Reference;
 
     __TransmitterPutBuffer(Ring, Buffer);
 
 fail1:
     Error("fail1 (%08x)\n", status);
 
-    while (Packet->Value != 1) {
+    while (Packet->Reference != 1) {
         PLIST_ENTRY         ListEntry;
 
         ASSERT(State->Count != 0);
@@ -927,7 +985,7 @@ fail1:
         ASSERT3P(Buffer->Context, ==, Packet);
         Buffer->Context = NULL;        
 
-        Packet->Value--;
+        --Packet->Reference;
 
         __TransmitterPutBuffer(Ring, Buffer);
     }
@@ -956,10 +1014,10 @@ __TransmitterRingGrantPayload(
 
     State = &Ring->State;
     Packet = State->Packet;
-    Payload = &State->Payload;
+    Payload = &Packet->Payload;
 
     ASSERT(Packet != NULL);
-    ASSERT3U(Packet->Value, ==, 1);
+    ASSERT3U(Packet->Reference, ==, 1);
 
     Mdl = Payload->Mdl;
     Offset = Payload->Offset;
@@ -988,7 +1046,7 @@ __TransmitterRingGrantPayload(
 
             Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_PACKET;
             Fragment->Context = Packet;
-            Packet->Value++;
+            Packet->Reference++;
 
             Pfn = MmGetMdlPfnArray(Mdl)[MdlOffset / PAGE_SIZE];
             PageOffset = MdlOffset & (PAGE_SIZE - 1);
@@ -1045,7 +1103,7 @@ fail2:
         Fragment->Context = NULL;
         Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID;
 
-        Packet->Value--;
+        --Packet->Reference;
 
         __TransmitterPutFragment(Ring, Fragment);
     }
@@ -1056,7 +1114,7 @@ fail1:
 
     ASSERT3P(Fragment, ==, NULL);
 
-    while (Packet->Value != 1) {
+    while (Packet->Reference != 1) {
         PLIST_ENTRY         ListEntry;
 
         ASSERT(State->Count != 0);
@@ -1083,7 +1141,7 @@ fail1:
         Fragment->Context = NULL;
         Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID;
 
-        Packet->Value--;
+        --Packet->Reference;
 
         __TransmitterPutFragment(Ring, Fragment);
     }
@@ -1117,10 +1175,11 @@ __TransmitterRingPrepareHeader(
 
     State = &Ring->State;
     Packet = State->Packet;
-    Payload = &State->Payload;
-    Info = &State->Info;
 
-    ASSERT3U(Packet->Value, ==, 0);
+    Payload = &Packet->Payload;
+    Info = &Packet->Info;
+
+    ASSERT3U(Packet->Reference, ==, 0);
 
     Buffer = __TransmitterGetBuffer(Ring);
 
@@ -1129,18 +1188,14 @@ __TransmitterRingPrepareHeader(
         goto fail1;
 
     Buffer->Context = Packet;
-    Packet->Value++;
+    Packet->Reference++;
 
     Mdl = Buffer->Mdl;
 
     StartVa = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
     ASSERT(StartVa != NULL);
 
-    status = ParsePacket(StartVa, TransmitterRingPullup, Ring, Payload, Info);
-    if (!NT_SUCCESS(status))
-        goto fail2;
-
-    State->StartVa = StartVa;
+    RtlCopyMemory(StartVa, Packet->Header, Info->Length);
 
     Mdl->ByteCount = Info->Length;
 
@@ -1148,7 +1203,7 @@ __TransmitterRingPrepareHeader(
 
     status = STATUS_NO_MEMORY;
     if (Fragment == NULL)
-        goto fail3;
+        goto fail2;
 
     Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_BUFFER;
     Fragment->Context = Buffer;
@@ -1166,7 +1221,7 @@ __TransmitterRingPrepareHeader(
                            TRUE,
                            &Fragment->Entry);
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail3;
 
     Fragment->Offset = 0;
     Fragment->Length = Mdl->ByteCount + Payload->Length;
@@ -1178,7 +1233,7 @@ __TransmitterRingPrepareHeader(
     ASSERT(Info->EthernetHeader.Length != 0);
     EthernetHeader = (PETHERNET_HEADER)(StartVa + 
Info->EthernetHeader.Offset);        
 
-    if (State->Send.OffloadOptions.OffloadTagManipulation) {
+    if (Packet->OffloadOptions.OffloadTagManipulation) {
         ULONG   Offset;
 
         Offset = FIELD_OFFSET(ETHERNET_TAGGED_HEADER, Tag);
@@ -1189,9 +1244,10 @@ __TransmitterRingPrepareHeader(
 
         // Insert the tag
         EthernetHeader->Tagged.Tag.ProtocolID = HTONS(ETHERTYPE_TPID);
-        EthernetHeader->Tagged.Tag.ControlInformation = 
HTONS(State->Send.TagControlInformation);
+        EthernetHeader->Tagged.Tag.ControlInformation = 
HTONS(Packet->TagControlInformation);
         ASSERT(ETHERNET_HEADER_IS_TAGGED(EthernetHeader));
 
+        Packet->Length += sizeof (ETHERNET_TAG);
         Mdl->ByteCount += sizeof (ETHERNET_TAG);
         Fragment->Length += sizeof (ETHERNET_TAG);
 
@@ -1215,7 +1271,7 @@ __TransmitterRingPrepareHeader(
             Info->TcpOptions.Offset += sizeof (ETHERNET_TAG);
     }
 
-    if (State->Send.OffloadOptions.OffloadIpVersion4LargePacket) {
+    if (Packet->OffloadOptions.OffloadIpVersion4LargePacket) {
         PIP_HEADER  IpHeader;
         PTCP_HEADER TcpHeader;
         ULONG       Length;
@@ -1242,20 +1298,20 @@ __TransmitterRingPrepareHeader(
         IpHeader->Version4.PacketLength = HTONS((USHORT)Length);
 
         // IP checksum calulcation must be offloaded for large packets
-        State->Send.OffloadOptions.OffloadIpVersion4HeaderChecksum = 1;
+        Packet->OffloadOptions.OffloadIpVersion4HeaderChecksum = 1;
 
         // TCP checksum calulcation must be offloaded for large packets
         TcpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
-        State->Send.OffloadOptions.OffloadIpVersion4TcpChecksum = 1;
+        Packet->OffloadOptions.OffloadIpVersion4TcpChecksum = 1;
 
         // If the MSS is such that the payload would constitute only a single 
fragment then
         // we no longer need trate the packet as a large packet.
-        ASSERT3U(State->Send.MaximumSegmentSize, <=, Payload->Length);
-        if (State->Send.MaximumSegmentSize == Payload->Length)
-            State->Send.OffloadOptions.OffloadIpVersion4LargePacket = 0;
+        ASSERT3U(Packet->MaximumSegmentSize, <=, Payload->Length);
+        if (Packet->MaximumSegmentSize == Payload->Length)
+            Packet->OffloadOptions.OffloadIpVersion4LargePacket = 0;
     }
     
-    if (State->Send.OffloadOptions.OffloadIpVersion6LargePacket) {
+    if (Packet->OffloadOptions.OffloadIpVersion6LargePacket) {
         PIP_HEADER  IpHeader;
         PTCP_HEADER TcpHeader;
         ULONG       Length;
@@ -1282,29 +1338,29 @@ __TransmitterRingPrepareHeader(
 
         // TCP checksum calulcation must be offloaded for large packets
         TcpHeader->Checksum = ChecksumPseudoHeader(StartVa, Info);
-        State->Send.OffloadOptions.OffloadIpVersion6TcpChecksum = 1;
+        Packet->OffloadOptions.OffloadIpVersion6TcpChecksum = 1;
 
         // If the MSS is such that the payload would constitute only a single 
fragment then
         // we no longer need treat the packet as a large packet.
-        ASSERT3U(State->Send.MaximumSegmentSize, <=, Payload->Length);
-        if (State->Send.MaximumSegmentSize == Payload->Length)
-            State->Send.OffloadOptions.OffloadIpVersion6LargePacket = 0;
+        ASSERT3U(Packet->MaximumSegmentSize, <=, Payload->Length);
+        if (Packet->MaximumSegmentSize == Payload->Length)
+            Packet->OffloadOptions.OffloadIpVersion6LargePacket = 0;
     }
 
     // Non-GSO packets must not exceed MTU
-    if (!State->Send.OffloadOptions.OffloadIpVersion4LargePacket &&
-        !State->Send.OffloadOptions.OffloadIpVersion6LargePacket) {
+    if (!Packet->OffloadOptions.OffloadIpVersion4LargePacket &&
+        !Packet->OffloadOptions.OffloadIpVersion6LargePacket) {
         ULONG   MaximumFrameSize;
 
         MacQueryMaximumFrameSize(Mac, &MaximumFrameSize);
         
         if (Fragment->Length > MaximumFrameSize) {
             status = STATUS_INVALID_PARAMETER;
-            goto fail5;
+            goto fail4;
         }
     }
 
-    if (State->Send.OffloadOptions.OffloadIpVersion4HeaderChecksum) {
+    if (Packet->OffloadOptions.OffloadIpVersion4HeaderChecksum) {
         PIP_HEADER  IpHeader;
 
         ASSERT(Info->IpHeader.Length != 0);
@@ -1316,8 +1372,8 @@ __TransmitterRingPrepareHeader(
 
     return STATUS_SUCCESS;
 
-fail5:
-    Error("fail5\n");
+fail4:
+    Error("fail4\n");
 
     ASSERT(State->Count != 0);
     --State->Count;
@@ -1335,8 +1391,8 @@ fail5:
                          Fragment->Entry);
     Fragment->Entry = NULL;
 
-fail4:
-    Error("fail4\n");
+fail3:
+    Error("fail3\n");
 
     Fragment->Context = NULL;
     Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID;
@@ -1346,15 +1402,10 @@ fail4:
 
     __TransmitterPutFragment(Ring, Fragment);
 
-fail3:
-    Error("fail3\n");
-
-    Mdl->ByteCount = 0;
-
 fail2:
     Error("fail2\n");
 
-    Packet->Value--;
+    --Packet->Reference;
     Buffer->Context = NULL;
 
     __TransmitterPutBuffer(Ring, Buffer);
@@ -1362,7 +1413,7 @@ fail2:
 fail1:
     Error("fail1 (%08x)\n", status);
 
-    ASSERT3U(Packet->Value, ==, 0);
+    ASSERT3U(Packet->Reference, ==, 0);
 
     return status;
 }
@@ -1461,7 +1512,7 @@ __TransmitterRingUnprepareFragments(
         }
 
         if (Packet != NULL)
-            Packet->Value--;
+            --Packet->Reference;
 
         __TransmitterPutFragment(Ring, Fragment);
     }
@@ -1478,11 +1529,6 @@ __TransmitterRingUnprepareFragments(
     if (Packet != NULL) {
         Ring->PacketsUnprepared++;
 
-        RtlZeroMemory(&State->Payload, sizeof (XENVIF_PACKET_PAYLOAD));
-
-        Packet->Send = State->Send;
-        RtlZeroMemory(&State->Send, sizeof 
(XENVIF_TRANSMITTER_PACKET_SEND_INFO));
-
         State->Packet = NULL;
     }
 
@@ -1493,8 +1539,8 @@ __TransmitterRingUnprepareFragments(
 
 static FORCEINLINE NTSTATUS
 __TransmitterRingPreparePacket(
-    IN  PXENVIF_TRANSMITTER_RING        Ring,
-    IN  PXENVIF_TRANSMITTER_PACKET      Packet
+    IN  PXENVIF_TRANSMITTER_RING    Ring,
+    IN  PXENVIF_TRANSMITTER_PACKET  Packet
     )
 {
     PXENVIF_TRANSMITTER             Transmitter;
@@ -1511,14 +1557,6 @@ __TransmitterRingPreparePacket(
 
     State->Packet = Packet;
 
-    State->Send = Packet->Send;
-    RtlZeroMemory(&Packet->Send, sizeof (XENVIF_TRANSMITTER_PACKET_SEND_INFO));
-
-    Payload = &State->Payload;
-    Payload->Mdl = Packet->Mdl;
-    Payload->Offset = Packet->Offset;
-    Payload->Length = Packet->Length;
-
     InitializeListHead(&State->List);
     ASSERT3U(State->Count, ==, 0);
 
@@ -1526,9 +1564,10 @@ __TransmitterRingPreparePacket(
     if (!NT_SUCCESS(status))
         goto fail1;
 
-    ASSERT3U(State->Count, ==, Packet->Value);
+    ASSERT3U(State->Count, ==, Packet->Reference);
 
-    Info = &State->Info;
+    Info = &Packet->Info;
+    Payload = &Packet->Payload;
 
     // Is the packet too short?
     if (Info->Length + Payload->Length < ETHERNET_MIN) {
@@ -1584,7 +1623,7 @@ __TransmitterRingPreparePacket(
 
         if (Transmitter->AlwaysCopy != 0 ||
             (!NT_SUCCESS(status) && status == STATUS_BUFFER_OVERFLOW)) {
-            ASSERT3U(State->Count, ==, Packet->Value);
+            ASSERT3U(State->Count, ==, Packet->Reference);
 
             status = __TransmitterRingCopyPayload(Ring);
         }
@@ -1593,7 +1632,7 @@ __TransmitterRingPreparePacket(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    ASSERT3U(State->Count, ==, Packet->Value);
+    ASSERT3U(State->Count, ==, Packet->Reference);
 
     Ring->PacketsPrepared++;
     return STATUS_SUCCESS;
@@ -1606,17 +1645,9 @@ fail2:
 fail1:
     Error("fail1 (%08x)\n", status);
 
-    State->StartVa = NULL;
-    RtlZeroMemory(&State->Info, sizeof (XENVIF_PACKET_INFO));
-
     ASSERT(IsListEmpty(&State->List));
     RtlZeroMemory(&State->List, sizeof (LIST_ENTRY));
 
-    RtlZeroMemory(&State->Payload, sizeof (XENVIF_PACKET_PAYLOAD));
-
-    Packet->Send = State->Send;
-    RtlZeroMemory(&State->Send, sizeof (XENVIF_TRANSMITTER_PACKET_SEND_INFO));
-
     State->Packet = NULL;
 
     ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE)));
@@ -2002,11 +2033,10 @@ __TransmitterRingPostFragments(
     PXENVIF_FRONTEND                Frontend;
     PXENVIF_TRANSMITTER_STATE       State;
     PXENVIF_TRANSMITTER_PACKET      Packet;
-    PXENVIF_PACKET_PAYLOAD          Payload;
+    XENVIF_VIF_OFFLOAD_OPTIONS      OffloadOptions;
     RING_IDX                        req_prod;
     RING_IDX                        rsp_cons;
     ULONG                           Extra;
-    ULONG                           PacketLength;
     BOOLEAN                         FirstRequest;
     PLIST_ENTRY                     ListEntry;
     PXENVIF_TRANSMITTER_FRAGMENT    Fragment;
@@ -2018,12 +2048,15 @@ __TransmitterRingPostFragments(
 
     State = &Ring->State;
     Packet = State->Packet;
-    Payload = &State->Payload;
+
+    if (Packet != NULL)
+        OffloadOptions = Packet->OffloadOptions;
+    else
+        OffloadOptions.Value = 0;
 
     ASSERT(!IsListEmpty(&State->List));
     ASSERT(State->Count != 0);
     ASSERT3U(State->Count, <=, XEN_NETIF_NR_SLOTS_MIN);
-    ASSERT(IMPLY(Packet != NULL, State->Count == Packet->Value));
 
     req_prod = Ring->Front.req_prod_pvt;
     rsp_cons = Ring->Front.rsp_cons;
@@ -2033,8 +2066,8 @@ __TransmitterRingPostFragments(
                                  XENVIF_TRANSMITTER_FRAGMENT,
                                  ListEntry);
 
-    Extra = (State->Send.OffloadOptions.OffloadIpVersion4LargePacket ||
-             State->Send.OffloadOptions.OffloadIpVersion6LargePacket ||
+    Extra = (OffloadOptions.OffloadIpVersion4LargePacket ||
+             OffloadOptions.OffloadIpVersion6LargePacket ||
              Fragment->Type == 
XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL) ?
             1 :
             0;
@@ -2048,7 +2081,6 @@ __TransmitterRingPostFragments(
     req = NULL;
 
     FirstRequest = TRUE;
-    PacketLength = 0;
     while (State->Count != 0) {
         --State->Count;
 
@@ -2078,14 +2110,14 @@ __TransmitterRingPostFragments(
         if (FirstRequest) {
             FirstRequest = FALSE;
 
-            if (State->Send.OffloadOptions.OffloadIpVersion4TcpChecksum ||
-                State->Send.OffloadOptions.OffloadIpVersion4UdpChecksum ||
-                State->Send.OffloadOptions.OffloadIpVersion6TcpChecksum ||
-                State->Send.OffloadOptions.OffloadIpVersion6UdpChecksum)
+            if (OffloadOptions.OffloadIpVersion4TcpChecksum ||
+                OffloadOptions.OffloadIpVersion4UdpChecksum ||
+                OffloadOptions.OffloadIpVersion6TcpChecksum ||
+                OffloadOptions.OffloadIpVersion6UdpChecksum)
                 req->flags |= NETTXF_csum_blank | NETTXF_data_validated;
 
-            if (State->Send.OffloadOptions.OffloadIpVersion4LargePacket ||
-                State->Send.OffloadOptions.OffloadIpVersion6LargePacket ||
+            if (OffloadOptions.OffloadIpVersion4LargePacket ||
+                OffloadOptions.OffloadIpVersion6LargePacket ||
                 Fragment->Type == 
XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL) {
                 struct netif_extra_info *extra;
 
@@ -2096,17 +2128,17 @@ __TransmitterRingPostFragments(
                 req_prod++;
                 Ring->RequestsPosted++;
 
-                if (State->Send.OffloadOptions.OffloadIpVersion4LargePacket ||
-                    State->Send.OffloadOptions.OffloadIpVersion6LargePacket) {
-                    ASSERT(State->Send.MaximumSegmentSize != 0);
+                if (OffloadOptions.OffloadIpVersion4LargePacket ||
+                    OffloadOptions.OffloadIpVersion6LargePacket) {
+                    ASSERT(Packet->MaximumSegmentSize != 0);
 
                     extra->type = XEN_NETIF_EXTRA_TYPE_GSO;
                     extra->flags = 0;
 
-                    extra->u.gso.type = 
(State->Send.OffloadOptions.OffloadIpVersion4LargePacket) ?
+                    extra->u.gso.type = 
(OffloadOptions.OffloadIpVersion4LargePacket) ?
                                         XEN_NETIF_GSO_TYPE_TCPV4 :
-                                        XEN_NETIF_GSO_TYPE_TCPV6;;
-                    extra->u.gso.size = State->Send.MaximumSegmentSize;
+                                        XEN_NETIF_GSO_TYPE_TCPV6;
+                    extra->u.gso.size = Packet->MaximumSegmentSize;
                     extra->u.gso.pad = 0;
                     extra->u.gso.features = 0;
 
@@ -2129,9 +2161,6 @@ __TransmitterRingPostFragments(
 
                 req->flags |= NETTXF_extra_info;
             }
-
-            // The first fragment length is the length of the entire packet
-            PacketLength = Fragment->Length;
         }
 
         // Store a copy of the request in case we need to fake a response 
ourselves
@@ -2151,14 +2180,14 @@ __TransmitterRingPostFragments(
 
     // Set the initial completion information
     if (Packet != NULL) {
-        PUCHAR              StartVa;
-        PXENVIF_PACKET_INFO Info;
-        PETHERNET_HEADER    Header;
+        PUCHAR                  StartVa;
+        PXENVIF_PACKET_INFO     Info;
+        PXENVIF_PACKET_PAYLOAD  Payload;
+        PETHERNET_HEADER        Header;
 
-        ASSERT(PacketLength != 0);
-
-        StartVa = State->StartVa;
-        Info = &State->Info;
+        StartVa = Packet->Header;
+        Info = &Packet->Info;
+        Payload = &Packet->Payload;
 
         ASSERT(IsZeroMemory(&Packet->Completion, sizeof 
(XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO)));
 
@@ -2166,14 +2195,9 @@ __TransmitterRingPostFragments(
         Header = (PETHERNET_HEADER)(StartVa + Info->EthernetHeader.Offset);
 
         Packet->Completion.Type = 
GET_ETHERNET_ADDRESS_TYPE(&Header->Untagged.DestinationAddress);
-        Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_PENDING;
-        Packet->Completion.PacketLength = (USHORT)PacketLength;
+        Packet->Completion.PacketLength = (USHORT)Packet->Length;
         Packet->Completion.PayloadLength = (USHORT)Payload->Length;
 
-        State->StartVa = NULL;
-        RtlZeroMemory(&State->Info, sizeof (XENVIF_PACKET_INFO));
-        RtlZeroMemory(&State->Payload, sizeof (XENVIF_PACKET_PAYLOAD));
-        RtlZeroMemory(&State->Send, sizeof 
(XENVIF_TRANSMITTER_PACKET_SEND_INFO));
         State->Packet = NULL;
 
         Ring->PacketsSent++;
@@ -2268,7 +2292,7 @@ __TransmitterRingCompletePacket(
     Transmitter = Ring->Transmitter;
     Frontend = Transmitter->Frontend;
 
-    ASSERT(Packet->Completion.Status != XENVIF_TRANSMITTER_PACKET_PENDING);
+    ASSERT(Packet->Completion.Status != 0);
 
     if (Packet->Completion.Status != XENVIF_TRANSMITTER_PACKET_OK) {
         FrontendIncrementStatistic(Frontend,
@@ -2447,10 +2471,10 @@ TransmitterRingPoll(
                 continue;
             }
 
-            Packet->Value--;
+            --Packet->Reference;
 
             if (rsp->status != NETIF_RSP_OKAY &&
-                Packet->Completion.Status == 
XENVIF_TRANSMITTER_PACKET_PENDING) {
+                Packet->Completion.Status == 0) {
                 switch (rsp->status) {
                 case NETIF_RSP_DROPPED:
                     Packet->Completion.Status = 
XENVIF_TRANSMITTER_PACKET_DROPPED;
@@ -2468,10 +2492,10 @@ TransmitterRingPoll(
 
             RtlZeroMemory(rsp, sizeof (netif_tx_response_t));
 
-            if (Packet->Value != 0)
+            if (Packet->Reference != 0)
                 continue;
 
-            if (Packet->Completion.Status == XENVIF_TRANSMITTER_PACKET_PENDING)
+            if (Packet->Completion.Status == 0)
                 Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_OK;
 
             __TransmitterRingCompletePacket(Ring, Packet);
@@ -2589,11 +2613,12 @@ TransmitterRingSwizzle(
         ListEntry = NextEntry;
     }
 
-    ListEntry = List.Flink;
     if (!IsListEmpty(&List)) {
+        ListEntry = List.Flink;
+
         RemoveEntryList(&List);
-        InitializeListHead(&List);
         AppendTailList(&Ring->PacketQueue, ListEntry);
+
         Ring->PacketsQueued += Count;
     }
 }
@@ -2632,6 +2657,8 @@ TransmitterRingSchedule(
             PXENVIF_TRANSMITTER_REQUEST Request;
 
             ListEntry = RemoveHeadList(&Ring->RequestQueue);
+            ASSERT3P(ListEntry, !=, &Ring->RequestQueue);
+
             RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
 
             Request = CONTAINING_RECORD(ListEntry,
@@ -2669,13 +2696,15 @@ TransmitterRingSchedule(
             PXENVIF_TRANSMITTER_PACKET  Packet;
 
             ListEntry = RemoveHeadList(&Ring->PacketQueue);
+            ASSERT3P(ListEntry, !=, &Ring->PacketQueue);
+
             RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
 
             Packet = CONTAINING_RECORD(ListEntry,
                                        XENVIF_TRANSMITTER_PACKET,
                                        ListEntry);
 
-            Packet->Value = 0;
+            Packet->Reference = 0;
 
             status = __TransmitterRingPreparePacket(Ring, Packet);
             if (!NT_SUCCESS(status)) {
@@ -2712,20 +2741,70 @@ TransmitterRingSchedule(
 }
 
 static FORCEINLINE VOID
+__TransmitterReturnPacketVersion2(
+    IN  PXENVIF_TRANSMITTER                         Transmitter,
+    IN  PVOID                                       Cookie,
+    IN  PXENVIF_TRANSMITTER_PACKET_COMPLETION_INFO  Completion
+    )
+{
+    struct _XENVIF_TRANSMITTER_PACKET_V2            *PacketVersion2;
+    PXENVIF_FRONTEND                                Frontend;
+    PXENVIF_VIF_CONTEXT                             Context;
+    LIST_ENTRY                                      List;
+
+    PacketVersion2 = Cookie;
+    PacketVersion2->Completion = *Completion;
+
+    Frontend = Transmitter->Frontend;
+    Context = PdoGetVifContext(FrontendGetPdo(Frontend));
+
+    InitializeListHead(&List);
+
+    ASSERT(IsZeroMemory(&PacketVersion2->ListEntry, sizeof (LIST_ENTRY)));
+    InsertTailList(&List, &PacketVersion2->ListEntry);
+
+    VifTransmitterReturnPacketsVersion2(Context, &List);
+    ASSERT(IsListEmpty(&List));
+}
+
+static FORCEINLINE VOID
 __TransmitterReturnPackets(
     IN  PXENVIF_TRANSMITTER Transmitter,
     IN  PLIST_ENTRY         List
     )
 {
     PXENVIF_FRONTEND        Frontend;
-
-    if (IsListEmpty(List))
-        return;
+    PXENVIF_VIF_CONTEXT     Context;
+    ULONG                   Version;
 
     Frontend = Transmitter->Frontend;
+    Context = PdoGetVifContext(FrontendGetPdo(Frontend));
+    Version = VifGetVersion(Context);
+
+    while (!IsListEmpty(List)) {
+        PLIST_ENTRY                 ListEntry;
+        PXENVIF_TRANSMITTER_PACKET  Packet;
 
-    VifTransmitterReturnPackets(PdoGetVifContext(FrontendGetPdo(Frontend)),
-                                List);
+        ListEntry = RemoveHeadList(List);
+        ASSERT3P(ListEntry, !=, List);
+
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        Packet = CONTAINING_RECORD(ListEntry,
+                                   XENVIF_TRANSMITTER_PACKET,
+                                   ListEntry);
+
+        if  (Version < 4)
+            __TransmitterReturnPacketVersion2(Transmitter,
+                                              Packet->Cookie,
+                                              &Packet->Completion);
+        else
+            VifTransmitterReturnPacket(Context,
+                                       Packet->Cookie,
+                                       &Packet->Completion);
+
+        __TransmitterPutPacket(Transmitter, Packet);
+    }
 }
 
 static FORCEINLINE BOOLEAN
@@ -2837,13 +2916,12 @@ __TransmitterRingReleaseLock(
     // thread could be simuntaneously adding to the list.
 
     do {
-        PLIST_ENTRY     ListEntry;
-
         TransmitterRingSwizzle(Ring);
         TransmitterRingSchedule(Ring);
 
-        ListEntry = Ring->PacketComplete.Flink;
         if (!IsListEmpty(&Ring->PacketComplete)) {
+            PLIST_ENTRY     ListEntry = Ring->PacketComplete.Flink;
+
             RemoveEntryList(&Ring->PacketComplete);
             InitializeListHead(&Ring->PacketComplete);
             AppendTailList(&List, ListEntry);
@@ -3752,21 +3830,24 @@ __TransmitterRingTeardown(
 }
 
 static FORCEINLINE VOID
-__TransmitterRingQueuePackets(
+__TransmitterRingQueuePacket(
     IN  PXENVIF_TRANSMITTER_RING    Ring,
-    IN  PLIST_ENTRY                 List
+    IN  PXENVIF_TRANSMITTER_PACKET  Packet
     )
 {
+    PLIST_ENTRY                     ListEntry;
     ULONG_PTR                       Old;
     ULONG_PTR                       LockBit;
     ULONG_PTR                       New;
 
+    ListEntry = &Packet->ListEntry;
+
     do {
         Old = (ULONG_PTR)Ring->Lock;
         LockBit = Old & XENVIF_TRANSMITTER_LOCK_BIT;
 
-        List->Flink->Blink = (PVOID)(Old & ~XENVIF_TRANSMITTER_LOCK_BIT);
-        New = (ULONG_PTR)List->Blink;
+        ListEntry->Blink = (PVOID)(Old & ~XENVIF_TRANSMITTER_LOCK_BIT);
+        New = (ULONG_PTR)ListEntry;
         ASSERT((New & XENVIF_TRANSMITTER_LOCK_BIT) == 0);
         New |= LockBit;
     } while ((ULONG_PTR)InterlockedCompareExchangePointer(&Ring->Lock, 
(PVOID)New, (PVOID)Old) != Old);
@@ -4485,7 +4566,7 @@ TransmitterTeardown(
 }
 
 static BOOLEAN
-__TransmitterGetPacketHeadersPullup(
+TransmitterGetPacketHeadersVersion2Pullup(
     IN      PVOID                   Argument,
     IN      PUCHAR                  DestinationVa,
     IN OUT  PXENVIF_PACKET_PAYLOAD  Payload,
@@ -4546,22 +4627,22 @@ fail1:
 }
 
 NTSTATUS
-TransmitterGetPacketHeaders(
-    IN  PXENVIF_TRANSMITTER         Transmitter,
-    IN  PXENVIF_TRANSMITTER_PACKET  Packet,
-    OUT PVOID                       Headers,
-    OUT PXENVIF_PACKET_INFO         Info
+TransmitterGetPacketHeadersVersion2(
+    IN  PXENVIF_TRANSMITTER                     Transmitter,
+    IN  struct _XENVIF_TRANSMITTER_PACKET_V2    *PacketVersion2,
+    OUT PVOID                                   Headers,
+    OUT PXENVIF_PACKET_INFO                     Info
     )
 {
-    XENVIF_PACKET_PAYLOAD           Payload;
-    NTSTATUS                        status;
+    XENVIF_PACKET_PAYLOAD                       Payload;
+    NTSTATUS                                    status;
 
-    Payload.Mdl = Packet->Mdl;
-    Payload.Offset = Packet->Offset;
-    Payload.Length = Packet->Length;
+    Payload.Mdl = PacketVersion2->Mdl;
+    Payload.Offset = PacketVersion2->Offset;
+    Payload.Length = PacketVersion2->Length;
 
     status = ParsePacket(Headers,
-                         __TransmitterGetPacketHeadersPullup,
+                         TransmitterGetPacketHeadersVersion2Pullup,
                          Transmitter,
                          &Payload,
                          Info);
@@ -4574,70 +4655,241 @@ fail1:
     return status;
 }
 
-VOID
-TransmitterQueuePackets(
-    IN  PXENVIF_TRANSMITTER     Transmitter,
-    IN  PLIST_ENTRY             List
+static FORCEINLINE VOID
+__TransmitterHashAccumulate(
+    IN OUT  PULONG  Accumulator,
+    IN      PUCHAR  Array,
+    IN      ULONG   Length
     )
 {
-    PXENVIF_TRANSMITTER_RING    Ring;
-    PXENVIF_FRONTEND            Frontend;
-    LONG                        NumQueues;
+    ULONG           Current;
+    ULONG           Index;
 
-    Frontend = Transmitter->Frontend;
-    NumQueues = FrontendGetNumQueues(Frontend);
+    Current = *Accumulator;
+
+    for (Index = 0; Index < Length; Index++) {
+        ULONG   Overflow;
+
+        Current = (Current << 4) + Array[Index];
+
+        Overflow = Current & 0x000fff00;
+        if (Overflow != 0) {
+            Current ^= Overflow >> 8;
+            Current ^= Overflow;
+        }
+    }
+
+    *Accumulator = Current;
+}
+
+static FORCEINLINE ULONG
+__TransmitterHashPacket(
+    IN  PXENVIF_TRANSMITTER_PACKET  Packet
+    )
+{
+    PUCHAR                          StartVa;
+    PXENVIF_PACKET_INFO             Info;
+    PIP_HEADER                      IpHeader;
+    ULONG                           Value;
+
+    Value = 0;
+
+    StartVa = Packet->Header;
+    Info = &Packet->Info;
+
+    if (Info->TcpHeader.Length == 0 && Info->UdpHeader.Length == 0)
+        goto done;
+
+    ASSERT(Info->IpHeader.Length != 0);
+    IpHeader = (PIP_HEADER)(StartVa + Info->IpHeader.Offset);
 
-    if (NumQueues == 1) {
-        Ring = Transmitter->Ring[0];
+    if (IpHeader->Version == 4) {
+        PIPV4_HEADER    Version4 = &IpHeader->Version4;
 
-        __TransmitterRingQueuePackets(Ring, List);
+        __TransmitterHashAccumulate(&Value,
+                                    Version4->SourceAddress.Byte,
+                                    IPV4_ADDRESS_LENGTH);
+        __TransmitterHashAccumulate(&Value,
+                                    Version4->DestinationAddress.Byte,
+                                    IPV4_ADDRESS_LENGTH);
     } else {
-        while (!IsListEmpty(List)) {
-            PXENVIF_TRANSMITTER_PACKET  Packet;
-            LIST_ENTRY                  HashList;
-            ULONG                       Index;
+        PIPV6_HEADER    Version6 = &IpHeader->Version6;
 
-            InitializeListHead(&HashList);
-            Index = 0;
+        ASSERT3U(IpHeader->Version, ==, 6);
 
-            while (!IsListEmpty(List)) {
-                PLIST_ENTRY ListEntry;
-                ULONG       Hash;
+        __TransmitterHashAccumulate(&Value,
+                                    Version6->SourceAddress.Byte,
+                                    IPV6_ADDRESS_LENGTH);
+        __TransmitterHashAccumulate(&Value,
+                                    Version6->DestinationAddress.Byte,
+                                    IPV6_ADDRESS_LENGTH);
+    }
 
-                ListEntry = RemoveHeadList(List);
-                ASSERT3P(ListEntry, !=, List);
+    if (Info->TcpHeader.Length != 0) {
+        PTCP_HEADER TcpHeader;
 
-                RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+        TcpHeader = (PTCP_HEADER)(StartVa + Info->TcpHeader.Offset);
 
-                Packet = CONTAINING_RECORD(ListEntry, 
XENVIF_TRANSMITTER_PACKET, ListEntry);
+        __TransmitterHashAccumulate(&Value,
+                                    (PUCHAR)&TcpHeader->SourcePort,
+                                    sizeof (USHORT));
+        __TransmitterHashAccumulate(&Value,
+                                    (PUCHAR)&TcpHeader->DestinationPort,
+                                    sizeof (USHORT));
+    } else {
+        PUDP_HEADER UdpHeader;
 
-                Hash = Packet->Value % NumQueues;
-                if (Hash != Index) {
-                    if (!IsListEmpty(&HashList)) {
-                        Ring = Transmitter->Ring[Index];
-                        ASSERT3P(Ring, !=, NULL);
+        ASSERT(Info->UdpHeader.Length != 0);
 
-                        __TransmitterRingQueuePackets(Ring, &HashList);
-                        InitializeListHead(&HashList);
-                    }
+        UdpHeader = (PUDP_HEADER)(StartVa + Info->UdpHeader.Offset);
 
-                    Index = Hash;
-                }
+        __TransmitterHashAccumulate(&Value,
+                                    (PUCHAR)&UdpHeader->SourcePort,
+                                    sizeof (USHORT));
+        __TransmitterHashAccumulate(&Value,
+                                    (PUCHAR)&UdpHeader->DestinationPort,
+                                    sizeof (USHORT));
+    }
 
-                InsertTailList(&HashList, ListEntry);
-            }
+done:
+    return Value;
+}
+
+NTSTATUS
+TransmitterQueuePacket(
+    IN  PXENVIF_TRANSMITTER         Transmitter,
+    IN  PMDL                        Mdl,
+    IN  ULONG                       Offset,
+    IN  ULONG                       Length,
+    IN  XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions,
+    IN  USHORT                      MaximumSegmentSize,
+    IN  USHORT                      TagControlInformation,
+    IN  PXENVIF_PACKET_HASH         Hash,
+    IN  PVOID                       Cookie
+    )
+{
+    PXENVIF_FRONTEND                Frontend;
+    PXENVIF_TRANSMITTER_PACKET      Packet;
+    PUCHAR                          StartVa;
+    PXENVIF_PACKET_PAYLOAD          Payload;
+    PXENVIF_PACKET_INFO             Info;
+    ULONG                           Index;
+    PXENVIF_TRANSMITTER_RING        Ring;
+    NTSTATUS                        status;
 
-            if (!IsListEmpty(&HashList)) {
-                Ring = Transmitter->Ring[Index];
-                ASSERT3P(Ring, !=, NULL);
+    Frontend = Transmitter->Frontend;
 
-                __TransmitterRingQueuePackets(Ring, &HashList);
-                InitializeListHead(&HashList);
-            }
+    Packet = __TransmitterGetPacket(Transmitter);
 
-            ASSERT(IsListEmpty(&HashList));
-        }
+    status = STATUS_NO_MEMORY;
+    if (Packet == NULL)
+        goto fail1;
+
+    Packet->Mdl = Mdl;
+    Packet->Offset = Offset;
+    Packet->Length = Length;
+    Packet->OffloadOptions = OffloadOptions;
+    Packet->MaximumSegmentSize = MaximumSegmentSize;
+    Packet->TagControlInformation = TagControlInformation;
+    Packet->Cookie = Cookie;
+
+    StartVa = Packet->Header;
+
+    Payload = &Packet->Payload;
+    Payload->Mdl = Packet->Mdl;
+    Payload->Offset = Packet->Offset;
+    Payload->Length = Packet->Length;
+
+    Info = &Packet->Info;
+
+    status = ParsePacket(StartVa, TransmitterPullup, Transmitter, Payload, 
Info);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    switch (Hash->Algorithm) {
+    case XENVIF_PACKET_HASH_ALGORITHM_NONE:
+        Index = __TransmitterHashPacket(Packet);
+        break;
+
+    case XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED:
+        Index = Hash->Value;
+        break;
+
+    default:
+        ASSERT(FALSE);
+        Index = 0;
+        break;
+    }
+
+    Index %= FrontendGetNumQueues(Frontend);
+    Ring = Transmitter->Ring[Index];
+
+    __TransmitterRingQueuePacket(Ring, Packet);
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+    __TransmitterPutPacket(Transmitter, Packet);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+TransmitterQueuePacketsVersion2(
+    IN  PXENVIF_TRANSMITTER     Transmitter,
+    IN  PLIST_ENTRY             List
+    )
+{
+    LIST_ENTRY                  Reject;
+
+    InitializeListHead(&Reject);
+
+    while (!IsListEmpty(List)) {
+        PLIST_ENTRY                             ListEntry;
+        struct _XENVIF_TRANSMITTER_PACKET_V2    *PacketVersion2;
+        XENVIF_PACKET_HASH                      Hash;
+        NTSTATUS                                status;
+
+        ListEntry = RemoveHeadList(List);
+        ASSERT3P(ListEntry, !=, List);
+
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        PacketVersion2 = CONTAINING_RECORD(ListEntry,
+                                           struct 
_XENVIF_TRANSMITTER_PACKET_V2,
+                                           ListEntry);
+
+        Hash.Algorithm = XENVIF_PACKET_HASH_ALGORITHM_UNSPECIFIED;
+        Hash.Value = PacketVersion2->Value;
+
+        status = TransmitterQueuePacket(Transmitter,
+                                        PacketVersion2->Mdl,
+                                        PacketVersion2->Offset,
+                                        PacketVersion2->Length,
+                                        PacketVersion2->Send.OffloadOptions,
+                                        
PacketVersion2->Send.MaximumSegmentSize,
+                                        
PacketVersion2->Send.TagControlInformation,
+                                        &Hash,
+                                        PacketVersion2);
+        if (!NT_SUCCESS(status))
+            InsertTailList(&Reject, &PacketVersion2->ListEntry);
+    }
+
+    ASSERT(IsListEmpty(List));
+
+    if (!IsListEmpty(&Reject)) {
+        PLIST_ENTRY ListEntry = Reject.Flink;
+
+        RemoveEntryList(&Reject);
+        AppendTailList(List, ListEntry);
     }
+
+    return (IsListEmpty(List)) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
 }
 
 VOID
diff --git a/src/xenvif/transmitter.h b/src/xenvif/transmitter.h
index 04f1f6e..0b7f654 100644
--- a/src/xenvif/transmitter.h
+++ b/src/xenvif/transmitter.h
@@ -115,8 +115,21 @@ TransmitterQueryRingSize(
     OUT PULONG              Size
     );
 
-extern VOID
-TransmitterQueuePackets(
+extern NTSTATUS
+TransmitterQueuePacket(
+    IN  PXENVIF_TRANSMITTER         Transmitter,
+    IN  PMDL                        Mdl,
+    IN  ULONG                       Offset,
+    IN  ULONG                       Length,
+    IN  XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions,
+    IN  USHORT                      MaximumSegmentSize,
+    IN  USHORT                      TagControlInformation,
+    IN  PXENVIF_PACKET_HASH         Hash,
+    IN  PVOID                       Cookie
+    );
+
+extern NTSTATUS
+TransmitterQueuePacketsVersion2(
     IN  PXENVIF_TRANSMITTER Transmitter,
     IN  PLIST_ENTRY         List
     );
@@ -135,11 +148,11 @@ TransmitterQueryLargePacketSize(
     );
 
 extern NTSTATUS
-TransmitterGetPacketHeaders(
-    IN  PXENVIF_TRANSMITTER         Transmitter,
-    IN  PXENVIF_TRANSMITTER_PACKET  Packet,
-    OUT PVOID                       Headers,
-    OUT PXENVIF_PACKET_INFO         Info
+TransmitterGetPacketHeadersVersion2(
+    IN  PXENVIF_TRANSMITTER                     Transmitter,
+    IN  struct _XENVIF_TRANSMITTER_PACKET_V2    *Packet,
+    OUT PVOID                                   Headers,
+    OUT PXENVIF_PACKET_INFO                     Info
     );
 
 #endif  // _XENVIF_TRANSMITTER_H
diff --git a/src/xenvif/vif.c b/src/xenvif/vif.c
index ac4d454..76365d2 100644
--- a/src/xenvif/vif.c
+++ b/src/xenvif/vif.c
@@ -317,7 +317,7 @@ done:
 }
 
 static VOID
-VifReceiverReturnPackets( 
+VifReceiverReturnPacketsVersion1(
     IN  PINTERFACE      Interface,
     IN  PLIST_ENTRY     List
     )
@@ -326,30 +326,45 @@ VifReceiverReturnPackets(
 
     AcquireMrswLockShared(&Context->Lock);
 
-    ReceiverReturnPackets(FrontendGetReceiver(Context->Frontend),
-                          List);
+    ReceiverReturnPacketsVersion1(FrontendGetReceiver(Context->Frontend),
+                                  List);
+
+    ReleaseMrswLockShared(&Context->Lock);
+}
+
+static VOID
+VifReceiverReturnPacket(
+    IN  PINTERFACE      Interface,
+    IN  PVOID           Cookie
+    )
+{
+    PXENVIF_VIF_CONTEXT Context = Interface->Context;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    ReceiverReturnPacket(FrontendGetReceiver(Context->Frontend),
+                         Cookie);
 
     ReleaseMrswLockShared(&Context->Lock);
 }
 
 static NTSTATUS
-VifTransmitterGetPacketHeaders(
-    IN  PINTERFACE                      Interface,
-    IN  PXENVIF_TRANSMITTER_PACKET      Packet,
-    OUT PVOID                           Headers,
-    OUT PXENVIF_PACKET_INFO             Info
+VifTransmitterGetPacketHeadersVersion2(
+    IN  PINTERFACE                              Interface,
+    IN  struct _XENVIF_TRANSMITTER_PACKET_V2    *Packet,
+    OUT PVOID                                   Headers,
+    OUT PXENVIF_PACKET_INFO                     Info
     )
 {
-    PXENVIF_VIF_CONTEXT                 Context = Interface->Context;
-    NTSTATUS                            status;
+    PXENVIF_VIF_CONTEXT                         Context = Interface->Context;
+    NTSTATUS                                    status;
 
     AcquireMrswLockShared(&Context->Lock);
 
-    ASSERT3U(VifGetVersion(Context), >=, 2);
-    status = 
TransmitterGetPacketHeaders(FrontendGetTransmitter(Context->Frontend),
-                                         Packet,
-                                         Headers,
-                                         Info);
+    status = 
TransmitterGetPacketHeadersVersion2(FrontendGetTransmitter(Context->Frontend),
+                                                 Packet,
+                                                 Headers,
+                                                 Info);
 
     ReleaseMrswLockShared(&Context->Lock);
 
@@ -357,7 +372,7 @@ VifTransmitterGetPacketHeaders(
 }
 
 static NTSTATUS
-VifTransmitterQueuePackets(
+VifTransmitterQueuePacketsVersion2(
     IN  PINTERFACE      Interface,
     IN  PLIST_ENTRY     List
     )
@@ -369,20 +384,64 @@ VifTransmitterQueuePackets(
 
     status = STATUS_UNSUCCESSFUL;
     if (Context->Enabled == FALSE)
-        goto fail1;
+        goto done;
 
-    ASSERT3U(VifGetVersion(Context), >=, 2);
-    TransmitterQueuePackets(FrontendGetTransmitter(Context->Frontend),
-                            List);
+    status = 
TransmitterQueuePacketsVersion2(FrontendGetTransmitter(Context->Frontend),
+                                             List);
 
+done:
     ReleaseMrswLockShared(&Context->Lock);
 
-    return STATUS_SUCCESS;
+    return status;
+}
 
-fail1:
+static VOID
+VifTransmitterQueuePacket(
+    IN  PINTERFACE                  Interface,
+    IN  PMDL                        Mdl,
+    IN  ULONG                       Offset,
+    IN  ULONG                       Length,
+    IN  XENVIF_VIF_OFFLOAD_OPTIONS  OffloadOptions,
+    IN  USHORT                      MaximumSegmentSize,
+    IN  USHORT                      TagControlInformation,
+    IN  PXENVIF_PACKET_HASH         Hash,
+    IN  PVOID                       Cookie
+    )
+{
+    PXENVIF_VIF_CONTEXT             Context = Interface->Context;
+    NTSTATUS                        status;
+
+    AcquireMrswLockShared(&Context->Lock);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Context->Enabled == FALSE)
+        goto done;
+
+    ASSERT3U(VifGetVersion(Context), >=, 4);
+    status = TransmitterQueuePacket(FrontendGetTransmitter(Context->Frontend),
+                                    Mdl,
+                                    Offset,
+                                    Length,
+                                    OffloadOptions,
+                                    MaximumSegmentSize,
+                                    TagControlInformation,
+                                    Hash,
+                                    Cookie);
+
+done:
     ReleaseMrswLockShared(&Context->Lock);
 
-    return status;
+    if (!NT_SUCCESS(status)) {
+        XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO   Completion;
+
+        RtlZeroMemory(&Completion, sizeof 
(XENVIF_TRANSMITTER_PACKET_COMPLETION_INFO));
+
+        Completion.Status = XENVIF_TRANSMITTER_PACKET_DROPPED;
+
+        VifTransmitterReturnPacket(Context,
+                                   Cookie,
+                                   &Completion);
+    }
 }
 
 static VOID
@@ -652,6 +711,7 @@ VifAcquire(
     Trace("====>\n");
 
     Context->Frontend = PdoGetFrontend(Context->Pdo);
+    Context->Version = Interface->Version;
 
     Trace("<====\n");
 
@@ -678,6 +738,7 @@ VifRelease(
 
     ASSERT(!Context->Enabled);
 
+    Context->Version = 0;
     Context->Frontend = NULL;
 
     Trace("<====\n");
@@ -693,11 +754,11 @@ static struct _XENVIF_VIF_INTERFACE_V2 
VifInterfaceVersion2 = {
     VifEnable,
     VifDisable,
     VifQueryStatistic,
-    VifReceiverReturnPackets,
+    VifReceiverReturnPacketsVersion1,
     VifReceiverSetOffloadOptions,
     VifReceiverQueryRingSize,
-    VifTransmitterGetPacketHeaders,
-    VifTransmitterQueuePackets,
+    VifTransmitterGetPacketHeadersVersion2,
+    VifTransmitterQueuePacketsVersion2,
     VifTransmitterQueryOffloadOptions,
     VifTransmitterQueryLargePacketSize,
     VifTransmitterQueryRingSize,
@@ -718,12 +779,37 @@ static struct _XENVIF_VIF_INTERFACE_V3 
VifInterfaceVersion3 = {
     VifEnable,
     VifDisable,
     VifQueryStatistic,
-    VifReceiverReturnPackets,
+    VifReceiverReturnPacketsVersion1,
     VifReceiverSetOffloadOptions,
     VifReceiverSetBackfillSize,
     VifReceiverQueryRingSize,
-    VifTransmitterGetPacketHeaders,
-    VifTransmitterQueuePackets,
+    VifTransmitterGetPacketHeadersVersion2,
+    VifTransmitterQueuePacketsVersion2,
+    VifTransmitterQueryOffloadOptions,
+    VifTransmitterQueryLargePacketSize,
+    VifTransmitterQueryRingSize,
+    VifMacQueryState,
+    VifMacQueryMaximumFrameSize,
+    VifMacQueryPermanentAddress,
+    VifMacQueryCurrentAddress,
+    VifMacQueryMulticastAddresses,
+    VifMacSetMulticastAddresses,
+    VifMacSetFilterLevel,
+    VifMacQueryFilterLevel
+};
+
+static struct _XENVIF_VIF_INTERFACE_V4 VifInterfaceVersion4 = {
+    { sizeof (struct _XENVIF_VIF_INTERFACE_V4), 4, NULL, NULL, NULL },
+    VifAcquire,
+    VifRelease,
+    VifEnable,
+    VifDisable,
+    VifQueryStatistic,
+    VifReceiverReturnPacket,
+    VifReceiverSetOffloadOptions,
+    VifReceiverSetBackfillSize,
+    VifReceiverQueryRingSize,
+    VifTransmitterQueuePacket,
     VifTransmitterQueryOffloadOptions,
     VifTransmitterQueryLargePacketSize,
     VifTransmitterQueryRingSize,
@@ -835,13 +921,28 @@ VifGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 4: {
+        struct _XENVIF_VIF_INTERFACE_V4 *VifInterface;
+
+        VifInterface = (struct _XENVIF_VIF_INTERFACE_V4 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENVIF_VIF_INTERFACE_V4))
+            break;
+
+        *VifInterface = VifInterfaceVersion4;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
     }
 
-    Context->Version = Version;
-
     return status;
 }   
 
@@ -873,18 +974,43 @@ VifTeardown(
 }
 
 VOID
-VifReceiverQueuePackets(
+VifReceiverQueuePacketsVersion1(
     IN  PXENVIF_VIF_CONTEXT Context,
     IN  PLIST_ENTRY         List
     )
 {
     Context->Callback(Context->Argument,
-                      XENVIF_RECEIVER_QUEUE_PACKETS,
+                      XENVIF_RECEIVER_QUEUE_PACKET,
                       List);
 }
 
 VOID
-VifTransmitterReturnPackets(
+VifReceiverQueuePacket(
+    IN  PXENVIF_VIF_CONTEXT             Context,
+    IN  PMDL                            Mdl,
+    IN  ULONG                           Offset,
+    IN  ULONG                           Length,
+    IN  XENVIF_PACKET_CHECKSUM_FLAGS    Flags,
+    IN  USHORT                          MaximumSegmentSize,
+    IN  USHORT                          TagControlInformation,
+    IN  PXENVIF_PACKET_INFO             Info,
+    IN  PVOID                           Cookie
+    )
+{
+    Context->Callback(Context->Argument,
+                      XENVIF_RECEIVER_QUEUE_PACKET,
+                      Mdl,
+                      Offset,
+                      Length,
+                      Flags,
+                      MaximumSegmentSize,
+                      TagControlInformation,
+                      Info,
+                      Cookie);
+}
+
+VOID
+VifTransmitterReturnPacketsVersion2(
     IN  PXENVIF_VIF_CONTEXT Context,
     IN  PLIST_ENTRY         List
     )
@@ -892,10 +1018,25 @@ VifTransmitterReturnPackets(
     ASSERT3U(VifGetVersion(Context), >=, 2);
 
     Context->Callback(Context->Argument,
-                      XENVIF_TRANSMITTER_RETURN_PACKETS,
+                      XENVIF_TRANSMITTER_RETURN_PACKET,
                       List);
 }
 
+VOID
+VifTransmitterReturnPacket(
+    IN  PXENVIF_VIF_CONTEXT                         Context,
+    IN  PVOID                                       Cookie,
+    IN  PXENVIF_TRANSMITTER_PACKET_COMPLETION_INFO  Completion
+    )
+{
+    ASSERT3U(VifGetVersion(Context), >=, 4);
+
+    Context->Callback(Context->Argument,
+                      XENVIF_TRANSMITTER_RETURN_PACKET,
+                      Cookie,
+                      Completion);
+}
+
 PXENVIF_THREAD
 VifGetMacThread(
     IN  PXENVIF_VIF_CONTEXT Context
diff --git a/src/xenvif/vif.h b/src/xenvif/vif.h
index a842b79..ebb4337 100644
--- a/src/xenvif/vif.h
+++ b/src/xenvif/vif.h
@@ -63,17 +63,37 @@ VifTeardown(
 // CALLBACKS
 
 extern VOID
-VifReceiverQueuePackets(
+VifReceiverQueuePacketsVersion1(
     IN  PXENVIF_VIF_CONTEXT Context,
     IN  PLIST_ENTRY         List
     );
 
 extern VOID
-VifTransmitterReturnPackets(
+VifReceiverQueuePacket(
+    IN  PXENVIF_VIF_CONTEXT             Context,
+    IN  PMDL                            Mdl,
+    IN  ULONG                           Offset,
+    IN  ULONG                           Length,
+    IN  XENVIF_PACKET_CHECKSUM_FLAGS    Flags,
+    IN  USHORT                          MaximumSegmentSize,
+    IN  USHORT                          TagControlInformation,
+    IN  PXENVIF_PACKET_INFO             Info,
+    IN  PVOID                           Cookie
+    );
+
+extern VOID
+VifTransmitterReturnPacketsVersion2(
     IN  PXENVIF_VIF_CONTEXT Context,
     IN  PLIST_ENTRY         List
     );
 
+extern VOID
+VifTransmitterReturnPacket(
+    IN  PXENVIF_VIF_CONTEXT                         Context,
+    IN  PVOID                                       Cookie,
+    IN  PXENVIF_TRANSMITTER_PACKET_COMPLETION_INFO  Completion
+    );
+
 extern PXENVIF_THREAD
 VifGetMacThread(
     IN  PXENVIF_VIF_CONTEXT Context
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.