win-pvdrivers

view xennet/xennet6.c @ 979:8f483a2b2991

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