VirtualBox

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

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

VMNet: bugref:9932 Explicit handling of interface start timeout

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.4 KB
Line 
1/* $Id: DrvVMNet.m 92140 2021-10-29 09:30:22Z 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_FAILURE;
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 if (max_packet_size == 0)
378 {
379 max_packet_size = 1518;
380 LogRel(("VMNet: Failed to retrieve max packet size, assuming %d bytes.\n", max_packet_size));
381 LogRel(("VMNet: Avaliable interface parameter keys:\n"));
382 xpc_dictionary_apply(interface_param, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
383 RT_NOREF(value);
384 LogRel(("VMNet: %s\n", key));
385 return true;
386 });
387 }
388#ifdef LOG_ENABLED
389 // Log(("MAC address: %s\n", xpc_dictionary_get_string(interface_param, vmnet_mac_address_key)));
390 Log(("Max packet size: %zu\n", max_packet_size));
391 Log(("MTU size: %llu\n", xpc_dictionary_get_uint64(interface_param, vmnet_mtu_key)));
392 Log(("Avaliable keys:\n"));
393 xpc_dictionary_apply(interface_param, ^bool(const char * _Nonnull key, xpc_object_t _Nonnull value) {
394 RT_NOREF(value);
395 Log(("%s\n", key));
396 return true;
397 });
398#endif /* LOG_ENABLED */
399 }
400 dispatch_semaphore_signal(operation_done);
401 });
402 if (dispatch_semaphore_wait(operation_done, dispatch_time(DISPATCH_TIME_NOW, RT_NS_10SEC)))
403 {
404 LogRel(("VMNet: Failed to start VMNET interface due to time out!\n"));
405 return VMNET_FAILURE;
406 }
407
408 if (vmnet_status != VMNET_SUCCESS)
409 return vmnet_status;
410
411 if (pThis->Interface == NULL)
412 {
413 Log(("Failed to start VMNET interface with unknown status!\n"));
414 return VMNET_FAILURE;
415 }
416
417 LogRel(("VMNet: Max packet size is %zu\n", max_packet_size));
418
419 vmnet_interface_set_event_callback(pThis->Interface, VMNET_INTERFACE_PACKETS_AVAILABLE, pThis->InterfaceQueue, ^(interface_event_t event_mask, xpc_object_t _Nonnull event) {
420 if (event_mask & VMNET_INTERFACE_PACKETS_AVAILABLE)
421 {
422 int rc;
423 struct vmpktdesc packets;
424 struct iovec io;
425 int packet_count = (int)xpc_dictionary_get_uint64(event, vmnet_estimated_packets_available_key);
426 if (packet_count == 1)
427 Log3(("Incoming packets available: %d\n", packet_count));
428 else
429 Log(("WARNING! %d incoming packets available, but we will fetch just one.\n", packet_count));
430 packet_count = 1;
431 io.iov_base = malloc(max_packet_size);
432 io.iov_len = max_packet_size;
433 packets.vm_pkt_iov = &io;
434 packets.vm_pkt_iovcnt = 1;
435 packets.vm_pkt_size = max_packet_size;
436 packets.vm_flags = 0;
437 rc = vmnet_read(pThis->Interface, &packets, &packet_count);
438 if (rc != VMNET_SUCCESS)
439 Log(("Failed to read packets with error code %d\n", rc));
440 else
441 {
442 Log3(("Successfully read %d packets:\n", packet_count));
443 for (int i = 0; i < packet_count; ++i)
444 {
445 rc = drvVMNetReceive(pThis, io.iov_base, packets.vm_pkt_size);
446 }
447 }
448 free(io.iov_base);
449 }
450 });
451
452 return vmnet_status;
453}
454
455static int drvVMNetDetach(PDRVVMNET pThis)
456{
457 if (pThis->Interface)
458 {
459 vmnet_stop_interface(pThis->Interface, pThis->InterfaceQueue, ^(vmnet_return_t status){
460 RT_NOREF(status);
461 Log(("VMNET interface has been stopped. Status = %d.\n", status));
462 });
463 pThis->Interface = 0;
464 }
465 if (pThis->InterfaceQueue)
466 {
467 dispatch_release(pThis->InterfaceQueue);
468 pThis->InterfaceQueue = 0;
469 }
470
471 return 0;
472}
473
474
475/**
476 * @interface_method_impl{PDMDRVREG,pfnDestruct}
477 */
478static DECLCALLBACK(void) drvVMNetDestruct(PPDMDRVINS pDrvIns)
479{
480 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
481 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
482
483 LogFlow(("drvVMNetDestruct: %p\n", pDrvIns));
484 drvVMNetDetach(pThis);
485 if (RTCritSectIsInitialized(&pThis->XmitLock))
486 RTCritSectDelete(&pThis->XmitLock);
487}
488
489
490/**
491 * @interface_method_impl{Construct a NAT network transport driver instance,
492 * PDMDRVREG,pfnDestruct}
493 */
494static DECLCALLBACK(int) drvVMNetConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
495{
496 RT_NOREF(fFlags);
497 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
498 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
499 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
500
501 LogFlow(("drvVMNetConstruct: %p\n", pDrvIns));
502
503 /*
504 * Init the static parts.
505 */
506 pThis->pDrvIns = pDrvIns;
507 /* IBase */
508 pDrvIns->IBase.pfnQueryInterface = drvVMNetQueryInterface;
509 /* INetworkUp */
510 pThis->INetworkUp.pfnBeginXmit = drvVMNetUp_BeginXmit;
511 pThis->INetworkUp.pfnAllocBuf = drvVMNetUp_AllocBuf;
512 pThis->INetworkUp.pfnFreeBuf = drvVMNetUp_FreeBuf;
513 pThis->INetworkUp.pfnSendBuf = drvVMNetUp_SendBuf;
514 pThis->INetworkUp.pfnEndXmit = drvVMNetUp_EndXmit;
515 pThis->INetworkUp.pfnSetPromiscuousMode = drvVMNetUp_SetPromiscuousMode;
516 pThis->INetworkUp.pfnNotifyLinkChanged = drvVMNetUp_NotifyLinkChanged;
517
518 /* Initialize the state. */
519 pThis->enmState = VMNETSTATE_SUSPENDED;
520
521 /*
522 * Create the locks.
523 */
524 int rc = RTCritSectInit(&pThis->XmitLock);
525 AssertRCReturn(rc, rc);
526
527 /*
528 * Validate the config.
529 */
530 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
531 "Network"
532 "|Id"
533 "|Trunk"
534 "|TrunkType"
535 "|NetworkMask"
536 "|LowerIP"
537 "|UpperIP",
538 "");
539
540 /** @cfgm{GUID, string}
541 * The unique id of the VMNET interface.
542 */
543 char szUUID[40];
544 rc = pHlp->pfnCFGMQueryString(pCfg, "Id", szUUID, sizeof(szUUID));
545 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
546 uuid_generate_random(pThis->uuid);
547 else if (RT_FAILURE(rc))
548 return PDMDRV_SET_ERROR(pDrvIns, rc,
549 N_("Configuration error: Failed to get the \"Id\" value"));
550 else if (uuid_parse(szUUID, pThis->uuid))
551 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
552 N_("Configuration error: Invalid \"Id\" value: %s"), szUUID);
553
554 /** @cfgm{TrunkType, uint32_t}
555 * The trunk connection type see INTNETTRUNKTYPE.
556 */
557 uint32_t u32TrunkType;
558 rc = pHlp->pfnCFGMQueryU32(pCfg, "TrunkType", &u32TrunkType);
559 if (RT_FAILURE(rc))
560 return PDMDRV_SET_ERROR(pDrvIns, rc,
561 N_("Configuration error: Failed to get the \"TrunkType\" value"));
562
563 switch ((INTNETTRUNKTYPE)u32TrunkType)
564 {
565 case kIntNetTrunkType_NetAdp:
566 /*
567 * Get the network mask.
568 */
569 rc = pHlp->pfnCFGMQueryString(pCfg, "NetworkMask", pThis->szNetworkMask, sizeof(pThis->szNetworkMask));
570 if (RT_FAILURE(rc))
571 return PDMDRV_SET_ERROR(pDrvIns, rc,
572 N_("Configuration error: Failed to get the \"NetworkMask\" value"));
573
574 /*
575 * Get the network mask.
576 */
577 rc = pHlp->pfnCFGMQueryString(pCfg, "LowerIP", pThis->szLowerIP, sizeof(pThis->szLowerIP));
578 if (RT_FAILURE(rc))
579 return PDMDRV_SET_ERROR(pDrvIns, rc,
580 N_("Configuration error: Failed to get the \"LowerIP\" value"));
581
582 /*
583 * Get the network mask.
584 */
585 rc = pHlp->pfnCFGMQueryString(pCfg, "UpperIP", pThis->szUpperIP, sizeof(pThis->szUpperIP));
586 if (RT_FAILURE(rc))
587 return PDMDRV_SET_ERROR(pDrvIns, rc,
588 N_("Configuration error: Failed to get the \"UpperIP\" value"));
589
590 pThis->uMode = VMNET_HOST_MODE;
591 LogRel(("VMNet: Host network with mask %s (%s to %s)\n", pThis->szNetworkMask, pThis->szLowerIP, pThis->szUpperIP));
592 break;
593
594 case kIntNetTrunkType_NetFlt:
595 /** @cfgm{Trunk, string}
596 * The name of the host interface to use for bridging.
597 */
598 rc = pHlp->pfnCFGMQueryString(pCfg, "Trunk", pThis->szHostInterface, sizeof(pThis->szHostInterface));
599 if (RT_FAILURE(rc))
600 return PDMDRV_SET_ERROR(pDrvIns, rc,
601 N_("Configuration error: Failed to get the \"Trunk\" value"));
602 pThis->uMode = VMNET_BRIDGED_MODE;
603 LogRel(("VMNet: Bridge to %s\n", pThis->szHostInterface));
604 break;
605
606 default:
607 return PDMDRV_SET_ERROR(pDrvIns, rc,
608 N_("Configuration error: Unsupported \"TrunkType\" value"));
609 }
610
611 /*
612 * Check that no-one is attached to us.
613 */
614 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
615 ("Configuration error: Not possible to attach anything to this driver!\n"),
616 VERR_PDM_DRVINS_NO_ATTACH);
617
618 /*
619 * Query the network port interface.
620 */
621 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
622 if (!pThis->pIAboveNet)
623 {
624 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network port interface!\n"));
625 return VERR_PDM_MISSING_INTERFACE_ABOVE;
626 }
627
628 /*
629 * Query the network config interface.
630 */
631 pThis->pIAboveConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
632 if (!pThis->pIAboveConfig)
633 {
634 AssertMsgFailed(("Configuration error: the above device/driver didn't export the network config interface!\n"));
635 return VERR_PDM_MISSING_INTERFACE_ABOVE;
636 }
637
638 vmnet_return_t status = drvVMNetAttach(pThis);
639 if (status != VMNET_SUCCESS)
640 return PDMDrvHlpVMSetError(pDrvIns, VERR_INVALID_PARAMETER, RT_SRC_POS,
641 N_("Error: vmnet_start_interface returned %d"), status);
642
643 return VINF_SUCCESS;
644}
645
646
647/**
648 * Power On notification.
649 *
650 * @param pDrvIns The driver instance.
651 */
652static DECLCALLBACK(void) drvVMNetPowerOn(PPDMDRVINS pDrvIns)
653{
654 LogFlow(("drvVMNetPowerOn\n"));
655 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
656 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
657}
658
659
660/**
661 * Suspend notification.
662 *
663 * @param pDrvIns The driver instance.
664 */
665static DECLCALLBACK(void) drvVMNetSuspend(PPDMDRVINS pDrvIns)
666{
667 LogFlow(("drvVMNetSuspend\n"));
668 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
669 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_SUSPENDED);
670}
671
672
673/**
674 * Resume notification.
675 *
676 * @param pDrvIns The driver instance.
677 */
678static DECLCALLBACK(void) drvVMNetResume(PPDMDRVINS pDrvIns)
679{
680 LogFlow(("drvVMNetResume\n"));
681 PDRVVMNET pThis = PDMINS_2_DATA(pDrvIns, PDRVVMNET);
682 ASMAtomicXchgSize(&pThis->enmState, VMNETSTATE_RUNNING);
683}
684
685
686
687/**
688 * Network sniffer filter driver registration record.
689 */
690const PDMDRVREG g_DrvVMNet =
691{
692 /* u32Version */
693 PDM_DRVREG_VERSION,
694 /* szName */
695 "VMNet",
696 /* szRCMod */
697 "",
698 /* szR0Mod */
699 "",
700 /* pszDescription */
701 "VMNET Filter Driver",
702 /* fFlags */
703 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
704 /* fClass. */
705 PDM_DRVREG_CLASS_NETWORK,
706 /* cMaxInstances */
707 UINT32_MAX,
708 /* cbInstance */
709 sizeof(DRVVMNET),
710 /* pfnConstruct */
711 drvVMNetConstruct,
712 /* pfnDestruct */
713 drvVMNetDestruct,
714 /* pfnRelocate */
715 NULL,
716 /* pfnIOCtl */
717 NULL,
718 /* pfnPowerOn */
719 drvVMNetPowerOn,
720 /* pfnReset */
721 NULL,
722 /* pfnSuspend */
723 drvVMNetSuspend,
724 /* pfnResume */
725 drvVMNetResume,
726 /* pfnAttach */
727 NULL,
728 /* pfnDetach */
729 NULL,
730 /* pfnPowerOff */
731 NULL,
732 /* pfnSoftReset */
733 NULL,
734 /* u32EndVersion */
735 PDM_DRVREG_VERSION
736};
737
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