win-pvdrivers

view xennet/xennet.c @ 133:e5e6978fd09e

Created a macro to avoid warnings when casting int variables to pointers under different arch's
author James Harper <james.harper@bendigoit.com.au>
date Fri Jan 18 20:25:32 2008 +1100 (2008-01-18)
parents 1f482a9da56e
children f3f156c524ee
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 #if defined(_X86_)
45 #define INT_TO_PTR(x) ((PVOID)(LONG)(x))
46 #else
47 #if defined(_AMD64_)
48 #define INT_TO_PTR(x) ((PVOID)(LONGLONG)(x))
49 #endif
50 #endif
52 #pragma warning(disable: 4127) // conditional expression is constant
54 struct xennet_info
55 {
56 /* Base device vars */
57 PDEVICE_OBJECT pdo;
58 PDEVICE_OBJECT fdo;
59 PDEVICE_OBJECT lower_do;
60 WDFDEVICE wdf_device;
61 WCHAR dev_desc[NAME_SIZE];
63 /* NDIS-related vars */
64 NDIS_HANDLE adapter_handle;
65 NDIS_HANDLE packet_pool;
66 NDIS_HANDLE buffer_pool;
67 ULONG packet_filter;
68 int connected;
69 UINT8 perm_mac_addr[ETH_ALEN];
70 UINT8 curr_mac_addr[ETH_ALEN];
72 /* Misc. Xen vars */
73 XEN_IFACE XenInterface;
74 PXENPCI_XEN_DEVICE_DATA pdo_data;
75 evtchn_port_t event_channel;
76 ULONG state;
77 KEVENT backend_state_change_event;
78 KEVENT shutdown_event;
79 char backend_path[MAX_XENBUS_STR_LEN];
80 ULONG backend_state;
82 /* Xen ring-related vars */
83 KSPIN_LOCK rx_lock;
84 KSPIN_LOCK tx_lock;
86 LIST_ENTRY tx_waiting_pkt_list;
87 LIST_ENTRY rx_free_pkt_list;
89 struct netif_tx_front_ring tx;
90 struct netif_rx_front_ring rx;
91 grant_ref_t tx_ring_ref;
92 grant_ref_t rx_ring_ref;
94 /* ptrs to the actual rings themselvves */
95 struct netif_tx_sring *tx_pgs;
96 struct netif_rx_sring *rx_pgs;
98 /* MDLs for the above */
99 PMDL tx_mdl;
100 PMDL rx_mdl;
102 /* Packets given to netback. The first entry in tx_pkts
103 * is an index into a chain of free entries. */
104 int tx_pkt_ids_used;
105 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE+1];
106 PNDIS_BUFFER rx_buffers[NET_RX_RING_SIZE];
108 grant_ref_t gref_tx_head;
109 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE+1];
110 grant_ref_t gref_rx_head;
111 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
113 /* Receive-ring batched refills. */
114 #define RX_MIN_TARGET 8
115 #define RX_DFL_MIN_TARGET 64
116 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
117 ULONG rx_target;
118 ULONG rx_max_target;
119 ULONG rx_min_target;
121 /* how many packets are in the net stack atm */
122 LONG rx_outstanding;
123 LONG tx_outstanding;
125 /* stats */
126 ULONG64 stat_tx_ok;
127 ULONG64 stat_rx_ok;
128 ULONG64 stat_tx_error;
129 ULONG64 stat_rx_error;
130 ULONG64 stat_rx_no_buffer;
131 };
133 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
134 static unsigned long
135 simple_strtoul(const char *cp,char **endp,unsigned int base)
136 {
137 unsigned long result = 0,value;
139 if (!base) {
140 base = 10;
141 if (*cp == '0') {
142 base = 8;
143 cp++;
144 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
145 cp++;
146 base = 16;
147 }
148 }
149 } else if (base == 16) {
150 if (cp[0] == '0' && toupper(cp[1]) == 'X')
151 cp += 2;
152 }
153 while (isxdigit(*cp) &&
154 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
155 result = result*base + value;
156 cp++;
157 }
158 if (endp)
159 *endp = (char *)cp;
160 return result;
161 }
163 static void
164 add_id_to_freelist(struct xennet_info *xi, unsigned short id)
165 {
166 xi->tx_pkts[id] = xi->tx_pkts[0];
167 xi->tx_pkts[0] = INT_TO_PTR(id);
168 xi->tx_pkt_ids_used--;
169 }
171 static unsigned short
172 get_id_from_freelist(struct xennet_info *xi)
173 {
174 unsigned short id;
175 if (xi->tx_pkt_ids_used >= NET_TX_RING_SIZE)
176 return 0;
177 id = (unsigned short)(unsigned long)xi->tx_pkts[0];
178 xi->tx_pkts[0] = xi->tx_pkts[id];
179 xi->tx_pkt_ids_used++;
180 return id;
181 }
183 VOID
184 XenNet_SendQueuedPackets(struct xennet_info *xi);
186 // Called at DISPATCH_LEVEL
187 static NDIS_STATUS
188 XenNet_TxBufferGC(struct xennet_info *xi)
189 {
190 RING_IDX cons, prod;
191 unsigned short id;
192 PNDIS_PACKET pkt;
193 PMDL pmdl;
194 KIRQL OldIrql;
196 ASSERT(xi->connected);
198 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
200 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
202 do {
203 prod = xi->tx.sring->rsp_prod;
204 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
206 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
207 struct netif_tx_response *txrsp;
209 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
210 if (txrsp->status == NETIF_RSP_NULL)
211 continue;
213 id = txrsp->id;
214 pkt = xi->tx_pkts[id];
215 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
216 xi->grant_tx_ref[id]);
217 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
218 add_id_to_freelist(xi, id);
220 /* free linearized data page */
221 pmdl = *(PMDL *)pkt->MiniportReservedEx;
222 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
223 IoFreeMdl(pmdl);
225 InterlockedDecrement(&xi->tx_outstanding);
226 xi->stat_tx_ok++;
227 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
228 }
230 xi->tx.rsp_cons = prod;
232 /*
233 * Set a new event, then check for race with update of tx_cons.
234 * Note that it is essential to schedule a callback, no matter
235 * how few buffers are pending. Even if there is space in the
236 * transmit ring, higher layers may be blocked because too much
237 * data is outstanding: in such cases notification from Xen is
238 * likely to be the only kick that we'll get.
239 */
240 xi->tx.sring->rsp_event =
241 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
242 KeMemoryBarrier();
243 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
245 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
247 /* if queued packets, send them now */
248 XenNet_SendQueuedPackets(xi);
250 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
252 return NDIS_STATUS_SUCCESS;
253 }
255 static void
256 XenNet_TxBufferFree(struct xennet_info *xi)
257 {
258 PNDIS_PACKET packet;
259 PMDL pmdl;
260 PLIST_ENTRY entry;
261 unsigned short id;
263 ASSERT(!xi->connected);
265 /* Free packets in tx queue */
266 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
267 while (entry != &xi->tx_waiting_pkt_list)
268 {
269 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[4]);
271 /* free linearized data page */
272 pmdl = *(PMDL *)packet->MiniportReservedEx;
273 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
274 IoFreeMdl(pmdl);
276 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
278 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
279 }
281 /* free sent-but-not-completed packets */
282 for (id = 1; id < NET_TX_RING_SIZE+1; id++) {
283 if (xi->grant_tx_ref[id] == GRANT_INVALID_REF)
284 continue;
286 packet = xi->tx_pkts[id];
287 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
288 xi->grant_tx_ref[id]);
289 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
290 add_id_to_freelist(xi, id);
292 /* free linearized data page */
293 pmdl = *(PMDL *)packet->MiniportReservedEx;
294 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
295 IoFreeMdl(pmdl);
297 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
298 }
299 }
301 // Called at DISPATCH_LEVEL with no locks held
302 static NDIS_STATUS
303 XenNet_RxBufferAlloc(struct xennet_info *xi)
304 {
305 unsigned short id;
306 PNDIS_BUFFER buffer;
307 int i, batch_target, notify;
308 RING_IDX req_prod = xi->rx.req_prod_pvt;
309 grant_ref_t ref;
310 netif_rx_request_t *req;
311 NDIS_STATUS status;
312 PVOID start;
313 KIRQL OldIrql;
315 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
317 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
319 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
320 for (i = 0; i < batch_target; i++)
321 {
322 /*
323 * Allocate memory and an NDIS_BUFFER.
324 */
325 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
326 if (status != NDIS_STATUS_SUCCESS)
327 {
328 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
329 break;
330 }
331 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
332 ASSERT(status == NDIS_STATUS_SUCCESS); // should never fail
334 /* Give to netback */
335 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
336 ASSERT(!xi->rx_buffers[id]);
337 xi->rx_buffers[id] = buffer;
338 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
339 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
340 ref = xi->XenInterface.GntTbl_GrantAccess(
341 xi->XenInterface.InterfaceHeader.Context, 0,
342 *MmGetMdlPfnArray(buffer), FALSE);
343 ASSERT((signed short)ref >= 0);
344 xi->grant_rx_ref[id] = ref;
346 req->id = id;
347 req->gref = ref;
348 }
350 xi->rx.req_prod_pvt = req_prod + i;
351 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
352 if (notify)
353 {
354 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
355 xi->event_channel);
356 }
358 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
360 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
362 return NDIS_STATUS_SUCCESS;
363 }
365 /* Free all Rx buffers (on halt, for example) */
366 static void
367 XenNet_RxBufferFree(struct xennet_info *xi)
368 {
369 int i;
370 grant_ref_t ref;
371 PNDIS_BUFFER buffer;
372 KIRQL OldIrql;
374 ASSERT(!xi->connected);
376 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
378 for (i = 0; i < NET_RX_RING_SIZE; i++)
379 {
380 if (!xi->rx_buffers[i])
381 continue;
383 buffer = xi->rx_buffers[i];
384 ref = xi->grant_rx_ref[i];
386 /* don't check return, what can we do about it on failure? */
387 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context, ref);
389 NdisFreeMemory(NdisBufferVirtualAddressSafe(buffer, NormalPagePriority), 0, 0);
390 NdisFreeBuffer(buffer);
391 }
393 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
394 }
396 VOID
397 XenNet_ReturnPacket(
398 IN NDIS_HANDLE MiniportAdapterContext,
399 IN PNDIS_PACKET Packet
400 )
401 {
402 struct xennet_info *xi = MiniportAdapterContext;
403 PNDIS_BUFFER buffer;
404 PNDIS_BUFFER next_buffer;
405 PVOID buff_va;
406 UINT buff_len;
407 UINT tot_buff_len;
409 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
411 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
412 &tot_buff_len, NormalPagePriority);
413 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
414 ASSERT(buff_va != NULL);
416 while (buffer)
417 {
418 NdisGetNextBuffer(buffer, &next_buffer);
419 NdisFreeMemory(NdisBufferVirtualAddressSafe(buffer, NormalPagePriority), 0, 0);
420 NdisFreeBuffer(buffer);
421 buffer = next_buffer;
422 }
424 NdisFreePacket(Packet);
426 InterlockedDecrement(&xi->rx_outstanding);
428 // if we are no longer connected then _halt probably needs to know when rx_outstanding reaches zero
429 if (!xi->connected && !xi->rx_outstanding)
430 KeSetEvent(&xi->shutdown_event, 1, FALSE);
432 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
433 }
435 // Called at DISPATCH_LEVEL
436 static NDIS_STATUS
437 XenNet_RxBufferCheck(struct xennet_info *xi)
438 {
439 RING_IDX cons, prod;
441 PNDIS_PACKET packet = NULL;
442 PNDIS_BUFFER buffer;
443 int moretodo;
444 KIRQL OldIrql;
445 struct netif_rx_response *rxrsp = NULL;
446 int more_frags = 0;
447 NDIS_STATUS status;
449 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
451 ASSERT(xi->connected);
453 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
455 do {
456 prod = xi->rx.sring->rsp_prod;
457 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
459 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
460 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
461 ASSERT(rxrsp->status > 0);
463 if (!more_frags) // handling the packet's 1st buffer
464 {
465 // KdPrint((__DRIVER_NAME " Got a packet\n"));
466 NdisAllocatePacket(&status, &packet, xi->packet_pool);
467 ASSERT(status == NDIS_STATUS_SUCCESS);
468 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
469 }
471 buffer = xi->rx_buffers[rxrsp->id];
472 xi->rx_buffers[rxrsp->id] = NULL;
473 NdisAdjustBufferLength(buffer, rxrsp->status);
474 NdisChainBufferAtBack(packet, buffer);
476 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
477 xi->grant_rx_ref[rxrsp->id]);
478 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
480 #if 0
481 KdPrint((__DRIVER_NAME " Flags = %sNETRXF_data_validated|%sNETRXF_csum_blank|%sNETRXF_more_data|%sNETRXF_extra_info\n",
482 (rxrsp->flags&NETRXF_data_validated)?"":"!",
483 (rxrsp->flags&NETRXF_csum_blank)?"":"!",
484 (rxrsp->flags&NETRXF_more_data)?"":"!",
485 (rxrsp->flags&NETRXF_extra_info)?"":"!"));
486 #endif
487 ASSERT(!(rxrsp->flags & NETRXF_extra_info)); // not used on RX
489 more_frags = rxrsp->flags & NETRXF_more_data;
491 /* Packet done, pass it up */
492 if (!more_frags)
493 {
494 xi->stat_rx_ok++;
495 InterlockedIncrement(&xi->rx_outstanding);
496 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
497 NdisMIndicateReceivePacket(xi->adapter_handle, &packet, 1);
498 }
499 }
500 xi->rx.rsp_cons = prod;
502 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
503 } while (moretodo);
505 if (more_frags)
506 {
507 KdPrint((__DRIVER_NAME " Missing fragments\n"));
508 XenNet_ReturnPacket(xi, packet);
509 }
511 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
513 /* Give netback more buffers */
514 XenNet_RxBufferAlloc(xi);
516 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
518 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
520 return NDIS_STATUS_SUCCESS;
521 }
523 // Called at DISPATCH_LEVEL
524 static BOOLEAN
525 XenNet_Interrupt(
526 PKINTERRUPT Interrupt,
527 PVOID ServiceContext
528 )
529 {
530 struct xennet_info *xi = ServiceContext;
532 UNREFERENCED_PARAMETER(Interrupt);
534 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
536 if (xi->connected)
537 {
538 XenNet_TxBufferGC(xi);
539 XenNet_RxBufferCheck(xi);
540 }
542 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
544 return TRUE;
545 }
547 // Called at <= DISPATCH_LEVEL
549 static VOID
550 XenNet_BackEndStateHandler(char *Path, PVOID Data)
551 {
552 struct xennet_info *xi = Data;
553 char *Value;
554 char TmpPath[MAX_XENBUS_STR_LEN];
555 xenbus_transaction_t xbt = 0;
556 int retry = 0;
557 char *err;
558 int i;
559 ULONG new_backend_state;
561 struct set_params {
562 char *name;
563 int value;
564 } params[] = {
565 {"tx-ring-ref", 0},
566 {"rx-ring-ref", 0},
567 {"event-channel", 0},
568 {"request-rx-copy", 1},
569 {"feature-rx-notify", 1},
570 {"feature-no-csum-offload", 1},
571 {"feature-sg", 1},
572 {"feature-gso-tcpv4", 0},
573 {NULL, 0},
574 };
576 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
577 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
579 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
580 XBT_NIL, Path, &Value);
581 new_backend_state = atoi(Value);
582 xi->XenInterface.FreeMem(Value);
584 if (xi->backend_state == new_backend_state)
585 {
586 KdPrint((__DRIVER_NAME " state unchanged\n"));
587 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
588 return;
589 }
591 xi->backend_state = new_backend_state;
593 switch (xi->backend_state)
594 {
595 case XenbusStateUnknown:
596 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
597 break;
599 case XenbusStateInitialising:
600 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
601 break;
603 case XenbusStateInitWait:
604 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
606 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
607 xi->XenInterface.InterfaceHeader.Context, 0);
608 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
609 xi->event_channel, XenNet_Interrupt, xi);
611 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
612 // or, allocate mem and then get mdl, then free mdl
613 xi->tx_mdl = AllocatePage();
614 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl);
615 SHARED_RING_INIT(xi->tx_pgs);
616 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
617 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
618 xi->XenInterface.InterfaceHeader.Context, 0,
619 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
621 xi->rx_mdl = AllocatePage();
622 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl);
623 SHARED_RING_INIT(xi->rx_pgs);
624 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
625 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
626 xi->XenInterface.InterfaceHeader.Context, 0,
627 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
629 /* fixup array for dynamic values */
630 params[0].value = xi->tx_ring_ref;
631 params[1].value = xi->rx_ring_ref;
632 params[2].value = xi->event_channel;
634 xi->XenInterface.XenBus_StartTransaction(
635 xi->XenInterface.InterfaceHeader.Context, &xbt);
637 for (i = 0; params[i].name; i++)
638 {
639 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
640 xi->pdo_data->Path, params[i].name);
641 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
642 XBT_NIL, TmpPath, "%d", params[i].value);
643 if (err)
644 {
645 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
646 goto trouble;
647 }
648 }
650 /* commit transaction */
651 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
652 xbt, 0, &retry);
654 XenNet_RxBufferAlloc(xi);
656 xi->state = XenbusStateConnected;
657 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
658 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
659 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
660 XBT_NIL, TmpPath, "%d", xi->state);
662 /* send fake arp? */
664 xi->connected = TRUE;
666 break;
668 case XenbusStateInitialised:
669 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
670 break;
672 case XenbusStateConnected:
673 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
674 break;
676 case XenbusStateClosing:
677 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
678 break;
680 case XenbusStateClosed:
681 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
682 break;
684 default:
685 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
686 break;
687 }
689 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
691 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
693 return;
695 trouble:
696 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
697 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
698 xbt, 1, &retry);
699 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
700 }
702 static NDIS_STATUS
703 XenNet_Init(
704 OUT PNDIS_STATUS OpenErrorStatus,
705 OUT PUINT SelectedMediumIndex,
706 IN PNDIS_MEDIUM MediumArray,
707 IN UINT MediumArraySize,
708 IN NDIS_HANDLE MiniportAdapterHandle,
709 IN NDIS_HANDLE WrapperConfigurationContext
710 )
711 {
712 NDIS_STATUS status;
713 UINT i;
714 BOOLEAN medium_found = FALSE;
715 struct xennet_info *xi = NULL;
716 ULONG length;
717 WDF_OBJECT_ATTRIBUTES wdf_attrs;
718 char *res;
719 char *Value;
720 char TmpPath[MAX_XENBUS_STR_LEN];
722 UNREFERENCED_PARAMETER(OpenErrorStatus);
723 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
725 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
726 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
728 /* deal with medium stuff */
729 for (i = 0; i < MediumArraySize; i++)
730 {
731 if (MediumArray[i] == NdisMedium802_3)
732 {
733 medium_found = TRUE;
734 break;
735 }
736 }
737 if (!medium_found)
738 {
739 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
740 return NDIS_STATUS_UNSUPPORTED_MEDIA;
741 }
742 *SelectedMediumIndex = i;
744 /* Alloc memory for adapter private info */
745 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
746 if (!NT_SUCCESS(status))
747 {
748 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
749 status = NDIS_STATUS_RESOURCES;
750 goto err;
751 }
752 RtlZeroMemory(xi, sizeof(*xi));
754 /* init xennet_info */
755 xi->adapter_handle = MiniportAdapterHandle;
756 xi->rx_target = RX_DFL_MIN_TARGET;
757 xi->rx_min_target = RX_DFL_MIN_TARGET;
758 xi->rx_max_target = RX_MAX_TARGET;
760 xi->state = XenbusStateUnknown;
761 xi->backend_state = XenbusStateUnknown;
763 KeInitializeSpinLock(&xi->tx_lock);
764 KeInitializeSpinLock(&xi->rx_lock);
765 InitializeListHead(&xi->rx_free_pkt_list);
766 InitializeListHead(&xi->tx_waiting_pkt_list);
769 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
770 PROTOCOL_RESERVED_SIZE_IN_PACKET);
771 if (status != NDIS_STATUS_SUCCESS)
772 {
773 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
774 status = NDIS_STATUS_RESOURCES;
775 goto err;
776 }
777 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
779 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
780 if (status != NDIS_STATUS_SUCCESS)
781 {
782 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
783 status = NDIS_STATUS_RESOURCES;
784 goto err;
785 }
787 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
788 &xi->lower_do, NULL, NULL);
789 xi->pdo_data = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
791 /* Initialize tx_pkts as a free chain containing every entry. */
792 for (i = 0; i < NET_TX_RING_SIZE+1; i++) {
793 xi->tx_pkts[i] = INT_TO_PTR(i + 1);
794 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
795 }
797 for (i = 0; i < NET_RX_RING_SIZE; i++) {
798 xi->rx_buffers[i] = NULL;
799 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
800 }
802 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
804 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
805 NAME_SIZE, xi->dev_desc, &length);
806 if (!NT_SUCCESS(status))
807 {
808 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
809 status = NDIS_STATUS_FAILURE;
810 goto err;
811 }
813 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
814 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
815 NdisInterfaceInternal);
817 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
819 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
820 xi->lower_do, xi->pdo, &xi->wdf_device);
821 if (!NT_SUCCESS(status))
822 {
823 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
824 status = NDIS_STATUS_FAILURE;
825 goto err;
826 }
828 /* get lower (Xen) interfaces */
830 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
831 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
832 if(!NT_SUCCESS(status))
833 {
834 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
835 status = NDIS_STATUS_FAILURE;
836 goto err;
837 }
839 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
840 "%s/backend", xi->pdo_data->Path);
841 KdPrint(("About to read %s to get backend path\n", TmpPath));
842 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
843 XBT_NIL, TmpPath, &Value);
844 if (res)
845 {
846 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
847 xi->XenInterface.FreeMem(res);
848 status = NDIS_STATUS_FAILURE;
849 goto err;
850 }
851 RtlStringCbCopyA(xi->backend_path, ARRAY_SIZE(xi->backend_path), Value);
852 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->backend_path));
854 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/type", xi->backend_path);
855 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
856 XBT_NIL, TmpPath, &Value);
858 #if 0
859 if (res || strcmp(Value, "netfront") != 0)
860 {
861 KdPrint((__DRIVER_NAME " Backend type is not 'netfront'\n"));
862 status = NDIS_STATUS_FAILURE;
863 goto err;
864 }
865 #endif
867 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
868 KeInitializeEvent(&xi->shutdown_event, SynchronizationEvent, FALSE);
870 /* Add watch on backend state */
871 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
872 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
873 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
875 /* Tell backend we're coming up */
876 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
877 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
878 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
880 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
882 // wait here for signal that we are all set up
883 while (xi->backend_state != XenbusStateConnected)
884 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
886 KdPrint((__DRIVER_NAME " Connected\n"));
888 /* get mac address */
889 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->backend_path);
890 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
891 XBT_NIL, TmpPath, &Value);
892 if (!Value)
893 {
894 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
895 status = NDIS_STATUS_FAILURE;
896 goto err;
897 }
898 else
899 {
900 char *s, *e;
901 s = Value;
902 for (i = 0; i < ETH_ALEN; i++) {
903 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
904 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
905 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
906 xi->XenInterface.FreeMem(Value);
907 status = NDIS_STATUS_FAILURE;
908 goto err;
909 }
910 s = e + 1;
911 }
912 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
913 xi->XenInterface.FreeMem(Value);
914 }
916 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
918 return NDIS_STATUS_SUCCESS;
920 err:
921 NdisFreeMemory(xi, 0, 0);
922 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
923 return status;
924 }
926 // Q = Query Mandatory, S = Set Mandatory
927 NDIS_OID supported_oids[] =
928 {
929 /* general OIDs */
930 OID_GEN_SUPPORTED_LIST, // Q
931 OID_GEN_HARDWARE_STATUS, // Q
932 OID_GEN_MEDIA_SUPPORTED, // Q
933 OID_GEN_MEDIA_IN_USE, // Q
934 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
935 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
936 OID_GEN_LINK_SPEED, // Q
937 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
938 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
939 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
940 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
941 OID_GEN_VENDOR_ID, // Q
942 OID_GEN_VENDOR_DESCRIPTION, // Q
943 OID_GEN_CURRENT_PACKET_FILTER, // QS
944 OID_GEN_CURRENT_LOOKAHEAD, // QS
945 OID_GEN_DRIVER_VERSION, // Q
946 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
947 OID_GEN_PROTOCOL_OPTIONS, // S
948 OID_GEN_MAC_OPTIONS, // Q
949 OID_GEN_MEDIA_CONNECT_STATUS, // Q
950 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
951 /* stats */
952 OID_GEN_XMIT_OK, // Q
953 OID_GEN_RCV_OK, // Q
954 OID_GEN_XMIT_ERROR, // Q
955 OID_GEN_RCV_ERROR, // Q
956 OID_GEN_RCV_NO_BUFFER, // Q
957 /* media-specific OIDs */
958 OID_802_3_PERMANENT_ADDRESS,
959 OID_802_3_CURRENT_ADDRESS,
960 OID_802_3_MULTICAST_LIST,
961 OID_802_3_MAXIMUM_LIST_SIZE,
962 /* tcp offload */
963 OID_TCP_TASK_OFFLOAD,
964 };
966 /* return 4 or 8 depending on size of buffer */
967 #define HANDLE_STAT_RETURN \
968 {if (InformationBufferLength == 4) { \
969 len = 4; *BytesNeeded = 8; \
970 } else { \
971 len = 8; \
972 } }
974 //#define OFFLOAD_LARGE_SEND
976 NDIS_STATUS
977 XenNet_QueryInformation(
978 IN NDIS_HANDLE MiniportAdapterContext,
979 IN NDIS_OID Oid,
980 IN PVOID InformationBuffer,
981 IN ULONG InformationBufferLength,
982 OUT PULONG BytesWritten,
983 OUT PULONG BytesNeeded)
984 {
985 struct xennet_info *xi = MiniportAdapterContext;
986 UCHAR vendor_desc[] = XN_VENDOR_DESC;
987 ULONG64 temp_data;
988 PVOID data = &temp_data;
989 UINT len = 4;
990 BOOLEAN used_temp_buffer = TRUE;
991 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
992 PNDIS_TASK_OFFLOAD_HEADER ntoh;
993 PNDIS_TASK_OFFLOAD nto;
994 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
995 #ifdef OFFLOAD_LARGE_SEND
996 PNDIS_TASK_TCP_LARGE_SEND nttls;
997 #endif
999 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1001 switch(Oid)
1003 case OID_GEN_SUPPORTED_LIST:
1004 data = supported_oids;
1005 len = sizeof(supported_oids);
1006 break;
1007 case OID_GEN_HARDWARE_STATUS:
1008 if (!xi->connected)
1009 temp_data = NdisHardwareStatusInitializing;
1010 else
1011 temp_data = NdisHardwareStatusReady;
1012 break;
1013 case OID_GEN_MEDIA_SUPPORTED:
1014 temp_data = NdisMedium802_3;
1015 break;
1016 case OID_GEN_MEDIA_IN_USE:
1017 temp_data = NdisMedium802_3;
1018 break;
1019 case OID_GEN_MAXIMUM_LOOKAHEAD:
1020 temp_data = XN_DATA_SIZE;
1021 break;
1022 case OID_GEN_MAXIMUM_FRAME_SIZE:
1023 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
1024 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
1025 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
1026 break;
1027 case OID_GEN_LINK_SPEED:
1028 temp_data = 10000000; /* 1Gb */
1029 break;
1030 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1031 /* pkts times sizeof ring, maybe? */
1032 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
1033 break;
1034 case OID_GEN_RECEIVE_BUFFER_SPACE:
1035 /* pkts times sizeof ring, maybe? */
1036 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
1037 break;
1038 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1039 temp_data = XN_MAX_PKT_SIZE;
1040 break;
1041 case OID_GEN_RECEIVE_BLOCK_SIZE:
1042 temp_data = XN_MAX_PKT_SIZE;
1043 break;
1044 case OID_GEN_VENDOR_ID:
1045 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
1046 break;
1047 case OID_GEN_VENDOR_DESCRIPTION:
1048 data = vendor_desc;
1049 len = sizeof(vendor_desc);
1050 break;
1051 case OID_GEN_CURRENT_PACKET_FILTER:
1052 temp_data = xi->packet_filter;
1053 break;
1054 case OID_GEN_CURRENT_LOOKAHEAD:
1055 // TODO: we should store this...
1056 temp_data = XN_MAX_PKT_SIZE;
1057 break;
1058 case OID_GEN_DRIVER_VERSION:
1059 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
1060 len = 2;
1061 break;
1062 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1063 temp_data = XN_MAX_PKT_SIZE;
1064 break;
1065 case OID_GEN_MAC_OPTIONS:
1066 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1067 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1068 NDIS_MAC_OPTION_NO_LOOPBACK;
1069 break;
1070 case OID_GEN_MEDIA_CONNECT_STATUS:
1071 if (xi->connected)
1072 temp_data = NdisMediaStateConnected;
1073 else
1074 temp_data = NdisMediaStateDisconnected;
1075 break;
1076 case OID_GEN_MAXIMUM_SEND_PACKETS:
1077 temp_data = XN_MAX_SEND_PKTS;
1078 break;
1079 case OID_GEN_XMIT_OK:
1080 temp_data = xi->stat_tx_ok;
1081 HANDLE_STAT_RETURN;
1082 break;
1083 case OID_GEN_RCV_OK:
1084 temp_data = xi->stat_rx_ok;
1085 HANDLE_STAT_RETURN;
1086 break;
1087 case OID_GEN_XMIT_ERROR:
1088 temp_data = xi->stat_tx_error;
1089 HANDLE_STAT_RETURN;
1090 break;
1091 case OID_GEN_RCV_ERROR:
1092 temp_data = xi->stat_rx_error;
1093 HANDLE_STAT_RETURN;
1094 break;
1095 case OID_GEN_RCV_NO_BUFFER:
1096 temp_data = xi->stat_rx_no_buffer;
1097 HANDLE_STAT_RETURN;
1098 break;
1099 case OID_802_3_PERMANENT_ADDRESS:
1100 data = xi->perm_mac_addr;
1101 len = ETH_ALEN;
1102 break;
1103 case OID_802_3_CURRENT_ADDRESS:
1104 data = xi->curr_mac_addr;
1105 len = ETH_ALEN;
1106 break;
1107 case OID_802_3_MULTICAST_LIST:
1108 data = NULL;
1109 len = 0;
1110 case OID_802_3_MAXIMUM_LIST_SIZE:
1111 temp_data = 0; /* no mcast support */
1112 break;
1113 case OID_TCP_TASK_OFFLOAD:
1114 KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
1115 /* it's times like this that C really sucks */
1117 len = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1119 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1120 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1121 #ifdef OFFLOAD_LARGE_SEND
1122 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1123 + sizeof(NDIS_TASK_TCP_LARGE_SEND);
1124 #endif
1126 if (len > InformationBufferLength)
1128 break;
1131 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1132 ASSERT(ntoh->Version == NDIS_TASK_OFFLOAD_VERSION);
1133 ASSERT(ntoh->Size == sizeof(*ntoh));
1134 ASSERT(ntoh->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation);
1135 ntoh->OffsetFirstTask = ntoh->Size;
1137 /* fill in first nto */
1138 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
1139 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1140 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1141 nto->Task = TcpIpChecksumNdisTask;
1142 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1144 /* fill in checksum offload struct */
1145 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1146 nttic->V4Transmit.IpOptionsSupported = 0;
1147 nttic->V4Transmit.TcpOptionsSupported = 0;
1148 nttic->V4Transmit.TcpChecksum = 0;
1149 nttic->V4Transmit.UdpChecksum = 0;
1150 nttic->V4Transmit.IpChecksum = 0;
1151 nttic->V4Receive.IpOptionsSupported = 1;
1152 nttic->V4Receive.TcpOptionsSupported = 1;
1153 nttic->V4Receive.TcpChecksum = 1;
1154 nttic->V4Receive.UdpChecksum = 1;
1155 nttic->V4Receive.IpChecksum = 1;
1156 nttic->V6Transmit.IpOptionsSupported = 0;
1157 nttic->V6Transmit.TcpOptionsSupported = 0;
1158 nttic->V6Transmit.TcpChecksum = 0;
1159 nttic->V6Transmit.UdpChecksum = 0;
1160 nttic->V6Receive.IpOptionsSupported = 0;
1161 nttic->V6Receive.TcpOptionsSupported = 0;
1162 nttic->V6Receive.TcpChecksum = 0;
1163 nttic->V6Receive.UdpChecksum = 0;
1165 #ifdef OFFLOAD_LARGE_SEND
1166 /* offset from start of current NTO to start of next NTO */
1167 nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1168 + nto->TaskBufferLength;
1170 /* fill in second nto */
1171 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
1172 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1173 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1174 nto->Task = TcpLargeSendNdisTask;
1175 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
1177 /* fill in large send struct */
1178 nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
1179 nttls->Version = 0;
1180 nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
1181 nttls->MinSegmentCount = 4; /* also made up */
1182 nttls->TcpOptions = FALSE;
1183 nttls->IpOptions = FALSE;
1184 #endif
1185 nto->OffsetNextTask = 0; /* last one */
1187 used_temp_buffer = FALSE;
1188 break;
1189 default:
1190 KdPrint(("Get Unknown OID 0x%x\n", Oid));
1191 status = NDIS_STATUS_NOT_SUPPORTED;
1194 if (!NT_SUCCESS(status))
1196 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
1197 return status;
1200 if (len > InformationBufferLength)
1202 *BytesNeeded = len;
1203 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (BUFFER_TOO_SHORT)\n"));
1204 return NDIS_STATUS_BUFFER_TOO_SHORT;
1207 *BytesWritten = len;
1208 if (len && used_temp_buffer)
1210 NdisMoveMemory((PUCHAR)InformationBuffer, data, len);
1213 //KdPrint(("Got OID 0x%x\n", Oid));
1214 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1216 return status;
1219 NDIS_STATUS
1220 XenNet_SetInformation(
1221 IN NDIS_HANDLE MiniportAdapterContext,
1222 IN NDIS_OID Oid,
1223 IN PVOID InformationBuffer,
1224 IN ULONG InformationBufferLength,
1225 OUT PULONG BytesRead,
1226 OUT PULONG BytesNeeded
1229 NTSTATUS status;
1230 struct xennet_info *xi = MiniportAdapterContext;
1231 PULONG64 data = InformationBuffer;
1232 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1233 PNDIS_TASK_OFFLOAD nto;
1234 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1235 int offset;
1237 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1239 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1240 UNREFERENCED_PARAMETER(InformationBufferLength);
1241 UNREFERENCED_PARAMETER(BytesRead);
1242 UNREFERENCED_PARAMETER(BytesNeeded);
1244 switch(Oid)
1246 case OID_GEN_SUPPORTED_LIST:
1247 status = NDIS_STATUS_NOT_SUPPORTED;
1248 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1249 break;
1250 case OID_GEN_HARDWARE_STATUS:
1251 status = NDIS_STATUS_NOT_SUPPORTED;
1252 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1253 break;
1254 case OID_GEN_MEDIA_SUPPORTED:
1255 status = NDIS_STATUS_NOT_SUPPORTED;
1256 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1257 break;
1258 case OID_GEN_MEDIA_IN_USE:
1259 status = NDIS_STATUS_NOT_SUPPORTED;
1260 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1261 break;
1262 case OID_GEN_MAXIMUM_LOOKAHEAD:
1263 status = NDIS_STATUS_NOT_SUPPORTED;
1264 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1265 break;
1266 case OID_GEN_MAXIMUM_FRAME_SIZE:
1267 status = NDIS_STATUS_NOT_SUPPORTED;
1268 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1269 break;
1270 case OID_GEN_LINK_SPEED:
1271 status = NDIS_STATUS_NOT_SUPPORTED;
1272 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1273 break;
1274 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1275 status = NDIS_STATUS_NOT_SUPPORTED;
1276 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1277 break;
1278 case OID_GEN_RECEIVE_BUFFER_SPACE:
1279 status = NDIS_STATUS_NOT_SUPPORTED;
1280 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1281 break;
1282 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1283 status = NDIS_STATUS_NOT_SUPPORTED;
1284 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1285 break;
1286 case OID_GEN_RECEIVE_BLOCK_SIZE:
1287 status = NDIS_STATUS_NOT_SUPPORTED;
1288 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1289 break;
1290 case OID_GEN_VENDOR_ID:
1291 status = NDIS_STATUS_NOT_SUPPORTED;
1292 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1293 break;
1294 case OID_GEN_VENDOR_DESCRIPTION:
1295 status = NDIS_STATUS_NOT_SUPPORTED;
1296 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1297 break;
1298 case OID_GEN_CURRENT_PACKET_FILTER:
1299 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1300 xi->packet_filter = *(ULONG *)data;
1301 status = NDIS_STATUS_SUCCESS;
1302 break;
1303 case OID_GEN_CURRENT_LOOKAHEAD:
1304 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1305 // TODO: We should do this...
1306 status = NDIS_STATUS_SUCCESS;
1307 break;
1308 case OID_GEN_DRIVER_VERSION:
1309 status = NDIS_STATUS_NOT_SUPPORTED;
1310 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1311 break;
1312 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1313 status = NDIS_STATUS_NOT_SUPPORTED;
1314 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1315 break;
1316 case OID_GEN_PROTOCOL_OPTIONS:
1317 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1318 // TODO - actually do this...
1319 status = NDIS_STATUS_SUCCESS;
1320 break;
1321 case OID_GEN_MAC_OPTIONS:
1322 status = NDIS_STATUS_NOT_SUPPORTED;
1323 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1324 break;
1325 case OID_GEN_MEDIA_CONNECT_STATUS:
1326 status = NDIS_STATUS_NOT_SUPPORTED;
1327 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1328 break;
1329 case OID_GEN_MAXIMUM_SEND_PACKETS:
1330 status = NDIS_STATUS_NOT_SUPPORTED;
1331 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1332 break;
1333 case OID_GEN_XMIT_OK:
1334 status = NDIS_STATUS_NOT_SUPPORTED;
1335 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1336 break;
1337 case OID_GEN_RCV_OK:
1338 status = NDIS_STATUS_NOT_SUPPORTED;
1339 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1340 break;
1341 case OID_GEN_XMIT_ERROR:
1342 status = NDIS_STATUS_NOT_SUPPORTED;
1343 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1344 break;
1345 case OID_GEN_RCV_ERROR:
1346 status = NDIS_STATUS_NOT_SUPPORTED;
1347 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1348 break;
1349 case OID_GEN_RCV_NO_BUFFER:
1350 status = NDIS_STATUS_NOT_SUPPORTED;
1351 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1352 break;
1353 case OID_802_3_PERMANENT_ADDRESS:
1354 status = NDIS_STATUS_NOT_SUPPORTED;
1355 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1356 break;
1357 case OID_802_3_CURRENT_ADDRESS:
1358 status = NDIS_STATUS_NOT_SUPPORTED;
1359 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1360 break;
1361 case OID_802_3_MULTICAST_LIST:
1362 status = NDIS_STATUS_NOT_SUPPORTED;
1363 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1364 break;
1365 case OID_802_3_MAXIMUM_LIST_SIZE:
1366 status = NDIS_STATUS_NOT_SUPPORTED;
1367 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1368 break;
1369 case OID_TCP_TASK_OFFLOAD:
1370 // Just fake this for now... ultimately we need to manually calc rx checksum if offload is disabled by windows
1371 status = NDIS_STATUS_SUCCESS;
1372 KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
1373 // we should disable everything here, then enable what has been set
1374 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1375 *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1376 offset = ntoh->OffsetFirstTask;
1377 nto = (PNDIS_TASK_OFFLOAD)ntoh; // not really, just to get the first offset right
1378 while (offset != 0)
1380 *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
1381 nto = (PNDIS_TASK_OFFLOAD)(((PUCHAR)nto) + offset);
1382 switch (nto->Task)
1384 case TcpIpChecksumNdisTask:
1385 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1386 KdPrint(("TcpIpChecksumNdisTask\n"));
1387 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1388 KdPrint((" V4Transmit.IpOptionsSupported = %d\n", nttic->V4Transmit.IpOptionsSupported));
1389 KdPrint((" V4Transmit.TcpOptionsSupported = %d\n", nttic->V4Transmit.TcpOptionsSupported));
1390 KdPrint((" V4Transmit.TcpChecksum = %d\n", nttic->V4Transmit.TcpChecksum));
1391 KdPrint((" V4Transmit.UdpChecksum = %d\n", nttic->V4Transmit.UdpChecksum));
1392 KdPrint((" V4Transmit.IpChecksum = %d\n", nttic->V4Transmit.IpChecksum));
1393 KdPrint((" V4Receive.IpOptionsSupported = %d\n", nttic->V4Receive.IpOptionsSupported));
1394 KdPrint((" V4Receive.TcpOptionsSupported = %d\n", nttic->V4Receive.TcpOptionsSupported));
1395 KdPrint((" V4Receive.TcpChecksum = %d\n", nttic->V4Receive.TcpChecksum));
1396 KdPrint((" V4Receive.UdpChecksum = %d\n", nttic->V4Receive.UdpChecksum));
1397 KdPrint((" V4Receive.IpChecksum = %d\n", nttic->V4Receive.IpChecksum));
1398 KdPrint((" V6Transmit.IpOptionsSupported = %d\n", nttic->V6Transmit.IpOptionsSupported));
1399 KdPrint((" V6Transmit.TcpOptionsSupported = %d\n", nttic->V6Transmit.TcpOptionsSupported));
1400 KdPrint((" V6Transmit.TcpChecksum = %d\n", nttic->V6Transmit.TcpChecksum));
1401 KdPrint((" V6Transmit.UdpChecksum = %d\n", nttic->V6Transmit.UdpChecksum));
1402 KdPrint((" V6Receive.IpOptionsSupported = %d\n", nttic->V6Receive.IpOptionsSupported));
1403 KdPrint((" V6Receive.TcpOptionsSupported = %d\n", nttic->V6Receive.TcpOptionsSupported));
1404 KdPrint((" V6Receive.TcpChecksum = %d\n", nttic->V6Receive.TcpChecksum));
1405 KdPrint((" V6Receive.UdpChecksum = %d\n", nttic->V6Receive.UdpChecksum));
1406 break;
1407 default:
1408 KdPrint((" Unknown Task %d\n", nto->Task));
1410 offset = nto->OffsetNextTask;
1412 break;
1413 default:
1414 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1415 status = NDIS_STATUS_NOT_SUPPORTED;
1416 break;
1418 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1419 return status;
1422 PMDL
1423 XenNet_Linearize(PNDIS_PACKET Packet)
1425 NDIS_STATUS status;
1426 PMDL pmdl;
1427 char *start;
1428 PNDIS_BUFFER buffer;
1429 PVOID buff_va;
1430 UINT buff_len;
1431 UINT tot_buff_len;
1433 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1435 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1436 &tot_buff_len, NormalPagePriority);
1437 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1439 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1440 if (!NT_SUCCESS(status))
1442 KdPrint(("Could not allocate memory for linearization\n"));
1443 return NULL;
1445 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1446 if (!pmdl)
1448 KdPrint(("Could not allocate MDL for linearization\n"));
1449 NdisFreeMemory(start, 0, 0);
1450 return NULL;
1452 MmBuildMdlForNonPagedPool(pmdl);
1454 while (buffer)
1456 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1457 RtlCopyMemory(start, buff_va, buff_len);
1458 start += buff_len;
1459 NdisGetNextBuffer(buffer, &buffer);
1462 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1463 return pmdl;
1466 VOID
1467 XenNet_SendQueuedPackets(struct xennet_info *xi)
1469 PLIST_ENTRY entry;
1470 PNDIS_PACKET packet;
1471 KIRQL OldIrql;
1472 struct netif_tx_request *tx;
1473 unsigned short id;
1474 int notify;
1475 PMDL pmdl;
1476 UINT pkt_size;
1478 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
1480 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1481 /* if empty, the above returns head*, not NULL */
1482 while (entry != &xi->tx_waiting_pkt_list)
1484 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[4]);
1486 NdisQueryPacket(packet, NULL, NULL, NULL, &pkt_size);
1487 pmdl = *(PMDL *)packet->MiniportReservedEx;
1489 id = get_id_from_freelist(xi);
1490 if (!id)
1492 /* whups, out of space on the ring. requeue and get out */
1493 InsertHeadList(&xi->tx_waiting_pkt_list, entry);
1494 break;
1496 xi->tx_pkts[id] = packet;
1498 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1499 tx->id = id;
1500 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1501 xi->XenInterface.InterfaceHeader.Context,
1502 0,
1503 *MmGetMdlPfnArray(pmdl),
1504 TRUE);
1505 xi->grant_tx_ref[id] = tx->gref;
1506 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1507 tx->size = (UINT16)pkt_size;
1508 // NETTXF_csum_blank should only be used for tcp and udp packets...
1509 tx->flags = 0; //NETTXF_csum_blank;
1511 xi->tx.req_prod_pvt++;
1513 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1516 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
1518 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1519 if (notify)
1521 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1522 xi->event_channel);
1526 VOID
1527 XenNet_SendPackets(
1528 IN NDIS_HANDLE MiniportAdapterContext,
1529 IN PPNDIS_PACKET PacketArray,
1530 IN UINT NumberOfPackets
1533 struct xennet_info *xi = MiniportAdapterContext;
1534 PNDIS_PACKET curr_packet;
1535 UINT i;
1536 PMDL pmdl;
1537 PLIST_ENTRY entry;
1539 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1541 for (i = 0; i < NumberOfPackets; i++)
1543 curr_packet = PacketArray[i];
1544 ASSERT(curr_packet);
1546 //KdPrint(("sending pkt, len %d\n", pkt_size));
1548 pmdl = XenNet_Linearize(curr_packet);
1549 if (!pmdl)
1551 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1552 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1553 break;
1556 /* NOTE:
1557 * We use the UCHAR[12] array in each packet's MiniportReservedEx thusly:
1558 * 0-3: PMDL to linearized data
1559 * 4-11: LIST_ENTRY for placing packet on the waiting pkt list
1560 */
1561 *(PMDL *)&curr_packet->MiniportReservedEx = pmdl;
1563 entry = (PLIST_ENTRY)&curr_packet->MiniportReservedEx[4];
1564 ExInterlockedInsertTailList(&xi->tx_waiting_pkt_list, entry, &xi->tx_lock);
1565 InterlockedIncrement(&xi->tx_outstanding);
1568 XenNet_SendQueuedPackets(xi);
1570 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1573 VOID
1574 XenNet_PnPEventNotify(
1575 IN NDIS_HANDLE MiniportAdapterContext,
1576 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1577 IN PVOID InformationBuffer,
1578 IN ULONG InformationBufferLength
1581 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1582 UNREFERENCED_PARAMETER(PnPEvent);
1583 UNREFERENCED_PARAMETER(InformationBuffer);
1584 UNREFERENCED_PARAMETER(InformationBufferLength);
1586 KdPrint((__FUNCTION__ " called\n"));
1589 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
1590 VOID
1591 XenNet_Shutdown(
1592 IN NDIS_HANDLE MiniportAdapterContext
1595 struct xennet_info *xi = MiniportAdapterContext;
1597 /* turn off interrupt */
1598 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
1599 xi->event_channel);
1601 KdPrint((__FUNCTION__ " called\n"));
1604 /* Opposite of XenNet_Init */
1605 XenNet_Halt(
1606 IN NDIS_HANDLE MiniportAdapterContext
1609 struct xennet_info *xi = MiniportAdapterContext;
1610 CHAR TmpPath[MAX_XENBUS_STR_LEN];
1611 PVOID if_cxt = xi->XenInterface.InterfaceHeader.Context;
1613 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1614 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1615 KdPrint((__DRIVER_NAME " tx_outstanding = %d\n", xi->tx_outstanding));
1616 KdPrint((__DRIVER_NAME " rx_outstanding = %d\n", xi->rx_outstanding));
1618 // this disables the interrupt
1619 XenNet_Shutdown(xi);
1621 // set frontend state to 'closing'
1622 xi->state = XenbusStateClosing;
1623 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1624 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
1626 // wait for backend to set 'Closing' state
1628 while (xi->backend_state != XenbusStateClosing)
1629 KeWaitForSingleObject(&xi->backend_state_change_event, Executive,
1630 KernelMode, FALSE, NULL);
1632 // set frontend state to 'closed'
1633 xi->state = XenbusStateClosed;
1634 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1635 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
1637 // wait for backend to set 'Closed' state
1638 while (xi->backend_state != XenbusStateClosed)
1639 KeWaitForSingleObject(&xi->backend_state_change_event, Executive,
1640 KernelMode, FALSE, NULL);
1642 xi->connected = FALSE;
1644 /* wait for all receive buffers to be returned */
1645 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
1646 while (xi->rx_outstanding > 0)
1647 KeWaitForSingleObject(&xi->shutdown_event, Executive, KernelMode, FALSE, NULL);
1649 // TODO: remove event channel xenbus entry (how?)
1651 KdPrint((__DRIVER_NAME " tx_outstanding = %d\n", xi->tx_outstanding));
1652 KdPrint((__DRIVER_NAME " rx_outstanding = %d\n", xi->rx_outstanding));
1654 /* free TX resources */
1655 if (xi->XenInterface.GntTbl_EndAccess(if_cxt, xi->tx_ring_ref))
1657 xi->tx_ring_ref = GRANT_INVALID_REF;
1658 FreePages(xi->tx_mdl);
1660 /* if EndAccess fails then tx/rx ring pages LEAKED -- it's not safe to reuse
1661 pages Dom0 still has access to */
1662 xi->tx_pgs = NULL;
1663 XenNet_TxBufferFree(xi);
1665 KdPrint((__DRIVER_NAME " tx_outstanding = %d\n", xi->tx_outstanding));
1666 KdPrint((__DRIVER_NAME " rx_outstanding = %d\n", xi->rx_outstanding));
1668 /* free RX resources */
1669 if (xi->XenInterface.GntTbl_EndAccess(if_cxt, xi->rx_ring_ref))
1671 xi->rx_ring_ref = GRANT_INVALID_REF;
1672 FreePages(xi->rx_mdl);
1674 xi->rx_pgs = NULL;
1675 XenNet_RxBufferFree(MiniportAdapterContext);
1677 /* Remove watch on backend state */
1678 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
1679 xi->XenInterface.XenBus_RemWatch(if_cxt, XBT_NIL, TmpPath,
1680 XenNet_BackEndStateHandler, xi);
1682 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
1684 WdfDriverMiniportUnload(WdfGetDriver());
1686 NdisFreeBufferPool(xi->buffer_pool);
1687 NdisFreePacketPool(xi->packet_pool);
1689 KdPrint((__DRIVER_NAME " tx_outstanding = %d\n", xi->tx_outstanding));
1690 KdPrint((__DRIVER_NAME " rx_outstanding = %d\n", xi->rx_outstanding));
1692 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
1694 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1697 NTSTATUS
1698 DriverEntry(
1699 PDRIVER_OBJECT DriverObject,
1700 PUNICODE_STRING RegistryPath
1703 NTSTATUS status;
1704 WDF_DRIVER_CONFIG config;
1705 NDIS_HANDLE ndis_wrapper_handle;
1706 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1708 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1710 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1711 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1713 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1714 &config, WDF_NO_HANDLE);
1715 if (!NT_SUCCESS(status))
1717 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1718 return status;
1721 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1722 if (!ndis_wrapper_handle)
1724 KdPrint(("NdisMInitializeWrapper failed\n"));
1725 return NDIS_STATUS_FAILURE;
1728 /* NDIS 5.1 driver */
1729 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1730 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1732 mini_chars.HaltHandler = XenNet_Halt;
1733 mini_chars.InitializeHandler = XenNet_Init;
1734 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1735 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1736 mini_chars.ResetHandler = NULL; //TODO: fill in
1737 mini_chars.SetInformationHandler = XenNet_SetInformation;
1738 /* added in v.4 -- use multiple pkts interface */
1739 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1740 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1741 /* added in v.5.1 */
1742 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1743 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1745 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1747 /* set up upper-edge interface */
1748 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1749 if (!NT_SUCCESS(status))
1751 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1752 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1753 return status;
1756 return status;