win-pvdrivers

view xennet/xennet6.c @ 962:278b479f3f7d

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 81f132396f9e
children 8f483a2b2991
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover <andy.grover@oracle.com>
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
21 #include <stdlib.h>
22 #include <io/xenbus.h>
23 #include "xennet6.h"
25 /* Not really necessary but keeps PREfast happy */
26 DRIVER_INITIALIZE DriverEntry;
27 static IO_WORKITEM_ROUTINE XenNet_ResumeWorkItem;
28 #if (VER_PRODUCTBUILD >= 7600)
29 static KDEFERRED_ROUTINE XenNet_SuspendResume;
30 #endif
32 #pragma NDIS_INIT_FUNCTION(DriverEntry)
34 NDIS_HANDLE driver_handle = NULL;
36 USHORT ndis_os_major_version = 0;
37 USHORT ndis_os_minor_version = 0;
39 /* ----- BEGIN Other people's code --------- */
40 /* from linux/include/linux/ctype.h, used under GPLv2 */
41 #define _U 0x01 /* upper */
42 #define _L 0x02 /* lower */
43 #define _D 0x04 /* digit */
44 #define _C 0x08 /* cntrl */
45 #define _P 0x10 /* punct */
46 #define _S 0x20 /* white space (space/lf/tab) */
47 #define _X 0x40 /* hex digit */
48 #define _SP 0x80 /* hard space (0x20) */
50 /* from linux/include/lib/ctype.c, used under GPLv2 */
51 unsigned char _ctype[] = {
52 _C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
53 _C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
54 _C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
55 _C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
56 _S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
57 _P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
58 _D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
59 _D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
60 _P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
61 _U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
62 _U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
63 _U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
64 _P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
65 _L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
66 _L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
67 _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
68 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
69 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
70 _S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
71 _P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
72 _U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
73 _U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
74 _L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
75 _L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
77 /* from linux/include/linux/ctype.h, used under GPLv2 */
78 #define __ismask(x) (_ctype[(int)(unsigned char)(x)])
80 #define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
81 #define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
82 #define iscntrl(c) ((__ismask(c)&(_C)) != 0)
83 #define isdigit(c) ((__ismask(c)&(_D)) != 0)
84 #define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
85 #define islower(c) ((__ismask(c)&(_L)) != 0)
86 #define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
87 #define ispunct(c) ((__ismask(c)&(_P)) != 0)
88 #define isspace(c) ((__ismask(c)&(_S)) != 0)
89 #define isupper(c) ((__ismask(c)&(_U)) != 0)
90 #define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
92 #define TOLOWER(x) ((x) | 0x20)
94 /* from linux/lib/vsprintf.c, used under GPLv2 */
95 /* Copyright (C) 1991, 1992 Linus Torvalds
96 * Wirzenius wrote this portably, Torvalds fucked it up :-)
97 */
98 /**
99 * simple_strtoul - convert a string to an unsigned long
100 * @cp: The start of the string
101 * @endp: A pointer to the end of the parsed string will be placed here
102 * @base: The number base to use
103 */
104 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
105 {
106 unsigned long result = 0,value;
108 if (!base) {
109 base = 10;
110 if (*cp == '0') {
111 base = 8;
112 cp++;
113 if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) {
114 cp++;
115 base = 16;
116 }
117 }
118 } else if (base == 16) {
119 if (cp[0] == '0' && TOLOWER(cp[1]) == 'x')
120 cp += 2;
121 }
122 while (isxdigit(*cp) &&
123 (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) {
124 result = result*base + value;
125 cp++;
126 }
127 if (endp)
128 *endp = (char *)cp;
129 return result;
130 }
131 /* end vsprintf.c code */
132 /* ----- END Other people's code --------- */
134 static NDIS_STATUS
135 XenNet_ConnectBackend(struct xennet_info *xi)
136 {
137 PUCHAR ptr;
138 UCHAR type;
139 PCHAR setting, value, value2;
140 UINT i;
142 FUNCTION_ENTER();
144 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
146 xi->backend_csum_supported = TRUE; /* just assume this */
147 xi->backend_gso_value = 0;
148 xi->backend_sg_supported = FALSE;
150 ptr = xi->config_page;
151 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value2)) != XEN_INIT_TYPE_END)
152 {
153 switch(type)
154 {
155 case XEN_INIT_TYPE_RING: /* frontend ring */
156 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_RING - %s = %p\n", setting, value));
157 if (strcmp(setting, "tx-ring-ref") == 0)
158 {
159 FRONT_RING_INIT(&xi->tx, (netif_tx_sring_t *)value, PAGE_SIZE);
160 } else if (strcmp(setting, "rx-ring-ref") == 0)
161 {
162 FRONT_RING_INIT(&xi->rx, (netif_rx_sring_t *)value, PAGE_SIZE);
163 }
164 break;
165 case XEN_INIT_TYPE_EVENT_CHANNEL: /* frontend event channel */
166 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_EVENT_CHANNEL - %s = %d\n", setting, PtrToUlong(value)));
167 if (strcmp(setting, "event-channel") == 0)
168 {
169 xi->event_channel = PtrToUlong(value);
170 }
171 break;
172 case XEN_INIT_TYPE_READ_STRING_FRONT:
173 break;
174 case XEN_INIT_TYPE_READ_STRING_BACK:
175 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
176 if (strcmp(setting, "mac") == 0)
177 {
178 char *s, *e;
179 s = value;
180 for (i = 0; i < ETH_ALEN; i++) {
181 xi->perm_mac_addr[i] = (uint8_t)simple_strtoul(s, &e, 16);
182 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
183 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
184 }
185 s = e + 1;
186 }
187 if ((xi->curr_mac_addr[0] & 0x03) != 0x02)
188 {
189 /* only copy if curr_mac_addr is not a LUA */
190 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
191 }
192 }
193 else if (strcmp(setting, "feature-sg") == 0)
194 {
195 if (atoi(value))
196 {
197 xi->backend_sg_supported = TRUE;
198 }
199 }
200 else if (strcmp(setting, "feature-gso-tcpv4") == 0)
201 {
202 if (atoi(value))
203 {
204 xi->backend_gso_value = xi->frontend_gso_value;
205 }
206 }
207 break;
208 case XEN_INIT_TYPE_VECTORS:
209 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
210 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
211 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
212 {
213 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
214 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
215 FUNCTION_EXIT();
216 return NDIS_STATUS_ADAPTER_NOT_FOUND;
217 }
218 else
219 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
220 break;
221 case XEN_INIT_TYPE_STATE_PTR:
222 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
223 xi->device_state = (PXENPCI_DEVICE_STATE)value;
224 break;
225 default:
226 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
227 break;
228 }
229 }
230 if (!xi->backend_sg_supported)
231 xi->backend_gso_value = min(xi->backend_gso_value, PAGE_SIZE - MAX_PKT_HEADER_LENGTH);
233 xi->current_sg_supported = xi->frontend_sg_supported && xi->backend_sg_supported;
234 xi->current_csum_supported = xi->frontend_csum_supported && xi->backend_csum_supported;
235 xi->current_gso_value = min(xi->backend_gso_value, xi->backend_gso_value);
236 xi->current_mtu_value = xi->frontend_mtu_value;
237 xi->current_gso_rx_split_type = xi->frontend_gso_rx_split_type;
239 FUNCTION_EXIT();
241 return NDIS_STATUS_SUCCESS;
242 } /* XenNet_ConnectBackend */
244 static VOID
245 XenNet_ResumeWorkItem(PDEVICE_OBJECT device_object, PVOID context)
246 {
247 struct xennet_info *xi = context;
248 KIRQL old_irql;
250 UNREFERENCED_PARAMETER(device_object);
252 FUNCTION_ENTER();
254 ASSERT(xi->resume_work_item);
256 IoFreeWorkItem(xi->resume_work_item);
258 XenNet_TxResumeStart(xi);
259 XenNet_RxResumeStart(xi);
260 XenNet_ConnectBackend(xi);
261 XenNet_RxResumeEnd(xi);
262 XenNet_TxResumeEnd(xi);
264 KeAcquireSpinLock(&xi->resume_lock, &old_irql);
265 xi->resume_work_item = NULL;
266 KdPrint((__DRIVER_NAME " *Setting suspend_resume_state_fdo = %d\n", xi->device_state->suspend_resume_state_pdo));
267 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
268 KdPrint((__DRIVER_NAME " *Notifying event channel %d\n", xi->device_state->pdo_event_channel));
269 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
270 KeReleaseSpinLock(&xi->resume_lock, old_irql);
272 FUNCTION_EXIT();
274 }
276 static VOID
277 XenNet_SuspendResume(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
278 {
279 struct xennet_info *xi = context;
280 KIRQL old_irql;
281 PIO_WORKITEM resume_work_item;
283 UNREFERENCED_PARAMETER(dpc);
284 UNREFERENCED_PARAMETER(arg1);
285 UNREFERENCED_PARAMETER(arg2);
287 FUNCTION_ENTER();
289 switch (xi->device_state->suspend_resume_state_pdo)
290 {
291 case SR_STATE_SUSPENDING:
292 KdPrint((__DRIVER_NAME " New state SUSPENDING\n"));
293 KeAcquireSpinLock(&xi->rx_lock, &old_irql);
294 if (xi->rx_id_free == NET_RX_RING_SIZE)
295 {
296 xi->device_state->suspend_resume_state_fdo = SR_STATE_SUSPENDING;
297 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
298 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
299 }
300 KeReleaseSpinLock(&xi->rx_lock, old_irql);
301 break;
302 case SR_STATE_RESUMING:
303 KdPrint((__DRIVER_NAME " New state SR_STATE_RESUMING\n"));
304 /* do it like this so we don't race and double-free the work item */
305 resume_work_item = IoAllocateWorkItem(xi->fdo);
306 KeAcquireSpinLock(&xi->resume_lock, &old_irql);
307 if (xi->resume_work_item || xi->device_state->suspend_resume_state_fdo == SR_STATE_RESUMING)
308 {
309 KeReleaseSpinLock(&xi->resume_lock, old_irql);
310 IoFreeWorkItem(resume_work_item);
311 return;
312 }
313 xi->resume_work_item = resume_work_item;
314 KeReleaseSpinLock(&xi->resume_lock, old_irql);
315 IoQueueWorkItem(xi->resume_work_item, XenNet_ResumeWorkItem, DelayedWorkQueue, xi);
316 break;
317 default:
318 KdPrint((__DRIVER_NAME " New state %d\n", xi->device_state->suspend_resume_state_fdo));
319 xi->device_state->suspend_resume_state_fdo = xi->device_state->suspend_resume_state_pdo;
320 KdPrint((__DRIVER_NAME " Notifying event channel %d\n", xi->device_state->pdo_event_channel));
321 xi->vectors.EvtChn_Notify(xi->vectors.context, xi->device_state->pdo_event_channel);
322 break;
323 }
324 KeMemoryBarrier();
326 FUNCTION_EXIT();
327 }
329 static VOID
330 XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
331 {
332 struct xennet_info *xi = context;
333 BOOLEAN dont_set_event;
335 UNREFERENCED_PARAMETER(dpc);
336 UNREFERENCED_PARAMETER(arg1);
337 UNREFERENCED_PARAMETER(arg2);
339 //FUNCTION_ENTER();
340 /* 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 */
341 dont_set_event = XenNet_RxBufferCheck(xi);
342 XenNet_TxBufferGC(xi, dont_set_event);
343 //FUNCTION_EXIT();
344 }
346 static BOOLEAN
347 XenNet_HandleEvent(PVOID context)
348 {
349 struct xennet_info *xi = context;
350 ULONG suspend_resume_state_pdo;
352 //FUNCTION_ENTER();
353 suspend_resume_state_pdo = xi->device_state->suspend_resume_state_pdo;
354 KeMemoryBarrier();
356 if (!xi->shutting_down && suspend_resume_state_pdo != xi->device_state->suspend_resume_state_fdo)
357 {
358 KeInsertQueueDpc(&xi->suspend_dpc, NULL, NULL);
359 }
360 if (xi->connected && !xi->inactive && suspend_resume_state_pdo != SR_STATE_RESUMING)
361 {
362 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
363 }
364 //FUNCTION_EXIT();
365 return TRUE;
366 }
368 #if 0
369 VOID
370 XenNet_SetPower(PDEVICE_OBJECT device_object, PVOID context)
371 {
372 NTSTATUS status = STATUS_SUCCESS;
373 KIRQL old_irql;
374 struct xennet_info *xi = context;
376 FUNCTION_ENTER();
377 UNREFERENCED_PARAMETER(device_object);
379 switch (xi->new_power_state)
380 {
381 case NdisDeviceStateD0:
382 KdPrint((" NdisDeviceStateD0\n"));
383 status = XenNet_D0Entry(xi);
384 break;
385 case NdisDeviceStateD1:
386 KdPrint((" NdisDeviceStateD1\n"));
387 if (xi->power_state == NdisDeviceStateD0)
388 status = XenNet_D0Exit(xi);
389 break;
390 case NdisDeviceStateD2:
391 KdPrint((" NdisDeviceStateD2\n"));
392 if (xi->power_state == NdisDeviceStateD0)
393 status = XenNet_D0Exit(xi);
394 break;
395 case NdisDeviceStateD3:
396 KdPrint((" NdisDeviceStateD3\n"));
397 if (xi->power_state == NdisDeviceStateD0)
398 status = XenNet_D0Exit(xi);
399 break;
400 default:
401 KdPrint((" NdisDeviceState??\n"));
402 status = NDIS_STATUS_NOT_SUPPORTED;
403 break;
404 }
405 xi->power_state = xi->new_power_state;
407 old_irql = KeRaiseIrqlToDpcLevel();
408 NdisMSetInformationComplete(xi->adapter_handle, status);
409 KeLowerIrql(old_irql);
411 FUNCTION_EXIT();
412 }
413 #endif
415 NDIS_STATUS
416 XenNet_D0Entry(struct xennet_info *xi)
417 {
418 NDIS_STATUS status;
419 PUCHAR ptr;
420 CHAR buf[128];
422 FUNCTION_ENTER();
424 xi->shutting_down = FALSE;
426 ptr = xi->config_page;
427 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "tx-ring-ref", NULL, NULL);
428 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_RING, "rx-ring-ref", NULL, NULL);
429 #pragma warning(suppress:4054)
430 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_EVENT_CHANNEL, "event-channel", (PVOID)XenNet_HandleEvent, xi);
431 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "mac", NULL, NULL);
432 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-sg", NULL, NULL);
433 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_READ_STRING_BACK, "feature-gso-tcpv4", NULL, NULL);
434 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "request-rx-copy", "1", NULL);
435 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-rx-notify", "1", NULL);
436 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !xi->frontend_csum_supported);
437 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-no-csum-offload", buf, NULL);
438 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", (int)xi->frontend_sg_supported);
439 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-sg", buf, NULL);
440 RtlStringCbPrintfA(buf, ARRAY_SIZE(buf), "%d", !!xi->frontend_gso_value);
441 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_WRITE_STRING, "feature-gso-tcpv4", buf, NULL);
442 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_PRE_CONNECT, NULL, NULL, NULL);
443 __ADD_XEN_INIT_UCHAR(&ptr, 0); /* no pre-connect required */
444 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_POST_CONNECT, NULL, NULL, NULL);
445 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
446 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateConnected);
447 __ADD_XEN_INIT_UCHAR(&ptr, 20);
448 __ADD_XEN_INIT_UCHAR(&ptr, 0);
449 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_XB_STATE_MAP_SHUTDOWN, NULL, NULL, NULL);
450 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
451 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosing);
452 __ADD_XEN_INIT_UCHAR(&ptr, 50);
453 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
454 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateClosed);
455 __ADD_XEN_INIT_UCHAR(&ptr, 50);
456 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitialising);
457 __ADD_XEN_INIT_UCHAR(&ptr, XenbusStateInitWait);
458 __ADD_XEN_INIT_UCHAR(&ptr, 50);
459 __ADD_XEN_INIT_UCHAR(&ptr, 0);
460 ADD_XEN_INIT_REQ(&ptr, XEN_INIT_TYPE_END, NULL, NULL, NULL);
462 status = xi->vectors.XenPci_XenConfigDevice(xi->vectors.context);
463 if (!NT_SUCCESS(status))
464 {
465 KdPrint(("Failed to complete device configuration (%08x)\n", status));
466 return status;
467 }
469 status = XenNet_ConnectBackend(xi);
471 if (!NT_SUCCESS(status))
472 {
473 KdPrint(("Failed to complete device configuration (%08x)\n", status));
474 return status;
475 }
477 XenNet_TxInit(xi);
478 XenNet_RxInit(xi);
480 xi->connected = TRUE;
482 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
484 FUNCTION_EXIT();
486 return status;
487 }
489 // Called at <= DISPATCH_LEVEL
490 static NDIS_STATUS
491 XenNet_Initialize(NDIS_HANDLE adapter_handle, NDIS_HANDLE driver_context, PNDIS_MINIPORT_INIT_PARAMETERS init_parameters)
492 {
493 NDIS_STATUS status;
494 struct xennet_info *xi = NULL;
495 PNDIS_RESOURCE_LIST nrl;
496 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
497 NDIS_HANDLE config_handle;
498 NDIS_STRING config_param_name;
499 NDIS_CONFIGURATION_OBJECT config_object;
500 PNDIS_CONFIGURATION_PARAMETER config_param;
501 //PNDIS_MINIPORT_ADAPTER_ATTRIBUTES adapter_attributes;
502 ULONG i;
503 PUCHAR ptr;
504 UCHAR type;
505 PCHAR setting, value;
506 ULONG length;
507 //CHAR buf[128];
508 PVOID network_address;
509 UINT network_address_length;
510 BOOLEAN qemu_hide_filter = FALSE;
511 ULONG qemu_hide_flags_value = 0;
512 NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES registration_attributes;
513 NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES general_attributes;
514 NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES offload_attributes;
515 NDIS_OFFLOAD df_offload, hw_offload;
516 NDIS_TCP_CONNECTION_OFFLOAD df_conn_offload, hw_conn_offload;
517 static NDIS_OID *supported_oids;
519 UNREFERENCED_PARAMETER(driver_context);
521 FUNCTION_ENTER();
523 /* Alloc memory for adapter private info */
524 status = NdisAllocateMemoryWithTag((PVOID)&xi, sizeof(*xi), XENNET_POOL_TAG);
525 if (!NT_SUCCESS(status))
526 {
527 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
528 status = NDIS_STATUS_RESOURCES;
529 goto err;
530 }
531 RtlZeroMemory(xi, sizeof(*xi));
532 xi->adapter_handle = adapter_handle;
533 xi->rx_target = RX_DFL_MIN_TARGET;
534 xi->rx_min_target = RX_DFL_MIN_TARGET;
535 xi->rx_max_target = RX_MAX_TARGET;
536 xi->inactive = TRUE;
538 xi->multicast_list_size = 0;
539 xi->current_lookahead = MIN_LOOKAHEAD_LENGTH;
541 xi->event_channel = 0;
542 xi->stats.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
543 xi->stats.Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
544 xi->stats.Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
545 xi->stats.SupportedStatistics = NDIS_STATISTICS_XMIT_OK_SUPPORTED
546 | NDIS_STATISTICS_RCV_OK_SUPPORTED
547 | NDIS_STATISTICS_XMIT_ERROR_SUPPORTED
548 | NDIS_STATISTICS_RCV_ERROR_SUPPORTED
549 | NDIS_STATISTICS_RCV_NO_BUFFER_SUPPORTED
550 | NDIS_STATISTICS_DIRECTED_BYTES_XMIT_SUPPORTED
551 | NDIS_STATISTICS_DIRECTED_FRAMES_XMIT_SUPPORTED
552 | NDIS_STATISTICS_MULTICAST_BYTES_XMIT_SUPPORTED
553 | NDIS_STATISTICS_MULTICAST_FRAMES_XMIT_SUPPORTED
554 | NDIS_STATISTICS_BROADCAST_BYTES_XMIT_SUPPORTED
555 | NDIS_STATISTICS_BROADCAST_FRAMES_XMIT_SUPPORTED
556 | NDIS_STATISTICS_DIRECTED_BYTES_RCV_SUPPORTED
557 | NDIS_STATISTICS_DIRECTED_FRAMES_RCV_SUPPORTED
558 | NDIS_STATISTICS_MULTICAST_BYTES_RCV_SUPPORTED
559 | NDIS_STATISTICS_MULTICAST_FRAMES_RCV_SUPPORTED
560 | NDIS_STATISTICS_BROADCAST_BYTES_RCV_SUPPORTED
561 | NDIS_STATISTICS_BROADCAST_FRAMES_RCV_SUPPORTED
562 | NDIS_STATISTICS_RCV_CRC_ERROR_SUPPORTED
563 | NDIS_STATISTICS_TRANSMIT_QUEUE_LENGTH_SUPPORTED
564 | NDIS_STATISTICS_BYTES_RCV_SUPPORTED
565 | NDIS_STATISTICS_BYTES_XMIT_SUPPORTED
566 | NDIS_STATISTICS_RCV_DISCARDS_SUPPORTED
567 | NDIS_STATISTICS_GEN_STATISTICS_SUPPORTED
568 | NDIS_STATISTICS_XMIT_DISCARDS_SUPPORTED;
570 nrl = init_parameters->AllocatedResources;
571 for (i = 0; i < nrl->Count; i++)
572 {
573 prd = &nrl->PartialDescriptors[i];
575 switch(prd->Type)
576 {
577 case CmResourceTypeInterrupt:
578 break;
579 case CmResourceTypeMemory:
580 if (xi->config_page)
581 {
582 KdPrint(("More than one memory range\n"));
583 return NDIS_STATUS_RESOURCES;
584 }
585 else
586 {
587 status = NdisMMapIoSpace(&xi->config_page, xi->adapter_handle, prd->u.Memory.Start, prd->u.Memory.Length);
588 if (!NT_SUCCESS(status))
589 {
590 KdPrint(("NdisMMapIoSpace failed with 0x%x\n", status));
591 return NDIS_STATUS_RESOURCES;
592 }
593 }
594 break;
595 }
596 }
597 if (!xi->config_page)
598 {
599 KdPrint(("No config page given\n"));
600 return NDIS_STATUS_RESOURCES;
601 }
603 KeInitializeDpc(&xi->suspend_dpc, XenNet_SuspendResume, xi);
604 KeInitializeSpinLock(&xi->resume_lock);
606 KeInitializeDpc(&xi->rxtx_dpc, XenNet_RxTxDpc, xi);
607 KeSetTargetProcessorDpc(&xi->rxtx_dpc, 0);
608 KeSetImportanceDpc(&xi->rxtx_dpc, HighImportance);
610 NdisMGetDeviceProperty(xi->adapter_handle, &xi->pdo, &xi->fdo,
611 &xi->lower_do, NULL, NULL);
612 xi->packet_filter = 0;
614 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
615 NAME_SIZE, xi->dev_desc, &length);
616 if (!NT_SUCCESS(status))
617 {
618 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
619 status = NDIS_STATUS_FAILURE;
620 goto err;
621 }
623 ptr = xi->config_page;
624 while((type = GET_XEN_INIT_RSP(&ptr, (PVOID)&setting, (PVOID)&value, (PVOID)&value)) != XEN_INIT_TYPE_END)
625 {
626 switch(type)
627 {
628 case XEN_INIT_TYPE_VECTORS:
629 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_VECTORS\n"));
630 if (((PXENPCI_VECTORS)value)->length != sizeof(XENPCI_VECTORS) ||
631 ((PXENPCI_VECTORS)value)->magic != XEN_DATA_MAGIC)
632 {
633 KdPrint((__DRIVER_NAME " vectors mismatch (magic = %08x, length = %d)\n",
634 ((PXENPCI_VECTORS)value)->magic, ((PXENPCI_VECTORS)value)->length));
635 FUNCTION_EXIT();
636 return NDIS_STATUS_FAILURE;
637 }
638 else
639 memcpy(&xi->vectors, value, sizeof(XENPCI_VECTORS));
640 break;
641 case XEN_INIT_TYPE_STATE_PTR:
642 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_DEVICE_STATE - %p\n", PtrToUlong(value)));
643 xi->device_state = (PXENPCI_DEVICE_STATE)value;
644 break;
645 case XEN_INIT_TYPE_QEMU_HIDE_FLAGS:
646 qemu_hide_flags_value = PtrToUlong(value);
647 break;
648 case XEN_INIT_TYPE_QEMU_HIDE_FILTER:
649 qemu_hide_filter = TRUE;
650 break;
651 default:
652 KdPrint((__DRIVER_NAME " XEN_INIT_TYPE_%d\n", type));
653 break;
654 }
655 }
657 if ((qemu_hide_flags_value & QEMU_UNPLUG_ALL_IDE_DISKS) || qemu_hide_filter)
658 xi->inactive = FALSE;
660 xi->power_state = NdisDeviceStateD0;
661 xi->power_workitem = IoAllocateWorkItem(xi->fdo);
663 // now build config page
665 config_object.Header.Size = sizeof(NDIS_CONFIGURATION_OBJECT);
666 config_object.Header.Type = NDIS_OBJECT_TYPE_CONFIGURATION_OBJECT;
667 config_object.Header.Revision = NDIS_CONFIGURATION_OBJECT_REVISION_1;
668 config_object.NdisHandle = xi->adapter_handle;
669 config_object.Flags = 0;
671 status = NdisOpenConfigurationEx(&config_object, &config_handle);
672 if (!NT_SUCCESS(status))
673 {
674 KdPrint(("Could not open config in registry (%08x)\n", status));
675 status = NDIS_STATUS_RESOURCES;
676 goto err;
677 }
679 NdisInitUnicodeString(&config_param_name, L"ScatterGather");
680 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
681 if (!NT_SUCCESS(status))
682 {
683 KdPrint(("Could not read ScatterGather value (%08x)\n", status));
684 xi->frontend_sg_supported = TRUE;
685 }
686 else
687 {
688 KdPrint(("ScatterGather = %d\n", config_param->ParameterData.IntegerData));
689 xi->frontend_sg_supported = !!config_param->ParameterData.IntegerData;
690 }
691 if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
692 FUNCTION_MSG("No support for SG with NDIS 6.0, disabled\n");
693 xi->frontend_sg_supported = FALSE;
694 }
696 NdisInitUnicodeString(&config_param_name, L"LargeSendOffload");
697 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
698 if (!NT_SUCCESS(status))
699 {
700 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
701 xi->frontend_gso_value = 0;
702 }
703 else
704 {
705 KdPrint(("LargeSendOffload = %d\n", config_param->ParameterData.IntegerData));
706 xi->frontend_gso_value = config_param->ParameterData.IntegerData;
707 if (xi->frontend_gso_value > 61440)
708 {
709 xi->frontend_gso_value = 61440;
710 KdPrint(("(clipped to %d)\n", xi->frontend_gso_value));
711 }
712 if (!xi->frontend_sg_supported && xi->frontend_gso_value > PAGE_SIZE - MAX_PKT_HEADER_LENGTH)
713 {
714 /* without SG, GSO can be a maximum of PAGE_SIZE - MAX_PKT_HEADER_LENGTH */
715 xi->frontend_gso_value = min(xi->frontend_gso_value, PAGE_SIZE - MAX_PKT_HEADER_LENGTH);
716 KdPrint(("(clipped to %d with sg disabled)\n", xi->frontend_gso_value));
717 }
718 }
719 if (xi->frontend_sg_supported && ndis_os_minor_version < 1) {
720 FUNCTION_MSG("No support for GSO with NDIS 6.0, disabled\n");
721 xi->frontend_gso_value = 0;
722 }
724 NdisInitUnicodeString(&config_param_name, L"LargeSendOffloadRxSplitMTU");
725 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
726 if (!NT_SUCCESS(status))
727 {
728 KdPrint(("Could not read LargeSendOffload value (%08x)\n", status));
729 xi->frontend_gso_rx_split_type = RX_LSO_SPLIT_HALF;
730 }
731 else
732 {
733 KdPrint(("LargeSendOffloadRxSplitMTU = %d\n", config_param->ParameterData.IntegerData));
734 switch (config_param->ParameterData.IntegerData)
735 {
736 case RX_LSO_SPLIT_MSS:
737 case RX_LSO_SPLIT_HALF:
738 case RX_LSO_SPLIT_NONE:
739 xi->frontend_gso_rx_split_type = config_param->ParameterData.IntegerData;
740 break;
741 default:
742 xi->frontend_gso_rx_split_type = RX_LSO_SPLIT_HALF;
743 break;
744 }
745 }
747 NdisInitUnicodeString(&config_param_name, L"ChecksumOffload");
748 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
749 if (!NT_SUCCESS(status))
750 {
751 KdPrint(("Could not read ChecksumOffload value (%08x)\n", status));
752 xi->frontend_csum_supported = TRUE;
753 }
754 else
755 {
756 KdPrint(("ChecksumOffload = %d\n", config_param->ParameterData.IntegerData));
757 xi->frontend_csum_supported = !!config_param->ParameterData.IntegerData;
758 }
760 NdisInitUnicodeString(&config_param_name, L"MTU");
761 NdisReadConfiguration(&status, &config_param, config_handle, &config_param_name, NdisParameterInteger);
762 if (!NT_SUCCESS(status))
763 {
764 KdPrint(("Could not read MTU value (%08x)\n", status));
765 xi->frontend_mtu_value = 1500;
766 }
767 else
768 {
769 KdPrint(("MTU = %d\n", config_param->ParameterData.IntegerData));
770 xi->frontend_mtu_value = config_param->ParameterData.IntegerData;
771 }
773 NdisReadNetworkAddress(&status, &network_address, &network_address_length, config_handle);
774 if (!NT_SUCCESS(status) || network_address_length != ETH_ALEN || ((((PUCHAR)network_address)[0] & 0x03) != 0x02))
775 {
776 KdPrint(("Could not read NetworkAddress value (%08x) or value is invalid\n", status));
777 memset(xi->curr_mac_addr, 0, ETH_ALEN);
778 }
779 else
780 {
781 memcpy(xi->curr_mac_addr, network_address, ETH_ALEN);
782 KdPrint((" Set MAC address from registry to %02X:%02X:%02X:%02X:%02X:%02X\n",
783 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
784 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]));
785 }
787 NdisCloseConfiguration(config_handle);
789 status = XenNet_D0Entry(xi);
790 if (!NT_SUCCESS(status))
791 {
792 KdPrint(("Failed to go to D0 (%08x)\n", status));
793 goto err;
794 }
796 xi->config_max_pkt_size = max(xi->current_mtu_value + XN_HDR_SIZE, xi->current_gso_value + XN_HDR_SIZE);
798 registration_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
799 registration_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
800 registration_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
801 registration_attributes.MiniportAdapterContext = xi;
802 registration_attributes.AttributeFlags = 0;
803 registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_HARDWARE_DEVICE;
804 registration_attributes.AttributeFlags |= NDIS_MINIPORT_ATTRIBUTES_SURPRISE_REMOVE_OK;
805 registration_attributes.CheckForHangTimeInSeconds = 0; /* use default */
806 registration_attributes.InterfaceType = NdisInterfacePNPBus;
807 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&registration_attributes);
808 if (!NT_SUCCESS(status))
809 {
810 KdPrint(("NdisMSetMiniportAttributes(registration) failed (%08x)\n", status));
811 goto err;
812 }
814 general_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
815 general_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1; /* revision 2 is NDIS 6.2 */
816 general_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
817 general_attributes.Flags = 0;
818 general_attributes.MediaType = NdisMedium802_3;
819 general_attributes.PhysicalMediumType = NdisPhysicalMediumOther;
820 general_attributes.MtuSize = xi->current_mtu_value;
821 general_attributes.MaxXmitLinkSpeed = MAX_LINK_SPEED;
822 general_attributes.XmitLinkSpeed = MAX_LINK_SPEED;
823 general_attributes.MaxRcvLinkSpeed = MAX_LINK_SPEED;
824 general_attributes.RcvLinkSpeed = MAX_LINK_SPEED;
825 general_attributes.MediaConnectState = MediaConnectStateConnected;
826 general_attributes.MediaDuplexState = MediaDuplexStateFull;
827 general_attributes.LookaheadSize = xi->current_lookahead;
828 general_attributes.PowerManagementCapabilities = NULL;
829 general_attributes.MacOptions = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
830 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
831 NDIS_MAC_OPTION_NO_LOOPBACK;
832 general_attributes.SupportedPacketFilters = SUPPORTED_PACKET_FILTERS;
833 general_attributes.MaxMulticastListSize = MULTICAST_LIST_MAX_SIZE;
834 general_attributes.MacAddressLength = 6;
835 NdisMoveMemory(general_attributes.PermanentMacAddress, xi->perm_mac_addr, general_attributes.MacAddressLength);
836 NdisMoveMemory(general_attributes.CurrentMacAddress, xi->curr_mac_addr, general_attributes.MacAddressLength);
837 general_attributes.RecvScaleCapabilities = NULL; /* we do want to support this soon */
838 general_attributes.AccessType = NET_IF_ACCESS_BROADCAST;
839 general_attributes.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
840 general_attributes.ConnectionType = NET_IF_CONNECTION_DEDICATED;
841 general_attributes.IfType = IF_TYPE_ETHERNET_CSMACD;
842 general_attributes.IfConnectorPresent = TRUE;
843 general_attributes.SupportedStatistics = xi->stats.SupportedStatistics;
844 general_attributes.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
845 general_attributes.DataBackFillSize = 0; // see NdisRetreatNetBufferDataStart
846 general_attributes.ContextBackFillSize = 0; // ?? NFI ??
848 for (i = 0; xennet_oids[i].oid; i++);
850 status = NdisAllocateMemoryWithTag((PVOID)&supported_oids, sizeof(NDIS_OID) * i, XENNET_POOL_TAG);
851 if (!NT_SUCCESS(status))
852 {
853 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
854 status = NDIS_STATUS_RESOURCES;
855 goto err;
856 }
858 for (i = 0; xennet_oids[i].oid; i++)
859 {
860 supported_oids[i] = xennet_oids[i].oid;
861 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);
862 }
863 general_attributes.SupportedOidList = supported_oids;
864 general_attributes.SupportedOidListLength = sizeof(NDIS_OID) * i;
865 general_attributes.AutoNegotiationFlags = NDIS_LINK_STATE_XMIT_LINK_SPEED_AUTO_NEGOTIATED
866 | NDIS_LINK_STATE_RCV_LINK_SPEED_AUTO_NEGOTIATED
867 | NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
868 //general_attributes.PowerManagementCapabilitiesEx = NULL; // >= 6.20
869 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&general_attributes);
870 if (!NT_SUCCESS(status))
871 {
872 KdPrint(("NdisMSetMiniportAttributes(general) failed (%08x)\n", status));
873 goto err;
874 }
875 NdisFreeMemory(supported_oids, 0, 0);
877 /* this is the initial offload state */
878 RtlZeroMemory(&df_offload, sizeof(df_offload));
879 df_offload.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
880 df_offload.Header.Revision = NDIS_OFFLOAD_REVISION_1; // revision 2 does exist
881 df_offload.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
882 /* this is the supported offload state */
883 RtlZeroMemory(&hw_offload, sizeof(hw_offload));
884 hw_offload.Header.Type = NDIS_OBJECT_TYPE_OFFLOAD;
885 hw_offload.Header.Revision = NDIS_OFFLOAD_REVISION_1; // revision 2 does exist
886 hw_offload.Header.Size = NDIS_SIZEOF_NDIS_OFFLOAD_REVISION_1;
887 if (xi->current_csum_supported)
888 {
889 df_offload.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
890 df_offload.Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_SET_ON;
891 df_offload.Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SET_ON;
892 df_offload.Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_SET_ON;
893 df_offload.Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_SET_ON;
894 df_offload.Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_SET_ON;
895 df_offload.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
896 df_offload.Checksum.IPv4Receive.IpOptionsSupported = NDIS_OFFLOAD_SET_ON;
897 df_offload.Checksum.IPv4Receive.TcpOptionsSupported = NDIS_OFFLOAD_SET_ON;
898 df_offload.Checksum.IPv4Receive.TcpChecksum = NDIS_OFFLOAD_SET_ON;
899 df_offload.Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_SET_ON;
900 df_offload.Checksum.IPv4Receive.IpChecksum = NDIS_OFFLOAD_SET_ON;
901 /* offload.Checksum.IPv6Transmit is not supported */
902 /* offload.Checksum.IPv6Receive is not supported */
903 hw_offload.Checksum.IPv4Transmit.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
904 hw_offload.Checksum.IPv4Transmit.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
905 hw_offload.Checksum.IPv4Transmit.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
906 hw_offload.Checksum.IPv4Transmit.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
907 hw_offload.Checksum.IPv4Transmit.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
908 hw_offload.Checksum.IPv4Transmit.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
909 hw_offload.Checksum.IPv4Receive.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
910 hw_offload.Checksum.IPv4Receive.IpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
911 hw_offload.Checksum.IPv4Receive.TcpOptionsSupported = NDIS_OFFLOAD_SUPPORTED;
912 hw_offload.Checksum.IPv4Receive.TcpChecksum = NDIS_OFFLOAD_SUPPORTED;
913 hw_offload.Checksum.IPv4Receive.UdpChecksum = NDIS_OFFLOAD_SUPPORTED;
914 hw_offload.Checksum.IPv4Receive.IpChecksum = NDIS_OFFLOAD_SUPPORTED;
915 /* hw_offload.Checksum.IPv6Transmit is not supported */
916 /* hw_offload.Checksum.IPv6Receive is not supported */
917 }
918 if (xi->current_gso_value)
919 {
920 hw_offload.LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
921 hw_offload.LsoV1.IPv4.MaxOffLoadSize = xi->current_gso_value;
922 hw_offload.LsoV1.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
923 hw_offload.LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
924 hw_offload.LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
925 hw_offload.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
926 hw_offload.LsoV2.IPv4.MaxOffLoadSize = xi->current_gso_value;
927 hw_offload.LsoV2.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
928 /* hw_offload.LsoV2.IPv6 is not supported */
929 df_offload.LsoV1.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
930 df_offload.LsoV1.IPv4.MaxOffLoadSize = xi->current_gso_value;
931 df_offload.LsoV1.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
932 df_offload.LsoV1.IPv4.TcpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
933 df_offload.LsoV1.IPv4.IpOptions = NDIS_OFFLOAD_NOT_SUPPORTED; /* linux can't handle this */
934 df_offload.LsoV2.IPv4.Encapsulation = NDIS_ENCAPSULATION_IEEE_802_3;
935 df_offload.LsoV2.IPv4.MaxOffLoadSize = xi->current_gso_value;
936 df_offload.LsoV2.IPv4.MinSegmentCount = MIN_LARGE_SEND_SEGMENTS;
937 /* df_offload.LsoV2.IPv6 is not supported */
938 }
939 /* hw_offload.IPsecV1 is not supported */
940 /* hw_offload.IPsecV2 is not supported */
941 /* df_offload.IPsecV1 is not supported */
942 /* df_offload.IPsecV2 is not supported */
943 hw_offload.Flags = 0;
944 df_offload.Flags = 0;
946 RtlZeroMemory(&df_conn_offload, sizeof(df_conn_offload));
947 df_conn_offload.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
948 df_conn_offload.Header.Revision = NDIS_TCP_CONNECTION_OFFLOAD_REVISION_1;
949 df_conn_offload.Header.Size = NDIS_SIZEOF_TCP_CONNECTION_OFFLOAD_REVISION_1;
951 RtlZeroMemory(&hw_conn_offload, sizeof(hw_conn_offload));
952 hw_conn_offload.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
953 hw_conn_offload.Header.Revision = NDIS_TCP_CONNECTION_OFFLOAD_REVISION_1;
954 hw_conn_offload.Header.Size = NDIS_SIZEOF_TCP_CONNECTION_OFFLOAD_REVISION_1;
956 offload_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES;
957 offload_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1;
958 offload_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_OFFLOAD_ATTRIBUTES_REVISION_1;
959 offload_attributes.DefaultOffloadConfiguration = &df_offload;
960 offload_attributes.HardwareOffloadCapabilities = &hw_offload;
961 offload_attributes.DefaultTcpConnectionOffloadConfiguration = &df_conn_offload;
962 offload_attributes.TcpConnectionOffloadHardwareCapabilities = &hw_conn_offload;
963 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&offload_attributes);
964 if (!NT_SUCCESS(status))
965 {
966 KdPrint(("NdisMSetMiniportAttributes(offload) failed (%08x)\n", status));
967 goto err;
968 }
970 #if 0
971 if (ndis_os_minor_version >= 1) {
972 NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES hw_assist_attributes;
973 NDIS_HD_SPLIT_ATTRIBUTES hd_split_attributes;
975 RtlZeroMemory(&hd_split_attributes, sizeof(hd_split_attributes));
976 hd_split_attributes.Header.Type = NDIS_OBJECT_TYPE_HD_SPLIT_ATTRIBUTES;
977 hd_split_attributes.Header.Revision = NDIS_HD_SPLIT_ATTRIBUTES_REVISION_1;
978 hd_split_attributes.Header.Size = NDIS_SIZEOF_HD_SPLIT_ATTRIBUTES_REVISION_1;
979 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;
980 hd_split_attributes.CurrentCapabilities = hd_split_attributes.HardwareCapabilities;
981 /* the other members are set on output */
983 RtlZeroMemory(&hw_assist_attributes, sizeof(hw_assist_attributes));
984 hw_assist_attributes.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES;
985 hw_assist_attributes.Header.Revision = NDIS_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
986 hw_assist_attributes.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_HARDWARE_ASSIST_ATTRIBUTES_REVISION_1;
987 hw_assist_attributes.HDSplitAttributes = &hd_split_attributes;
988 status = NdisMSetMiniportAttributes(xi->adapter_handle, (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&hw_assist_attributes);
989 if (!NT_SUCCESS(status))
990 {
991 FUNCTION_MSG("NdisMSetMiniportAttributes(hw_assist) failed (%08x)\n", status);
992 goto err;
993 }
994 FUNCTION_MSG("HW Split enabled\n");
995 FUNCTION_MSG(" HDSplitFlags = %08x\n", hd_split_attributes.HDSplitFlags);
996 FUNCTION_MSG(" BackfillSize = %d\n", hd_split_attributes.BackfillSize);
997 FUNCTION_MSG(" MaxHeaderSize = %d\n", hd_split_attributes.MaxHeaderSize);
998 //what about backfill here?
999 }
1000 #endif
1001 return NDIS_STATUS_SUCCESS;
1003 err:
1004 NdisFreeMemory(xi, 0, 0);
1005 FUNCTION_EXIT_STATUS(status);
1007 return status;
1010 NDIS_STATUS
1011 XenNet_D0Exit(struct xennet_info *xi)
1013 FUNCTION_ENTER();
1014 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1016 xi->shutting_down = TRUE;
1017 KeMemoryBarrier(); /* make sure everyone sees that we are now shutting down */
1019 XenNet_TxShutdown(xi);
1020 XenNet_RxShutdown(xi);
1022 xi->connected = FALSE;
1023 KeMemoryBarrier(); /* make sure everyone sees that we are now disconnected */
1025 xi->vectors.XenPci_XenShutdownDevice(xi->vectors.context);
1027 FUNCTION_EXIT();
1029 return STATUS_SUCCESS;
1032 static VOID
1033 XenNet_DevicePnPEventNotify(NDIS_HANDLE adapter_context, PNET_DEVICE_PNP_EVENT pnp_event)
1035 UNREFERENCED_PARAMETER(adapter_context);
1037 FUNCTION_ENTER();
1038 switch (pnp_event->DevicePnPEvent)
1040 case NdisDevicePnPEventSurpriseRemoved:
1041 KdPrint((__DRIVER_NAME " NdisDevicePnPEventSurpriseRemoved\n"));
1042 break;
1043 case NdisDevicePnPEventPowerProfileChanged :
1044 KdPrint((__DRIVER_NAME " NdisDevicePnPEventPowerProfileChanged\n"));
1045 break;
1046 default:
1047 KdPrint((__DRIVER_NAME " NdisDevicePnPEvent%d\n", pnp_event->DevicePnPEvent));
1048 break;
1050 FUNCTION_EXIT();
1053 /* called at <= HIGH_IRQL, or PASSIVE_LEVEL, depending on shutdown_action */
1054 VOID
1055 XenNet_Shutdown(NDIS_HANDLE adapter_context, NDIS_SHUTDOWN_ACTION shutdown_action)
1057 UNREFERENCED_PARAMETER(adapter_context);
1058 UNREFERENCED_PARAMETER(shutdown_action);
1060 FUNCTION_ENTER();
1061 FUNCTION_EXIT();
1064 static BOOLEAN
1065 XenNet_CheckForHang(NDIS_HANDLE adapter_context)
1067 UNREFERENCED_PARAMETER(adapter_context);
1069 //FUNCTION_ENTER();
1070 //FUNCTION_EXIT();
1071 return FALSE;
1074 /* Opposite of XenNet_Init */
1075 static VOID
1076 XenNet_Halt(NDIS_HANDLE adapter_context, NDIS_HALT_ACTION halt_action)
1078 struct xennet_info *xi = adapter_context;
1079 UNREFERENCED_PARAMETER(halt_action);
1081 FUNCTION_ENTER();
1083 XenNet_D0Exit(xi);
1085 NdisFreeMemory(xi, 0, 0);
1087 FUNCTION_EXIT();
1090 static NDIS_STATUS
1091 XenNet_Reset(NDIS_HANDLE adapter_context, PBOOLEAN addressing_reset)
1093 UNREFERENCED_PARAMETER(adapter_context);
1095 FUNCTION_ENTER();
1096 *addressing_reset = FALSE;
1097 FUNCTION_EXIT();
1098 return NDIS_STATUS_SUCCESS;
1101 /* called at PASSIVE_LEVEL */
1102 static NDIS_STATUS
1103 XenNet_Pause(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_PAUSE_PARAMETERS pause_parameters)
1105 UNREFERENCED_PARAMETER(adapter_context);
1106 UNREFERENCED_PARAMETER(pause_parameters);
1107 FUNCTION_ENTER();
1108 FUNCTION_EXIT();
1109 return STATUS_SUCCESS;
1112 /* called at PASSIVE_LEVEL */
1113 static NDIS_STATUS
1114 XenNet_Restart(NDIS_HANDLE adapter_context, PNDIS_MINIPORT_RESTART_PARAMETERS restart_parameters)
1116 UNREFERENCED_PARAMETER(adapter_context);
1117 UNREFERENCED_PARAMETER(restart_parameters);
1118 FUNCTION_ENTER();
1119 FUNCTION_EXIT();
1120 return STATUS_SUCCESS;
1123 static VOID
1124 XenNet_Unload(PDRIVER_OBJECT driver_object)
1126 UNREFERENCED_PARAMETER(driver_object);
1127 FUNCTION_ENTER();
1128 NdisMDeregisterMiniportDriver(driver_handle);
1129 FUNCTION_EXIT();
1132 static NDIS_STATUS
1133 XenNet_SetOptions(NDIS_HANDLE driver_handle, NDIS_HANDLE driver_context)
1135 UNREFERENCED_PARAMETER(driver_handle);
1136 UNREFERENCED_PARAMETER(driver_context);
1137 FUNCTION_ENTER();
1138 FUNCTION_EXIT();
1139 return STATUS_SUCCESS;
1142 NTSTATUS
1143 DriverEntry(PDRIVER_OBJECT driver_object, PUNICODE_STRING registry_path)
1145 NTSTATUS status;
1146 NDIS_MINIPORT_DRIVER_CHARACTERISTICS mini_chars;
1147 ULONG ndis_version;
1149 FUNCTION_ENTER();
1151 ndis_version = NdisGetVersion();
1153 ndis_os_major_version = ndis_version >> 16;
1154 ndis_os_minor_version = ndis_version & 0xFFFF;
1156 NdisZeroMemory(&mini_chars, sizeof(mini_chars));
1158 mini_chars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
1160 if (ndis_os_minor_version < 1) {
1161 mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
1162 mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
1164 mini_chars.MajorNdisVersion = 6;
1165 mini_chars.MinorNdisVersion = 0;
1166 } else {
1167 mini_chars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
1168 mini_chars.Header.Size = NDIS_SIZEOF_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_2;
1169 mini_chars.MajorNdisVersion = 6;
1170 mini_chars.MinorNdisVersion = 1;
1172 mini_chars.MajorDriverVersion = VENDOR_DRIVER_VERSION_MAJOR;
1173 mini_chars.MinorDriverVersion = VENDOR_DRIVER_VERSION_MINOR;
1175 KdPrint((__DRIVER_NAME " Driver MajorNdisVersion = %d, Driver MinorNdisVersion = %d\n", NDIS_MINIPORT_MAJOR_VERSION, NDIS_MINIPORT_MINOR_VERSION));
1176 KdPrint((__DRIVER_NAME " Windows MajorNdisVersion = %d, Windows MinorNdisVersion = %d\n", ndis_os_major_version, ndis_os_minor_version));
1178 mini_chars.Flags = NDIS_WDM_DRIVER;
1180 mini_chars.SetOptionsHandler = XenNet_SetOptions;
1181 mini_chars.InitializeHandlerEx = XenNet_Initialize;
1182 mini_chars.HaltHandlerEx = XenNet_Halt;
1183 mini_chars.UnloadHandler = XenNet_Unload;
1184 mini_chars.PauseHandler = XenNet_Pause;
1185 mini_chars.RestartHandler = XenNet_Restart;
1186 mini_chars.CheckForHangHandlerEx = XenNet_CheckForHang;
1187 mini_chars.ResetHandlerEx = XenNet_Reset;
1188 mini_chars.DevicePnPEventNotifyHandler = XenNet_DevicePnPEventNotify;
1189 mini_chars.ShutdownHandlerEx = XenNet_Shutdown;
1191 mini_chars.OidRequestHandler = XenNet_OidRequest;
1192 mini_chars.CancelOidRequestHandler = XenNet_CancelOidRequest;
1193 if (ndis_os_minor_version >= 1) {
1194 mini_chars.DirectOidRequestHandler = NULL;
1195 mini_chars.CancelDirectOidRequestHandler = NULL;
1198 mini_chars.SendNetBufferListsHandler = XenNet_SendNetBufferLists;
1199 mini_chars.CancelSendHandler = XenNet_CancelSend;
1201 mini_chars.ReturnNetBufferListsHandler = XenNet_ReturnNetBufferLists;
1203 status = NdisMRegisterMiniportDriver(driver_object, registry_path, NULL, &mini_chars, &driver_handle);
1204 if (!NT_SUCCESS(status))
1206 KdPrint((__DRIVER_NAME " NdisMRegisterMiniportDriver failed, status = 0x%x\n", status));
1207 return status;
1210 FUNCTION_EXIT();
1212 return status;