VirtualBox

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

最後變更 在這個檔案從92097是 92097,由 vboxsync 提交於 3 年 前

VMNet: bugref:9932 Better handling of missing max packet size

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

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