win-pvdrivers

view xennet/xennet.c @ 1106:2d392ecdd366

Fix race is xenvbd causing 30 second freeze under high load
author James Harper <james.harper@bendigoit.com.au>
date Tue Nov 11 23:08:11 2014 +1100 (2014-11-11)
parents 27bd2a5a4704
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #include <stdlib.h>
31 #include <io/xenbus.h>
32 #include "xennet.h"
34 /* Not really necessary but keeps PREfast happy */
35 DRIVER_INITIALIZE DriverEntry;
36 #if (VER_PRODUCTBUILD >= 7600)
37 static KDEFERRED_ROUTINE XenNet_RxTxDpc;
38 #endif
39 VOID XenNet_DeviceCallback(PVOID context, ULONG callback_type, PVOID value);
41 #pragma NDIS_INIT_FUNCTION(DriverEntry)
43 NDIS_HANDLE driver_handle = NULL;
45 USHORT ndis_os_major_version = 0;
46 USHORT ndis_os_minor_version = 0;
48 static VOID
49 XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
50 {
51 struct xennet_info *xi = context;
52 BOOLEAN dont_set_event;
54 UNREFERENCED_PARAMETER(dpc);
55 UNREFERENCED_PARAMETER(arg1);
56 UNREFERENCED_PARAMETER(arg2);
58 //FUNCTION_ENTER();
59 /* if Rx goes over its per-dpc quota then make sure TxBufferGC doesn't set an event as we are already guaranteed to be called again */
60 dont_set_event = XenNet_RxBufferCheck(xi);
61 XenNet_TxBufferGC(xi, dont_set_event);
62 //FUNCTION_EXIT();
63 }
65 // Called at PASSIVE_LEVEL
66 #if NTDDI_VERSION < NTDDI_VISTA
67 static NDIS_STATUS
68 XenNet_Init(PNDIS_STATUS open_error_status, PUINT SelectedMediumIndex, PNDIS_MEDIUM MediumArray, UINT MediumArraySize, NDIS_HANDLE adapter_handle, NDIS_HANDLE WrapperConfigurationContext)
69 #else
70 static NDIS_STATUS
71 XenNet_Initialize(NDIS_HANDLE adapter_handle, NDIS_HANDLE driver_context, PNDIS_MINIPORT_INIT_PARAMETERS init_parameters)
72 #endif
73 {
74 NDIS_STATUS status;
75 struct xennet_info *xi = NULL;
76 NDIS_HANDLE config_handle;
77 PNDIS_CONFIGURATION_PARAMETER config_param;
78 NDIS_STRING config_param_name;
79 ULONG i;
80 //ULONG length;
81 PVOID network_address;
82 UINT network_address_length;
83 #if NTDDI_VERSION < NTDDI_VISTA
84 #else
85 NDIS_CONFIGURATION_OBJECT config_object;
86 NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES registration_attributes;
87 NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES general_attributes;
88 NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES offload_attributes;
89 NDIS_OFFLOAD df_offload, hw_offload;
90 NDIS_TCP_CONNECTION_OFFLOAD df_conn_offload, hw_conn_offload;
91 NDIS_OID *supported_oids;
92 #endif
94 #if NTDDI_VERSION < NTDDI_VISTA
95 UNREFERENCED_PARAMETER(open_error_status);
96 #else
97 UNREFERENCED_PARAMETER(driver_context);
98 UNREFERENCED_PARAMETER(init_parameters);
99 #endif
101 FUNCTION_ENTER();
103 #if NTDDI_VERSION < NTDDI_VISTA
104 for (i = 0; i < MediumArraySize; i++) {
105 if (MediumArray[i] == NdisMedium802_3) {
106 break;
107 }
108 }
109 if (i == MediumArraySize) {
110 FUNCTION_MSG("NIC_MEDIA_TYPE not in MediumArray\n");
111 return NDIS_STATUS_UNSUPPORTED_MEDIA;
112 }
113 *SelectedMediumIndex = i;
114 #endif
115 /* Alloc memory for adapter private info */
116 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
117 if (!NT_SUCCESS(status)) {
118 FUNCTION_MSG("NdisAllocateMemoryWithTag failed with 0x%x\n", status);
119 status = NDIS_STATUS_RESOURCES;
120 goto err;
121 }
122 RtlZeroMemory(xi, sizeof(*xi));
123 xi->adapter_handle = adapter_handle;
124 xi->device_state = DEVICE_STATE_INITIALISING;
125 NdisMGetDeviceProperty(xi->adapter_handle, &xi->pdo, &xi->fdo,
126 &xi->lower_do, NULL, NULL);
127 KeInitializeEvent(&xi->backend_event, SynchronizationEvent, FALSE);
129 #if NTDDI_VERSION < NTDDI_VISTA
130 #endif
131 xi->rx_target = RX_DEFAULT_TARGET;
132 //xi->rx_min_target = RX_DFL_MIN_TARGET;
133 //xi->rx_max_target = RX_MAX_TARGET;
135 xi->multicast_list_size = 0;
136 xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
138 #if NTDDI_VERSION < NTDDI_VISTA
139 #else
140 xi->stats.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
141 xi->stats.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
142 xi->stats.Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
143 xi->stats.SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED
144 | NDIS_STATISTICS_RCV_OK_SUPPORTED
145 | NDIS_STATISTICS_XMIT_ERROR_SUPPORTED
146 | NDIS_STATISTICS_RCV_ERROR_SUPPORTED
147 | NDIS_STATISTICS_RCV_NO_BUFFER_SUPPORTED
148 | NDIS_STATISTICS_DIRECTED_BYTES_XMIT_SUPPORTED
149 | NDIS_STATISTICS_DIRECTED_FRAMES_XMIT_SUPPORTED
150 | NDIS_STATISTICS_MULTICAST_BYTES_XMIT_SUPPORTED
151 | NDIS_STATISTICS_MULTICAST_FRAMES_XMIT_SUPPORTED
152 | NDIS_STATISTICS_BROADCAST_BYTES_XMIT_SUPPORTED
153 | NDIS_STATISTICS_BROADCAST_FRAMES_XMIT_SUPPORTED
154 | NDIS_STATISTICS_DIRECTED_BYTES_RCV_SUPPORTED
155 | NDIS_STATISTICS_DIRECTED_FRAMES_RCV_SUPPORTED
156 | NDIS_STATISTICS_MULTICAST_BYTES_RCV_SUPPORTED
157 | NDIS_STATISTICS_MULTICAST_FRAMES_RCV_SUPPORTED
158 | NDIS_STATISTICS_BROADCAST_BYTES_RCV_SUPPORTED
159 | NDIS_STATISTICS_BROADCAST_FRAMES_RCV_SUPPORTED
160 | NDIS_STATISTICS_RCV_CRC_ERROR_SUPPORTED
161 | NDIS_STATISTICS_TRANSMIT_QUEUE_LENGTH_SUPPORTED
162 | NDIS_STATISTICS_BYTES_RCV_SUPPORTED
163 | NDIS_STATISTICS_BYTES_XMIT_SUPPORTED
164 | NDIS_STATISTICS_RCV_DISCARDS_SUPPORTED
165 | NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED
166 | NDIS_STATISTICS_XMIT_DISCARDS_SUPPORTED;
167 #endif
169 KeInitializeDpc(&xi->rxtx_dpc, XenNet_RxTxDpc, xi);
171 xi->packet_filter = 0;
173 #if NTDDI_VERSION < NTDDI_VISTA
174 NdisOpenConfiguration(&status, &config_handle, WrapperConfigurationContext);
175 #else
176 config_object.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
177 config_object.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
178 config_object.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
179 config_object.NdisHandle = xi->adapter_handle;
180 config_object.Flags = 0;
182 status = NdisOpenConfigurationEx(&config_object, &config_handle);
183 #endif
184 if (!NT_SUCCESS(status)) {
185 FUNCTION_MSG("Could not open config in registry (%08x)\n", status);
186 status = NDIS_STATUS_RESOURCES;
187 goto err;
188 }
190 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
191 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
192 if (!NT_SUCCESS(status))
193 {
194 FUNCTION_MSG("Could not read ScatterGather value (%08x)\n", status);
195 xi->frontend_sg_supported = TRUE;
196 } else {
197 FUNCTION_MSG("ScatterGather = %d\n", config_param->ParameterData.IntegerData);
198 xi->frontend_sg_supported = (BOOLEAN)!!config_param->ParameterData.IntegerData;
199 }
200 if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
201 FUNCTION_MSG("No support for SG with NDIS 6.0, disabled\n");
202 xi->frontend_sg_supported = FALSE;
203 }
205 NdisInitUnicodeString(&config_param_name, L"RxCoalesce");
206 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
207 if (!NT_SUCCESS(status)) {
208 FUNCTION_MSG("Could not read RxCoalesce value (%08x)\n", status);
209 xi->config_rx_coalesce = TRUE;
210 } else {
211 FUNCTION_MSG("RxCoalesce = %d\n", config_param->ParameterData.IntegerData);
212 xi->config_rx_coalesce = (BOOLEAN)!!config_param->ParameterData.IntegerData;
213 }
215 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
216 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
217 if (!NT_SUCCESS(status)) {
218 FUNCTION_MSG("Could not read LargeSendOffload value (%08x)\n", status);
219 xi->frontend_gso_value = 0;
220 } else {
221 FUNCTION_MSG("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData);
222 xi->frontend_gso_value = config_param->ParameterData.IntegerData;
223 if (xi->frontend_gso_value > 61440) {
224 xi->frontend_gso_value = 61440;
225 FUNCTION_MSG(" (clipped to %d)\n", xi->frontend_gso_value);
226 }
227 if (!xi->frontend_sg_supported && xi->frontend_gso_value > PAGE_SIZE - MAX_PKT_HEADER_LENGTH) {
228 /* without SG, GSO can be a maximum of PAGE_SIZE - MAX_PKT_HEADER_LENGTH */
229 xi->frontend_gso_value = min(xi->frontend_gso_value, PAGE_SIZE - MAX_PKT_HEADER_LENGTH);
230 FUNCTION_MSG(" (clipped to %d with sg disabled)\n", xi->frontend_gso_value);
231 }
232 }
233 if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
234 FUNCTION_MSG("No support for GSO with NDIS 6.0, disabled\n");
235 xi->frontend_gso_value = 0;
236 }
238 NdisInitUnicodeString(&config_param_name, L"LargeSendOffloadRxSplitMTU");
239 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
240 if (!NT_SUCCESS(status)) {
241 FUNCTION_MSG("Could not read LargeSendOffload value (%08x)\n", status);
242 xi->frontend_gso_rx_split_type = RX_LSO_SPLIT_HALF;
243 } else {
244 FUNCTION_MSG("LargeSendOffloadRxSplitMTU = %d\n", config_param->ParameterData.IntegerData);
245 switch (config_param->ParameterData.IntegerData) {
246 case RX_LSO_SPLIT_MSS:
247 case RX_LSO_SPLIT_HALF:
248 case RX_LSO_SPLIT_NONE:
249 xi->frontend_gso_rx_split_type = config_param->ParameterData.IntegerData;
250 break;
251 default:
252 xi->frontend_gso_rx_split_type = RX_LSO_SPLIT_HALF;
253 break;
254 }
255 }
257 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
258 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
259 if (!NT_SUCCESS(status)) {
260 FUNCTION_MSG("Could not read ChecksumOffload value (%08x)\n", status);
261 xi->frontend_csum_supported = TRUE;
262 } else {
263 FUNCTION_MSG("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData);
264 xi->frontend_csum_supported = (BOOLEAN)!!config_param->ParameterData.IntegerData;
265 }
267 NdisInitUnicodeString(&config_param_name, L"MTU");
268 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
269 if (!NT_SUCCESS(status)) {
270 FUNCTION_MSG("Could not read MTU value (%08x)\n", status);
271 xi->frontend_mtu_value = 1500;
272 } else {
273 FUNCTION_MSG("MTU = %d\n", config_param->ParameterData.IntegerData);
274 xi->frontend_mtu_value = config_param->ParameterData.IntegerData;
275 }
277 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
278 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02)) {
279 FUNCTION_MSG("Could not read registry NetworkAddress value (%08x) or value is invalid\n", status);
280 memset(xi->curr_mac_addr, 0, ETH_ALEN);
281 } else {
282 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
283 FUNCTION_MSG("Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
284 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
285 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]);
286 }
288 NdisCloseConfiguration(config_handle);
290 status = XenNet_Connect(xi, FALSE);
291 if (!NT_SUCCESS(status)) {
292 goto err;
293 }
295 if (!xi->backend_sg_supported)
296 xi->backend_gso_value = min(xi->backend_gso_value, PAGE_SIZE - MAX_PKT_HEADER_LENGTH);
298 xi->current_sg_supported = xi->frontend_sg_supported && xi->backend_sg_supported;
299 xi->current_mtu_value = xi->frontend_mtu_value;
300 xi->current_gso_rx_split_type = xi->frontend_gso_rx_split_type;
302 #if NTDDI_VERSION < NTDDI_VISTA
303 /* these are set by OID for NDIS5 */
304 xi->current_csum_supported = FALSE;
305 xi->current_gso_value = 0;
306 xi->config_max_pkt_size = xi->current_mtu_value + XN_HDR_SIZE;
307 #else
308 xi->current_csum_supported = xi->frontend_csum_supported && xi->backend_csum_supported;
309 xi->current_gso_value = min(xi->backend_gso_value, xi->backend_gso_value);
310 xi->config_max_pkt_size = max(xi->current_mtu_value + XN_HDR_SIZE, xi->current_gso_value + XN_HDR_SIZE);
311 #endif
313 #if NTDDI_VERSION < NTDDI_VISTA
314 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE)xi, 0, 0 /* the last zero is to give the next | something to | with */
315 #ifdef NDIS51_MINIPORT
316 |NDIS_ATTRIBUTE_USES_SAFE_BUFFER_APIS
317 #endif
318 |NDIS_ATTRIBUTE_DESERIALIZE
319 |NDIS_ATTRIBUTE_SURPRISE_REMOVE_OK,
320 NdisInterfaceInternal); /* PnpBus option doesn't exist... */
321 #else
322 registration_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
323 registration_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
324 registration_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
325 registration_attributes.MiniportAdapterContext = xi;
326 registration_attributes.AttributeFlags = 0;
327 registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_HARDWARE_DEVICE;
328 registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK;
329 registration_attributes.CheckForHangTimeInSeconds = 0; /* use default */
330 registration_attributes.InterfaceType = NdisInterfacePNPBus;
331 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&registration_attributes);
332 if (!NT_SUCCESS(status)) {
333 FUNCTION_MSG("NdisMSetMiniportAttributes(registration) failed (%08x)\n", status);
334 goto err;
335 }
337 general_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
338 general_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; /* revision 2 is NDIS 6.2 */
339 general_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
340 general_attributes.Flags = 0;
341 general_attributes.MediaType = NdisMedium802_3;
342 general_attributes.PhysicalMediumType = NdisPhysicalMediumOther;
343 general_attributes.MtuSize = xi->current_mtu_value;
344 general_attributes.MaxXmitLinkSpeed = MAX_LINK_SPEED;
345 general_attributes.XmitLinkSpeed = MAX_LINK_SPEED;
346 general_attributes.MaxRcvLinkSpeed = MAX_LINK_SPEED;
347 general_attributes.RcvLinkSpeed = MAX_LINK_SPEED;
348 general_attributes.MediaConnectState = MediaConnectStateConnected;
349 general_attributes.MediaDuplexState = MediaDuplexStateFull;
350 general_attributes.LookaheadSize = xi->current_lookahead;
351 general_attributes.PowerManagementCapabilities = NULL;
352 general_attributes.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
353 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
354 NDIS_MAC_OPTION_NO_LOOPBACK;
355 general_attributes.SupportedPacketFilters = SUPPORTED_PACKET_FILTERS;
356 general_attributes.MaxMulticastListSize = MULTICAST_LIST_MAX_SIZE;
357 general_attributes.MacAddressLength = 6;
358 NdisMoveMemory(general_attributes.PermanentMacAddress, xi->perm_mac_addr, general_attributes.MacAddressLength);
359 NdisMoveMemory(general_attributes.CurrentMacAddress, xi->curr_mac_addr, general_attributes.MacAddressLength);
360 general_attributes.RecvScaleCapabilities = NULL; /* we do want to support this soon */
361 general_attributes.AccessType = NET_IF_ACCESS_BROADCAST;
362 general_attributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
363 general_attributes.ConnectionType = NET_IF_CONNECTION_DEDICATED;
364 general_attributes.IfType = IF_TYPE_ETHERNET_CSMACD;
365 general_attributes.IfConnectorPresent = TRUE;
366 general_attributes.SupportedStatistics = xi->stats.SupportedStatistics;
367 general_attributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
368 general_attributes.DataBackFillSize = 0; // see NdisRetreatNetBufferDataStart
369 general_attributes.ContextBackFillSize = 0; // ?? NFI ??
371 for (i = 0; xennet_oids[i].oid; i++);
373 status = NdisAllocateMemoryWithTag((PVOID)&supported_oids, sizeof(NDIS_OID) * i, XENNET_POOL_TAG);
374 if (!NT_SUCCESS(status)) {
375 FUNCTION_MSG("NdisAllocateMemoryWithTag failed with 0x%x\n", status);
376 status = NDIS_STATUS_RESOURCES;
377 goto err;
378 }
380 for (i = 0; xennet_oids[i].oid; i++) {
381 supported_oids[i] = xennet_oids[i].oid;
382 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);
383 }
384 general_attributes.SupportedOidList = supported_oids;
385 general_attributes.SupportedOidListLength = sizeof(NDIS_OID) * i;
386 general_attributes.AutoNegotiationFlags = NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED
387 | NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED
388 | NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
389 //general_attributes.PowerManagementCapabilitiesEx = NULL; // >= 6.20
390 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&general_attributes);
391 if (!NT_SUCCESS(status)) {
392 FUNCTION_MSG("NdisMSetMiniportAttributes(general) failed (%08x)\n", status);
393 goto err;
394 }
395 NdisFreeMemory(supported_oids, 0, 0);
397 /* this is the initial offload state */
398 RtlZeroMemory(&df_offload, sizeof(df_offload));
399 df_offload.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
400 df_offload.Header.Revision = NDIS_OFFLOAD_REVISION_1; // revision 2 does exist
401 df_offload.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
402 /* this is the supported offload state */
403 RtlZeroMemory(&hw_offload, sizeof(hw_offload));
404 hw_offload.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
405 hw_offload.Header.Revision = NDIS_OFFLOAD_REVISION_1; // revision 2 does exist
406 hw_offload.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
407 if (xi->current_csum_supported)
408 {
409 df_offload.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
410 df_offload.Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_SET_ON;
411 df_offload.Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SET_ON;
412 df_offload.Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_SET_ON;
413 df_offload.Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_SET_ON;
414 df_offload.Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_SET_ON;
415 df_offload.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
416 df_offload.Checksum.IPv4Receive.IpOptionsSupported = NDIS_OFFLOAD_SET_ON;
417 df_offload.Checksum.IPv4Receive.TcpOptionsSupported = NDIS_OFFLOAD_SET_ON;
418 df_offload.Checksum.IPv4Receive.TcpChecksum = NDIS_OFFLOAD_SET_ON;
419 df_offload.Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_SET_ON;
420 df_offload.Checksum.IPv4Receive.IpChecksum = NDIS_OFFLOAD_SET_ON;
421 /* offload.Checksum.IPv6Transmit is not supported */
422 /* offload.Checksum.IPv6Receive is not supported */
423 hw_offload.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
424 hw_offload.Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
425 hw_offload.Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
426 hw_offload.Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
427 hw_offload.Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
428 hw_offload.Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
429 hw_offload.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
430 hw_offload.Checksum.IPv4Receive.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
431 hw_offload.Checksum.IPv4Receive.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
432 hw_offload.Checksum.IPv4Receive.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
433 hw_offload.Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
434 hw_offload.Checksum.IPv4Receive.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
435 /* hw_offload.Checksum.IPv6Transmit is not supported */
436 /* hw_offload.Checksum.IPv6Receive is not supported */
437 }
438 if (xi->current_gso_value)
439 {
440 hw_offload.LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
441 hw_offload.LsoV1.IPv4.MaxOffLoadSize = xi->current_gso_value;
442 hw_offload.LsoV1.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
443 hw_offload.LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
444 hw_offload.LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
445 hw_offload.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
446 hw_offload.LsoV2.IPv4.MaxOffLoadSize = xi->current_gso_value;
447 hw_offload.LsoV2.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
448 /* hw_offload.LsoV2.IPv6 is not supported */
449 df_offload.LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
450 df_offload.LsoV1.IPv4.MaxOffLoadSize = xi->current_gso_value;
451 df_offload.LsoV1.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
452 df_offload.LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
453 df_offload.LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
454 df_offload.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
455 df_offload.LsoV2.IPv4.MaxOffLoadSize = xi->current_gso_value;
456 df_offload.LsoV2.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
457 /* df_offload.LsoV2.IPv6 is not supported */
458 }
459 /* hw_offload.IPsecV1 is not supported */
460 /* hw_offload.IPsecV2 is not supported */
461 /* df_offload.IPsecV1 is not supported */
462 /* df_offload.IPsecV2 is not supported */
463 hw_offload.Flags = 0;
464 df_offload.Flags = 0;
466 RtlZeroMemory(&df_conn_offload, sizeof(df_conn_offload));
467 df_conn_offload.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
468 df_conn_offload.Header.Revision = NDIS_TCP_CONNECTION_OFFLOAD_REVISION_1;
469 df_conn_offload.Header.Size = NDIS_SIZEOF_TCP_CONNECTION_OFFLOAD_REVISION_1;
471 RtlZeroMemory(&hw_conn_offload, sizeof(hw_conn_offload));
472 hw_conn_offload.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
473 hw_conn_offload.Header.Revision = NDIS_TCP_CONNECTION_OFFLOAD_REVISION_1;
474 hw_conn_offload.Header.Size = NDIS_SIZEOF_TCP_CONNECTION_OFFLOAD_REVISION_1;
476 offload_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES;
477 offload_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1;
478 offload_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1;
479 offload_attributes.DefaultOffloadConfiguration = &df_offload;
480 offload_attributes.HardwareOffloadCapabilities = &hw_offload;
481 offload_attributes.DefaultTcpConnectionOffloadConfiguration = &df_conn_offload;
482 offload_attributes.TcpConnectionOffloadHardwareCapabilities = &hw_conn_offload;
483 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&offload_attributes);
484 if (!NT_SUCCESS(status)) {
485 FUNCTION_MSG("NdisMSetMiniportAttributes(offload) failed (%08x)\n", status);
486 goto err;
487 }
489 #if 0
490 if (ndis_os_minor_version >= 1) {
491 NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES hw_assist_attributes;
492 NDIS_HD_SPLIT_ATTRIBUTES hd_split_attributes;
494 RtlZeroMemory(&hd_split_attributes, sizeof(hd_split_attributes));
495 hd_split_attributes.Header.Type = NDIS_OBJECT_TYPE_HD_SPLIT_ATTRIBUTES;
496 hd_split_attributes.Header.Revision = NDIS_HD_SPLIT_ATTRIBUTES_REVISION_1;
497 hd_split_attributes.Header.Size = NDIS_SIZEOF_HD_SPLIT_ATTRIBUTES_REVISION_1;
498 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;
499 hd_split_attributes.CurrentCapabilities = hd_split_attributes.HardwareCapabilities;
500 /* the other members are set on output */
502 RtlZeroMemory(&hw_assist_attributes, sizeof(hw_assist_attributes));
503 hw_assist_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES;
504 hw_assist_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
505 hw_assist_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
506 hw_assist_attributes.HDSplitAttributes = &hd_split_attributes;
507 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&hw_assist_attributes);
508 if (!NT_SUCCESS(status))
509 {
510 FUNCTION_MSG("NdisMSetMiniportAttributes(hw_assist) failed (%08x)\n", status);
511 goto err;
512 }
513 FUNCTION_MSG("HW Split enabled\n");
514 FUNCTION_MSG(" HDSplitFlags = %08x\n", hd_split_attributes.HDSplitFlags);
515 FUNCTION_MSG(" BackfillSize = %d\n", hd_split_attributes.BackfillSize);
516 FUNCTION_MSG(" MaxHeaderSize = %d\n", hd_split_attributes.MaxHeaderSize);
517 //what about backfill here?
518 }
519 #endif
520 #endif
521 if (xi->device_state != DEVICE_STATE_INACTIVE)
522 xi->device_state = DEVICE_STATE_ACTIVE;
523 FUNCTION_EXIT();
524 return NDIS_STATUS_SUCCESS;
526 err:
527 if (xi) {
528 NdisFreeMemory(xi, 0, 0);
529 }
530 FUNCTION_EXIT_STATUS(status);
532 return status;
533 }
535 #if NTDDI_VERSION < NTDDI_VISTA
536 static VOID
537 XenNet_PnPEventNotify(NDIS_HANDLE adapter_context, NDIS_DEVICE_PNP_EVENT pnp_event, PVOID information_buffer, ULONG information_buffer_length) {
538 UNREFERENCED_PARAMETER(information_buffer);
539 UNREFERENCED_PARAMETER(information_buffer_length);
540 UNREFERENCED_PARAMETER(adapter_context);
542 FUNCTION_ENTER();
543 switch (pnp_event)
544 {
545 case NdisDevicePnPEventSurpriseRemoved:
546 FUNCTION_MSG("NdisDevicePnPEventSurpriseRemoved\n");
547 break;
548 case NdisDevicePnPEventPowerProfileChanged :
549 FUNCTION_MSG("NdisDevicePnPEventPowerProfileChanged\n");
550 break;
551 default:
552 FUNCTION_MSG("NdisDevicePnPEvent%d\n", pnp_event);
553 break;
554 }
555 FUNCTION_EXIT();
556 }
557 #else
558 static VOID
559 XenNet_DevicePnPEventNotify(NDIS_HANDLE adapter_context, PNET_DEVICE_PNP_EVENT pnp_event) {
560 UNREFERENCED_PARAMETER(adapter_context);
562 FUNCTION_ENTER();
563 switch (pnp_event->DevicePnPEvent)
564 {
565 case NdisDevicePnPEventSurpriseRemoved:
566 FUNCTION_MSG("NdisDevicePnPEventSurpriseRemoved\n");
567 break;
568 case NdisDevicePnPEventPowerProfileChanged :
569 FUNCTION_MSG("NdisDevicePnPEventPowerProfileChanged\n");
570 break;
571 default:
572 FUNCTION_MSG("NdisDevicePnPEvent%d\n", pnp_event->DevicePnPEvent);
573 break;
574 }
575 FUNCTION_EXIT();
576 }
577 #endif
579 /* called at <= HIGH_IRQL, or PASSIVE_LEVEL, depending on shutdown_action */
580 static VOID
581 #if NTDDI_VERSION < NTDDI_VISTA
582 XenNet_Shutdown(NDIS_HANDLE adapter_context) {
583 #else
584 XenNet_Shutdown(NDIS_HANDLE adapter_context, NDIS_SHUTDOWN_ACTION shutdown_action) {
585 UNREFERENCED_PARAMETER(shutdown_action);
586 #endif
587 UNREFERENCED_PARAMETER(adapter_context);
588 FUNCTION_ENTER();
589 FUNCTION_EXIT();
590 }
592 static BOOLEAN
593 XenNet_CheckForHang(NDIS_HANDLE adapter_context)
594 {
595 UNREFERENCED_PARAMETER(adapter_context);
597 //FUNCTION_ENTER();
598 //FUNCTION_EXIT();
599 return FALSE;
600 }
602 /* Opposite of XenNet_Init */
603 static VOID
604 #if NTDDI_VERSION < NTDDI_VISTA
605 XenNet_Halt(NDIS_HANDLE adapter_context) {
606 #else
607 XenNet_Halt(NDIS_HANDLE adapter_context, NDIS_HALT_ACTION halt_action) {
608 #endif
609 struct xennet_info *xi = adapter_context;
610 #if NTDDI_VERSION < NTDDI_VISTA
611 #else
612 UNREFERENCED_PARAMETER(halt_action);
613 #endif
614 FUNCTION_ENTER();
615 XenNet_Disconnect(xi, FALSE);
616 NdisFreeMemory(xi, 0, 0);
618 FUNCTION_EXIT();
619 }
621 static NDIS_STATUS
622 XenNet_Reset(NDIS_HANDLE adapter_context, PBOOLEAN addressing_reset)
623 {
624 UNREFERENCED_PARAMETER(adapter_context);
626 FUNCTION_ENTER();
627 *addressing_reset = FALSE;
628 FUNCTION_EXIT();
629 return NDIS_STATUS_SUCCESS;
630 }
632 #if NTDDI_VERSION < NTDDI_VISTA
633 #else
634 /* called at PASSIVE_LEVEL */
635 static NDIS_STATUS
636 XenNet_Pause(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_PAUSE_PARAMETERS pause_parameters)
637 {
638 UNREFERENCED_PARAMETER(adapter_context);
639 UNREFERENCED_PARAMETER(pause_parameters);
640 FUNCTION_ENTER();
641 FUNCTION_EXIT();
642 return STATUS_SUCCESS;
643 }
645 /* called at PASSIVE_LEVEL */
646 static NDIS_STATUS
647 XenNet_Restart(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_RESTART_PARAMETERS restart_parameters)
648 {
649 UNREFERENCED_PARAMETER(adapter_context);
650 UNREFERENCED_PARAMETER(restart_parameters);
651 FUNCTION_ENTER();
652 FUNCTION_EXIT();
653 return STATUS_SUCCESS;
654 }
656 static VOID
657 XenNet_Unload(PDRIVER_OBJECT driver_object)
658 {
659 UNREFERENCED_PARAMETER(driver_object);
660 FUNCTION_ENTER();
661 NdisMDeregisterMiniportDriver(driver_handle);
662 FUNCTION_EXIT();
663 }
665 static NDIS_STATUS
666 XenNet_SetOptions(NDIS_HANDLE driver_handle, NDIS_HANDLE driver_context)
667 {
668 UNREFERENCED_PARAMETER(driver_handle);
669 UNREFERENCED_PARAMETER(driver_context);
670 FUNCTION_ENTER();
671 FUNCTION_EXIT();
672 return STATUS_SUCCESS;
673 }
674 #endif
676 NTSTATUS
677 DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
678 {
679 NTSTATUS status;
680 ULONG ndis_version;
681 #if NTDDI_VERSION < NTDDI_VISTA
682 NDIS_HANDLE ndis_wrapper_handle = NULL;
683 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
684 #else
685 NDIS_MINIPORT_DRIVER_CHARACTERISTICS mini_chars;
686 #endif
688 FUNCTION_ENTER();
690 NdisZeroMemory(&mini_chars, sizeof(mini_chars));
692 ndis_version = NdisGetVersion();
694 ndis_os_major_version = (USHORT)(ndis_version >> 16);
695 ndis_os_minor_version = (USHORT)(ndis_version & 0xFFFF);
697 FUNCTION_MSG("Driver MajorNdisVersion = %d, Driver MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION);
698 FUNCTION_MSG("Windows MajorNdisVersion = %d, Windows MinorNdisVersion = %d\n", ndis_os_major_version, ndis_os_minor_version);
700 #if NTDDI_VERSION < NTDDI_VISTA
701 NdisMInitializeWrapper(&ndis_wrapper_handle, driver_object, registry_path, NULL);
702 if (!ndis_wrapper_handle) {
703 FUNCTION_MSG("NdisMInitializeWrapper failed\n");
704 return NDIS_STATUS_FAILURE;
705 }
707 mini_chars.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
708 mini_chars.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
709 mini_chars.HaltHandler = XenNet_Halt;
710 mini_chars.InitializeHandler = XenNet_Init;
711 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
712 mini_chars.ResetHandler = XenNet_Reset;
713 mini_chars.SetInformationHandler = XenNet_SetInformation;
714 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
715 mini_chars.SendPacketsHandler = XenNet_SendPackets;
716 #ifdef NDIS51_MINIPORT
717 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
718 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
719 #endif
720 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
721 if (!NT_SUCCESS(status)) {
722 FUNCTION_MSG("NdisMRegisterMiniport failed, status = 0x%x\n", status);
723 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
724 return status;
725 }
726 #else
727 mini_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
729 if (ndis_os_minor_version < 1) {
730 mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
731 mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
733 mini_chars.MajorNdisVersion = 6;
734 mini_chars.MinorNdisVersion = 0;
735 } else {
736 mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
737 mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
738 mini_chars.MajorNdisVersion = 6;
739 mini_chars.MinorNdisVersion = 1;
740 }
741 mini_chars.MajorDriverVersion = VENDOR_DRIVER_VERSION_MAJOR;
742 mini_chars.MinorDriverVersion = VENDOR_DRIVER_VERSION_MINOR;
744 mini_chars.Flags = NDIS_WDM_DRIVER;
746 mini_chars.SetOptionsHandler = XenNet_SetOptions;
747 mini_chars.InitializeHandlerEx = XenNet_Initialize;
748 mini_chars.HaltHandlerEx = XenNet_Halt;
749 mini_chars.UnloadHandler = XenNet_Unload;
750 mini_chars.PauseHandler = XenNet_Pause;
751 mini_chars.RestartHandler = XenNet_Restart;
752 mini_chars.CheckForHangHandlerEx = XenNet_CheckForHang;
753 mini_chars.ResetHandlerEx = XenNet_Reset;
754 mini_chars.DevicePnPEventNotifyHandler = XenNet_DevicePnPEventNotify;
755 mini_chars.ShutdownHandlerEx = XenNet_Shutdown;
757 mini_chars.OidRequestHandler = XenNet_OidRequest;
758 mini_chars.CancelOidRequestHandler = XenNet_CancelOidRequest;
759 if (ndis_os_minor_version >= 1) {
760 mini_chars.DirectOidRequestHandler = NULL;
761 mini_chars.CancelDirectOidRequestHandler = NULL;
762 }
764 mini_chars.SendNetBufferListsHandler = XenNet_SendNetBufferLists;
765 mini_chars.CancelSendHandler = XenNet_CancelSend;
767 mini_chars.ReturnNetBufferListsHandler = XenNet_ReturnNetBufferLists;
769 status = NdisMRegisterMiniportDriver(driver_object, registry_path, NULL, &mini_chars, &driver_handle);
770 if (!NT_SUCCESS(status)) {
771 FUNCTION_MSG("NdisMRegisterMiniportDriver failed, status = 0x%x\n", status);
772 return status;
773 }
774 #endif
775 FUNCTION_EXIT();
777 return status;
778 }