VirtualBox

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

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

#3987: Virtio: Split DevVirtioNet.cpp into three files.

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