win-pvdrivers

view xennet/xennet.c @ 104:4ad735c07462

xennet: pretty sure it's a good thing to tell backend we're initializing
author Andy Grover <andy.grover@oracle.com>
date Tue Jan 08 18:14:17 2008 -0800 (2008-01-08)
parents a96426482216
children 2f6159eaf2b1
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+1];
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+1];
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
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 void XenNet_TxBufferFree(struct xennet_info *xi)
235 {
236 PNDIS_PACKET packet;
237 PMDL pmdl;
238 unsigned short id;
240 /* TODO: free packets in tx queue (once implemented) */
242 /* free sent-but-not-completed packets */
243 for (id = 1; id < NET_TX_RING_SIZE+1; id++) {
244 if (xi->grant_tx_ref[id] == GRANT_INVALID_REF)
245 continue;
247 packet = xi->tx_pkts[id];
248 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
249 xi->grant_tx_ref[id]);
250 xi->grant_tx_ref[id] = GRANT_INVALID_REF;
251 add_id_to_freelist(xi->tx_pkts, id);
253 /* free linearized data page */
254 pmdl = *(PMDL *)packet->MiniportReservedEx;
255 NdisFreeMemory(MmGetMdlVirtualAddress(pmdl), 0, 0); // <= DISPATCH_LEVEL
256 IoFreeMdl(pmdl);
258 NdisMSendComplete(xi->adapter_handle, packet, NDIS_STATUS_FAILURE);
259 }
260 }
262 // Called at DISPATCH_LEVEL with RxLock held
263 static NDIS_STATUS
264 XenNet_RxBufferAlloc(struct xennet_info *xi)
265 {
266 unsigned short id;
267 PNDIS_PACKET packet;
268 PNDIS_BUFFER buffer;
269 int i, batch_target, notify;
270 RING_IDX req_prod = xi->rx.req_prod_pvt;
271 grant_ref_t ref;
272 netif_rx_request_t *req;
273 NDIS_STATUS status;
274 PVOID start;
276 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
278 batch_target = xi->rx_target - (req_prod - xi->rx.rsp_cons);
279 for (i = 0; i < batch_target; i++)
280 {
281 /*
282 * Allocate a packet, page, and buffer. Hook them up.
283 */
284 status = NdisAllocateMemoryWithTag(&start, PAGE_SIZE, XENNET_POOL_TAG);
285 if (status != NDIS_STATUS_SUCCESS)
286 {
287 KdPrint(("NdisAllocateMemoryWithTag Failed! status = 0x%x\n", status));
288 break;
289 }
290 NdisAllocateBuffer(&status, &buffer, xi->buffer_pool, start, PAGE_SIZE);
291 if (status != NDIS_STATUS_SUCCESS)
292 {
293 KdPrint(("NdisAllocateBuffer Failed! status = 0x%x\n", status));
294 NdisFreeMemory(start, 0, 0);
295 break;
296 }
297 NdisAllocatePacket(&status, &packet, xi->packet_pool);
298 if (status != NDIS_STATUS_SUCCESS)
299 {
300 KdPrint(("NdisAllocatePacket Failed! status = 0x%x\n", status));
301 NdisFreeMemory(start, 0, 0);
302 NdisFreeBuffer(buffer);
303 break;
304 }
305 NdisChainBufferAtBack(packet, buffer);
306 NDIS_SET_PACKET_HEADER_SIZE(packet, XN_HDR_SIZE);
308 /* Give to netback */
309 id = (unsigned short)(req_prod + i) & (NET_RX_RING_SIZE - 1);
310 ASSERT(!xi->rx_pkts[id]);
311 xi->rx_pkts[id] = packet;
312 req = RING_GET_REQUEST(&xi->rx, req_prod + i);
313 /* an NDIS_BUFFER is just a MDL, so we can get its pfn array */
314 ref = xi->XenInterface.GntTbl_GrantAccess(
315 xi->XenInterface.InterfaceHeader.Context, 0,
316 *MmGetMdlPfnArray(buffer), FALSE);
317 ASSERT((signed short)ref >= 0);
318 xi->grant_rx_ref[id] = ref;
320 req->id = id;
321 req->gref = ref;
322 }
324 xi->rx.req_prod_pvt = req_prod + i;
325 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->rx, notify);
326 if (notify)
327 {
328 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
329 xi->event_channel);
330 }
332 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
334 return NDIS_STATUS_SUCCESS;
335 }
337 static void
338 XenNet_RxBufferFree(struct xennet_info *xi)
339 {
340 int i;
341 grant_ref_t ref;
342 PNDIS_PACKET packet;
343 PNDIS_BUFFER buffer;
344 PVOID buff_va;
345 UINT buff_len;
346 UINT tot_buff_len;
347 KIRQL OldIrql;
349 ASSERT(!xi->connected);
351 KeAcquireSpinLock(&xi->RxLock, &OldIrql);
353 for (i = 0; i < NET_RX_RING_SIZE; i++)
354 {
355 if (!xi->rx_pkts[i])
356 continue;
358 packet = xi->rx_pkts[i];
359 ref = xi->grant_rx_ref[i];
361 /* don't check return, what can we do about it on failure? */
362 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context, ref);
364 NdisGetFirstBufferFromPacketSafe(packet, &buffer, &buff_va, &buff_len,
365 &tot_buff_len, NormalPagePriority);
366 ASSERT(buff_len == tot_buff_len);
368 NdisFreeMemory(buff_va, 0, 0);
369 NdisFreeBuffer(buffer);
370 NdisFreePacket(packet);
371 }
373 KeReleaseSpinLock(&xi->RxLock, OldIrql);
374 }
376 // Called at DISPATCH_LEVEL
377 static NDIS_STATUS
378 XenNet_RxBufferCheck(struct xennet_info *xi)
379 {
380 RING_IDX cons, prod;
382 PNDIS_PACKET packet;
383 PNDIS_BUFFER buffer;
384 PVOID buff_va;
385 UINT buff_len;
386 UINT tot_buff_len;
387 int moretodo;
388 KIRQL OldIrql;
389 PNDIS_TCP_IP_CHECKSUM_PACKET_INFO csum_info;
391 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
393 ASSERT(xi->connected);
395 KeAcquireSpinLock(&xi->RxLock, &OldIrql);
397 do {
398 prod = xi->rx.sring->rsp_prod;
399 KeMemoryBarrier(); /* Ensure we see responses up to 'rp'. */
401 for (cons = xi->rx.rsp_cons; cons != prod; cons++) {
402 struct netif_rx_response *rxrsp;
404 rxrsp = RING_GET_RESPONSE(&xi->rx, cons);
405 if (rxrsp->status == NETIF_RSP_NULL)
406 continue;
408 // KdPrint((__DRIVER_NAME " Got a packet\n"));
410 packet = xi->rx_pkts[rxrsp->id];
411 xi->rx_pkts[rxrsp->id] = NULL;
412 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
413 xi->grant_rx_ref[rxrsp->id]);
414 xi->grant_rx_ref[rxrsp->id] = GRANT_INVALID_REF;
416 NdisGetFirstBufferFromPacketSafe(packet, &buffer, &buff_va, &buff_len,
417 &tot_buff_len, NormalPagePriority);
418 ASSERT(rxrsp->offset == 0);
419 ASSERT(rxrsp->status > 0);
420 NdisAdjustBufferLength(buffer, rxrsp->status);
422 #if 0
423 KdPrint((__DRIVER_NAME " Flags = %sNETRXF_data_validated|%sNETRXF_csum_blank|%sNETRXF_more_data|%sNETRXF_extra_info\n",
424 (rxrsp->flags|NETRXF_data_validated)?"":"!",
425 (rxrsp->flags|NETRXF_csum_blank)?"":"!",
426 (rxrsp->flags|NETRXF_more_data)?"":"!",
427 (rxrsp->flags|NETRXF_extra_info)?"":"!"));
428 #endif
429 // maybe use NDIS_GET_PACKET_PROTOCOL_TYPE(Packet) here and check for == NDIS_PROTOCOL_ID_TCP_IP etc
431 csum_info = (PNDIS_TCP_IP_CHECKSUM_PACKET_INFO)&NDIS_PER_PACKET_INFO_FROM_PACKET(packet, TcpIpChecksumPacketInfo);
432 csum_info->Receive.NdisPacketTcpChecksumSucceeded = 1;
433 csum_info->Receive.NdisPacketUdpChecksumSucceeded = 1;
434 csum_info->Receive.NdisPacketIpChecksumSucceeded = 1;
436 xi->stat_rx_ok++;
437 NDIS_SET_PACKET_STATUS(packet, NDIS_STATUS_SUCCESS);
439 /* just indicate 1 packet for now */
440 // KdPrint((__DRIVER_NAME " Indicating Received\n"));
441 NdisMIndicateReceivePacket(xi->adapter_handle, &packet, 1);
442 // KdPrint((__DRIVER_NAME " Done Indicating Received\n"));
443 }
445 xi->rx.rsp_cons = prod;
447 RING_FINAL_CHECK_FOR_RESPONSES(&xi->rx, moretodo);
448 } while (moretodo);
450 /* Give netback more buffers */
451 XenNet_RxBufferAlloc(xi);
453 KeReleaseSpinLock(&xi->RxLock, OldIrql);
455 //xi->rx.sring->rsp_event = xi->rx.rsp_cons + 1;
457 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
459 return NDIS_STATUS_SUCCESS;
460 }
462 // Called at DISPATCH_LEVEL
463 static BOOLEAN
464 XenNet_Interrupt(
465 PKINTERRUPT Interrupt,
466 PVOID ServiceContext
467 )
468 {
469 struct xennet_info *xi = ServiceContext;
471 UNREFERENCED_PARAMETER(Interrupt);
473 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
475 if (xi->connected)
476 {
477 XenNet_TxBufferGC(xi);
478 XenNet_RxBufferCheck(xi);
479 }
481 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
483 return TRUE;
484 }
486 // Called at <= DISPATCH_LEVEL
488 static VOID
489 XenNet_BackEndStateHandler(char *Path, PVOID Data)
490 {
491 struct xennet_info *xi = Data;
492 char *Value;
493 char TmpPath[128];
494 xenbus_transaction_t xbt = 0;
495 int retry = 0;
496 char *err;
497 int i;
498 ULONG new_backend_state;
500 struct set_params {
501 char *name;
502 int value;
503 } params[] = {
504 {"tx-ring-ref", 0},
505 {"rx-ring-ref", 0},
506 {"event-channel", 0},
507 {"request-rx-copy", 1},
508 {"feature-rx-notify", 1},
509 {"feature-no-csum-offload", 0},
510 {"feature-sg", 1},
511 {"feature-gso-tcpv4", 0},
512 {NULL, 0},
513 };
515 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
516 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
518 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
519 XBT_NIL, Path, &Value);
520 new_backend_state = atoi(Value);
521 xi->XenInterface.FreeMem(Value);
523 if (xi->backend_state == new_backend_state)
524 {
525 KdPrint((__DRIVER_NAME " state unchanged\n"));
526 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
527 return;
528 }
530 xi->backend_state = new_backend_state;
532 switch (xi->backend_state)
533 {
534 case XenbusStateUnknown:
535 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
536 break;
538 case XenbusStateInitialising:
539 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
540 break;
542 case XenbusStateInitWait:
543 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
545 xi->event_channel = xi->XenInterface.EvtChn_AllocUnbound(
546 xi->XenInterface.InterfaceHeader.Context, 0);
547 xi->XenInterface.EvtChn_BindDpc(xi->XenInterface.InterfaceHeader.Context,
548 xi->event_channel, XenNet_Interrupt, xi);
550 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
551 // or, allocate mem and then get mdl, then free mdl
552 xi->tx_mdl = AllocatePage();
553 xi->tx_pgs = MmGetMdlVirtualAddress(xi->tx_mdl); //MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
554 SHARED_RING_INIT(xi->tx_pgs);
555 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
556 xi->tx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
557 xi->XenInterface.InterfaceHeader.Context, 0,
558 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
560 xi->rx_mdl = AllocatePage();
561 xi->rx_pgs = MmGetMdlVirtualAddress(xi->rx_mdl); //MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached, NULL, FALSE, NormalPagePriority);
562 SHARED_RING_INIT(xi->rx_pgs);
563 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
564 xi->rx_ring_ref = xi->XenInterface.GntTbl_GrantAccess(
565 xi->XenInterface.InterfaceHeader.Context, 0,
566 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
568 /* fixup array for dynamic values */
569 params[0].value = xi->tx_ring_ref;
570 params[1].value = xi->rx_ring_ref;
571 params[2].value = xi->event_channel;
573 xi->XenInterface.XenBus_StartTransaction(
574 xi->XenInterface.InterfaceHeader.Context, &xbt);
576 for (i = 0; params[i].name; i++)
577 {
578 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/%s",
579 xi->pdoData->Path, params[i].name);
580 err = xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
581 XBT_NIL, TmpPath, "%d", params[i].value);
582 if (err)
583 {
584 KdPrint(("setting %s failed, err = %s\n", params[i].name, err));
585 goto trouble;
586 }
587 }
589 /* commit transaction */
590 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
591 xbt, 0, &retry);
593 XenNet_RxBufferAlloc(xi);
595 xi->state = XenbusStateConnected;
596 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
597 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
598 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
599 XBT_NIL, TmpPath, "%d", xi->state);
601 /* send fake arp? */
603 xi->connected = TRUE;
605 break;
607 case XenbusStateInitialised:
608 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
609 break;
611 case XenbusStateConnected:
612 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
613 break;
615 case XenbusStateClosing:
616 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
617 break;
619 case XenbusStateClosed:
620 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
621 break;
623 default:
624 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", xi->backend_state));
625 break;
626 }
628 KeSetEvent(&xi->backend_state_change_event, 1, FALSE);
630 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
632 return;
634 trouble:
635 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
636 xi->XenInterface.XenBus_EndTransaction(xi->XenInterface.InterfaceHeader.Context,
637 xbt, 1, &retry);
638 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
639 }
641 static NDIS_STATUS
642 XenNet_Init(
643 OUT PNDIS_STATUS OpenErrorStatus,
644 OUT PUINT SelectedMediumIndex,
645 IN PNDIS_MEDIUM MediumArray,
646 IN UINT MediumArraySize,
647 IN NDIS_HANDLE MiniportAdapterHandle,
648 IN NDIS_HANDLE WrapperConfigurationContext
649 )
650 {
651 NDIS_STATUS status;
652 UINT i;
653 BOOLEAN medium_found = FALSE;
654 struct xennet_info *xi = NULL;
655 ULONG length;
656 WDF_OBJECT_ATTRIBUTES wdf_attrs;
657 char *res;
658 char *Value;
659 char TmpPath[128];
661 UNREFERENCED_PARAMETER(OpenErrorStatus);
662 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
664 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
665 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
667 /* deal with medium stuff */
668 for (i = 0; i < MediumArraySize; i++)
669 {
670 if (MediumArray[i] == NdisMedium802_3)
671 {
672 medium_found = TRUE;
673 break;
674 }
675 }
676 if (!medium_found)
677 {
678 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
679 return NDIS_STATUS_UNSUPPORTED_MEDIA;
680 }
681 *SelectedMediumIndex = i;
683 /* Alloc memory for adapter private info */
684 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
685 if (!NT_SUCCESS(status))
686 {
687 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
688 status = NDIS_STATUS_RESOURCES;
689 goto err;
690 }
691 RtlZeroMemory(xi, sizeof(*xi));
693 /* init xennet_info */
694 xi->adapter_handle = MiniportAdapterHandle;
695 xi->rx_target = RX_DFL_MIN_TARGET;
696 xi->rx_min_target = RX_DFL_MIN_TARGET;
697 xi->rx_max_target = RX_MAX_TARGET;
699 xi->state = XenbusStateUnknown;
700 xi->backend_state = XenbusStateUnknown;
702 KeInitializeSpinLock(&xi->TxLock);
703 KeInitializeSpinLock(&xi->RxLock);
705 NdisAllocatePacketPool(&status, &xi->packet_pool, NET_RX_RING_SIZE,
706 PROTOCOL_RESERVED_SIZE_IN_PACKET);
707 if (status != NDIS_STATUS_SUCCESS)
708 {
709 KdPrint(("NdisAllocatePacketPool failed with 0x%x\n", status));
710 status = NDIS_STATUS_RESOURCES;
711 goto err;
712 }
714 NdisAllocateBufferPool(&status, &xi->buffer_pool, NET_RX_RING_SIZE);
715 if (status != NDIS_STATUS_SUCCESS)
716 {
717 KdPrint(("NdisAllocateBufferPool failed with 0x%x\n", status));
718 status = NDIS_STATUS_RESOURCES;
719 goto err;
720 }
722 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
723 &xi->lower_do, NULL, NULL);
724 xi->pdoData = (PXENPCI_XEN_DEVICE_DATA)xi->pdo->DeviceExtension;
726 /* Initialize tx_pkts as a free chain containing every entry. */
727 for (i = 0; i < NET_TX_RING_SIZE+1; i++) {
728 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
729 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
730 }
732 for (i = 0; i < NET_RX_RING_SIZE; i++) {
733 xi->rx_pkts[i] = NULL;
734 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
735 }
737 xi->packet_filter = NDIS_PACKET_TYPE_PROMISCUOUS;
739 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
740 NAME_SIZE, xi->name, &length);
741 if (!NT_SUCCESS(status))
742 {
743 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
744 status = NDIS_STATUS_FAILURE;
745 goto err;
746 }
748 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
749 0, (NDIS_ATTRIBUTE_DESERIALIZE /*| NDIS_ATTRIBUTE_BUS_MASTER*/),
750 NdisInterfaceInternal);
752 WDF_OBJECT_ATTRIBUTES_INIT(&wdf_attrs);
754 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
755 xi->lower_do, xi->pdo, &xi->wdf_device);
756 if (!NT_SUCCESS(status))
757 {
758 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
759 status = NDIS_STATUS_FAILURE;
760 goto err;
761 }
763 /* get lower (Xen) interfaces */
765 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE,
766 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE), 1, NULL);
767 if(!NT_SUCCESS(status))
768 {
769 KdPrint(("WdfFdoQueryForInterface failed with status 0x%08x\n", status));
770 status = NDIS_STATUS_FAILURE;
771 goto err;
772 }
774 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
775 "%s/backend", xi->pdoData->Path);
776 KdPrint(("About to read %s to get backend path\n", TmpPath));
777 res = xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
778 XBT_NIL, TmpPath, &Value);
779 if (res)
780 {
781 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
782 xi->XenInterface.FreeMem(res);
783 status = NDIS_STATUS_FAILURE;
784 goto err;
785 }
786 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
787 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
789 KeInitializeEvent(&xi->backend_state_change_event, SynchronizationEvent, FALSE);
791 /* Add watch on backend state */
792 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
793 xi->XenInterface.XenBus_AddWatch(xi->XenInterface.InterfaceHeader.Context,
794 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
796 /* Tell backend we're coming up */
797 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
798 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
799 XBT_NIL, TmpPath, "%d", XenbusStateInitialising);
801 KdPrint((__DRIVER_NAME " Waiting for backend to connect\n"));
803 // wait here for signal that we are all set up
804 while (xi->backend_state != XenbusStateConnected)
805 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
807 KdPrint((__DRIVER_NAME " Connected\n"));
809 /* get mac address */
810 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->BackendPath);
811 xi->XenInterface.XenBus_Read(xi->XenInterface.InterfaceHeader.Context,
812 XBT_NIL, TmpPath, &Value);
813 if (!Value)
814 {
815 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
816 status = NDIS_STATUS_FAILURE;
817 goto err;
818 }
819 else
820 {
821 char *s, *e;
822 s = Value;
823 for (i = 0; i < ETH_ALEN; i++) {
824 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
825 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
826 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
827 xi->XenInterface.FreeMem(Value);
828 status = NDIS_STATUS_FAILURE;
829 goto err;
830 }
831 s = e + 1;
832 }
833 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
834 xi->XenInterface.FreeMem(Value);
835 }
837 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
839 return NDIS_STATUS_SUCCESS;
841 err:
842 NdisFreeMemory(xi, 0, 0);
843 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
844 return status;
845 }
847 // Q = Query Mandatory, S = Set Mandatory
848 NDIS_OID supported_oids[] =
849 {
850 /* general OIDs */
851 OID_GEN_SUPPORTED_LIST, // Q
852 OID_GEN_HARDWARE_STATUS, // Q
853 OID_GEN_MEDIA_SUPPORTED, // Q
854 OID_GEN_MEDIA_IN_USE, // Q
855 OID_GEN_MAXIMUM_LOOKAHEAD, // Q
856 OID_GEN_MAXIMUM_FRAME_SIZE, // Q
857 OID_GEN_LINK_SPEED, // Q
858 OID_GEN_TRANSMIT_BUFFER_SPACE, // Q
859 OID_GEN_RECEIVE_BUFFER_SPACE, // Q
860 OID_GEN_TRANSMIT_BLOCK_SIZE, // Q
861 OID_GEN_RECEIVE_BLOCK_SIZE, // Q
862 OID_GEN_VENDOR_ID, // Q
863 OID_GEN_VENDOR_DESCRIPTION, // Q
864 OID_GEN_CURRENT_PACKET_FILTER, // QS
865 OID_GEN_CURRENT_LOOKAHEAD, // QS
866 OID_GEN_DRIVER_VERSION, // Q
867 OID_GEN_MAXIMUM_TOTAL_SIZE, // Q
868 OID_GEN_PROTOCOL_OPTIONS, // S
869 OID_GEN_MAC_OPTIONS, // Q
870 OID_GEN_MEDIA_CONNECT_STATUS, // Q
871 OID_GEN_MAXIMUM_SEND_PACKETS, // Q
872 /* stats */
873 OID_GEN_XMIT_OK, // Q
874 OID_GEN_RCV_OK, // Q
875 OID_GEN_XMIT_ERROR, // Q
876 OID_GEN_RCV_ERROR, // Q
877 OID_GEN_RCV_NO_BUFFER, // Q
878 /* media-specific OIDs */
879 OID_802_3_PERMANENT_ADDRESS,
880 OID_802_3_CURRENT_ADDRESS,
881 OID_802_3_MULTICAST_LIST,
882 OID_802_3_MAXIMUM_LIST_SIZE,
883 /* tcp offload */
884 OID_TCP_TASK_OFFLOAD,
885 };
887 /* return 4 or 8 depending on size of buffer */
888 #define HANDLE_STAT_RETURN \
889 {if (InformationBufferLength == 4) { \
890 len = 4; *BytesNeeded = 8; \
891 } else { \
892 len = 8; \
893 } }
895 //#define LARGE_SEND
897 NDIS_STATUS
898 XenNet_QueryInformation(
899 IN NDIS_HANDLE MiniportAdapterContext,
900 IN NDIS_OID Oid,
901 IN PVOID InformationBuffer,
902 IN ULONG InformationBufferLength,
903 OUT PULONG BytesWritten,
904 OUT PULONG BytesNeeded)
905 {
906 struct xennet_info *xi = MiniportAdapterContext;
907 UCHAR vendor_desc[] = XN_VENDOR_DESC;
908 ULONG64 temp_data;
909 PVOID data = &temp_data;
910 ULONG offset = 0;
911 UINT len = 4;
912 BOOLEAN used_temp_buffer = TRUE;
913 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
914 PNDIS_TASK_OFFLOAD_HEADER ntoh;
915 PNDIS_TASK_OFFLOAD nto;
916 PNDIS_TASK_TCP_IP_CHECKSUM nttic;
917 #ifdef LARGE_SEND
918 PNDIS_TASK_TCP_LARGE_SEND nttls;
919 #endif
921 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
923 switch(Oid)
924 {
925 case OID_GEN_SUPPORTED_LIST:
926 data = supported_oids;
927 len = sizeof(supported_oids);
928 break;
929 case OID_GEN_HARDWARE_STATUS:
930 if (!xi->connected)
931 temp_data = NdisHardwareStatusInitializing;
932 else
933 temp_data = NdisHardwareStatusReady;
934 break;
935 case OID_GEN_MEDIA_SUPPORTED:
936 temp_data = NdisMedium802_3;
937 break;
938 case OID_GEN_MEDIA_IN_USE:
939 temp_data = NdisMedium802_3;
940 break;
941 case OID_GEN_MAXIMUM_LOOKAHEAD:
942 temp_data = XN_DATA_SIZE;
943 break;
944 case OID_GEN_MAXIMUM_FRAME_SIZE:
945 // According to the specs, OID_GEN_MAXIMUM_FRAME_SIZE does not include the header, so
946 // it is XN_DATA_SIZE not XN_MAX_PKT_SIZE
947 temp_data = XN_DATA_SIZE; // XN_MAX_PKT_SIZE;
948 break;
949 case OID_GEN_LINK_SPEED:
950 temp_data = 10000000; /* 1Gb */
951 break;
952 case OID_GEN_TRANSMIT_BUFFER_SPACE:
953 /* pkts times sizeof ring, maybe? */
954 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
955 break;
956 case OID_GEN_RECEIVE_BUFFER_SPACE:
957 /* pkts times sizeof ring, maybe? */
958 temp_data = XN_MAX_PKT_SIZE * NET_RX_RING_SIZE;
959 break;
960 case OID_GEN_TRANSMIT_BLOCK_SIZE:
961 temp_data = XN_MAX_PKT_SIZE;
962 break;
963 case OID_GEN_RECEIVE_BLOCK_SIZE:
964 temp_data = XN_MAX_PKT_SIZE;
965 break;
966 case OID_GEN_VENDOR_ID:
967 temp_data = 0xFFFFFF; // Not guaranteed to be XENSOURCE_MAC_HDR;
968 break;
969 case OID_GEN_VENDOR_DESCRIPTION:
970 data = vendor_desc;
971 len = sizeof(vendor_desc);
972 break;
973 case OID_GEN_CURRENT_PACKET_FILTER:
974 temp_data = xi->packet_filter;
975 break;
976 case OID_GEN_CURRENT_LOOKAHEAD:
977 // TODO: we should store this...
978 temp_data = XN_MAX_PKT_SIZE;
979 break;
980 case OID_GEN_DRIVER_VERSION:
981 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
982 len = 2;
983 break;
984 case OID_GEN_MAXIMUM_TOTAL_SIZE:
985 temp_data = XN_MAX_PKT_SIZE;
986 break;
987 case OID_GEN_MAC_OPTIONS:
988 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
989 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
990 NDIS_MAC_OPTION_NO_LOOPBACK;
991 break;
992 case OID_GEN_MEDIA_CONNECT_STATUS:
993 if (xi->connected)
994 temp_data = NdisMediaStateConnected;
995 else
996 temp_data = NdisMediaStateDisconnected;
997 break;
998 case OID_GEN_MAXIMUM_SEND_PACKETS:
999 temp_data = XN_MAX_SEND_PKTS;
1000 break;
1001 case OID_GEN_XMIT_OK:
1002 temp_data = xi->stat_tx_ok;
1003 HANDLE_STAT_RETURN;
1004 break;
1005 case OID_GEN_RCV_OK:
1006 temp_data = xi->stat_rx_ok;
1007 HANDLE_STAT_RETURN;
1008 break;
1009 case OID_GEN_XMIT_ERROR:
1010 temp_data = xi->stat_tx_error;
1011 HANDLE_STAT_RETURN;
1012 break;
1013 case OID_GEN_RCV_ERROR:
1014 temp_data = xi->stat_rx_error;
1015 HANDLE_STAT_RETURN;
1016 break;
1017 case OID_GEN_RCV_NO_BUFFER:
1018 temp_data = xi->stat_rx_no_buffer;
1019 HANDLE_STAT_RETURN;
1020 break;
1021 case OID_802_3_PERMANENT_ADDRESS:
1022 data = xi->perm_mac_addr;
1023 len = ETH_ALEN;
1024 break;
1025 case OID_802_3_CURRENT_ADDRESS:
1026 data = xi->curr_mac_addr;
1027 len = ETH_ALEN;
1028 break;
1029 case OID_802_3_MULTICAST_LIST:
1030 data = NULL;
1031 len = 0;
1032 case OID_802_3_MAXIMUM_LIST_SIZE:
1033 temp_data = 0; /* no mcast support */
1034 break;
1035 case OID_TCP_TASK_OFFLOAD:
1036 KdPrint(("Get OID_TCP_TASK_OFFLOAD\n"));
1037 /* it's times like this that C really sucks */
1038 len = sizeof(NDIS_TASK_OFFLOAD_HEADER)
1039 + FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1040 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1041 #ifdef LARGE_SEND
1042 len += FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1043 + sizeof(NDIS_TASK_TCP_LARGE_SEND);
1044 #endif
1046 if (len > InformationBufferLength)
1048 break;
1051 ntoh = InformationBuffer;
1052 ASSERT(ntoh->Version == NDIS_TASK_OFFLOAD_VERSION);
1053 ASSERT(ntoh->Size == sizeof(*ntoh));
1054 ASSERT(ntoh->EncapsulationFormat.Encapsulation == IEEE_802_3_Encapsulation);
1055 ntoh->OffsetFirstTask = ntoh->Size;
1057 /* fill in first nto */
1058 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + ntoh->OffsetFirstTask);
1059 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1060 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1061 nto->Task = TcpIpChecksumNdisTask;
1062 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1064 /* fill in checksum offload struct */
1065 nttic = (PNDIS_TASK_TCP_IP_CHECKSUM)nto->TaskBuffer;
1066 nttic->V4Transmit.IpOptionsSupported = 0;
1067 nttic->V4Transmit.TcpOptionsSupported = 0;
1068 nttic->V4Transmit.TcpChecksum = 0;
1069 nttic->V4Transmit.UdpChecksum = 0;
1070 nttic->V4Transmit.IpChecksum = 0;
1071 nttic->V4Receive.IpOptionsSupported = 1;
1072 nttic->V4Receive.TcpOptionsSupported = 1;
1073 nttic->V4Receive.TcpChecksum = 1;
1074 nttic->V4Receive.UdpChecksum = 1;
1075 nttic->V4Receive.IpChecksum = 1;
1076 nttic->V6Transmit.IpOptionsSupported = 0;
1077 nttic->V6Transmit.TcpOptionsSupported = 0;
1078 nttic->V6Transmit.TcpChecksum = 0;
1079 nttic->V6Transmit.UdpChecksum = 0;
1080 nttic->V6Receive.IpOptionsSupported = 0;
1081 nttic->V6Receive.TcpOptionsSupported = 0;
1082 nttic->V6Receive.TcpChecksum = 0;
1083 nttic->V6Receive.UdpChecksum = 0;
1084 #ifdef LARGE_SEND
1085 nto->OffsetNextTask = sizeof(NDIS_TASK_OFFLOAD_HEADER)
1086 + FIELD_OFFSET(NDIS_TASK_OFFLOAD, TaskBuffer)
1087 + sizeof(NDIS_TASK_TCP_IP_CHECKSUM);
1089 /* fill in second nto */
1090 nto = (PNDIS_TASK_OFFLOAD)((PCHAR)(ntoh) + nto->OffsetNextTask);
1091 nto->Version = NDIS_TASK_OFFLOAD_VERSION;
1092 nto->Size = sizeof(NDIS_TASK_OFFLOAD);
1093 nto->Task = TcpLargeSendNdisTask;
1094 nto->TaskBufferLength = sizeof(NDIS_TASK_TCP_LARGE_SEND);
1096 /* fill in large send struct */
1097 nttls = (PNDIS_TASK_TCP_LARGE_SEND)nto->TaskBuffer;
1098 nttls->Version = 0;
1099 nttls->MaxOffLoadSize = 1024*64; /* made up, fixme */
1100 nttls->MinSegmentCount = 4; /* also made up */
1101 nttls->TcpOptions = FALSE;
1102 nttls->IpOptions = FALSE;
1103 #endif
1104 nto->OffsetNextTask = 0; /* last one */
1106 used_temp_buffer = FALSE;
1107 break;
1108 default:
1109 KdPrint(("Get Unknown OID 0x%x\n", Oid));
1110 status = NDIS_STATUS_NOT_SUPPORTED;
1113 if (!NT_SUCCESS(status))
1115 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (returned error)\n"));
1116 return status;
1119 if (len > InformationBufferLength)
1121 *BytesNeeded = len;
1122 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ " (BUFFER_TOO_SHORT)\n"));
1123 return NDIS_STATUS_BUFFER_TOO_SHORT;
1126 *BytesWritten = len;
1127 if (len && used_temp_buffer)
1129 NdisMoveMemory(((PUCHAR)InformationBuffer) + offset, data, len - offset);
1132 //KdPrint(("Got OID 0x%x\n", Oid));
1133 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1135 return status;
1138 NDIS_STATUS
1139 XenNet_SetInformation(
1140 IN NDIS_HANDLE MiniportAdapterContext,
1141 IN NDIS_OID Oid,
1142 IN PVOID InformationBuffer,
1143 IN ULONG InformationBufferLength,
1144 OUT PULONG BytesRead,
1145 OUT PULONG BytesNeeded
1148 NTSTATUS status;
1149 struct xennet_info *xi = MiniportAdapterContext;
1150 PULONG64 data = InformationBuffer;
1152 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1154 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1155 UNREFERENCED_PARAMETER(InformationBufferLength);
1156 UNREFERENCED_PARAMETER(BytesRead);
1157 UNREFERENCED_PARAMETER(BytesNeeded);
1159 switch(Oid)
1161 case OID_GEN_SUPPORTED_LIST:
1162 status = NDIS_STATUS_NOT_SUPPORTED;
1163 KdPrint(("Unsupported set OID_GEN_SUPPORTED_LIST\n"));
1164 break;
1165 case OID_GEN_HARDWARE_STATUS:
1166 status = NDIS_STATUS_NOT_SUPPORTED;
1167 KdPrint(("Unsupported set OID_GEN_HARDWARE_STATUS\n"));
1168 break;
1169 case OID_GEN_MEDIA_SUPPORTED:
1170 status = NDIS_STATUS_NOT_SUPPORTED;
1171 KdPrint(("Unsupported set OID_GEN_MEDIA_SUPPORTED\n"));
1172 break;
1173 case OID_GEN_MEDIA_IN_USE:
1174 status = NDIS_STATUS_NOT_SUPPORTED;
1175 KdPrint(("Unsupported set OID_GEN_MEDIA_IN_USE\n"));
1176 break;
1177 case OID_GEN_MAXIMUM_LOOKAHEAD:
1178 status = NDIS_STATUS_NOT_SUPPORTED;
1179 KdPrint(("Unsupported set OID_GEN_MAXIMUM_LOOKAHEAD\n"));
1180 break;
1181 case OID_GEN_MAXIMUM_FRAME_SIZE:
1182 status = NDIS_STATUS_NOT_SUPPORTED;
1183 KdPrint(("Unsupported set OID_GEN_MAXIMUM_FRAME_SIZE\n"));
1184 break;
1185 case OID_GEN_LINK_SPEED:
1186 status = NDIS_STATUS_NOT_SUPPORTED;
1187 KdPrint(("Unsupported set OID_GEN_LINK_SPEED\n"));
1188 break;
1189 case OID_GEN_TRANSMIT_BUFFER_SPACE:
1190 status = NDIS_STATUS_NOT_SUPPORTED;
1191 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BUFFER_SPACE\n"));
1192 break;
1193 case OID_GEN_RECEIVE_BUFFER_SPACE:
1194 status = NDIS_STATUS_NOT_SUPPORTED;
1195 KdPrint(("Unsupported set OID_GEN_RECEIVE_BUFFER_SPACE\n"));
1196 break;
1197 case OID_GEN_TRANSMIT_BLOCK_SIZE:
1198 status = NDIS_STATUS_NOT_SUPPORTED;
1199 KdPrint(("Unsupported set OID_GEN_TRANSMIT_BLOCK_SIZE\n"));
1200 break;
1201 case OID_GEN_RECEIVE_BLOCK_SIZE:
1202 status = NDIS_STATUS_NOT_SUPPORTED;
1203 KdPrint(("Unsupported set OID_GEN_RECEIVE_BLOCK_SIZE\n"));
1204 break;
1205 case OID_GEN_VENDOR_ID:
1206 status = NDIS_STATUS_NOT_SUPPORTED;
1207 KdPrint(("Unsupported set OID_GEN_VENDOR_ID\n"));
1208 break;
1209 case OID_GEN_VENDOR_DESCRIPTION:
1210 status = NDIS_STATUS_NOT_SUPPORTED;
1211 KdPrint(("Unsupported set OID_GEN_VENDOR_DESCRIPTION\n"));
1212 break;
1213 case OID_GEN_CURRENT_PACKET_FILTER:
1214 KdPrint(("Set OID_GEN_CURRENT_PACKET_FILTER\n"));
1215 xi->packet_filter = *(ULONG *)data;
1216 status = NDIS_STATUS_SUCCESS;
1217 break;
1218 case OID_GEN_CURRENT_LOOKAHEAD:
1219 KdPrint(("Set OID_GEN_CURRENT_LOOKAHEAD %d\n", *(int *)data));
1220 // TODO: We should do this...
1221 status = NDIS_STATUS_SUCCESS;
1222 break;
1223 case OID_GEN_DRIVER_VERSION:
1224 status = NDIS_STATUS_NOT_SUPPORTED;
1225 KdPrint(("Unsupported set OID_GEN_DRIVER_VERSION\n"));
1226 break;
1227 case OID_GEN_MAXIMUM_TOTAL_SIZE:
1228 status = NDIS_STATUS_NOT_SUPPORTED;
1229 KdPrint(("Unsupported set OID_GEN_MAXIMUM_TOTAL_SIZE\n"));
1230 break;
1231 case OID_GEN_PROTOCOL_OPTIONS:
1232 KdPrint(("Unsupported set OID_GEN_PROTOCOL_OPTIONS\n"));
1233 // TODO - actually do this...
1234 status = NDIS_STATUS_SUCCESS;
1235 break;
1236 case OID_GEN_MAC_OPTIONS:
1237 status = NDIS_STATUS_NOT_SUPPORTED;
1238 KdPrint(("Unsupported set OID_GEN_MAC_OPTIONS\n"));
1239 break;
1240 case OID_GEN_MEDIA_CONNECT_STATUS:
1241 status = NDIS_STATUS_NOT_SUPPORTED;
1242 KdPrint(("Unsupported set OID_GEN_MEDIA_CONNECT_STATUS\n"));
1243 break;
1244 case OID_GEN_MAXIMUM_SEND_PACKETS:
1245 status = NDIS_STATUS_NOT_SUPPORTED;
1246 KdPrint(("Unsupported set OID_GEN_MAXIMUM_SEND_PACKETS\n"));
1247 break;
1248 case OID_GEN_XMIT_OK:
1249 status = NDIS_STATUS_NOT_SUPPORTED;
1250 KdPrint(("Unsupported set OID_GEN_XMIT_OK\n"));
1251 break;
1252 case OID_GEN_RCV_OK:
1253 status = NDIS_STATUS_NOT_SUPPORTED;
1254 KdPrint(("Unsupported set OID_GEN_RCV_OK\n"));
1255 break;
1256 case OID_GEN_XMIT_ERROR:
1257 status = NDIS_STATUS_NOT_SUPPORTED;
1258 KdPrint(("Unsupported set OID_GEN_XMIT_ERROR\n"));
1259 break;
1260 case OID_GEN_RCV_ERROR:
1261 status = NDIS_STATUS_NOT_SUPPORTED;
1262 KdPrint(("Unsupported set OID_GEN_RCV_ERROR\n"));
1263 break;
1264 case OID_GEN_RCV_NO_BUFFER:
1265 status = NDIS_STATUS_NOT_SUPPORTED;
1266 KdPrint(("Unsupported set OID_GEN_RCV_NO_BUFFER\n"));
1267 break;
1268 case OID_802_3_PERMANENT_ADDRESS:
1269 status = NDIS_STATUS_NOT_SUPPORTED;
1270 KdPrint(("Unsupported set OID_802_3_PERMANENT_ADDRESS\n"));
1271 break;
1272 case OID_802_3_CURRENT_ADDRESS:
1273 status = NDIS_STATUS_NOT_SUPPORTED;
1274 KdPrint(("Unsupported set OID_802_3_CURRENT_ADDRESS\n"));
1275 break;
1276 case OID_802_3_MULTICAST_LIST:
1277 status = NDIS_STATUS_NOT_SUPPORTED;
1278 KdPrint(("Unsupported set OID_802_3_MULTICAST_LIST\n"));
1279 break;
1280 case OID_802_3_MAXIMUM_LIST_SIZE:
1281 status = NDIS_STATUS_NOT_SUPPORTED;
1282 KdPrint(("Unsupported set OID_802_3_MAXIMUM_LIST_SIZE\n"));
1283 break;
1284 case OID_TCP_TASK_OFFLOAD:
1285 // Just fake this for now... not sure if we will do anything different as a result...
1286 KdPrint(("Set OID_TCP_TASK_OFFLOAD\n"));
1287 status = NDIS_STATUS_SUCCESS;
1288 break;
1289 default:
1290 KdPrint(("Set Unknown OID 0x%x\n", Oid));
1291 status = NDIS_STATUS_NOT_SUPPORTED;
1292 break;
1294 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1295 return status;
1298 VOID
1299 XenNet_ReturnPacket(
1300 IN NDIS_HANDLE MiniportAdapterContext,
1301 IN PNDIS_PACKET Packet
1304 PNDIS_BUFFER buffer;
1305 PVOID buff_va;
1306 UINT buff_len;
1307 UINT tot_buff_len;
1309 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1311 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1313 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1314 &tot_buff_len, NormalPagePriority);
1315 ASSERT(buff_len == tot_buff_len);
1317 /* TODO: reuse returned packets */
1319 NdisFreeMemory(buff_va, 0, 0);
1320 NdisFreeBuffer(buffer);
1321 NdisFreePacket(Packet);
1323 //KdPrint((__FUNCTION__ " called\n"));
1324 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1327 PMDL
1328 XenNet_Linearize(PNDIS_PACKET Packet)
1330 NDIS_STATUS status;
1331 PMDL pmdl;
1332 char *start;
1333 PNDIS_BUFFER buffer;
1334 PVOID buff_va;
1335 UINT buff_len;
1336 UINT tot_buff_len;
1338 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1340 NdisGetFirstBufferFromPacketSafe(Packet, &buffer, &buff_va, &buff_len,
1341 &tot_buff_len, NormalPagePriority);
1342 ASSERT(tot_buff_len <= XN_MAX_PKT_SIZE);
1344 status = NdisAllocateMemoryWithTag(&start, tot_buff_len, XENNET_POOL_TAG);
1345 if (!NT_SUCCESS(status))
1347 KdPrint(("Could not allocate memory for linearization\n"));
1348 return NULL;
1350 pmdl = IoAllocateMdl(start, tot_buff_len, FALSE, FALSE, FALSE);
1351 if (!pmdl)
1353 KdPrint(("Could not allocate MDL for linearization\n"));
1354 NdisFreeMemory(start, 0, 0);
1355 return NULL;
1357 MmBuildMdlForNonPagedPool(pmdl);
1359 while (buffer)
1361 NdisQueryBufferSafe(buffer, &buff_va, &buff_len, NormalPagePriority);
1362 RtlCopyMemory(start, buff_va, buff_len);
1363 start += buff_len;
1364 NdisGetNextBuffer(buffer, &buffer);
1367 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1368 return pmdl;
1371 VOID
1372 XenNet_SendPackets(
1373 IN NDIS_HANDLE MiniportAdapterContext,
1374 IN PPNDIS_PACKET PacketArray,
1375 IN UINT NumberOfPackets
1378 struct xennet_info *xi = MiniportAdapterContext;
1379 PNDIS_PACKET curr_packet;
1380 UINT i;
1381 struct netif_tx_request *tx;
1382 unsigned short id;
1383 int notify;
1384 PMDL pmdl;
1385 UINT pkt_size;
1386 KIRQL OldIrql;
1388 // KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1390 KeAcquireSpinLock(&xi->TxLock, &OldIrql);
1392 for (i = 0; i < NumberOfPackets; i++)
1394 curr_packet = PacketArray[i];
1395 ASSERT(curr_packet);
1397 NdisQueryPacket(curr_packet, NULL, NULL, NULL, &pkt_size);
1399 //KdPrint(("sending pkt, len %d\n", pkt_size));
1401 /* TODO: check if freelist is full */
1403 pmdl = XenNet_Linearize(curr_packet);
1404 if (!pmdl)
1406 KdPrint((__DRIVER_NAME "Couldn't linearize packet!\n"));
1407 NdisMSendComplete(xi, curr_packet, NDIS_STATUS_FAILURE);
1408 break;
1410 *((PMDL *)curr_packet->MiniportReservedEx) = pmdl;
1412 id = get_id_from_freelist(xi->tx_pkts);
1413 xi->tx_pkts[id] = curr_packet;
1415 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
1416 tx->id = id;
1417 tx->gref = xi->XenInterface.GntTbl_GrantAccess(
1418 xi->XenInterface.InterfaceHeader.Context,
1419 0,
1420 *MmGetMdlPfnArray(pmdl),
1421 TRUE);
1422 xi->grant_tx_ref[id] = tx->gref;
1423 tx->offset = (uint16_t)MmGetMdlByteOffset(pmdl);
1424 tx->size = (UINT16)pkt_size;
1425 // NETTXF_csum_blank should only be used for tcp and udp packets...
1426 tx->flags = 0; //NETTXF_csum_blank;
1428 xi->tx.req_prod_pvt++;
1430 // NDIS_SET_PACKET_STATUS(curr_packet, NDIS_STATUS_SUCCESS);
1431 // NdisMSendComplete(xi, curr_packet, NDIS_STATUS_SUCCESS);
1434 RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&xi->tx, notify);
1435 if (notify)
1437 xi->XenInterface.EvtChn_Notify(xi->XenInterface.InterfaceHeader.Context,
1438 xi->event_channel);
1441 KeReleaseSpinLock(&xi->TxLock, OldIrql);
1443 // KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1446 VOID
1447 XenNet_PnPEventNotify(
1448 IN NDIS_HANDLE MiniportAdapterContext,
1449 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
1450 IN PVOID InformationBuffer,
1451 IN ULONG InformationBufferLength
1454 UNREFERENCED_PARAMETER(MiniportAdapterContext);
1455 UNREFERENCED_PARAMETER(PnPEvent);
1456 UNREFERENCED_PARAMETER(InformationBuffer);
1457 UNREFERENCED_PARAMETER(InformationBufferLength);
1459 KdPrint((__FUNCTION__ " called\n"));
1462 /* Called when machine is shutting down, so just quiesce the HW and be done fast. */
1463 VOID
1464 XenNet_Shutdown(
1465 IN NDIS_HANDLE MiniportAdapterContext
1468 struct xennet_info *xi = MiniportAdapterContext;
1470 /* turn off interrupt */
1471 xi->XenInterface.EvtChn_Unbind(xi->XenInterface.InterfaceHeader.Context,
1472 xi->event_channel);
1474 KdPrint((__FUNCTION__ " called\n"));
1477 /* Opposite of XenNet_Init */
1478 XenNet_Halt(
1479 IN NDIS_HANDLE MiniportAdapterContext
1482 struct xennet_info *xi = MiniportAdapterContext;
1483 CHAR TmpPath[128];
1485 KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
1486 KdPrint((__DRIVER_NAME " IRQL = %d\n", KeGetCurrentIrql()));
1488 XenNet_Shutdown(xi);
1490 // set frontend state to 'closing'
1491 xi->state = XenbusStateClosing;
1492 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
1493 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1494 XBT_NIL, TmpPath, "%d", xi->state);
1496 // wait for backend to set 'Closing' state
1498 while (xi->backend_state != XenbusStateClosing)
1499 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1501 // set frontend state to 'closed'
1502 xi->state = XenbusStateClosed;
1503 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->pdoData->Path);
1504 xi->XenInterface.XenBus_Printf(xi->XenInterface.InterfaceHeader.Context,
1505 XBT_NIL, TmpPath, "%d", xi->state);
1507 // wait for backend to set 'Closed' state
1508 while (xi->backend_state != XenbusStateClosed)
1509 KeWaitForSingleObject(&xi->backend_state_change_event, Executive, KernelMode, FALSE, NULL);
1511 xi->connected = FALSE;
1513 // TODO: remove event channel xenbus entry (how?)
1515 /* free TX resources */
1516 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1517 xi->tx_ring_ref);
1518 xi->tx_ring_ref = GRANT_INVALID_REF;
1519 FreePages(xi->tx_mdl);
1520 xi->tx_pgs = NULL;
1521 XenNet_TxBufferFree(xi);
1523 /* free RX resources */
1524 xi->XenInterface.GntTbl_EndAccess(xi->XenInterface.InterfaceHeader.Context,
1525 xi->rx_ring_ref);
1526 xi->rx_ring_ref = GRANT_INVALID_REF;
1527 FreePages(xi->rx_mdl);
1528 xi->rx_pgs = NULL;
1529 XenNet_RxBufferFree(MiniportAdapterContext);
1531 /* Remove watch on backend state */
1532 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
1533 xi->XenInterface.XenBus_RemWatch(xi->XenInterface.InterfaceHeader.Context,
1534 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
1536 xi->XenInterface.InterfaceHeader.InterfaceDereference(NULL);
1538 WdfDriverMiniportUnload(WdfGetDriver());
1540 NdisFreeBufferPool(xi->buffer_pool);
1541 NdisFreePacketPool(xi->packet_pool);
1542 NdisFreeMemory(xi, 0, 0); // <= DISPATCH_LEVEL
1544 KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
1547 NTSTATUS
1548 DriverEntry(
1549 PDRIVER_OBJECT DriverObject,
1550 PUNICODE_STRING RegistryPath
1553 NTSTATUS status;
1554 WDF_DRIVER_CONFIG config;
1555 NDIS_HANDLE ndis_wrapper_handle;
1556 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
1558 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
1560 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
1561 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
1563 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
1564 &config, WDF_NO_HANDLE);
1565 if (!NT_SUCCESS(status))
1567 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
1568 return status;
1571 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
1572 if (!ndis_wrapper_handle)
1574 KdPrint(("NdisMInitializeWrapper failed\n"));
1575 return NDIS_STATUS_FAILURE;
1578 /* NDIS 5.1 driver */
1579 mini_chars.MajorNdisVersion = NDIS_MAJOR_VER;
1580 mini_chars.MinorNdisVersion = NDIS_MINOR_VER;
1582 mini_chars.HaltHandler = XenNet_Halt;
1583 mini_chars.InitializeHandler = XenNet_Init;
1584 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
1585 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
1586 mini_chars.ResetHandler = NULL; //TODO: fill in
1587 mini_chars.SetInformationHandler = XenNet_SetInformation;
1588 /* added in v.4 -- use multiple pkts interface */
1589 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
1590 mini_chars.SendPacketsHandler = XenNet_SendPackets;
1591 /* added in v.5.1 */
1592 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
1593 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
1595 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
1597 /* set up upper-edge interface */
1598 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
1599 if (!NT_SUCCESS(status))
1601 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
1602 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
1603 return status;
1606 return status;