VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvVMNet.m@ 91438

Last change on this file since 91438 was 91438, checked in by vboxsync, 3 years ago

Devices: bugref:9932 Suspend/resume support, limit VMNET compilation to darwin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: DrvVMNet.m 91438 2021-09-28 17:01:52Z vboxsync $ */
2/** @file
3 * DrvVMNet - Network filter driver that uses MAC OS VMNET API.
4 */
5
6/*
7 * Copyright (C) 2021 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_VMNET
23#include <VBox/vmm/pdmdrv.h>
24#include <VBox/vmm/pdmnetifs.h>
25#include <VBox/vmm/pdmnetinline.h>
26#include <VBox/intnet.h>
27
28#include <VBox/log.h>
29#include <iprt/assert.h>
30#include <iprt/critsect.h>
31#include <iprt/file.h>
32#include <iprt/mem.h>
33#include <iprt/process.h>
34#include <iprt/string.h>
35#include <iprt/time.h>
36#include <iprt/uuid.h>
37#include <iprt/path.h>
38#include <VBox/param.h>
39
40#include "Pcap.h"
41#include "VBoxDD.h"
42
43#include <sys/uio.h>
44#import <vmnet/vmnet.h>
45
46#define VMNET_MAX_HOST_INTERFACE_NAME_LENGTH 16
47#define VMNET_MAX_IP_ADDRESS_STRING_LENGTH 48
48
49/* Force release logging for debug builds */
50#if 0
51# undef Log
52# undef LogFlow
53# undef Log2
54# undef Log3
55# define Log LogRel
56# define LogFlow LogRel
57# define Log2 LogRel
58# define Log3 LogRel
59#endif
60
61
62/*********************************************************************************************************************************
63* Structures and Typedefs *
64*********************************************************************************************************************************/
65/**
66 * VMNET driver states.
67 */
68 typedef enum VMNETSTATE
69{
70 /** The driver is suspended. */
71 VMNETSTATE_SUSPENDED = 1,
72 /** The driver is running. */
73 VMNETSTATE_RUNNING,
74 /** The usual 32-bit type blowup. */
75 VMNETSTATE_32BIT_HACK = 0x7fffffff
76} VMNETSTATE;
77
78/**
79 * VMNET driver instance data.
80 *
81 * @implements PDMINETWORKUP
82 * @implements PDMINETWORKCONFIG
83 */
84typedef struct DRVVMNET
85{
86 /** The network interface. */
87 PDMINETWORKUP INetworkUp;
88 /** The port we're attached to. */
89 PPDMINETWORKDOWN pIAboveNet;
90 /** The config port interface we're attached to. */
91 PPDMINETWORKCONFIG pIAboveConfig;
92 /** Pointer to the driver instance. */
93 PPDMDRVINS pDrvIns;
94 /** For when we're the leaf driver. */
95 RTCRITSECT XmitLock;
96 /** VMNET interface queue handle. */
97 dispatch_queue_t InterfaceQueue;
98 /** VMNET interface handle. */
99 interface_ref Interface;
100 /** The unique id for this network. */
101 uuid_t uuid;
102 /** The operation mode: bridged or host. */
103 uint32_t uMode;
104 /** The operational state: suspended or running. */
105 VMNETSTATE volatile enmState;
106 /** The host interface name for bridge mode. */
107 char szHostInterface[VMNET_MAX_HOST_INTERFACE_NAME_LENGTH];
108 /** The network mask for host mode. */
109 char szNetworkMask[VMNET_MAX_IP_ADDRESS_STRING_LENGTH];
110 /** The lower IP address of DHCP range for host mode. */
111 char szLowerIP[VMNET_MAX_IP_ADDRESS_STRING_LENGTH];
112 /** The upper IP address of DHCP range for host mode. */
113 char szUpperIP[VMNET_MAX_IP_ADDRESS_STRING_LENGTH];
114} DRVVMNET, *PDRVVMNET;
115
116
117
118/**
119 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
120 */
121static DECLCALLBACK(int) drvVMNetUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
122{
123 RT_NOREF(fOnWorkerThread);
124 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
125 LogFlow(("drvVMNetUp_BeginXmit:\n"));
126 int rc = RTCritSectTryEnter(&pThis->XmitLock);
127 if (RT_UNLIKELY(rc == VERR_SEM_BUSY))
128 rc = VERR_TRY_AGAIN;
129 return rc;
130}
131
132
133/**
134 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
135 */
136static DECLCALLBACK(int) drvVMNetUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
137 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
138{
139 RT_NOREF(pInterface);
140 //PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
141 LogFlow(("drvVMNetUp_AllocBuf: cb=%llu%s\n", cbMin, pGso == NULL ? "" : " GSO"));
142 /*
143 * Allocate a scatter / gather buffer descriptor that is immediately
144 * followed by the buffer space of its single segment. The GSO context
145 * comes after that again.
146 */
147 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16)
148 + RT_ALIGN_Z(cbMin, 16)
149 + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
150 if (!pSgBuf)
151 return VERR_NO_MEMORY;
152
153 /*
154 * Initialize the S/G buffer and return.
155 */
156 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
157 pSgBuf->cbUsed = 0;
158 pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16);
159 pSgBuf->pvAllocator = NULL;
160 if (!pGso)
161 pSgBuf->pvUser = NULL;
162 else
163 {
164 pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
165 *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso;
166 }
167 pSgBuf->cSegs = 1;
168 pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
169 pSgBuf->aSegs[0].pvSeg = pSgBuf + 1;
170
171 LogFlow(("drvVMNetUp_AllocBuf: successful %p\n", pSgBuf));
172 *ppSgBuf = pSgBuf;
173 return VINF_SUCCESS;
174}
175
176
177/**
178 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
179 */
180static DECLCALLBACK(int) drvVMNetUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
181{
182 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
183 LogFlow(("drvVMNetUp_FreeBuf: %p\n", pSgBuf));
184 Assert(RTCritSectIsOwner(&pThis->XmitLock));
185 if (pSgBuf)
186 {
187 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
188 pSgBuf->fFlags = 0;
189 RTMemFree(pSgBuf);
190 }
191 return VINF_SUCCESS;
192}
193
194
195static int drvVMNetReceive(PDRVVMNET pThis, const uint8_t *pbFrame, uint32_t cbFrame)
196{
197 if (pThis->enmState != VMNETSTATE_RUNNING)
198 {
199 Log(("drvVMNetReceive: Ignoring incoming packet (%d bytes) in suspended state\n", cbFrame));
200 return VINF_SUCCESS;
201 }
202
203 Log(("drvVMNetReceive: Incoming packet: %RTmac <= %RTmac (%d bytes)\n", pbFrame, pbFrame + 6, cbFrame));
204 Log2(("%.*Rhxd\n", cbFrame, pbFrame));
205 if (pThis->pIAboveNet && pThis->pIAboveNet->pfnReceive)
206 return pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pbFrame, cbFrame);
207 return VERR_TRY_AGAIN;
208}
209
210
211static int drvVMNetSend(PDRVVMNET pThis, const uint8_t *pbFrame, uint32_t cbFrame)
212{
213 if (pThis->enmState != VMNETSTATE_RUNNING)
214 {
215 Log(("drvVMNetReceive: Ignoring outgoing packet (%d bytes) in suspended state\n", cbFrame));
216 return VINF_SUCCESS;
217 }
218
219 Log(("drvVMNetSend: Outgoing packet (%d bytes)\n", cbFrame));
220 Log2(("%.*Rhxd\n", cbFrame, pbFrame));
221
222 struct iovec io;
223 struct vmpktdesc packets;
224 int packet_count = 1;
225
226 io.iov_base = (void*)pbFrame;
227 io.iov_len = cbFrame;
228 packets.vm_pkt_size = cbFrame;
229 packets.vm_pkt_iov = &io;
230 packets.vm_pkt_iovcnt = 1;
231 packets.vm_flags = 0;
232
233 vmnet_return_t rc = vmnet_write(pThis->Interface, &packets, &packet_count);
234 if (rc != VMNET_SUCCESS)
235 Log(("drvVMNetSend: Failed to send a packet with error code %d\n", rc));
236 return (rc == VMNET_SUCCESS) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
237}
238
239/**
240 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
241 */
242static DECLCALLBACK(int) drvVMNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
243{
244 RT_NOREF(fOnWorkerThread);
245 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
246
247 LogFlow(("drvVMNetUp_SendBuf: %p\n", pSgBuf));
248 Assert(RTCritSectIsOwner(&pThis->XmitLock));
249
250 int rc;
251 if (!pSgBuf->pvUser)
252 {
253 rc = drvVMNetSend(pThis, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed);
254 }
255 else
256 {
257 uint8_t abHdrScratch[256];
258 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
259 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
260 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
261 rc = VINF_SUCCESS;
262 for (uint32_t iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
263 {
264 uint32_t cbSegFrame;
265 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
266 iSeg, cSegs, &cbSegFrame);
267 rc = drvVMNetSend(pThis, pvSegFrame, cbSegFrame);
268 }
269 }
270
271 LogFlow(("drvVMNetUp_SendBuf: free %p\n", pSgBuf));
272 pSgBuf->fFlags = 0;
273 RTMemFree(pSgBuf);
274 return rc;
275}
276
277
278/**
279 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
280 */
281static DECLCALLBACK(void) drvVMNetUp_EndXmit(PPDMINETWORKUP pInterface)
282{
283 LogFlow(("drvVMNetUp_EndXmit:\n"));
284 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
285 RTCritSectLeave(&pThis->XmitLock);
286}
287
288
289/**
290 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
291 */
292static DECLCALLBACK(void) drvVMNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
293{
294 RT_NOREF(pInterface);
295 LogFlow(("drvVMNetUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
296 // PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
297}
298
299
300/**
301 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
302 */
303static DECLCALLBACK(void) drvVMNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
304{
305 RT_NOREF(pInterface);
306 LogFlow(("drvVMNetUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
307 // PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
308}
309
310
311/**
312 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
313 */
314static DECLCALLBACK(void *) drvVMNetQueryInterface(PPDMIBASE pInterface, const char *pszIID)
315{
316 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
317 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
318 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
319 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
320 //PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKVMNETCONFIG, &pThis->INetworkVmnetConfig);
321 return NULL;
322}
323
324
325static vmnet_return_t drvVMNetAttach(PDRVVMNET pThis)
326{
327 xpc_object_t interface_desc;
328 dispatch_semaphore_t operation_done;
329 __block vmnet_return_t vmnet_status = VMNET_SUCCESS;
330 __block size_t max_packet_size = 0;
331 //__block RTMAC MacAddress;
332
333 pThis->InterfaceQueue = dispatch_queue_create("VMNET", DISPATCH_QUEUE_SERIAL);
334 operation_done = dispatch_semaphore_create(0);
335 interface_desc = xpc_dictionary_create(NULL, NULL, 0);
336 xpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, pThis->uuid);
337 xpc_dictionary_set_bool(interface_desc, vmnet_allocate_mac_address_key, false);
338 xpc_dictionary_set_uint64(interface_desc, vmnet_operation_mode_key, pThis->uMode);
339 if (pThis->uMode == VMNET_BRIDGED_MODE)
340 {
341 LogFlow(("drvVMNetAttach: mode=briged hostInterface='%s'\n", pThis->szHostInterface));
342 xpc_dictionary_set_string(interface_desc, vmnet_shared_interface_name_key, pThis->szHostInterface);
343 }
344 else
345 {
346#ifdef LOG_ENABLED
347 char szUUID[40];
348 uuid_unparse(pThis->uuid, szUUID);
349 LogFlow(("drvVMNetAttach: mode=host id='%s' netmask='%s' start='%s' end='%s'\n", szUUID, pThis->szNetworkMask, pThis->szLowerIP, pThis->szUpperIP));
350#endif
351 xpc_dictionary_set_string(interface_desc, vmnet_subnet_mask_key, pThis->szNetworkMask);
352 xpc_dictionary_set_string(interface_desc, vmnet_start_address_key, pThis->szLowerIP);
353 xpc_dictionary_set_string(interface_desc, vmnet_end_address_key, pThis->szUpperIP);
354 }
355 pThis->Interface = vmnet_start_interface(interface_desc, pThis->InterfaceQueue,
356 ^(vmnet_return_t status, xpc_object_t interface_param)
357 {
358 // Log(("Callback reached!\n"));
359 vmnet_status = status;
360 if (status != VMNET_SUCCESS)
361 Log(("Failed to start VMNET interface. Status = %d.\n", status));
362 else if (interface_param == NULL)
363 Log(("No interface parameters provided!\n"));
364 else
365 {
366 Log(("VMNET interface has been started. Status = %d.\n", status));
367#if 0
368 const char *pcszMacAddress = xpc_dictionary_get_string(interface_param, vmnet_mac_address_key);
369 int rc = VERR_NOT_FOUND;
370 if (pcszMacAddress)
371 rc = RTNetStrToMacAddr(pcszMacAddress, &pThis->MacAddress);
372 if (RT_FAILURE(rc))
373 Log(("drvVMNetAttachBridged: Failed to convert '%s' to MAC address (%Rrc)\n", pcszMacAddress ? pcszMacAddress : "(null)", rc));
374#endif
375#ifdef LOG_ENABLED
376 max_packet_size = xpc_dictionary_get_uint64(interface_param, vmnet_max_packet_size_key);
377 // Log(("MAC address: %s\n", xpc_dictionary_get_string(interface_param, vmnet_mac_address_key)));
378 Log(("Max packet size: %zu\n", max_packet_size));
379 Log(("MTU size: %llu\n", xpc_dictionary_get_uint64(interface_param, vmnet_mtu_key)));
380 Log(("Avaliable keys:\n"));
381 xpc_dictionary_apply(interface_param, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
382 RT_NOREF(value);
383 Log(("%s\n", key));
384 return true;
385 });
386#endif /* LOG_ENABLED */
387 }
388 dispatch_semaphore_signal(operation_done);
389 });
390 dispatch_semaphore_wait(operation_done, DISPATCH_TIME_FOREVER);
391
392 if (vmnet_status != VMNET_SUCCESS)
393 return vmnet_status;
394
395 if (pThis->Interface == NULL)
396 {
397 Log(("Failed to start VMNET interface with unknown status!\n"));
398 return VMNET_FAILURE;
399 }
400
401 vmnet_interface_set_event_callback(pThis->Interface, VMNET_INTERFACE_PACKETS_AVAILABLE, pThis->InterfaceQueue, ^(interface_event_t event_mask, xpc_object_t _Nonnull event) {
402 if (event_mask & VMNET_INTERFACE_PACKETS_AVAILABLE)
403 {
404 int rc;
405 struct vmpktdesc packets;
406 struct iovec io;
407 int packet_count = (int)xpc_dictionary_get_uint64(event, vmnet_estimated_packets_available_key);
408 if (packet_count == 1)
409 Log3(("Incoming packets available: %d\n", packet_count));
410 else
411 Log(("WARNING! %d incoming packets available, but we will fetch just one.\n", packet_count));
412 packet_count = 1;
413 io.iov_base = malloc(max_packet_size);
414 io.iov_len = max_packet_size;
415 packets.vm_pkt_iov = &io;
416 packets.vm_pkt_iovcnt = 1;
417 packets.vm_pkt_size = max_packet_size;
418 packets.vm_flags = 0;
419 rc = vmnet_read(pThis->Interface, &packets, &packet_count);
420 if (rc != VMNET_SUCCESS)
421 Log(("Failed to read packets\n"));
422 else
423 {
424 Log3(("Successfully read %d packets:\n", packet_count));
425 for (int i = 0; i < packet_count; ++i)
426 {
427 rc = drvVMNetReceive(pThis, io.iov_base, packets.vm_pkt_size);
428 }
429 }
430 free(io.iov_base);
431 }
432 });
433
434 return vmnet_status;
435}
436
437static int drvVMNetDetach(PDRVVMNET pThis)
438{
439 if (pThis->Interface)
440 {
441 vmnet_stop_interface(pThis->Interface, pThis->InterfaceQueue, ^(vmnet_return_t status){
442 Log(("VMNET interface has been stopped. Status = %d.\n", status));
443 });
444 pThis->Interface = 0;
445 }
446 if (pThis->InterfaceQueue)
447 {
448 dispatch_release(pThis->InterfaceQueue);
449 pThis->InterfaceQueue = 0;
450 }
451
452 return 0;
453}
454
455
456/**
457 * @interface_method_impl{PDMDRVREG,pfnDestruct}
458 */
459static DECLCALLBACK(void) drvVMNetDestruct(PPDMDRVINS pDrvIns)
460{
461 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
462 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
463
464 LogFlow(("drvVMNetDestruct: %p\n", pDrvIns));
465 drvVMNetDetach(pThis);
466 if (RTCritSectIsInitialized(&pThis->XmitLock))
467 RTCritSectDelete(&pThis->XmitLock);
468}
469
470
471/**
472 * @interface_method_impl{Construct a NAT network transport driver instance,
473 * PDMDRVREG,pfnDestruct}
474 */
475static DECLCALLBACK(int) drvVMNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
476{
477 RT_NOREF(fFlags);
478 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
479 LogFlow(("drvVMNetConstruct: %p\n", pDrvIns));
480 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
481
482 /*
483 * Init the static parts.
484 */
485 pThis->pDrvIns = pDrvIns;
486 /* IBase */
487 pDrvIns->IBase.pfnQueryInterface = drvVMNetQueryInterface;
488 /* INetworkUp */
489 pThis->INetworkUp.pfnBeginXmit = drvVMNetUp_BeginXmit;
490 pThis->INetworkUp.pfnAllocBuf = drvVMNetUp_AllocBuf;
491 pThis->INetworkUp.pfnFreeBuf = drvVMNetUp_FreeBuf;
492 pThis->INetworkUp.pfnSendBuf = drvVMNetUp_SendBuf;
493 pThis->INetworkUp.pfnEndXmit = drvVMNetUp_EndXmit;
494 pThis->INetworkUp.pfnSetPromiscuousMode = drvVMNetUp_SetPromiscuousMode;
495 pThis->INetworkUp.pfnNotifyLinkChanged = drvVMNetUp_NotifyLinkChanged;
496
497 /* Initialize the state. */
498 pThis->enmState = VMNETSTATE_SUSPENDED;
499
500 /*
501 * Create the locks.
502 */
503 int rc = RTCritSectInit(&pThis->XmitLock);
504 AssertRCReturn(rc, rc);
505
506 /*
507 * Validate the config.
508 */
509 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
510 "Network"
511 "|Id"
512 "|Trunk"
513 "|TrunkType"
514 "|NetworkMask"
515 "|LowerIP"
516 "|UpperIP",
517 "");
518
519 /** @cfgm{GUID, string}
520 * The unique id of the VMNET interface.
521 */
522 char szUUID[40];
523 rc = CFGMR3QueryString(pCfg, "Id", szUUID, sizeof(szUUID));
524 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
525 uuid_generate_random(pThis->uuid);
526 else if (RT_FAILURE(rc))
527 return PDMDRV_SET_ERROR(pDrvIns, rc,
528 N_("Configuration error: Failed to get the \"Id\" value"));
529 else if (uuid_parse(szUUID, pThis->uuid))
530 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
531 N_("Configuration error: Invalid \"Id\" value: %s"), szUUID);
532
533 /** @cfgm{TrunkType, uint32_t}
534 * The trunk connection type see INTNETTRUNKTYPE.
535 */
536 uint32_t u32TrunkType;
537 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
538 if (RT_FAILURE(rc))
539 return PDMDRV_SET_ERROR(pDrvIns, rc,
540 N_("Configuration error: Failed to get the \"TrunkType\" value"));
541
542 switch ((INTNETTRUNKTYPE)u32TrunkType)
543 {
544 case kIntNetTrunkType_NetAdp:
545 /*
546 * Get the network mask.
547 */
548 rc = CFGMR3QueryString(pCfg, "NetworkMask", pThis->szNetworkMask, sizeof(pThis->szNetworkMask));
549#if 0
550 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
551 {
552 LogRel(("No network mask specified for \"%s\", 255.255.255.0 assumed.\n", pThis->szNetwork))
553 }
554#endif
555 if (RT_FAILURE(rc))
556 return PDMDRV_SET_ERROR(pDrvIns, rc,
557 N_("Configuration error: Failed to get the \"NetworkMask\" value"));
558
559 /*
560 * Get the network mask.
561 */
562 rc = CFGMR3QueryString(pCfg, "LowerIP", pThis->szLowerIP, sizeof(pThis->szLowerIP));
563 if (RT_FAILURE(rc))
564 return PDMDRV_SET_ERROR(pDrvIns, rc,
565 N_("Configuration error: Failed to get the \"LowerIP\" value"));
566
567 /*
568 * Get the network mask.
569 */
570 rc = CFGMR3QueryString(pCfg, "UpperIP", pThis->szUpperIP, sizeof(pThis->szUpperIP));
571 if (RT_FAILURE(rc))
572 return PDMDRV_SET_ERROR(pDrvIns, rc,
573 N_("Configuration error: Failed to get the \"UpperIP\" value"));
574
575 pThis->uMode = VMNET_HOST_MODE;
576 LogRel(("VMNet: host network with mask %s (%s to %s)\n", pThis->szNetworkMask, pThis->szLowerIP, pThis->szUpperIP));
577 break;
578
579 case kIntNetTrunkType_NetFlt:
580 /** @cfgm{Trunk, string}
581 * The name of the host interface to use for bridging.
582 */
583 rc = CFGMR3QueryString(pCfg, "Trunk", pThis->szHostInterface, sizeof(pThis->szHostInterface));
584 if (RT_FAILURE(rc))
585 return PDMDRV_SET_ERROR(pDrvIns, rc,
586 N_("Configuration error: Failed to get the \"Trunk\" value"));
587 pThis->uMode = VMNET_BRIDGED_MODE;
588 LogRel(("VMNet: bridge to %s\n", pThis->szHostInterface));
589 break;
590
591 default:
592 return PDMDRV_SET_ERROR(pDrvIns, rc,
593 N_("Configuration error: Unsupported \"TrunkType\" value"));
594 }
595
596 /*
597 * Check that no-one is attached to us.
598 */
599 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
600 ("Configuration error: Not possible to attach anything to this driver!\n"),
601 VERR_PDM_DRVINS_NO_ATTACH);
602
603 /*
604 * Query the network port interface.
605 */
606 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
607 if (!pThis->pIAboveNet)
608 {
609 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
610 return VERR_PDM_MISSING_INTERFACE_ABOVE;
611 }
612
613 /*
614 * Query the network config interface.
615 */
616 pThis->pIAboveConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
617 if (!pThis->pIAboveConfig)
618 {
619 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
620 return VERR_PDM_MISSING_INTERFACE_ABOVE;
621 }
622
623 vmnet_return_t status = drvVMNetAttach(pThis);
624 if (status != VMNET_SUCCESS)
625 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
626 N_("Error: vmnet_start_interface returned %d"), status);
627
628 return VINF_SUCCESS;
629}
630
631
632/**
633 * Power On notification.
634 *
635 * @param pDrvIns The driver instance.
636 */
637static DECLCALLBACK(void) drvVMNetPowerOn(PPDMDRVINS pDrvIns)
638{
639 LogFlow(("drvVMNetPowerOn\n"));
640 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
641 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
642}
643
644
645/**
646 * Suspend notification.
647 *
648 * @param pDrvIns The driver instance.
649 */
650static DECLCALLBACK(void) drvVMNetSuspend(PPDMDRVINS pDrvIns)
651{
652 LogFlow(("drvVMNetSuspend\n"));
653 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
654 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_SUSPENDED);
655}
656
657
658/**
659 * Resume notification.
660 *
661 * @param pDrvIns The driver instance.
662 */
663static DECLCALLBACK(void) drvVMNetResume(PPDMDRVINS pDrvIns)
664{
665 LogFlow(("drvVMNetResume\n"));
666 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
667 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
668}
669
670
671
672/**
673 * Network sniffer filter driver registration record.
674 */
675const PDMDRVREG g_DrvVMNet =
676{
677 /* u32Version */
678 PDM_DRVREG_VERSION,
679 /* szName */
680 "VMNet",
681 /* szRCMod */
682 "",
683 /* szR0Mod */
684 "",
685 /* pszDescription */
686 "VMNET Filter Driver",
687 /* fFlags */
688 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
689 /* fClass. */
690 PDM_DRVREG_CLASS_NETWORK,
691 /* cMaxInstances */
692 UINT32_MAX,
693 /* cbInstance */
694 sizeof(DRVVMNET),
695 /* pfnConstruct */
696 drvVMNetConstruct,
697 /* pfnDestruct */
698 drvVMNetDestruct,
699 /* pfnRelocate */
700 NULL,
701 /* pfnIOCtl */
702 NULL,
703 /* pfnPowerOn */
704 drvVMNetPowerOn,
705 /* pfnReset */
706 NULL,
707 /* pfnSuspend */
708 drvVMNetSuspend,
709 /* pfnResume */
710 drvVMNetResume,
711 /* pfnAttach */
712 NULL,
713 /* pfnDetach */
714 NULL,
715 /* pfnPowerOff */
716 NULL,
717 /* pfnSoftReset */
718 NULL,
719 /* u32EndVersion */
720 PDM_DRVREG_VERSION
721};
722
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