win-pvdrivers

view xennet/xennet.c @ 90:93879f914f05

fix shutdown memory leaks caught by driver verifier
author Andy Grover <andy.grover@oracle.com>
date Wed Jan 02 15:47:16 2008 -0800 (2008-01-02)
parents 70258b4c8380
children 24963c2b7846
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 Lock;
118 };
120 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
121 static unsigned long
122 simple_strtoul(const char *cp,char **endp,unsigned int base)
123 {
124 unsigned long result = 0,value;
126 if (!base) {
127 base = 10;
128 if (*cp == '0') {
129 base = 8;
130 cp++;
131 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
132 cp++;
133 base = 16;
134 }
135 }
136 } else if (base == 16) {
137 if (cp[0] == '0' && toupper(cp[1]) == 'X')
138 cp += 2;
139 }
140 while (isxdigit(*cp) &&
141 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
142 result = result*base + value;
143 cp++;
144 }
145 if (endp)
146 *endp = (char *)cp;
147 return result;
148 }
150 static void
151 add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
152 {
153 list[id] = list[0];
154 list[0] = (void *)(unsigned long)id;
155 }
157 static unsigned short
158 get_id_from_freelist(NDIS_PACKET **list)
159 {
160 unsigned short id = (unsigned short)(unsigned long)list[0];
161 list[0] = list[id];
162 return id;
163 }
165 // Called at DISPATCH_LEVEL with spinlock held
166 static NDIS_STATUS
167 XenNet_TxBufferGC(struct xennet_info *xi)
168 {
169 RING_IDX cons, prod;
170 unsigned short id;
171 PNDIS_PACKET pkt;
172 PMDL pmdl;
174 ASSERT(xi->connected);
176 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
178 do {
179 prod = xi->tx.sring->rsp_prod;
180 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
182 for (cons = xi->tx.rsp_cons; cons != prod; cons++) {
183 struct netif_tx_response *txrsp;
185 txrsp = RING_GET_RESPONSE(&xi->tx, cons);
186 if (txrsp->status == NETIF_RSP_NULL)
187 continue;
189 id = txrsp->id;
190 pkt = xi->tx_pkts[id];
191 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
192 xi->grant_tx_ref[id]);
193 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
194 add_id_to_freelist(xi->tx_pkts, id);
196 /* free linearized data page */
197 pmdl = *(PMDL *)pkt->MiniportReservedEx;
198 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
199 IoFreeMdl(pmdl);
201 xi->stat_tx_ok++;
202 NdisMSendComplete(xi->adapter_handle, pkt, NDIS_STATUS_SUCCESS);
203 }
205 xi->tx.rsp_cons = prod;
207 /*
208 * Set a new event, then check for race with update of tx_cons.
209 * Note that it is essential to schedule a callback, no matter
210 * how few buffers are pending. Even if there is space in the
211 * transmit ring, higher layers may be blocked because too much
212 * data is outstanding: in such cases notification from Xen is
213 * likely to be the only kick that we'll get.
214 */
215 xi->tx.sring->rsp_event =
216 prod + ((xi->tx.sring->req_prod - prod) >> 1) + 1;
217 KeMemoryBarrier();
218 } while ((cons == prod) && (prod != xi->tx.sring->rsp_prod));
220 /* if queued packets, send them now?
221 network_maybe_wake_tx(dev); */
223 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
225 return NDIS_STATUS_SUCCESS;
226 }
228 static NDIS_STATUS
229 XenNet_AllocRXBuffers(struct xennet_info *xi)
230 {
231 unsigned short id;
232 PNDIS_PACKET packet;
233 PNDIS_BUFFER buffer;
234 int i, batch_target, notify;
235 RING_IDX req_prod = xi->rx.req_prod_pvt;
236 grant_ref_t ref;
237 netif_rx_request_t *req;
238 NDIS_STATUS status;
239 PVOID start;
241 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
243 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
244 for (i = 0; i < batch_target; i++)
245 {
246 /*
247 * Allocate a packet, page, and buffer. Hook them up.
248 */
249 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
250 if (status != NDIS_STATUS_SUCCESS)
251 {
252 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
253 break;
254 }
255 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
256 if (status != NDIS_STATUS_SUCCESS)
257 {
258 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
259 NdisFreeMemory(start, 0, 0);
260 break;
261 }
262 NdisAllocatePacket(&status, &packet, xi->packet_pool);
263 if (status != NDIS_STATUS_SUCCESS)
264 {
265 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
266 NdisFreeMemory(start, 0, 0);
267 NdisFreeBuffer(buffer);
268 break;
269 }
270 NdisChainBufferAtBack(packet, buffer);
271 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
273 /* Give to netback */
274 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
275 ASSERT(!xi->rx_pkts[id]);
276 xi->rx_pkts[id] = packet;
277 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
278 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
279 ref = xi->XenInterface.GntTbl_GrantAccess(
280 xi->XenInterface.InterfaceHeader.Context, 0,
281 *MmGetMdlPfnArray(buffer), FALSE);
282 ASSERT((signed short)ref >= 0);
283 xi->grant_rx_ref[id] = ref;
285 req->id = id;
286 req->gref = ref;
287 }
289 xi->rx.req_prod_pvt = req_prod + i;
290 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
291 if (notify)
292 {
293 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
294 xi->event_channel);
295 }
297 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
299 return NDIS_STATUS_SUCCESS;
300 }
302 // Called at DISPATCH_LEVEL with spinlock held
303 static NDIS_STATUS
304 XenNet_RxBufferCheck(struct xennet_info *xi)
305 {
306 RING_IDX cons, prod;
308 PNDIS_PACKET pkt;
309 PNDIS_BUFFER buffer;
310 PVOID buff_va;
311 UINT buff_len;
312 UINT tot_buff_len;
313 int moretodo;
315 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
317 ASSERT(xi->connected);
319 do {
320 prod = xi->rx.sring->rsp_prod;
321 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
323 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
324 struct netif_rx_response *rxrsp;
326 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
327 if (rxrsp->status == NETIF_RSP_NULL)
328 continue;
330 // KdPrint((__DRIVER_NAME " Got a packet\n"));
332 pkt = xi->rx_pkts[rxrsp->id];
333 xi->rx_pkts[rxrsp->id] = NULL;
334 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
335 xi->grant_rx_ref[rxrsp->id]);
336 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
338 NdisGetFirstBufferFromPacketSafe(pkt, &buffer, &buff_va, &buff_len,
339 &tot_buff_len, NormalPagePriority);
340 ASSERT(rxrsp->offset == 0);
341 ASSERT(rxrsp->status > 0);
342 NdisAdjustBufferLength(buffer, rxrsp->status);
344 xi->stat_rx_ok++;
345 NDIS_SET_PACKET_STATUS(pkt, NDIS_STATUS_SUCCESS);
347 /* just indicate 1 packet for now */
348 // KdPrint((__DRIVER_NAME " Indicating Received\n"));
349 NdisMIndicateReceivePacket(xi->adapter_handle, &pkt, 1);
350 // KdPrint((__DRIVER_NAME " Done Indicating Received\n"));
351 }
353 xi->rx.rsp_cons = prod;
355 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
356 #if 0
357 /*
358 * Set a new event, then check for race with update of rx_cons.
359 * Note that it is essential to schedule a callback, no matter
360 * how few buffers are pending. Even if there is space in the
361 * transmit ring, higher layers may be blocked because too much
362 * data is outstanding: in such cases notification from Xen is
363 * likely to be the only kick that we'll get.
364 */
365 xi->rx.sring->rsp_event =
366 prod + ((xi->rx.sring->req_prod - prod) >> 1) + 1;
367 KeMemoryBarrier();
368 } while ((cons == prod) && (prod != xi->rx.sring->rsp_prod));
369 #endif
370 } while (moretodo);
372 /* Give netback more buffers */
373 XenNet_AllocRXBuffers(xi);
375 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
377 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
379 return NDIS_STATUS_SUCCESS;
380 }
382 // Called at DISPATCH_LEVEL
383 static BOOLEAN
384 XenNet_Interrupt(
385 PKINTERRUPT Interrupt,
386 PVOID ServiceContext
387 )
388 {
389 struct xennet_info *xi = ServiceContext;
390 KIRQL OldIrql;
392 UNREFERENCED_PARAMETER(Interrupt);
394 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
396 KeAcquireSpinLock(&xi->Lock, &OldIrql);
398 //KdPrint((__DRIVER_NAME " ***XenNet Interrupt***\n"));
400 if (xi->connected)
401 {
402 XenNet_TxBufferGC(xi);
403 XenNet_RxBufferCheck(xi);
404 }
406 KeReleaseSpinLock(&xi->Lock, OldIrql);
408 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
410 return TRUE;
411 }
413 static VOID
414 XenNet_BackEndStateHandler(char *Path, PVOID Data)
415 {
416 struct xennet_info *xi = Data;
417 char *Value;
418 char TmpPath[128];
419 xenbus_transaction_t xbt = 0;
420 int retry = 0;
421 char *err;
422 int i;
424 struct set_params {
425 char *name;
426 int value;
427 } params[] = {
428 {"tx-ring-ref", 0},
429 {"rx-ring-ref", 0},
430 {"event-channel", 0},
431 {"request-rx-copy", 1},
432 #if 0 // these seemed to cause kernel messages about checksums
433 {"feature-rx-notify", 1},
434 {"feature-no-csum-offload", 1},
435 {"feature-sg", 1},
436 {"feature-gso-tcpv4", 0},
437 #endif
438 {NULL, 0},
439 };
441 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
442 XBT_NIL, Path, &Value);
443 xi->backend_state = atoi(Value);
444 xi->XenInterface.FreeMem(Value);
446 switch (xi->backend_state)
447 {
448 case XenbusStateUnknown:
449 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
450 break;
452 case XenbusStateInitialising:
453 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
454 break;
456 case XenbusStateInitWait:
457 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
459 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
460 xi->XenInterface.InterfaceHeader.Context, 0);
461 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
462 xi->event_channel, XenNet_Interrupt, xi);
464 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
465 // or, allocate mem and then get mdl, then free mdl
466 xi->tx_mdl = AllocatePage();
467 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl); //MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
468 SHARED_RING_INIT(xi->tx_pgs);
469 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
470 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
471 xi->XenInterface.InterfaceHeader.Context, 0,
472 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
474 xi->rx_mdl = AllocatePage();
475 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl); //MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
476 SHARED_RING_INIT(xi->rx_pgs);
477 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
478 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
479 xi->XenInterface.InterfaceHeader.Context, 0,
480 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
482 /* fixup array for dynamic values */
483 params[0].value = xi->tx_ring_ref;
484 params[1].value = xi->rx_ring_ref;
485 params[2].value = xi->event_channel;
487 xi->XenInterface.XenBus_StartTransaction(
488 xi->XenInterface.InterfaceHeader.Context, &xbt);
490 for (i = 0; params[i].name; i++)
491 {
492 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
493 xi->pdoData->Path, params[i].name);
494 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
495 XBT_NIL, TmpPath, "%d", params[i].value);
496 if (err)
497 {
498 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
499 goto trouble;
500 }
501 }
503 /* commit transaction */
504 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
505 xbt, 0, &retry);
507 XenNet_AllocRXBuffers(xi);
509 xi->state = XenbusStateConnected;
510 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
511 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
512 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
513 XBT_NIL, TmpPath, "%d", xi->state);
515 /* send fake arp? */
517 xi->connected = TRUE;
519 break;
521 case XenbusStateInitialised:
522 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
523 break;
525 case XenbusStateConnected:
526 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
527 break;
529 case XenbusStateClosing:
530 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
531 break;
533 case XenbusStateClosed:
534 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
535 break;
537 default:
538 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
539 break;
540 }
542 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
544 return;
546 trouble:
547 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
548 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
549 xbt, 1, &retry);
551 }
553 VOID
554 XenNet_Halt(
555 IN NDIS_HANDLE MiniportAdapterContext
556 )
557 {
558 struct xennet_info *xi = MiniportAdapterContext;
559 CHAR TmpPath[128];
561 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
562 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
564 // set frontend state to 'closing'
565 xi->state = XenbusStateClosing;
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 'Closing' state
571 while (xi->backend_state != XenbusStateClosing)
572 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
574 // set frontend state to 'closed'
575 xi->state = XenbusStateClosed;
576 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
577 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
578 XBT_NIL, TmpPath, "%d", xi->state);
580 // wait for backend to set 'Closed' state
581 while (xi->backend_state != XenbusStateClosed)
582 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
584 // remove event channel xenbus entry
585 // unbind event channel
586 // remove tx/rx ring entries
587 // clean up all grant table entries
588 // free all memory
590 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
591 }
593 static NDIS_STATUS
594 XenNet_Init(
595 OUT PNDIS_STATUS OpenErrorStatus,
596 OUT PUINT SelectedMediumIndex,
597 IN PNDIS_MEDIUM MediumArray,
598 IN UINT MediumArraySize,
599 IN NDIS_HANDLE MiniportAdapterHandle,
600 IN NDIS_HANDLE WrapperConfigurationContext
601 )
602 {
603 NDIS_STATUS status;
604 UINT i;
605 BOOLEAN medium_found = FALSE;
606 struct xennet_info *xi = NULL;
607 ULONG length;
608 WDF_OBJECT_ATTRIBUTES wdf_attrs;
609 char *res;
610 char *Value;
611 char TmpPath[128];
613 UNREFERENCED_PARAMETER(OpenErrorStatus);
614 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
616 /* deal with medium stuff */
617 for (i = 0; i < MediumArraySize; i++)
618 {
619 if (MediumArray[i] == NdisMedium802_3)
620 {
621 medium_found = TRUE;
622 break;
623 }
624 }
625 if (!medium_found)
626 {
627 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
628 return NDIS_STATUS_UNSUPPORTED_MEDIA;
629 }
630 *SelectedMediumIndex = i;
632 /* Alloc memory for adapter private info */
633 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
634 if (!NT_SUCCESS(status))
635 {
636 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
637 status = NDIS_STATUS_RESOURCES;
638 goto err;
639 }
640 RtlZeroMemory(xi, sizeof(*xi));
642 /* init xennet_info */
643 xi->adapter_handle = MiniportAdapterHandle;
644 xi->rx_target = RX_DFL_MIN_TARGET;
645 xi->rx_min_target = RX_DFL_MIN_TARGET;
646 xi->rx_max_target = RX_MAX_TARGET;
648 xi->state = XenbusStateUnknown;
649 xi->backend_state = XenbusStateUnknown;
651 KeInitializeSpinLock(&xi->Lock);
653 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
654 PROTOCOL_RESERVED_SIZE_IN_PACKET);
655 if (status != NDIS_STATUS_SUCCESS)
656 {
657 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
658 status = NDIS_STATUS_RESOURCES;
659 goto err;
660 }
662 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
663 if (status != NDIS_STATUS_SUCCESS)
664 {
665 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
666 status = NDIS_STATUS_RESOURCES;
667 goto err;
668 }
670 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
671 &xi->lower_do, NULL, NULL);
672 xi->pdoData = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
674 /* Initialize tx_pkts as a free chain containing every entry. */
675 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
676 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
677 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
678 }
680 for (i = 0; i < NET_RX_RING_SIZE; i++) {
681 xi->rx_pkts[i] = NULL;
682 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
683 }
685 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
687 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
688 NAME_SIZE, xi->name, &length);
689 if (!NT_SUCCESS(status))
690 {
691 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
692 status = NDIS_STATUS_FAILURE;
693 goto err;
694 }
696 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
697 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
698 NdisInterfaceInternal);
700 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
702 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
703 xi->lower_do, xi->pdo, &xi->wdf_device);
704 if (!NT_SUCCESS(status))
705 {
706 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
707 status = NDIS_STATUS_FAILURE;
708 goto err;
709 }
711 /* get lower (Xen) interfaces */
713 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
714 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
715 if(!NT_SUCCESS(status))
716 {
717 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
718 status = NDIS_STATUS_FAILURE;
719 goto err;
720 }
722 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
723 "%s/backend", xi->pdoData->Path);
724 KdPrint(("About to read %s to get backend path\n", TmpPath));
725 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
726 XBT_NIL, TmpPath, &Value);
727 if (res)
728 {
729 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
730 xi->XenInterface.FreeMem(res);
731 status = NDIS_STATUS_FAILURE;
732 goto err;
733 }
734 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
735 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
737 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
739 /* Add watch on backend state */
740 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
741 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
742 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
744 // wait here for signal that we are all set up
745 while (xi->backend_state != XenbusStateConnected)
746 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
748 /* get mac address */
749 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->BackendPath);
750 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
751 XBT_NIL, TmpPath, &Value);
752 if (!Value)
753 {
754 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
755 status = NDIS_STATUS_FAILURE;
756 goto err;
757 }
758 else
759 {
760 char *s, *e;
761 int i;
762 s = Value;
763 for (i = 0; i < ETH_ALEN; i++) {
764 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
765 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
766 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
767 xi->XenInterface.FreeMem(Value);
768 status = NDIS_STATUS_FAILURE;
769 goto err;
770 }
771 s = e + 1;
772 }
773 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
774 xi->XenInterface.FreeMem(Value);
775 }
777 return NDIS_STATUS_SUCCESS;
779 err:
780 NdisFreeMemory(xi, 0, 0);
781 return status;
782 }
784 // Q = Query Mandatory, S = Set Mandatory
785 NDIS_OID supported_oids[] =
786 {
787 /* general OIDs */
788 OID_GEN_SUPPORTED_LIST, // Q
789 OID_GEN_HARDWARE_STATUS, // Q
790 OID_GEN_MEDIA_SUPPORTED, // Q
791 OID_GEN_MEDIA_IN_USE, // Q
792 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
793 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
794 OID_GEN_LINK_SPEED, // Q
795 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
796 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
797 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
798 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
799 OID_GEN_VENDOR_ID, // Q
800 OID_GEN_VENDOR_DESCRIPTION, // Q
801 OID_GEN_CURRENT_PACKET_FILTER, // QS
802 OID_GEN_CURRENT_LOOKAHEAD, // QS
803 OID_GEN_DRIVER_VERSION, // Q
804 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
805 OID_GEN_PROTOCOL_OPTIONS, // S
806 OID_GEN_MAC_OPTIONS, // Q
807 OID_GEN_MEDIA_CONNECT_STATUS, // Q
808 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
809 /* stats */
810 OID_GEN_XMIT_OK, // Q
811 OID_GEN_RCV_OK, // Q
812 OID_GEN_XMIT_ERROR, // Q
813 OID_GEN_RCV_ERROR, // Q
814 OID_GEN_RCV_NO_BUFFER, // Q
815 /* media-specific OIDs */
816 OID_802_3_PERMANENT_ADDRESS,
817 OID_802_3_CURRENT_ADDRESS,
818 OID_802_3_MULTICAST_LIST,
819 OID_802_3_MAXIMUM_LIST_SIZE,
820 };
822 NDIS_STATUS
823 XenNet_QueryInformation(
824 IN NDIS_HANDLE MiniportAdapterContext,
825 IN NDIS_OID Oid,
826 IN PVOID InformationBuffer,
827 IN ULONG InformationBufferLength,
828 OUT PULONG BytesWritten,
829 OUT PULONG BytesNeeded)
830 {
831 struct xennet_info *xi = MiniportAdapterContext;
832 UCHAR vendor_desc[] = XN_VENDOR_DESC;
833 ULONG64 temp_data;
834 PVOID data = &temp_data;
835 UINT len = 4;
836 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
838 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
840 switch(Oid)
841 {
842 case OID_GEN_SUPPORTED_LIST:
843 data = supported_oids;
844 len = sizeof(supported_oids);
845 break;
846 case OID_GEN_HARDWARE_STATUS:
847 if (!xi->connected)
848 temp_data = NdisHardwareStatusInitializing;
849 else
850 temp_data = NdisHardwareStatusReady;
851 break;
852 case OID_GEN_MEDIA_SUPPORTED:
853 temp_data = NdisMedium802_3;
854 break;
855 case OID_GEN_MEDIA_IN_USE:
856 temp_data = NdisMedium802_3;
857 break;
858 case OID_GEN_MAXIMUM_LOOKAHEAD:
859 temp_data = XN_DATA_SIZE;
860 break;
861 case OID_GEN_MAXIMUM_FRAME_SIZE:
862 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
863 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
864 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
865 break;
866 case OID_GEN_LINK_SPEED:
867 temp_data = 10000000; /* 1Gb */
868 break;
869 case OID_GEN_TRANSMIT_BUFFER_SPACE:
870 /* pkts times sizeof ring, maybe? */
871 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
872 break;
873 case OID_GEN_RECEIVE_BUFFER_SPACE:
874 /* pkts times sizeof ring, maybe? */
875 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
876 break;
877 case OID_GEN_TRANSMIT_BLOCK_SIZE:
878 temp_data = XN_MAX_PKT_SIZE;
879 break;
880 case OID_GEN_RECEIVE_BLOCK_SIZE:
881 temp_data = XN_MAX_PKT_SIZE;
882 break;
883 case OID_GEN_VENDOR_ID:
884 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
885 break;
886 case OID_GEN_VENDOR_DESCRIPTION:
887 data = vendor_desc;
888 len = sizeof(vendor_desc);
889 break;
890 case OID_GEN_CURRENT_PACKET_FILTER:
891 temp_data = xi->packet_filter;
892 break;
893 case OID_GEN_CURRENT_LOOKAHEAD:
894 // TODO: we should store this...
895 temp_data = XN_MAX_PKT_SIZE;
896 break;
897 case OID_GEN_DRIVER_VERSION:
898 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
899 len = 2;
900 break;
901 case OID_GEN_MAXIMUM_TOTAL_SIZE:
902 temp_data = XN_MAX_PKT_SIZE;
903 break;
904 case OID_GEN_MAC_OPTIONS:
905 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
906 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
907 NDIS_MAC_OPTION_NO_LOOPBACK;
908 break;
909 case OID_GEN_MEDIA_CONNECT_STATUS:
910 if (xi->connected)
911 temp_data = NdisMediaStateConnected;
912 else
913 temp_data = NdisMediaStateDisconnected;
914 break;
915 case OID_GEN_MAXIMUM_SEND_PACKETS:
916 temp_data = XN_MAX_SEND_PKTS;
917 break;
918 case OID_GEN_XMIT_OK:
919 temp_data = xi->stat_tx_ok;
920 len = sizeof(ULONG64);
921 break;
922 case OID_GEN_RCV_OK:
923 temp_data = xi->stat_rx_ok;
924 len = sizeof(ULONG64);
925 break;
926 case OID_GEN_XMIT_ERROR:
927 temp_data = xi->stat_tx_error;
928 len = sizeof(ULONG64);
929 break;
930 case OID_GEN_RCV_ERROR:
931 temp_data = xi->stat_rx_error;
932 len = sizeof(ULONG64);
933 break;
934 case OID_GEN_RCV_NO_BUFFER:
935 temp_data = xi->stat_rx_no_buffer;
936 len = sizeof(ULONG64);
937 break;
938 case OID_802_3_PERMANENT_ADDRESS:
939 data = xi->perm_mac_addr;
940 len = ETH_ALEN;
941 break;
942 case OID_802_3_CURRENT_ADDRESS:
943 data = xi->curr_mac_addr;
944 len = ETH_ALEN;
945 break;
946 case OID_802_3_MULTICAST_LIST:
947 data = NULL;
948 len = 0;
949 case OID_802_3_MAXIMUM_LIST_SIZE:
950 temp_data = 0; /* no mcast support */
951 break;
952 default:
953 KdPrint(("Get Unknown OID 0x%x\n", Oid));
954 status = NDIS_STATUS_NOT_SUPPORTED;
955 }
957 if (!NT_SUCCESS(status))
958 {
959 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
960 return status;
961 }
963 if (len > InformationBufferLength)
964 {
965 *BytesNeeded = len;
966 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
967 return NDIS_STATUS_BUFFER_TOO_SHORT;
968 }
970 *BytesWritten = len;
971 if (len)
972 {
973 NdisMoveMemory(InformationBuffer, data, len);
974 }
976 //KdPrint(("Got OID 0x%x\n", Oid));
977 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
979 return status;
980 }
982 NDIS_STATUS
983 XenNet_SetInformation(
984 IN NDIS_HANDLE MiniportAdapterContext,
985 IN NDIS_OID Oid,
986 IN PVOID InformationBuffer,
987 IN ULONG InformationBufferLength,
988 OUT PULONG BytesRead,
989 OUT PULONG BytesNeeded
990 )
991 {
992 NTSTATUS status;
993 struct xennet_info *xi = MiniportAdapterContext;
994 PULONG64 data = InformationBuffer;
996 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
998 UNREFERENCED_PARAMETER(MiniportAdapterContext);
999 UNREFERENCED_PARAMETER(InformationBufferLength);
1000 UNREFERENCED_PARAMETER(BytesRead);
1001 UNREFERENCED_PARAMETER(BytesNeeded);
1003 switch(Oid)
1005 case OID_GEN_SUPPORTED_LIST:
1006 status = NDIS_STATUS_NOT_SUPPORTED;
1007 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1008 break;
1009 case OID_GEN_HARDWARE_STATUS:
1010 status = NDIS_STATUS_NOT_SUPPORTED;
1011 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1012 break;
1013 case OID_GEN_MEDIA_SUPPORTED:
1014 status = NDIS_STATUS_NOT_SUPPORTED;
1015 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1016 break;
1017 case OID_GEN_MEDIA_IN_USE:
1018 status = NDIS_STATUS_NOT_SUPPORTED;
1019 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1020 break;
1021 case OID_GEN_MAXIMUM_LOOKAHEAD:
1022 status = NDIS_STATUS_NOT_SUPPORTED;
1023 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1024 break;
1025 case OID_GEN_MAXIMUM_FRAME_SIZE:
1026 status = NDIS_STATUS_NOT_SUPPORTED;
1027 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1028 break;
1029 case OID_GEN_LINK_SPEED:
1030 status = NDIS_STATUS_NOT_SUPPORTED;
1031 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1032 break;
1033 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1034 status = NDIS_STATUS_NOT_SUPPORTED;
1035 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1036 break;
1037 case OID_GEN_RECEIVE_BUFFER_SPACE:
1038 status = NDIS_STATUS_NOT_SUPPORTED;
1039 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1040 break;
1041 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1042 status = NDIS_STATUS_NOT_SUPPORTED;
1043 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1044 break;
1045 case OID_GEN_RECEIVE_BLOCK_SIZE:
1046 status = NDIS_STATUS_NOT_SUPPORTED;
1047 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1048 break;
1049 case OID_GEN_VENDOR_ID:
1050 status = NDIS_STATUS_NOT_SUPPORTED;
1051 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1052 break;
1053 case OID_GEN_VENDOR_DESCRIPTION:
1054 status = NDIS_STATUS_NOT_SUPPORTED;
1055 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1056 break;
1057 case OID_GEN_CURRENT_PACKET_FILTER:
1058 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1059 xi->packet_filter = *(ULONG *)data;
1060 status = NDIS_STATUS_SUCCESS;
1061 break;
1062 case OID_GEN_CURRENT_LOOKAHEAD:
1063 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1064 // TODO: We should do this...
1065 status = NDIS_STATUS_SUCCESS;
1066 break;
1067 case OID_GEN_DRIVER_VERSION:
1068 status = NDIS_STATUS_NOT_SUPPORTED;
1069 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1070 break;
1071 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1072 status = NDIS_STATUS_NOT_SUPPORTED;
1073 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1074 break;
1075 case OID_GEN_PROTOCOL_OPTIONS:
1076 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1077 // TODO - actually do this...
1078 status = NDIS_STATUS_SUCCESS;
1079 break;
1080 case OID_GEN_MAC_OPTIONS:
1081 status = NDIS_STATUS_NOT_SUPPORTED;
1082 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1083 break;
1084 case OID_GEN_MEDIA_CONNECT_STATUS:
1085 status = NDIS_STATUS_NOT_SUPPORTED;
1086 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1087 break;
1088 case OID_GEN_MAXIMUM_SEND_PACKETS:
1089 status = NDIS_STATUS_NOT_SUPPORTED;
1090 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1091 break;
1092 case OID_GEN_XMIT_OK:
1093 status = NDIS_STATUS_NOT_SUPPORTED;
1094 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1095 break;
1096 case OID_GEN_RCV_OK:
1097 status = NDIS_STATUS_NOT_SUPPORTED;
1098 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1099 break;
1100 case OID_GEN_XMIT_ERROR:
1101 status = NDIS_STATUS_NOT_SUPPORTED;
1102 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1103 break;
1104 case OID_GEN_RCV_ERROR:
1105 status = NDIS_STATUS_NOT_SUPPORTED;
1106 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1107 break;
1108 case OID_GEN_RCV_NO_BUFFER:
1109 status = NDIS_STATUS_NOT_SUPPORTED;
1110 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1111 break;
1112 case OID_802_3_PERMANENT_ADDRESS:
1113 status = NDIS_STATUS_NOT_SUPPORTED;
1114 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1115 break;
1116 case OID_802_3_CURRENT_ADDRESS:
1117 status = NDIS_STATUS_NOT_SUPPORTED;
1118 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1119 break;
1120 case OID_802_3_MULTICAST_LIST:
1121 status = NDIS_STATUS_NOT_SUPPORTED;
1122 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1123 break;
1124 case OID_802_3_MAXIMUM_LIST_SIZE:
1125 status = NDIS_STATUS_NOT_SUPPORTED;
1126 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1127 break;
1128 default:
1129 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1130 status = NDIS_STATUS_NOT_SUPPORTED;
1131 break;
1133 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1134 return status;
1137 VOID
1138 XenNet_ReturnPacket(
1139 IN NDIS_HANDLE MiniportAdapterContext,
1140 IN PNDIS_PACKET Packet
1143 PNDIS_BUFFER buffer;
1144 PVOID buff_va;
1145 UINT buff_len;
1146 UINT tot_buff_len;
1148 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1150 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1152 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1153 &tot_buff_len, NormalPagePriority);
1154 ASSERT(buff_len == tot_buff_len);
1156 NdisFreeMemory(buff_va, 0, 0);
1157 NdisFreeBuffer(buffer);
1158 NdisFreePacket(Packet);
1160 //KdPrint((__FUNCTION__ " called\n"));
1161 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1164 PMDL
1165 XenNet_Linearize(PNDIS_PACKET Packet)
1167 NDIS_STATUS status;
1168 PMDL pmdl;
1169 char *start;
1170 PNDIS_BUFFER buffer;
1171 PVOID buff_va;
1172 UINT buff_len;
1173 UINT tot_buff_len;
1175 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1177 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1178 &tot_buff_len, NormalPagePriority);
1179 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1181 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1182 if (!NT_SUCCESS(status))
1184 KdPrint(("Could not allocate memory for linearization\n"));
1185 return NULL;
1187 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1188 if (!pmdl)
1190 KdPrint(("Could not allocate MDL for linearization\n"));
1191 NdisFreeMemory(start, 0, 0);
1192 return NULL;
1194 MmBuildMdlForNonPagedPool(pmdl);
1196 while (buffer)
1198 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1199 RtlCopyMemory(start, buff_va, buff_len);
1200 start += buff_len;
1201 NdisGetNextBuffer(buffer, &buffer);
1204 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1205 return pmdl;
1208 VOID
1209 XenNet_SendPackets(
1210 IN NDIS_HANDLE MiniportAdapterContext,
1211 IN PPNDIS_PACKET PacketArray,
1212 IN UINT NumberOfPackets
1215 struct xennet_info *xi = MiniportAdapterContext;
1216 PNDIS_PACKET curr_packet;
1217 UINT i;
1218 struct netif_tx_request *tx;
1219 unsigned short id;
1220 int notify;
1221 PMDL pmdl;
1222 UINT pkt_size;
1223 KIRQL OldIrql;
1225 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1227 KeAcquireSpinLock(&xi->Lock, &OldIrql);
1229 for (i = 0; i < NumberOfPackets; i++)
1231 curr_packet = PacketArray[i];
1232 ASSERT(curr_packet);
1234 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1236 //KdPrint(("sending pkt, len %d\n", pkt_size));
1238 pmdl = XenNet_Linearize(curr_packet);
1239 if (!pmdl)
1241 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1242 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1243 break;
1245 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1247 id = get_id_from_freelist(xi->tx_pkts);
1248 xi->tx_pkts[id] = curr_packet;
1250 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1251 tx->id = id;
1252 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1253 xi->XenInterface.InterfaceHeader.Context,
1254 0,
1255 *MmGetMdlPfnArray(pmdl),
1256 TRUE);
1257 xi->grant_tx_ref[id] = tx->gref;
1258 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1259 tx->size = (UINT16)pkt_size;
1260 // NETTXF_csum_blank should only be used for tcp and udp packets...
1261 tx->flags = 0; //NETTXF_csum_blank;
1263 xi->tx.req_prod_pvt++;
1265 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1266 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1269 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1270 if (notify)
1272 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1273 xi->event_channel);
1276 KeReleaseSpinLock(&xi->Lock, OldIrql);
1278 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1281 VOID
1282 XenNet_PnPEventNotify(
1283 IN NDIS_HANDLE MiniportAdapterContext,
1284 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1285 IN PVOID InformationBuffer,
1286 IN ULONG InformationBufferLength
1289 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1290 UNREFERENCED_PARAMETER(PnPEvent);
1291 UNREFERENCED_PARAMETER(InformationBuffer);
1292 UNREFERENCED_PARAMETER(InformationBufferLength);
1294 KdPrint((__FUNCTION__ " called\n"));
1297 VOID
1298 XenNet_Shutdown(
1299 IN NDIS_HANDLE MiniportAdapterContext
1302 //struct xennet_info *xi = MiniportAdapterContext;
1303 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1305 // I think all we are supposed to do here is reset the adapter, which for us might be nothing...
1307 KdPrint((__FUNCTION__ " called\n"));
1310 NTSTATUS
1311 DriverEntry(
1312 PDRIVER_OBJECT DriverObject,
1313 PUNICODE_STRING RegistryPath
1316 NTSTATUS status;
1317 WDF_DRIVER_CONFIG config;
1318 NDIS_HANDLE ndis_wrapper_handle;
1319 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1321 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1323 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1324 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1326 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1327 &config, WDF_NO_HANDLE);
1328 if (!NT_SUCCESS(status))
1330 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1331 return status;
1334 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1335 if (!ndis_wrapper_handle)
1337 KdPrint(("NdisMInitializeWrapper failed\n"));
1338 return NDIS_STATUS_FAILURE;
1341 /* NDIS 5.1 driver */
1342 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1343 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1345 mini_chars.HaltHandler = XenNet_Halt;
1346 mini_chars.InitializeHandler = XenNet_Init;
1347 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1348 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1349 mini_chars.ResetHandler = NULL; //TODO: fill in
1350 mini_chars.SetInformationHandler = XenNet_SetInformation;
1351 /* added in v.4 -- use multiple pkts interface */
1352 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1353 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1354 /* added in v.5.1 */
1355 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1356 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1358 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1360 /* set up upper-edge interface */
1361 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1362 if (!NT_SUCCESS(status))
1364 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1365 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1366 return status;
1369 return status;