VirtualBox

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

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

VMNet: bugref:9932 Fixed uninitialized max_packet_size, really enabled VBOX_WITH_VMNET, minor log improvements

  • 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 91466 2021-09-29 16:57:26Z 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 RT_NOREF(pThis);
186 if (pSgBuf)
187 {
188 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
189 pSgBuf->fFlags = 0;
190 RTMemFree(pSgBuf);
191 }
192 return VINF_SUCCESS;
193}
194
195
196static int drvVMNetReceive(PDRVVMNET pThis, const uint8_t *pbFrame, uint32_t cbFrame)
197{
198 if (pThis->enmState != VMNETSTATE_RUNNING)
199 {
200 Log(("drvVMNetReceive: Ignoring incoming packet (%d bytes) in suspended state\n", cbFrame));
201 return VINF_SUCCESS;
202 }
203
204 Log(("drvVMNetReceive: Incoming packet: %RTmac <= %RTmac (%d bytes)\n", pbFrame, pbFrame + 6, cbFrame));
205 Log2(("%.*Rhxd\n", cbFrame, pbFrame));
206 if (pThis->pIAboveNet && pThis->pIAboveNet->pfnReceive)
207 return pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, pbFrame, cbFrame);
208 return VERR_TRY_AGAIN;
209}
210
211
212static int drvVMNetSend(PDRVVMNET pThis, const uint8_t *pbFrame, uint32_t cbFrame)
213{
214 if (pThis->enmState != VMNETSTATE_RUNNING)
215 {
216 Log(("drvVMNetReceive: Ignoring outgoing packet (%d bytes) in suspended state\n", cbFrame));
217 return VINF_SUCCESS;
218 }
219
220 Log(("drvVMNetSend: Outgoing packet (%d bytes)\n", cbFrame));
221 Log2(("%.*Rhxd\n", cbFrame, pbFrame));
222
223 struct iovec io;
224 struct vmpktdesc packets;
225 int packet_count = 1;
226
227 io.iov_base = (void*)pbFrame;
228 io.iov_len = cbFrame;
229 packets.vm_pkt_size = cbFrame;
230 packets.vm_pkt_iov = &io;
231 packets.vm_pkt_iovcnt = 1;
232 packets.vm_flags = 0;
233
234 vmnet_return_t rc = vmnet_write(pThis->Interface, &packets, &packet_count);
235 if (rc != VMNET_SUCCESS)
236 Log(("drvVMNetSend: Failed to send a packet with error code %d\n", rc));
237 return (rc == VMNET_SUCCESS) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
238}
239
240/**
241 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
242 */
243static DECLCALLBACK(int) drvVMNetUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
244{
245 RT_NOREF(fOnWorkerThread);
246 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
247
248 LogFlow(("drvVMNetUp_SendBuf: %p\n", pSgBuf));
249 Assert(RTCritSectIsOwner(&pThis->XmitLock));
250
251 int rc;
252 if (!pSgBuf->pvUser)
253 {
254 rc = drvVMNetSend(pThis, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed);
255 }
256 else
257 {
258 uint8_t abHdrScratch[256];
259 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
260 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
261 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
262 rc = VINF_SUCCESS;
263 for (uint32_t iSeg = 0; iSeg < cSegs && RT_SUCCESS(rc); iSeg++)
264 {
265 uint32_t cbSegFrame;
266 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
267 iSeg, cSegs, &cbSegFrame);
268 rc = drvVMNetSend(pThis, pvSegFrame, cbSegFrame);
269 }
270 }
271
272 LogFlow(("drvVMNetUp_SendBuf: free %p\n", pSgBuf));
273 pSgBuf->fFlags = 0;
274 RTMemFree(pSgBuf);
275 return rc;
276}
277
278
279/**
280 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
281 */
282static DECLCALLBACK(void) drvVMNetUp_EndXmit(PPDMINETWORKUP pInterface)
283{
284 LogFlow(("drvVMNetUp_EndXmit:\n"));
285 PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
286 RTCritSectLeave(&pThis->XmitLock);
287}
288
289
290/**
291 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
292 */
293static DECLCALLBACK(void) drvVMNetUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
294{
295 RT_NOREF(pInterface, fPromiscuous);
296 LogFlow(("drvVMNetUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
297 // PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
298}
299
300
301/**
302 * @interface_method_impl{PDMINETWORKUP,pfnNotifyLinkChanged}
303 */
304static DECLCALLBACK(void) drvVMNetUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
305{
306 RT_NOREF(pInterface, enmLinkState);
307 LogFlow(("drvVMNetUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
308 // PDRVVMNET pThis = RT_FROM_MEMBER(pInterface, DRVVMNET, INetworkUp);
309}
310
311
312/**
313 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
314 */
315static DECLCALLBACK(void *) drvVMNetQueryInterface(PPDMIBASE pInterface, const char *pszIID)
316{
317 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
318 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
319 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
320 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
321 //PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKVMNETCONFIG, &pThis->INetworkVmnetConfig);
322 return NULL;
323}
324
325
326static vmnet_return_t drvVMNetAttach(PDRVVMNET pThis)
327{
328 xpc_object_t interface_desc;
329 dispatch_semaphore_t operation_done;
330 __block vmnet_return_t vmnet_status = VMNET_SUCCESS;
331 __block size_t max_packet_size = 0;
332 //__block RTMAC MacAddress;
333
334 pThis->InterfaceQueue = dispatch_queue_create("VMNET", DISPATCH_QUEUE_SERIAL);
335 operation_done = dispatch_semaphore_create(0);
336 interface_desc = xpc_dictionary_create(NULL, NULL, 0);
337 xpc_dictionary_set_uuid(interface_desc, vmnet_interface_id_key, pThis->uuid);
338 xpc_dictionary_set_bool(interface_desc, vmnet_allocate_mac_address_key, false);
339 xpc_dictionary_set_uint64(interface_desc, vmnet_operation_mode_key, pThis->uMode);
340 if (pThis->uMode == VMNET_BRIDGED_MODE)
341 {
342 LogFlow(("drvVMNetAttach: mode=briged hostInterface='%s'\n", pThis->szHostInterface));
343 xpc_dictionary_set_string(interface_desc, vmnet_shared_interface_name_key, pThis->szHostInterface);
344 }
345 else
346 {
347#ifdef LOG_ENABLED
348 char szUUID[40];
349 uuid_unparse(pThis->uuid, szUUID);
350 LogFlow(("drvVMNetAttach: mode=host id='%s' netmask='%s' start='%s' end='%s'\n", szUUID, pThis->szNetworkMask, pThis->szLowerIP, pThis->szUpperIP));
351#endif
352 xpc_dictionary_set_string(interface_desc, vmnet_subnet_mask_key, pThis->szNetworkMask);
353 xpc_dictionary_set_string(interface_desc, vmnet_start_address_key, pThis->szLowerIP);
354 xpc_dictionary_set_string(interface_desc, vmnet_end_address_key, pThis->szUpperIP);
355 }
356 pThis->Interface = vmnet_start_interface(interface_desc, pThis->InterfaceQueue,
357 ^(vmnet_return_t status, xpc_object_t interface_param)
358 {
359 // Log(("Callback reached!\n"));
360 vmnet_status = status;
361 if (status != VMNET_SUCCESS)
362 Log(("Failed to start VMNET interface. Status = %d.\n", status));
363 else if (interface_param == NULL)
364 Log(("No interface parameters provided!\n"));
365 else
366 {
367 Log(("VMNET interface has been started. Status = %d.\n", status));
368#if 0
369 const char *pcszMacAddress = xpc_dictionary_get_string(interface_param, vmnet_mac_address_key);
370 int rc = VERR_NOT_FOUND;
371 if (pcszMacAddress)
372 rc = RTNetStrToMacAddr(pcszMacAddress, &pThis->MacAddress);
373 if (RT_FAILURE(rc))
374 Log(("drvVMNetAttachBridged: Failed to convert '%s' to MAC address (%Rrc)\n", pcszMacAddress ? pcszMacAddress : "(null)", rc));
375#endif
376 max_packet_size = xpc_dictionary_get_uint64(interface_param, vmnet_max_packet_size_key);
377#ifdef LOG_ENABLED
378 // Log(("MAC address: %s\n", xpc_dictionary_get_string(interface_param, vmnet_mac_address_key)));
379 Log(("Max packet size: %zu\n", max_packet_size));
380 Log(("MTU size: %llu\n", xpc_dictionary_get_uint64(interface_param, vmnet_mtu_key)));
381 Log(("Avaliable keys:\n"));
382 xpc_dictionary_apply(interface_param, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
383 RT_NOREF(value);
384 Log(("%s\n", key));
385 return true;
386 });
387#endif /* LOG_ENABLED */
388 }
389 dispatch_semaphore_signal(operation_done);
390 });
391 dispatch_semaphore_wait(operation_done, DISPATCH_TIME_FOREVER);
392
393 if (vmnet_status != VMNET_SUCCESS)
394 return vmnet_status;
395
396 if (pThis->Interface == NULL)
397 {
398 Log(("Failed to start VMNET interface with unknown status!\n"));
399 return VMNET_FAILURE;
400 }
401
402 LogRel(("VMNET: Max packet size is %zu\n", max_packet_size));
403
404 vmnet_interface_set_event_callback(pThis->Interface, VMNET_INTERFACE_PACKETS_AVAILABLE, pThis->InterfaceQueue, ^(interface_event_t event_mask, xpc_object_t _Nonnull event) {
405 if (event_mask & VMNET_INTERFACE_PACKETS_AVAILABLE)
406 {
407 int rc;
408 struct vmpktdesc packets;
409 struct iovec io;
410 int packet_count = (int)xpc_dictionary_get_uint64(event, vmnet_estimated_packets_available_key);
411 if (packet_count == 1)
412 Log3(("Incoming packets available: %d\n", packet_count));
413 else
414 Log(("WARNING! %d incoming packets available, but we will fetch just one.\n", packet_count));
415 packet_count = 1;
416 io.iov_base = malloc(max_packet_size);
417 io.iov_len = max_packet_size;
418 packets.vm_pkt_iov = &io;
419 packets.vm_pkt_iovcnt = 1;
420 packets.vm_pkt_size = max_packet_size;
421 packets.vm_flags = 0;
422 rc = vmnet_read(pThis->Interface, &packets, &packet_count);
423 if (rc != VMNET_SUCCESS)
424 Log(("Failed to read packets, rc=%d\n", rc));
425 else
426 {
427 Log3(("Successfully read %d packets:\n", packet_count));
428 for (int i = 0; i < packet_count; ++i)
429 {
430 rc = drvVMNetReceive(pThis, io.iov_base, packets.vm_pkt_size);
431 }
432 }
433 free(io.iov_base);
434 }
435 });
436
437 return vmnet_status;
438}
439
440static int drvVMNetDetach(PDRVVMNET pThis)
441{
442 if (pThis->Interface)
443 {
444 vmnet_stop_interface(pThis->Interface, pThis->InterfaceQueue, ^(vmnet_return_t status){
445 RT_NOREF(status);
446 Log(("VMNET interface has been stopped. Status = %d.\n", status));
447 });
448 pThis->Interface = 0;
449 }
450 if (pThis->InterfaceQueue)
451 {
452 dispatch_release(pThis->InterfaceQueue);
453 pThis->InterfaceQueue = 0;
454 }
455
456 return 0;
457}
458
459
460/**
461 * @interface_method_impl{PDMDRVREG,pfnDestruct}
462 */
463static DECLCALLBACK(void) drvVMNetDestruct(PPDMDRVINS pDrvIns)
464{
465 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
466 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
467
468 LogFlow(("drvVMNetDestruct: %p\n", pDrvIns));
469 drvVMNetDetach(pThis);
470 if (RTCritSectIsInitialized(&pThis->XmitLock))
471 RTCritSectDelete(&pThis->XmitLock);
472}
473
474
475/**
476 * @interface_method_impl{Construct a NAT network transport driver instance,
477 * PDMDRVREG,pfnDestruct}
478 */
479static DECLCALLBACK(int) drvVMNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
480{
481 RT_NOREF(fFlags);
482 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
483 LogFlow(("drvVMNetConstruct: %p\n", pDrvIns));
484 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
485
486 /*
487 * Init the static parts.
488 */
489 pThis->pDrvIns = pDrvIns;
490 /* IBase */
491 pDrvIns->IBase.pfnQueryInterface = drvVMNetQueryInterface;
492 /* INetworkUp */
493 pThis->INetworkUp.pfnBeginXmit = drvVMNetUp_BeginXmit;
494 pThis->INetworkUp.pfnAllocBuf = drvVMNetUp_AllocBuf;
495 pThis->INetworkUp.pfnFreeBuf = drvVMNetUp_FreeBuf;
496 pThis->INetworkUp.pfnSendBuf = drvVMNetUp_SendBuf;
497 pThis->INetworkUp.pfnEndXmit = drvVMNetUp_EndXmit;
498 pThis->INetworkUp.pfnSetPromiscuousMode = drvVMNetUp_SetPromiscuousMode;
499 pThis->INetworkUp.pfnNotifyLinkChanged = drvVMNetUp_NotifyLinkChanged;
500
501 /* Initialize the state. */
502 pThis->enmState = VMNETSTATE_SUSPENDED;
503
504 /*
505 * Create the locks.
506 */
507 int rc = RTCritSectInit(&pThis->XmitLock);
508 AssertRCReturn(rc, rc);
509
510 /*
511 * Validate the config.
512 */
513 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
514 "Network"
515 "|Id"
516 "|Trunk"
517 "|TrunkType"
518 "|NetworkMask"
519 "|LowerIP"
520 "|UpperIP",
521 "");
522
523 /** @cfgm{GUID, string}
524 * The unique id of the VMNET interface.
525 */
526 char szUUID[40];
527 rc = CFGMR3QueryString(pCfg, "Id", szUUID, sizeof(szUUID));
528 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
529 uuid_generate_random(pThis->uuid);
530 else if (RT_FAILURE(rc))
531 return PDMDRV_SET_ERROR(pDrvIns, rc,
532 N_("Configuration error: Failed to get the \"Id\" value"));
533 else if (uuid_parse(szUUID, pThis->uuid))
534 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
535 N_("Configuration error: Invalid \"Id\" value: %s"), szUUID);
536
537 /** @cfgm{TrunkType, uint32_t}
538 * The trunk connection type see INTNETTRUNKTYPE.
539 */
540 uint32_t u32TrunkType;
541 rc = CFGMR3QueryU32(pCfg, "TrunkType", &u32TrunkType);
542 if (RT_FAILURE(rc))
543 return PDMDRV_SET_ERROR(pDrvIns, rc,
544 N_("Configuration error: Failed to get the \"TrunkType\" value"));
545
546 switch ((INTNETTRUNKTYPE)u32TrunkType)
547 {
548 case kIntNetTrunkType_NetAdp:
549 /*
550 * Get the network mask.
551 */
552 rc = CFGMR3QueryString(pCfg, "NetworkMask", pThis->szNetworkMask, sizeof(pThis->szNetworkMask));
553 if (RT_FAILURE(rc))
554 return PDMDRV_SET_ERROR(pDrvIns, rc,
555 N_("Configuration error: Failed to get the \"NetworkMask\" value"));
556
557 /*
558 * Get the network mask.
559 */
560 rc = CFGMR3QueryString(pCfg, "LowerIP", pThis->szLowerIP, sizeof(pThis->szLowerIP));
561 if (RT_FAILURE(rc))
562 return PDMDRV_SET_ERROR(pDrvIns, rc,
563 N_("Configuration error: Failed to get the \"LowerIP\" value"));
564
565 /*
566 * Get the network mask.
567 */
568 rc = CFGMR3QueryString(pCfg, "UpperIP", pThis->szUpperIP, sizeof(pThis->szUpperIP));
569 if (RT_FAILURE(rc))
570 return PDMDRV_SET_ERROR(pDrvIns, rc,
571 N_("Configuration error: Failed to get the \"UpperIP\" value"));
572
573 pThis->uMode = VMNET_HOST_MODE;
574 LogRel(("VMNet: Host network with mask %s (%s to %s)\n", pThis->szNetworkMask, pThis->szLowerIP, pThis->szUpperIP));
575 break;
576
577 case kIntNetTrunkType_NetFlt:
578 /** @cfgm{Trunk, string}
579 * The name of the host interface to use for bridging.
580 */
581 rc = CFGMR3QueryString(pCfg, "Trunk", pThis->szHostInterface, sizeof(pThis->szHostInterface));
582 if (RT_FAILURE(rc))
583 return PDMDRV_SET_ERROR(pDrvIns, rc,
584 N_("Configuration error: Failed to get the \"Trunk\" value"));
585 pThis->uMode = VMNET_BRIDGED_MODE;
586 LogRel(("VMNet: Bridge to %s\n", pThis->szHostInterface));
587 break;
588
589 default:
590 return PDMDRV_SET_ERROR(pDrvIns, rc,
591 N_("Configuration error: Unsupported \"TrunkType\" value"));
592 }
593
594 /*
595 * Check that no-one is attached to us.
596 */
597 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
598 ("Configuration error: Not possible to attach anything to this driver!\n"),
599 VERR_PDM_DRVINS_NO_ATTACH);
600
601 /*
602 * Query the network port interface.
603 */
604 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
605 if (!pThis->pIAboveNet)
606 {
607 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
608 return VERR_PDM_MISSING_INTERFACE_ABOVE;
609 }
610
611 /*
612 * Query the network config interface.
613 */
614 pThis->pIAboveConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
615 if (!pThis->pIAboveConfig)
616 {
617 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
618 return VERR_PDM_MISSING_INTERFACE_ABOVE;
619 }
620
621 vmnet_return_t status = drvVMNetAttach(pThis);
622 if (status != VMNET_SUCCESS)
623 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
624 N_("Error: vmnet_start_interface returned %d"), status);
625
626 return VINF_SUCCESS;
627}
628
629
630/**
631 * Power On notification.
632 *
633 * @param pDrvIns The driver instance.
634 */
635static DECLCALLBACK(void) drvVMNetPowerOn(PPDMDRVINS pDrvIns)
636{
637 LogFlow(("drvVMNetPowerOn\n"));
638 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
639 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
640}
641
642
643/**
644 * Suspend notification.
645 *
646 * @param pDrvIns The driver instance.
647 */
648static DECLCALLBACK(void) drvVMNetSuspend(PPDMDRVINS pDrvIns)
649{
650 LogFlow(("drvVMNetSuspend\n"));
651 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
652 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_SUSPENDED);
653}
654
655
656/**
657 * Resume notification.
658 *
659 * @param pDrvIns The driver instance.
660 */
661static DECLCALLBACK(void) drvVMNetResume(PPDMDRVINS pDrvIns)
662{
663 LogFlow(("drvVMNetResume\n"));
664 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
665 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
666}
667
668
669
670/**
671 * Network sniffer filter driver registration record.
672 */
673const PDMDRVREG g_DrvVMNet =
674{
675 /* u32Version */
676 PDM_DRVREG_VERSION,
677 /* szName */
678 "VMNet",
679 /* szRCMod */
680 "",
681 /* szR0Mod */
682 "",
683 /* pszDescription */
684 "VMNET Filter Driver",
685 /* fFlags */
686 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
687 /* fClass. */
688 PDM_DRVREG_CLASS_NETWORK,
689 /* cMaxInstances */
690 UINT32_MAX,
691 /* cbInstance */
692 sizeof(DRVVMNET),
693 /* pfnConstruct */
694 drvVMNetConstruct,
695 /* pfnDestruct */
696 drvVMNetDestruct,
697 /* pfnRelocate */
698 NULL,
699 /* pfnIOCtl */
700 NULL,
701 /* pfnPowerOn */
702 drvVMNetPowerOn,
703 /* pfnReset */
704 NULL,
705 /* pfnSuspend */
706 drvVMNetSuspend,
707 /* pfnResume */
708 drvVMNetResume,
709 /* pfnAttach */
710 NULL,
711 /* pfnDetach */
712 NULL,
713 /* pfnPowerOff */
714 NULL,
715 /* pfnSoftReset */
716 NULL,
717 /* u32EndVersion */
718 PDM_DRVREG_VERSION
719};
720
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