VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DevVirtioNet.cpp@ 28258

Last change on this file since 28258 was 28213, checked in by vboxsync, 15 years ago

PDMINETWORKUP,Drv*,Dev*: Eliminated pfnSendDeprecated.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 63.3 KB
Line 
1/* $Id: DevVirtioNet.cpp 28213 2010-04-12 15:15:51Z vboxsync $ */
2/** @file
3 * DevVirtioNet - Virtio Network Device
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
24#define VNET_GC_SUPPORT
25
26#include <VBox/pdmdev.h>
27#include <VBox/pdmnetifs.h>
28#include <iprt/semaphore.h>
29#ifdef IN_RING3
30# include <iprt/mem.h>
31# include <iprt/uuid.h>
32#endif /* IN_RING3 */
33#include "../Builtins.h"
34#include "../VirtIO/Virtio.h"
35
36
37#ifndef VBOX_DEVICE_STRUCT_TESTCASE
38
39#define INSTANCE(pState) pState->VPCI.szInstance
40#define IFACE_TO_STATE(pIface, ifaceName) \
41 ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))
42#define STATUS pState->config.uStatus
43
44#ifdef IN_RING3
45
46#define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_NET_ID
47#define VNET_PCI_CLASS 0x0200
48#define VNET_N_QUEUES 3
49#define VNET_NAME_FMT "VNet%d"
50
51#if 0
52/* Virtio Block Device */
53#define VNET_PCI_SUBSYSTEM_ID 1 + VIRTIO_BLK_ID
54#define VNET_PCI_CLASS 0x0180
55#define VNET_N_QUEUES 2
56#define VNET_NAME_FMT "VBlk%d"
57#endif
58
59#endif /* IN_RING3 */
60
61/* Forward declarations ******************************************************/
62RT_C_DECLS_BEGIN
63PDMBOTHCBDECL(int) vnetIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
64PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
65RT_C_DECLS_END
66
67#endif /* VBOX_DEVICE_STRUCT_TESTCASE */
68
69
70#define VNET_TX_DELAY 150 /* 150 microseconds */
71#define VNET_MAX_FRAME_SIZE 65536 // TODO: Is it the right limit?
72#define VNET_MAC_FILTER_LEN 32
73#define VNET_MAX_VID (1 << 12)
74
75/* Virtio net features */
76#define VNET_F_CSUM 0x00000001 /* Host handles pkts w/ partial csum */
77#define VNET_F_GUEST_CSUM 0x00000002 /* Guest handles pkts w/ partial csum */
78#define VNET_F_MAC 0x00000020 /* Host has given MAC address. */
79#define VNET_F_GSO 0x00000040 /* Host handles pkts w/ any GSO type */
80#define VNET_F_GUEST_TSO4 0x00000080 /* Guest can handle TSOv4 in. */
81#define VNET_F_GUEST_TSO6 0x00000100 /* Guest can handle TSOv6 in. */
82#define VNET_F_GUEST_ECN 0x00000200 /* Guest can handle TSO[6] w/ ECN in. */
83#define VNET_F_GUEST_UFO 0x00000400 /* Guest can handle UFO in. */
84#define VNET_F_HOST_TSO4 0x00000800 /* Host can handle TSOv4 in. */
85#define VNET_F_HOST_TSO6 0x00001000 /* Host can handle TSOv6 in. */
86#define VNET_F_HOST_ECN 0x00002000 /* Host can handle TSO[6] w/ ECN in. */
87#define VNET_F_HOST_UFO 0x00004000 /* Host can handle UFO in. */
88#define VNET_F_MRG_RXBUF 0x00008000 /* Host can merge receive buffers. */
89#define VNET_F_STATUS 0x00010000 /* virtio_net_config.status available */
90#define VNET_F_CTRL_VQ 0x00020000 /* Control channel available */
91#define VNET_F_CTRL_RX 0x00040000 /* Control channel RX mode support */
92#define VNET_F_CTRL_VLAN 0x00080000 /* Control channel VLAN filtering */
93
94#define VNET_S_LINK_UP 1
95
96
97#ifdef _MSC_VER
98struct VNetPCIConfig
99#else /* !_MSC_VER */
100struct __attribute__ ((__packed__)) VNetPCIConfig
101#endif /* !_MSC_VER */
102{
103 RTMAC mac;
104 uint16_t uStatus;
105};
106AssertCompileMemberOffset(struct VNetPCIConfig, uStatus, 6);
107
108/**
109 * Device state structure. Holds the current state of device.
110 *
111 * @extends VPCISTATE
112 * @implements PDMINETWORKDOWN
113 * @implements PDMINETWORKCONFIG
114 */
115struct VNetState_st
116{
117 /* VPCISTATE must be the first member! */
118 VPCISTATE VPCI;
119
120// PDMCRITSECT csRx; /**< Protects RX queue. */
121
122 PDMINETWORKDOWN INetworkDown;
123 PDMINETWORKCONFIG INetworkConfig;
124 R3PTRTYPE(PPDMIBASE) pDrvBase; /**< Attached network driver. */
125 R3PTRTYPE(PPDMINETWORKUP) pDrv; /**< Connector of attached network driver. */
126
127 R3PTRTYPE(PPDMQUEUE) pCanRxQueueR3; /**< Rx wakeup signaller - R3. */
128 R0PTRTYPE(PPDMQUEUE) pCanRxQueueR0; /**< Rx wakeup signaller - R0. */
129 RCPTRTYPE(PPDMQUEUE) pCanRxQueueRC; /**< Rx wakeup signaller - RC. */
130
131#if HC_ARCH_BITS == 64
132 uint32_t padding;
133#endif
134
135 /** transmit buffer */
136 R3PTRTYPE(uint8_t*) pTxBuf;
137 /**< Link Up(/Restore) Timer. */
138 PTMTIMERR3 pLinkUpTimer;
139#ifdef VNET_TX_DELAY
140 /**< Transmit Delay Timer - R3. */
141 PTMTIMERR3 pTxTimerR3;
142 /**< Transmit Delay Timer - R0. */
143 PTMTIMERR0 pTxTimerR0;
144 /**< Transmit Delay Timer - GC. */
145 PTMTIMERRC pTxTimerRC;
146
147#if HC_ARCH_BITS == 64
148 uint32_t padding2;
149#endif
150
151 uint32_t u32i;
152 uint32_t u32AvgDiff;
153 uint32_t u32MinDiff;
154 uint32_t u32MaxDiff;
155 uint64_t u64NanoTS;
156
157#endif /* VNET_TX_DELAY */
158 /** Indicates transmission in progress -- only one thread is allowed. */
159 uint32_t uIsTransmitting;
160
161 /** PCI config area holding MAC address as well as TBD. */
162 struct VNetPCIConfig config;
163 /** MAC address obtained from the configuration. */
164 RTMAC macConfigured;
165 /** True if physical cable is attached in configuration. */
166 bool fCableConnected;
167
168 /** Number of packet being sent/received to show in debug log. */
169 uint32_t u32PktNo;
170
171 /** N/A: */
172 bool volatile fMaybeOutOfSpace;
173
174 /** Promiscuous mode -- RX filter accepts all packets. */
175 bool fPromiscuous;
176 /** AllMulti mode -- RX filter accepts all multicast packets. */
177 bool fAllMulti;
178 /** The number of actually used slots in aMacTable. */
179 uint32_t nMacFilterEntries;
180 /** Array of MAC addresses accepted by RX filter. */
181 RTMAC aMacFilter[VNET_MAC_FILTER_LEN];
182 /** Bit array of VLAN filter, one bit per VLAN ID. */
183 uint8_t aVlanFilter[VNET_MAX_VID / sizeof(uint8_t)];
184
185 R3PTRTYPE(PVQUEUE) pRxQueue;
186 R3PTRTYPE(PVQUEUE) pTxQueue;
187 R3PTRTYPE(PVQUEUE) pCtlQueue;
188 /* Receive-blocking-related fields ***************************************/
189
190 /** EMT: Gets signalled when more RX descriptors become available. */
191 RTSEMEVENT hEventMoreRxDescAvail;
192
193 /* Statistic fields ******************************************************/
194
195 STAMCOUNTER StatReceiveBytes;
196 STAMCOUNTER StatTransmitBytes;
197#if defined(VBOX_WITH_STATISTICS)
198 STAMPROFILE StatReceive;
199 STAMPROFILE StatReceiveStore;
200 STAMPROFILEADV StatTransmit;
201 STAMPROFILE StatTransmitSend;
202 STAMPROFILE StatRxOverflow;
203 STAMCOUNTER StatRxOverflowWakeup;
204#endif /* VBOX_WITH_STATISTICS */
205
206};
207typedef struct VNetState_st VNETSTATE;
208typedef VNETSTATE *PVNETSTATE;
209
210#ifndef VBOX_DEVICE_STRUCT_TESTCASE
211
212#define VNETHDR_GSO_NONE 0
213
214struct VNetHdr
215{
216 uint8_t u8Flags;
217 uint8_t u8GSOType;
218 uint16_t u16HdrLen;
219 uint16_t u16GSOSize;
220 uint16_t u16CSumStart;
221 uint16_t u16CSumOffset;
222};
223typedef struct VNetHdr VNETHDR;
224typedef VNETHDR *PVNETHDR;
225AssertCompileSize(VNETHDR, 10);
226
227AssertCompileMemberOffset(VNETSTATE, VPCI, 0);
228
229#define VNET_OK 0
230#define VNET_ERROR 1
231typedef uint8_t VNETCTLACK;
232
233#define VNET_CTRL_CLS_RX_MODE 0
234#define VNET_CTRL_CMD_RX_MODE_PROMISC 0
235#define VNET_CTRL_CMD_RX_MODE_ALLMULTI 1
236
237#define VNET_CTRL_CLS_MAC 1
238#define VNET_CTRL_CMD_MAC_TABLE_SET 0
239
240#define VNET_CTRL_CLS_VLAN 2
241#define VNET_CTRL_CMD_VLAN_ADD 0
242#define VNET_CTRL_CMD_VLAN_DEL 1
243
244
245struct VNetCtlHdr
246{
247 uint8_t u8Class;
248 uint8_t u8Command;
249};
250typedef struct VNetCtlHdr VNETCTLHDR;
251typedef VNETCTLHDR *PVNETCTLHDR;
252AssertCompileSize(VNETCTLHDR, 2);
253
254DECLINLINE(int) vnetCsEnter(PVNETSTATE pState, int rcBusy)
255{
256 return vpciCsEnter(&pState->VPCI, rcBusy);
257}
258
259DECLINLINE(void) vnetCsLeave(PVNETSTATE pState)
260{
261 vpciCsLeave(&pState->VPCI);
262}
263
264DECLINLINE(int) vnetCsRxEnter(PVNETSTATE pState, int rcBusy)
265{
266 // STAM_PROFILE_START(&pState->CTXSUFF(StatCsRx), a);
267 // int rc = PDMCritSectEnter(&pState->csRx, rcBusy);
268 // STAM_PROFILE_STOP(&pState->CTXSUFF(StatCsRx), a);
269 // return rc;
270 return VINF_SUCCESS;
271}
272
273DECLINLINE(void) vnetCsRxLeave(PVNETSTATE pState)
274{
275 // PDMCritSectLeave(&pState->csRx);
276}
277
278/**
279 * Dump a packet to debug log.
280 *
281 * @param pState The device state structure.
282 * @param cpPacket The packet.
283 * @param cb The size of the packet.
284 * @param cszText A string denoting direction of packet transfer.
285 */
286DECLINLINE(void) vnetPacketDump(PVNETSTATE pState, const uint8_t *cpPacket, size_t cb, const char *cszText)
287{
288#ifdef DEBUG
289 Log(("%s %s packet #%d (%d bytes):\n",
290 INSTANCE(pState), cszText, ++pState->u32PktNo, cb));
291 //Log3(("%.*Rhxd\n", cb, cpPacket));
292#endif
293}
294
295
296
297PDMBOTHCBDECL(uint32_t) vnetGetHostFeatures(void *pvState)
298{
299 /* We support:
300 * - Host-provided MAC address
301 * - Link status reporting in config space
302 * - Control queue
303 * - RX mode setting
304 * - MAC filter table
305 * - VLAN filter
306 */
307 return VNET_F_MAC
308 | VNET_F_STATUS
309 | VNET_F_CTRL_VQ
310 | VNET_F_CTRL_RX
311 | VNET_F_CTRL_VLAN;
312}
313
314PDMBOTHCBDECL(uint32_t) vnetGetHostMinimalFeatures(void *pvState)
315{
316 return VNET_F_MAC;
317}
318
319PDMBOTHCBDECL(void) vnetSetHostFeatures(void *pvState, uint32_t uFeatures)
320{
321 // TODO: Nothing to do here yet
322 VNETSTATE *pState = (VNETSTATE *)pvState;
323 LogFlow(("%s vnetSetHostFeatures: uFeatures=%x\n", INSTANCE(pState), uFeatures));
324}
325
326PDMBOTHCBDECL(int) vnetGetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
327{
328 VNETSTATE *pState = (VNETSTATE *)pvState;
329 if (port + cb > sizeof(struct VNetPCIConfig))
330 {
331 Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
332 return VERR_IOM_IOPORT_UNUSED;
333 }
334 memcpy(data, ((uint8_t*)&pState->config) + port, cb);
335 return VINF_SUCCESS;
336}
337
338PDMBOTHCBDECL(int) vnetSetConfig(void *pvState, uint32_t port, uint32_t cb, void *data)
339{
340 VNETSTATE *pState = (VNETSTATE *)pvState;
341 if (port + cb > sizeof(struct VNetPCIConfig))
342 {
343 Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
344 if (port < sizeof(struct VNetPCIConfig))
345 memcpy(((uint8_t*)&pState->config) + port, data,
346 sizeof(struct VNetPCIConfig) - port);
347 return VINF_SUCCESS;
348 }
349 memcpy(((uint8_t*)&pState->config) + port, data, cb);
350 return VINF_SUCCESS;
351}
352
353/**
354 * Hardware reset. Revert all registers to initial values.
355 *
356 * @param pState The device state structure.
357 */
358PDMBOTHCBDECL(void) vnetReset(void *pvState)
359{
360 VNETSTATE *pState = (VNETSTATE*)pvState;
361 Log(("%s Reset triggered\n", INSTANCE(pState)));
362
363 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
364 if (RT_UNLIKELY(rc != VINF_SUCCESS))
365 {
366 LogRel(("vnetReset failed to enter RX critical section!\n"));
367 return;
368 }
369 vpciReset(&pState->VPCI);
370 vnetCsRxLeave(pState);
371
372 // TODO: Implement reset
373 if (pState->fCableConnected)
374 STATUS = VNET_S_LINK_UP;
375 else
376 STATUS = 0;
377 /*
378 * By default we pass all packets up since the older guests cannot control
379 * virtio mode.
380 */
381 pState->fPromiscuous = true;
382 pState->fAllMulti = false;
383 pState->nMacFilterEntries = 0;
384 memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
385 memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
386 pState->uIsTransmitting = 0;
387}
388
389#ifdef IN_RING3
390
391/**
392 * Wakeup the RX thread.
393 */
394static void vnetWakeupReceive(PPDMDEVINS pDevIns)
395{
396 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE *);
397 if ( pState->fMaybeOutOfSpace
398 && pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
399 {
400 STAM_COUNTER_INC(&pState->StatRxOverflowWakeup);
401 Log(("%s Waking up Out-of-RX-space semaphore\n", INSTANCE(pState)));
402 RTSemEventSignal(pState->hEventMoreRxDescAvail);
403 }
404}
405
406/**
407 * Link Up Timer handler.
408 *
409 * @param pDevIns Pointer to device instance structure.
410 * @param pTimer Pointer to the timer.
411 * @param pvUser NULL.
412 * @thread EMT
413 */
414static DECLCALLBACK(void) vnetLinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
415{
416 VNETSTATE *pState = (VNETSTATE *)pvUser;
417
418 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
419 if (RT_UNLIKELY(rc != VINF_SUCCESS))
420 return;
421 STATUS |= VNET_S_LINK_UP;
422 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
423 vnetWakeupReceive(pDevIns);
424 vnetCsLeave(pState);
425}
426
427
428
429
430/**
431 * Handler for the wakeup signaller queue.
432 */
433static DECLCALLBACK(bool) vnetCanRxQueueConsumer(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)
434{
435 vnetWakeupReceive(pDevIns);
436 return true;
437}
438
439#endif /* IN_RING3 */
440
441/**
442 * This function is called when the driver becomes ready.
443 *
444 * @param pState The device state structure.
445 */
446PDMBOTHCBDECL(void) vnetReady(void *pvState)
447{
448 VNETSTATE *pState = (VNETSTATE*)pvState;
449 Log(("%s Driver became ready, waking up RX thread...\n", INSTANCE(pState)));
450#ifdef IN_RING3
451 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
452#else
453 PPDMQUEUEITEMCORE pItem = PDMQueueAlloc(pState->CTX_SUFF(pCanRxQueue));
454 if (pItem)
455 PDMQueueInsert(pState->CTX_SUFF(pCanRxQueue), pItem);
456#endif
457}
458
459/**
460 * Port I/O Handler for IN operations.
461 *
462 * @returns VBox status code.
463 *
464 * @param pDevIns The device instance.
465 * @param pvUser Pointer to the device state structure.
466 * @param port Port number used for the IN operation.
467 * @param pu32 Where to store the result.
468 * @param cb Number of bytes read.
469 * @thread EMT
470 */
471PDMBOTHCBDECL(int) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser,
472 RTIOPORT port, uint32_t *pu32, unsigned cb)
473{
474 return vpciIOPortIn(pDevIns, pvUser, port, pu32, cb,
475 vnetGetHostFeatures,
476 vnetGetConfig);
477}
478
479
480/**
481 * Port I/O Handler for OUT operations.
482 *
483 * @returns VBox status code.
484 *
485 * @param pDevIns The device instance.
486 * @param pvUser User argument.
487 * @param Port Port number used for the IN operation.
488 * @param u32 The value to output.
489 * @param cb The value size in bytes.
490 * @thread EMT
491 */
492PDMBOTHCBDECL(int) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser,
493 RTIOPORT port, uint32_t u32, unsigned cb)
494{
495 return vpciIOPortOut(pDevIns, pvUser, port, u32, cb,
496 vnetGetHostMinimalFeatures,
497 vnetGetHostFeatures,
498 vnetSetHostFeatures,
499 vnetReset,
500 vnetReady,
501 vnetSetConfig);
502}
503
504
505#ifdef IN_RING3
506
507/**
508 * Check if the device can receive data now.
509 * This must be called before the pfnRecieve() method is called.
510 *
511 * @remarks As a side effect this function enables queue notification
512 * if it cannot receive because the queue is empty.
513 * It disables notification if it can receive.
514 *
515 * @returns VERR_NET_NO_BUFFER_SPACE if it cannot.
516 * @param pInterface Pointer to the interface structure containing the called function pointer.
517 * @thread RX
518 */
519static int vnetCanReceive(VNETSTATE *pState)
520{
521 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
522 AssertRCReturn(rc, rc);
523
524 LogFlow(("%s vnetCanReceive\n", INSTANCE(pState)));
525 if (!(pState->VPCI.uStatus & VPCI_STATUS_DRV_OK))
526 rc = VERR_NET_NO_BUFFER_SPACE;
527 else if (!vqueueIsReady(&pState->VPCI, pState->pRxQueue))
528 rc = VERR_NET_NO_BUFFER_SPACE;
529 else if (vqueueIsEmpty(&pState->VPCI, pState->pRxQueue))
530 {
531 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, true);
532 rc = VERR_NET_NO_BUFFER_SPACE;
533 }
534 else
535 {
536 vringSetNotification(&pState->VPCI, &pState->pRxQueue->VRing, false);
537 rc = VINF_SUCCESS;
538 }
539
540 LogFlow(("%s vnetCanReceive -> %Rrc\n", INSTANCE(pState), rc));
541 vnetCsRxLeave(pState);
542 return rc;
543}
544
545static DECLCALLBACK(int) vnetWaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
546{
547 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkDown);
548 LogFlow(("%s vnetWaitReceiveAvail(cMillies=%u)\n", INSTANCE(pState), cMillies));
549 int rc = vnetCanReceive(pState);
550
551 if (RT_SUCCESS(rc))
552 return VINF_SUCCESS;
553 if (RT_UNLIKELY(cMillies == 0))
554 return VERR_NET_NO_BUFFER_SPACE;
555
556 rc = VERR_INTERRUPTED;
557 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, true);
558 STAM_PROFILE_START(&pState->StatRxOverflow, a);
559
560 VMSTATE enmVMState;
561 while (RT_LIKELY( (enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns))) == VMSTATE_RUNNING
562 || enmVMState == VMSTATE_RUNNING_LS))
563 {
564 int rc2 = vnetCanReceive(pState);
565 if (RT_SUCCESS(rc2))
566 {
567 rc = VINF_SUCCESS;
568 break;
569 }
570 Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
571 INSTANCE(pState), cMillies));
572 RTSemEventWait(pState->hEventMoreRxDescAvail, cMillies);
573 }
574 STAM_PROFILE_STOP(&pState->StatRxOverflow, a);
575 ASMAtomicXchgBool(&pState->fMaybeOutOfSpace, false);
576
577 LogFlow(("%s vnetWaitReceiveAvail -> %d\n", INSTANCE(pState), rc));
578 return rc;
579}
580
581
582/**
583 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
584 */
585static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
586{
587 VNETSTATE *pThis = IFACE_TO_STATE(pInterface, VPCI.IBase);
588 Assert(&pThis->VPCI.IBase == pInterface);
589
590 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThis->INetworkDown);
591 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
592 return vpciQueryInterface(pInterface, pszIID);
593}
594
595/**
596 * Returns true if it is a broadcast packet.
597 *
598 * @returns true if destination address indicates broadcast.
599 * @param pvBuf The ethernet packet.
600 */
601DECLINLINE(bool) vnetIsBroadcast(const void *pvBuf)
602{
603 static const uint8_t s_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
604 return memcmp(pvBuf, s_abBcastAddr, sizeof(s_abBcastAddr)) == 0;
605}
606
607/**
608 * Returns true if it is a multicast packet.
609 *
610 * @remarks returns true for broadcast packets as well.
611 * @returns true if destination address indicates multicast.
612 * @param pvBuf The ethernet packet.
613 */
614DECLINLINE(bool) vnetIsMulticast(const void *pvBuf)
615{
616 return (*(char*)pvBuf) & 1;
617}
618
619/**
620 * Determines if the packet is to be delivered to upper layer.
621 *
622 * @returns true if packet is intended for this node.
623 * @param pState Pointer to the state structure.
624 * @param pvBuf The ethernet packet.
625 * @param cb Number of bytes available in the packet.
626 */
627static bool vnetAddressFilter(PVNETSTATE pState, const void *pvBuf, size_t cb)
628{
629 if (pState->fPromiscuous)
630 return true;
631
632 /* Ignore everything outside of our VLANs */
633 uint16_t *u16Ptr = (uint16_t*)pvBuf;
634 /* Compare TPID with VLAN Ether Type */
635 if ( u16Ptr[6] == RT_H2BE_U16(0x8100)
636 && !ASMBitTest(pState->aVlanFilter, RT_BE2H_U16(u16Ptr[7]) & 0xFFF))
637 return false;
638
639 if (vnetIsBroadcast(pvBuf))
640 return true;
641
642 if (pState->fAllMulti && vnetIsMulticast(pvBuf))
643 return true;
644
645 if (!memcmp(pState->config.mac.au8, pvBuf, sizeof(RTMAC)))
646 return true;
647
648 for (unsigned i = 0; i < pState->nMacFilterEntries; i++)
649 if (!memcmp(&pState->aMacFilter[i], pvBuf, sizeof(RTMAC)))
650 return true;
651
652 return false;
653}
654
655/**
656 * Pad and store received packet.
657 *
658 * @remarks Make sure that the packet appears to upper layer as one coming
659 * from real Ethernet: pad it and insert FCS.
660 *
661 * @returns VBox status code.
662 * @param pState The device state structure.
663 * @param pvBuf The available data.
664 * @param cb Number of bytes available in the buffer.
665 * @thread RX
666 */
667static int vnetHandleRxPacket(PVNETSTATE pState, const void *pvBuf, size_t cb)
668{
669 VNETHDR hdr;
670
671 hdr.u8Flags = 0;
672 hdr.u8GSOType = VNETHDR_GSO_NONE;
673
674 vnetPacketDump(pState, (const uint8_t*)pvBuf, cb, "<-- Incoming");
675
676 unsigned int uOffset = 0;
677 for (unsigned int nElem = 0; uOffset < cb; nElem++)
678 {
679 VQUEUEELEM elem;
680 unsigned int nSeg = 0, uElemSize = 0;
681
682 if (!vqueueGet(&pState->VPCI, pState->pRxQueue, &elem))
683 {
684 Log(("%s vnetHandleRxPacket: Suddenly there is no space in receive queue!\n", INSTANCE(pState)));
685 return VERR_INTERNAL_ERROR;
686 }
687
688 if (elem.nIn < 1)
689 {
690 Log(("%s vnetHandleRxPacket: No writable descriptors in receive queue!\n", INSTANCE(pState)));
691 return VERR_INTERNAL_ERROR;
692 }
693
694 if (nElem == 0)
695 {
696 /* The very first segment of the very first element gets the header. */
697 if (elem.aSegsIn[nSeg].cb != sizeof(VNETHDR))
698 {
699 Log(("%s vnetHandleRxPacket: The first descriptor does match the header size!\n", INSTANCE(pState)));
700 return VERR_INTERNAL_ERROR;
701 }
702
703 elem.aSegsIn[nSeg++].pv = &hdr;
704 uElemSize += sizeof(VNETHDR);
705 }
706
707 while (nSeg < elem.nIn && uOffset < cb)
708 {
709 unsigned int uSize = RT_MIN(elem.aSegsIn[nSeg].cb, cb - uOffset);
710 elem.aSegsIn[nSeg++].pv = (uint8_t*)pvBuf + uOffset;
711 uOffset += uSize;
712 uElemSize += uSize;
713 }
714 STAM_PROFILE_START(&pState->StatReceiveStore, a);
715 vqueuePut(&pState->VPCI, pState->pRxQueue, &elem, uElemSize);
716 STAM_PROFILE_STOP(&pState->StatReceiveStore, a);
717 }
718 vqueueSync(&pState->VPCI, pState->pRxQueue);
719
720 return VINF_SUCCESS;
721}
722
723/**
724 * Receive data from the network.
725 *
726 * @returns VBox status code.
727 * @param pInterface Pointer to the interface structure containing the called function pointer.
728 * @param pvBuf The available data.
729 * @param cb Number of bytes available in the buffer.
730 * @thread RX
731 */
732static DECLCALLBACK(int) vnetReceive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
733{
734 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkDown);
735
736 Log2(("%s vnetReceive: pvBuf=%p cb=%u\n", INSTANCE(pState), pvBuf, cb));
737 int rc = vnetCanReceive(pState);
738 if (RT_FAILURE(rc))
739 return rc;
740
741 /* Drop packets if VM is not running or cable is disconnected. */
742 VMSTATE enmVMState = PDMDevHlpVMState(pState->VPCI.CTX_SUFF(pDevIns));
743 if (( enmVMState != VMSTATE_RUNNING
744 && enmVMState != VMSTATE_RUNNING_LS)
745 || !(STATUS & VNET_S_LINK_UP))
746 return VINF_SUCCESS;
747
748 STAM_PROFILE_START(&pState->StatReceive, a);
749 vpciSetReadLed(&pState->VPCI, true);
750 if (vnetAddressFilter(pState, pvBuf, cb))
751 {
752 rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
753 if (RT_SUCCESS(rc))
754 {
755 rc = vnetHandleRxPacket(pState, pvBuf, cb);
756 STAM_REL_COUNTER_ADD(&pState->StatReceiveBytes, cb);
757 vnetCsRxLeave(pState);
758 }
759 }
760 vpciSetReadLed(&pState->VPCI, false);
761 STAM_PROFILE_STOP(&pState->StatReceive, a);
762 return rc;
763}
764
765/**
766 * Gets the current Media Access Control (MAC) address.
767 *
768 * @returns VBox status code.
769 * @param pInterface Pointer to the interface structure containing the called function pointer.
770 * @param pMac Where to store the MAC address.
771 * @thread EMT
772 */
773static DECLCALLBACK(int) vnetGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
774{
775 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
776 memcpy(pMac, pState->config.mac.au8, sizeof(RTMAC));
777 return VINF_SUCCESS;
778}
779
780/**
781 * Gets the new link state.
782 *
783 * @returns The current link state.
784 * @param pInterface Pointer to the interface structure containing the called function pointer.
785 * @thread EMT
786 */
787static DECLCALLBACK(PDMNETWORKLINKSTATE) vnetGetLinkState(PPDMINETWORKCONFIG pInterface)
788{
789 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
790 if (STATUS & VNET_S_LINK_UP)
791 return PDMNETWORKLINKSTATE_UP;
792 return PDMNETWORKLINKSTATE_DOWN;
793}
794
795
796/**
797 * Sets the new link state.
798 *
799 * @returns VBox status code.
800 * @param pInterface Pointer to the interface structure containing the called function pointer.
801 * @param enmState The new link state
802 */
803static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
804{
805 VNETSTATE *pState = IFACE_TO_STATE(pInterface, INetworkConfig);
806 bool fOldUp = !!(STATUS & VNET_S_LINK_UP);
807 bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
808
809 if (fNewUp != fOldUp)
810 {
811 if (fNewUp)
812 {
813 Log(("%s Link is up\n", INSTANCE(pState)));
814 STATUS |= VNET_S_LINK_UP;
815 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
816 }
817 else
818 {
819 Log(("%s Link is down\n", INSTANCE(pState)));
820 STATUS &= ~VNET_S_LINK_UP;
821 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
822 }
823 if (pState->pDrv)
824 pState->pDrv->pfnNotifyLinkChanged(pState->pDrv, enmState);
825 }
826 return VINF_SUCCESS;
827}
828
829static DECLCALLBACK(void) vnetQueueReceive(void *pvState, PVQUEUE pQueue)
830{
831 VNETSTATE *pState = (VNETSTATE*)pvState;
832 Log(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pState)));
833 vnetWakeupReceive(pState->VPCI.CTX_SUFF(pDevIns));
834}
835
836static DECLCALLBACK(void) vnetTransmitPendingPackets(PVNETSTATE pState, PVQUEUE pQueue)
837{
838 /*
839 * Only one thread is allowed to transmit at a time, others should skip
840 * transmission as the packets will be picked up by the transmitting
841 * thread.
842 */
843 if (!ASMAtomicCmpXchgU32(&pState->uIsTransmitting, 1, 0))
844 return;
845
846 if ((pState->VPCI.uStatus & VPCI_STATUS_DRV_OK) == 0)
847 {
848 Log(("%s Ignoring transmit requests from non-existent driver (status=0x%x).\n",
849 INSTANCE(pState), pState->VPCI.uStatus));
850 return;
851 }
852
853 Log3(("%s vnetTransmitPendingPackets: About to trasmit %d pending packets\n", INSTANCE(pState),
854 vringReadAvailIndex(&pState->VPCI, &pState->pTxQueue->VRing) - pState->pTxQueue->uNextAvailIndex));
855
856 vpciSetWriteLed(&pState->VPCI, true);
857
858 VQUEUEELEM elem;
859 while (vqueueGet(&pState->VPCI, pQueue, &elem))
860 {
861 unsigned int uOffset = 0;
862 if (elem.nOut < 2 || elem.aSegsOut[0].cb != sizeof(VNETHDR))
863 {
864 Log(("%s vnetQueueTransmit: The first segment is not the header! (%u < 2 || %u != %u).\n",
865 INSTANCE(pState), elem.nOut, elem.aSegsOut[0].cb, sizeof(VNETHDR)));
866 break; /* For now we simply ignore the header, but it must be there anyway! */
867 }
868 else
869 {
870 STAM_PROFILE_ADV_START(&pState->StatTransmit, a);
871 /* Assemble a complete frame. */
872 for (unsigned int i = 1; i < elem.nOut && uOffset < VNET_MAX_FRAME_SIZE; i++)
873 {
874 unsigned int uSize = elem.aSegsOut[i].cb;
875 if (uSize > VNET_MAX_FRAME_SIZE - uOffset)
876 {
877 Log(("%s vnetQueueTransmit: Packet is too big (>64k), truncating...\n", INSTANCE(pState)));
878 uSize = VNET_MAX_FRAME_SIZE - uOffset;
879 }
880 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns), elem.aSegsOut[i].addr,
881 pState->pTxBuf + uOffset, uSize);
882 uOffset += uSize;
883 }
884 if (pState->pDrv)
885 {
886 vnetPacketDump(pState, pState->pTxBuf, uOffset, "--> Outgoing");
887
888 STAM_PROFILE_START(&pState->StatTransmitSend, a);
889
890 /** @todo Optimize away the extra copying! (lazy bird) */
891 PPDMSCATTERGATHER pSgBuf;
892 int rc = pState->pDrv->pfnAllocBuf(pState->pDrv, uOffset, NULL /*pGso*/, &pSgBuf);
893 if (RT_SUCCESS(rc))
894 {
895 Assert(pSgBuf->cSegs == 1);
896 memcpy(pSgBuf->aSegs[0].pvSeg, pState->pTxBuf, uOffset);
897 pSgBuf->cbUsed = uOffset;
898 rc = pState->pDrv->pfnSendBuf(pState->pDrv, pSgBuf, false);
899 }
900
901 STAM_PROFILE_STOP(&pState->StatTransmitSend, a);
902 STAM_REL_COUNTER_ADD(&pState->StatTransmitBytes, uOffset);
903 }
904 }
905 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(VNETHDR) + uOffset);
906 vqueueSync(&pState->VPCI, pQueue);
907 STAM_PROFILE_ADV_STOP(&pState->StatTransmit, a);
908 }
909 vpciSetWriteLed(&pState->VPCI, false);
910
911 ASMAtomicWriteU32(&pState->uIsTransmitting, 0);
912}
913
914#ifdef VNET_TX_DELAY
915static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
916{
917 VNETSTATE *pState = (VNETSTATE*)pvState;
918
919 if (TMTimerIsActive(pState->CTX_SUFF(pTxTimer)))
920 {
921 int rc = TMTimerStop(pState->CTX_SUFF(pTxTimer));
922 Log3(("%s vnetQueueTransmit: Got kicked with notification disabled, "
923 "re-enable notification and flush TX queue\n", INSTANCE(pState)));
924 vnetTransmitPendingPackets(pState, pQueue);
925 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
926 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
927 else
928 {
929 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
930 vnetCsLeave(pState);
931 }
932 }
933 else
934 {
935 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
936 LogRel(("vnetQueueTransmit: Failed to enter critical section!/n"));
937 else
938 {
939 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, false);
940 TMTimerSetMicro(pState->CTX_SUFF(pTxTimer), VNET_TX_DELAY);
941 pState->u64NanoTS = RTTimeNanoTS();
942 vnetCsLeave(pState);
943 }
944 }
945}
946
947/**
948 * Transmit Delay Timer handler.
949 *
950 * @remarks We only get here when the timer expires.
951 *
952 * @param pDevIns Pointer to device instance structure.
953 * @param pTimer Pointer to the timer.
954 * @param pvUser NULL.
955 * @thread EMT
956 */
957static DECLCALLBACK(void) vnetTxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
958{
959 VNETSTATE *pState = (VNETSTATE*)pvUser;
960
961 uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pState->u64NanoTS)/1000);
962 if (u32MicroDiff < pState->u32MinDiff)
963 pState->u32MinDiff = u32MicroDiff;
964 if (u32MicroDiff > pState->u32MaxDiff)
965 pState->u32MaxDiff = u32MicroDiff;
966 pState->u32AvgDiff = (pState->u32AvgDiff * pState->u32i + u32MicroDiff) / (pState->u32i + 1);
967 pState->u32i++;
968 Log3(("vnetTxTimer: Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",
969 u32MicroDiff, pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
970
971// Log3(("%s vnetTxTimer: Expired\n", INSTANCE(pState)));
972 vnetTransmitPendingPackets(pState, pState->pTxQueue);
973 if (RT_FAILURE(vnetCsEnter(pState, VERR_SEM_BUSY)))
974 {
975 LogRel(("vnetTxTimer: Failed to enter critical section!/n"));
976 return;
977 }
978 vringSetNotification(&pState->VPCI, &pState->pTxQueue->VRing, true);
979 vnetCsLeave(pState);
980}
981
982#else /* !VNET_TX_DELAY */
983static DECLCALLBACK(void) vnetQueueTransmit(void *pvState, PVQUEUE pQueue)
984{
985 VNETSTATE *pState = (VNETSTATE*)pvState;
986
987 vnetTransmitPendingPackets(pState, pQueue);
988}
989#endif /* !VNET_TX_DELAY */
990
991static uint8_t vnetControlRx(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
992{
993 uint8_t u8Ack = VNET_OK;
994 uint8_t fOn;
995 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
996 pElem->aSegsOut[1].addr,
997 &fOn, sizeof(fOn));
998 Log(("%s vnetControlRx: uCommand=%u fOn=%u\n", INSTANCE(pState), pCtlHdr->u8Command, fOn));
999 switch (pCtlHdr->u8Command)
1000 {
1001 case VNET_CTRL_CMD_RX_MODE_PROMISC:
1002 pState->fPromiscuous = !!fOn;
1003 break;
1004 case VNET_CTRL_CMD_RX_MODE_ALLMULTI:
1005 pState->fAllMulti = !!fOn;
1006 break;
1007 default:
1008 u8Ack = VNET_ERROR;
1009 }
1010
1011 return u8Ack;
1012}
1013
1014static uint8_t vnetControlMac(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1015{
1016 uint32_t nMacs = 0;
1017
1018 if (pCtlHdr->u8Command != VNET_CTRL_CMD_MAC_TABLE_SET
1019 || pElem->nOut != 3
1020 || pElem->aSegsOut[1].cb < sizeof(nMacs)
1021 || pElem->aSegsOut[2].cb < sizeof(nMacs))
1022 {
1023 Log(("%s vnetControlMac: Segment layout is wrong "
1024 "(u8Command=%u nOut=%u cb1=%u cb2=%u)\n", INSTANCE(pState),
1025 pCtlHdr->u8Command, pElem->nOut,
1026 pElem->aSegsOut[1].cb, pElem->aSegsOut[2].cb));
1027 return VNET_ERROR;
1028 }
1029
1030 /* Load unicast addresses */
1031 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1032 pElem->aSegsOut[1].addr,
1033 &nMacs, sizeof(nMacs));
1034
1035 if (pElem->aSegsOut[1].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1036 {
1037 Log(("%s vnetControlMac: The unicast mac segment is too small "
1038 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[1].cb));
1039 return VNET_ERROR;
1040 }
1041
1042 if (nMacs > VNET_MAC_FILTER_LEN)
1043 {
1044 Log(("%s vnetControlMac: MAC table is too big, have to use promiscuous"
1045 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1046 pState->fPromiscuous = true;
1047 }
1048 else
1049 {
1050 if (nMacs)
1051 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1052 pElem->aSegsOut[1].addr + sizeof(nMacs),
1053 pState->aMacFilter, nMacs * sizeof(RTMAC));
1054 pState->nMacFilterEntries = nMacs;
1055#ifdef DEBUG
1056 Log(("%s vnetControlMac: unicast macs:\n", INSTANCE(pState)));
1057 for(unsigned i = 0; i < nMacs; i++)
1058 Log((" %RTmac\n", &pState->aMacFilter[i]));
1059#endif /* DEBUG */
1060 }
1061
1062 /* Load multicast addresses */
1063 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1064 pElem->aSegsOut[2].addr,
1065 &nMacs, sizeof(nMacs));
1066
1067 if (pElem->aSegsOut[2].cb < nMacs * sizeof(RTMAC) + sizeof(nMacs))
1068 {
1069 Log(("%s vnetControlMac: The multicast mac segment is too small "
1070 "(nMacs=%u cb=%u)\n", INSTANCE(pState), pElem->aSegsOut[2].cb));
1071 return VNET_ERROR;
1072 }
1073
1074 if (nMacs > VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1075 {
1076 Log(("%s vnetControlMac: MAC table is too big, have to use allmulti"
1077 " mode (nMacs=%u)\n", INSTANCE(pState), nMacs));
1078 pState->fAllMulti = true;
1079 }
1080 else
1081 {
1082 if (nMacs)
1083 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1084 pElem->aSegsOut[2].addr + sizeof(nMacs),
1085 &pState->aMacFilter[pState->nMacFilterEntries],
1086 nMacs * sizeof(RTMAC));
1087#ifdef DEBUG
1088 Log(("%s vnetControlMac: multicast macs:\n", INSTANCE(pState)));
1089 for(unsigned i = 0; i < nMacs; i++)
1090 Log((" %RTmac\n",
1091 &pState->aMacFilter[i+pState->nMacFilterEntries]));
1092#endif /* DEBUG */
1093 pState->nMacFilterEntries += nMacs;
1094 }
1095
1096 return VNET_OK;
1097}
1098
1099static uint8_t vnetControlVlan(PVNETSTATE pState, PVNETCTLHDR pCtlHdr, PVQUEUEELEM pElem)
1100{
1101 uint8_t u8Ack = VNET_OK;
1102 uint16_t u16Vid;
1103
1104 if (pElem->nOut != 2 || pElem->aSegsOut[1].cb != sizeof(u16Vid))
1105 {
1106 Log(("%s vnetControlVlan: Segment layout is wrong "
1107 "(u8Command=%u nOut=%u cb=%u)\n", INSTANCE(pState),
1108 pCtlHdr->u8Command, pElem->nOut, pElem->aSegsOut[1].cb));
1109 return VNET_ERROR;
1110 }
1111
1112 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1113 pElem->aSegsOut[1].addr,
1114 &u16Vid, sizeof(u16Vid));
1115
1116 if (u16Vid >= VNET_MAX_VID)
1117 {
1118 Log(("%s vnetControlVlan: VLAN ID is out of range "
1119 "(VID=%u)\n", INSTANCE(pState), u16Vid));
1120 return VNET_ERROR;
1121 }
1122
1123 Log(("%s vnetControlVlan: uCommand=%u VID=%u\n", INSTANCE(pState),
1124 pCtlHdr->u8Command, u16Vid));
1125
1126 switch (pCtlHdr->u8Command)
1127 {
1128 case VNET_CTRL_CMD_VLAN_ADD:
1129 ASMBitSet(pState->aVlanFilter, u16Vid);
1130 break;
1131 case VNET_CTRL_CMD_VLAN_DEL:
1132 ASMBitClear(pState->aVlanFilter, u16Vid);
1133 break;
1134 default:
1135 u8Ack = VNET_ERROR;
1136 }
1137
1138 return u8Ack;
1139}
1140
1141
1142static DECLCALLBACK(void) vnetQueueControl(void *pvState, PVQUEUE pQueue)
1143{
1144 VNETSTATE *pState = (VNETSTATE*)pvState;
1145 uint8_t u8Ack;
1146 VQUEUEELEM elem;
1147 while (vqueueGet(&pState->VPCI, pQueue, &elem))
1148 {
1149 unsigned int uOffset = 0;
1150 if (elem.nOut < 1 || elem.aSegsOut[0].cb < sizeof(VNETCTLHDR))
1151 {
1152 Log(("%s vnetQueueControl: The first 'out' segment is not the "
1153 "header! (%u < 1 || %u < %u).\n", INSTANCE(pState), elem.nOut,
1154 elem.aSegsOut[0].cb,sizeof(VNETCTLHDR)));
1155 break; /* Skip the element and hope the next one is good. */
1156 }
1157 else if ( elem.nIn < 1
1158 || elem.aSegsIn[elem.nIn - 1].cb < sizeof(VNETCTLACK))
1159 {
1160 Log(("%s vnetQueueControl: The last 'in' segment is too small "
1161 "to hold the acknowledge! (%u < 1 || %u < %u).\n",
1162 INSTANCE(pState), elem.nIn, elem.aSegsIn[elem.nIn - 1].cb,
1163 sizeof(VNETCTLACK)));
1164 break; /* Skip the element and hope the next one is good. */
1165 }
1166 else
1167 {
1168 VNETCTLHDR CtlHdr;
1169 PDMDevHlpPhysRead(pState->VPCI.CTX_SUFF(pDevIns),
1170 elem.aSegsOut[0].addr,
1171 &CtlHdr, sizeof(CtlHdr));
1172 switch (CtlHdr.u8Class)
1173 {
1174 case VNET_CTRL_CLS_RX_MODE:
1175 u8Ack = vnetControlRx(pState, &CtlHdr, &elem);
1176 break;
1177 case VNET_CTRL_CLS_MAC:
1178 u8Ack = vnetControlMac(pState, &CtlHdr, &elem);
1179 break;
1180 case VNET_CTRL_CLS_VLAN:
1181 u8Ack = vnetControlVlan(pState, &CtlHdr, &elem);
1182 break;
1183 default:
1184 u8Ack = VNET_ERROR;
1185 }
1186 Log(("%s Processed control message %u, ack=%u.\n", INSTANCE(pState),
1187 CtlHdr.u8Class, u8Ack));
1188 PDMDevHlpPhysWrite(pState->VPCI.CTX_SUFF(pDevIns),
1189 elem.aSegsIn[elem.nIn - 1].addr,
1190 &u8Ack, sizeof(u8Ack));
1191 }
1192 vqueuePut(&pState->VPCI, pQueue, &elem, sizeof(u8Ack));
1193 vqueueSync(&pState->VPCI, pQueue);
1194 }
1195}
1196
1197/**
1198 * Saves the configuration.
1199 *
1200 * @param pState The VNET state.
1201 * @param pSSM The handle to the saved state.
1202 */
1203static void vnetSaveConfig(VNETSTATE *pState, PSSMHANDLE pSSM)
1204{
1205 SSMR3PutMem(pSSM, &pState->macConfigured, sizeof(pState->macConfigured));
1206}
1207
1208/**
1209 * Live save - save basic configuration.
1210 *
1211 * @returns VBox status code.
1212 * @param pDevIns The device instance.
1213 * @param pSSM The handle to the saved state.
1214 * @param uPass
1215 */
1216static DECLCALLBACK(int) vnetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
1217{
1218 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1219 vnetSaveConfig(pState, pSSM);
1220 return VINF_SSM_DONT_CALL_AGAIN;
1221}
1222
1223/**
1224 * Prepares for state saving.
1225 *
1226 * @returns VBox status code.
1227 * @param pDevIns The device instance.
1228 * @param pSSM The handle to the saved state.
1229 */
1230static DECLCALLBACK(int) vnetSavePrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1231{
1232 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1233
1234 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1235 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1236 return rc;
1237 vnetCsRxLeave(pState);
1238 return VINF_SUCCESS;
1239}
1240
1241/**
1242 * Saves the state of device.
1243 *
1244 * @returns VBox status code.
1245 * @param pDevIns The device instance.
1246 * @param pSSM The handle to the saved state.
1247 */
1248static DECLCALLBACK(int) vnetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1249{
1250 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1251
1252 /* Save config first */
1253 vnetSaveConfig(pState, pSSM);
1254
1255 /* Save the common part */
1256 int rc = vpciSaveExec(&pState->VPCI, pSSM);
1257 AssertRCReturn(rc, rc);
1258 /* Save device-specific part */
1259 rc = SSMR3PutMem( pSSM, pState->config.mac.au8, sizeof(pState->config.mac));
1260 AssertRCReturn(rc, rc);
1261 rc = SSMR3PutBool(pSSM, pState->fPromiscuous);
1262 AssertRCReturn(rc, rc);
1263 rc = SSMR3PutBool(pSSM, pState->fAllMulti);
1264 AssertRCReturn(rc, rc);
1265 rc = SSMR3PutU32( pSSM, pState->nMacFilterEntries);
1266 AssertRCReturn(rc, rc);
1267 rc = SSMR3PutMem( pSSM, pState->aMacFilter,
1268 pState->nMacFilterEntries * sizeof(RTMAC));
1269 AssertRCReturn(rc, rc);
1270 rc = SSMR3PutMem( pSSM, pState->aVlanFilter, sizeof(pState->aVlanFilter));
1271 AssertRCReturn(rc, rc);
1272 Log(("%s State has been saved\n", INSTANCE(pState)));
1273 return VINF_SUCCESS;
1274}
1275
1276
1277/**
1278 * Serializes the receive thread, it may be working inside the critsect.
1279 *
1280 * @returns VBox status code.
1281 * @param pDevIns The device instance.
1282 * @param pSSM The handle to the saved state.
1283 */
1284static DECLCALLBACK(int) vnetLoadPrep(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1285{
1286 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1287
1288 int rc = vnetCsRxEnter(pState, VERR_SEM_BUSY);
1289 if (RT_UNLIKELY(rc != VINF_SUCCESS))
1290 return rc;
1291 vnetCsRxLeave(pState);
1292 return VINF_SUCCESS;
1293}
1294
1295/* Takes down the link temporarily if it's current status is up.
1296 *
1297 * This is used during restore and when replumbing the network link.
1298 *
1299 * The temporary link outage is supposed to indicate to the OS that all network
1300 * connections have been lost and that it for instance is appropriate to
1301 * renegotiate any DHCP lease.
1302 *
1303 * @param pThis The PCNet instance data.
1304 */
1305static void vnetTempLinkDown(PVNETSTATE pState)
1306{
1307 if (STATUS & VNET_S_LINK_UP)
1308 {
1309 STATUS &= ~VNET_S_LINK_UP;
1310 vpciRaiseInterrupt(&pState->VPCI, VERR_SEM_BUSY, VPCI_ISR_CONFIG);
1311 /* Restore the link back in 5 seconds. */
1312 int rc = TMTimerSetMillies(pState->pLinkUpTimer, 5000);
1313 AssertRC(rc);
1314 }
1315}
1316
1317
1318/**
1319 * Restore previously saved state of device.
1320 *
1321 * @returns VBox status code.
1322 * @param pDevIns The device instance.
1323 * @param pSSM The handle to the saved state.
1324 * @param uVersion The data unit version number.
1325 * @param uPass The data pass.
1326 */
1327static DECLCALLBACK(int) vnetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1328{
1329 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1330 int rc;
1331
1332 /* config checks */
1333 RTMAC macConfigured;
1334 rc = SSMR3GetMem(pSSM, &macConfigured, sizeof(macConfigured));
1335 AssertRCReturn(rc, rc);
1336 if (memcmp(&macConfigured, &pState->macConfigured, sizeof(macConfigured))
1337 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
1338 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", INSTANCE(pState), &pState->macConfigured, &macConfigured));
1339
1340 rc = vpciLoadExec(&pState->VPCI, pSSM, uVersion, uPass, VNET_N_QUEUES);
1341 AssertRCReturn(rc, rc);
1342
1343 if (uPass == SSM_PASS_FINAL)
1344 {
1345 rc = SSMR3GetMem( pSSM, pState->config.mac.au8,
1346 sizeof(pState->config.mac));
1347 AssertRCReturn(rc, rc);
1348 if (uVersion > VIRTIO_SAVEDSTATE_VERSION_3_1_BETA1)
1349 {
1350 rc = SSMR3GetBool(pSSM, &pState->fPromiscuous);
1351 AssertRCReturn(rc, rc);
1352 rc = SSMR3GetBool(pSSM, &pState->fAllMulti);
1353 AssertRCReturn(rc, rc);
1354 rc = SSMR3GetU32(pSSM, &pState->nMacFilterEntries);
1355 AssertRCReturn(rc, rc);
1356 rc = SSMR3GetMem(pSSM, pState->aMacFilter,
1357 pState->nMacFilterEntries * sizeof(RTMAC));
1358 AssertRCReturn(rc, rc);
1359 /* Clear the rest. */
1360 if (pState->nMacFilterEntries < VNET_MAC_FILTER_LEN)
1361 memset(&pState->aMacFilter[pState->nMacFilterEntries],
1362 0,
1363 (VNET_MAC_FILTER_LEN - pState->nMacFilterEntries)
1364 * sizeof(RTMAC));
1365 rc = SSMR3GetMem(pSSM, pState->aVlanFilter,
1366 sizeof(pState->aVlanFilter));
1367 AssertRCReturn(rc, rc);
1368 }
1369 else
1370 {
1371 pState->fPromiscuous = true;
1372 pState->fAllMulti = false;
1373 pState->nMacFilterEntries = 0;
1374 memset(pState->aMacFilter, 0, VNET_MAC_FILTER_LEN * sizeof(RTMAC));
1375 memset(pState->aVlanFilter, 0, sizeof(pState->aVlanFilter));
1376 }
1377 }
1378
1379 return rc;
1380}
1381
1382/**
1383 * Link status adjustments after loading.
1384 *
1385 * @returns VBox status code.
1386 * @param pDevIns The device instance.
1387 * @param pSSM The handle to the saved state.
1388 */
1389static DECLCALLBACK(int) vnetLoadDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1390{
1391 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1392
1393 /*
1394 * Indicate link down to the guest OS that all network connections have
1395 * been lost, unless we've been teleported here.
1396 */
1397 if (!PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))
1398 vnetTempLinkDown(pState);
1399
1400 return VINF_SUCCESS;
1401}
1402
1403/**
1404 * Map PCI I/O region.
1405 *
1406 * @return VBox status code.
1407 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1408 * @param iRegion The region number.
1409 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1410 * I/O port, else it's a physical address.
1411 * This address is *NOT* relative to pci_mem_base like earlier!
1412 * @param cb Region size.
1413 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1414 * @thread EMT
1415 */
1416static DECLCALLBACK(int) vnetMap(PPCIDEVICE pPciDev, int iRegion,
1417 RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1418{
1419 int rc;
1420 VNETSTATE *pState = PDMINS_2_DATA(pPciDev->pDevIns, VNETSTATE*);
1421
1422 if (enmType != PCI_ADDRESS_SPACE_IO)
1423 {
1424 /* We should never get here */
1425 AssertMsgFailed(("Invalid PCI address space param in map callback"));
1426 return VERR_INTERNAL_ERROR;
1427 }
1428
1429 pState->VPCI.addrIOPort = (RTIOPORT)GCPhysAddress;
1430 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1431 cb, 0, vnetIOPortOut, vnetIOPortIn,
1432 NULL, NULL, "VirtioNet");
1433#ifdef VNET_GC_SUPPORT
1434 AssertRCReturn(rc, rc);
1435 rc = PDMDevHlpIOPortRegisterR0(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1436 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1437 NULL, NULL, "VirtioNet");
1438 AssertRCReturn(rc, rc);
1439 rc = PDMDevHlpIOPortRegisterRC(pPciDev->pDevIns, pState->VPCI.addrIOPort,
1440 cb, 0, "vnetIOPortOut", "vnetIOPortIn",
1441 NULL, NULL, "VirtioNet");
1442#endif
1443 AssertRC(rc);
1444 return rc;
1445}
1446
1447/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
1448
1449#ifdef VBOX_DYNAMIC_NET_ATTACH
1450
1451/**
1452 * Detach notification.
1453 *
1454 * One port on the network card has been disconnected from the network.
1455 *
1456 * @param pDevIns The device instance.
1457 * @param iLUN The logical unit which is being detached.
1458 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1459 */
1460static DECLCALLBACK(void) vnetDetach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1461{
1462 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1463 Log(("%s vnetDetach:\n", INSTANCE(pState)));
1464
1465 AssertLogRelReturnVoid(iLUN == 0);
1466
1467 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1468 if (RT_FAILURE(rc))
1469 {
1470 LogRel(("vnetDetach failed to enter critical section!\n"));
1471 return;
1472 }
1473
1474 /*
1475 * Zero some important members.
1476 */
1477 pState->pDrvBase = NULL;
1478 pState->pDrv = NULL;
1479
1480 vnetCsLeave(pState);
1481}
1482
1483
1484/**
1485 * Attach the Network attachment.
1486 *
1487 * One port on the network card has been connected to a network.
1488 *
1489 * @returns VBox status code.
1490 * @param pDevIns The device instance.
1491 * @param iLUN The logical unit which is being attached.
1492 * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
1493 *
1494 * @remarks This code path is not used during construction.
1495 */
1496static DECLCALLBACK(int) vnetAttach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
1497{
1498 VNETSTATE *pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1499 LogFlow(("%s vnetAttach:\n", INSTANCE(pState)));
1500
1501 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
1502
1503 int rc = vnetCsEnter(pState, VERR_SEM_BUSY);
1504 if (RT_FAILURE(rc))
1505 {
1506 LogRel(("vnetAttach failed to enter critical section!\n"));
1507 return rc;
1508 }
1509
1510 /*
1511 * Attach the driver.
1512 */
1513 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1514 if (RT_SUCCESS(rc))
1515 {
1516 if (rc == VINF_NAT_DNS)
1517 {
1518#ifdef RT_OS_LINUX
1519 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1520 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1521#else
1522 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1523 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1524#endif
1525 }
1526 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
1527 AssertMsgStmt(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
1528 rc = VERR_PDM_MISSING_INTERFACE_BELOW);
1529 }
1530 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1531 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
1532 {
1533 /* This should never happen because this function is not called
1534 * if there is no driver to attach! */
1535 Log(("%s No attached driver!\n", INSTANCE(pState)));
1536 }
1537
1538 /*
1539 * Temporary set the link down if it was up so that the guest
1540 * will know that we have change the configuration of the
1541 * network card
1542 */
1543 if (RT_SUCCESS(rc))
1544 vnetTempLinkDown(pState);
1545
1546 vnetCsLeave(pState);
1547 return rc;
1548
1549}
1550
1551#endif /* VBOX_DYNAMIC_NET_ATTACH */
1552
1553/**
1554 * @copydoc FNPDMDEVSUSPEND
1555 */
1556static DECLCALLBACK(void) vnetSuspend(PPDMDEVINS pDevIns)
1557{
1558 /* Poke thread waiting for buffer space. */
1559 vnetWakeupReceive(pDevIns);
1560}
1561
1562/**
1563 * @copydoc FNPDMDEVPOWEROFF
1564 */
1565static DECLCALLBACK(void) vnetPowerOff(PPDMDEVINS pDevIns)
1566{
1567 /* Poke thread waiting for buffer space. */
1568 vnetWakeupReceive(pDevIns);
1569}
1570
1571/**
1572 * Device relocation callback.
1573 *
1574 * When this callback is called the device instance data, and if the
1575 * device have a GC component, is being relocated, or/and the selectors
1576 * have been changed. The device must use the chance to perform the
1577 * necessary pointer relocations and data updates.
1578 *
1579 * Before the GC code is executed the first time, this function will be
1580 * called with a 0 delta so GC pointer calculations can be one in one place.
1581 *
1582 * @param pDevIns Pointer to the device instance.
1583 * @param offDelta The relocation delta relative to the old location.
1584 *
1585 * @remark A relocation CANNOT fail.
1586 */
1587static DECLCALLBACK(void) vnetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1588{
1589 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1590 vpciRelocate(pDevIns, offDelta);
1591 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1592#ifdef VNET_TX_DELAY
1593 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
1594#endif /* VNET_TX_DELAY */
1595 // TBD
1596}
1597
1598/**
1599 * Destruct a device instance.
1600 *
1601 * We need to free non-VM resources only.
1602 *
1603 * @returns VBox status.
1604 * @param pDevIns The device instance data.
1605 * @thread EMT
1606 */
1607static DECLCALLBACK(int) vnetDestruct(PPDMDEVINS pDevIns)
1608{
1609 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1610 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
1611
1612 LogRel(("TxTimer stats (avg/min/max): %7d usec %7d usec %7d usec\n",
1613 pState->u32AvgDiff, pState->u32MinDiff, pState->u32MaxDiff));
1614 Log(("%s Destroying instance\n", INSTANCE(pState)));
1615 if (pState->hEventMoreRxDescAvail != NIL_RTSEMEVENT)
1616 {
1617 RTSemEventSignal(pState->hEventMoreRxDescAvail);
1618 RTSemEventDestroy(pState->hEventMoreRxDescAvail);
1619 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1620 }
1621
1622 if (pState->pTxBuf)
1623 {
1624 RTMemFree(pState->pTxBuf);
1625 pState->pTxBuf = NULL;
1626 }
1627 // if (PDMCritSectIsInitialized(&pState->csRx))
1628 // PDMR3CritSectDelete(&pState->csRx);
1629
1630 return vpciDestruct(&pState->VPCI);
1631}
1632
1633/**
1634 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1635 */
1636static DECLCALLBACK(int) vnetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1637{
1638 VNETSTATE* pState = PDMINS_2_DATA(pDevIns, VNETSTATE*);
1639 int rc;
1640 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1641
1642 /* Initialize PCI part first. */
1643 pState->VPCI.IBase.pfnQueryInterface = vnetQueryInterface;
1644 rc = vpciConstruct(pDevIns, &pState->VPCI, iInstance,
1645 VNET_NAME_FMT, VNET_PCI_SUBSYSTEM_ID,
1646 VNET_PCI_CLASS, VNET_N_QUEUES);
1647 pState->pRxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueReceive, "RX ");
1648 pState->pTxQueue = vpciAddQueue(&pState->VPCI, 256, vnetQueueTransmit, "TX ");
1649 pState->pCtlQueue = vpciAddQueue(&pState->VPCI, 16, vnetQueueControl, "CTL");
1650
1651 Log(("%s Constructing new instance\n", INSTANCE(pState)));
1652
1653 pState->hEventMoreRxDescAvail = NIL_RTSEMEVENT;
1654
1655 /*
1656 * Validate configuration.
1657 */
1658 if (!CFGMR3AreValuesValid(pCfg, "MAC\0" "CableConnected\0" "LineSpeed\0"))
1659 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
1660 N_("Invalid configuration for VirtioNet device"));
1661
1662 /* Get config params */
1663 rc = CFGMR3QueryBytes(pCfg, "MAC", pState->macConfigured.au8,
1664 sizeof(pState->macConfigured));
1665 if (RT_FAILURE(rc))
1666 return PDMDEV_SET_ERROR(pDevIns, rc,
1667 N_("Configuration error: Failed to get MAC address"));
1668 rc = CFGMR3QueryBool(pCfg, "CableConnected", &pState->fCableConnected);
1669 if (RT_FAILURE(rc))
1670 return PDMDEV_SET_ERROR(pDevIns, rc,
1671 N_("Configuration error: Failed to get the value of 'CableConnected'"));
1672
1673 /* Initialize PCI config space */
1674 memcpy(pState->config.mac.au8, pState->macConfigured.au8, sizeof(pState->config.mac.au8));
1675 pState->config.uStatus = 0;
1676
1677 /* Initialize state structure */
1678 pState->u32PktNo = 1;
1679
1680 /* Interfaces */
1681 pState->INetworkDown.pfnWaitReceiveAvail = vnetWaitReceiveAvail;
1682 pState->INetworkDown.pfnReceive = vnetReceive;
1683 pState->INetworkConfig.pfnGetMac = vnetGetMac;
1684 pState->INetworkConfig.pfnGetLinkState = vnetGetLinkState;
1685 pState->INetworkConfig.pfnSetLinkState = vnetSetLinkState;
1686
1687 pState->pTxBuf = (uint8_t *)RTMemAllocZ(VNET_MAX_FRAME_SIZE);
1688 AssertMsgReturn(pState->pTxBuf,
1689 ("Cannot allocate TX buffer for virtio-net device\n"), VERR_NO_MEMORY);
1690
1691 /* Initialize critical section. */
1692 // char szTmp[sizeof(pState->VPCI.szInstance) + 2];
1693 // RTStrPrintf(szTmp, sizeof(szTmp), "%sRX", pState->VPCI.szInstance);
1694 // rc = PDMDevHlpCritSectInit(pDevIns, &pState->csRx, szTmp);
1695 // if (RT_FAILURE(rc))
1696 // return rc;
1697
1698 /* Map our ports to IO space. */
1699 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0,
1700 VPCI_CONFIG + sizeof(VNetPCIConfig),
1701 PCI_ADDRESS_SPACE_IO, vnetMap);
1702 if (RT_FAILURE(rc))
1703 return rc;
1704
1705
1706 /* Register save/restore state handlers. */
1707 rc = PDMDevHlpSSMRegisterEx(pDevIns, VIRTIO_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
1708 NULL, vnetLiveExec, NULL,
1709 vnetSavePrep, vnetSaveExec, NULL,
1710 vnetLoadPrep, vnetLoadExec, vnetLoadDone);
1711 if (RT_FAILURE(rc))
1712 return rc;
1713
1714 /* Create the RX notifier signaller. */
1715 rc = PDMDevHlpQueueCreate(pDevIns, sizeof(PDMQUEUEITEMCORE), 1, 0,
1716 vnetCanRxQueueConsumer, true, "VNet-Rcv", &pState->pCanRxQueueR3);
1717 if (RT_FAILURE(rc))
1718 return rc;
1719 pState->pCanRxQueueR0 = PDMQueueR0Ptr(pState->pCanRxQueueR3);
1720 pState->pCanRxQueueRC = PDMQueueRCPtr(pState->pCanRxQueueR3);
1721
1722 /* Create Link Up Timer */
1723 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetLinkUpTimer, pState,
1724 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
1725 "VirtioNet Link Up Timer", &pState->pLinkUpTimer);
1726 if (RT_FAILURE(rc))
1727 return rc;
1728
1729#ifdef VNET_TX_DELAY
1730 /* Create Transmit Delay Timer */
1731 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL, vnetTxTimer, pState,
1732 TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
1733 "VirtioNet TX Delay Timer", &pState->pTxTimerR3);
1734 if (RT_FAILURE(rc))
1735 return rc;
1736 pState->pTxTimerR0 = TMTimerR0Ptr(pState->pTxTimerR3);
1737 pState->pTxTimerRC = TMTimerRCPtr(pState->pTxTimerR3);
1738
1739 pState->u32i = pState->u32AvgDiff = pState->u32MaxDiff = 0;
1740 pState->u32MinDiff = ~0;
1741#endif /* VNET_TX_DELAY */
1742
1743 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->VPCI.IBase, &pState->pDrvBase, "Network Port");
1744 if (RT_SUCCESS(rc))
1745 {
1746 if (rc == VINF_NAT_DNS)
1747 {
1748 PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT",
1749 N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
1750 }
1751 pState->pDrv = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP);
1752 AssertMsgReturn(pState->pDrv, ("Failed to obtain the PDMINETWORKUP interface!\n"),
1753 VERR_PDM_MISSING_INTERFACE_BELOW);
1754 }
1755 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER
1756 || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME )
1757 {
1758 /* No error! */
1759 Log(("%s This adapter is not attached to any network!\n", INSTANCE(pState)));
1760 }
1761 else
1762 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN"));
1763
1764 rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail);
1765 if (RT_FAILURE(rc))
1766 return rc;
1767
1768 vnetReset(pState);
1769
1770 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
1771 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
1772#if defined(VBOX_WITH_STATISTICS)
1773 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
1774 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveStore, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive storing", "/Devices/VNet%d/Receive/Store", iInstance);
1775 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
1776 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
1777 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
1778 PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
1779#endif /* VBOX_WITH_STATISTICS */
1780
1781 return VINF_SUCCESS;
1782}
1783
1784/**
1785 * The device registration structure.
1786 */
1787const PDMDEVREG g_DeviceVirtioNet =
1788{
1789 /* Structure version. PDM_DEVREG_VERSION defines the current version. */
1790 PDM_DEVREG_VERSION,
1791 /* Device name. */
1792 "virtio-net",
1793 /* Name of guest context module (no path).
1794 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1795 "VBoxDDGC.gc",
1796 /* Name of ring-0 module (no path).
1797 * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
1798 "VBoxDDR0.r0",
1799 /* The description of the device. The UTF-8 string pointed to shall, like this structure,
1800 * remain unchanged from registration till VM destruction. */
1801 "Virtio Ethernet.\n",
1802
1803 /* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
1804#ifdef VNET_GC_SUPPORT
1805 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1806#else
1807 PDM_DEVREG_FLAGS_DEFAULT_BITS,
1808#endif
1809 /* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
1810 PDM_DEVREG_CLASS_NETWORK,
1811 /* Maximum number of instances (per VM). */
1812 8,
1813 /* Size of the instance data. */
1814 sizeof(VNETSTATE),
1815
1816 /* Construct instance - required. */
1817 vnetConstruct,
1818 /* Destruct instance - optional. */
1819 vnetDestruct,
1820 /* Relocation command - optional. */
1821 vnetRelocate,
1822 /* I/O Control interface - optional. */
1823 NULL,
1824 /* Power on notification - optional. */
1825 NULL,
1826 /* Reset notification - optional. */
1827 NULL,
1828 /* Suspend notification - optional. */
1829 vnetSuspend,
1830 /* Resume notification - optional. */
1831 NULL,
1832#ifdef VBOX_DYNAMIC_NET_ATTACH
1833 /* Attach command - optional. */
1834 vnetAttach,
1835 /* Detach notification - optional. */
1836 vnetDetach,
1837#else /* !VBOX_DYNAMIC_NET_ATTACH */
1838 /* Attach command - optional. */
1839 NULL,
1840 /* Detach notification - optional. */
1841 NULL,
1842#endif /* !VBOX_DYNAMIC_NET_ATTACH */
1843 /* Query a LUN base interface - optional. */
1844 NULL,
1845 /* Init complete notification - optional. */
1846 NULL,
1847 /* Power off notification - optional. */
1848 vnetPowerOff,
1849 /* pfnSoftReset */
1850 NULL,
1851 /* u32VersionEnd */
1852 PDM_DEVREG_VERSION
1853};
1854
1855#endif /* IN_RING3 */
1856#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette