win-pvdrivers

view xennet/xennet.c @ 115:0d9e5303a8d2

- Fix 'unbind' so that the dpc (if any) is cancelled or completed before returning.
- Add code to make sure that no further calls will be made to ReturnPacket after _Halt is complete
Upgrading xennet.sys on a running system now appears to work properly again.
author James Harper <james.harper@bendigoit.com.au>
date Sat Jan 12 22:14:04 2008 +1100 (2008-01-12)
parents 64e4596aec1c
children 4f25a9922d0b
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 KEVENT shutdown_event;
71 char backend_path[MAX_XENBUS_STR_LEN];
72 ULONG backend_state;
74 /* Xen ring-related vars */
75 KSPIN_LOCK rx_lock;
76 KSPIN_LOCK tx_lock;
78 LIST_ENTRY tx_waiting_pkt_list;
79 LIST_ENTRY rx_free_pkt_list;
81 struct netif_tx_front_ring tx;
82 struct netif_rx_front_ring rx;
83 grant_ref_t tx_ring_ref;
84 grant_ref_t rx_ring_ref;
86 /* ptrs to the actual rings themselvves */
87 struct netif_tx_sring *tx_pgs;
88 struct netif_rx_sring *rx_pgs;
90 /* MDLs for the above */
91 PMDL tx_mdl;
92 PMDL rx_mdl;
94 /* Outstanding packets. The first entry in tx_pkts
95 * is an index into a chain of free entries. */
96 int tx_pkt_ids_used;
97 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE+1];
98 PNDIS_BUFFER rx_buffers[NET_RX_RING_SIZE];
100 grant_ref_t gref_tx_head;
101 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE+1];
102 grant_ref_t gref_rx_head;
103 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
105 /* Receive-ring batched refills. */
106 #define RX_MIN_TARGET 8
107 #define RX_DFL_MIN_TARGET 64
108 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
109 ULONG rx_target;
110 ULONG rx_max_target;
111 ULONG rx_min_target;
113 ULONG rx_outstanding;
115 /* stats */
116 ULONG64 stat_tx_ok;
117 ULONG64 stat_rx_ok;
118 ULONG64 stat_tx_error;
119 ULONG64 stat_rx_error;
120 ULONG64 stat_rx_no_buffer;
121 };
123 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
124 static unsigned long
125 simple_strtoul(const char *cp,char **endp,unsigned int base)
126 {
127 unsigned long result = 0,value;
129 if (!base) {
130 base = 10;
131 if (*cp == '0') {
132 base = 8;
133 cp++;
134 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
135 cp++;
136 base = 16;
137 }
138 }
139 } else if (base == 16) {
140 if (cp[0] == '0' && toupper(cp[1]) == 'X')
141 cp += 2;
142 }
143 while (isxdigit(*cp) &&
144 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
145 result = result*base + value;
146 cp++;
147 }
148 if (endp)
149 *endp = (char *)cp;
150 return result;
151 }
153 static void
154 add_id_to_freelist(struct xennet_info *xi, unsigned short id)
155 {
156 xi->tx_pkts[id] = xi->tx_pkts[0];
157 xi->tx_pkts[0] = (void *)(unsigned long)id;
158 xi->tx_pkt_ids_used--;
159 }
161 static unsigned short
162 get_id_from_freelist(struct xennet_info *xi)
163 {
164 unsigned short id;
165 if (xi->tx_pkt_ids_used >= NET_TX_RING_SIZE)
166 return 0;
167 id = (unsigned short)(unsigned long)xi->tx_pkts[0];
168 xi->tx_pkts[0] = xi->tx_pkts[id];
169 xi->tx_pkt_ids_used++;
170 return id;
171 }
173 VOID XenNet_SendQueuedPackets(struct xennet_info *xi);
175 // Called at DISPATCH_LEVEL
176 static NDIS_STATUS
177 XenNet_TxBufferGC(struct xennet_info *xi)
178 {
179 RING_IDX cons, prod;
180 unsigned short id;
181 PNDIS_PACKET pkt;
182 PMDL pmdl;
183 KIRQL OldIrql;
185 ASSERT(xi->connected);
187 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
189 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
191 do {
192 prod = xi->tx.sring->rsp_prod;
193 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
195 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
196 struct netif_tx_response *txrsp;
198 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
199 if (txrsp->status == NETIF_RSP_NULL)
200 continue;
202 id = txrsp->id;
203 pkt = xi->tx_pkts[id];
204 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
205 xi->grant_tx_ref[id]);
206 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
207 add_id_to_freelist(xi, id);
209 /* free linearized data page */
210 pmdl = *(PMDL *)pkt->MiniportReservedEx;
211 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
212 IoFreeMdl(pmdl);
214 xi->stat_tx_ok++;
215 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
216 }
218 xi->tx.rsp_cons = prod;
220 /*
221 * Set a new event, then check for race with update of tx_cons.
222 * Note that it is essential to schedule a callback, no matter
223 * how few buffers are pending. Even if there is space in the
224 * transmit ring, higher layers may be blocked because too much
225 * data is outstanding: in such cases notification from Xen is
226 * likely to be the only kick that we'll get.
227 */
228 xi->tx.sring->rsp_event =
229 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
230 KeMemoryBarrier();
231 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
233 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
235 /* if queued packets, send them now */
236 XenNet_SendQueuedPackets(xi);
238 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
240 return NDIS_STATUS_SUCCESS;
241 }
243 static void XenNet_TxBufferFree(struct xennet_info *xi)
244 {
245 PNDIS_PACKET packet;
246 PMDL pmdl;
247 unsigned short id;
249 /* TODO: free packets in tx queue (once implemented) */
251 /* free sent-but-not-completed packets */
252 for (id = 1; id < NET_TX_RING_SIZE+1; id++) {
253 if (xi->grant_tx_ref[id] == GRANT_INVALID_REF)
254 continue;
256 packet = xi->tx_pkts[id];
257 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
258 xi->grant_tx_ref[id]);
259 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
260 add_id_to_freelist(xi, id);
262 /* free linearized data page */
263 pmdl = *(PMDL *)packet->MiniportReservedEx;
264 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
265 IoFreeMdl(pmdl);
267 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
268 }
269 }
271 // Called at DISPATCH_LEVEL with no locks held
272 static NDIS_STATUS
273 XenNet_RxBufferAlloc(struct xennet_info *xi)
274 {
275 unsigned short id;
276 PNDIS_BUFFER buffer;
277 int i, batch_target, notify;
278 RING_IDX req_prod = xi->rx.req_prod_pvt;
279 grant_ref_t ref;
280 netif_rx_request_t *req;
281 NDIS_STATUS status;
282 PVOID start;
283 KIRQL OldIrql;
285 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
287 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
289 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
290 for (i = 0; i < batch_target; i++)
291 {
292 /*
293 * Allocate memory and an NDIS_BUFFER.
294 */
295 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
296 if (status != NDIS_STATUS_SUCCESS)
297 {
298 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
299 break;
300 }
301 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
302 ASSERT(status == NDIS_STATUS_SUCCESS); // should never fail
304 /* Give to netback */
305 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
306 ASSERT(!xi->rx_buffers[id]);
307 xi->rx_buffers[id] = buffer;
308 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
309 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
310 ref = xi->XenInterface.GntTbl_GrantAccess(
311 xi->XenInterface.InterfaceHeader.Context, 0,
312 *MmGetMdlPfnArray(buffer), FALSE);
313 ASSERT((signed short)ref >= 0);
314 xi->grant_rx_ref[id] = ref;
316 req->id = id;
317 req->gref = ref;
318 }
320 xi->rx.req_prod_pvt = req_prod + i;
321 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
322 if (notify)
323 {
324 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
325 xi->event_channel);
326 }
328 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
330 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
332 return NDIS_STATUS_SUCCESS;
333 }
335 /* Free all Rx buffers (on halt, for example) */
336 static void
337 XenNet_RxBufferFree(struct xennet_info *xi)
338 {
339 int i;
340 grant_ref_t ref;
341 PNDIS_BUFFER buffer;
342 KIRQL OldIrql;
344 ASSERT(!xi->connected);
346 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
348 for (i = 0; i < NET_RX_RING_SIZE; i++)
349 {
350 if (!xi->rx_buffers[i])
351 continue;
353 buffer = xi->rx_buffers[i];
354 ref = xi->grant_rx_ref[i];
356 /* don't check return, what can we do about it on failure? */
357 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context, ref);
359 NdisFreeMemory(NdisBufferVirtualAddressSafe(buffer, NormalPagePriority), 0, 0);
360 NdisFreeBuffer(buffer);
361 }
363 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
364 }
366 VOID
367 XenNet_ReturnPacket(
368 IN NDIS_HANDLE MiniportAdapterContext,
369 IN PNDIS_PACKET Packet
370 )
371 {
372 struct xennet_info *xi = MiniportAdapterContext;
373 PNDIS_BUFFER buffer;
374 PNDIS_BUFFER next_buffer;
375 PVOID buff_va;
376 UINT buff_len;
377 UINT tot_buff_len;
379 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
381 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
382 &tot_buff_len, NormalPagePriority);
383 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
385 while (buffer)
386 {
387 NdisGetNextBuffer(buffer, &next_buffer);
388 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
389 NdisFreeMemory(buff_va, 0, 0);
390 NdisFreeBuffer(buffer);
391 buffer = next_buffer;
392 }
394 NdisFreePacket(Packet);
396 InterlockedDecrement(&xi->rx_outstanding);
397 // if we are no longer connected then _halt probably needs to know when rx_outstanding reaches zero
398 if (!xi->connected && !xi->rx_outstanding)
399 KeSetEvent(&xi->shutdown_event, 1, FALSE);
401 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
402 }
404 // Called at DISPATCH_LEVEL
405 static NDIS_STATUS
406 XenNet_RxBufferCheck(struct xennet_info *xi)
407 {
408 RING_IDX cons, prod;
410 PNDIS_PACKET packet = NULL;
411 PNDIS_BUFFER buffer;
412 int moretodo;
413 KIRQL OldIrql;
414 PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
415 struct netif_rx_response *rxrsp = NULL;
416 int more_frags = 0;
417 NDIS_STATUS status;
419 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
421 ASSERT(xi->connected);
423 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
425 do {
426 prod = xi->rx.sring->rsp_prod;
427 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
429 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
430 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
431 ASSERT(rxrsp->status > 0);
433 if (!more_frags) // handling the packet's 1st buffer
434 {
435 // KdPrint((__DRIVER_NAME " Got a packet\n"));
436 NdisAllocatePacket(&status, &packet, xi->packet_pool);
437 ASSERT(status == NDIS_STATUS_SUCCESS);
438 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
439 /*
440 if (NDIS_GET_PACKET_PROTOCOL_TYPE(packet) == NDIS_PROTOCOL_ID_TCP_IP
441 && (rxrsp->flags & (NETRXF_csum_blank|NETRXF_data_validated)))
442 {
443 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo);
444 csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
445 csum_info->Receive.NdisPacketUdpChecksumSucceeded = 1;
446 csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
447 // KdPrint((__DRIVER_NAME " Offload = %08x\n", NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo)));
448 }
449 */
450 }
452 buffer = xi->rx_buffers[rxrsp->id];
453 xi->rx_buffers[rxrsp->id] = NULL;
454 NdisAdjustBufferLength(buffer, rxrsp->status);
455 NdisChainBufferAtBack(packet, buffer);
457 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
458 xi->grant_rx_ref[rxrsp->id]);
459 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
461 #if 0
462 KdPrint((__DRIVER_NAME " Flags = %sNETRXF_data_validated|%sNETRXF_csum_blank|%sNETRXF_more_data|%sNETRXF_extra_info\n",
463 (rxrsp->flags&NETRXF_data_validated)?"":"!",
464 (rxrsp->flags&NETRXF_csum_blank)?"":"!",
465 (rxrsp->flags&NETRXF_more_data)?"":"!",
466 (rxrsp->flags&NETRXF_extra_info)?"":"!"));
467 #endif
468 ASSERT(!(rxrsp->flags & NETRXF_extra_info)); // not used on RX
470 more_frags = rxrsp->flags & NETRXF_more_data;
472 /* Packet done, pass it up */
473 if (!more_frags)
474 {
475 xi->stat_rx_ok++;
476 InterlockedIncrement(&xi->rx_outstanding);
477 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
478 NdisMIndicateReceivePacket(xi->adapter_handle, &packet, 1);
479 }
480 }
481 xi->rx.rsp_cons = prod;
483 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
484 } while (moretodo);
486 if (more_frags)
487 {
488 KdPrint((__DRIVER_NAME " Missing fragments\n"));
489 XenNet_ReturnPacket(xi, packet);
490 }
492 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
494 /* Give netback more buffers */
495 XenNet_RxBufferAlloc(xi);
497 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
499 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
501 return NDIS_STATUS_SUCCESS;
502 }
504 // Called at DISPATCH_LEVEL
505 static BOOLEAN
506 XenNet_Interrupt(
507 PKINTERRUPT Interrupt,
508 PVOID ServiceContext
509 )
510 {
511 struct xennet_info *xi = ServiceContext;
513 UNREFERENCED_PARAMETER(Interrupt);
515 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
517 if (xi->connected)
518 {
519 XenNet_TxBufferGC(xi);
520 XenNet_RxBufferCheck(xi);
521 }
523 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
525 return TRUE;
526 }
528 // Called at <= DISPATCH_LEVEL
530 static VOID
531 XenNet_BackEndStateHandler(char *Path, PVOID Data)
532 {
533 struct xennet_info *xi = Data;
534 char *Value;
535 char TmpPath[MAX_XENBUS_STR_LEN];
536 xenbus_transaction_t xbt = 0;
537 int retry = 0;
538 char *err;
539 int i;
540 ULONG new_backend_state;
542 struct set_params {
543 char *name;
544 int value;
545 } params[] = {
546 {"tx-ring-ref", 0},
547 {"rx-ring-ref", 0},
548 {"event-channel", 0},
549 {"request-rx-copy", 1},
550 {"feature-rx-notify", 1},
551 {"feature-no-csum-offload", 1},
552 {"feature-sg", 1},
553 {"feature-gso-tcpv4", 0},
554 {NULL, 0},
555 };
557 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
558 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
560 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
561 XBT_NIL, Path, &Value);
562 new_backend_state = atoi(Value);
563 xi->XenInterface.FreeMem(Value);
565 if (xi->backend_state == new_backend_state)
566 {
567 KdPrint((__DRIVER_NAME " state unchanged\n"));
568 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
569 return;
570 }
572 xi->backend_state = new_backend_state;
574 switch (xi->backend_state)
575 {
576 case XenbusStateUnknown:
577 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
578 break;
580 case XenbusStateInitialising:
581 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
582 break;
584 case XenbusStateInitWait:
585 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
587 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
588 xi->XenInterface.InterfaceHeader.Context, 0);
589 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
590 xi->event_channel, XenNet_Interrupt, xi);
592 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
593 // or, allocate mem and then get mdl, then free mdl
594 xi->tx_mdl = AllocatePage();
595 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl); //MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
596 SHARED_RING_INIT(xi->tx_pgs);
597 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
598 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
599 xi->XenInterface.InterfaceHeader.Context, 0,
600 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
602 xi->rx_mdl = AllocatePage();
603 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl); //MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
604 SHARED_RING_INIT(xi->rx_pgs);
605 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
606 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
607 xi->XenInterface.InterfaceHeader.Context, 0,
608 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
610 /* fixup array for dynamic values */
611 params[0].value = xi->tx_ring_ref;
612 params[1].value = xi->rx_ring_ref;
613 params[2].value = xi->event_channel;
615 xi->XenInterface.XenBus_StartTransaction(
616 xi->XenInterface.InterfaceHeader.Context, &xbt);
618 for (i = 0; params[i].name; i++)
619 {
620 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
621 xi->pdo_data->Path, params[i].name);
622 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
623 XBT_NIL, TmpPath, "%d", params[i].value);
624 if (err)
625 {
626 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
627 goto trouble;
628 }
629 }
631 /* commit transaction */
632 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
633 xbt, 0, &retry);
635 XenNet_RxBufferAlloc(xi);
637 xi->state = XenbusStateConnected;
638 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
639 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
640 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
641 XBT_NIL, TmpPath, "%d", xi->state);
643 /* send fake arp? */
645 xi->connected = TRUE;
647 break;
649 case XenbusStateInitialised:
650 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
651 break;
653 case XenbusStateConnected:
654 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
655 break;
657 case XenbusStateClosing:
658 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
659 break;
661 case XenbusStateClosed:
662 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
663 break;
665 default:
666 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
667 break;
668 }
670 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
672 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
674 return;
676 trouble:
677 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
678 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
679 xbt, 1, &retry);
680 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
681 }
683 static NDIS_STATUS
684 XenNet_Init(
685 OUT PNDIS_STATUS OpenErrorStatus,
686 OUT PUINT SelectedMediumIndex,
687 IN PNDIS_MEDIUM MediumArray,
688 IN UINT MediumArraySize,
689 IN NDIS_HANDLE MiniportAdapterHandle,
690 IN NDIS_HANDLE WrapperConfigurationContext
691 )
692 {
693 NDIS_STATUS status;
694 UINT i;
695 BOOLEAN medium_found = FALSE;
696 struct xennet_info *xi = NULL;
697 ULONG length;
698 WDF_OBJECT_ATTRIBUTES wdf_attrs;
699 char *res;
700 char *Value;
701 char TmpPath[MAX_XENBUS_STR_LEN];
703 UNREFERENCED_PARAMETER(OpenErrorStatus);
704 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
706 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
707 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
709 /* deal with medium stuff */
710 for (i = 0; i < MediumArraySize; i++)
711 {
712 if (MediumArray[i] == NdisMedium802_3)
713 {
714 medium_found = TRUE;
715 break;
716 }
717 }
718 if (!medium_found)
719 {
720 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
721 return NDIS_STATUS_UNSUPPORTED_MEDIA;
722 }
723 *SelectedMediumIndex = i;
725 /* Alloc memory for adapter private info */
726 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
727 if (!NT_SUCCESS(status))
728 {
729 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
730 status = NDIS_STATUS_RESOURCES;
731 goto err;
732 }
733 RtlZeroMemory(xi, sizeof(*xi));
735 /* init xennet_info */
736 xi->adapter_handle = MiniportAdapterHandle;
737 xi->rx_target = RX_DFL_MIN_TARGET;
738 xi->rx_min_target = RX_DFL_MIN_TARGET;
739 xi->rx_max_target = RX_MAX_TARGET;
741 xi->state = XenbusStateUnknown;
742 xi->backend_state = XenbusStateUnknown;
744 KeInitializeSpinLock(&xi->tx_lock);
745 KeInitializeSpinLock(&xi->rx_lock);
746 InitializeListHead(&xi->rx_free_pkt_list);
747 InitializeListHead(&xi->tx_waiting_pkt_list);
750 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
751 PROTOCOL_RESERVED_SIZE_IN_PACKET);
752 if (status != NDIS_STATUS_SUCCESS)
753 {
754 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
755 status = NDIS_STATUS_RESOURCES;
756 goto err;
757 }
758 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
760 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
761 if (status != NDIS_STATUS_SUCCESS)
762 {
763 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
764 status = NDIS_STATUS_RESOURCES;
765 goto err;
766 }
768 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
769 &xi->lower_do, NULL, NULL);
770 xi->pdo_data = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
772 /* Initialize tx_pkts as a free chain containing every entry. */
773 for (i = 0; i < NET_TX_RING_SIZE+1; i++) {
774 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
775 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
776 }
778 for (i = 0; i < NET_RX_RING_SIZE; i++) {
779 xi->rx_buffers[i] = NULL;
780 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
781 }
783 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
785 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
786 NAME_SIZE, xi->dev_desc, &length);
787 if (!NT_SUCCESS(status))
788 {
789 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
790 status = NDIS_STATUS_FAILURE;
791 goto err;
792 }
794 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
795 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
796 NdisInterfaceInternal);
798 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
800 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
801 xi->lower_do, xi->pdo, &xi->wdf_device);
802 if (!NT_SUCCESS(status))
803 {
804 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
805 status = NDIS_STATUS_FAILURE;
806 goto err;
807 }
809 /* get lower (Xen) interfaces */
811 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
812 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
813 if(!NT_SUCCESS(status))
814 {
815 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
816 status = NDIS_STATUS_FAILURE;
817 goto err;
818 }
820 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
821 "%s/backend", xi->pdo_data->Path);
822 KdPrint(("About to read %s to get backend path\n", TmpPath));
823 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
824 XBT_NIL, TmpPath, &Value);
825 if (res)
826 {
827 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
828 xi->XenInterface.FreeMem(res);
829 status = NDIS_STATUS_FAILURE;
830 goto err;
831 }
832 RtlStringCbCopyA(xi->backend_path, ARRAY_SIZE(xi->backend_path), Value);
833 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->backend_path));
835 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/type", xi->backend_path);
836 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
837 XBT_NIL, TmpPath, &Value);
839 #if 1
840 if (res || strcmp(Value, "netfront") != 0)
841 {
842 KdPrint((__DRIVER_NAME " Backend type is not 'netfront'\n"));
843 status = NDIS_STATUS_FAILURE;
844 goto err;
845 }
846 #endif
848 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
849 KeInitializeEvent(&xi->shutdown_event, SynchronizationEvent, FALSE);
851 /* Add watch on backend state */
852 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
853 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
854 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
856 /* Tell backend we're coming up */
857 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
858 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
859 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
861 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
863 // wait here for signal that we are all set up
864 while (xi->backend_state != XenbusStateConnected)
865 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
867 KdPrint((__DRIVER_NAME " Connected\n"));
869 /* get mac address */
870 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->backend_path);
871 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
872 XBT_NIL, TmpPath, &Value);
873 if (!Value)
874 {
875 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
876 status = NDIS_STATUS_FAILURE;
877 goto err;
878 }
879 else
880 {
881 char *s, *e;
882 s = Value;
883 for (i = 0; i < ETH_ALEN; i++) {
884 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
885 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
886 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
887 xi->XenInterface.FreeMem(Value);
888 status = NDIS_STATUS_FAILURE;
889 goto err;
890 }
891 s = e + 1;
892 }
893 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
894 xi->XenInterface.FreeMem(Value);
895 }
897 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
899 return NDIS_STATUS_SUCCESS;
901 err:
902 NdisFreeMemory(xi, 0, 0);
903 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
904 return status;
905 }
907 // Q = Query Mandatory, S = Set Mandatory
908 NDIS_OID supported_oids[] =
909 {
910 /* general OIDs */
911 OID_GEN_SUPPORTED_LIST, // Q
912 OID_GEN_HARDWARE_STATUS, // Q
913 OID_GEN_MEDIA_SUPPORTED, // Q
914 OID_GEN_MEDIA_IN_USE, // Q
915 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
916 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
917 OID_GEN_LINK_SPEED, // Q
918 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
919 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
920 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
921 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
922 OID_GEN_VENDOR_ID, // Q
923 OID_GEN_VENDOR_DESCRIPTION, // Q
924 OID_GEN_CURRENT_PACKET_FILTER, // QS
925 OID_GEN_CURRENT_LOOKAHEAD, // QS
926 OID_GEN_DRIVER_VERSION, // Q
927 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
928 OID_GEN_PROTOCOL_OPTIONS, // S
929 OID_GEN_MAC_OPTIONS, // Q
930 OID_GEN_MEDIA_CONNECT_STATUS, // Q
931 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
932 /* stats */
933 OID_GEN_XMIT_OK, // Q
934 OID_GEN_RCV_OK, // Q
935 OID_GEN_XMIT_ERROR, // Q
936 OID_GEN_RCV_ERROR, // Q
937 OID_GEN_RCV_NO_BUFFER, // Q
938 /* media-specific OIDs */
939 OID_802_3_PERMANENT_ADDRESS,
940 OID_802_3_CURRENT_ADDRESS,
941 OID_802_3_MULTICAST_LIST,
942 OID_802_3_MAXIMUM_LIST_SIZE,
943 /* tcp offload */
944 OID_TCP_TASK_OFFLOAD,
945 };
947 /* return 4 or 8 depending on size of buffer */
948 #define HANDLE_STAT_RETURN \
949 {if (InformationBufferLength == 4) { \
950 len = 4; *BytesNeeded = 8; \
951 } else { \
952 len = 8; \
953 } }
955 //#define OFFLOAD_LARGE_SEND
957 NDIS_STATUS
958 XenNet_QueryInformation(
959 IN NDIS_HANDLE MiniportAdapterContext,
960 IN NDIS_OID Oid,
961 IN PVOID InformationBuffer,
962 IN ULONG InformationBufferLength,
963 OUT PULONG BytesWritten,
964 OUT PULONG BytesNeeded)
965 {
966 struct xennet_info *xi = MiniportAdapterContext;
967 UCHAR vendor_desc[] = XN_VENDOR_DESC;
968 ULONG64 temp_data;
969 PVOID data = &temp_data;
970 UINT len = 4;
971 BOOLEAN used_temp_buffer = TRUE;
972 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
973 PNDIS_TASK_OFFLOAD_HEADER ntoh;
974 PNDIS_TASK_OFFLOAD nto;
975 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
976 #ifdef OFFLOAD_LARGE_SEND
977 PNDIS_TASK_TCP_LARGE_SEND nttls;
978 #endif
980 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
982 switch(Oid)
983 {
984 case OID_GEN_SUPPORTED_LIST:
985 data = supported_oids;
986 len = sizeof(supported_oids);
987 break;
988 case OID_GEN_HARDWARE_STATUS:
989 if (!xi->connected)
990 temp_data = NdisHardwareStatusInitializing;
991 else
992 temp_data = NdisHardwareStatusReady;
993 break;
994 case OID_GEN_MEDIA_SUPPORTED:
995 temp_data = NdisMedium802_3;
996 break;
997 case OID_GEN_MEDIA_IN_USE:
998 temp_data = NdisMedium802_3;
999 break;
1000 case OID_GEN_MAXIMUM_LOOKAHEAD:
1001 temp_data = XN_DATA_SIZE;
1002 break;
1003 case OID_GEN_MAXIMUM_FRAME_SIZE:
1004 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
1005 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
1006 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
1007 break;
1008 case OID_GEN_LINK_SPEED:
1009 temp_data = 10000000; /* 1Gb */
1010 break;
1011 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1012 /* pkts times sizeof ring, maybe? */
1013 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
1014 break;
1015 case OID_GEN_RECEIVE_BUFFER_SPACE:
1016 /* pkts times sizeof ring, maybe? */
1017 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
1018 break;
1019 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1020 temp_data = XN_MAX_PKT_SIZE;
1021 break;
1022 case OID_GEN_RECEIVE_BLOCK_SIZE:
1023 temp_data = XN_MAX_PKT_SIZE;
1024 break;
1025 case OID_GEN_VENDOR_ID:
1026 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
1027 break;
1028 case OID_GEN_VENDOR_DESCRIPTION:
1029 data = vendor_desc;
1030 len = sizeof(vendor_desc);
1031 break;
1032 case OID_GEN_CURRENT_PACKET_FILTER:
1033 temp_data = xi->packet_filter;
1034 break;
1035 case OID_GEN_CURRENT_LOOKAHEAD:
1036 // TODO: we should store this...
1037 temp_data = XN_MAX_PKT_SIZE;
1038 break;
1039 case OID_GEN_DRIVER_VERSION:
1040 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
1041 len = 2;
1042 break;
1043 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1044 temp_data = XN_MAX_PKT_SIZE;
1045 break;
1046 case OID_GEN_MAC_OPTIONS:
1047 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1048 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1049 NDIS_MAC_OPTION_NO_LOOPBACK;
1050 break;
1051 case OID_GEN_MEDIA_CONNECT_STATUS:
1052 if (xi->connected)
1053 temp_data = NdisMediaStateConnected;
1054 else
1055 temp_data = NdisMediaStateDisconnected;
1056 break;
1057 case OID_GEN_MAXIMUM_SEND_PACKETS:
1058 temp_data = XN_MAX_SEND_PKTS;
1059 break;
1060 case OID_GEN_XMIT_OK:
1061 temp_data = xi->stat_tx_ok;
1062 HANDLE_STAT_RETURN;
1063 break;
1064 case OID_GEN_RCV_OK:
1065 temp_data = xi->stat_rx_ok;
1066 HANDLE_STAT_RETURN;
1067 break;
1068 case OID_GEN_XMIT_ERROR:
1069 temp_data = xi->stat_tx_error;
1070 HANDLE_STAT_RETURN;
1071 break;
1072 case OID_GEN_RCV_ERROR:
1073 temp_data = xi->stat_rx_error;
1074 HANDLE_STAT_RETURN;
1075 break;
1076 case OID_GEN_RCV_NO_BUFFER:
1077 temp_data = xi->stat_rx_no_buffer;
1078 HANDLE_STAT_RETURN;
1079 break;
1080 case OID_802_3_PERMANENT_ADDRESS:
1081 data = xi->perm_mac_addr;
1082 len = ETH_ALEN;
1083 break;
1084 case OID_802_3_CURRENT_ADDRESS:
1085 data = xi->curr_mac_addr;
1086 len = ETH_ALEN;
1087 break;
1088 case OID_802_3_MULTICAST_LIST:
1089 data = NULL;
1090 len = 0;
1091 case OID_802_3_MAXIMUM_LIST_SIZE:
1092 temp_data = 0; /* no mcast support */
1093 break;
1094 case OID_TCP_TASK_OFFLOAD:
1095 KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
1096 /* it's times like this that C really sucks */
1098 len = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1100 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1101 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1102 #ifdef OFFLOAD_LARGE_SEND
1103 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1104 + sizeof(NDIS_TASK_TCP_LARGE_SEND);
1105 #endif
1107 if (len > InformationBufferLength)
1109 break;
1112 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1113 ASSERT(ntoh->Version == NDIS_TASK_OFFLOAD_VERSION);
1114 ASSERT(ntoh->Size == sizeof(*ntoh));
1115 ASSERT(ntoh->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation);
1116 ntoh->OffsetFirstTask = ntoh->Size;
1118 /* fill in first nto */
1119 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
1120 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1121 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1122 nto->Task = TcpIpChecksumNdisTask;
1123 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1125 /* fill in checksum offload struct */
1126 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1127 nttic->V4Transmit.IpOptionsSupported = 0;
1128 nttic->V4Transmit.TcpOptionsSupported = 0;
1129 nttic->V4Transmit.TcpChecksum = 0;
1130 nttic->V4Transmit.UdpChecksum = 0;
1131 nttic->V4Transmit.IpChecksum = 0;
1132 nttic->V4Receive.IpOptionsSupported = 1;
1133 nttic->V4Receive.TcpOptionsSupported = 1;
1134 nttic->V4Receive.TcpChecksum = 1;
1135 nttic->V4Receive.UdpChecksum = 1;
1136 nttic->V4Receive.IpChecksum = 1;
1137 nttic->V6Transmit.IpOptionsSupported = 0;
1138 nttic->V6Transmit.TcpOptionsSupported = 0;
1139 nttic->V6Transmit.TcpChecksum = 0;
1140 nttic->V6Transmit.UdpChecksum = 0;
1141 nttic->V6Receive.IpOptionsSupported = 0;
1142 nttic->V6Receive.TcpOptionsSupported = 0;
1143 nttic->V6Receive.TcpChecksum = 0;
1144 nttic->V6Receive.UdpChecksum = 0;
1146 #ifdef OFFLOAD_LARGE_SEND
1147 /* offset from start of current NTO to start of next NTO */
1148 nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1149 + nto->TaskBufferLength;
1151 /* fill in second nto */
1152 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
1153 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1154 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1155 nto->Task = TcpLargeSendNdisTask;
1156 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
1158 /* fill in large send struct */
1159 nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
1160 nttls->Version = 0;
1161 nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
1162 nttls->MinSegmentCount = 4; /* also made up */
1163 nttls->TcpOptions = FALSE;
1164 nttls->IpOptions = FALSE;
1165 #endif
1166 nto->OffsetNextTask = 0; /* last one */
1168 used_temp_buffer = FALSE;
1169 break;
1170 default:
1171 KdPrint(("Get Unknown OID 0x%x\n", Oid));
1172 status = NDIS_STATUS_NOT_SUPPORTED;
1175 if (!NT_SUCCESS(status))
1177 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
1178 return status;
1181 if (len > InformationBufferLength)
1183 *BytesNeeded = len;
1184 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (BUFFER_TOO_SHORT)\n"));
1185 return NDIS_STATUS_BUFFER_TOO_SHORT;
1188 *BytesWritten = len;
1189 if (len && used_temp_buffer)
1191 NdisMoveMemory((PUCHAR)InformationBuffer, data, len);
1194 //KdPrint(("Got OID 0x%x\n", Oid));
1195 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1197 return status;
1200 NDIS_STATUS
1201 XenNet_SetInformation(
1202 IN NDIS_HANDLE MiniportAdapterContext,
1203 IN NDIS_OID Oid,
1204 IN PVOID InformationBuffer,
1205 IN ULONG InformationBufferLength,
1206 OUT PULONG BytesRead,
1207 OUT PULONG BytesNeeded
1210 NTSTATUS status;
1211 struct xennet_info *xi = MiniportAdapterContext;
1212 PULONG64 data = InformationBuffer;
1213 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1214 PNDIS_TASK_OFFLOAD nto;
1215 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1216 int offset;
1218 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1220 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1221 UNREFERENCED_PARAMETER(InformationBufferLength);
1222 UNREFERENCED_PARAMETER(BytesRead);
1223 UNREFERENCED_PARAMETER(BytesNeeded);
1225 switch(Oid)
1227 case OID_GEN_SUPPORTED_LIST:
1228 status = NDIS_STATUS_NOT_SUPPORTED;
1229 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1230 break;
1231 case OID_GEN_HARDWARE_STATUS:
1232 status = NDIS_STATUS_NOT_SUPPORTED;
1233 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1234 break;
1235 case OID_GEN_MEDIA_SUPPORTED:
1236 status = NDIS_STATUS_NOT_SUPPORTED;
1237 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1238 break;
1239 case OID_GEN_MEDIA_IN_USE:
1240 status = NDIS_STATUS_NOT_SUPPORTED;
1241 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1242 break;
1243 case OID_GEN_MAXIMUM_LOOKAHEAD:
1244 status = NDIS_STATUS_NOT_SUPPORTED;
1245 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1246 break;
1247 case OID_GEN_MAXIMUM_FRAME_SIZE:
1248 status = NDIS_STATUS_NOT_SUPPORTED;
1249 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1250 break;
1251 case OID_GEN_LINK_SPEED:
1252 status = NDIS_STATUS_NOT_SUPPORTED;
1253 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1254 break;
1255 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1256 status = NDIS_STATUS_NOT_SUPPORTED;
1257 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1258 break;
1259 case OID_GEN_RECEIVE_BUFFER_SPACE:
1260 status = NDIS_STATUS_NOT_SUPPORTED;
1261 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1262 break;
1263 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1264 status = NDIS_STATUS_NOT_SUPPORTED;
1265 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1266 break;
1267 case OID_GEN_RECEIVE_BLOCK_SIZE:
1268 status = NDIS_STATUS_NOT_SUPPORTED;
1269 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1270 break;
1271 case OID_GEN_VENDOR_ID:
1272 status = NDIS_STATUS_NOT_SUPPORTED;
1273 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1274 break;
1275 case OID_GEN_VENDOR_DESCRIPTION:
1276 status = NDIS_STATUS_NOT_SUPPORTED;
1277 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1278 break;
1279 case OID_GEN_CURRENT_PACKET_FILTER:
1280 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1281 xi->packet_filter = *(ULONG *)data;
1282 status = NDIS_STATUS_SUCCESS;
1283 break;
1284 case OID_GEN_CURRENT_LOOKAHEAD:
1285 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1286 // TODO: We should do this...
1287 status = NDIS_STATUS_SUCCESS;
1288 break;
1289 case OID_GEN_DRIVER_VERSION:
1290 status = NDIS_STATUS_NOT_SUPPORTED;
1291 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1292 break;
1293 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1294 status = NDIS_STATUS_NOT_SUPPORTED;
1295 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1296 break;
1297 case OID_GEN_PROTOCOL_OPTIONS:
1298 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1299 // TODO - actually do this...
1300 status = NDIS_STATUS_SUCCESS;
1301 break;
1302 case OID_GEN_MAC_OPTIONS:
1303 status = NDIS_STATUS_NOT_SUPPORTED;
1304 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1305 break;
1306 case OID_GEN_MEDIA_CONNECT_STATUS:
1307 status = NDIS_STATUS_NOT_SUPPORTED;
1308 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1309 break;
1310 case OID_GEN_MAXIMUM_SEND_PACKETS:
1311 status = NDIS_STATUS_NOT_SUPPORTED;
1312 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1313 break;
1314 case OID_GEN_XMIT_OK:
1315 status = NDIS_STATUS_NOT_SUPPORTED;
1316 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1317 break;
1318 case OID_GEN_RCV_OK:
1319 status = NDIS_STATUS_NOT_SUPPORTED;
1320 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1321 break;
1322 case OID_GEN_XMIT_ERROR:
1323 status = NDIS_STATUS_NOT_SUPPORTED;
1324 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1325 break;
1326 case OID_GEN_RCV_ERROR:
1327 status = NDIS_STATUS_NOT_SUPPORTED;
1328 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1329 break;
1330 case OID_GEN_RCV_NO_BUFFER:
1331 status = NDIS_STATUS_NOT_SUPPORTED;
1332 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1333 break;
1334 case OID_802_3_PERMANENT_ADDRESS:
1335 status = NDIS_STATUS_NOT_SUPPORTED;
1336 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1337 break;
1338 case OID_802_3_CURRENT_ADDRESS:
1339 status = NDIS_STATUS_NOT_SUPPORTED;
1340 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1341 break;
1342 case OID_802_3_MULTICAST_LIST:
1343 status = NDIS_STATUS_NOT_SUPPORTED;
1344 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1345 break;
1346 case OID_802_3_MAXIMUM_LIST_SIZE:
1347 status = NDIS_STATUS_NOT_SUPPORTED;
1348 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1349 break;
1350 case OID_TCP_TASK_OFFLOAD:
1351 // Just fake this for now... ultimately we need to manually calc rx checksum if offload is disabled by windows
1352 status = NDIS_STATUS_SUCCESS;
1353 KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
1354 // we should disable everything here, then enable what has been set
1355 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1356 *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1357 offset = ntoh->OffsetFirstTask;
1358 nto = (PNDIS_TASK_OFFLOAD)ntoh; // not really, just to get the first offset right
1359 while (offset != 0)
1361 *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
1362 nto = (PNDIS_TASK_OFFLOAD)(((PUCHAR)nto) + offset);
1363 switch (nto->Task)
1365 case TcpIpChecksumNdisTask:
1366 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1367 KdPrint(("TcpIpChecksumNdisTask\n"));
1368 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1369 KdPrint((" V4Transmit.IpOptionsSupported = %d\n", nttic->V4Transmit.IpOptionsSupported));
1370 KdPrint((" V4Transmit.TcpOptionsSupported = %d\n", nttic->V4Transmit.TcpOptionsSupported));
1371 KdPrint((" V4Transmit.TcpChecksum = %d\n", nttic->V4Transmit.TcpChecksum));
1372 KdPrint((" V4Transmit.UdpChecksum = %d\n", nttic->V4Transmit.UdpChecksum));
1373 KdPrint((" V4Transmit.IpChecksum = %d\n", nttic->V4Transmit.IpChecksum));
1374 KdPrint((" V4Receive.IpOptionsSupported = %d\n", nttic->V4Receive.IpOptionsSupported));
1375 KdPrint((" V4Receive.TcpOptionsSupported = %d\n", nttic->V4Receive.TcpOptionsSupported));
1376 KdPrint((" V4Receive.TcpChecksum = %d\n", nttic->V4Receive.TcpChecksum));
1377 KdPrint((" V4Receive.UdpChecksum = %d\n", nttic->V4Receive.UdpChecksum));
1378 KdPrint((" V4Receive.IpChecksum = %d\n", nttic->V4Receive.IpChecksum));
1379 KdPrint((" V6Transmit.IpOptionsSupported = %d\n", nttic->V6Transmit.IpOptionsSupported));
1380 KdPrint((" V6Transmit.TcpOptionsSupported = %d\n", nttic->V6Transmit.TcpOptionsSupported));
1381 KdPrint((" V6Transmit.TcpChecksum = %d\n", nttic->V6Transmit.TcpChecksum));
1382 KdPrint((" V6Transmit.UdpChecksum = %d\n", nttic->V6Transmit.UdpChecksum));
1383 KdPrint((" V6Receive.IpOptionsSupported = %d\n", nttic->V6Receive.IpOptionsSupported));
1384 KdPrint((" V6Receive.TcpOptionsSupported = %d\n", nttic->V6Receive.TcpOptionsSupported));
1385 KdPrint((" V6Receive.TcpChecksum = %d\n", nttic->V6Receive.TcpChecksum));
1386 KdPrint((" V6Receive.UdpChecksum = %d\n", nttic->V6Receive.UdpChecksum));
1387 break;
1388 default:
1389 KdPrint((" Unknown Task %d\n", nto->Task));
1391 offset = nto->OffsetNextTask;
1393 break;
1394 default:
1395 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1396 status = NDIS_STATUS_NOT_SUPPORTED;
1397 break;
1399 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1400 return status;
1403 PMDL
1404 XenNet_Linearize(PNDIS_PACKET Packet)
1406 NDIS_STATUS status;
1407 PMDL pmdl;
1408 char *start;
1409 PNDIS_BUFFER buffer;
1410 PVOID buff_va;
1411 UINT buff_len;
1412 UINT tot_buff_len;
1414 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1416 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1417 &tot_buff_len, NormalPagePriority);
1418 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1420 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1421 if (!NT_SUCCESS(status))
1423 KdPrint(("Could not allocate memory for linearization\n"));
1424 return NULL;
1426 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1427 if (!pmdl)
1429 KdPrint(("Could not allocate MDL for linearization\n"));
1430 NdisFreeMemory(start, 0, 0);
1431 return NULL;
1433 MmBuildMdlForNonPagedPool(pmdl);
1435 while (buffer)
1437 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1438 RtlCopyMemory(start, buff_va, buff_len);
1439 start += buff_len;
1440 NdisGetNextBuffer(buffer, &buffer);
1443 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1444 return pmdl;
1447 VOID
1448 XenNet_SendQueuedPackets(struct xennet_info *xi)
1450 PLIST_ENTRY entry;
1451 PNDIS_PACKET packet;
1452 KIRQL OldIrql;
1453 struct netif_tx_request *tx;
1454 unsigned short id;
1455 int notify;
1456 PMDL pmdl;
1457 UINT pkt_size;
1459 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
1461 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1462 /* if empty, the above returns head*, not NULL */
1463 while (entry != &xi->tx_waiting_pkt_list)
1465 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[4]);
1467 NdisQueryPacket(packet, NULL, NULL, NULL, &pkt_size);
1468 pmdl = *(PMDL *)packet->MiniportReservedEx;
1470 id = get_id_from_freelist(xi);
1471 if (!id)
1473 /* whups, out of space on the ring. requeue and get out */
1474 InsertHeadList(&xi->tx_waiting_pkt_list, entry);
1475 break;
1477 xi->tx_pkts[id] = packet;
1479 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1480 tx->id = id;
1481 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1482 xi->XenInterface.InterfaceHeader.Context,
1483 0,
1484 *MmGetMdlPfnArray(pmdl),
1485 TRUE);
1486 xi->grant_tx_ref[id] = tx->gref;
1487 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1488 tx->size = (UINT16)pkt_size;
1489 // NETTXF_csum_blank should only be used for tcp and udp packets...
1490 tx->flags = 0; //NETTXF_csum_blank;
1492 xi->tx.req_prod_pvt++;
1494 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1497 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
1499 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1500 if (notify)
1502 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1503 xi->event_channel);
1507 VOID
1508 XenNet_SendPackets(
1509 IN NDIS_HANDLE MiniportAdapterContext,
1510 IN PPNDIS_PACKET PacketArray,
1511 IN UINT NumberOfPackets
1514 struct xennet_info *xi = MiniportAdapterContext;
1515 PNDIS_PACKET curr_packet;
1516 UINT i;
1517 PMDL pmdl;
1518 PLIST_ENTRY entry;
1520 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1522 for (i = 0; i < NumberOfPackets; i++)
1524 curr_packet = PacketArray[i];
1525 ASSERT(curr_packet);
1527 //KdPrint(("sending pkt, len %d\n", pkt_size));
1529 pmdl = XenNet_Linearize(curr_packet);
1530 if (!pmdl)
1532 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1533 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1534 break;
1537 /* NOTE:
1538 * We use the UCHAR[12] array in each packet's MiniportReservedEx thusly:
1539 * 0-3: PMDL to linearized data
1540 * 4-11: LIST_ENTRY for placing packet on the waiting pkt list
1541 */
1542 *(PMDL *)&curr_packet->MiniportReservedEx = pmdl;
1544 entry = (PLIST_ENTRY)&curr_packet->MiniportReservedEx[4];
1545 ExInterlockedInsertTailList(&xi->tx_waiting_pkt_list, entry, &xi->tx_lock);
1548 XenNet_SendQueuedPackets(xi);
1550 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1553 VOID
1554 XenNet_PnPEventNotify(
1555 IN NDIS_HANDLE MiniportAdapterContext,
1556 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1557 IN PVOID InformationBuffer,
1558 IN ULONG InformationBufferLength
1561 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1562 UNREFERENCED_PARAMETER(PnPEvent);
1563 UNREFERENCED_PARAMETER(InformationBuffer);
1564 UNREFERENCED_PARAMETER(InformationBufferLength);
1566 KdPrint((__FUNCTION__ " called\n"));
1569 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
1570 VOID
1571 XenNet_Shutdown(
1572 IN NDIS_HANDLE MiniportAdapterContext
1575 struct xennet_info *xi = MiniportAdapterContext;
1577 /* turn off interrupt */
1578 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
1579 xi->event_channel);
1581 KdPrint((__FUNCTION__ " called\n"));
1584 /* Opposite of XenNet_Init */
1585 XenNet_Halt(
1586 IN NDIS_HANDLE MiniportAdapterContext
1589 struct xennet_info *xi = MiniportAdapterContext;
1590 CHAR TmpPath[MAX_XENBUS_STR_LEN];
1592 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1593 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1595 // this disables the interrupt
1596 XenNet_Shutdown(xi);
1598 // set frontend state to 'closing'
1599 xi->state = XenbusStateClosing;
1600 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1601 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1602 XBT_NIL, TmpPath, "%d", xi->state);
1604 // wait for backend to set 'Closing' state
1606 while (xi->backend_state != XenbusStateClosing)
1607 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1609 // set frontend state to 'closed'
1610 xi->state = XenbusStateClosed;
1611 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1612 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1613 XBT_NIL, TmpPath, "%d", xi->state);
1615 // wait for backend to set 'Closed' state
1616 while (xi->backend_state != XenbusStateClosed)
1617 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1619 xi->connected = FALSE;
1621 /* wait for all receive buffers to be returned */
1622 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
1623 while (xi->rx_outstanding > 0)
1624 KeWaitForSingleObject(&xi->shutdown_event, Executive, KernelMode, FALSE, NULL);
1626 // TODO: remove event channel xenbus entry (how?)
1628 /* free TX resources */
1629 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1630 xi->tx_ring_ref);
1631 xi->tx_ring_ref = GRANT_INVALID_REF;
1632 FreePages(xi->tx_mdl);
1633 xi->tx_pgs = NULL;
1634 XenNet_TxBufferFree(xi);
1636 /* free RX resources */
1637 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1638 xi->rx_ring_ref);
1639 xi->rx_ring_ref = GRANT_INVALID_REF;
1640 FreePages(xi->rx_mdl);
1641 xi->rx_pgs = NULL;
1642 XenNet_RxBufferFree(MiniportAdapterContext);
1644 /* Remove watch on backend state */
1645 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
1646 xi->XenInterface.XenBus_RemWatch(xi->XenInterface.InterfaceHeader.Context,
1647 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
1649 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
1651 WdfDriverMiniportUnload(WdfGetDriver());
1653 NdisFreeBufferPool(xi->buffer_pool);
1654 NdisFreePacketPool(xi->packet_pool);
1655 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
1657 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1660 NTSTATUS
1661 DriverEntry(
1662 PDRIVER_OBJECT DriverObject,
1663 PUNICODE_STRING RegistryPath
1666 NTSTATUS status;
1667 WDF_DRIVER_CONFIG config;
1668 NDIS_HANDLE ndis_wrapper_handle;
1669 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1671 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1673 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1674 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1676 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1677 &config, WDF_NO_HANDLE);
1678 if (!NT_SUCCESS(status))
1680 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1681 return status;
1684 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1685 if (!ndis_wrapper_handle)
1687 KdPrint(("NdisMInitializeWrapper failed\n"));
1688 return NDIS_STATUS_FAILURE;
1691 /* NDIS 5.1 driver */
1692 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1693 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1695 mini_chars.HaltHandler = XenNet_Halt;
1696 mini_chars.InitializeHandler = XenNet_Init;
1697 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1698 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1699 mini_chars.ResetHandler = NULL; //TODO: fill in
1700 mini_chars.SetInformationHandler = XenNet_SetInformation;
1701 /* added in v.4 -- use multiple pkts interface */
1702 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1703 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1704 /* added in v.5.1 */
1705 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1706 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1708 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1710 /* set up upper-edge interface */
1711 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1712 if (!NT_SUCCESS(status))
1714 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1715 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1716 return status;
1719 return status;