win-pvdrivers

changeset 962:278b479f3f7d 0.11.0.351

Fix for problem on rx where tcpip.sys leaks memory if the first MDL contains a fragment of the TCP payload.
Fixed a bug in detecting checksum support
Improve multi-buffer handling in rx path
Remove old #ifdef'd out code
Adding NDIS version detection for version-dependent features
Started adding Header/Data split
author James Harper <james.harper@bendigoit.com.au>
date Fri Dec 30 20:58:01 2011 +1100 (2011-12-30)
parents c67807a32ff9
children f4bc40d6987f
files xennet/xennet6.c xennet/xennet6.h xennet/xennet6_common.c xennet/xennet6_rx.c
line diff
     1.1 --- a/xennet/xennet6.c	Fri Dec 30 20:32:40 2011 +1100
     1.2 +++ b/xennet/xennet6.c	Fri Dec 30 20:58:01 2011 +1100
     1.3 @@ -33,6 +33,9 @@ static KDEFERRED_ROUTINE XenNet_SuspendR
     1.4  
     1.5  NDIS_HANDLE driver_handle = NULL;
     1.6  
     1.7 +USHORT ndis_os_major_version = 0;
     1.8 +USHORT ndis_os_minor_version = 0;
     1.9 +
    1.10  /* ----- BEGIN Other people's code --------- */
    1.11  /* from linux/include/linux/ctype.h, used under GPLv2 */
    1.12  #define _U      0x01    /* upper */
    1.13 @@ -483,63 +486,6 @@ XenNet_D0Entry(struct xennet_info *xi)
    1.14    return status;
    1.15  }
    1.16  
    1.17 -#if 0
    1.18 -static NDIS_OID supported_oids[] =
    1.19 -{
    1.20 -  /* mandatory */
    1.21 -  OID_GEN_HARDWARE_STATUS,       // Q
    1.22 -
    1.23 -  OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
    1.24 -  OID_GEN_RECEIVE_BUFFER_SPACE,  // Q
    1.25 -  OID_GEN_TRANSMIT_BLOCK_SIZE,   // Q
    1.26 -  OID_GEN_RECEIVE_BLOCK_SIZE,    // Q
    1.27 -
    1.28 -  OID_GEN_VENDOR_ID,             // Q
    1.29 -  OID_GEN_VENDOR_DESCRIPTION,    // Q
    1.30 -  OID_GEN_VENDOR_DRIVER_VERSION, // Q
    1.31 -
    1.32 -  OID_GEN_CURRENT_PACKET_FILTER, // QS
    1.33 -  OID_GEN_CURRENT_LOOKAHEAD,     // QS
    1.34 -  OID_GEN_DRIVER_VERSION,        // Q
    1.35 -  OID_GEN_MAXIMUM_TOTAL_SIZE,    // Q
    1.36 -  OID_GEN_LINK_PARAMETERS,       // S
    1.37 -  OID_GEN_INTERRUPT_MODERATION,  // QS
    1.38 -  
    1.39 -  OID_GEN_MAXIMUM_SEND_PACKETS,  // Q
    1.40 -
    1.41 -  /* general optional */
    1.42 -  OID_GEN_NETWORK_LAYER_ADDRESSES,       
    1.43 -  OID_GEN_TRANSPORT_HEADER_OFFSET,
    1.44 -
    1.45 -  /* power */
    1.46 -  OID_PNP_CAPABILITIES,
    1.47 -  OID_PNP_SET_POWER,
    1.48 -  OID_PNP_QUERY_POWER,
    1.49 -  
    1.50 -  /* stats */
    1.51 -  OID_GEN_XMIT_OK,
    1.52 -  OID_GEN_RCV_OK,
    1.53 -  OID_GEN_XMIT_ERROR,
    1.54 -  OID_GEN_RCV_ERROR,
    1.55 -  OID_GEN_RCV_NO_BUFFER,
    1.56 -  OID_GEN_STATISTICS,
    1.57 -  
    1.58 -  /* media-specific */
    1.59 -  OID_802_3_PERMANENT_ADDRESS,
    1.60 -  OID_802_3_CURRENT_ADDRESS,
    1.61 -  OID_802_3_MULTICAST_LIST,
    1.62 -  OID_802_3_MAXIMUM_LIST_SIZE,
    1.63 -  OID_802_3_RCV_ERROR_ALIGNMENT,
    1.64 -  OID_802_3_XMIT_ONE_COLLISION,
    1.65 -  OID_802_3_XMIT_MORE_COLLISIONS,
    1.66 -  
    1.67 -  /* tcp offload */
    1.68 -  OID_TCP_TASK_OFFLOAD,
    1.69 -  OID_TCP_OFFLOAD_PARAMETERS,
    1.70 -  OID_OFFLOAD_ENCAPSULATION,
    1.71 -};
    1.72 -#endif
    1.73 -
    1.74  // Called at <= DISPATCH_LEVEL
    1.75  static NDIS_STATUS
    1.76  XenNet_Initialize(NDIS_HANDLE adapter_handle, NDIS_HANDLE driver_context, PNDIS_MINIPORT_INIT_PARAMETERS init_parameters)
    1.77 @@ -742,6 +688,10 @@ XenNet_Initialize(NDIS_HANDLE adapter_ha
    1.78      KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
    1.79      xi->frontend_sg_supported = !!config_param->ParameterData.IntegerData;
    1.80    }
    1.81 +  if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
    1.82 +    FUNCTION_MSG("No support for SG with NDIS 6.0, disabled\n");
    1.83 +    xi->frontend_sg_supported = FALSE;
    1.84 +  }
    1.85    
    1.86    NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
    1.87    NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
    1.88 @@ -766,6 +716,10 @@ XenNet_Initialize(NDIS_HANDLE adapter_ha
    1.89        KdPrint(("(clipped to %d with sg disabled)\n", xi->frontend_gso_value));
    1.90      }
    1.91    }
    1.92 +  if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
    1.93 +    FUNCTION_MSG("No support for GSO with NDIS 6.0, disabled\n");
    1.94 +    xi->frontend_gso_value = 0;
    1.95 +  }
    1.96  
    1.97    NdisInitUnicodeString(&config_param_name, L"LargeSendOffloadRxSplitMTU");
    1.98    NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
    1.99 @@ -795,12 +749,12 @@ XenNet_Initialize(NDIS_HANDLE adapter_ha
   1.100    if (!NT_SUCCESS(status))
   1.101    {
   1.102      KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
   1.103 -    xi->backend_csum_supported = TRUE;
   1.104 +    xi->frontend_csum_supported = TRUE;
   1.105    }
   1.106    else
   1.107    {
   1.108      KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
   1.109 -    xi->backend_csum_supported = !!config_param->ParameterData.IntegerData;
   1.110 +    xi->frontend_csum_supported = !!config_param->ParameterData.IntegerData;
   1.111    }
   1.112  
   1.113    NdisInitUnicodeString(&config_param_name, L"MTU");
   1.114 @@ -904,6 +858,7 @@ XenNet_Initialize(NDIS_HANDLE adapter_ha
   1.115    for (i = 0; xennet_oids[i].oid; i++)
   1.116    {
   1.117      supported_oids[i] = xennet_oids[i].oid;
   1.118 +    FUNCTION_MSG("Supporting %08x (%s) %s %d bytes\n", xennet_oids[i].oid, xennet_oids[i].oid_name, (xennet_oids[i].query_routine?(xennet_oids[i].set_routine?"get/set":"get only"):(xennet_oids[i].set_routine?"set only":"none")), xennet_oids[i].min_length);
   1.119    }
   1.120    general_attributes.SupportedOidList = supported_oids;
   1.121    general_attributes.SupportedOidListLength = sizeof(NDIS_OID) * i;
   1.122 @@ -1011,7 +966,38 @@ XenNet_Initialize(NDIS_HANDLE adapter_ha
   1.123      KdPrint(("NdisMSetMiniportAttributes(offload) failed (%08x)\n", status));
   1.124      goto err;
   1.125    }
   1.126 -
   1.127 +  
   1.128 +  #if 0
   1.129 +  if (ndis_os_minor_version >= 1) {
   1.130 +    NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES hw_assist_attributes;
   1.131 +    NDIS_HD_SPLIT_ATTRIBUTES hd_split_attributes;
   1.132 +    
   1.133 +    RtlZeroMemory(&hd_split_attributes, sizeof(hd_split_attributes));
   1.134 +    hd_split_attributes.Header.Type = NDIS_OBJECT_TYPE_HD_SPLIT_ATTRIBUTES;
   1.135 +    hd_split_attributes.Header.Revision = NDIS_HD_SPLIT_ATTRIBUTES_REVISION_1;
   1.136 +    hd_split_attributes.Header.Size = NDIS_SIZEOF_HD_SPLIT_ATTRIBUTES_REVISION_1;
   1.137 +    hd_split_attributes.HardwareCapabilities = NDIS_HD_SPLIT_CAPS_SUPPORTS_HEADER_DATA_SPLIT | NDIS_HD_SPLIT_CAPS_SUPPORTS_IPV4_OPTIONS | NDIS_HD_SPLIT_CAPS_SUPPORTS_TCP_OPTIONS;
   1.138 +    hd_split_attributes.CurrentCapabilities = hd_split_attributes.HardwareCapabilities;
   1.139 +    /* the other members are set on output */
   1.140 +    
   1.141 +    RtlZeroMemory(&hw_assist_attributes, sizeof(hw_assist_attributes));
   1.142 +    hw_assist_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES;
   1.143 +    hw_assist_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
   1.144 +    hw_assist_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
   1.145 +    hw_assist_attributes.HDSplitAttributes = &hd_split_attributes;
   1.146 +    status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&hw_assist_attributes);
   1.147 +    if (!NT_SUCCESS(status))
   1.148 +    {
   1.149 +      FUNCTION_MSG("NdisMSetMiniportAttributes(hw_assist) failed (%08x)\n", status);
   1.150 +      goto err;
   1.151 +    }
   1.152 +    FUNCTION_MSG("HW Split enabled\n");
   1.153 +    FUNCTION_MSG(" HDSplitFlags = %08x\n", hd_split_attributes.HDSplitFlags);
   1.154 +    FUNCTION_MSG(" BackfillSize = %d\n", hd_split_attributes.BackfillSize);
   1.155 +    FUNCTION_MSG(" MaxHeaderSize = %d\n", hd_split_attributes.MaxHeaderSize);
   1.156 +    //what about backfill here?
   1.157 +  }
   1.158 +  #endif
   1.159    return NDIS_STATUS_SUCCESS;
   1.160    
   1.161  err:
   1.162 @@ -1163,20 +1149,31 @@ DriverEntry(PDRIVER_OBJECT driver_object
   1.163    FUNCTION_ENTER();
   1.164  
   1.165    ndis_version = NdisGetVersion();
   1.166 -  KdPrint((__DRIVER_NAME "     ndis_version = %08x\n", ndis_version));
   1.167 +  
   1.168 +  ndis_os_major_version = ndis_version >> 16;
   1.169 +  ndis_os_minor_version = ndis_version & 0xFFFF;
   1.170  
   1.171    NdisZeroMemory(&mini_chars, sizeof(mini_chars));
   1.172  
   1.173    mini_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
   1.174 -  mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
   1.175 -  mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
   1.176 +  
   1.177 +  if (ndis_os_minor_version < 1) {
   1.178 +    mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
   1.179 +    mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
   1.180  
   1.181 -  mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
   1.182 -  mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
   1.183 +    mini_chars.MajorNdisVersion = 6;
   1.184 +    mini_chars.MinorNdisVersion = 0;
   1.185 +  } else {
   1.186 +    mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
   1.187 +    mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
   1.188 +    mini_chars.MajorNdisVersion = 6;
   1.189 +    mini_chars.MinorNdisVersion = 1;
   1.190 +  }
   1.191    mini_chars.MajorDriverVersion = VENDOR_DRIVER_VERSION_MAJOR;
   1.192    mini_chars.MinorDriverVersion = VENDOR_DRIVER_VERSION_MINOR;
   1.193  
   1.194 -  KdPrint((__DRIVER_NAME "     MajorNdisVersion = %d,  MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
   1.195 +  KdPrint((__DRIVER_NAME "     Driver MajorNdisVersion = %d, Driver MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
   1.196 +  KdPrint((__DRIVER_NAME "     Windows MajorNdisVersion = %d, Windows MinorNdisVersion = %d\n", ndis_os_major_version, ndis_os_minor_version));
   1.197  
   1.198    mini_chars.Flags = NDIS_WDM_DRIVER;
   1.199    
   1.200 @@ -1193,10 +1190,10 @@ DriverEntry(PDRIVER_OBJECT driver_object
   1.201  
   1.202    mini_chars.OidRequestHandler = XenNet_OidRequest;
   1.203    mini_chars.CancelOidRequestHandler = XenNet_CancelOidRequest;
   1.204 -  #if 0 // these must be for NDIS > 6.0 ?
   1.205 -  mini_chars.DirectOidRequestHandler = NULL;
   1.206 -  mini_chars.CancelDirectOidRequestHandler = NULL;
   1.207 -  #endif
   1.208 +  if (ndis_os_minor_version >= 1) {
   1.209 +    mini_chars.DirectOidRequestHandler = NULL;
   1.210 +    mini_chars.CancelDirectOidRequestHandler = NULL;
   1.211 +  }
   1.212  
   1.213    mini_chars.SendNetBufferListsHandler = XenNet_SendNetBufferLists;
   1.214    mini_chars.CancelSendHandler = XenNet_CancelSend;
     2.1 --- a/xennet/xennet6.h	Fri Dec 30 20:32:40 2011 +1100
     2.2 +++ b/xennet/xennet6.h	Fri Dec 30 20:58:01 2011 +1100
     2.3 @@ -24,15 +24,14 @@ Foundation, Inc., 51 Franklin Street, Fi
     2.4  #include <ntddk.h>
     2.5  #include <wdm.h>
     2.6  #define NDIS_MINIPORT_DRIVER 1
     2.7 -#define NDIS60_MINIPORT 1
     2.8 -#define NDIS_SUPPORT_NDIS6 1
     2.9 +#define NDIS61_MINIPORT 1
    2.10  #include <ndis.h>
    2.11  #define NTSTRSAFE_LIB
    2.12  #include <ntstrsafe.h>
    2.13  #include <liblfds.h>
    2.14  
    2.15  #define VENDOR_DRIVER_VERSION_MAJOR 0
    2.16 -#define VENDOR_DRIVER_VERSION_MINOR 10
    2.17 +#define VENDOR_DRIVER_VERSION_MINOR 11
    2.18  
    2.19  #define MAX_LINK_SPEED 10000000000L; /* there is not really any theoretical maximum... */
    2.20  
    2.21 @@ -41,11 +40,11 @@ Foundation, Inc., 51 Franklin Street, Fi
    2.22  #define __DRIVER_NAME "XenNet"
    2.23  
    2.24  #define NB_LIST_ENTRY_FIELD MiniportReserved[0] // TX (2 entries)
    2.25 -#define NB_HEADER_BUF_FIELD MiniportReserved[0] // RX
    2.26 +#define NB_FIRST_PB_FIELD MiniportReserved[0] // RX
    2.27  #define NB_NBL_FIELD MiniportReserved[2] // TX
    2.28  #define NB_LIST_ENTRY(_nb) (*(PLIST_ENTRY)&(_nb)->NB_LIST_ENTRY_FIELD)
    2.29  #define NB_NBL(_nb) (*(PNET_BUFFER_LIST *)&(_nb)->NB_NBL_FIELD)
    2.30 -#define NB_HEADER_BUF(_nb) (*(shared_buffer_t **)&(_nb)->NB_HEADER_BUF_FIELD)
    2.31 +#define NB_FIRST_PB(_nb) (*(shared_buffer_t **)&(_nb)->NB_FIRST_PB_FIELD)
    2.32  
    2.33  #define NBL_REF_FIELD MiniportReserved[0] // TX
    2.34  //#define NBL_LIST_ENTRY_FIELD MiniportReserved[0] // TX (2 entries) - overlaps with REF_FIELD
    2.35 @@ -188,7 +187,7 @@ SET_NET_ULONG(PVOID ptr, ULONG data)
    2.36  #define MAX_PKT_HEADER_LENGTH (MAX_ETH_HEADER_LENGTH + MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
    2.37  
    2.38  #define MIN_LOOKAHEAD_LENGTH (MAX_IP4_HEADER_LENGTH + MAX_TCP_HEADER_LENGTH)
    2.39 -#define MAX_LOOKAHEAD_LENGTH PAGE_SIZE /* don't know if this is a good idea - was 256*/
    2.40 +#define MAX_LOOKAHEAD_LENGTH PAGE_SIZE
    2.41  
    2.42  #define LINUX_MAX_SG_ELEMENTS 19
    2.43  
    2.44 @@ -330,7 +329,6 @@ struct xennet_info
    2.45    volatile LONG rx_hb_free;
    2.46    struct stack_state *rx_hb_stack;
    2.47    shared_buffer_t *rx_ring_pbs[NET_RX_RING_SIZE];
    2.48 -  NPAGED_LOOKASIDE_LIST rx_lookaside_list;
    2.49    /* Receive-ring batched refills. */
    2.50    ULONG rx_target;
    2.51    ULONG rx_max_target;
    2.52 @@ -383,6 +381,10 @@ struct xennet_oids_t {
    2.53  
    2.54  extern struct xennet_oids_t xennet_oids[];
    2.55  
    2.56 +extern USHORT ndis_os_major_version;
    2.57 +extern USHORT ndis_os_minor_version;
    2.58 +
    2.59 +
    2.60  MINIPORT_OID_REQUEST XenNet_OidRequest;
    2.61  MINIPORT_CANCEL_OID_REQUEST XenNet_CancelOidRequest;
    2.62  
     3.1 --- a/xennet/xennet6_common.c	Fri Dec 30 20:32:40 2011 +1100
     3.2 +++ b/xennet/xennet6_common.c	Fri Dec 30 20:58:01 2011 +1100
     3.3 @@ -211,9 +211,10 @@ XenNet_ParsePacketHeader(packet_info_t *
     3.4  
     3.5    if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
     3.6    {
     3.7 -    if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length)))
     3.8 +    /* we don't actually need the tcp options to analyse the header */
     3.9 +    if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + MIN_TCP_HEADER_LENGTH)))
    3.10      {
    3.11 -      //KdPrint((__DRIVER_NAME "     packet too small (IP Header + IP Options + TCP Header + TCP Options)\n"));
    3.12 +      //KdPrint((__DRIVER_NAME "     packet too small (IP Header + IP Options + TCP Header (not including TCP Options))\n"));
    3.13        pi->parse_result = PARSE_TOO_SMALL;
    3.14        return;
    3.15      }
     4.1 --- a/xennet/xennet6_rx.c	Fri Dec 30 20:32:40 2011 +1100
     4.2 +++ b/xennet/xennet6_rx.c	Fri Dec 30 20:58:01 2011 +1100
     4.3 @@ -231,111 +231,115 @@ XenNet_MakePacket(struct xennet_info *xi
     4.4      return FALSE;
     4.5    }
     4.6  
     4.7 -  header_buf = get_hb_from_freelist(xi);
     4.8 -  if (!header_buf)
     4.9 -  {
    4.10 -    KdPrint((__DRIVER_NAME "     No free header buffers\n"));
    4.11 -    NdisFreeNetBufferList(nbl);
    4.12 -    NdisFreeNetBuffer(nb);
    4.13 -    //FUNCTION_EXIT();
    4.14 -    return FALSE;
    4.15 -  }
    4.16 -  header_va = (PUCHAR)(header_buf + 1);
    4.17 -  NdisMoveMemory(header_va, pi->header, pi->header_length);
    4.18 -  //KdPrint((__DRIVER_NAME "     header_length = %d, current_lookahead = %d\n", pi->header_length, xi->current_lookahead));
    4.19 -  //KdPrint((__DRIVER_NAME "     ip4_header_length = %d\n", pi->ip4_header_length));
    4.20 -  //KdPrint((__DRIVER_NAME "     tcp_header_length = %d\n", pi->tcp_header_length));
    4.21 -  /* make sure we satisfy the lookahead requirement */
    4.22 -  if (pi->split_required)
    4.23 -  {
    4.24 -    /* for split packets we need to make sure the 'header' is no bigger than header+mss bytes */
    4.25 -    XenNet_BuildHeader(pi, header_va, min((ULONG)MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length + pi->mss, MAX_ETH_HEADER_LENGTH + max(MIN_LOOKAHEAD_LENGTH, xi->current_lookahead)));
    4.26 -  }
    4.27 -  else
    4.28 -  {
    4.29 -    XenNet_BuildHeader(pi, header_va, max(MIN_LOOKAHEAD_LENGTH, xi->current_lookahead) + MAX_ETH_HEADER_LENGTH);
    4.30 -  }
    4.31 -  header_extra = pi->header_length - (MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length);
    4.32 -  ASSERT(pi->header_length <= MAX_ETH_HEADER_LENGTH + MAX_LOOKAHEAD_LENGTH);
    4.33 -  header_buf->mdl->ByteCount = pi->header_length;
    4.34 -  mdl_head = mdl_tail = curr_mdl = header_buf->mdl;
    4.35 -  NB_HEADER_BUF(nb) = header_buf;
    4.36 -  header_buf->next = pi->curr_pb;
    4.37 -  NET_BUFFER_FIRST_MDL(nb) = mdl_head;
    4.38 -  NET_BUFFER_CURRENT_MDL(nb) = mdl_head;
    4.39 -  NET_BUFFER_CURRENT_MDL_OFFSET(nb) = 0;
    4.40 -  NET_BUFFER_DATA_OFFSET(nb) = 0;
    4.41 -  NET_BUFFER_DATA_LENGTH(nb) = pi->header_length;
    4.42 -
    4.43 -  // TODO: if there are only a few bytes left on the first buffer then add them to the header buffer too... maybe
    4.44 -
    4.45 -  if (pi->split_required)
    4.46 -  {
    4.47 -    ULONG tcp_length;
    4.48 -    USHORT new_ip4_length;
    4.49 -    tcp_length = (USHORT)min(pi->mss, pi->tcp_remaining);
    4.50 -    new_ip4_length = (USHORT)(pi->ip4_header_length + pi->tcp_header_length + tcp_length);
    4.51 -    //KdPrint((__DRIVER_NAME "     new_ip4_length = %d\n", new_ip4_length));
    4.52 -    //KdPrint((__DRIVER_NAME "     this tcp_length = %d\n", tcp_length));
    4.53 -    SET_NET_USHORT(&header_va[XN_HDR_SIZE + 2], new_ip4_length);
    4.54 -    SET_NET_ULONG(&header_va[XN_HDR_SIZE + pi->ip4_header_length + 4], pi->tcp_seq);
    4.55 -    pi->tcp_seq += tcp_length;
    4.56 -    pi->tcp_remaining = (USHORT)(pi->tcp_remaining - tcp_length);
    4.57 -    /* part of the packet is already present in the header buffer for lookahead */
    4.58 -    out_remaining = tcp_length - header_extra;
    4.59 -    ASSERT((LONG)out_remaining >= 0);
    4.60 -  }
    4.61 -  else
    4.62 -  {
    4.63 -    out_remaining = pi->total_length - pi->header_length;
    4.64 -    ASSERT((LONG)out_remaining >= 0);
    4.65 -  }
    4.66 -  //KdPrint((__DRIVER_NAME "     before loop - out_remaining = %d\n", out_remaining));
    4.67 -
    4.68 -  while (out_remaining != 0)
    4.69 -  {
    4.70 -    //ULONG in_buffer_offset;
    4.71 -    ULONG in_buffer_length;
    4.72 -    ULONG out_length;
    4.73 -    
    4.74 -    //KdPrint((__DRIVER_NAME "     in loop - out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
    4.75 -    if (!pi->curr_mdl || !pi->curr_pb)
    4.76 +  if (!pi->first_mdl->Next && !pi->split_required) {
    4.77 +    /* a single buffer <= MTU */
    4.78 +    header_buf = NULL;
    4.79 +    XenNet_BuildHeader(pi, pi->first_mdl_virtual, pi->first_mdl_length);
    4.80 +    NET_BUFFER_FIRST_MDL(nb) = pi->first_mdl;
    4.81 +    NET_BUFFER_CURRENT_MDL(nb) = pi->first_mdl;
    4.82 +    NET_BUFFER_CURRENT_MDL_OFFSET(nb) = 0;
    4.83 +    NET_BUFFER_DATA_OFFSET(nb) = 0;
    4.84 +    NET_BUFFER_DATA_LENGTH(nb) = pi->total_length;
    4.85 +    NB_FIRST_PB(nb) = pi->first_pb;
    4.86 +    ref_pb(xi, pi->first_pb);
    4.87 +  } else {
    4.88 +    ASSERT(ndis_os_minor_version >= 1);
    4.89 +    header_buf = get_hb_from_freelist(xi);
    4.90 +    if (!header_buf)
    4.91      {
    4.92 -      KdPrint((__DRIVER_NAME "     out of buffers for packet\n"));
    4.93 -      //KdPrint((__DRIVER_NAME "     out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
    4.94 -      // TODO: free some stuff or we'll leak
    4.95 -      /* unchain buffers then free packet */
    4.96 +      KdPrint((__DRIVER_NAME "     No free header buffers\n"));
    4.97 +      NdisFreeNetBufferList(nbl);
    4.98 +      NdisFreeNetBuffer(nb);
    4.99        //FUNCTION_EXIT();
   4.100        return FALSE;
   4.101      }
   4.102 +    header_va = (PUCHAR)(header_buf + 1);
   4.103 +    NdisMoveMemory(header_va, pi->header, pi->header_length);
   4.104 +    //KdPrint((__DRIVER_NAME "     header_length = %d, current_lookahead = %d\n", pi->header_length, xi->current_lookahead));
   4.105 +    //KdPrint((__DRIVER_NAME "     ip4_header_length = %d\n", pi->ip4_header_length));
   4.106 +    //KdPrint((__DRIVER_NAME "     tcp_header_length = %d\n", pi->tcp_header_length));
   4.107 +    /* make sure only the header is in the first buffer (or the entire packet, but that is done in the above case) */
   4.108 +    XenNet_BuildHeader(pi, header_va, MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length);
   4.109 +    header_extra = pi->header_length - (MAX_ETH_HEADER_LENGTH + pi->ip4_header_length + pi->tcp_header_length);
   4.110 +    ASSERT(pi->header_length <= MAX_ETH_HEADER_LENGTH + MAX_LOOKAHEAD_LENGTH);
   4.111 +    header_buf->mdl->ByteCount = pi->header_length;
   4.112 +    mdl_head = mdl_tail = curr_mdl = header_buf->mdl;
   4.113 +    NB_FIRST_PB(nb) = header_buf;
   4.114 +    header_buf->next = pi->curr_pb;
   4.115 +    NET_BUFFER_FIRST_MDL(nb) = mdl_head;
   4.116 +    NET_BUFFER_CURRENT_MDL(nb) = mdl_head;
   4.117 +    NET_BUFFER_CURRENT_MDL_OFFSET(nb) = 0;
   4.118 +    NET_BUFFER_DATA_OFFSET(nb) = 0;
   4.119 +    NET_BUFFER_DATA_LENGTH(nb) = pi->header_length;
   4.120  
   4.121 -    in_buffer_length = MmGetMdlByteCount(pi->curr_mdl);
   4.122 -    out_length = min(out_remaining, in_buffer_length - pi->curr_mdl_offset);
   4.123 -    curr_mdl = IoAllocateMdl((PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length, FALSE, FALSE, NULL);
   4.124 -    ASSERT(curr_mdl);
   4.125 -    IoBuildPartialMdl(pi->curr_mdl, curr_mdl, (PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length);
   4.126 -    mdl_tail->Next = curr_mdl;
   4.127 -    mdl_tail = curr_mdl;
   4.128 -    curr_mdl->Next = NULL; /* I think this might be redundant */
   4.129 -    NET_BUFFER_DATA_LENGTH(nb) += out_length;
   4.130 -    ref_pb(xi, pi->curr_pb);
   4.131 -    pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + out_length);
   4.132 -    if (pi->curr_mdl_offset == in_buffer_length)
   4.133 +    if (pi->split_required)
   4.134      {
   4.135 -      pi->curr_mdl = pi->curr_mdl->Next;
   4.136 -      pi->curr_pb = pi->curr_pb->next;
   4.137 -      pi->curr_mdl_offset = 0;
   4.138 +      ULONG tcp_length;
   4.139 +      USHORT new_ip4_length;
   4.140 +      tcp_length = (USHORT)min(pi->mss, pi->tcp_remaining);
   4.141 +      new_ip4_length = (USHORT)(pi->ip4_header_length + pi->tcp_header_length + tcp_length);
   4.142 +      //KdPrint((__DRIVER_NAME "     new_ip4_length = %d\n", new_ip4_length));
   4.143 +      //KdPrint((__DRIVER_NAME "     this tcp_length = %d\n", tcp_length));
   4.144 +      SET_NET_USHORT(&header_va[XN_HDR_SIZE + 2], new_ip4_length);
   4.145 +      SET_NET_ULONG(&header_va[XN_HDR_SIZE + pi->ip4_header_length + 4], pi->tcp_seq);
   4.146 +      pi->tcp_seq += tcp_length;
   4.147 +      pi->tcp_remaining = (USHORT)(pi->tcp_remaining - tcp_length);
   4.148 +      /* part of the packet is already present in the header buffer for lookahead */
   4.149 +      out_remaining = tcp_length - header_extra;
   4.150 +      ASSERT((LONG)out_remaining >= 0);
   4.151      }
   4.152 -    out_remaining -= out_length;
   4.153 +    else
   4.154 +    {
   4.155 +      out_remaining = pi->total_length - pi->header_length;
   4.156 +      ASSERT((LONG)out_remaining >= 0);
   4.157 +    }
   4.158 +    //KdPrint((__DRIVER_NAME "     before loop - out_remaining = %d\n", out_remaining));
   4.159 +
   4.160 +    while (out_remaining != 0)
   4.161 +    {
   4.162 +      //ULONG in_buffer_offset;
   4.163 +      ULONG in_buffer_length;
   4.164 +      ULONG out_length;
   4.165 +      
   4.166 +      //KdPrint((__DRIVER_NAME "     in loop - out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
   4.167 +      if (!pi->curr_mdl || !pi->curr_pb)
   4.168 +      {
   4.169 +        KdPrint((__DRIVER_NAME "     out of buffers for packet\n"));
   4.170 +        //KdPrint((__DRIVER_NAME "     out_remaining = %d, curr_buffer = %p, curr_pb = %p\n", out_remaining, pi->curr_mdl, pi->curr_pb));
   4.171 +        // TODO: free some stuff or we'll leak
   4.172 +        /* unchain buffers then free packet */
   4.173 +        //FUNCTION_EXIT();
   4.174 +        return FALSE;
   4.175 +      }
   4.176 +
   4.177 +      in_buffer_length = MmGetMdlByteCount(pi->curr_mdl);
   4.178 +      out_length = min(out_remaining, in_buffer_length - pi->curr_mdl_offset);
   4.179 +      curr_mdl = IoAllocateMdl((PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length, FALSE, FALSE, NULL);
   4.180 +      ASSERT(curr_mdl);
   4.181 +      IoBuildPartialMdl(pi->curr_mdl, curr_mdl, (PUCHAR)MmGetMdlVirtualAddress(pi->curr_mdl) + pi->curr_mdl_offset, out_length);
   4.182 +      mdl_tail->Next = curr_mdl;
   4.183 +      mdl_tail = curr_mdl;
   4.184 +      curr_mdl->Next = NULL; /* I think this might be redundant */
   4.185 +      NET_BUFFER_DATA_LENGTH(nb) += out_length;
   4.186 +      ref_pb(xi, pi->curr_pb);
   4.187 +      pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + out_length);
   4.188 +      if (pi->curr_mdl_offset == in_buffer_length)
   4.189 +      {
   4.190 +        pi->curr_mdl = pi->curr_mdl->Next;
   4.191 +        pi->curr_pb = pi->curr_pb->next;
   4.192 +        pi->curr_mdl_offset = 0;
   4.193 +      }
   4.194 +      out_remaining -= out_length;
   4.195 +    }
   4.196 +    if (pi->split_required)
   4.197 +    {
   4.198 +      // TODO: only if Ip checksum is disabled...
   4.199 +      //XenNet_SumIpHeader(header_va, pi->ip4_header_length);
   4.200 +    }
   4.201 +    if (header_extra > 0)
   4.202 +      pi->header_length -= header_extra;
   4.203 +    //ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
   4.204    }
   4.205 -  if (pi->split_required)
   4.206 -  {
   4.207 -    // TODO: only if Ip checksum is disabled...
   4.208 -    //XenNet_SumIpHeader(header_va, pi->ip4_header_length);
   4.209 -  }
   4.210 -  if (header_extra > 0)
   4.211 -    pi->header_length -= header_extra;
   4.212 -  //ASSERT(*(shared_buffer_t **)&packet->MiniportReservedEx[0]);
   4.213    
   4.214    rc->packet_count++;
   4.215    NET_BUFFER_LIST_FIRST_NB(nbl) = nb;
   4.216 @@ -400,142 +404,6 @@ XenNet_MakePacket(struct xennet_info *xi
   4.217    return TRUE;
   4.218  }
   4.219  
   4.220 -#if 0
   4.221 -/*
   4.222 - Windows appears to insist that the checksum on received packets is correct, and won't
   4.223 - believe us when we lie about it, which happens when the packet is generated on the
   4.224 - same bridge in Dom0. Doh!
   4.225 - This is only for TCP and UDP packets. IP checksums appear to be correct anyways.
   4.226 -*/
   4.227 -
   4.228 -static BOOLEAN
   4.229 -XenNet_SumPacketData(
   4.230 -  packet_info_t *pi,
   4.231 -  PNDIS_PACKET packet,
   4.232 -  BOOLEAN set_csum
   4.233 -)
   4.234 -{
   4.235 -  USHORT i;
   4.236 -  PUCHAR buffer;
   4.237 -  PMDL mdl;
   4.238 -  UINT total_length;
   4.239 -  UINT data_length;
   4.240 -  UINT buffer_length;
   4.241 -  USHORT buffer_offset;
   4.242 -  ULONG csum;
   4.243 -  PUSHORT csum_ptr;
   4.244 -  USHORT remaining;
   4.245 -  USHORT ip4_length;
   4.246 -  BOOLEAN csum_span = TRUE; /* when the USHORT to be checksummed spans a buffer */
   4.247 -  
   4.248 -  //FUNCTION_ENTER();
   4.249 -
   4.250 -  NdisGetFirstBufferFromPacketSafe(packet, &mdl, &buffer, &buffer_length, &total_length, NormalPagePriority);
   4.251 -  ASSERT(mdl);
   4.252 -
   4.253 -  ip4_length = GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 2]);
   4.254 -  data_length = ip4_length + XN_HDR_SIZE;
   4.255 -  
   4.256 -  if ((USHORT)data_length > total_length)
   4.257 -  {
   4.258 -    KdPrint((__DRIVER_NAME "     Size Mismatch %d (ip4_length + XN_HDR_SIZE) != %d (total_length)\n", ip4_length + XN_HDR_SIZE, total_length));
   4.259 -    return FALSE;
   4.260 -  }
   4.261 -
   4.262 -  switch (pi->ip_proto)
   4.263 -  {
   4.264 -  case 6:
   4.265 -    ASSERT(buffer_length >= (USHORT)(XN_HDR_SIZE + pi->ip4_header_length + 17));
   4.266 -    csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 16];
   4.267 -    break;
   4.268 -  case 17:
   4.269 -    ASSERT(buffer_length >= (USHORT)(XN_HDR_SIZE + pi->ip4_header_length + 7));
   4.270 -    csum_ptr = (USHORT *)&buffer[XN_HDR_SIZE + pi->ip4_header_length + 6];
   4.271 -    break;
   4.272 -  default:
   4.273 -    KdPrint((__DRIVER_NAME "     Don't know how to calc sum for IP Proto %d\n", pi->ip_proto));
   4.274 -    //FUNCTION_EXIT();
   4.275 -    return FALSE; // should never happen
   4.276 -  }
   4.277 -
   4.278 -  if (set_csum)  
   4.279 -    *csum_ptr = 0;
   4.280 -
   4.281 -  csum = 0;
   4.282 -  csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 12]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 14]); // src
   4.283 -  csum += GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 16]) + GET_NET_PUSHORT(&buffer[XN_HDR_SIZE + 18]); // dst
   4.284 -  csum += ((USHORT)buffer[XN_HDR_SIZE + 9]);
   4.285 -
   4.286 -  remaining = ip4_length - pi->ip4_header_length;
   4.287 -
   4.288 -  csum += remaining;
   4.289 -  
   4.290 -  csum_span = FALSE;
   4.291 -  buffer_offset = i = XN_HDR_SIZE + pi->ip4_header_length;
   4.292 -  while (i < data_length)
   4.293 -  {
   4.294 -    /* don't include the checksum field itself in the calculation */
   4.295 -    if ((pi->ip_proto == 6 && i == XN_HDR_SIZE + pi->ip4_header_length + 16) || (pi->ip_proto == 17 && i == XN_HDR_SIZE + pi->ip4_header_length + 6))
   4.296 -    {
   4.297 -      /* we know that this always happens in the header buffer so we are guaranteed the full two bytes */
   4.298 -      i += 2;
   4.299 -      buffer_offset += 2;
   4.300 -      continue;
   4.301 -    }
   4.302 -    if (csum_span)
   4.303 -    {
   4.304 -      /* the other half of the next bit */
   4.305 -      ASSERT(buffer_offset == 0);
   4.306 -      csum += (USHORT)buffer[buffer_offset];
   4.307 -      csum_span = FALSE;
   4.308 -      i += 1;
   4.309 -      buffer_offset += 1;
   4.310 -    }
   4.311 -    else if (buffer_offset == buffer_length - 1)
   4.312 -    {
   4.313 -      /* deal with a buffer ending on an odd byte boundary */
   4.314 -      csum += (USHORT)buffer[buffer_offset] << 8;
   4.315 -      csum_span = TRUE;
   4.316 -      i += 1;
   4.317 -      buffer_offset += 1;
   4.318 -    }
   4.319 -    else
   4.320 -    {
   4.321 -      csum += GET_NET_PUSHORT(&buffer[buffer_offset]);
   4.322 -      i += 2;
   4.323 -      buffer_offset += 2;
   4.324 -    }
   4.325 -    if (buffer_offset == buffer_length && i < total_length)
   4.326 -    {
   4.327 -      NdisGetNextBuffer(mdl, &mdl);
   4.328 -      if (mdl == NULL)
   4.329 -      {
   4.330 -        KdPrint((__DRIVER_NAME "     Ran out of buffers\n"));
   4.331 -        return FALSE; // should never happen
   4.332 -      }
   4.333 -      NdisQueryBufferSafe(mdl, &buffer, &buffer_length, NormalPagePriority);
   4.334 -      ASSERT(buffer_length);
   4.335 -      buffer_offset = 0;
   4.336 -    }
   4.337 -  }
   4.338 -      
   4.339 -  while (csum & 0xFFFF0000)
   4.340 -    csum = (csum & 0xFFFF) + (csum >> 16);
   4.341 -  
   4.342 -  if (set_csum)
   4.343 -  {
   4.344 -    *csum_ptr = (USHORT)~GET_NET_USHORT((USHORT)csum);
   4.345 -  }
   4.346 -  else
   4.347 -  {
   4.348 -    //FUNCTION_EXIT();
   4.349 -    return (BOOLEAN)(*csum_ptr == (USHORT)~GET_NET_USHORT((USHORT)csum));
   4.350 -  }
   4.351 -  //FUNCTION_EXIT();
   4.352 -  return TRUE;
   4.353 -}
   4.354 -#endif
   4.355 -
   4.356  static VOID
   4.357  XenNet_MakePackets(struct xennet_info *xi, rx_context_t *rc, packet_info_t *pi)
   4.358  {
   4.359 @@ -558,7 +426,7 @@ XenNet_MakePackets(struct xennet_info *x
   4.360      switch (xi->current_gso_rx_split_type)
   4.361      {
   4.362      case RX_LSO_SPLIT_HALF:
   4.363 -      pi->mss = (pi->tcp_length + 1) / 2;
   4.364 +      pi->mss = max((pi->tcp_length + 1) / 2, pi->mss);
   4.365        break;
   4.366      case RX_LSO_SPLIT_NONE:
   4.367        pi->mss = 65535;
   4.368 @@ -656,7 +524,7 @@ XenNet_ReturnNetBufferLists(NDIS_HANDLE 
   4.369        
   4.370        next_nb = NET_BUFFER_NEXT_NB(curr_nb);
   4.371        curr_mdl = NET_BUFFER_FIRST_MDL(curr_nb);
   4.372 -      page_buf = NB_HEADER_BUF(curr_nb);
   4.373 +      page_buf = NB_FIRST_PB(curr_nb);
   4.374        while (curr_mdl)
   4.375        {
   4.376          shared_buffer_t *next_buf;