win-pvdrivers

view xennet/xennet.c @ 113:e96b7ebe0147

xennet: buffer pool should never be exhausted -- if it is, it's a bug
author Andy Grover <andy.grover@oracle.com>
date Fri Jan 11 11:47:58 2008 -0800 (2008-01-11)
parents 57b0d44f10f5
children 64e4596aec1c
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 "xennet.h"
25 /* Xen macros use these, so they need to be redefined to Win equivs */
26 #define wmb() KeMemoryBarrier()
27 #define mb() KeMemoryBarrier()
29 #if !defined (NDIS51_MINIPORT)
30 #error requires NDIS 5.1 compilation environment
31 #endif
33 #define GRANT_INVALID_REF 0
35 /* couldn't get regular xen ring macros to work...*/
36 #define __NET_RING_SIZE(type, _sz) \
37 (__RD32( \
38 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
39 / sizeof(union type##_sring_entry)))
41 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
42 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
44 #pragma warning(disable: 4127) // conditional expression is constant
46 struct xennet_info
47 {
48 /* Base device vars */
49 PDEVICE_OBJECT pdo;
50 PDEVICE_OBJECT fdo;
51 PDEVICE_OBJECT lower_do;
52 WDFDEVICE wdf_device;
53 WCHAR dev_desc[NAME_SIZE];
55 /* NDIS-related vars */
56 NDIS_HANDLE adapter_handle;
57 NDIS_HANDLE packet_pool;
58 NDIS_HANDLE buffer_pool;
59 ULONG packet_filter;
60 int connected;
61 UINT8 perm_mac_addr[ETH_ALEN];
62 UINT8 curr_mac_addr[ETH_ALEN];
64 /* Misc. Xen vars */
65 XEN_IFACE XenInterface;
66 PXENPCI_XEN_DEVICE_DATA pdo_data;
67 evtchn_port_t event_channel;
68 ULONG state;
69 KEVENT backend_state_change_event;
70 char backend_path[MAX_XENBUS_STR_LEN];
71 ULONG backend_state;
73 /* Xen ring-related vars */
74 KSPIN_LOCK rx_lock;
75 KSPIN_LOCK tx_lock;
77 LIST_ENTRY tx_waiting_pkt_list;
78 LIST_ENTRY rx_free_pkt_list;
80 struct netif_tx_front_ring tx;
81 struct netif_rx_front_ring rx;
82 grant_ref_t tx_ring_ref;
83 grant_ref_t rx_ring_ref;
85 /* ptrs to the actual rings themselvves */
86 struct netif_tx_sring *tx_pgs;
87 struct netif_rx_sring *rx_pgs;
89 /* MDLs for the above */
90 PMDL tx_mdl;
91 PMDL rx_mdl;
93 /* Outstanding packets. The first entry in tx_pkts
94 * is an index into a chain of free entries. */
95 int tx_pkt_ids_used;
96 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE+1];
97 PNDIS_BUFFER rx_buffers[NET_RX_RING_SIZE];
99 grant_ref_t gref_tx_head;
100 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE+1];
101 grant_ref_t gref_rx_head;
102 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
104 /* Receive-ring batched refills. */
105 #define RX_MIN_TARGET 8
106 #define RX_DFL_MIN_TARGET 64
107 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
108 ULONG rx_target;
109 ULONG rx_max_target;
110 ULONG rx_min_target;
112 /* stats */
113 ULONG64 stat_tx_ok;
114 ULONG64 stat_rx_ok;
115 ULONG64 stat_tx_error;
116 ULONG64 stat_rx_error;
117 ULONG64 stat_rx_no_buffer;
118 };
120 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
121 static unsigned long
122 simple_strtoul(const char *cp,char **endp,unsigned int base)
123 {
124 unsigned long result = 0,value;
126 if (!base) {
127 base = 10;
128 if (*cp == '0') {
129 base = 8;
130 cp++;
131 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
132 cp++;
133 base = 16;
134 }
135 }
136 } else if (base == 16) {
137 if (cp[0] == '0' && toupper(cp[1]) == 'X')
138 cp += 2;
139 }
140 while (isxdigit(*cp) &&
141 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
142 result = result*base + value;
143 cp++;
144 }
145 if (endp)
146 *endp = (char *)cp;
147 return result;
148 }
150 static void
151 add_id_to_freelist(struct xennet_info *xi, unsigned short id)
152 {
153 xi->tx_pkts[id] = xi->tx_pkts[0];
154 xi->tx_pkts[0] = (void *)(unsigned long)id;
155 xi->tx_pkt_ids_used--;
156 }
158 static unsigned short
159 get_id_from_freelist(struct xennet_info *xi)
160 {
161 unsigned short id;
162 if (xi->tx_pkt_ids_used >= NET_TX_RING_SIZE)
163 return 0;
164 id = (unsigned short)(unsigned long)xi->tx_pkts[0];
165 xi->tx_pkts[0] = xi->tx_pkts[id];
166 xi->tx_pkt_ids_used++;
167 return id;
168 }
170 VOID XenNet_SendQueuedPackets(struct xennet_info *xi);
172 // Called at DISPATCH_LEVEL
173 static NDIS_STATUS
174 XenNet_TxBufferGC(struct xennet_info *xi)
175 {
176 RING_IDX cons, prod;
177 unsigned short id;
178 PNDIS_PACKET pkt;
179 PMDL pmdl;
180 KIRQL OldIrql;
182 ASSERT(xi->connected);
184 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
186 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
188 do {
189 prod = xi->tx.sring->rsp_prod;
190 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
192 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
193 struct netif_tx_response *txrsp;
195 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
196 if (txrsp->status == NETIF_RSP_NULL)
197 continue;
199 id = txrsp->id;
200 pkt = xi->tx_pkts[id];
201 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
202 xi->grant_tx_ref[id]);
203 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
204 add_id_to_freelist(xi, id);
206 /* free linearized data page */
207 pmdl = *(PMDL *)pkt->MiniportReservedEx;
208 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
209 IoFreeMdl(pmdl);
211 xi->stat_tx_ok++;
212 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
213 }
215 xi->tx.rsp_cons = prod;
217 /*
218 * Set a new event, then check for race with update of tx_cons.
219 * Note that it is essential to schedule a callback, no matter
220 * how few buffers are pending. Even if there is space in the
221 * transmit ring, higher layers may be blocked because too much
222 * data is outstanding: in such cases notification from Xen is
223 * likely to be the only kick that we'll get.
224 */
225 xi->tx.sring->rsp_event =
226 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
227 KeMemoryBarrier();
228 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
230 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
232 /* if queued packets, send them now */
233 XenNet_SendQueuedPackets(xi);
235 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
237 return NDIS_STATUS_SUCCESS;
238 }
240 static void XenNet_TxBufferFree(struct xennet_info *xi)
241 {
242 PNDIS_PACKET packet;
243 PMDL pmdl;
244 unsigned short id;
246 /* TODO: free packets in tx queue (once implemented) */
248 /* free sent-but-not-completed packets */
249 for (id = 1; id < NET_TX_RING_SIZE+1; id++) {
250 if (xi->grant_tx_ref[id] == GRANT_INVALID_REF)
251 continue;
253 packet = xi->tx_pkts[id];
254 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
255 xi->grant_tx_ref[id]);
256 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
257 add_id_to_freelist(xi, id);
259 /* free linearized data page */
260 pmdl = *(PMDL *)packet->MiniportReservedEx;
261 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
262 IoFreeMdl(pmdl);
264 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
265 }
266 }
268 // Called at DISPATCH_LEVEL with no locks held
269 static NDIS_STATUS
270 XenNet_RxBufferAlloc(struct xennet_info *xi)
271 {
272 unsigned short id;
273 PNDIS_BUFFER buffer;
274 int i, batch_target, notify;
275 RING_IDX req_prod = xi->rx.req_prod_pvt;
276 grant_ref_t ref;
277 netif_rx_request_t *req;
278 NDIS_STATUS status;
279 PVOID start;
280 KIRQL OldIrql;
282 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
284 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
286 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
287 for (i = 0; i < batch_target; i++)
288 {
289 /*
290 * Allocate memory and an NDIS_BUFFER.
291 */
292 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
293 if (status != NDIS_STATUS_SUCCESS)
294 {
295 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
296 break;
297 }
298 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
299 ASSERT(status == NDIS_STATUS_SUCCESS); // should never fail
301 /* Give to netback */
302 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
303 ASSERT(!xi->rx_buffers[id]);
304 xi->rx_buffers[id] = buffer;
305 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
306 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
307 ref = xi->XenInterface.GntTbl_GrantAccess(
308 xi->XenInterface.InterfaceHeader.Context, 0,
309 *MmGetMdlPfnArray(buffer), FALSE);
310 ASSERT((signed short)ref >= 0);
311 xi->grant_rx_ref[id] = ref;
313 req->id = id;
314 req->gref = ref;
315 }
317 xi->rx.req_prod_pvt = req_prod + i;
318 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
319 if (notify)
320 {
321 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
322 xi->event_channel);
323 }
325 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
327 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
329 return NDIS_STATUS_SUCCESS;
330 }
332 /* Free all Rx buffers (on halt, for example) */
333 static void
334 XenNet_RxBufferFree(struct xennet_info *xi)
335 {
336 int i;
337 grant_ref_t ref;
338 PNDIS_BUFFER buffer;
339 KIRQL OldIrql;
341 ASSERT(!xi->connected);
343 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
345 for (i = 0; i < NET_RX_RING_SIZE; i++)
346 {
347 if (!xi->rx_buffers[i])
348 continue;
350 buffer = xi->rx_buffers[i];
351 ref = xi->grant_rx_ref[i];
353 /* don't check return, what can we do about it on failure? */
354 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context, ref);
356 NdisFreeMemory(NdisBufferVirtualAddressSafe(buffer, NormalPagePriority), 0, 0);
357 NdisFreeBuffer(buffer);
358 }
360 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
361 }
363 static VOID
364 XenNet_ProcessReceivedTcpPacket(PNDIS_PACKET packet, PUCHAR buf, ULONG len)
365 {
366 USHORT checksum = (buf[16] << 8) | buf[17];
367 buf[16] = 0;
368 buf[17] = 0;
369 }
371 static VOID
372 XenNet_ProcessReceivedIpPacket(PNDIS_PACKET packet, PUCHAR buf, ULONG len)
373 {
374 UCHAR version;
375 UCHAR header_len;
376 UCHAR proto;
377 USHORT total_len;
379 if (len < 20)
380 {
381 KdPrint((__DRIVER_NAME " IP packet too small\n"));
382 return;
383 }
384 version = buf[0] >> 4;
385 if (version != 4)
386 {
387 KdPrint((__DRIVER_NAME " IP version not IPv4 (version = %d)\n", version));
388 return;
389 }
391 KdPrint((__DRIVER_NAME " %d.%d.%d.%d -> %d.%d.%d.%d\n",
392 buf[12], buf[13], buf[14], buf[15],
393 buf[16], buf[17], buf[18], buf[19]));
395 header_len = (buf[0] & 15) * 4;
396 total_len = (buf[2] << 8) | buf[3];
398 if (total_len != len)
399 {
400 KdPrint((__DRIVER_NAME " IP packet probably fragmented.\n"));
401 return;
402 }
404 // todo: check header checksum & fix if wrong
406 proto = buf[9];
408 switch (proto)
409 {
410 case 6: //tcp
411 KdPrint((__DRIVER_NAME " IP Proto = TCP\n"));
412 XenNet_ProcessReceivedTcpPacket(packet, buf + header_len, len - header_len);
413 break;
414 case 17: //udp
415 KdPrint((__DRIVER_NAME " IP Proto = UDP\n"));
416 break;
417 default:
418 KdPrint((__DRIVER_NAME " IP Proto = %d\n", proto));
419 break;
420 }
421 }
423 static VOID
424 XenNet_ProcessReceivedEthernetPacket(PNDIS_PACKET packet, PUCHAR buf, ULONG len)
425 {
426 USHORT ethertype = (buf[12]) << 8 | buf[13];
428 if (len < 14)
429 {
430 KdPrint((__DRIVER_NAME " Ethernet packet header too small (%d).\n", len));
431 return;
432 }
433 if (ethertype < 0x600)
434 return; // not Ethernet II
435 switch (ethertype)
436 {
437 case 0x0800:
438 KdPrint((__DRIVER_NAME " EtherType = IP\n"));
439 XenNet_ProcessReceivedIpPacket(packet, buf + 14, len - 14);
440 break;
441 case 0x0806:
442 KdPrint((__DRIVER_NAME " EtherType = ARP\n"));
443 break;
444 case 0x8100:
445 KdPrint((__DRIVER_NAME " EtherType = VLAN\n"));
446 break;
447 default:
448 KdPrint((__DRIVER_NAME " EtherType = %04x\n", ethertype));
449 break;
450 }
451 }
453 // Called at DISPATCH_LEVEL
454 static NDIS_STATUS
455 XenNet_RxBufferCheck(struct xennet_info *xi)
456 {
457 RING_IDX cons, prod;
459 PNDIS_PACKET packet = NULL;
460 PNDIS_BUFFER buffer;
461 int moretodo;
462 KIRQL OldIrql;
463 PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
464 struct netif_rx_response *rxrsp = NULL;
465 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
466 NDIS_STATUS status;
468 ASSERT(xi->connected);
470 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
472 do {
473 prod = xi->rx.sring->rsp_prod;
474 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
476 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
477 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
478 ASSERT(rxrsp->status > 0);
480 if (!(rxrsp->flags & NETRXF_more_data)) // handling the packet's 1st buffer
481 {
482 // KdPrint((__DRIVER_NAME " Got a packet\n"));
483 NdisAllocatePacket(&status, &packet, xi->packet_pool);
484 ASSERT(status == NDIS_STATUS_SUCCESS);
485 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
486 /*
487 if (NDIS_GET_PACKET_PROTOCOL_TYPE(packet) == NDIS_PROTOCOL_ID_TCP_IP
488 && (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated)))
489 {
490 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo);
491 csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
492 csum_info->Receive.NdisPacketUdpChecksumSucceeded = 1;
493 csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
494 // KdPrint((__DRIVER_NAME " Offload = %08x\n", NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo)));
495 }
496 */
497 }
498 buffer = xi->rx_buffers[rxrsp->id];
499 xi->rx_buffers[rxrsp->id] = NULL;
500 NdisAdjustBufferLength(buffer, rxrsp->status);
502 NdisChainBufferAtBack(packet, buffer);
504 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
505 xi->grant_rx_ref[rxrsp->id]);
506 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
508 #if 1
509 KdPrint((__DRIVER_NAME " Flags = %sNETRXF_data_validated|%sNETRXF_csum_blank|%sNETRXF_more_data|%sNETRXF_extra_info\n",
510 (rxrsp->flags&NETRXF_data_validated)?"":"!",
511 (rxrsp->flags&NETRXF_csum_blank)?"":"!",
512 (rxrsp->flags&NETRXF_more_data)?"":"!",
513 (rxrsp->flags&NETRXF_extra_info)?"":"!"));
514 #endif
515 ASSERT(!(rxrsp->flags & NETRXF_extra_info)); // not used on RX
517 //XenNet_ProcessReceivedEthernetPacket(packet, buff_va, rxrsp->status);
519 /* Packet done, pass it up */
520 if (!(rxrsp->flags & NETRXF_more_data))
521 {
522 xi->stat_rx_ok++;
523 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
524 NdisMIndicateReceivePacket(xi->adapter_handle, &packet, 1);
525 }
526 }
528 ASSERT(!(rxrsp->flags & NETRXF_more_data));
530 xi->rx.rsp_cons = prod;
532 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
533 } while (moretodo);
535 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
537 /* Give netback more buffers */
538 XenNet_RxBufferAlloc(xi);
540 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
542 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
544 return NDIS_STATUS_SUCCESS;
545 }
547 // Called at DISPATCH_LEVEL
548 static BOOLEAN
549 XenNet_Interrupt(
550 PKINTERRUPT Interrupt,
551 PVOID ServiceContext
552 )
553 {
554 struct xennet_info *xi = ServiceContext;
556 UNREFERENCED_PARAMETER(Interrupt);
558 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
560 if (xi->connected)
561 {
562 XenNet_TxBufferGC(xi);
563 XenNet_RxBufferCheck(xi);
564 }
566 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
568 return TRUE;
569 }
571 // Called at <= DISPATCH_LEVEL
573 static VOID
574 XenNet_BackEndStateHandler(char *Path, PVOID Data)
575 {
576 struct xennet_info *xi = Data;
577 char *Value;
578 char TmpPath[MAX_XENBUS_STR_LEN];
579 xenbus_transaction_t xbt = 0;
580 int retry = 0;
581 char *err;
582 int i;
583 ULONG new_backend_state;
585 struct set_params {
586 char *name;
587 int value;
588 } params[] = {
589 {"tx-ring-ref", 0},
590 {"rx-ring-ref", 0},
591 {"event-channel", 0},
592 {"request-rx-copy", 1},
593 {"feature-rx-notify", 1},
594 {"feature-no-csum-offload", 1},
595 {"feature-sg", 1},
596 {"feature-gso-tcpv4", 0},
597 {NULL, 0},
598 };
600 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
601 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
603 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
604 XBT_NIL, Path, &Value);
605 new_backend_state = atoi(Value);
606 xi->XenInterface.FreeMem(Value);
608 if (xi->backend_state == new_backend_state)
609 {
610 KdPrint((__DRIVER_NAME " state unchanged\n"));
611 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
612 return;
613 }
615 xi->backend_state = new_backend_state;
617 switch (xi->backend_state)
618 {
619 case XenbusStateUnknown:
620 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
621 break;
623 case XenbusStateInitialising:
624 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
625 break;
627 case XenbusStateInitWait:
628 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
630 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
631 xi->XenInterface.InterfaceHeader.Context, 0);
632 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
633 xi->event_channel, XenNet_Interrupt, xi);
635 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
636 // or, allocate mem and then get mdl, then free mdl
637 xi->tx_mdl = AllocatePage();
638 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl); //MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
639 SHARED_RING_INIT(xi->tx_pgs);
640 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
641 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
642 xi->XenInterface.InterfaceHeader.Context, 0,
643 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
645 xi->rx_mdl = AllocatePage();
646 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl); //MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
647 SHARED_RING_INIT(xi->rx_pgs);
648 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
649 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
650 xi->XenInterface.InterfaceHeader.Context, 0,
651 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
653 /* fixup array for dynamic values */
654 params[0].value = xi->tx_ring_ref;
655 params[1].value = xi->rx_ring_ref;
656 params[2].value = xi->event_channel;
658 xi->XenInterface.XenBus_StartTransaction(
659 xi->XenInterface.InterfaceHeader.Context, &xbt);
661 for (i = 0; params[i].name; i++)
662 {
663 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
664 xi->pdo_data->Path, params[i].name);
665 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
666 XBT_NIL, TmpPath, "%d", params[i].value);
667 if (err)
668 {
669 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
670 goto trouble;
671 }
672 }
674 /* commit transaction */
675 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
676 xbt, 0, &retry);
678 XenNet_RxBufferAlloc(xi);
680 xi->state = XenbusStateConnected;
681 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
682 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
683 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
684 XBT_NIL, TmpPath, "%d", xi->state);
686 /* send fake arp? */
688 xi->connected = TRUE;
690 break;
692 case XenbusStateInitialised:
693 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
694 break;
696 case XenbusStateConnected:
697 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
698 break;
700 case XenbusStateClosing:
701 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
702 break;
704 case XenbusStateClosed:
705 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
706 break;
708 default:
709 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
710 break;
711 }
713 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
715 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
717 return;
719 trouble:
720 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
721 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
722 xbt, 1, &retry);
723 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
724 }
726 static NDIS_STATUS
727 XenNet_Init(
728 OUT PNDIS_STATUS OpenErrorStatus,
729 OUT PUINT SelectedMediumIndex,
730 IN PNDIS_MEDIUM MediumArray,
731 IN UINT MediumArraySize,
732 IN NDIS_HANDLE MiniportAdapterHandle,
733 IN NDIS_HANDLE WrapperConfigurationContext
734 )
735 {
736 NDIS_STATUS status;
737 UINT i;
738 BOOLEAN medium_found = FALSE;
739 struct xennet_info *xi = NULL;
740 ULONG length;
741 WDF_OBJECT_ATTRIBUTES wdf_attrs;
742 char *res;
743 char *Value;
744 char TmpPath[MAX_XENBUS_STR_LEN];
746 UNREFERENCED_PARAMETER(OpenErrorStatus);
747 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
749 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
750 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
752 /* deal with medium stuff */
753 for (i = 0; i < MediumArraySize; i++)
754 {
755 if (MediumArray[i] == NdisMedium802_3)
756 {
757 medium_found = TRUE;
758 break;
759 }
760 }
761 if (!medium_found)
762 {
763 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
764 return NDIS_STATUS_UNSUPPORTED_MEDIA;
765 }
766 *SelectedMediumIndex = i;
768 /* Alloc memory for adapter private info */
769 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
770 if (!NT_SUCCESS(status))
771 {
772 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
773 status = NDIS_STATUS_RESOURCES;
774 goto err;
775 }
776 RtlZeroMemory(xi, sizeof(*xi));
778 /* init xennet_info */
779 xi->adapter_handle = MiniportAdapterHandle;
780 xi->rx_target = RX_DFL_MIN_TARGET;
781 xi->rx_min_target = RX_DFL_MIN_TARGET;
782 xi->rx_max_target = RX_MAX_TARGET;
784 xi->state = XenbusStateUnknown;
785 xi->backend_state = XenbusStateUnknown;
787 KeInitializeSpinLock(&xi->tx_lock);
788 KeInitializeSpinLock(&xi->rx_lock);
789 InitializeListHead(&xi->rx_free_pkt_list);
790 InitializeListHead(&xi->tx_waiting_pkt_list);
793 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
794 PROTOCOL_RESERVED_SIZE_IN_PACKET);
795 if (status != NDIS_STATUS_SUCCESS)
796 {
797 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
798 status = NDIS_STATUS_RESOURCES;
799 goto err;
800 }
801 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
803 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
804 if (status != NDIS_STATUS_SUCCESS)
805 {
806 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
807 status = NDIS_STATUS_RESOURCES;
808 goto err;
809 }
811 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
812 &xi->lower_do, NULL, NULL);
813 xi->pdo_data = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
815 /* Initialize tx_pkts as a free chain containing every entry. */
816 for (i = 0; i < NET_TX_RING_SIZE+1; i++) {
817 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
818 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
819 }
821 for (i = 0; i < NET_RX_RING_SIZE; i++) {
822 xi->rx_buffers[i] = NULL;
823 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
824 }
826 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
828 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
829 NAME_SIZE, xi->dev_desc, &length);
830 if (!NT_SUCCESS(status))
831 {
832 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
833 status = NDIS_STATUS_FAILURE;
834 goto err;
835 }
837 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
838 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
839 NdisInterfaceInternal);
841 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
843 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
844 xi->lower_do, xi->pdo, &xi->wdf_device);
845 if (!NT_SUCCESS(status))
846 {
847 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
848 status = NDIS_STATUS_FAILURE;
849 goto err;
850 }
852 /* get lower (Xen) interfaces */
854 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
855 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
856 if(!NT_SUCCESS(status))
857 {
858 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
859 status = NDIS_STATUS_FAILURE;
860 goto err;
861 }
863 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
864 "%s/backend", xi->pdo_data->Path);
865 KdPrint(("About to read %s to get backend path\n", TmpPath));
866 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
867 XBT_NIL, TmpPath, &Value);
868 if (res)
869 {
870 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
871 xi->XenInterface.FreeMem(res);
872 status = NDIS_STATUS_FAILURE;
873 goto err;
874 }
875 RtlStringCbCopyA(xi->backend_path, ARRAY_SIZE(xi->backend_path), Value);
876 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->backend_path));
878 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/type", xi->backend_path);
879 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
880 XBT_NIL, TmpPath, &Value);
882 #if 1
883 if (res || strcmp(Value, "netfront") != 0)
884 {
885 KdPrint((__DRIVER_NAME " Backend type is not 'netfront'\n"));
886 status = NDIS_STATUS_FAILURE;
887 goto err;
888 }
889 #endif
891 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
893 /* Add watch on backend state */
894 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
895 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
896 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
898 /* Tell backend we're coming up */
899 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
900 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
901 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
903 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
905 // wait here for signal that we are all set up
906 while (xi->backend_state != XenbusStateConnected)
907 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
909 KdPrint((__DRIVER_NAME " Connected\n"));
911 /* get mac address */
912 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->backend_path);
913 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
914 XBT_NIL, TmpPath, &Value);
915 if (!Value)
916 {
917 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
918 status = NDIS_STATUS_FAILURE;
919 goto err;
920 }
921 else
922 {
923 char *s, *e;
924 s = Value;
925 for (i = 0; i < ETH_ALEN; i++) {
926 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
927 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
928 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
929 xi->XenInterface.FreeMem(Value);
930 status = NDIS_STATUS_FAILURE;
931 goto err;
932 }
933 s = e + 1;
934 }
935 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
936 xi->XenInterface.FreeMem(Value);
937 }
939 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
941 return NDIS_STATUS_SUCCESS;
943 err:
944 NdisFreeMemory(xi, 0, 0);
945 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
946 return status;
947 }
949 // Q = Query Mandatory, S = Set Mandatory
950 NDIS_OID supported_oids[] =
951 {
952 /* general OIDs */
953 OID_GEN_SUPPORTED_LIST, // Q
954 OID_GEN_HARDWARE_STATUS, // Q
955 OID_GEN_MEDIA_SUPPORTED, // Q
956 OID_GEN_MEDIA_IN_USE, // Q
957 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
958 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
959 OID_GEN_LINK_SPEED, // Q
960 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
961 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
962 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
963 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
964 OID_GEN_VENDOR_ID, // Q
965 OID_GEN_VENDOR_DESCRIPTION, // Q
966 OID_GEN_CURRENT_PACKET_FILTER, // QS
967 OID_GEN_CURRENT_LOOKAHEAD, // QS
968 OID_GEN_DRIVER_VERSION, // Q
969 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
970 OID_GEN_PROTOCOL_OPTIONS, // S
971 OID_GEN_MAC_OPTIONS, // Q
972 OID_GEN_MEDIA_CONNECT_STATUS, // Q
973 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
974 /* stats */
975 OID_GEN_XMIT_OK, // Q
976 OID_GEN_RCV_OK, // Q
977 OID_GEN_XMIT_ERROR, // Q
978 OID_GEN_RCV_ERROR, // Q
979 OID_GEN_RCV_NO_BUFFER, // Q
980 /* media-specific OIDs */
981 OID_802_3_PERMANENT_ADDRESS,
982 OID_802_3_CURRENT_ADDRESS,
983 OID_802_3_MULTICAST_LIST,
984 OID_802_3_MAXIMUM_LIST_SIZE,
985 /* tcp offload */
986 OID_TCP_TASK_OFFLOAD,
987 };
989 /* return 4 or 8 depending on size of buffer */
990 #define HANDLE_STAT_RETURN \
991 {if (InformationBufferLength == 4) { \
992 len = 4; *BytesNeeded = 8; \
993 } else { \
994 len = 8; \
995 } }
997 //#define OFFLOAD_LARGE_SEND
999 NDIS_STATUS
1000 XenNet_QueryInformation(
1001 IN NDIS_HANDLE MiniportAdapterContext,
1002 IN NDIS_OID Oid,
1003 IN PVOID InformationBuffer,
1004 IN ULONG InformationBufferLength,
1005 OUT PULONG BytesWritten,
1006 OUT PULONG BytesNeeded)
1008 struct xennet_info *xi = MiniportAdapterContext;
1009 UCHAR vendor_desc[] = XN_VENDOR_DESC;
1010 ULONG64 temp_data;
1011 PVOID data = &temp_data;
1012 UINT len = 4;
1013 BOOLEAN used_temp_buffer = TRUE;
1014 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1015 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1016 PNDIS_TASK_OFFLOAD nto;
1017 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1018 #ifdef OFFLOAD_LARGE_SEND
1019 PNDIS_TASK_TCP_LARGE_SEND nttls;
1020 #endif
1022 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1024 switch(Oid)
1026 case OID_GEN_SUPPORTED_LIST:
1027 data = supported_oids;
1028 len = sizeof(supported_oids);
1029 break;
1030 case OID_GEN_HARDWARE_STATUS:
1031 if (!xi->connected)
1032 temp_data = NdisHardwareStatusInitializing;
1033 else
1034 temp_data = NdisHardwareStatusReady;
1035 break;
1036 case OID_GEN_MEDIA_SUPPORTED:
1037 temp_data = NdisMedium802_3;
1038 break;
1039 case OID_GEN_MEDIA_IN_USE:
1040 temp_data = NdisMedium802_3;
1041 break;
1042 case OID_GEN_MAXIMUM_LOOKAHEAD:
1043 temp_data = XN_DATA_SIZE;
1044 break;
1045 case OID_GEN_MAXIMUM_FRAME_SIZE:
1046 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
1047 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
1048 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
1049 break;
1050 case OID_GEN_LINK_SPEED:
1051 temp_data = 10000000; /* 1Gb */
1052 break;
1053 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1054 /* pkts times sizeof ring, maybe? */
1055 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
1056 break;
1057 case OID_GEN_RECEIVE_BUFFER_SPACE:
1058 /* pkts times sizeof ring, maybe? */
1059 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
1060 break;
1061 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1062 temp_data = XN_MAX_PKT_SIZE;
1063 break;
1064 case OID_GEN_RECEIVE_BLOCK_SIZE:
1065 temp_data = XN_MAX_PKT_SIZE;
1066 break;
1067 case OID_GEN_VENDOR_ID:
1068 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
1069 break;
1070 case OID_GEN_VENDOR_DESCRIPTION:
1071 data = vendor_desc;
1072 len = sizeof(vendor_desc);
1073 break;
1074 case OID_GEN_CURRENT_PACKET_FILTER:
1075 temp_data = xi->packet_filter;
1076 break;
1077 case OID_GEN_CURRENT_LOOKAHEAD:
1078 // TODO: we should store this...
1079 temp_data = XN_MAX_PKT_SIZE;
1080 break;
1081 case OID_GEN_DRIVER_VERSION:
1082 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
1083 len = 2;
1084 break;
1085 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1086 temp_data = XN_MAX_PKT_SIZE;
1087 break;
1088 case OID_GEN_MAC_OPTIONS:
1089 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1090 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1091 NDIS_MAC_OPTION_NO_LOOPBACK;
1092 break;
1093 case OID_GEN_MEDIA_CONNECT_STATUS:
1094 if (xi->connected)
1095 temp_data = NdisMediaStateConnected;
1096 else
1097 temp_data = NdisMediaStateDisconnected;
1098 break;
1099 case OID_GEN_MAXIMUM_SEND_PACKETS:
1100 temp_data = XN_MAX_SEND_PKTS;
1101 break;
1102 case OID_GEN_XMIT_OK:
1103 temp_data = xi->stat_tx_ok;
1104 HANDLE_STAT_RETURN;
1105 break;
1106 case OID_GEN_RCV_OK:
1107 temp_data = xi->stat_rx_ok;
1108 HANDLE_STAT_RETURN;
1109 break;
1110 case OID_GEN_XMIT_ERROR:
1111 temp_data = xi->stat_tx_error;
1112 HANDLE_STAT_RETURN;
1113 break;
1114 case OID_GEN_RCV_ERROR:
1115 temp_data = xi->stat_rx_error;
1116 HANDLE_STAT_RETURN;
1117 break;
1118 case OID_GEN_RCV_NO_BUFFER:
1119 temp_data = xi->stat_rx_no_buffer;
1120 HANDLE_STAT_RETURN;
1121 break;
1122 case OID_802_3_PERMANENT_ADDRESS:
1123 data = xi->perm_mac_addr;
1124 len = ETH_ALEN;
1125 break;
1126 case OID_802_3_CURRENT_ADDRESS:
1127 data = xi->curr_mac_addr;
1128 len = ETH_ALEN;
1129 break;
1130 case OID_802_3_MULTICAST_LIST:
1131 data = NULL;
1132 len = 0;
1133 case OID_802_3_MAXIMUM_LIST_SIZE:
1134 temp_data = 0; /* no mcast support */
1135 break;
1136 case OID_TCP_TASK_OFFLOAD:
1137 KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
1138 /* it's times like this that C really sucks */
1140 len = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1142 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1143 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1144 #ifdef OFFLOAD_LARGE_SEND
1145 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1146 + sizeof(NDIS_TASK_TCP_LARGE_SEND);
1147 #endif
1149 if (len > InformationBufferLength)
1151 break;
1154 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1155 ASSERT(ntoh->Version == NDIS_TASK_OFFLOAD_VERSION);
1156 ASSERT(ntoh->Size == sizeof(*ntoh));
1157 ASSERT(ntoh->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation);
1158 ntoh->OffsetFirstTask = ntoh->Size;
1160 /* fill in first nto */
1161 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
1162 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1163 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1164 nto->Task = TcpIpChecksumNdisTask;
1165 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1167 /* fill in checksum offload struct */
1168 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1169 nttic->V4Transmit.IpOptionsSupported = 0;
1170 nttic->V4Transmit.TcpOptionsSupported = 0;
1171 nttic->V4Transmit.TcpChecksum = 0;
1172 nttic->V4Transmit.UdpChecksum = 0;
1173 nttic->V4Transmit.IpChecksum = 0;
1174 nttic->V4Receive.IpOptionsSupported = 1;
1175 nttic->V4Receive.TcpOptionsSupported = 1;
1176 nttic->V4Receive.TcpChecksum = 1;
1177 nttic->V4Receive.UdpChecksum = 1;
1178 nttic->V4Receive.IpChecksum = 1;
1179 nttic->V6Transmit.IpOptionsSupported = 0;
1180 nttic->V6Transmit.TcpOptionsSupported = 0;
1181 nttic->V6Transmit.TcpChecksum = 0;
1182 nttic->V6Transmit.UdpChecksum = 0;
1183 nttic->V6Receive.IpOptionsSupported = 0;
1184 nttic->V6Receive.TcpOptionsSupported = 0;
1185 nttic->V6Receive.TcpChecksum = 0;
1186 nttic->V6Receive.UdpChecksum = 0;
1188 #ifdef OFFLOAD_LARGE_SEND
1189 /* offset from start of current NTO to start of next NTO */
1190 nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1191 + nto->TaskBufferLength;
1193 /* fill in second nto */
1194 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
1195 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1196 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1197 nto->Task = TcpLargeSendNdisTask;
1198 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
1200 /* fill in large send struct */
1201 nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
1202 nttls->Version = 0;
1203 nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
1204 nttls->MinSegmentCount = 4; /* also made up */
1205 nttls->TcpOptions = FALSE;
1206 nttls->IpOptions = FALSE;
1207 #endif
1208 nto->OffsetNextTask = 0; /* last one */
1210 used_temp_buffer = FALSE;
1211 break;
1212 default:
1213 KdPrint(("Get Unknown OID 0x%x\n", Oid));
1214 status = NDIS_STATUS_NOT_SUPPORTED;
1217 if (!NT_SUCCESS(status))
1219 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
1220 return status;
1223 if (len > InformationBufferLength)
1225 *BytesNeeded = len;
1226 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (BUFFER_TOO_SHORT)\n"));
1227 return NDIS_STATUS_BUFFER_TOO_SHORT;
1230 *BytesWritten = len;
1231 if (len && used_temp_buffer)
1233 NdisMoveMemory((PUCHAR)InformationBuffer, data, len);
1236 //KdPrint(("Got OID 0x%x\n", Oid));
1237 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1239 return status;
1242 NDIS_STATUS
1243 XenNet_SetInformation(
1244 IN NDIS_HANDLE MiniportAdapterContext,
1245 IN NDIS_OID Oid,
1246 IN PVOID InformationBuffer,
1247 IN ULONG InformationBufferLength,
1248 OUT PULONG BytesRead,
1249 OUT PULONG BytesNeeded
1252 NTSTATUS status;
1253 struct xennet_info *xi = MiniportAdapterContext;
1254 PULONG64 data = InformationBuffer;
1255 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1256 PNDIS_TASK_OFFLOAD nto;
1257 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1258 int offset;
1260 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1262 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1263 UNREFERENCED_PARAMETER(InformationBufferLength);
1264 UNREFERENCED_PARAMETER(BytesRead);
1265 UNREFERENCED_PARAMETER(BytesNeeded);
1267 switch(Oid)
1269 case OID_GEN_SUPPORTED_LIST:
1270 status = NDIS_STATUS_NOT_SUPPORTED;
1271 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1272 break;
1273 case OID_GEN_HARDWARE_STATUS:
1274 status = NDIS_STATUS_NOT_SUPPORTED;
1275 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1276 break;
1277 case OID_GEN_MEDIA_SUPPORTED:
1278 status = NDIS_STATUS_NOT_SUPPORTED;
1279 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1280 break;
1281 case OID_GEN_MEDIA_IN_USE:
1282 status = NDIS_STATUS_NOT_SUPPORTED;
1283 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1284 break;
1285 case OID_GEN_MAXIMUM_LOOKAHEAD:
1286 status = NDIS_STATUS_NOT_SUPPORTED;
1287 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1288 break;
1289 case OID_GEN_MAXIMUM_FRAME_SIZE:
1290 status = NDIS_STATUS_NOT_SUPPORTED;
1291 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1292 break;
1293 case OID_GEN_LINK_SPEED:
1294 status = NDIS_STATUS_NOT_SUPPORTED;
1295 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1296 break;
1297 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1298 status = NDIS_STATUS_NOT_SUPPORTED;
1299 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1300 break;
1301 case OID_GEN_RECEIVE_BUFFER_SPACE:
1302 status = NDIS_STATUS_NOT_SUPPORTED;
1303 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1304 break;
1305 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1306 status = NDIS_STATUS_NOT_SUPPORTED;
1307 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1308 break;
1309 case OID_GEN_RECEIVE_BLOCK_SIZE:
1310 status = NDIS_STATUS_NOT_SUPPORTED;
1311 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1312 break;
1313 case OID_GEN_VENDOR_ID:
1314 status = NDIS_STATUS_NOT_SUPPORTED;
1315 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1316 break;
1317 case OID_GEN_VENDOR_DESCRIPTION:
1318 status = NDIS_STATUS_NOT_SUPPORTED;
1319 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1320 break;
1321 case OID_GEN_CURRENT_PACKET_FILTER:
1322 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1323 xi->packet_filter = *(ULONG *)data;
1324 status = NDIS_STATUS_SUCCESS;
1325 break;
1326 case OID_GEN_CURRENT_LOOKAHEAD:
1327 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1328 // TODO: We should do this...
1329 status = NDIS_STATUS_SUCCESS;
1330 break;
1331 case OID_GEN_DRIVER_VERSION:
1332 status = NDIS_STATUS_NOT_SUPPORTED;
1333 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1334 break;
1335 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1336 status = NDIS_STATUS_NOT_SUPPORTED;
1337 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1338 break;
1339 case OID_GEN_PROTOCOL_OPTIONS:
1340 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1341 // TODO - actually do this...
1342 status = NDIS_STATUS_SUCCESS;
1343 break;
1344 case OID_GEN_MAC_OPTIONS:
1345 status = NDIS_STATUS_NOT_SUPPORTED;
1346 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1347 break;
1348 case OID_GEN_MEDIA_CONNECT_STATUS:
1349 status = NDIS_STATUS_NOT_SUPPORTED;
1350 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1351 break;
1352 case OID_GEN_MAXIMUM_SEND_PACKETS:
1353 status = NDIS_STATUS_NOT_SUPPORTED;
1354 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1355 break;
1356 case OID_GEN_XMIT_OK:
1357 status = NDIS_STATUS_NOT_SUPPORTED;
1358 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1359 break;
1360 case OID_GEN_RCV_OK:
1361 status = NDIS_STATUS_NOT_SUPPORTED;
1362 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1363 break;
1364 case OID_GEN_XMIT_ERROR:
1365 status = NDIS_STATUS_NOT_SUPPORTED;
1366 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1367 break;
1368 case OID_GEN_RCV_ERROR:
1369 status = NDIS_STATUS_NOT_SUPPORTED;
1370 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1371 break;
1372 case OID_GEN_RCV_NO_BUFFER:
1373 status = NDIS_STATUS_NOT_SUPPORTED;
1374 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1375 break;
1376 case OID_802_3_PERMANENT_ADDRESS:
1377 status = NDIS_STATUS_NOT_SUPPORTED;
1378 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1379 break;
1380 case OID_802_3_CURRENT_ADDRESS:
1381 status = NDIS_STATUS_NOT_SUPPORTED;
1382 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1383 break;
1384 case OID_802_3_MULTICAST_LIST:
1385 status = NDIS_STATUS_NOT_SUPPORTED;
1386 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1387 break;
1388 case OID_802_3_MAXIMUM_LIST_SIZE:
1389 status = NDIS_STATUS_NOT_SUPPORTED;
1390 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1391 break;
1392 case OID_TCP_TASK_OFFLOAD:
1393 // Just fake this for now... ultimately we need to manually calc rx checksum if offload is disabled by windows
1394 status = NDIS_STATUS_SUCCESS;
1395 KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
1396 // we should disable everything here, then enable what has been set
1397 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1398 *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1399 offset = ntoh->OffsetFirstTask;
1400 nto = (PNDIS_TASK_OFFLOAD)ntoh; // not really, just to get the first offset right
1401 while (offset != 0)
1403 *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
1404 nto = (PNDIS_TASK_OFFLOAD)(((PUCHAR)nto) + offset);
1405 switch (nto->Task)
1407 case TcpIpChecksumNdisTask:
1408 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1409 KdPrint(("TcpIpChecksumNdisTask\n"));
1410 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1411 KdPrint((" V4Transmit.IpOptionsSupported = %d\n", nttic->V4Transmit.IpOptionsSupported));
1412 KdPrint((" V4Transmit.TcpOptionsSupported = %d\n", nttic->V4Transmit.TcpOptionsSupported));
1413 KdPrint((" V4Transmit.TcpChecksum = %d\n", nttic->V4Transmit.TcpChecksum));
1414 KdPrint((" V4Transmit.UdpChecksum = %d\n", nttic->V4Transmit.UdpChecksum));
1415 KdPrint((" V4Transmit.IpChecksum = %d\n", nttic->V4Transmit.IpChecksum));
1416 KdPrint((" V4Receive.IpOptionsSupported = %d\n", nttic->V4Receive.IpOptionsSupported));
1417 KdPrint((" V4Receive.TcpOptionsSupported = %d\n", nttic->V4Receive.TcpOptionsSupported));
1418 KdPrint((" V4Receive.TcpChecksum = %d\n", nttic->V4Receive.TcpChecksum));
1419 KdPrint((" V4Receive.UdpChecksum = %d\n", nttic->V4Receive.UdpChecksum));
1420 KdPrint((" V4Receive.IpChecksum = %d\n", nttic->V4Receive.IpChecksum));
1421 KdPrint((" V6Transmit.IpOptionsSupported = %d\n", nttic->V6Transmit.IpOptionsSupported));
1422 KdPrint((" V6Transmit.TcpOptionsSupported = %d\n", nttic->V6Transmit.TcpOptionsSupported));
1423 KdPrint((" V6Transmit.TcpChecksum = %d\n", nttic->V6Transmit.TcpChecksum));
1424 KdPrint((" V6Transmit.UdpChecksum = %d\n", nttic->V6Transmit.UdpChecksum));
1425 KdPrint((" V6Receive.IpOptionsSupported = %d\n", nttic->V6Receive.IpOptionsSupported));
1426 KdPrint((" V6Receive.TcpOptionsSupported = %d\n", nttic->V6Receive.TcpOptionsSupported));
1427 KdPrint((" V6Receive.TcpChecksum = %d\n", nttic->V6Receive.TcpChecksum));
1428 KdPrint((" V6Receive.UdpChecksum = %d\n", nttic->V6Receive.UdpChecksum));
1429 break;
1430 default:
1431 KdPrint((" Unknown Task %d\n", nto->Task));
1433 offset = nto->OffsetNextTask;
1435 break;
1436 default:
1437 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1438 status = NDIS_STATUS_NOT_SUPPORTED;
1439 break;
1441 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1442 return status;
1445 VOID
1446 XenNet_ReturnPacket(
1447 IN NDIS_HANDLE MiniportAdapterContext,
1448 IN PNDIS_PACKET Packet
1451 PNDIS_BUFFER buffer;
1452 PVOID buff_va;
1453 UINT buff_len;
1454 UINT tot_buff_len;
1456 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1458 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1460 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1461 &tot_buff_len, NormalPagePriority);
1462 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1464 while (buffer)
1466 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1467 NdisFreeMemory(buff_va, 0, 0);
1468 NdisFreeBuffer(buffer);
1469 NdisGetNextBuffer(buffer, &buffer);
1472 NdisFreePacket(Packet);
1474 //KdPrint((__FUNCTION__ " called\n"));
1475 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1478 PMDL
1479 XenNet_Linearize(PNDIS_PACKET Packet)
1481 NDIS_STATUS status;
1482 PMDL pmdl;
1483 char *start;
1484 PNDIS_BUFFER buffer;
1485 PVOID buff_va;
1486 UINT buff_len;
1487 UINT tot_buff_len;
1489 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1491 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1492 &tot_buff_len, NormalPagePriority);
1493 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1495 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1496 if (!NT_SUCCESS(status))
1498 KdPrint(("Could not allocate memory for linearization\n"));
1499 return NULL;
1501 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1502 if (!pmdl)
1504 KdPrint(("Could not allocate MDL for linearization\n"));
1505 NdisFreeMemory(start, 0, 0);
1506 return NULL;
1508 MmBuildMdlForNonPagedPool(pmdl);
1510 while (buffer)
1512 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1513 RtlCopyMemory(start, buff_va, buff_len);
1514 start += buff_len;
1515 NdisGetNextBuffer(buffer, &buffer);
1518 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1519 return pmdl;
1522 VOID
1523 XenNet_SendQueuedPackets(struct xennet_info *xi)
1525 PLIST_ENTRY entry;
1526 PNDIS_PACKET packet;
1527 KIRQL OldIrql;
1528 struct netif_tx_request *tx;
1529 unsigned short id;
1530 int notify;
1531 PMDL pmdl;
1532 UINT pkt_size;
1534 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
1536 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1537 /* if empty, the above returns head*, not NULL */
1538 while (entry != &xi->tx_waiting_pkt_list)
1540 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[4]);
1542 NdisQueryPacket(packet, NULL, NULL, NULL, &pkt_size);
1543 pmdl = *(PMDL *)packet->MiniportReservedEx;
1545 id = get_id_from_freelist(xi);
1546 if (!id)
1548 /* whups, out of space on the ring. requeue and get out */
1549 InsertHeadList(&xi->tx_waiting_pkt_list, entry);
1550 break;
1552 xi->tx_pkts[id] = packet;
1554 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1555 tx->id = id;
1556 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1557 xi->XenInterface.InterfaceHeader.Context,
1558 0,
1559 *MmGetMdlPfnArray(pmdl),
1560 TRUE);
1561 xi->grant_tx_ref[id] = tx->gref;
1562 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1563 tx->size = (UINT16)pkt_size;
1564 // NETTXF_csum_blank should only be used for tcp and udp packets...
1565 tx->flags = 0; //NETTXF_csum_blank;
1567 xi->tx.req_prod_pvt++;
1569 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1572 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
1574 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1575 if (notify)
1577 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1578 xi->event_channel);
1582 VOID
1583 XenNet_SendPackets(
1584 IN NDIS_HANDLE MiniportAdapterContext,
1585 IN PPNDIS_PACKET PacketArray,
1586 IN UINT NumberOfPackets
1589 struct xennet_info *xi = MiniportAdapterContext;
1590 PNDIS_PACKET curr_packet;
1591 UINT i;
1592 PMDL pmdl;
1593 PLIST_ENTRY entry;
1595 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1597 for (i = 0; i < NumberOfPackets; i++)
1599 curr_packet = PacketArray[i];
1600 ASSERT(curr_packet);
1602 //KdPrint(("sending pkt, len %d\n", pkt_size));
1604 pmdl = XenNet_Linearize(curr_packet);
1605 if (!pmdl)
1607 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1608 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1609 break;
1612 /* NOTE:
1613 * We use the UCHAR[12] array in each packet's MiniportReservedEx thusly:
1614 * 0-3: PMDL to linearized data
1615 * 4-11: LIST_ENTRY for placing packet on the waiting pkt list
1616 */
1617 *(PMDL *)&curr_packet->MiniportReservedEx = pmdl;
1619 entry = (PLIST_ENTRY)&curr_packet->MiniportReservedEx[4];
1620 ExInterlockedInsertTailList(&xi->tx_waiting_pkt_list, entry, &xi->tx_lock);
1623 XenNet_SendQueuedPackets(xi);
1625 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1628 VOID
1629 XenNet_PnPEventNotify(
1630 IN NDIS_HANDLE MiniportAdapterContext,
1631 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1632 IN PVOID InformationBuffer,
1633 IN ULONG InformationBufferLength
1636 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1637 UNREFERENCED_PARAMETER(PnPEvent);
1638 UNREFERENCED_PARAMETER(InformationBuffer);
1639 UNREFERENCED_PARAMETER(InformationBufferLength);
1641 KdPrint((__FUNCTION__ " called\n"));
1644 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
1645 VOID
1646 XenNet_Shutdown(
1647 IN NDIS_HANDLE MiniportAdapterContext
1650 struct xennet_info *xi = MiniportAdapterContext;
1652 /* turn off interrupt */
1653 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
1654 xi->event_channel);
1656 KdPrint((__FUNCTION__ " called\n"));
1659 /* Opposite of XenNet_Init */
1660 XenNet_Halt(
1661 IN NDIS_HANDLE MiniportAdapterContext
1664 struct xennet_info *xi = MiniportAdapterContext;
1665 CHAR TmpPath[MAX_XENBUS_STR_LEN];
1667 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1668 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1670 XenNet_Shutdown(xi);
1672 // set frontend state to 'closing'
1673 xi->state = XenbusStateClosing;
1674 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1675 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1676 XBT_NIL, TmpPath, "%d", xi->state);
1678 // wait for backend to set 'Closing' state
1680 while (xi->backend_state != XenbusStateClosing)
1681 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1683 // set frontend state to 'closed'
1684 xi->state = XenbusStateClosed;
1685 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1686 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1687 XBT_NIL, TmpPath, "%d", xi->state);
1689 // wait for backend to set 'Closed' state
1690 while (xi->backend_state != XenbusStateClosed)
1691 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1693 xi->connected = FALSE;
1695 // TODO: remove event channel xenbus entry (how?)
1697 /* free TX resources */
1698 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1699 xi->tx_ring_ref);
1700 xi->tx_ring_ref = GRANT_INVALID_REF;
1701 FreePages(xi->tx_mdl);
1702 xi->tx_pgs = NULL;
1703 XenNet_TxBufferFree(xi);
1705 /* free RX resources */
1706 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1707 xi->rx_ring_ref);
1708 xi->rx_ring_ref = GRANT_INVALID_REF;
1709 FreePages(xi->rx_mdl);
1710 xi->rx_pgs = NULL;
1711 XenNet_RxBufferFree(MiniportAdapterContext);
1713 /* Remove watch on backend state */
1714 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
1715 xi->XenInterface.XenBus_RemWatch(xi->XenInterface.InterfaceHeader.Context,
1716 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
1718 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
1720 WdfDriverMiniportUnload(WdfGetDriver());
1722 NdisFreeBufferPool(xi->buffer_pool);
1723 NdisFreePacketPool(xi->packet_pool);
1724 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
1726 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1729 NTSTATUS
1730 DriverEntry(
1731 PDRIVER_OBJECT DriverObject,
1732 PUNICODE_STRING RegistryPath
1735 NTSTATUS status;
1736 WDF_DRIVER_CONFIG config;
1737 NDIS_HANDLE ndis_wrapper_handle;
1738 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1740 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1742 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1743 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1745 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1746 &config, WDF_NO_HANDLE);
1747 if (!NT_SUCCESS(status))
1749 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1750 return status;
1753 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1754 if (!ndis_wrapper_handle)
1756 KdPrint(("NdisMInitializeWrapper failed\n"));
1757 return NDIS_STATUS_FAILURE;
1760 /* NDIS 5.1 driver */
1761 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1762 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1764 mini_chars.HaltHandler = XenNet_Halt;
1765 mini_chars.InitializeHandler = XenNet_Init;
1766 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1767 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1768 mini_chars.ResetHandler = NULL; //TODO: fill in
1769 mini_chars.SetInformationHandler = XenNet_SetInformation;
1770 /* added in v.4 -- use multiple pkts interface */
1771 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1772 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1773 /* added in v.5.1 */
1774 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1775 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1777 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1779 /* set up upper-edge interface */
1780 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1781 if (!NT_SUCCESS(status))
1783 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1784 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1785 return status;
1788 return status;