win-pvdrivers

view xennet/xennet.c @ 148:4c4b14a2d516

xennet: check offload struct headers always, instead of with asserts. Caught by ndistest.
Clean up some warnings.
author Andy Grover <andy.grover@oracle.com>
date Wed Jan 23 11:58:03 2008 -0800 (2008-01-23)
parents 8d3f39a47293
children c8d4df1e1d12
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 _buffer_entry
47 {
48 char data[PAGE_SIZE - sizeof(LIST_ENTRY) - sizeof(PNDIS_BUFFER)];
49 LIST_ENTRY entry;
50 PNDIS_BUFFER buffer;
51 } typedef buffer_entry_t;
53 struct xennet_info
54 {
55 /* Base device vars */
56 PDEVICE_OBJECT pdo;
57 PDEVICE_OBJECT fdo;
58 PDEVICE_OBJECT lower_do;
59 WDFDEVICE wdf_device;
60 WCHAR dev_desc[NAME_SIZE];
62 /* NDIS-related vars */
63 NDIS_HANDLE adapter_handle;
64 NDIS_HANDLE packet_pool;
65 NDIS_HANDLE buffer_pool;
66 ULONG packet_filter;
67 int connected;
68 UINT8 perm_mac_addr[ETH_ALEN];
69 UINT8 curr_mac_addr[ETH_ALEN];
71 /* Misc. Xen vars */
72 XEN_IFACE XenInterface;
73 PXENPCI_XEN_DEVICE_DATA pdo_data;
74 evtchn_port_t event_channel;
75 ULONG state;
76 KEVENT backend_state_change_event;
77 KEVENT shutdown_event;
78 char backend_path[MAX_XENBUS_STR_LEN];
79 ULONG backend_state;
81 /* Xen ring-related vars */
82 KSPIN_LOCK rx_lock;
83 KSPIN_LOCK tx_lock;
85 LIST_ENTRY tx_waiting_pkt_list;
86 LIST_ENTRY rx_free_buf_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_RX_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] = IntToPtr(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;
195 PVOID ptr;
197 ASSERT(xi->connected);
199 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
201 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
203 do {
204 prod = xi->tx.sring->rsp_prod;
205 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
207 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
208 struct netif_tx_response *txrsp;
210 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
211 if (txrsp->status == NETIF_RSP_NULL)
212 continue;
214 id = txrsp->id;
215 pkt = xi->tx_pkts[id];
216 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
217 xi->grant_tx_ref[id]);
218 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
219 add_id_to_freelist(xi, id);
221 /* free linearized data page */
222 pmdl = *(PMDL *)pkt->MiniportReservedEx;
223 ptr = MmGetMdlVirtualAddress(pmdl);
224 IoFreeMdl(pmdl);
225 NdisFreeMemory(ptr, 0, 0); // <= DISPATCH_LEVEL
226 InterlockedDecrement(&xi->tx_outstanding);
227 xi->stat_tx_ok++;
228 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
229 }
231 xi->tx.rsp_cons = prod;
233 /*
234 * Set a new event, then check for race with update of tx_cons.
235 * Note that it is essential to schedule a callback, no matter
236 * how few buffers are pending. Even if there is space in the
237 * transmit ring, higher layers may be blocked because too much
238 * data is outstanding: in such cases notification from Xen is
239 * likely to be the only kick that we'll get.
240 */
241 xi->tx.sring->rsp_event =
242 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
243 KeMemoryBarrier();
244 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
246 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
248 /* if queued packets, send them now */
249 XenNet_SendQueuedPackets(xi);
251 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
253 return NDIS_STATUS_SUCCESS;
254 }
256 static void
257 XenNet_TxBufferFree(struct xennet_info *xi)
258 {
259 PNDIS_PACKET packet;
260 PMDL pmdl;
261 PLIST_ENTRY entry;
262 unsigned short id;
263 PVOID ptr;
265 ASSERT(!xi->connected);
267 /* Free packets in tx queue */
268 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
269 while (entry != &xi->tx_waiting_pkt_list)
270 {
271 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
273 /* free linearized data page */
274 pmdl = *(PMDL *)packet->MiniportReservedEx;
275 ptr = MmGetMdlVirtualAddress(pmdl);
276 IoFreeMdl(pmdl);
277 NdisFreeMemory(ptr, 0, 0); // <= DISPATCH_LEVEL
278 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
279 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
280 }
282 /* free sent-but-not-completed packets */
283 for (id = 1; id < NET_TX_RING_SIZE+1; id++) {
284 if (xi->grant_tx_ref[id] == GRANT_INVALID_REF)
285 continue;
287 packet = xi->tx_pkts[id];
288 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
289 xi->grant_tx_ref[id]);
290 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
291 add_id_to_freelist(xi, id);
293 /* free linearized data page */
294 pmdl = *(PMDL *)packet->MiniportReservedEx;
295 ptr = MmGetMdlVirtualAddress(pmdl);
296 IoFreeMdl(pmdl);
297 NdisFreeMemory(ptr, 0, 0); // <= DISPATCH_LEVEL
299 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
300 }
301 }
303 // Called at DISPATCH_LEVEL with no locks held
304 static NDIS_STATUS
305 XenNet_RxBufferAlloc(struct xennet_info *xi)
306 {
307 unsigned short id;
308 PNDIS_BUFFER buffer;
309 int i, batch_target, notify;
310 RING_IDX req_prod = xi->rx.req_prod_pvt;
311 grant_ref_t ref;
312 netif_rx_request_t *req;
313 // NDIS_STATUS status;
314 // PVOID start;
315 KIRQL OldIrql;
316 PLIST_ENTRY entry;
318 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
320 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
322 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
324 for (i = 0; i < batch_target; i++)
325 {
326 entry = RemoveHeadList(&xi->rx_free_buf_list);
327 if (entry == &xi->rx_free_buf_list)
328 break;
329 buffer = CONTAINING_RECORD(entry, buffer_entry_t, entry)->buffer;
331 /* Give to netback */
332 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
333 ASSERT(!xi->rx_buffers[id]);
334 xi->rx_buffers[id] = buffer;
335 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
336 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
337 ref = xi->XenInterface.GntTbl_GrantAccess(
338 xi->XenInterface.InterfaceHeader.Context, 0,
339 *MmGetMdlPfnArray(buffer), FALSE);
340 ASSERT((signed short)ref >= 0);
341 xi->grant_rx_ref[id] = ref;
343 req->id = id;
344 req->gref = ref;
345 }
347 xi->rx.req_prod_pvt = req_prod + i;
348 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
349 if (notify)
350 {
351 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
352 xi->event_channel);
353 }
355 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
357 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
359 return NDIS_STATUS_SUCCESS;
360 }
362 /* Free all Rx buffers (on halt, for example) */
363 static void
364 XenNet_RxBufferFree(struct xennet_info *xi)
365 {
366 int i;
367 grant_ref_t ref;
368 PNDIS_BUFFER buffer;
369 PNDIS_PACKET packet;
370 KIRQL OldIrql;
371 PVOID buff_va;
372 PLIST_ENTRY entry;
373 int ungranted;
375 ASSERT(!xi->connected);
377 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
379 for (i = 0; i < NET_RX_RING_SIZE; i++)
380 {
381 if (!xi->rx_buffers[i])
382 continue;
384 buffer = xi->rx_buffers[i];
385 ref = xi->grant_rx_ref[i];
387 /* don't check return, what can we do about it on failure? */
388 ungranted = xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context, ref);
390 NdisAdjustBufferLength(buffer, sizeof(buffer_entry_t));
391 buff_va = NdisBufferVirtualAddressSafe(buffer, NormalPagePriority);
392 NdisFreeBuffer(buffer);
393 if (ungranted)
394 {
395 NdisFreeMemory(buff_va, 0, 0); // <= DISPATCH_LEVEL
396 }
397 }
399 while ((entry = RemoveHeadList(&xi->rx_free_buf_list)) != &xi->rx_free_buf_list)
400 {
401 buffer = CONTAINING_RECORD(entry, buffer_entry_t, entry)->buffer;
402 NdisAdjustBufferLength(buffer, sizeof(buffer_entry_t));
403 buff_va = NdisBufferVirtualAddressSafe(buffer, NormalPagePriority);
404 NdisFreeBuffer(buffer);
405 NdisFreeMemory(buff_va, 0, 0); // <= DISPATCH_LEVEL
406 }
408 while ((entry = RemoveHeadList(&xi->rx_free_pkt_list)) != &xi->rx_free_pkt_list)
409 {
410 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
411 NdisFreePacket(packet);
412 }
414 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
415 }
417 VOID
418 XenNet_ReturnPacket(
419 IN NDIS_HANDLE MiniportAdapterContext,
420 IN PNDIS_PACKET Packet
421 )
422 {
423 struct xennet_info *xi = MiniportAdapterContext;
424 PNDIS_BUFFER buffer;
425 // PNDIS_BUFFER next_buffer;
426 // PVOID buff_va;
427 // UINT buff_len;
428 UINT tot_buff_len;
429 buffer_entry_t *buffer_entry;
431 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
433 NdisQueryPacketLength(Packet, &tot_buff_len);
434 // NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
435 // &tot_buff_len, NormalPagePriority);
436 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
437 // ASSERT(buff_va != NULL);
439 NdisUnchainBufferAtBack(Packet, &buffer);
440 while (buffer)
441 {
442 NdisAdjustBufferLength(buffer, sizeof(buffer_entry_t));
443 buffer_entry = NdisBufferVirtualAddressSafe(buffer, NormalPagePriority);
444 InsertTailList(&xi->rx_free_buf_list, &buffer_entry->entry);
445 NdisUnchainBufferAtBack(Packet, &buffer);
446 }
448 NdisReinitializePacket(Packet);
449 InsertTailList(&xi->rx_free_pkt_list, (PLIST_ENTRY)&Packet->MiniportReservedEx[sizeof(PVOID)]);
451 InterlockedDecrement(&xi->rx_outstanding);
453 // if we are no longer connected then _halt needs to know when rx_outstanding reaches zero
454 if (!xi->connected && !xi->rx_outstanding)
455 KeSetEvent(&xi->shutdown_event, 1, FALSE);
457 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
458 }
460 // Called at DISPATCH_LEVEL
461 static NDIS_STATUS
462 XenNet_RxBufferCheck(struct xennet_info *xi)
463 {
464 RING_IDX cons, prod;
465 PLIST_ENTRY entry;
466 PNDIS_PACKET packet = NULL;
467 PNDIS_BUFFER buffer;
468 int moretodo;
469 KIRQL OldIrql;
470 struct netif_rx_response *rxrsp = NULL;
471 int more_frags = 0;
472 UINT length;
474 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
476 ASSERT(xi->connected);
478 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
480 do {
481 prod = xi->rx.sring->rsp_prod;
482 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
484 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
485 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
486 ASSERT(rxrsp->status > 0);
488 if (!more_frags) // handling the packet's 1st buffer
489 {
490 entry = RemoveHeadList(&xi->rx_free_pkt_list);
491 ASSERT(entry != &xi->rx_free_pkt_list);
492 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
493 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
494 NdisQueryPacketLength(packet, &length);
495 }
497 buffer = xi->rx_buffers[rxrsp->id];
498 xi->rx_buffers[rxrsp->id] = NULL;
499 NdisAdjustBufferLength(buffer, rxrsp->status);
500 NdisChainBufferAtBack(packet, buffer);
501 NdisQueryPacketLength(packet, &length);
502 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
503 xi->grant_rx_ref[rxrsp->id]);
504 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
506 #if 0
507 KdPrint((__DRIVER_NAME " Flags = %sNETRXF_data_validated|%sNETRXF_csum_blank|%sNETRXF_more_data|%sNETRXF_extra_info\n",
508 (rxrsp->flags&NETRXF_data_validated)?"":"!",
509 (rxrsp->flags&NETRXF_csum_blank)?"":"!",
510 (rxrsp->flags&NETRXF_more_data)?"":"!",
511 (rxrsp->flags&NETRXF_extra_info)?"":"!"));
512 #endif
513 ASSERT(!(rxrsp->flags & NETRXF_extra_info)); // not used on RX
515 more_frags = rxrsp->flags & NETRXF_more_data;
517 /* Packet done, pass it up */
518 if (!more_frags)
519 {
520 xi->stat_rx_ok++;
521 InterlockedIncrement(&xi->rx_outstanding);
522 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
523 NdisMIndicateReceivePacket(xi->adapter_handle, &packet, 1);
524 }
525 }
526 xi->rx.rsp_cons = prod;
528 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
529 } while (moretodo);
531 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
533 if (more_frags)
534 {
535 KdPrint((__DRIVER_NAME " Missing fragments\n"));
536 XenNet_ReturnPacket(xi, packet);
537 }
539 /* Give netback more buffers */
540 XenNet_RxBufferAlloc(xi);
542 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
544 return NDIS_STATUS_SUCCESS;
545 }
547 // Called at DISPATCH_LEVEL
549 static BOOLEAN
550 XenNet_Interrupt(
551 PKINTERRUPT Interrupt,
552 PVOID ServiceContext
553 )
554 {
555 struct xennet_info *xi = ServiceContext;
557 UNREFERENCED_PARAMETER(Interrupt);
559 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
560 if (xi->connected)
561 {
562 XenNet_TxBufferGC(xi);
563 XenNet_RxBufferCheck(xi);
564 }
565 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
567 return TRUE;
568 }
570 // Called at <= DISPATCH_LEVEL
572 static VOID
573 XenNet_BackEndStateHandler(char *Path, PVOID Data)
574 {
575 struct xennet_info *xi = Data;
576 char *Value;
577 char *err;
578 ULONG new_backend_state;
580 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
581 // KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
583 err = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
584 XBT_NIL, Path, &Value);
585 if (err)
586 {
587 KdPrint(("Failed to read %s\n", Path, err));
588 return;
589 }
590 new_backend_state = atoi(Value);
591 xi->XenInterface.FreeMem(Value);
593 if (xi->backend_state == new_backend_state)
594 {
595 KdPrint((__DRIVER_NAME " state unchanged\n"));
596 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
597 return;
598 }
600 xi->backend_state = new_backend_state;
602 switch (xi->backend_state)
603 {
604 case XenbusStateUnknown:
605 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
606 break;
608 case XenbusStateInitialising:
609 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
610 break;
612 case XenbusStateInitWait:
613 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
614 break;
616 case XenbusStateInitialised:
617 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
618 break;
620 case XenbusStateConnected:
621 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
622 break;
624 case XenbusStateClosing:
625 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
626 break;
628 case XenbusStateClosed:
629 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
630 break;
632 default:
633 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
634 break;
635 }
637 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
639 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
641 return;
642 }
644 static NDIS_STATUS
645 XenNet_Init(
646 OUT PNDIS_STATUS OpenErrorStatus,
647 OUT PUINT SelectedMediumIndex,
648 IN PNDIS_MEDIUM MediumArray,
649 IN UINT MediumArraySize,
650 IN NDIS_HANDLE MiniportAdapterHandle,
651 IN NDIS_HANDLE WrapperConfigurationContext
652 )
653 {
654 NDIS_STATUS status;
655 UINT i;
656 BOOLEAN medium_found = FALSE;
657 struct xennet_info *xi = NULL;
658 ULONG length;
659 WDF_OBJECT_ATTRIBUTES wdf_attrs;
660 char *res;
661 char *Value;
662 char TmpPath[MAX_XENBUS_STR_LEN];
663 struct set_params {
664 char *name;
665 int value;
666 } params[] = {
667 {"tx-ring-ref", 0},
668 {"rx-ring-ref", 0},
669 {"event-channel", 0},
670 {"request-rx-copy", 1},
671 {"feature-rx-notify", 1},
672 {"feature-no-csum-offload", 1},
673 {"feature-sg", 1},
674 {"feature-gso-tcpv4", 0},
675 {NULL, 0},
676 };
677 int retry = 0;
678 char *err;
679 xenbus_transaction_t xbt = 0;
680 KIRQL OldIrql;
681 PNDIS_PACKET packet;
682 buffer_entry_t *buffer_entry;
683 PLIST_ENTRY entry;
685 UNREFERENCED_PARAMETER(OpenErrorStatus);
686 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
688 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
689 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
691 /* deal with medium stuff */
692 for (i = 0; i < MediumArraySize; i++)
693 {
694 if (MediumArray[i] == NdisMedium802_3)
695 {
696 medium_found = TRUE;
697 break;
698 }
699 }
700 if (!medium_found)
701 {
702 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
703 return NDIS_STATUS_UNSUPPORTED_MEDIA;
704 }
705 *SelectedMediumIndex = i;
707 /* Alloc memory for adapter private info */
708 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
709 if (!NT_SUCCESS(status))
710 {
711 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
712 status = NDIS_STATUS_RESOURCES;
713 goto err;
714 }
715 RtlZeroMemory(xi, sizeof(*xi));
717 /* init xennet_info */
718 xi->adapter_handle = MiniportAdapterHandle;
719 xi->rx_target = RX_DFL_MIN_TARGET;
720 xi->rx_min_target = RX_DFL_MIN_TARGET;
721 xi->rx_max_target = RX_MAX_TARGET;
723 xi->state = XenbusStateUnknown;
724 xi->backend_state = XenbusStateUnknown;
726 KeInitializeSpinLock(&xi->tx_lock);
727 KeInitializeSpinLock(&xi->rx_lock);
729 InitializeListHead(&xi->rx_free_buf_list);
730 InitializeListHead(&xi->rx_free_pkt_list);
731 InitializeListHead(&xi->tx_waiting_pkt_list);
733 NdisAllocatePacketPool(&status, &xi->packet_pool, XN_RX_QUEUE_LEN,
734 PROTOCOL_RESERVED_SIZE_IN_PACKET);
735 if (status != NDIS_STATUS_SUCCESS)
736 {
737 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
738 status = NDIS_STATUS_RESOURCES;
739 goto err;
740 }
741 NdisSetPacketPoolProtocolId(xi->packet_pool, NDIS_PROTOCOL_ID_TCP_IP);
743 NdisAllocateBufferPool(&status, &xi->buffer_pool, XN_RX_QUEUE_LEN);
744 if (status != NDIS_STATUS_SUCCESS)
745 {
746 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
747 status = NDIS_STATUS_RESOURCES;
748 goto err;
749 }
751 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
752 &xi->lower_do, NULL, NULL);
753 xi->pdo_data = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
755 /* Initialize tx_pkts as a free chain containing every entry. */
756 for (i = 0; i < NET_TX_RING_SIZE+1; i++) {
757 xi->tx_pkts[i] = IntToPtr(i + 1);
758 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
759 }
760 for (i = 0; i < NET_RX_RING_SIZE; i++) {
761 xi->rx_buffers[i] = NULL;
762 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
763 }
765 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
767 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
768 NAME_SIZE, xi->dev_desc, &length);
769 if (!NT_SUCCESS(status))
770 {
771 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
772 status = NDIS_STATUS_FAILURE;
773 goto err;
774 }
776 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
777 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
778 NdisInterfaceInternal);
780 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
782 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
783 xi->lower_do, xi->pdo, &xi->wdf_device);
784 if (!NT_SUCCESS(status))
785 {
786 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
787 status = NDIS_STATUS_FAILURE;
788 goto err;
789 }
791 /* get lower (Xen) interfaces */
793 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
794 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
795 if(!NT_SUCCESS(status))
796 {
797 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
798 status = NDIS_STATUS_FAILURE;
799 goto err;
800 }
802 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
803 "%s/backend", xi->pdo_data->Path);
804 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
805 XBT_NIL, TmpPath, &Value);
806 if (res)
807 {
808 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
809 xi->XenInterface.FreeMem(res);
810 status = NDIS_STATUS_FAILURE;
811 goto err;
812 }
813 RtlStringCbCopyA(xi->backend_path, ARRAY_SIZE(xi->backend_path), Value);
814 xi->XenInterface.FreeMem(Value);
815 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->backend_path));
817 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
818 KeInitializeEvent(&xi->shutdown_event, SynchronizationEvent, FALSE);
820 /* Add watch on backend state */
821 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
822 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
823 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
825 /* Tell backend we're coming up */
826 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
827 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
828 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
830 // wait here for signal that we are all set up
831 while (xi->backend_state != XenbusStateInitWait)
832 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
834 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
835 xi->XenInterface.InterfaceHeader.Context, 0);
836 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
837 xi->event_channel, XenNet_Interrupt, xi);
839 xi->tx_mdl = AllocatePage();
840 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl);
841 SHARED_RING_INIT(xi->tx_pgs);
842 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
843 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
844 xi->XenInterface.InterfaceHeader.Context, 0,
845 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
847 xi->rx_mdl = AllocatePage();
848 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl);
849 SHARED_RING_INIT(xi->rx_pgs);
850 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
851 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
852 xi->XenInterface.InterfaceHeader.Context, 0,
853 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
855 /* fixup array for dynamic values */
856 params[0].value = xi->tx_ring_ref;
857 params[1].value = xi->rx_ring_ref;
858 params[2].value = xi->event_channel;
859 xi->XenInterface.XenBus_StartTransaction(
860 xi->XenInterface.InterfaceHeader.Context, &xbt);
862 for (err = NULL, i = 0; params[i].name; i++)
863 {
864 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
865 xi->pdo_data->Path, params[i].name);
866 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
867 XBT_NIL, TmpPath, "%d", params[i].value);
868 if (err)
869 {
870 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
871 break;
872 }
873 }
875 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
876 xbt, 1, &retry);
877 if (err)
878 {
879 status = NDIS_STATUS_FAILURE;
880 goto err;
881 }
883 xi->connected = TRUE;
885 KeMemoryBarrier(); // packets could be received anytime after we set Frontent to Connected
887 xi->state = XenbusStateConnected;
888 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
889 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
890 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
891 XBT_NIL, TmpPath, "%d", xi->state);
893 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
895 // wait here for signal that we are all set up
896 while (xi->backend_state != XenbusStateConnected)
897 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
899 KdPrint((__DRIVER_NAME " Connected\n"));
901 KeAcquireSpinLock(&xi->rx_lock, &OldIrql);
903 for (i = 0; i < XN_RX_QUEUE_LEN; i++)
904 {
905 status = NdisAllocateMemoryWithTag(&buffer_entry, sizeof(buffer_entry_t), XENNET_POOL_TAG);
906 if (status != NDIS_STATUS_SUCCESS)
907 {
908 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
909 break;
910 }
911 NdisAllocateBuffer(&status, &buffer_entry->buffer, xi->buffer_pool, buffer_entry, sizeof(buffer_entry->data));
912 ASSERT(status == NDIS_STATUS_SUCCESS); // should never fail
913 InsertTailList(&xi->rx_free_buf_list, &buffer_entry->entry);
915 NdisAllocatePacket(&status, &packet, xi->packet_pool);
916 entry = (PLIST_ENTRY)&packet->MiniportReservedEx[sizeof(PVOID)];
917 InsertTailList(&xi->rx_free_pkt_list, entry);
918 }
920 KeReleaseSpinLock(&xi->rx_lock, OldIrql);
922 XenNet_RxBufferAlloc(xi);
924 /* get mac address */
925 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->backend_path);
926 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
927 XBT_NIL, TmpPath, &Value);
928 if (!Value)
929 {
930 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
931 status = NDIS_STATUS_FAILURE;
932 goto err;
933 }
934 else
935 {
936 char *s, *e;
937 s = Value;
938 for (i = 0; i < ETH_ALEN; i++) {
939 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
940 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
941 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
942 xi->XenInterface.FreeMem(Value);
943 status = NDIS_STATUS_FAILURE;
944 goto err;
945 }
946 s = e + 1;
947 }
948 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
949 xi->XenInterface.FreeMem(Value);
950 }
952 /* send fake arp? */
954 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
956 return NDIS_STATUS_SUCCESS;
958 err:
959 NdisFreeMemory(xi, 0, 0);
960 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
961 return status;
962 }
964 // Q = Query Mandatory, S = Set Mandatory
965 NDIS_OID supported_oids[] =
966 {
967 /* general OIDs */
968 OID_GEN_SUPPORTED_LIST, // Q
969 OID_GEN_HARDWARE_STATUS, // Q
970 OID_GEN_MEDIA_SUPPORTED, // Q
971 OID_GEN_MEDIA_IN_USE, // Q
972 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
973 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
974 OID_GEN_LINK_SPEED, // Q
975 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
976 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
977 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
978 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
979 OID_GEN_VENDOR_ID, // Q
980 OID_GEN_VENDOR_DESCRIPTION, // Q
981 OID_GEN_CURRENT_PACKET_FILTER, // QS
982 OID_GEN_CURRENT_LOOKAHEAD, // QS
983 OID_GEN_DRIVER_VERSION, // Q
984 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
985 OID_GEN_PROTOCOL_OPTIONS, // S
986 OID_GEN_MAC_OPTIONS, // Q
987 OID_GEN_MEDIA_CONNECT_STATUS, // Q
988 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
989 /* stats */
990 OID_GEN_XMIT_OK, // Q
991 OID_GEN_RCV_OK, // Q
992 OID_GEN_XMIT_ERROR, // Q
993 OID_GEN_RCV_ERROR, // Q
994 OID_GEN_RCV_NO_BUFFER, // Q
995 /* media-specific OIDs */
996 OID_802_3_PERMANENT_ADDRESS,
997 OID_802_3_CURRENT_ADDRESS,
998 OID_802_3_MULTICAST_LIST,
999 OID_802_3_MAXIMUM_LIST_SIZE,
1000 /* tcp offload */
1001 OID_TCP_TASK_OFFLOAD,
1002 };
1004 /* return 4 or 8 depending on size of buffer */
1005 #define HANDLE_STAT_RETURN \
1006 {if (InformationBufferLength == 4) { \
1007 len = 4; *BytesNeeded = 8; \
1008 } else { \
1009 len = 8; \
1010 } }
1012 //#define OFFLOAD_LARGE_SEND
1014 NDIS_STATUS
1015 XenNet_QueryInformation(
1016 IN NDIS_HANDLE MiniportAdapterContext,
1017 IN NDIS_OID Oid,
1018 IN PVOID InformationBuffer,
1019 IN ULONG InformationBufferLength,
1020 OUT PULONG BytesWritten,
1021 OUT PULONG BytesNeeded)
1023 struct xennet_info *xi = MiniportAdapterContext;
1024 UCHAR vendor_desc[] = XN_VENDOR_DESC;
1025 ULONG64 temp_data;
1026 PVOID data = &temp_data;
1027 UINT len = 4;
1028 BOOLEAN used_temp_buffer = TRUE;
1029 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
1030 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1031 PNDIS_TASK_OFFLOAD nto;
1032 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1033 #ifdef OFFLOAD_LARGE_SEND
1034 PNDIS_TASK_TCP_LARGE_SEND nttls;
1035 #endif
1037 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1039 switch(Oid)
1041 case OID_GEN_SUPPORTED_LIST:
1042 data = supported_oids;
1043 len = sizeof(supported_oids);
1044 break;
1045 case OID_GEN_HARDWARE_STATUS:
1046 if (!xi->connected)
1047 temp_data = NdisHardwareStatusInitializing;
1048 else
1049 temp_data = NdisHardwareStatusReady;
1050 break;
1051 case OID_GEN_MEDIA_SUPPORTED:
1052 temp_data = NdisMedium802_3;
1053 break;
1054 case OID_GEN_MEDIA_IN_USE:
1055 temp_data = NdisMedium802_3;
1056 break;
1057 case OID_GEN_MAXIMUM_LOOKAHEAD:
1058 temp_data = XN_DATA_SIZE;
1059 break;
1060 case OID_GEN_MAXIMUM_FRAME_SIZE:
1061 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
1062 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
1063 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
1064 break;
1065 case OID_GEN_LINK_SPEED:
1066 temp_data = 10000000; /* 1Gb */
1067 break;
1068 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1069 /* pkts times sizeof ring, maybe? */
1070 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
1071 break;
1072 case OID_GEN_RECEIVE_BUFFER_SPACE:
1073 /* pkts times sizeof ring, maybe? */
1074 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
1075 break;
1076 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1077 temp_data = XN_MAX_PKT_SIZE;
1078 break;
1079 case OID_GEN_RECEIVE_BLOCK_SIZE:
1080 temp_data = XN_MAX_PKT_SIZE;
1081 break;
1082 case OID_GEN_VENDOR_ID:
1083 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
1084 break;
1085 case OID_GEN_VENDOR_DESCRIPTION:
1086 data = vendor_desc;
1087 len = sizeof(vendor_desc);
1088 break;
1089 case OID_GEN_CURRENT_PACKET_FILTER:
1090 temp_data = xi->packet_filter;
1091 break;
1092 case OID_GEN_CURRENT_LOOKAHEAD:
1093 // TODO: we should store this...
1094 temp_data = XN_MAX_PKT_SIZE;
1095 break;
1096 case OID_GEN_DRIVER_VERSION:
1097 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
1098 len = 2;
1099 break;
1100 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1101 temp_data = XN_MAX_PKT_SIZE;
1102 break;
1103 case OID_GEN_MAC_OPTIONS:
1104 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
1105 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
1106 NDIS_MAC_OPTION_NO_LOOPBACK;
1107 break;
1108 case OID_GEN_MEDIA_CONNECT_STATUS:
1109 if (xi->connected)
1110 temp_data = NdisMediaStateConnected;
1111 else
1112 temp_data = NdisMediaStateDisconnected;
1113 break;
1114 case OID_GEN_MAXIMUM_SEND_PACKETS:
1115 temp_data = XN_MAX_SEND_PKTS;
1116 break;
1117 case OID_GEN_XMIT_OK:
1118 temp_data = xi->stat_tx_ok;
1119 HANDLE_STAT_RETURN;
1120 break;
1121 case OID_GEN_RCV_OK:
1122 temp_data = xi->stat_rx_ok;
1123 HANDLE_STAT_RETURN;
1124 break;
1125 case OID_GEN_XMIT_ERROR:
1126 temp_data = xi->stat_tx_error;
1127 HANDLE_STAT_RETURN;
1128 break;
1129 case OID_GEN_RCV_ERROR:
1130 temp_data = xi->stat_rx_error;
1131 HANDLE_STAT_RETURN;
1132 break;
1133 case OID_GEN_RCV_NO_BUFFER:
1134 temp_data = xi->stat_rx_no_buffer;
1135 HANDLE_STAT_RETURN;
1136 break;
1137 case OID_802_3_PERMANENT_ADDRESS:
1138 data = xi->perm_mac_addr;
1139 len = ETH_ALEN;
1140 break;
1141 case OID_802_3_CURRENT_ADDRESS:
1142 data = xi->curr_mac_addr;
1143 len = ETH_ALEN;
1144 break;
1145 case OID_802_3_MULTICAST_LIST:
1146 data = NULL;
1147 len = 0;
1148 case OID_802_3_MAXIMUM_LIST_SIZE:
1149 temp_data = 0; /* no mcast support */
1150 break;
1151 case OID_TCP_TASK_OFFLOAD:
1152 KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
1153 /* it's times like this that C really sucks */
1155 len = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1157 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1158 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1159 #ifdef OFFLOAD_LARGE_SEND
1160 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1161 + sizeof(NDIS_TASK_TCP_LARGE_SEND);
1162 #endif
1164 if (len > InformationBufferLength)
1166 break;
1169 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1170 if (ntoh->Version != NDIS_TASK_OFFLOAD_VERSION
1171 || ntoh->Size != sizeof(*ntoh)
1172 || ntoh->EncapsulationFormat.Encapsulation != IEEE_802_3_Encapsulation)
1174 status = NDIS_STATUS_NOT_SUPPORTED;
1175 break;
1177 ntoh->OffsetFirstTask = ntoh->Size;
1179 /* fill in first nto */
1180 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
1181 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1182 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1183 nto->Task = TcpIpChecksumNdisTask;
1184 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1186 /* fill in checksum offload struct */
1187 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1188 nttic->V4Transmit.IpOptionsSupported = 0;
1189 nttic->V4Transmit.TcpOptionsSupported = 0;
1190 nttic->V4Transmit.TcpChecksum = 0;
1191 nttic->V4Transmit.UdpChecksum = 0;
1192 nttic->V4Transmit.IpChecksum = 0;
1193 nttic->V4Receive.IpOptionsSupported = 1;
1194 nttic->V4Receive.TcpOptionsSupported = 1;
1195 nttic->V4Receive.TcpChecksum = 1;
1196 nttic->V4Receive.UdpChecksum = 1;
1197 nttic->V4Receive.IpChecksum = 1;
1198 nttic->V6Transmit.IpOptionsSupported = 0;
1199 nttic->V6Transmit.TcpOptionsSupported = 0;
1200 nttic->V6Transmit.TcpChecksum = 0;
1201 nttic->V6Transmit.UdpChecksum = 0;
1202 nttic->V6Receive.IpOptionsSupported = 0;
1203 nttic->V6Receive.TcpOptionsSupported = 0;
1204 nttic->V6Receive.TcpChecksum = 0;
1205 nttic->V6Receive.UdpChecksum = 0;
1207 #ifdef OFFLOAD_LARGE_SEND
1208 /* offset from start of current NTO to start of next NTO */
1209 nto->OffsetNextTask = FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1210 + nto->TaskBufferLength;
1212 /* fill in second nto */
1213 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
1214 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1215 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1216 nto->Task = TcpLargeSendNdisTask;
1217 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
1219 /* fill in large send struct */
1220 nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
1221 nttls->Version = 0;
1222 nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
1223 nttls->MinSegmentCount = 4; /* also made up */
1224 nttls->TcpOptions = FALSE;
1225 nttls->IpOptions = FALSE;
1226 #endif
1227 nto->OffsetNextTask = 0; /* last one */
1229 used_temp_buffer = FALSE;
1230 break;
1231 default:
1232 KdPrint(("Get Unknown OID 0x%x\n", Oid));
1233 status = NDIS_STATUS_NOT_SUPPORTED;
1236 if (!NT_SUCCESS(status))
1238 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
1239 return status;
1242 if (len > InformationBufferLength)
1244 *BytesNeeded = len;
1245 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (BUFFER_TOO_SHORT)\n"));
1246 return NDIS_STATUS_BUFFER_TOO_SHORT;
1249 *BytesWritten = len;
1250 if (len && used_temp_buffer)
1252 NdisMoveMemory((PUCHAR)InformationBuffer, data, len);
1255 //KdPrint(("Got OID 0x%x\n", Oid));
1256 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1258 return status;
1261 NDIS_STATUS
1262 XenNet_SetInformation(
1263 IN NDIS_HANDLE MiniportAdapterContext,
1264 IN NDIS_OID Oid,
1265 IN PVOID InformationBuffer,
1266 IN ULONG InformationBufferLength,
1267 OUT PULONG BytesRead,
1268 OUT PULONG BytesNeeded
1271 NTSTATUS status;
1272 struct xennet_info *xi = MiniportAdapterContext;
1273 PULONG64 data = InformationBuffer;
1274 PNDIS_TASK_OFFLOAD_HEADER ntoh;
1275 PNDIS_TASK_OFFLOAD nto;
1276 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
1277 int offset;
1279 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1281 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1282 UNREFERENCED_PARAMETER(InformationBufferLength);
1283 UNREFERENCED_PARAMETER(BytesRead);
1284 UNREFERENCED_PARAMETER(BytesNeeded);
1286 switch(Oid)
1288 case OID_GEN_SUPPORTED_LIST:
1289 status = NDIS_STATUS_NOT_SUPPORTED;
1290 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1291 break;
1292 case OID_GEN_HARDWARE_STATUS:
1293 status = NDIS_STATUS_NOT_SUPPORTED;
1294 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1295 break;
1296 case OID_GEN_MEDIA_SUPPORTED:
1297 status = NDIS_STATUS_NOT_SUPPORTED;
1298 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1299 break;
1300 case OID_GEN_MEDIA_IN_USE:
1301 status = NDIS_STATUS_NOT_SUPPORTED;
1302 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1303 break;
1304 case OID_GEN_MAXIMUM_LOOKAHEAD:
1305 status = NDIS_STATUS_NOT_SUPPORTED;
1306 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1307 break;
1308 case OID_GEN_MAXIMUM_FRAME_SIZE:
1309 status = NDIS_STATUS_NOT_SUPPORTED;
1310 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1311 break;
1312 case OID_GEN_LINK_SPEED:
1313 status = NDIS_STATUS_NOT_SUPPORTED;
1314 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1315 break;
1316 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1317 status = NDIS_STATUS_NOT_SUPPORTED;
1318 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1319 break;
1320 case OID_GEN_RECEIVE_BUFFER_SPACE:
1321 status = NDIS_STATUS_NOT_SUPPORTED;
1322 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1323 break;
1324 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1325 status = NDIS_STATUS_NOT_SUPPORTED;
1326 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1327 break;
1328 case OID_GEN_RECEIVE_BLOCK_SIZE:
1329 status = NDIS_STATUS_NOT_SUPPORTED;
1330 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1331 break;
1332 case OID_GEN_VENDOR_ID:
1333 status = NDIS_STATUS_NOT_SUPPORTED;
1334 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1335 break;
1336 case OID_GEN_VENDOR_DESCRIPTION:
1337 status = NDIS_STATUS_NOT_SUPPORTED;
1338 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1339 break;
1340 case OID_GEN_CURRENT_PACKET_FILTER:
1341 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1342 xi->packet_filter = *(ULONG *)data;
1343 status = NDIS_STATUS_SUCCESS;
1344 break;
1345 case OID_GEN_CURRENT_LOOKAHEAD:
1346 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1347 // TODO: We should do this...
1348 status = NDIS_STATUS_SUCCESS;
1349 break;
1350 case OID_GEN_DRIVER_VERSION:
1351 status = NDIS_STATUS_NOT_SUPPORTED;
1352 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1353 break;
1354 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1355 status = NDIS_STATUS_NOT_SUPPORTED;
1356 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1357 break;
1358 case OID_GEN_PROTOCOL_OPTIONS:
1359 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1360 // TODO - actually do this...
1361 status = NDIS_STATUS_SUCCESS;
1362 break;
1363 case OID_GEN_MAC_OPTIONS:
1364 status = NDIS_STATUS_NOT_SUPPORTED;
1365 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1366 break;
1367 case OID_GEN_MEDIA_CONNECT_STATUS:
1368 status = NDIS_STATUS_NOT_SUPPORTED;
1369 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1370 break;
1371 case OID_GEN_MAXIMUM_SEND_PACKETS:
1372 status = NDIS_STATUS_NOT_SUPPORTED;
1373 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1374 break;
1375 case OID_GEN_XMIT_OK:
1376 status = NDIS_STATUS_NOT_SUPPORTED;
1377 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1378 break;
1379 case OID_GEN_RCV_OK:
1380 status = NDIS_STATUS_NOT_SUPPORTED;
1381 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1382 break;
1383 case OID_GEN_XMIT_ERROR:
1384 status = NDIS_STATUS_NOT_SUPPORTED;
1385 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1386 break;
1387 case OID_GEN_RCV_ERROR:
1388 status = NDIS_STATUS_NOT_SUPPORTED;
1389 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1390 break;
1391 case OID_GEN_RCV_NO_BUFFER:
1392 status = NDIS_STATUS_NOT_SUPPORTED;
1393 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1394 break;
1395 case OID_802_3_PERMANENT_ADDRESS:
1396 status = NDIS_STATUS_NOT_SUPPORTED;
1397 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1398 break;
1399 case OID_802_3_CURRENT_ADDRESS:
1400 status = NDIS_STATUS_NOT_SUPPORTED;
1401 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1402 break;
1403 case OID_802_3_MULTICAST_LIST:
1404 status = NDIS_STATUS_NOT_SUPPORTED;
1405 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1406 break;
1407 case OID_802_3_MAXIMUM_LIST_SIZE:
1408 status = NDIS_STATUS_NOT_SUPPORTED;
1409 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1410 break;
1411 case OID_TCP_TASK_OFFLOAD:
1412 // Just fake this for now... ultimately we need to manually calc rx checksum if offload is disabled by windows
1413 status = NDIS_STATUS_SUCCESS;
1414 KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
1415 // we should disable everything here, then enable what has been set
1416 ntoh = (PNDIS_TASK_OFFLOAD_HEADER)InformationBuffer;
1417 *BytesRead = sizeof(NDIS_TASK_OFFLOAD_HEADER);
1418 offset = ntoh->OffsetFirstTask;
1419 nto = (PNDIS_TASK_OFFLOAD)ntoh; // not really, just to get the first offset right
1420 while (offset != 0)
1422 *BytesRead += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer);
1423 nto = (PNDIS_TASK_OFFLOAD)(((PUCHAR)nto) + offset);
1424 switch (nto->Task)
1426 case TcpIpChecksumNdisTask:
1427 *BytesRead += sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1428 KdPrint(("TcpIpChecksumNdisTask\n"));
1429 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1430 KdPrint((" V4Transmit.IpOptionsSupported = %d\n", nttic->V4Transmit.IpOptionsSupported));
1431 KdPrint((" V4Transmit.TcpOptionsSupported = %d\n", nttic->V4Transmit.TcpOptionsSupported));
1432 KdPrint((" V4Transmit.TcpChecksum = %d\n", nttic->V4Transmit.TcpChecksum));
1433 KdPrint((" V4Transmit.UdpChecksum = %d\n", nttic->V4Transmit.UdpChecksum));
1434 KdPrint((" V4Transmit.IpChecksum = %d\n", nttic->V4Transmit.IpChecksum));
1435 KdPrint((" V4Receive.IpOptionsSupported = %d\n", nttic->V4Receive.IpOptionsSupported));
1436 KdPrint((" V4Receive.TcpOptionsSupported = %d\n", nttic->V4Receive.TcpOptionsSupported));
1437 KdPrint((" V4Receive.TcpChecksum = %d\n", nttic->V4Receive.TcpChecksum));
1438 KdPrint((" V4Receive.UdpChecksum = %d\n", nttic->V4Receive.UdpChecksum));
1439 KdPrint((" V4Receive.IpChecksum = %d\n", nttic->V4Receive.IpChecksum));
1440 KdPrint((" V6Transmit.IpOptionsSupported = %d\n", nttic->V6Transmit.IpOptionsSupported));
1441 KdPrint((" V6Transmit.TcpOptionsSupported = %d\n", nttic->V6Transmit.TcpOptionsSupported));
1442 KdPrint((" V6Transmit.TcpChecksum = %d\n", nttic->V6Transmit.TcpChecksum));
1443 KdPrint((" V6Transmit.UdpChecksum = %d\n", nttic->V6Transmit.UdpChecksum));
1444 KdPrint((" V6Receive.IpOptionsSupported = %d\n", nttic->V6Receive.IpOptionsSupported));
1445 KdPrint((" V6Receive.TcpOptionsSupported = %d\n", nttic->V6Receive.TcpOptionsSupported));
1446 KdPrint((" V6Receive.TcpChecksum = %d\n", nttic->V6Receive.TcpChecksum));
1447 KdPrint((" V6Receive.UdpChecksum = %d\n", nttic->V6Receive.UdpChecksum));
1448 break;
1449 default:
1450 KdPrint((" Unknown Task %d\n", nto->Task));
1452 offset = nto->OffsetNextTask;
1454 break;
1455 default:
1456 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1457 status = NDIS_STATUS_NOT_SUPPORTED;
1458 break;
1460 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1461 return status;
1464 PMDL
1465 XenNet_Linearize(PNDIS_PACKET Packet)
1467 NDIS_STATUS status;
1468 PMDL pmdl;
1469 char *start;
1470 PNDIS_BUFFER buffer;
1471 PVOID buff_va;
1472 UINT buff_len;
1473 UINT tot_buff_len;
1475 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1477 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1478 &tot_buff_len, NormalPagePriority);
1479 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1481 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
1482 if (!NT_SUCCESS(status))
1484 KdPrint(("Could not allocate memory for linearization\n"));
1485 return NULL;
1488 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, NULL);
1489 if (!pmdl)
1491 KdPrint(("Could not allocate MDL for linearization\n"));
1492 NdisFreeMemory(start, 0, 0);
1493 return NULL;
1495 MmBuildMdlForNonPagedPool(pmdl);
1497 while (buffer)
1499 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1500 RtlCopyMemory(start, buff_va, buff_len);
1501 start += buff_len;
1502 NdisGetNextBuffer(buffer, &buffer);
1505 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1506 return pmdl;
1509 VOID
1510 XenNet_SendQueuedPackets(struct xennet_info *xi)
1512 PLIST_ENTRY entry;
1513 PNDIS_PACKET packet;
1514 KIRQL OldIrql;
1515 struct netif_tx_request *tx;
1516 unsigned short id;
1517 int notify;
1518 PMDL pmdl;
1519 UINT pkt_size;
1521 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
1523 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1524 /* if empty, the above returns head*, not NULL */
1525 while (entry != &xi->tx_waiting_pkt_list)
1527 packet = CONTAINING_RECORD(entry, NDIS_PACKET, MiniportReservedEx[sizeof(PVOID)]);
1529 NdisQueryPacket(packet, NULL, NULL, NULL, &pkt_size);
1530 pmdl = *(PMDL *)packet->MiniportReservedEx;
1532 id = get_id_from_freelist(xi);
1533 if (!id)
1535 /* whups, out of space on the ring. requeue and get out */
1536 InsertHeadList(&xi->tx_waiting_pkt_list, entry);
1537 break;
1539 xi->tx_pkts[id] = packet;
1541 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1542 tx->id = id;
1543 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1544 xi->XenInterface.InterfaceHeader.Context,
1545 0,
1546 *MmGetMdlPfnArray(pmdl),
1547 TRUE);
1548 xi->grant_tx_ref[id] = tx->gref;
1549 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1550 tx->size = (UINT16)pkt_size;
1551 // NETTXF_csum_blank should only be used for tcp and udp packets...
1552 tx->flags = 0; //NETTXF_csum_blank;
1554 xi->tx.req_prod_pvt++;
1556 entry = RemoveHeadList(&xi->tx_waiting_pkt_list);
1559 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
1561 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1562 if (notify)
1564 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1565 xi->event_channel);
1569 VOID
1570 XenNet_SendPackets(
1571 IN NDIS_HANDLE MiniportAdapterContext,
1572 IN PPNDIS_PACKET PacketArray,
1573 IN UINT NumberOfPackets
1576 struct xennet_info *xi = MiniportAdapterContext;
1577 PNDIS_PACKET curr_packet;
1578 UINT i;
1579 PMDL pmdl;
1580 PLIST_ENTRY entry;
1581 KIRQL OldIrql;
1583 #if 0
1584 for (i = 0; i < NumberOfPackets; i++)
1586 curr_packet = PacketArray[i];
1587 NdisMSendComplete(xi->adapter_handle, curr_packet, NDIS_STATUS_FAILURE);
1589 return;
1590 #endif
1592 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1593 for (i = 0; i < NumberOfPackets; i++)
1595 curr_packet = PacketArray[i];
1596 ASSERT(curr_packet);
1598 //KdPrint(("sending pkt, len %d\n", pkt_size));
1600 pmdl = XenNet_Linearize(curr_packet);
1601 if (!pmdl)
1603 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1604 NdisMSendComplete(xi->adapter_handle, curr_packet, NDIS_STATUS_FAILURE);
1605 break;
1608 /* NOTE:
1609 * We use the UCHAR[3*sizeof(PVOID)] array in each packet's MiniportReservedEx thusly:
1610 * 0: PMDL to linearized data
1611 * sizeof(PVOID)+: LIST_ENTRY for placing packet on the waiting pkt list
1612 */
1613 *(PMDL *)&curr_packet->MiniportReservedEx = pmdl;
1615 entry = (PLIST_ENTRY)&curr_packet->MiniportReservedEx[sizeof(PVOID)];
1616 KeAcquireSpinLock(&xi->tx_lock, &OldIrql);
1617 InsertTailList(&xi->tx_waiting_pkt_list, entry);
1618 KeReleaseSpinLock(&xi->tx_lock, OldIrql);
1619 InterlockedIncrement(&xi->tx_outstanding);
1621 XenNet_SendQueuedPackets(xi);
1622 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1625 VOID
1626 XenNet_PnPEventNotify(
1627 IN NDIS_HANDLE MiniportAdapterContext,
1628 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1629 IN PVOID InformationBuffer,
1630 IN ULONG InformationBufferLength
1633 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1634 UNREFERENCED_PARAMETER(PnPEvent);
1635 UNREFERENCED_PARAMETER(InformationBuffer);
1636 UNREFERENCED_PARAMETER(InformationBufferLength);
1638 KdPrint((__FUNCTION__ " called\n"));
1641 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
1642 VOID
1643 XenNet_Shutdown(
1644 IN NDIS_HANDLE MiniportAdapterContext
1647 struct xennet_info *xi = MiniportAdapterContext;
1649 /* turn off interrupt */
1650 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
1651 xi->event_channel);
1653 KdPrint((__FUNCTION__ " called\n"));
1656 /* Opposite of XenNet_Init */
1657 VOID
1658 XenNet_Halt(
1659 IN NDIS_HANDLE MiniportAdapterContext
1662 struct xennet_info *xi = MiniportAdapterContext;
1663 CHAR TmpPath[MAX_XENBUS_STR_LEN];
1664 PVOID if_cxt = xi->XenInterface.InterfaceHeader.Context;
1666 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1667 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1669 // set frontend state to 'closing'
1670 xi->state = XenbusStateClosing;
1671 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1672 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
1674 // wait for backend to set 'Closing' state
1676 while (xi->backend_state != XenbusStateClosing)
1677 KeWaitForSingleObject(&xi->backend_state_change_event, Executive,
1678 KernelMode, FALSE, NULL);
1680 // set frontend state to 'closed'
1681 xi->state = XenbusStateClosed;
1682 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1683 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
1685 // wait for backend to set 'Closed' state
1686 while (xi->backend_state != XenbusStateClosed)
1687 KeWaitForSingleObject(&xi->backend_state_change_event, Executive,
1688 KernelMode, FALSE, NULL);
1690 // set frontend state to 'Initialising'
1691 xi->state = XenbusStateInitialising;
1692 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdo_data->Path);
1693 xi->XenInterface.XenBus_Printf(if_cxt, XBT_NIL, TmpPath, "%d", xi->state);
1695 // wait for backend to set 'InitWait' state
1696 while (xi->backend_state != XenbusStateInitWait)
1697 KeWaitForSingleObject(&xi->backend_state_change_event, Executive,
1698 KernelMode, FALSE, NULL);
1700 // this disables the interrupt
1701 XenNet_Shutdown(xi);
1703 xi->connected = FALSE;
1704 KeMemoryBarrier(); /* make sure everyone sees that we are now shut down */
1706 /* wait for all receive buffers to be returned */
1707 while (xi->rx_outstanding > 0)
1708 KeWaitForSingleObject(&xi->shutdown_event, Executive, KernelMode, FALSE, NULL);
1710 // TODO: remove event channel xenbus entry (how?)
1712 /* free TX resources */
1713 if (xi->XenInterface.GntTbl_EndAccess(if_cxt, xi->tx_ring_ref))
1715 xi->tx_ring_ref = GRANT_INVALID_REF;
1716 FreePages(xi->tx_mdl);
1718 /* if EndAccess fails then tx/rx ring pages LEAKED -- it's not safe to reuse
1719 pages Dom0 still has access to */
1720 xi->tx_pgs = NULL;
1722 /* free RX resources */
1723 if (xi->XenInterface.GntTbl_EndAccess(if_cxt, xi->rx_ring_ref))
1725 xi->rx_ring_ref = GRANT_INVALID_REF;
1726 FreePages(xi->rx_mdl);
1728 xi->rx_pgs = NULL;
1730 XenNet_TxBufferFree(xi);
1731 XenNet_RxBufferFree(MiniportAdapterContext);
1733 /* Remove watch on backend state */
1734 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->backend_path);
1735 xi->XenInterface.XenBus_RemWatch(if_cxt, XBT_NIL, TmpPath,
1736 XenNet_BackEndStateHandler, xi);
1738 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
1740 NdisFreeBufferPool(xi->buffer_pool);
1741 NdisFreePacketPool(xi->packet_pool);
1743 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
1745 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1748 VOID
1749 XenNet_Unload(
1750 PDRIVER_OBJECT DriverObject
1753 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1755 UNREFERENCED_PARAMETER(DriverObject);
1757 WdfDriverMiniportUnload(WdfGetDriver());
1759 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1762 NTSTATUS
1763 DriverEntry(
1764 PDRIVER_OBJECT DriverObject,
1765 PUNICODE_STRING RegistryPath
1768 NTSTATUS status;
1769 WDF_DRIVER_CONFIG config;
1770 NDIS_HANDLE ndis_wrapper_handle;
1771 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1773 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1775 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1776 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1778 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1779 &config, WDF_NO_HANDLE);
1780 if (!NT_SUCCESS(status))
1782 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1783 return status;
1786 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1787 if (!ndis_wrapper_handle)
1789 KdPrint(("NdisMInitializeWrapper failed\n"));
1790 return NDIS_STATUS_FAILURE;
1793 /* NDIS 5.1 driver */
1794 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1795 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1797 mini_chars.HaltHandler = XenNet_Halt;
1798 mini_chars.InitializeHandler = XenNet_Init;
1799 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1800 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1801 mini_chars.ResetHandler = NULL; //TODO: fill in
1802 mini_chars.SetInformationHandler = XenNet_SetInformation;
1803 /* added in v.4 -- use multiple pkts interface */
1804 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1805 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1806 /* added in v.5.1 */
1807 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1808 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1810 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1812 /* set up upper-edge interface */
1813 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1814 if (!NT_SUCCESS(status))
1816 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1817 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1818 return status;
1821 NdisMRegisterUnloadHandler(ndis_wrapper_handle, XenNet_Unload);
1823 return status;