win-pvdrivers

view xennet/xennet.c @ 30:bc0ea67acebb

xennet: Start implementing SendPackets
author Andy Grover <andy.grover@oracle.com>
date Mon Dec 03 23:04:07 2007 -0800 (2007-12-03)
parents e4f0a0a21488
children d5df0038627d
line source
1 /*
2 PV Net Driver for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
4 Copyright (C) 2007 Andrew Grover
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 #if !defined (NDIS51_MINIPORT)
26 #error requires NDIS 5.1 compilation environment
27 #endif
29 #define GRANT_INVALID_REF 0
31 /* couldn't get regular xen ring macros to work...*/
32 #define __NET_RING_SIZE(type, _sz) \
33 (__RD32( \
34 (_sz - sizeof(struct type##_sring) + sizeof(union type##_sring_entry)) \
35 / sizeof(union type##_sring_entry)))
37 #define NET_TX_RING_SIZE __NET_RING_SIZE(netif_tx, PAGE_SIZE)
38 #define NET_RX_RING_SIZE __NET_RING_SIZE(netif_rx, PAGE_SIZE)
40 #pragma warning(disable: 4127)
42 struct xennet_info
43 {
44 PDEVICE_OBJECT pdo;
45 PDEVICE_OBJECT fdo;
46 PDEVICE_OBJECT lower_do;
47 WDFDEVICE wdf_device;
49 WCHAR name[NAME_SIZE];
50 NDIS_HANDLE adapter_handle;
51 ULONG packet_filter;
52 int connected;
53 UINT8 perm_mac_addr[ETH_ALEN];
54 UINT8 curr_mac_addr[ETH_ALEN];
56 char Path[128];
57 char BackendPath[128];
58 XEN_IFACE_EVTCHN EvtChnInterface;
59 XEN_IFACE_XENBUS XenBusInterface;
60 XEN_IFACE_XEN XenInterface;
61 XEN_IFACE_GNTTBL GntTblInterface;
63 /* ring control structures */
64 struct netif_tx_front_ring tx;
65 struct netif_rx_front_ring rx;
67 /* ptrs to the actual rings themselvves */
68 struct netif_tx_sring *tx_pgs;
69 struct netif_rx_sring *rx_pgs;
71 /* MDLs for the above */
72 PMDL tx_mdl;
73 PMDL rx_mdl;
75 /* Outstanding packets. The first entry in tx_pkts
76 * is an index into a chain of free entries. */
77 PNDIS_PACKET tx_pkts[NET_TX_RING_SIZE];
78 PNDIS_PACKET rx_pkts[NET_RX_RING_SIZE];
80 grant_ref_t gref_tx_head;
81 grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
82 grant_ref_t gref_rx_head;
83 grant_ref_t grant_rx_ref[NET_TX_RING_SIZE];
85 UINT irq;
86 evtchn_port_t event_channel;
88 grant_ref_t tx_ring_ref;
89 grant_ref_t rx_ring_ref;
90 };
92 /* need to do typedef so the DECLARE below works */
93 typedef struct _wdf_device_info
94 {
95 struct xennet_info *xennet_info;
96 } wdf_device_info;
98 WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(wdf_device_info, GetWdfDeviceInfo)
100 /* This function copied from linux's lib/vsprintf.c, see it for attribution */
101 static unsigned long
102 simple_strtoul(const char *cp,char **endp,unsigned int base)
103 {
104 unsigned long result = 0,value;
106 if (!base) {
107 base = 10;
108 if (*cp == '0') {
109 base = 8;
110 cp++;
111 if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
112 cp++;
113 base = 16;
114 }
115 }
116 } else if (base == 16) {
117 if (cp[0] == '0' && toupper(cp[1]) == 'X')
118 cp += 2;
119 }
120 while (isxdigit(*cp) &&
121 (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
122 result = result*base + value;
123 cp++;
124 }
125 if (endp)
126 *endp = (char *)cp;
127 return result;
128 }
130 static void
131 add_id_to_freelist(NDIS_PACKET **list, unsigned short id)
132 {
133 list[id] = list[0];
134 list[0] = (void *)(unsigned long)id;
135 }
137 static unsigned short
138 get_id_from_freelist(NDIS_PACKET **list)
139 {
140 unsigned short id = (unsigned short)(unsigned long)list[0];
141 list[0] = list[id];
142 return id;
143 }
145 static PMDL
146 AllocatePages(int Pages)
147 {
148 PHYSICAL_ADDRESS Min;
149 PHYSICAL_ADDRESS Max;
150 PHYSICAL_ADDRESS Align;
151 PMDL Mdl;
153 KdPrint((__DRIVER_NAME " --> Allocate Pages\n"));
155 Min.QuadPart = 0;
156 Max.QuadPart = 0xFFFFFFFF;
157 Align.QuadPart = PAGE_SIZE;
159 Mdl = MmAllocatePagesForMdl(Min, Max, Align, Pages * PAGE_SIZE);
161 KdPrint((__DRIVER_NAME " <-- Allocate Pages (mdl = %08x)\n", Mdl));
163 return Mdl;
164 }
166 static PMDL
167 AllocatePage()
168 {
169 return AllocatePages(1);
170 }
172 static NDIS_STATUS
173 XenNet_TxBufGC(struct xennet_info *xi)
174 {
175 RING_IDX cons, prod;
176 #if 0
177 unsigned short id;
178 struct sk_buff *skb;
180 BUG_ON(!netfront_carrier_ok(np));
182 do {
183 prod = np->tx.sring->rsp_prod;
184 rmb(); /* Ensure we see responses up to 'rp'. */
186 for (cons = np->tx.rsp_cons; cons != prod; cons++) {
187 struct netif_tx_response *txrsp;
189 txrsp = RING_GET_RESPONSE(&np->tx, cons);
190 if (txrsp->status == NETIF_RSP_NULL)
191 continue;
193 id = txrsp->id;
194 skb = np->tx_skbs[id];
195 if (unlikely(gnttab_query_foreign_access(
196 np->grant_tx_ref[id]) != 0)) {
197 printk(KERN_ALERT "network_tx_buf_gc: warning "
198 "-- grant still in use by backend "
199 "domain.\n");
200 BUG();
201 }
202 gnttab_end_foreign_access_ref(
203 np->grant_tx_ref[id], GNTMAP_readonly);
204 gnttab_release_grant_reference(
205 &np->gref_tx_head, np->grant_tx_ref[id]);
206 np->grant_tx_ref[id] = GRANT_INVALID_REF;
207 add_id_to_freelist(np->tx_skbs, id);
208 dev_kfree_skb_irq(skb);
209 }
211 np->tx.rsp_cons = prod;
213 /*
214 * Set a new event, then check for race with update of tx_cons.
215 * Note that it is essential to schedule a callback, no matter
216 * how few buffers are pending. Even if there is space in the
217 * transmit ring, higher layers may be blocked because too much
218 * data is outstanding: in such cases notification from Xen is
219 * likely to be the only kick that we'll get.
220 */
221 np->tx.sring->rsp_event =
222 prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
223 mb();
224 } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
226 network_maybe_wake_tx(dev);
230 #endif
233 return NDIS_STATUS_SUCCESS;
234 }
236 static BOOLEAN
237 XenNet_Interrupt(
238 PKINTERRUPT Interrupt,
239 PVOID ServiceContext
240 )
241 {
242 struct xennet_info *xi = ServiceContext;
243 // KIRQL KIrql;
245 UNREFERENCED_PARAMETER(Interrupt);
247 if (xi->connected)
248 {
249 XenNet_TxBufGC(xi);
250 }
251 // KeAcquireSpinLock(&ChildDeviceData->Lock, &KIrql);
252 // KdPrint((__DRIVER_NAME " --> Setting Dpc Event\n"));
253 // KeSetEvent(&ChildDeviceData->DpcThreadEvent, 1, FALSE);
254 // KeReleaseSpinLock(&ChildDeviceData->Lock, KIrql);
255 // KdPrint((__DRIVER_NAME " --> Dpc Event Set\n"));
257 /* do something */
259 return TRUE;
260 }
262 static VOID
263 XenNet_BackEndStateHandler(char *Path, PVOID Data)
264 {
265 struct xennet_info *xi = Data;
266 char *Value;
267 int be_state;
268 char TmpPath[128];
269 xenbus_transaction_t xbt = 0;
270 int retry = 0;
271 char *err;
273 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
274 XBT_NIL, Path, &Value);
275 be_state = atoi(Value);
276 ExFreePool(Value);
278 switch (be_state)
279 {
280 case XenbusStateUnknown:
281 KdPrint((__DRIVER_NAME " Backend State Changed to Unknown\n"));
282 break;
284 case XenbusStateInitialising:
285 KdPrint((__DRIVER_NAME " Backend State Changed to Initialising\n"));
286 break;
288 case XenbusStateInitWait:
289 KdPrint((__DRIVER_NAME " Backend State Changed to InitWait\n"));
291 xi->event_channel = xi->EvtChnInterface.AllocUnbound(
292 xi->EvtChnInterface.InterfaceHeader.Context, 0);
293 xi->EvtChnInterface.Bind(xi->EvtChnInterface.InterfaceHeader.Context,
294 xi->event_channel, XenNet_Interrupt, xi);
296 /* TODO: must free pages in MDL as well as MDL using MmFreePagesFromMdl and ExFreePool */
297 // or, allocate mem and then get mdl, then free mdl
298 xi->tx_mdl = AllocatePage();
299 xi->tx_pgs = MmMapLockedPagesSpecifyCache(xi->tx_mdl, KernelMode, MmNonCached,
300 NULL, FALSE, NormalPagePriority);
301 SHARED_RING_INIT(xi->tx_pgs);
302 FRONT_RING_INIT(&xi->tx, xi->tx_pgs, PAGE_SIZE);
303 xi->tx_ring_ref = xi->GntTblInterface.GrantAccess(
304 xi->GntTblInterface.InterfaceHeader.Context, 0,
305 *MmGetMdlPfnArray(xi->tx_mdl), FALSE);
307 xi->rx_mdl = AllocatePage();
308 xi->rx_pgs = MmMapLockedPagesSpecifyCache(xi->rx_mdl, KernelMode, MmNonCached,
309 NULL, FALSE, NormalPagePriority);
310 SHARED_RING_INIT(xi->rx_pgs);
311 FRONT_RING_INIT(&xi->rx, xi->rx_pgs, PAGE_SIZE);
312 xi->rx_ring_ref = xi->GntTblInterface.GrantAccess(
313 xi->GntTblInterface.InterfaceHeader.Context, 0,
314 *MmGetMdlPfnArray(xi->rx_mdl), FALSE);
316 xi->XenBusInterface.StartTransaction(xi->XenBusInterface.InterfaceHeader.Context,
317 &xbt);
319 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/tx-ring-ref", xi->Path);
320 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
321 XBT_NIL, TmpPath, "%d", xi->tx_ring_ref);
322 if (err)
323 goto trouble;
325 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/rx-ring-ref", xi->Path);
326 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
327 XBT_NIL, TmpPath, "%d", xi->rx_ring_ref);
328 if (err)
329 goto trouble;
331 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/event-channel", xi->Path);
332 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
333 XBT_NIL, TmpPath, "%d", xi->event_channel);
334 if (err)
335 goto trouble;
337 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/request-rx-copy", xi->Path);
338 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
339 XBT_NIL, TmpPath, "%d", 1);
340 if (err)
341 goto trouble;
343 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/feature-rx-notify",
344 xi->Path);
345 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
346 XBT_NIL, TmpPath, "%d", 1);
347 if (err)
348 goto trouble;
350 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
351 "%s/feature-no-csum-offload", xi->Path);
352 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
353 XBT_NIL, TmpPath, "%d", 1);
354 if (err)
355 goto trouble;
357 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
358 "%s/feature-sg", xi->Path);
359 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
360 XBT_NIL, TmpPath, "%d", 0);
361 if (err)
362 goto trouble;
364 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
365 "%s/feature-gso-tcpv4", xi->Path);
366 err = xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
367 XBT_NIL, TmpPath, "%d", 0);
368 if (err)
369 goto trouble;
371 /* commit transaction */
372 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
373 xbt, 0, &retry);
375 /* TODO: prepare tx and rx rings */
377 KdPrint((__DRIVER_NAME " Set Frontend state to Initialised\n"));
378 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->Path);
379 xi->XenBusInterface.Printf(xi->XenBusInterface.InterfaceHeader.Context,
380 XBT_NIL, TmpPath, "%d", XenbusStateInitialised);
382 /* send fake arp? */
384 xi->connected = TRUE;
386 break;
388 case XenbusStateInitialised:
389 KdPrint((__DRIVER_NAME " Backend State Changed to Initialised\n"));
390 // create the device
391 break;
393 case XenbusStateConnected:
394 KdPrint((__DRIVER_NAME " Backend State Changed to Connected\n"));
396 /* do more stuff here */
398 KdPrint((__DRIVER_NAME " Set Frontend state to Connected\n"));
399 break;
401 case XenbusStateClosing:
402 KdPrint((__DRIVER_NAME " Backend State Changed to Closing\n"));
403 break;
405 case XenbusStateClosed:
406 KdPrint((__DRIVER_NAME " Backend State Changed to Closed\n"));
407 break;
409 default:
410 KdPrint((__DRIVER_NAME " Backend State Changed to Undefined = %d\n", be_state));
411 break;
412 }
414 trouble:
415 KdPrint((__DRIVER_NAME __FUNCTION__ ": Should never happen!\n"));
416 xi->XenBusInterface.EndTransaction(xi->XenBusInterface.InterfaceHeader.Context,
417 xbt, 1, &retry);
419 }
422 VOID
423 XenNet_Halt(
424 IN NDIS_HANDLE MiniportAdapterContext
425 )
426 {
427 UNREFERENCED_PARAMETER(MiniportAdapterContext);
428 }
430 static NDIS_STATUS
431 XenNet_Init(
432 OUT PNDIS_STATUS OpenErrorStatus,
433 OUT PUINT SelectedMediumIndex,
434 IN PNDIS_MEDIUM MediumArray,
435 IN UINT MediumArraySize,
436 IN NDIS_HANDLE MiniportAdapterHandle,
437 IN NDIS_HANDLE WrapperConfigurationContext
438 )
439 {
440 NDIS_STATUS status;
441 UINT i;
442 BOOLEAN medium_found = FALSE;
443 struct xennet_info *xi = NULL;
444 ULONG length;
445 WDF_OBJECT_ATTRIBUTES wdf_attrs;
446 char *msg;
447 char *Value;
448 char **vif_devs;
449 char TmpPath[128];
451 UNREFERENCED_PARAMETER(OpenErrorStatus);
452 UNREFERENCED_PARAMETER(WrapperConfigurationContext);
454 /* deal with medium stuff */
455 for (i = 0; i < MediumArraySize; i++)
456 {
457 if (MediumArray[i] == NdisMedium802_3)
458 {
459 medium_found = TRUE;
460 break;
461 }
462 }
463 if (!medium_found)
464 {
465 KdPrint(("NIC_MEDIA_TYPE not in MediumArray\n"));
466 return NDIS_STATUS_UNSUPPORTED_MEDIA;
467 }
468 *SelectedMediumIndex = i;
470 /* Alloc memory for adapter private info */
471 status = NdisAllocateMemoryWithTag(&xi, sizeof(*xi), XENNET_POOL_TAG);
472 if (!NT_SUCCESS(status))
473 {
474 KdPrint(("NdisAllocateMemoryWithTag failed with 0x%x\n", status));
475 status = NDIS_STATUS_RESOURCES;
476 goto err;
477 }
478 RtlZeroMemory(xi, sizeof(*xi));
480 /* init xennet_info */
481 xi->adapter_handle = MiniportAdapterHandle;
482 NdisMGetDeviceProperty(MiniportAdapterHandle, &xi->pdo, &xi->fdo,
483 &xi->lower_do, NULL, NULL);
485 /* Initialise {tx,rx}_pkts as a free chain containing every entry. */
486 for (i = 0; i <= NET_TX_RING_SIZE; i++) {
487 xi->tx_pkts[i] = (void *)((unsigned long) i+1);
488 xi->grant_tx_ref[i] = GRANT_INVALID_REF;
489 }
491 for (i = 0; i < NET_RX_RING_SIZE; i++) {
492 xi->rx_pkts[i] = NULL;
493 xi->grant_rx_ref[i] = GRANT_INVALID_REF;
494 }
496 status = IoGetDeviceProperty(xi->pdo, DevicePropertyDeviceDescription,
497 NAME_SIZE, xi->name, &length);
498 if (!NT_SUCCESS(status))
499 {
500 KdPrint(("IoGetDeviceProperty failed with 0x%x\n", status));
501 status = NDIS_STATUS_FAILURE;
502 goto err;
503 }
505 NdisMSetAttributesEx(xi->adapter_handle, (NDIS_HANDLE) xi,
506 0, NDIS_ATTRIBUTE_DESERIALIZE, NdisInterfaceInternal);
508 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&wdf_attrs, wdf_device_info);
510 status = WdfDeviceMiniportCreate(WdfGetDriver(), &wdf_attrs, xi->fdo,
511 xi->lower_do, xi->pdo, &xi->wdf_device);
512 if (!NT_SUCCESS(status))
513 {
514 KdPrint(("WdfDeviceMiniportCreate failed with 0x%x\n", status));
515 status = NDIS_STATUS_FAILURE;
516 goto err;
517 }
519 /* TODO: NdisMInitializeScatterGatherDma? */
520 // NDIS_PER_PACKET_INFO_FROM_PACKET(ndis_packet, ScatterGatherListPacketInfo)
522 GetWdfDeviceInfo(xi->wdf_device)->xennet_info = xi;
524 /* get lower (Xen) interfaces */
526 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_EVTCHN,
527 (PINTERFACE) &xi->EvtChnInterface, sizeof(XEN_IFACE_EVTCHN), 1, NULL);
528 if(!NT_SUCCESS(status))
529 {
530 KdPrint(("WdfFdoQueryForInterface (EvtChn) failed with status 0x%08x\n", status));
531 status = NDIS_STATUS_FAILURE;
532 goto err;
533 }
535 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XENBUS,
536 (PINTERFACE) &xi->XenBusInterface, sizeof(XEN_IFACE_XENBUS), 1, NULL);
537 if(!NT_SUCCESS(status))
538 {
539 KdPrint(("WdfFdoQueryForInterface (XenBus) failed with status 0x%08x\n", status));
540 status = NDIS_STATUS_FAILURE;
541 goto err;
542 }
544 #if 0
545 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_XEN,
546 (PINTERFACE) &xi->XenInterface, sizeof(XEN_IFACE_XEN), 1, NULL);
547 if(!NT_SUCCESS(status))
548 {
549 KdPrint(("WdfFdoQueryForInterface (Xen) failed with status 0x%08x\n", status));
550 status = NDIS_STATUS_FAILURE;
551 goto err;
552 }
553 #endif
555 status = WdfFdoQueryForInterface(xi->wdf_device, &GUID_XEN_IFACE_GNTTBL,
556 (PINTERFACE) &xi->GntTblInterface, sizeof(XEN_IFACE_GNTTBL), 1, NULL);
557 if(!NT_SUCCESS(status))
558 {
559 KdPrint(("WdfFdoQueryForInterface (GntTbl) failed with status 0x%08x\n", status));
560 status = NDIS_STATUS_FAILURE;
561 goto err;
562 }
564 msg = xi->XenBusInterface.List(xi->EvtChnInterface.InterfaceHeader.Context,
565 XBT_NIL, "device/vif", &vif_devs);
566 if (msg)
567 {
568 KdPrint((__DRIVER_NAME ": " __FUNCTION__ ": List retval is nonzero!\n"));
569 status = NDIS_STATUS_FAILURE;
570 goto err;
571 }
573 for (i = 0; vif_devs[i]; i++)
574 {
575 if (i > 0)
576 {
577 KdPrint((__DRIVER_NAME "Can only handle 1 vif so far, ignoring vif %s\n", vif_devs[i]));
578 continue;
579 }
580 RtlStringCbPrintfA(xi->Path, ARRAY_SIZE(xi->Path), "device/vif/%s", vif_devs[i]);
582 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath),
583 "device/vif/%s/state", vif_devs[i]);
584 KdPrint(("%s\n", TmpPath));
586 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/backend", xi->Path);
587 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
588 XBT_NIL, TmpPath, &Value);
589 if (!Value)
590 {
591 KdPrint((__DRIVER_NAME " backend Read Failed\n"));
592 }
593 else
594 {
595 RtlStringCbCopyA(xi->BackendPath, ARRAY_SIZE(xi->BackendPath), Value);
596 KdPrint((__DRIVER_NAME "backend path = %s\n", xi->BackendPath));
597 }
598 ExFreePool(Value);
600 /* Add watch on backend state */
601 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/state", xi->BackendPath);
602 xi->XenBusInterface.AddWatch(xi->XenBusInterface.InterfaceHeader.Context,
603 XBT_NIL, TmpPath, XenNet_BackEndStateHandler, xi);
605 /* get mac address */
606 RtlStringCbPrintfA(TmpPath, ARRAY_SIZE(TmpPath), "%s/mac", xi->Path);
607 xi->XenBusInterface.Read(xi->XenBusInterface.InterfaceHeader.Context,
608 XBT_NIL, TmpPath, &Value);
609 if (!Value)
610 {
611 KdPrint((__DRIVER_NAME " mac Read Failed\n"));
612 }
613 else
614 {
615 char *s, *e;
616 int i;
618 s = Value;
620 for (i = 0; i < ETH_ALEN; i++) {
621 xi->perm_mac_addr[i] = (UINT8)simple_strtoul(s, &e, 16);
622 if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
623 KdPrint((__DRIVER_NAME "Error parsing MAC address\n"));
624 ExFreePool(Value);
625 ExFreePool(vif_devs);
626 status = NDIS_STATUS_FAILURE;
627 goto err;
628 }
629 s = e + 1;
630 }
631 memcpy(xi->curr_mac_addr, xi->perm_mac_addr, ETH_ALEN);
632 }
633 ExFreePool(Value);
635 //XenVbd_HotPlugHandler(buffer, NULL);
636 //ExFreePoolWithTag(bdDevices[i], XENPCI_POOL_TAG);
637 }
638 ExFreePool(vif_devs);
640 return NDIS_STATUS_SUCCESS;
642 err:
643 NdisFreeMemory(xi, 0, 0);
644 return status;
645 }
647 NDIS_OID supported_oids[] =
648 {
649 OID_GEN_SUPPORTED_LIST,
650 OID_GEN_HARDWARE_STATUS,
651 OID_GEN_MEDIA_SUPPORTED,
652 OID_GEN_MEDIA_IN_USE,
653 OID_GEN_MAXIMUM_LOOKAHEAD,
654 OID_GEN_MAXIMUM_FRAME_SIZE,
655 OID_GEN_LINK_SPEED,
656 OID_GEN_TRANSMIT_BUFFER_SPACE,
657 OID_GEN_RECEIVE_BUFFER_SPACE,
658 OID_GEN_TRANSMIT_BLOCK_SIZE,
659 OID_GEN_RECEIVE_BLOCK_SIZE,
660 OID_GEN_VENDOR_ID,
661 OID_GEN_VENDOR_DESCRIPTION,
662 OID_GEN_CURRENT_PACKET_FILTER,
663 OID_GEN_CURRENT_LOOKAHEAD,
664 OID_GEN_DRIVER_VERSION,
665 OID_GEN_MAXIMUM_TOTAL_SIZE,
666 OID_GEN_MAC_OPTIONS,
667 OID_GEN_MEDIA_CONNECT_STATUS,
668 OID_GEN_MAXIMUM_SEND_PACKETS,
669 OID_802_3_PERMANENT_ADDRESS,
670 OID_802_3_CURRENT_ADDRESS,
671 OID_802_3_MULTICAST_LIST,
672 OID_802_3_MAXIMUM_LIST_SIZE,
673 };
675 NDIS_STATUS
676 XenNet_QueryInformation(
677 IN NDIS_HANDLE MiniportAdapterContext,
678 IN NDIS_OID Oid,
679 IN PVOID InformationBuffer,
680 IN ULONG InformationBufferLength,
681 OUT PULONG BytesWritten,
682 OUT PULONG BytesNeeded)
683 {
684 struct xennet_info *xi = MiniportAdapterContext;
685 UCHAR vendor_desc[] = XN_VENDOR_DESC;
686 ULONG temp_data;
687 PVOID data = &temp_data;
688 UINT len = sizeof(temp_data);
689 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
691 switch(Oid)
692 {
693 case OID_GEN_SUPPORTED_LIST:
694 data = supported_oids;
695 len = sizeof(supported_oids);
696 break;
697 case OID_GEN_HARDWARE_STATUS:
698 temp_data = NdisHardwareStatusReady;
699 break;
700 case OID_GEN_MEDIA_SUPPORTED:
701 temp_data = NdisMedium802_3;
702 break;
703 case OID_GEN_MEDIA_IN_USE:
704 temp_data = NdisMedium802_3;
705 break;
706 case OID_GEN_MAXIMUM_LOOKAHEAD:
707 temp_data = XN_DATA_SIZE;
708 break;
709 case OID_GEN_MAXIMUM_FRAME_SIZE:
710 temp_data = XN_MAX_PKT_SIZE;
711 break;
712 case OID_GEN_LINK_SPEED:
713 temp_data = 10000000; /* 1Gb */
714 break;
715 case OID_GEN_TRANSMIT_BUFFER_SPACE:
716 /* pkts times sizeof ring, maybe? */
717 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
718 break;
719 case OID_GEN_RECEIVE_BUFFER_SPACE:
720 /* pkts times sizeof ring, maybe? */
721 temp_data = XN_MAX_PKT_SIZE * NET_TX_RING_SIZE;
722 break;
723 case OID_GEN_TRANSMIT_BLOCK_SIZE:
724 temp_data = XN_MAX_PKT_SIZE;
725 break;
726 case OID_GEN_RECEIVE_BLOCK_SIZE:
727 temp_data = XN_MAX_PKT_SIZE;
728 break;
729 case OID_GEN_VENDOR_ID:
730 temp_data = XENSOURCE_MAC_HDR;
731 break;
732 case OID_GEN_VENDOR_DESCRIPTION:
733 data = vendor_desc;
734 len = sizeof(vendor_desc);
735 break;
736 case OID_GEN_CURRENT_PACKET_FILTER:
737 temp_data = xi->packet_filter;
738 break;
739 case OID_GEN_CURRENT_LOOKAHEAD:
740 temp_data = XN_MAX_PKT_SIZE;
741 break;
742 case OID_GEN_DRIVER_VERSION:
743 temp_data = (NDIS_MAJOR_VER << 8) | NDIS_MINOR_VER;
744 len = 2;
745 break;
746 case OID_GEN_MAXIMUM_TOTAL_SIZE:
747 temp_data = XN_MAX_PKT_SIZE;
748 break;
749 case OID_GEN_MAC_OPTIONS:
750 temp_data = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
751 NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
752 NDIS_MAC_OPTION_NO_LOOPBACK;
753 break;
754 case OID_GEN_MEDIA_CONNECT_STATUS:
755 if (xi->connected)
756 temp_data = NdisMediaStateConnected;
757 else
758 temp_data = NdisMediaStateDisconnected;
759 break;
760 case OID_GEN_MAXIMUM_SEND_PACKETS:
761 temp_data = XN_MAX_SEND_PKTS;
762 break;
763 case OID_802_3_PERMANENT_ADDRESS:
764 data = xi->perm_mac_addr;
765 len = ETH_ALEN;
766 break;
767 case OID_802_3_CURRENT_ADDRESS:
768 data = xi->curr_mac_addr;
769 len = ETH_ALEN;
770 break;
771 case OID_802_3_MULTICAST_LIST:
772 data = NULL;
773 len = 0;
774 case OID_802_3_MAXIMUM_LIST_SIZE:
775 temp_data = 0; /* no mcast support */
776 break;
777 default:
778 KdPrint(("Unknown OID 0x%x\n", Oid));
779 status = NDIS_STATUS_NOT_SUPPORTED;
780 }
782 if (!NT_SUCCESS(status))
783 {
784 return status;
785 }
787 if (len > InformationBufferLength)
788 {
789 *BytesNeeded = len;
790 return NDIS_STATUS_BUFFER_TOO_SHORT;
791 }
793 *BytesWritten = len;
794 if (len)
795 {
796 NdisMoveMemory(InformationBuffer, data, len);
797 }
799 KdPrint(("Got OID 0x%x\n", Oid));
801 return status;
802 }
804 NDIS_STATUS
805 XenNet_SetInformation(
806 IN NDIS_HANDLE MiniportAdapterContext,
807 IN NDIS_OID Oid,
808 IN PVOID InformationBuffer,
809 IN ULONG InformationBufferLength,
810 OUT PULONG BytesRead,
811 OUT PULONG BytesNeeded
812 )
813 {
814 UNREFERENCED_PARAMETER(MiniportAdapterContext);
815 UNREFERENCED_PARAMETER(Oid);
816 UNREFERENCED_PARAMETER(InformationBuffer);
817 UNREFERENCED_PARAMETER(InformationBufferLength);
818 UNREFERENCED_PARAMETER(BytesRead);
819 UNREFERENCED_PARAMETER(BytesNeeded);
821 KdPrint((__FUNCTION__ " called with OID=0x%x\n", Oid));
822 return NDIS_STATUS_SUCCESS;
823 }
825 VOID
826 XenNet_ReturnPacket(
827 IN NDIS_HANDLE MiniportAdapterContext,
828 IN PNDIS_PACKET Packet
829 )
830 {
831 UNREFERENCED_PARAMETER(MiniportAdapterContext);
832 UNREFERENCED_PARAMETER(Packet);
834 KdPrint((__FUNCTION__ " called\n"));
835 }
837 VOID
838 XenNet_SendPackets(
839 IN NDIS_HANDLE MiniportAdapterContext,
840 IN PPNDIS_PACKET PacketArray,
841 IN UINT NumberOfPackets
842 )
843 {
844 /* for each packet:
845 req_prod_pvt is the next entry in the cmd ring to use
846 add pkt to array of saved packets
847 fill out tx request for the first part of skb
848 add to grant table
849 do flags for csum etc
850 gso (later)
851 inc req_prod_pvt
852 frags
853 possibly notify
854 network_tx)buf_gc
855 stop netif if no more room
856 */
857 struct xennet_info *xi = MiniportAdapterContext;
858 PNDIS_PACKET curr_packet;
859 PNDIS_BUFFER curr_buff;
860 PVOID curr_buff_vaddr;
861 UINT curr_buff_len;
862 UINT tot_buff_len;
863 UINT i;
864 struct netif_tx_request *tx;
865 unsigned short id;
866 grant_ref_t ref;
868 KdPrint((__FUNCTION__ " called, sending %d pkts\n", NumberOfPackets));
870 for (i = 0; i < NumberOfPackets; i++)
871 {
872 curr_packet = PacketArray[i];
873 ASSERT(curr_packet);
875 NdisGetFirstBufferFromPacketSafe(curr_packet, &curr_buff, &curr_buff_vaddr,
876 &curr_buff_len, &tot_buff_len, NormalPagePriority);
878 while (curr_buff)
879 {
880 NdisQueryBufferSafe(curr_buff, &curr_buff_vaddr, &curr_buff_len,
881 NormalPagePriority);
883 id = get_id_from_freelist(xi->tx_pkts);
884 xi->tx_pkts[id] = curr_packet;
886 // TODO: get pfn/offset for buffer
887 // buffers attached to packets with NdisChainBufferAtBack
889 tx = RING_GET_REQUEST(&xi->tx, xi->tx.req_prod_pvt);
890 tx->id = id;
891 tx->gref = xi->GntTblInterface.GrantAccess(
892 xi->GntTblInterface.InterfaceHeader.Context,
893 0,
894 0, //FIXME
895 FALSE);
898 NdisGetNextBuffer(curr_buff, &curr_buff);
899 }
900 }
902 }
904 VOID
905 XenNet_PnPEventNotify(
906 IN NDIS_HANDLE MiniportAdapterContext,
907 IN NDIS_DEVICE_PNP_EVENT PnPEvent,
908 IN PVOID InformationBuffer,
909 IN ULONG InformationBufferLength
910 )
911 {
912 UNREFERENCED_PARAMETER(MiniportAdapterContext);
913 UNREFERENCED_PARAMETER(PnPEvent);
914 UNREFERENCED_PARAMETER(InformationBuffer);
915 UNREFERENCED_PARAMETER(InformationBufferLength);
917 KdPrint((__FUNCTION__ " called\n"));
918 }
920 VOID
921 XenNet_Shutdown(
922 IN NDIS_HANDLE MiniportAdapterContext
923 )
924 {
925 UNREFERENCED_PARAMETER(MiniportAdapterContext);
927 KdPrint((__FUNCTION__ " called\n"));
928 }
930 NTSTATUS
931 DriverEntry(
932 PDRIVER_OBJECT DriverObject,
933 PUNICODE_STRING RegistryPath
934 )
935 {
936 NTSTATUS status;
937 WDF_DRIVER_CONFIG config;
938 NDIS_HANDLE ndis_wrapper_handle;
939 NDIS_MINIPORT_CHARACTERISTICS mini_chars;
941 RtlZeroMemory(&mini_chars, sizeof(mini_chars));
943 WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK);
944 config.DriverInitFlags |= WdfDriverInitNoDispatchOverride;
946 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES,
947 &config, WDF_NO_HANDLE);
948 if (!NT_SUCCESS(status))
949 {
950 KdPrint(("WdfDriverCreate failed err = 0x%x\n", status));
951 return status;
952 }
954 NdisMInitializeWrapper(&ndis_wrapper_handle, DriverObject, RegistryPath, NULL);
955 if (!ndis_wrapper_handle)
956 {
957 KdPrint(("NdisMInitializeWrapper failed\n"));
958 return NDIS_STATUS_FAILURE;
959 }
961 /* NDIS 5.1 driver */
962 mini_chars.MajorNdisVersion = 5;
963 mini_chars.MinorNdisVersion = 1;
965 mini_chars.HaltHandler = XenNet_Halt;
966 mini_chars.InitializeHandler = XenNet_Init;
967 mini_chars.ISRHandler = NULL; // needed if we register interrupt?
968 mini_chars.QueryInformationHandler = XenNet_QueryInformation;
969 mini_chars.ResetHandler = NULL; //TODO: fill in
970 mini_chars.SetInformationHandler = XenNet_SetInformation;
971 /* added in v.4 -- use multiple pkts interface */
972 mini_chars.ReturnPacketHandler = XenNet_ReturnPacket;
973 mini_chars.SendPacketsHandler = XenNet_SendPackets;
974 /* added in v.5.1 */
975 mini_chars.PnPEventNotifyHandler = XenNet_PnPEventNotify;
976 mini_chars.AdapterShutdownHandler = XenNet_Shutdown;
978 /* TODO: we don't have hardware, but we have "resources", so do we need to implement fns to handle this? */
980 /* set up upper-edge interface */
981 status = NdisMRegisterMiniport(ndis_wrapper_handle, &mini_chars, sizeof(mini_chars));
982 if (!NT_SUCCESS(status))
983 {
984 KdPrint(("NdisMRegisterMiniport failed, status = 0x%x\n", status));
985 NdisTerminateWrapper(ndis_wrapper_handle, NULL);
986 return status;
987 }
989 return status;
990 }