win-pvdrivers

view xennet/xennet_common.c @ 1023:1ce315b193d1

Change all NT_ASSERT to XN_ASSERT
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 15:12:35 2013 +1100 (2013-02-19)
parents 9b6213b6be25
children cb767700f91c
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 "xennet.h"
23 /* Increase the header to a certain size */
24 BOOLEAN
25 XenNet_BuildHeader(packet_info_t *pi, PUCHAR header, ULONG new_header_size)
26 {
27 ULONG bytes_remaining;
29 //FUNCTION_ENTER();
31 if (!header)
32 header = pi->header;
34 if (new_header_size > pi->total_length) {
35 new_header_size = pi->total_length;
36 }
38 if (new_header_size <= pi->header_length) {
39 //FUNCTION_EXIT();
40 return TRUE; /* header is already at least the required size */
41 }
43 if (header == pi->first_mdl_virtual) {
44 /* still working in the first buffer */
45 if (new_header_size <= pi->first_mdl_length) {
46 //KdPrint((__DRIVER_NAME " new_header_size <= pi->first_mdl_length\n"));
47 pi->header_length = new_header_size;
48 if (pi->header_length == pi->first_mdl_length) {
49 #if NTDDI_VERSION < NTDDI_VISTA
50 NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
51 #else
52 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
53 #endif
54 pi->curr_mdl_offset = 0;
55 if (pi->curr_pb)
56 pi->curr_pb = pi->curr_pb->next;
57 } else {
58 pi->curr_mdl_offset = (USHORT)new_header_size;
59 }
60 //FUNCTION_EXIT();
61 return TRUE;
62 } else {
63 //KdPrint((__DRIVER_NAME " Switching to header_data\n"));
64 memcpy(pi->header_data, header, pi->header_length);
65 header = pi->header = pi->header_data;
66 }
67 }
69 bytes_remaining = new_header_size - pi->header_length;
70 // TODO: if there are only a small number of bytes left in the current buffer then increase to consume that too... it would have to be no more than the size of header+mss though
72 //KdPrint((__DRIVER_NAME " A bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
73 while (bytes_remaining && pi->curr_mdl) {
74 ULONG copy_size;
76 XN_ASSERT(pi->curr_mdl);
77 //KdPrint((__DRIVER_NAME " B bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
78 if (MmGetMdlByteCount(pi->curr_mdl)) {
79 PUCHAR src_addr;
80 src_addr = MmGetSystemAddressForMdlSafe(pi->curr_mdl, NormalPagePriority);
81 if (!src_addr) {
82 //FUNCTION_EXIT();
83 return FALSE;
84 }
85 copy_size = min(bytes_remaining, MmGetMdlByteCount(pi->curr_mdl) - pi->curr_mdl_offset);
86 //KdPrint((__DRIVER_NAME " B copy_size = %d\n", copy_size));
87 memcpy(header + pi->header_length,
88 src_addr + pi->curr_mdl_offset, copy_size);
89 pi->curr_mdl_offset = (USHORT)(pi->curr_mdl_offset + copy_size);
90 pi->header_length += copy_size;
91 bytes_remaining -= copy_size;
92 }
93 if (pi->curr_mdl_offset == MmGetMdlByteCount(pi->curr_mdl)) {
94 #if NTDDI_VERSION < NTDDI_VISTA
95 NdisGetNextBuffer(pi->curr_mdl, &pi->curr_mdl);
96 #else
97 NdisGetNextMdl(pi->curr_mdl, &pi->curr_mdl);
98 #endif
99 if (pi->curr_pb)
100 pi->curr_pb = pi->curr_pb->next;
101 pi->curr_mdl_offset = 0;
102 }
103 }
104 //KdPrint((__DRIVER_NAME " C bytes_remaining = %d, pi->curr_mdl = %p\n", bytes_remaining, pi->curr_mdl));
105 if (bytes_remaining) {
106 //KdPrint((__DRIVER_NAME " bytes_remaining\n"));
107 //FUNCTION_EXIT();
108 return FALSE;
109 }
110 //FUNCTION_EXIT();
111 return TRUE;
112 }
114 VOID
115 XenNet_ParsePacketHeader(packet_info_t *pi, PUCHAR alt_buffer, ULONG min_header_size)
116 {
117 //FUNCTION_ENTER();
119 XN_ASSERT(pi->first_mdl);
121 #if NTDDI_VERSION < NTDDI_VISTA
122 NdisQueryBufferSafe(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
123 #else
124 NdisQueryMdl(pi->first_mdl, (PVOID)&pi->first_mdl_virtual, &pi->first_mdl_length, NormalPagePriority);
125 #endif
126 pi->curr_mdl = pi->first_mdl;
127 if (alt_buffer)
128 pi->header = alt_buffer;
129 else
130 pi->header = pi->first_mdl_virtual;
132 pi->header_length = 0;
133 pi->curr_mdl_offset = pi->first_mdl_offset;
135 XenNet_BuildHeader(pi, NULL, min_header_size);
137 if (!XenNet_BuildHeader(pi, NULL, (ULONG)XN_HDR_SIZE))
138 {
139 //KdPrint((__DRIVER_NAME " packet too small (Ethernet Header)\n"));
140 pi->parse_result = PARSE_TOO_SMALL;
141 return;
142 }
144 if (pi->header[0] == 0xFF && pi->header[1] == 0xFF
145 && pi->header[2] == 0xFF && pi->header[3] == 0xFF
146 && pi->header[4] == 0xFF && pi->header[5] == 0xFF)
147 {
148 pi->is_broadcast = TRUE;
149 }
150 else if (pi->header[0] & 0x01)
151 {
152 pi->is_multicast = TRUE;
153 }
155 switch (GET_NET_PUSHORT(&pi->header[12])) // L2 protocol field
156 {
157 case 0x0800: /* IPv4 */
158 //KdPrint((__DRIVER_NAME " IP\n"));
159 if (pi->header_length < (ULONG)(XN_HDR_SIZE + 20))
160 {
161 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + 20)))
162 {
163 KdPrint((__DRIVER_NAME " packet too small (IP Header)\n"));
164 pi->parse_result = PARSE_TOO_SMALL;
165 return;
166 }
167 }
168 pi->ip_version = (pi->header[XN_HDR_SIZE + 0] & 0xF0) >> 4;
169 if (pi->ip_version != 4)
170 {
171 //KdPrint((__DRIVER_NAME " ip_version = %d\n", pi->ip_version));
172 pi->parse_result = PARSE_UNKNOWN_TYPE;
173 return;
174 }
175 pi->ip4_header_length = (pi->header[XN_HDR_SIZE + 0] & 0x0F) << 2;
176 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20))
177 {
178 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + 20)))
179 {
180 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header)\n"));
181 pi->parse_result = PARSE_TOO_SMALL;
182 return;
183 }
184 }
185 break;
186 case 0x86DD: /* IPv6 */
187 //KdPrint((__DRIVER_NAME " IPv6\n"));
188 //KdPrint((__DRIVER_NAME " (not currently used)\n"));
189 pi->parse_result = PARSE_UNKNOWN_TYPE;
190 return;
191 default:
192 //KdPrint((__DRIVER_NAME " Not IP (%04x)\n", GET_NET_PUSHORT(&pi->header[12])));
193 pi->parse_result = PARSE_UNKNOWN_TYPE;
194 return;
195 }
196 pi->ip_proto = pi->header[XN_HDR_SIZE + 9];
197 pi->ip4_length = GET_NET_PUSHORT(&pi->header[XN_HDR_SIZE + 2]);
198 pi->ip_has_options = (BOOLEAN)(pi->ip4_header_length > 20);
199 switch (pi->ip_proto)
200 {
201 case 6: // TCP
202 case 17: // UDP
203 break;
204 default:
205 //KdPrint((__DRIVER_NAME " Not TCP/UDP (%d)\n", pi->ip_proto));
206 pi->parse_result = PARSE_UNKNOWN_TYPE;
207 return;
208 }
209 pi->tcp_header_length = (pi->header[XN_HDR_SIZE + pi->ip4_header_length + 12] & 0xf0) >> 2;
211 if (pi->header_length < (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + pi->tcp_header_length))
212 {
213 /* we don't actually need the tcp options to analyse the header */
214 if (!XenNet_BuildHeader(pi, NULL, (ULONG)(XN_HDR_SIZE + pi->ip4_header_length + MIN_TCP_HEADER_LENGTH)))
215 {
216 //KdPrint((__DRIVER_NAME " packet too small (IP Header + IP Options + TCP Header (not including TCP Options))\n"));
217 pi->parse_result = PARSE_TOO_SMALL;
218 return;
219 }
220 }
222 if ((ULONG)XN_HDR_SIZE + pi->ip4_length > pi->total_length)
223 {
224 //KdPrint((__DRIVER_NAME " XN_HDR_SIZE + ip4_length (%d) > total_length (%d)\n", XN_HDR_SIZE + pi->ip4_length, pi->total_length));
225 pi->parse_result = PARSE_UNKNOWN_TYPE;
226 return;
227 }
229 pi->tcp_length = pi->ip4_length - pi->ip4_header_length - pi->tcp_header_length;
230 pi->tcp_remaining = pi->tcp_length;
231 pi->tcp_seq = GET_NET_PULONG(&pi->header[XN_HDR_SIZE + pi->ip4_header_length + 4]);
232 pi->tcp_has_options = (BOOLEAN)(pi->tcp_header_length > 20);
233 if (pi->mss > 0 && pi->tcp_length > pi->mss)
234 pi->split_required = TRUE;
236 //KdPrint((__DRIVER_NAME " ip4_length = %d\n", pi->ip4_length));
237 //KdPrint((__DRIVER_NAME " tcp_length = %d\n", pi->tcp_length));
238 //FUNCTION_EXIT();
240 pi->parse_result = PARSE_OK;
241 }
243 BOOLEAN
244 XenNet_CheckIpHeaderSum(PUCHAR header, USHORT ip4_header_length) {
245 ULONG csum = 0;
246 USHORT i;
248 XN_ASSERT(ip4_header_length > 12);
249 XN_ASSERT(!(ip4_header_length & 1));
251 for (i = 0; i < ip4_header_length; i += 2) {
252 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
253 }
254 while (csum & 0xFFFF0000)
255 csum = (csum & 0xFFFF) + (csum >> 16);
256 return (BOOLEAN)(csum == 0xFFFF);
257 }
259 VOID
260 XenNet_SumIpHeader(PUCHAR header, USHORT ip4_header_length) {
261 ULONG csum = 0;
262 USHORT i;
264 XN_ASSERT(ip4_header_length > 12);
265 XN_ASSERT(!(ip4_header_length & 1));
267 header[XN_HDR_SIZE + 10] = 0;
268 header[XN_HDR_SIZE + 11] = 0;
269 for (i = 0; i < ip4_header_length; i += 2) {
270 csum += GET_NET_PUSHORT(&header[XN_HDR_SIZE + i]);
271 }
272 while (csum & 0xFFFF0000)
273 csum = (csum & 0xFFFF) + (csum >> 16);
274 csum = ~csum;
275 SET_NET_USHORT(&header[XN_HDR_SIZE + 10], (USHORT)csum);
276 }
278 BOOLEAN
279 XenNet_FilterAcceptPacket(struct xennet_info *xi,packet_info_t *pi)
280 {
281 ULONG i;
282 BOOLEAN is_my_multicast = FALSE;
283 BOOLEAN is_directed = FALSE;
285 if (memcmp(xi->curr_mac_addr, pi->header, ETH_ALEN) == 0)
286 {
287 is_directed = TRUE;
288 }
289 else if (pi->is_multicast)
290 {
291 for (i = 0; i < xi->multicast_list_size; i++)
292 {
293 if (memcmp(xi->multicast_list[i], pi->header, 6) == 0)
294 break;
295 }
296 if (i < xi->multicast_list_size)
297 {
298 is_my_multicast = TRUE;
299 }
300 }
301 if (is_directed && (xi->packet_filter & NDIS_PACKET_TYPE_DIRECTED))
302 {
303 return TRUE;
304 }
305 if (is_my_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_MULTICAST))
306 {
307 return TRUE;
308 }
309 if (pi->is_multicast && (xi->packet_filter & NDIS_PACKET_TYPE_ALL_MULTICAST))
310 {
311 return TRUE;
312 }
313 if (pi->is_broadcast && (xi->packet_filter & NDIS_PACKET_TYPE_BROADCAST))
314 {
315 return TRUE;
316 }
317 if (xi->packet_filter & NDIS_PACKET_TYPE_PROMISCUOUS)
318 {
319 return TRUE;
320 }
321 //return TRUE;
322 return FALSE;
323 }
325 static VOID
326 XenNet_RxTxDpc(PKDPC dpc, PVOID context, PVOID arg1, PVOID arg2)
327 {
328 struct xennet_info *xi = context;
329 BOOLEAN dont_set_event;
331 UNREFERENCED_PARAMETER(dpc);
332 UNREFERENCED_PARAMETER(arg1);
333 UNREFERENCED_PARAMETER(arg2);
335 //FUNCTION_ENTER();
336 /* 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 */
337 dont_set_event = XenNet_RxBufferCheck(xi);
338 XenNet_TxBufferGC(xi, dont_set_event);
339 //FUNCTION_EXIT();
340 }
342 static BOOLEAN
343 XenNet_HandleEvent_DIRQL(PVOID context)
344 {
345 struct xennet_info *xi = context;
346 //ULONG suspend_resume_state_pdo;
348 //FUNCTION_ENTER();
349 if (xi->device_state == DEVICE_STATE_ACTIVE || xi->device_state == DEVICE_STATE_DISCONNECTING) {
350 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
351 }
352 //FUNCTION_EXIT();
353 return TRUE;
354 }
356 NTSTATUS
357 XenNet_Connect(PVOID context, BOOLEAN suspend) {
358 NTSTATUS status;
359 struct xennet_info *xi = context;
360 PFN_NUMBER pfn;
361 ULONG qemu_hide_filter;
362 ULONG qemu_hide_flags_value;
363 int i;
364 ULONG state;
365 ULONG octet;
366 PCHAR tmp_string;
367 ULONG tmp_ulong;
369 if (!suspend) {
370 xi->handle = XnOpenDevice(xi->pdo, XenNet_DeviceCallback, xi);
371 }
372 if (!xi->handle) {
373 FUNCTION_MSG("Cannot open Xen device\n");
374 return STATUS_UNSUCCESSFUL;
375 }
376 XnGetValue(xi->handle, XN_VALUE_TYPE_QEMU_HIDE_FLAGS, &qemu_hide_flags_value);
377 XnGetValue(xi->handle, XN_VALUE_TYPE_QEMU_FILTER, &qemu_hide_filter);
378 if (!(qemu_hide_flags_value & QEMU_UNPLUG_ALL_NICS) || qemu_hide_filter) {
379 FUNCTION_MSG("inactive\n");
380 xi->device_state = DEVICE_STATE_INACTIVE;
381 /* continue with setup so all the flags and capabilities are correct */
382 }
384 if (xi->device_state != DEVICE_STATE_INACTIVE) {
385 for (i = 0; i <= 5 && xi->backend_state != XenbusStateInitialising && xi->backend_state != XenbusStateInitWait && xi->backend_state != XenbusStateInitialised; i++) {
386 FUNCTION_MSG("Waiting for XenbusStateInitXxx\n");
387 if (xi->backend_state == XenbusStateClosed) {
388 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateInitialising);
389 }
390 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, NULL);
391 }
392 if (xi->backend_state != XenbusStateInitialising && xi->backend_state != XenbusStateInitWait && xi->backend_state != XenbusStateInitialised) {
393 FUNCTION_MSG("Backend state timeout\n");
394 return STATUS_UNSUCCESSFUL;
395 }
396 if (!NT_SUCCESS(status = XnBindEvent(xi->handle, &xi->event_channel, XenNet_HandleEvent_DIRQL, xi))) {
397 FUNCTION_MSG("Cannot allocate event channel\n");
398 return STATUS_UNSUCCESSFUL;
399 }
400 FUNCTION_MSG("event_channel = %d\n", xi->event_channel);
401 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "event-channel", xi->event_channel);
402 xi->tx_sring = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENNET_POOL_TAG);
403 if (!xi->tx_sring) {
404 FUNCTION_MSG("Cannot allocate tx_sring\n");
405 return STATUS_UNSUCCESSFUL;
406 }
407 SHARED_RING_INIT(xi->tx_sring);
408 FRONT_RING_INIT(&xi->tx_ring, xi->tx_sring, PAGE_SIZE);
409 pfn = (PFN_NUMBER)(MmGetPhysicalAddress(xi->tx_sring).QuadPart >> PAGE_SHIFT);
410 FUNCTION_MSG("tx sring pfn = %d\n", (ULONG)pfn);
411 xi->tx_sring_gref = XnGrantAccess(xi->handle, (ULONG)pfn, FALSE, INVALID_GRANT_REF, XENNET_POOL_TAG);
412 FUNCTION_MSG("tx sring_gref = %d\n", xi->tx_sring_gref);
413 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "tx-ring-ref", xi->tx_sring_gref);
414 xi->rx_sring = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, XENNET_POOL_TAG);
415 if (!xi->rx_sring) {
416 FUNCTION_MSG("Cannot allocate rx_sring\n");
417 return STATUS_UNSUCCESSFUL;
418 }
419 SHARED_RING_INIT(xi->rx_sring);
420 FRONT_RING_INIT(&xi->rx_ring, xi->rx_sring, PAGE_SIZE);
421 pfn = (PFN_NUMBER)(MmGetPhysicalAddress(xi->rx_sring).QuadPart >> PAGE_SHIFT);
422 FUNCTION_MSG("rx sring pfn = %d\n", (ULONG)pfn);
423 xi->rx_sring_gref = XnGrantAccess(xi->handle, (ULONG)pfn, FALSE, INVALID_GRANT_REF, XENNET_POOL_TAG);
424 FUNCTION_MSG("rx sring_gref = %d\n", xi->rx_sring_gref);
425 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "rx-ring-ref", xi->rx_sring_gref);
427 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "request-rx-copy", 1);
428 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "request-rx-notify", 1);
429 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-no-csum-offload", !xi->frontend_csum_supported);
430 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-sg", (int)xi->frontend_sg_supported);
431 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "feature-gso-tcpv4", !!xi->frontend_gso_value);
432 }
433 status = XnReadInt32(xi->handle, XN_BASE_BACKEND, "feature-sg", &tmp_ulong);
434 if (tmp_ulong) {
435 xi->backend_sg_supported = TRUE;
436 }
437 status = XnReadInt32(xi->handle, XN_BASE_BACKEND, "feature-gso-tcpv4", &tmp_ulong);
438 if (tmp_ulong) {
439 xi->backend_gso_value = xi->frontend_gso_value;
440 }
442 status = XnReadString(xi->handle, XN_BASE_BACKEND, "mac", &tmp_string);
443 state = 0;
444 octet = 0;
445 for (i = 0; state != 3 && i < (int)strlen(tmp_string); i++) {
446 if (octet == 6) {
447 state = 3;
448 break;
449 }
450 switch(state) {
451 case 0:
452 case 1:
453 if (tmp_string[i] >= '0' && tmp_string[i] <= '9') {
454 xi->perm_mac_addr[octet] |= (tmp_string[i] - '0') << ((1 - state) * 4);
455 state++;
456 } else if (tmp_string[i] >= 'A' && tmp_string[i] <= 'F') {
457 xi->perm_mac_addr[octet] |= (tmp_string[i] - 'A' + 10) << ((1 - state) * 4);
458 state++;
459 } else if (tmp_string[i] >= 'a' && tmp_string[i] <= 'f') {
460 xi->perm_mac_addr[octet] |= (tmp_string[i] - 'a' + 10) << ((1 - state) * 4);
461 state++;
462 } else {
463 state = 3;
464 }
465 break;
466 case 2:
467 if (tmp_string[i] == ':') {
468 octet++;
469 state = 0;
470 } else {
471 state = 3;
472 }
473 break;
474 }
475 }
476 if (octet != 5 || state != 2) {
477 FUNCTION_MSG("Failed to parse backend MAC address %s\n", tmp_string);
478 XnFreeMem(xi->handle, tmp_string);
479 return STATUS_UNSUCCESSFUL;
480 } else if ((xi->curr_mac_addr[0] & 0x03) != 0x02) {
481 /* only copy if curr_mac_addr is not a LUA */
482 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
483 }
484 XnFreeMem(xi->handle, tmp_string);
485 FUNCTION_MSG("MAC address is %02X:%02X:%02X:%02X:%02X:%02X\n",
486 xi->curr_mac_addr[0], xi->curr_mac_addr[1], xi->curr_mac_addr[2],
487 xi->curr_mac_addr[3], xi->curr_mac_addr[4], xi->curr_mac_addr[5]);
489 if (xi->device_state != DEVICE_STATE_INACTIVE) {
490 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateConnected);
492 for (i = 0; i <= 5 && xi->backend_state != XenbusStateConnected; i++) {
493 FUNCTION_MSG("Waiting for XenbusStateConnected\n");
494 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, NULL);
495 }
496 if (xi->backend_state != XenbusStateConnected) {
497 FUNCTION_MSG("Backend state timeout\n");
498 return STATUS_UNSUCCESSFUL;
499 }
500 XenNet_TxInit(xi);
501 XenNet_RxInit(xi);
502 }
504 /* we don't set device_state = DEVICE_STATE_ACTIVE here - has to be done during init once ndis is ready */
506 return STATUS_SUCCESS;
507 }
509 NTSTATUS
510 XenNet_Disconnect(PVOID context, BOOLEAN suspend) {
511 struct xennet_info *xi = (struct xennet_info *)context;
512 //PFN_NUMBER pfn;
513 NTSTATUS status;
515 if (xi->device_state != DEVICE_STATE_ACTIVE && xi->device_state != DEVICE_STATE_INACTIVE) {
516 FUNCTION_MSG("state not DEVICE_STATE_(IN)ACTIVE, is %d instead\n", xi->device_state);
517 FUNCTION_EXIT();
518 return STATUS_SUCCESS;
519 }
520 if (xi->device_state != DEVICE_STATE_INACTIVE) {
521 xi->device_state = DEVICE_STATE_DISCONNECTING;
522 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
523 while (xi->backend_state != XenbusStateClosing && xi->backend_state != XenbusStateClosed) {
524 FUNCTION_MSG("Waiting for XenbusStateClosing/Closed\n");
525 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, NULL);
526 }
527 status = XnWriteInt32(xi->handle, XN_BASE_FRONTEND, "state", XenbusStateClosed);
528 while (xi->backend_state != XenbusStateClosed) {
529 FUNCTION_MSG("Waiting for XenbusStateClosed\n");
530 KeWaitForSingleObject(&xi->backend_event, Executive, KernelMode, FALSE, NULL);
531 }
532 XnUnbindEvent(xi->handle, xi->event_channel);
534 #if NTDDI_VERSION < WINXP
535 KeFlushQueuedDpcs();
536 #endif
537 XenNet_TxShutdown(xi);
538 XenNet_RxShutdown(xi);
539 XnEndAccess(xi->handle, xi->rx_sring_gref, FALSE, XENNET_POOL_TAG);
540 ExFreePoolWithTag(xi->rx_sring, XENNET_POOL_TAG);
541 XnEndAccess(xi->handle, xi->tx_sring_gref, FALSE, XENNET_POOL_TAG);
542 ExFreePoolWithTag(xi->tx_sring, XENNET_POOL_TAG);
543 }
544 if (!suspend) {
545 XnCloseDevice(xi->handle);
546 }
547 xi->device_state = DEVICE_STATE_DISCONNECTED;
548 return STATUS_SUCCESS;
549 }
551 VOID
552 XenNet_DeviceCallback(PVOID context, ULONG callback_type, PVOID value) {
553 struct xennet_info *xi = (struct xennet_info *)context;
554 ULONG state;
556 FUNCTION_ENTER();
557 switch (callback_type) {
558 case XN_DEVICE_CALLBACK_BACKEND_STATE:
559 state = (ULONG)(ULONG_PTR)value;
560 if (state == xi->backend_state) {
561 FUNCTION_MSG("same state %d\n", state);
562 FUNCTION_EXIT();
563 }
564 FUNCTION_MSG("XenBusState = %d -> %d\n", xi->backend_state, state);
565 xi->backend_state = state;
566 KeSetEvent(&xi->backend_event, 0, FALSE);
567 break;
568 case XN_DEVICE_CALLBACK_SUSPEND:
569 FUNCTION_MSG("XN_DEVICE_CALLBACK_SUSPEND");
570 XenNet_Disconnect(xi, TRUE);
571 break;
572 case XN_DEVICE_CALLBACK_RESUME:
573 FUNCTION_MSG("XN_DEVICE_CALLBACK_RESUME");
574 xi->device_state = DEVICE_STATE_INITIALISING;
575 XenNet_Connect(xi, TRUE);
576 if (xi->device_state != DEVICE_STATE_INACTIVE) {
577 xi->device_state = DEVICE_STATE_ACTIVE;
578 }
579 KeInsertQueueDpc(&xi->rxtx_dpc, NULL, NULL);
580 break;
581 }
582 FUNCTION_EXIT();
583 }