win-pvdrivers

view xennet/xennet.c @ 91:24963c2b7846

xennet: break up tx and rx locks to prevent recursive acquire
author Andy Grover <andy.grover@oracle.com>
date Wed Jan 02 16:52:52 2008 -0800 (2008-01-02)
parents 93879f914f05
children b55f4ed508b0
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 PDEVICE_OBJECT pdo;
49 PDEVICE_OBJECT fdo;
50 PDEVICE_OBJECT lower_do;
51 WDFDEVICE wdf_device;
52 PXENPCI_XEN_DEVICE_DATA pdoData;
54 WCHAR name[NAME_SIZE];
55 NDIS_HANDLE adapter_handle;
56 ULONG packet_filter;
57 int connected;
58 UINT8 perm_mac_addr[ETH_ALEN];
59 UINT8 curr_mac_addr[ETH_ALEN];
61 // char Path[128];
62 char BackendPath[128];
63 XEN_IFACE XenInterface;
65 /* ring control structures */
66 struct netif_tx_front_ring tx;
67 struct netif_rx_front_ring rx;
69 /* ptrs to the actual rings themselvves */
70 struct netif_tx_sring *tx_pgs;
71 struct netif_rx_sring *rx_pgs;
73 /* MDLs for the above */
74 PMDL tx_mdl;
75 PMDL rx_mdl;
77 /* Outstanding packets. The first entry in tx_pkts
78 * is an index into a chain of free entries. */
79 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE];
80 PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
82 grant_ref_t gref_tx_head;
83 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
84 grant_ref_t gref_rx_head;
85 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
87 UINT irq;
88 evtchn_port_t event_channel;
90 grant_ref_t tx_ring_ref;
91 grant_ref_t rx_ring_ref;
93 /* Receive-ring batched refills. */
94 #define RX_MIN_TARGET 8
95 #define RX_DFL_MIN_TARGET 64
96 #define RX_MAX_TARGET min(NET_RX_RING_SIZE, 256)
97 ULONG rx_target;
98 ULONG rx_max_target;
99 ULONG rx_min_target;
101 NDIS_HANDLE packet_pool;
102 NDIS_HANDLE buffer_pool;
104 /* stats */
105 ULONG64 stat_tx_ok;
106 ULONG64 stat_rx_ok;
107 ULONG64 stat_tx_error;
108 ULONG64 stat_rx_error;
109 ULONG64 stat_rx_no_buffer;
111 // KEVENT backend_ready_event;
112 KEVENT backend_state_change_event;
114 ULONG state;
115 ULONG backend_state;
117 KSPIN_LOCK RxLock;
118 KSPIN_LOCK TxLock;
119 };
121 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
122 static unsigned long
123 simple_strtoul(const char *cp,char **endp,unsigned int base)
124 {
125 unsigned long result = 0,value;
127 if (!base) {
128 base = 10;
129 if (*cp == '0') {
130 base = 8;
131 cp++;
132 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
133 cp++;
134 base = 16;
135 }
136 }
137 } else if (base == 16) {
138 if (cp[0] == '0' && toupper(cp[1]) == 'X')
139 cp += 2;
140 }
141 while (isxdigit(*cp) &&
142 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
143 result = result*base + value;
144 cp++;
145 }
146 if (endp)
147 *endp = (char *)cp;
148 return result;
149 }
151 static void
152 add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
153 {
154 list[id] = list[0];
155 list[0] = (void *)(unsigned long)id;
156 }
158 static unsigned short
159 get_id_from_freelist(NDIS_PACKET **list)
160 {
161 unsigned short id = (unsigned short)(unsigned long)list[0];
162 list[0] = list[id];
163 return id;
164 }
166 // Called at DISPATCH_LEVEL with spinlock held
167 static NDIS_STATUS
168 XenNet_TxBufferGC(struct xennet_info *xi)
169 {
170 RING_IDX cons, prod;
171 unsigned short id;
172 PNDIS_PACKET pkt;
173 PMDL pmdl;
174 KIRQL OldIrql;
176 ASSERT(xi->connected);
178 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
180 KeAcquireSpinLock(&xi->TxLock, &OldIrql);
182 do {
183 prod = xi->tx.sring->rsp_prod;
184 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
186 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
187 struct netif_tx_response *txrsp;
189 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
190 if (txrsp->status == NETIF_RSP_NULL)
191 continue;
193 id = txrsp->id;
194 pkt = xi->tx_pkts[id];
195 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
196 xi->grant_tx_ref[id]);
197 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
198 add_id_to_freelist(xi->tx_pkts, id);
200 /* free linearized data page */
201 pmdl = *(PMDL *)pkt->MiniportReservedEx;
202 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
203 IoFreeMdl(pmdl);
205 xi->stat_tx_ok++;
206 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
207 }
209 xi->tx.rsp_cons = prod;
211 /*
212 * Set a new event, then check for race with update of tx_cons.
213 * Note that it is essential to schedule a callback, no matter
214 * how few buffers are pending. Even if there is space in the
215 * transmit ring, higher layers may be blocked because too much
216 * data is outstanding: in such cases notification from Xen is
217 * likely to be the only kick that we'll get.
218 */
219 xi->tx.sring->rsp_event =
220 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
221 KeMemoryBarrier();
222 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
224 /* if queued packets, send them now?
225 network_maybe_wake_tx(dev); */
227 KeReleaseSpinLock(&xi->TxLock, OldIrql);
229 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
231 return NDIS_STATUS_SUCCESS;
232 }
234 static NDIS_STATUS
235 XenNet_AllocRXBuffers(struct xennet_info *xi)
236 {
237 unsigned short id;
238 PNDIS_PACKET packet;
239 PNDIS_BUFFER buffer;
240 int i, batch_target, notify;
241 RING_IDX req_prod = xi->rx.req_prod_pvt;
242 grant_ref_t ref;
243 netif_rx_request_t *req;
244 NDIS_STATUS status;
245 PVOID start;
247 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
249 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
250 for (i = 0; i < batch_target; i++)
251 {
252 /*
253 * Allocate a packet, page, and buffer. Hook them up.
254 */
255 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
256 if (status != NDIS_STATUS_SUCCESS)
257 {
258 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
259 break;
260 }
261 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
262 if (status != NDIS_STATUS_SUCCESS)
263 {
264 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
265 NdisFreeMemory(start, 0, 0);
266 break;
267 }
268 NdisAllocatePacket(&status, &packet, xi->packet_pool);
269 if (status != NDIS_STATUS_SUCCESS)
270 {
271 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
272 NdisFreeMemory(start, 0, 0);
273 NdisFreeBuffer(buffer);
274 break;
275 }
276 NdisChainBufferAtBack(packet, buffer);
277 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
279 /* Give to netback */
280 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
281 ASSERT(!xi->rx_pkts[id]);
282 xi->rx_pkts[id] = packet;
283 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
284 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
285 ref = xi->XenInterface.GntTbl_GrantAccess(
286 xi->XenInterface.InterfaceHeader.Context, 0,
287 *MmGetMdlPfnArray(buffer), FALSE);
288 ASSERT((signed short)ref >= 0);
289 xi->grant_rx_ref[id] = ref;
291 req->id = id;
292 req->gref = ref;
293 }
295 xi->rx.req_prod_pvt = req_prod + i;
296 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
297 if (notify)
298 {
299 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
300 xi->event_channel);
301 }
303 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
305 return NDIS_STATUS_SUCCESS;
306 }
308 // Called at DISPATCH_LEVEL with spinlock held
309 static NDIS_STATUS
310 XenNet_RxBufferCheck(struct xennet_info *xi)
311 {
312 RING_IDX cons, prod;
314 PNDIS_PACKET pkt;
315 PNDIS_BUFFER buffer;
316 PVOID buff_va;
317 UINT buff_len;
318 UINT tot_buff_len;
319 int moretodo;
320 KIRQL OldIrql;
322 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
324 ASSERT(xi->connected);
326 KeAcquireSpinLock(&xi->RxLock, &OldIrql);
328 do {
329 prod = xi->rx.sring->rsp_prod;
330 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
332 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
333 struct netif_rx_response *rxrsp;
335 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
336 if (rxrsp->status == NETIF_RSP_NULL)
337 continue;
339 // KdPrint((__DRIVER_NAME " Got a packet\n"));
341 pkt = xi->rx_pkts[rxrsp->id];
342 xi->rx_pkts[rxrsp->id] = NULL;
343 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
344 xi->grant_rx_ref[rxrsp->id]);
345 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
347 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
348 &tot_buff_len, NormalPagePriority);
349 ASSERT(rxrsp->offset == 0);
350 ASSERT(rxrsp->status > 0);
351 NdisAdjustBufferLength(buffer, rxrsp->status);
353 xi->stat_rx_ok++;
354 NDIS_SET_PACKET_STATUS(pkt, NDIS_STATUS_SUCCESS);
356 /* just indicate 1 packet for now */
357 // KdPrint((__DRIVER_NAME " Indicating Received\n"));
358 NdisMIndicateReceivePacket(xi->adapter_handle, &pkt, 1);
359 // KdPrint((__DRIVER_NAME " Done Indicating Received\n"));
360 }
362 xi->rx.rsp_cons = prod;
364 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
365 } while (moretodo);
367 /* Give netback more buffers */
368 XenNet_AllocRXBuffers(xi);
370 KeReleaseSpinLock(&xi->RxLock, OldIrql);
372 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
374 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
376 return NDIS_STATUS_SUCCESS;
377 }
379 // Called at DISPATCH_LEVEL
380 static BOOLEAN
381 XenNet_Interrupt(
382 PKINTERRUPT Interrupt,
383 PVOID ServiceContext
384 )
385 {
386 struct xennet_info *xi = ServiceContext;
388 UNREFERENCED_PARAMETER(Interrupt);
390 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
392 if (xi->connected)
393 {
394 XenNet_TxBufferGC(xi);
395 XenNet_RxBufferCheck(xi);
396 }
398 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
400 return TRUE;
401 }
403 static VOID
404 XenNet_BackEndStateHandler(char *Path, PVOID Data)
405 {
406 struct xennet_info *xi = Data;
407 char *Value;
408 char TmpPath[128];
409 xenbus_transaction_t xbt = 0;
410 int retry = 0;
411 char *err;
412 int i;
414 struct set_params {
415 char *name;
416 int value;
417 } params[] = {
418 {"tx-ring-ref", 0},
419 {"rx-ring-ref", 0},
420 {"event-channel", 0},
421 {"request-rx-copy", 1},
422 #if 0 // these seemed to cause kernel messages about checksums
423 {"feature-rx-notify", 1},
424 {"feature-no-csum-offload", 1},
425 {"feature-sg", 1},
426 {"feature-gso-tcpv4", 0},
427 #endif
428 {NULL, 0},
429 };
431 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
432 XBT_NIL, Path, &Value);
433 xi->backend_state = atoi(Value);
434 xi->XenInterface.FreeMem(Value);
436 switch (xi->backend_state)
437 {
438 case XenbusStateUnknown:
439 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
440 break;
442 case XenbusStateInitialising:
443 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
444 break;
446 case XenbusStateInitWait:
447 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
449 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
450 xi->XenInterface.InterfaceHeader.Context, 0);
451 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
452 xi->event_channel, XenNet_Interrupt, xi);
454 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
455 // or, allocate mem and then get mdl, then free mdl
456 xi->tx_mdl = AllocatePage();
457 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl); //MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
458 SHARED_RING_INIT(xi->tx_pgs);
459 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
460 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
461 xi->XenInterface.InterfaceHeader.Context, 0,
462 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
464 xi->rx_mdl = AllocatePage();
465 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl); //MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
466 SHARED_RING_INIT(xi->rx_pgs);
467 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
468 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
469 xi->XenInterface.InterfaceHeader.Context, 0,
470 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
472 /* fixup array for dynamic values */
473 params[0].value = xi->tx_ring_ref;
474 params[1].value = xi->rx_ring_ref;
475 params[2].value = xi->event_channel;
477 xi->XenInterface.XenBus_StartTransaction(
478 xi->XenInterface.InterfaceHeader.Context, &xbt);
480 for (i = 0; params[i].name; i++)
481 {
482 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
483 xi->pdoData->Path, params[i].name);
484 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
485 XBT_NIL, TmpPath, "%d", params[i].value);
486 if (err)
487 {
488 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
489 goto trouble;
490 }
491 }
493 /* commit transaction */
494 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
495 xbt, 0, &retry);
497 XenNet_AllocRXBuffers(xi);
499 xi->state = XenbusStateConnected;
500 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
501 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
502 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
503 XBT_NIL, TmpPath, "%d", xi->state);
505 /* send fake arp? */
507 xi->connected = TRUE;
509 break;
511 case XenbusStateInitialised:
512 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
513 break;
515 case XenbusStateConnected:
516 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
517 break;
519 case XenbusStateClosing:
520 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
521 break;
523 case XenbusStateClosed:
524 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
525 break;
527 default:
528 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
529 break;
530 }
532 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
534 return;
536 trouble:
537 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
538 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
539 xbt, 1, &retry);
541 }
543 VOID
544 XenNet_Halt(
545 IN NDIS_HANDLE MiniportAdapterContext
546 )
547 {
548 struct xennet_info *xi = MiniportAdapterContext;
549 CHAR TmpPath[128];
551 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
552 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
554 // set frontend state to 'closing'
555 xi->state = XenbusStateClosing;
556 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
557 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
558 XBT_NIL, TmpPath, "%d", xi->state);
560 // wait for backend to set 'Closing' state
561 while (xi->backend_state != XenbusStateClosing)
562 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
564 // set frontend state to 'closed'
565 xi->state = XenbusStateClosed;
566 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
567 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
568 XBT_NIL, TmpPath, "%d", xi->state);
570 // wait for backend to set 'Closed' state
571 while (xi->backend_state != XenbusStateClosed)
572 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
574 // remove event channel xenbus entry
575 // unbind event channel
576 // remove tx/rx ring entries
577 // clean up all grant table entries
578 // free all memory
580 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
581 }
583 static NDIS_STATUS
584 XenNet_Init(
585 OUT PNDIS_STATUS OpenErrorStatus,
586 OUT PUINT SelectedMediumIndex,
587 IN PNDIS_MEDIUM MediumArray,
588 IN UINT MediumArraySize,
589 IN NDIS_HANDLE MiniportAdapterHandle,
590 IN NDIS_HANDLE WrapperConfigurationContext
591 )
592 {
593 NDIS_STATUS status;
594 UINT i;
595 BOOLEAN medium_found = FALSE;
596 struct xennet_info *xi = NULL;
597 ULONG length;
598 WDF_OBJECT_ATTRIBUTES wdf_attrs;
599 char *res;
600 char *Value;
601 char TmpPath[128];
603 UNREFERENCED_PARAMETER(OpenErrorStatus);
604 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
606 /* deal with medium stuff */
607 for (i = 0; i < MediumArraySize; i++)
608 {
609 if (MediumArray[i] == NdisMedium802_3)
610 {
611 medium_found = TRUE;
612 break;
613 }
614 }
615 if (!medium_found)
616 {
617 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
618 return NDIS_STATUS_UNSUPPORTED_MEDIA;
619 }
620 *SelectedMediumIndex = i;
622 /* Alloc memory for adapter private info */
623 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
624 if (!NT_SUCCESS(status))
625 {
626 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
627 status = NDIS_STATUS_RESOURCES;
628 goto err;
629 }
630 RtlZeroMemory(xi, sizeof(*xi));
632 /* init xennet_info */
633 xi->adapter_handle = MiniportAdapterHandle;
634 xi->rx_target = RX_DFL_MIN_TARGET;
635 xi->rx_min_target = RX_DFL_MIN_TARGET;
636 xi->rx_max_target = RX_MAX_TARGET;
638 xi->state = XenbusStateUnknown;
639 xi->backend_state = XenbusStateUnknown;
641 KeInitializeSpinLock(&xi->TxLock);
642 KeInitializeSpinLock(&xi->RxLock);
644 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
645 PROTOCOL_RESERVED_SIZE_IN_PACKET);
646 if (status != NDIS_STATUS_SUCCESS)
647 {
648 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
649 status = NDIS_STATUS_RESOURCES;
650 goto err;
651 }
653 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
654 if (status != NDIS_STATUS_SUCCESS)
655 {
656 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
657 status = NDIS_STATUS_RESOURCES;
658 goto err;
659 }
661 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
662 &xi->lower_do, NULL, NULL);
663 xi->pdoData = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
665 /* Initialize tx_pkts as a free chain containing every entry. */
666 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
667 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
668 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
669 }
671 for (i = 0; i < NET_RX_RING_SIZE; i++) {
672 xi->rx_pkts[i] = NULL;
673 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
674 }
676 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
678 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
679 NAME_SIZE, xi->name, &length);
680 if (!NT_SUCCESS(status))
681 {
682 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
683 status = NDIS_STATUS_FAILURE;
684 goto err;
685 }
687 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
688 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
689 NdisInterfaceInternal);
691 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
693 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
694 xi->lower_do, xi->pdo, &xi->wdf_device);
695 if (!NT_SUCCESS(status))
696 {
697 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
698 status = NDIS_STATUS_FAILURE;
699 goto err;
700 }
702 /* get lower (Xen) interfaces */
704 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
705 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
706 if(!NT_SUCCESS(status))
707 {
708 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
709 status = NDIS_STATUS_FAILURE;
710 goto err;
711 }
713 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
714 "%s/backend", xi->pdoData->Path);
715 KdPrint(("About to read %s to get backend path\n", TmpPath));
716 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
717 XBT_NIL, TmpPath, &Value);
718 if (res)
719 {
720 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
721 xi->XenInterface.FreeMem(res);
722 status = NDIS_STATUS_FAILURE;
723 goto err;
724 }
725 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
726 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
728 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
730 /* Add watch on backend state */
731 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
732 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
733 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
735 // wait here for signal that we are all set up
736 while (xi->backend_state != XenbusStateConnected)
737 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
739 /* get mac address */
740 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->BackendPath);
741 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
742 XBT_NIL, TmpPath, &Value);
743 if (!Value)
744 {
745 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
746 status = NDIS_STATUS_FAILURE;
747 goto err;
748 }
749 else
750 {
751 char *s, *e;
752 int i;
753 s = Value;
754 for (i = 0; i < ETH_ALEN; i++) {
755 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
756 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
757 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
758 xi->XenInterface.FreeMem(Value);
759 status = NDIS_STATUS_FAILURE;
760 goto err;
761 }
762 s = e + 1;
763 }
764 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
765 xi->XenInterface.FreeMem(Value);
766 }
768 return NDIS_STATUS_SUCCESS;
770 err:
771 NdisFreeMemory(xi, 0, 0);
772 return status;
773 }
775 // Q = Query Mandatory, S = Set Mandatory
776 NDIS_OID supported_oids[] =
777 {
778 /* general OIDs */
779 OID_GEN_SUPPORTED_LIST, // Q
780 OID_GEN_HARDWARE_STATUS, // Q
781 OID_GEN_MEDIA_SUPPORTED, // Q
782 OID_GEN_MEDIA_IN_USE, // Q
783 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
784 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
785 OID_GEN_LINK_SPEED, // Q
786 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
787 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
788 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
789 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
790 OID_GEN_VENDOR_ID, // Q
791 OID_GEN_VENDOR_DESCRIPTION, // Q
792 OID_GEN_CURRENT_PACKET_FILTER, // QS
793 OID_GEN_CURRENT_LOOKAHEAD, // QS
794 OID_GEN_DRIVER_VERSION, // Q
795 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
796 OID_GEN_PROTOCOL_OPTIONS, // S
797 OID_GEN_MAC_OPTIONS, // Q
798 OID_GEN_MEDIA_CONNECT_STATUS, // Q
799 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
800 /* stats */
801 OID_GEN_XMIT_OK, // Q
802 OID_GEN_RCV_OK, // Q
803 OID_GEN_XMIT_ERROR, // Q
804 OID_GEN_RCV_ERROR, // Q
805 OID_GEN_RCV_NO_BUFFER, // Q
806 /* media-specific OIDs */
807 OID_802_3_PERMANENT_ADDRESS,
808 OID_802_3_CURRENT_ADDRESS,
809 OID_802_3_MULTICAST_LIST,
810 OID_802_3_MAXIMUM_LIST_SIZE,
811 };
813 NDIS_STATUS
814 XenNet_QueryInformation(
815 IN NDIS_HANDLE MiniportAdapterContext,
816 IN NDIS_OID Oid,
817 IN PVOID InformationBuffer,
818 IN ULONG InformationBufferLength,
819 OUT PULONG BytesWritten,
820 OUT PULONG BytesNeeded)
821 {
822 struct xennet_info *xi = MiniportAdapterContext;
823 UCHAR vendor_desc[] = XN_VENDOR_DESC;
824 ULONG64 temp_data;
825 PVOID data = &temp_data;
826 UINT len = 4;
827 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
829 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
831 switch(Oid)
832 {
833 case OID_GEN_SUPPORTED_LIST:
834 data = supported_oids;
835 len = sizeof(supported_oids);
836 break;
837 case OID_GEN_HARDWARE_STATUS:
838 if (!xi->connected)
839 temp_data = NdisHardwareStatusInitializing;
840 else
841 temp_data = NdisHardwareStatusReady;
842 break;
843 case OID_GEN_MEDIA_SUPPORTED:
844 temp_data = NdisMedium802_3;
845 break;
846 case OID_GEN_MEDIA_IN_USE:
847 temp_data = NdisMedium802_3;
848 break;
849 case OID_GEN_MAXIMUM_LOOKAHEAD:
850 temp_data = XN_DATA_SIZE;
851 break;
852 case OID_GEN_MAXIMUM_FRAME_SIZE:
853 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
854 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
855 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
856 break;
857 case OID_GEN_LINK_SPEED:
858 temp_data = 10000000; /* 1Gb */
859 break;
860 case OID_GEN_TRANSMIT_BUFFER_SPACE:
861 /* pkts times sizeof ring, maybe? */
862 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
863 break;
864 case OID_GEN_RECEIVE_BUFFER_SPACE:
865 /* pkts times sizeof ring, maybe? */
866 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
867 break;
868 case OID_GEN_TRANSMIT_BLOCK_SIZE:
869 temp_data = XN_MAX_PKT_SIZE;
870 break;
871 case OID_GEN_RECEIVE_BLOCK_SIZE:
872 temp_data = XN_MAX_PKT_SIZE;
873 break;
874 case OID_GEN_VENDOR_ID:
875 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
876 break;
877 case OID_GEN_VENDOR_DESCRIPTION:
878 data = vendor_desc;
879 len = sizeof(vendor_desc);
880 break;
881 case OID_GEN_CURRENT_PACKET_FILTER:
882 temp_data = xi->packet_filter;
883 break;
884 case OID_GEN_CURRENT_LOOKAHEAD:
885 // TODO: we should store this...
886 temp_data = XN_MAX_PKT_SIZE;
887 break;
888 case OID_GEN_DRIVER_VERSION:
889 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
890 len = 2;
891 break;
892 case OID_GEN_MAXIMUM_TOTAL_SIZE:
893 temp_data = XN_MAX_PKT_SIZE;
894 break;
895 case OID_GEN_MAC_OPTIONS:
896 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
897 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
898 NDIS_MAC_OPTION_NO_LOOPBACK;
899 break;
900 case OID_GEN_MEDIA_CONNECT_STATUS:
901 if (xi->connected)
902 temp_data = NdisMediaStateConnected;
903 else
904 temp_data = NdisMediaStateDisconnected;
905 break;
906 case OID_GEN_MAXIMUM_SEND_PACKETS:
907 temp_data = XN_MAX_SEND_PKTS;
908 break;
909 case OID_GEN_XMIT_OK:
910 temp_data = xi->stat_tx_ok;
911 len = sizeof(ULONG64);
912 break;
913 case OID_GEN_RCV_OK:
914 temp_data = xi->stat_rx_ok;
915 len = sizeof(ULONG64);
916 break;
917 case OID_GEN_XMIT_ERROR:
918 temp_data = xi->stat_tx_error;
919 len = sizeof(ULONG64);
920 break;
921 case OID_GEN_RCV_ERROR:
922 temp_data = xi->stat_rx_error;
923 len = sizeof(ULONG64);
924 break;
925 case OID_GEN_RCV_NO_BUFFER:
926 temp_data = xi->stat_rx_no_buffer;
927 len = sizeof(ULONG64);
928 break;
929 case OID_802_3_PERMANENT_ADDRESS:
930 data = xi->perm_mac_addr;
931 len = ETH_ALEN;
932 break;
933 case OID_802_3_CURRENT_ADDRESS:
934 data = xi->curr_mac_addr;
935 len = ETH_ALEN;
936 break;
937 case OID_802_3_MULTICAST_LIST:
938 data = NULL;
939 len = 0;
940 case OID_802_3_MAXIMUM_LIST_SIZE:
941 temp_data = 0; /* no mcast support */
942 break;
943 default:
944 KdPrint(("Get Unknown OID 0x%x\n", Oid));
945 status = NDIS_STATUS_NOT_SUPPORTED;
946 }
948 if (!NT_SUCCESS(status))
949 {
950 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
951 return status;
952 }
954 if (len > InformationBufferLength)
955 {
956 *BytesNeeded = len;
957 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
958 return NDIS_STATUS_BUFFER_TOO_SHORT;
959 }
961 *BytesWritten = len;
962 if (len)
963 {
964 NdisMoveMemory(InformationBuffer, data, len);
965 }
967 //KdPrint(("Got OID 0x%x\n", Oid));
968 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
970 return status;
971 }
973 NDIS_STATUS
974 XenNet_SetInformation(
975 IN NDIS_HANDLE MiniportAdapterContext,
976 IN NDIS_OID Oid,
977 IN PVOID InformationBuffer,
978 IN ULONG InformationBufferLength,
979 OUT PULONG BytesRead,
980 OUT PULONG BytesNeeded
981 )
982 {
983 NTSTATUS status;
984 struct xennet_info *xi = MiniportAdapterContext;
985 PULONG64 data = InformationBuffer;
987 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
989 UNREFERENCED_PARAMETER(MiniportAdapterContext);
990 UNREFERENCED_PARAMETER(InformationBufferLength);
991 UNREFERENCED_PARAMETER(BytesRead);
992 UNREFERENCED_PARAMETER(BytesNeeded);
994 switch(Oid)
995 {
996 case OID_GEN_SUPPORTED_LIST:
997 status = NDIS_STATUS_NOT_SUPPORTED;
998 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
999 break;
1000 case OID_GEN_HARDWARE_STATUS:
1001 status = NDIS_STATUS_NOT_SUPPORTED;
1002 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1003 break;
1004 case OID_GEN_MEDIA_SUPPORTED:
1005 status = NDIS_STATUS_NOT_SUPPORTED;
1006 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1007 break;
1008 case OID_GEN_MEDIA_IN_USE:
1009 status = NDIS_STATUS_NOT_SUPPORTED;
1010 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1011 break;
1012 case OID_GEN_MAXIMUM_LOOKAHEAD:
1013 status = NDIS_STATUS_NOT_SUPPORTED;
1014 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1015 break;
1016 case OID_GEN_MAXIMUM_FRAME_SIZE:
1017 status = NDIS_STATUS_NOT_SUPPORTED;
1018 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1019 break;
1020 case OID_GEN_LINK_SPEED:
1021 status = NDIS_STATUS_NOT_SUPPORTED;
1022 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1023 break;
1024 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1025 status = NDIS_STATUS_NOT_SUPPORTED;
1026 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1027 break;
1028 case OID_GEN_RECEIVE_BUFFER_SPACE:
1029 status = NDIS_STATUS_NOT_SUPPORTED;
1030 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1031 break;
1032 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1033 status = NDIS_STATUS_NOT_SUPPORTED;
1034 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1035 break;
1036 case OID_GEN_RECEIVE_BLOCK_SIZE:
1037 status = NDIS_STATUS_NOT_SUPPORTED;
1038 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1039 break;
1040 case OID_GEN_VENDOR_ID:
1041 status = NDIS_STATUS_NOT_SUPPORTED;
1042 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1043 break;
1044 case OID_GEN_VENDOR_DESCRIPTION:
1045 status = NDIS_STATUS_NOT_SUPPORTED;
1046 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1047 break;
1048 case OID_GEN_CURRENT_PACKET_FILTER:
1049 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1050 xi->packet_filter = *(ULONG *)data;
1051 status = NDIS_STATUS_SUCCESS;
1052 break;
1053 case OID_GEN_CURRENT_LOOKAHEAD:
1054 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1055 // TODO: We should do this...
1056 status = NDIS_STATUS_SUCCESS;
1057 break;
1058 case OID_GEN_DRIVER_VERSION:
1059 status = NDIS_STATUS_NOT_SUPPORTED;
1060 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1061 break;
1062 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1063 status = NDIS_STATUS_NOT_SUPPORTED;
1064 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1065 break;
1066 case OID_GEN_PROTOCOL_OPTIONS:
1067 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1068 // TODO - actually do this...
1069 status = NDIS_STATUS_SUCCESS;
1070 break;
1071 case OID_GEN_MAC_OPTIONS:
1072 status = NDIS_STATUS_NOT_SUPPORTED;
1073 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1074 break;
1075 case OID_GEN_MEDIA_CONNECT_STATUS:
1076 status = NDIS_STATUS_NOT_SUPPORTED;
1077 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1078 break;
1079 case OID_GEN_MAXIMUM_SEND_PACKETS:
1080 status = NDIS_STATUS_NOT_SUPPORTED;
1081 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1082 break;
1083 case OID_GEN_XMIT_OK:
1084 status = NDIS_STATUS_NOT_SUPPORTED;
1085 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1086 break;
1087 case OID_GEN_RCV_OK:
1088 status = NDIS_STATUS_NOT_SUPPORTED;
1089 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1090 break;
1091 case OID_GEN_XMIT_ERROR:
1092 status = NDIS_STATUS_NOT_SUPPORTED;
1093 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1094 break;
1095 case OID_GEN_RCV_ERROR:
1096 status = NDIS_STATUS_NOT_SUPPORTED;
1097 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1098 break;
1099 case OID_GEN_RCV_NO_BUFFER:
1100 status = NDIS_STATUS_NOT_SUPPORTED;
1101 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1102 break;
1103 case OID_802_3_PERMANENT_ADDRESS:
1104 status = NDIS_STATUS_NOT_SUPPORTED;
1105 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1106 break;
1107 case OID_802_3_CURRENT_ADDRESS:
1108 status = NDIS_STATUS_NOT_SUPPORTED;
1109 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1110 break;
1111 case OID_802_3_MULTICAST_LIST:
1112 status = NDIS_STATUS_NOT_SUPPORTED;
1113 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1114 break;
1115 case OID_802_3_MAXIMUM_LIST_SIZE:
1116 status = NDIS_STATUS_NOT_SUPPORTED;
1117 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1118 break;
1119 default:
1120 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1121 status = NDIS_STATUS_NOT_SUPPORTED;
1122 break;
1124 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1125 return status;
1128 VOID
1129 XenNet_ReturnPacket(
1130 IN NDIS_HANDLE MiniportAdapterContext,
1131 IN PNDIS_PACKET Packet
1134 PNDIS_BUFFER buffer;
1135 PVOID buff_va;
1136 UINT buff_len;
1137 UINT tot_buff_len;
1139 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1141 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1143 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1144 &tot_buff_len, NormalPagePriority);
1145 ASSERT(buff_len == tot_buff_len);
1147 NdisFreeMemory(buff_va, 0, 0);
1148 NdisFreeBuffer(buffer);
1149 NdisFreePacket(Packet);
1151 //KdPrint((__FUNCTION__ " called\n"));
1152 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1155 PMDL
1156 XenNet_Linearize(PNDIS_PACKET Packet)
1158 NDIS_STATUS status;
1159 PMDL pmdl;
1160 char *start;
1161 PNDIS_BUFFER buffer;
1162 PVOID buff_va;
1163 UINT buff_len;
1164 UINT tot_buff_len;
1166 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1168 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1169 &tot_buff_len, NormalPagePriority);
1170 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1172 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1173 if (!NT_SUCCESS(status))
1175 KdPrint(("Could not allocate memory for linearization\n"));
1176 return NULL;
1178 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1179 if (!pmdl)
1181 KdPrint(("Could not allocate MDL for linearization\n"));
1182 NdisFreeMemory(start, 0, 0);
1183 return NULL;
1185 MmBuildMdlForNonPagedPool(pmdl);
1187 while (buffer)
1189 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1190 RtlCopyMemory(start, buff_va, buff_len);
1191 start += buff_len;
1192 NdisGetNextBuffer(buffer, &buffer);
1195 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1196 return pmdl;
1199 VOID
1200 XenNet_SendPackets(
1201 IN NDIS_HANDLE MiniportAdapterContext,
1202 IN PPNDIS_PACKET PacketArray,
1203 IN UINT NumberOfPackets
1206 struct xennet_info *xi = MiniportAdapterContext;
1207 PNDIS_PACKET curr_packet;
1208 UINT i;
1209 struct netif_tx_request *tx;
1210 unsigned short id;
1211 int notify;
1212 PMDL pmdl;
1213 UINT pkt_size;
1214 KIRQL OldIrql;
1216 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1218 KeAcquireSpinLock(&xi->TxLock, &OldIrql);
1220 for (i = 0; i < NumberOfPackets; i++)
1222 curr_packet = PacketArray[i];
1223 ASSERT(curr_packet);
1225 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1227 //KdPrint(("sending pkt, len %d\n", pkt_size));
1229 pmdl = XenNet_Linearize(curr_packet);
1230 if (!pmdl)
1232 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1233 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1234 break;
1236 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1238 id = get_id_from_freelist(xi->tx_pkts);
1239 xi->tx_pkts[id] = curr_packet;
1241 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1242 tx->id = id;
1243 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1244 xi->XenInterface.InterfaceHeader.Context,
1245 0,
1246 *MmGetMdlPfnArray(pmdl),
1247 TRUE);
1248 xi->grant_tx_ref[id] = tx->gref;
1249 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1250 tx->size = (UINT16)pkt_size;
1251 // NETTXF_csum_blank should only be used for tcp and udp packets...
1252 tx->flags = 0; //NETTXF_csum_blank;
1254 xi->tx.req_prod_pvt++;
1256 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1257 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1260 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1261 if (notify)
1263 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1264 xi->event_channel);
1267 KeReleaseSpinLock(&xi->TxLock, OldIrql);
1269 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1272 VOID
1273 XenNet_PnPEventNotify(
1274 IN NDIS_HANDLE MiniportAdapterContext,
1275 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1276 IN PVOID InformationBuffer,
1277 IN ULONG InformationBufferLength
1280 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1281 UNREFERENCED_PARAMETER(PnPEvent);
1282 UNREFERENCED_PARAMETER(InformationBuffer);
1283 UNREFERENCED_PARAMETER(InformationBufferLength);
1285 KdPrint((__FUNCTION__ " called\n"));
1288 VOID
1289 XenNet_Shutdown(
1290 IN NDIS_HANDLE MiniportAdapterContext
1293 //struct xennet_info *xi = MiniportAdapterContext;
1294 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1296 // I think all we are supposed to do here is reset the adapter, which for us might be nothing...
1298 KdPrint((__FUNCTION__ " called\n"));
1301 NTSTATUS
1302 DriverEntry(
1303 PDRIVER_OBJECT DriverObject,
1304 PUNICODE_STRING RegistryPath
1307 NTSTATUS status;
1308 WDF_DRIVER_CONFIG config;
1309 NDIS_HANDLE ndis_wrapper_handle;
1310 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1312 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1314 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1315 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1317 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1318 &config, WDF_NO_HANDLE);
1319 if (!NT_SUCCESS(status))
1321 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1322 return status;
1325 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1326 if (!ndis_wrapper_handle)
1328 KdPrint(("NdisMInitializeWrapper failed\n"));
1329 return NDIS_STATUS_FAILURE;
1332 /* NDIS 5.1 driver */
1333 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1334 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1336 mini_chars.HaltHandler = XenNet_Halt;
1337 mini_chars.InitializeHandler = XenNet_Init;
1338 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1339 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1340 mini_chars.ResetHandler = NULL; //TODO: fill in
1341 mini_chars.SetInformationHandler = XenNet_SetInformation;
1342 /* added in v.4 -- use multiple pkts interface */
1343 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1344 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1345 /* added in v.5.1 */
1346 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1347 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1349 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1351 /* set up upper-edge interface */
1352 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1353 if (!NT_SUCCESS(status))
1355 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1356 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1357 return status;
1360 return status;