VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use