VirtualBox

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

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

virtio-net: don't crash if the guest is trying to send but the adapter is not attached to a network

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

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