VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/DrvUDPTunnel.cpp@ 101539

Last change on this file since 101539 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: DrvUDPTunnel.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DrvUDPTunnel - UDP tunnel network transport driver
4 *
5 * Based on code contributed by Christophe Devriese
6 */
7
8/*
9 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * SPDX-License-Identifier: GPL-3.0-only
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#define LOG_GROUP LOG_GROUP_DRV_UDPTUNNEL
35#include <VBox/log.h>
36#include <VBox/vmm/pdmdrv.h>
37#include <VBox/vmm/pdmnetifs.h>
38#include <VBox/vmm/pdmnetinline.h>
39
40#include <iprt/asm.h>
41#include <iprt/assert.h>
42#include <iprt/ctype.h>
43#include <iprt/udp.h>
44#include <iprt/mem.h>
45#include <iprt/path.h>
46#include <iprt/uuid.h>
47#include <iprt/string.h>
48#include <iprt/critsect.h>
49
50#include "VBoxDD.h"
51
52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
56/**
57 * UDP tunnel driver instance data.
58 *
59 * @implements PDMINETWORKUP
60 */
61typedef struct DRVUDPTUNNEL
62{
63 /** The network interface. */
64 PDMINETWORKUP INetworkUp;
65 /** The network interface. */
66 PPDMINETWORKDOWN pIAboveNet;
67 /** Pointer to the driver instance. */
68 PPDMDRVINS pDrvIns;
69 /** UDP tunnel source port. */
70 uint16_t uSrcPort;
71 /** UDP tunnel destination port. */
72 uint16_t uDestPort;
73 /** UDP tunnel destination IP address. */
74 char *pszDestIP;
75 /** UDP tunnel instance string. */
76 char *pszInstance;
77
78 /** UDP destination address. */
79 RTNETADDR DestAddress;
80 /** Transmit lock used by drvUDPTunnelUp_BeginXmit. */
81 RTCRITSECT XmitLock;
82 /** Server data structure for UDP communication. */
83 PRTUDPSERVER pServer;
84
85 /** Flag whether the link is down. */
86 bool volatile fLinkDown;
87
88#ifdef VBOX_WITH_STATISTICS
89 /** Number of sent packets. */
90 STAMCOUNTER StatPktSent;
91 /** Number of sent bytes. */
92 STAMCOUNTER StatPktSentBytes;
93 /** Number of received packets. */
94 STAMCOUNTER StatPktRecv;
95 /** Number of received bytes. */
96 STAMCOUNTER StatPktRecvBytes;
97 /** Profiling packet transmit runs. */
98 STAMPROFILE StatTransmit;
99 /** Profiling packet receive runs. */
100 STAMPROFILEADV StatReceive;
101#endif /* VBOX_WITH_STATISTICS */
102
103#ifdef LOG_ENABLED
104 /** The nano ts of the last transfer. */
105 uint64_t u64LastTransferTS;
106 /** The nano ts of the last receive. */
107 uint64_t u64LastReceiveTS;
108#endif
109} DRVUDPTUNNEL, *PDRVUDPTUNNEL;
110
111
112/** Converts a pointer to UDPTUNNEL::INetworkUp to a PRDVUDPTUNNEL. */
113#define PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface) ( (PDRVUDPTUNNEL)((uintptr_t)pInterface - RT_UOFFSETOF(DRVUDPTUNNEL, INetworkUp)) )
114
115
116/*********************************************************************************************************************************
117* Internal Functions *
118*********************************************************************************************************************************/
119
120/**
121 * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
122 */
123static DECLCALLBACK(int) drvUDPTunnelUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
124{
125 RT_NOREF(fOnWorkerThread);
126 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
127 int rc = RTCritSectTryEnter(&pThis->XmitLock);
128 if (RT_FAILURE(rc))
129 {
130 /** @todo XMIT thread */
131 rc = VERR_TRY_AGAIN;
132 }
133 return rc;
134}
135
136/**
137 * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
138 */
139static DECLCALLBACK(int) drvUDPTunnelUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
140 PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
141{
142 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
143 Assert(RTCritSectIsOwner(&pThis->XmitLock)); NOREF(pThis);
144
145 /*
146 * Allocate a scatter / gather buffer descriptor that is immediately
147 * followed by the buffer space of its single segment. The GSO context
148 * comes after that again.
149 */
150 PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16)
151 + RT_ALIGN_Z(cbMin, 16)
152 + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
153 if (!pSgBuf)
154 return VERR_NO_MEMORY;
155
156 /*
157 * Initialize the S/G buffer and return.
158 */
159 pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
160 pSgBuf->cbUsed = 0;
161 pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16);
162 pSgBuf->pvAllocator = NULL;
163 if (!pGso)
164 pSgBuf->pvUser = NULL;
165 else
166 {
167 pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
168 *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso;
169 }
170 pSgBuf->cSegs = 1;
171 pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
172 pSgBuf->aSegs[0].pvSeg = pSgBuf + 1;
173
174#if 0 /* poison */
175 memset(pSgBuf->aSegs[0].pvSeg, 'F', pSgBuf->aSegs[0].cbSeg);
176#endif
177 *ppSgBuf = pSgBuf;
178 return VINF_SUCCESS;
179}
180
181
182/**
183 * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
184 */
185static DECLCALLBACK(int) drvUDPTunnelUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
186{
187 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
188 Assert(RTCritSectIsOwner(&pThis->XmitLock)); NOREF(pThis);
189 if (pSgBuf)
190 {
191 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
192 pSgBuf->fFlags = 0;
193 RTMemFree(pSgBuf);
194 }
195 return VINF_SUCCESS;
196}
197
198
199/**
200 * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
201 */
202static DECLCALLBACK(int) drvUDPTunnelUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
203{
204 RT_NOREF(fOnWorkerThread);
205 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
206 STAM_COUNTER_INC(&pThis->StatPktSent);
207 STAM_COUNTER_ADD(&pThis->StatPktSentBytes, pSgBuf->cbUsed);
208 STAM_PROFILE_START(&pThis->StatTransmit, a);
209
210 AssertPtr(pSgBuf);
211 Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
212 Assert(RTCritSectIsOwner(&pThis->XmitLock));
213
214 int rc;
215 if (!pSgBuf->pvUser)
216 {
217#ifdef LOG_ENABLED
218 uint64_t u64Now = RTTimeProgramNanoTS();
219 LogFunc(("%-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
220 pSgBuf->cbUsed, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
221 pThis->u64LastTransferTS = u64Now;
222#endif
223 Log2(("pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n%.*Rhxd\n",
224 pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg));
225
226 rc = RTUdpWrite(pThis->pServer, pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, &pThis->DestAddress);
227 }
228 else
229 {
230 uint8_t abHdrScratch[256];
231 uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
232 PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
233 uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1);
234 rc = VINF_SUCCESS;
235 for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
236 {
237 uint32_t cbSegFrame;
238 void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch,
239 iSeg, cSegs, &cbSegFrame);
240 rc = RTUdpWrite(pThis->pServer, pvSegFrame, cbSegFrame, &pThis->DestAddress);
241 }
242 }
243
244 pSgBuf->fFlags = 0;
245 RTMemFree(pSgBuf);
246
247 STAM_PROFILE_STOP(&pThis->StatTransmit, a);
248 AssertRC(rc);
249 if (RT_FAILURE(rc))
250 {
251 if (rc == VERR_NO_MEMORY)
252 rc = VERR_NET_NO_BUFFER_SPACE;
253 else
254 rc = VERR_NET_DOWN;
255 }
256 return rc;
257}
258
259
260/**
261 * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
262 */
263static DECLCALLBACK(void) drvUDPTunnelUp_EndXmit(PPDMINETWORKUP pInterface)
264{
265 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
266 RTCritSectLeave(&pThis->XmitLock);
267}
268
269
270/**
271 * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
272 */
273static DECLCALLBACK(void) drvUDPTunnelUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
274{
275 RT_NOREF(pInterface, fPromiscuous);
276 LogFlowFunc(("fPromiscuous=%d\n", fPromiscuous));
277 /* nothing to do */
278}
279
280
281/**
282 * Notification on link status changes.
283 *
284 * @param pInterface Pointer to the interface structure containing the called function pointer.
285 * @param enmLinkState The new link state.
286 * @thread EMT
287 */
288static DECLCALLBACK(void) drvUDPTunnelUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
289{
290 LogFlowFunc(("enmLinkState=%d\n", enmLinkState));
291 PDRVUDPTUNNEL pThis = PDMINETWORKUP_2_DRVUDPTUNNEL(pInterface);
292
293 bool fLinkDown;
294 switch (enmLinkState)
295 {
296 case PDMNETWORKLINKSTATE_DOWN:
297 case PDMNETWORKLINKSTATE_DOWN_RESUME:
298 fLinkDown = true;
299 break;
300 default:
301 AssertMsgFailed(("enmLinkState=%d\n", enmLinkState));
302 RT_FALL_THRU();
303 case PDMNETWORKLINKSTATE_UP:
304 fLinkDown = false;
305 break;
306 }
307 ASMAtomicXchgSize(&pThis->fLinkDown, fLinkDown);
308}
309
310
311static DECLCALLBACK(int) drvUDPTunnelReceive(RTSOCKET Sock, void *pvUser)
312{
313 PDRVUDPTUNNEL pThis = PDMINS_2_DATA((PPDMDRVINS)pvUser, PDRVUDPTUNNEL);
314 LogFlowFunc(("pThis=%p\n", pThis));
315
316 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
317
318 /*
319 * Read the frame.
320 */
321 char achBuf[16384];
322 size_t cbRead = 0;
323 int rc = RTUdpRead(Sock, achBuf, sizeof(achBuf), &cbRead, NULL);
324 if (RT_SUCCESS(rc))
325 {
326 if (!pThis->fLinkDown)
327 {
328 /*
329 * Wait for the device to have space for this frame.
330 * Most guests use frame-sized receive buffers, hence non-zero cbMax
331 * automatically means there is enough room for entire frame. Some
332 * guests (eg. Solaris) use large chains of small receive buffers
333 * (each 128 or so bytes large). We will still start receiving as soon
334 * as cbMax is non-zero because:
335 * - it would be quite expensive for pfnCanReceive to accurately
336 * determine free receive buffer space
337 * - if we were waiting for enough free buffers, there is a risk
338 * of deadlocking because the guest could be waiting for a receive
339 * overflow error to allocate more receive buffers
340 */
341 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
342 rc = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, RT_INDEFINITE_WAIT);
343 STAM_PROFILE_ADV_START(&pThis->StatReceive, a);
344
345 /*
346 * A return code != VINF_SUCCESS means that we were woken up during a VM
347 * state transition. Drop the packet and wait for the next one.
348 */
349 if (RT_FAILURE(rc))
350 {
351 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
352 return VINF_SUCCESS;
353 }
354
355 /*
356 * Pass the data up.
357 */
358#ifdef LOG_ENABLED
359 uint64_t u64Now = RTTimeProgramNanoTS();
360 LogFunc(("%-4d bytes at %llu ns deltas: r=%llu t=%llu\n",
361 cbRead, u64Now, u64Now - pThis->u64LastReceiveTS, u64Now - pThis->u64LastTransferTS));
362 pThis->u64LastReceiveTS = u64Now;
363#endif
364 Log2(("cbRead=%#x\n" "%.*Rhxd\n", cbRead, cbRead, achBuf));
365 STAM_COUNTER_INC(&pThis->StatPktRecv);
366 STAM_COUNTER_ADD(&pThis->StatPktRecvBytes, cbRead);
367 rc = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, achBuf, cbRead);
368 AssertRC(rc);
369 }
370 }
371 else
372 {
373 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
374 LogFunc(("RTUdpRead -> %Rrc\n", rc));
375 if (rc == VERR_INVALID_HANDLE)
376 return VERR_UDP_SERVER_STOP;
377 }
378
379 STAM_PROFILE_ADV_STOP(&pThis->StatReceive, a);
380 return VINF_SUCCESS;
381}
382
383
384/* -=-=-=-=- PDMIBASE -=-=-=-=- */
385
386/**
387 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
388 */
389static DECLCALLBACK(void *) drvUDPTunnelQueryInterface(PPDMIBASE pInterface, const char *pszIID)
390{
391 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
392 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
393
394 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
395 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
396 return NULL;
397}
398
399
400/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
401
402/**
403 * Destruct a driver instance.
404 *
405 * Most VM resources are freed by the VM. This callback is provided so that any non-VM
406 * resources can be freed correctly.
407 *
408 * @param pDrvIns The driver instance data.
409 */
410static DECLCALLBACK(void) drvUDPTunnelDestruct(PPDMDRVINS pDrvIns)
411{
412 LogFlowFunc(("\n"));
413 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
414 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
415
416 ASMAtomicXchgSize(&pThis->fLinkDown, true);
417
418 if (pThis->pszInstance)
419 {
420 RTStrFree(pThis->pszInstance);
421 pThis->pszInstance = NULL;
422 }
423
424 if (pThis->pszDestIP)
425 {
426 PDMDrvHlpMMHeapFree(pDrvIns, pThis->pszDestIP);
427 pThis->pszDestIP = NULL;
428 }
429
430 if (pThis->pServer)
431 {
432 RTUdpServerDestroy(pThis->pServer);
433 pThis->pServer = NULL;
434 }
435
436 /*
437 * Kill the xmit lock.
438 */
439 if (RTCritSectIsInitialized(&pThis->XmitLock))
440 RTCritSectDelete(&pThis->XmitLock);
441
442#ifdef VBOX_WITH_STATISTICS
443 /*
444 * Deregister statistics.
445 */
446 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
447 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
448 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
449 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
450 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
451 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
452#endif /* VBOX_WITH_STATISTICS */
453}
454
455
456/**
457 * Construct a UDP tunnel network transport driver instance.
458 *
459 * @copydoc FNPDMDRVCONSTRUCT
460 */
461static DECLCALLBACK(int) drvUDPTunnelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
462{
463 RT_NOREF(fFlags);
464 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
465 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
466 PCPDMDRVHLPR3 pHlp = pDrvIns->pHlpR3;
467
468 /*
469 * Init the static parts.
470 */
471 pThis->pDrvIns = pDrvIns;
472 pThis->pszDestIP = NULL;
473 pThis->pszInstance = NULL;
474
475 /* IBase */
476 pDrvIns->IBase.pfnQueryInterface = drvUDPTunnelQueryInterface;
477 /* INetwork */
478 pThis->INetworkUp.pfnBeginXmit = drvUDPTunnelUp_BeginXmit;
479 pThis->INetworkUp.pfnAllocBuf = drvUDPTunnelUp_AllocBuf;
480 pThis->INetworkUp.pfnFreeBuf = drvUDPTunnelUp_FreeBuf;
481 pThis->INetworkUp.pfnSendBuf = drvUDPTunnelUp_SendBuf;
482 pThis->INetworkUp.pfnEndXmit = drvUDPTunnelUp_EndXmit;
483 pThis->INetworkUp.pfnSetPromiscuousMode = drvUDPTunnelUp_SetPromiscuousMode;
484 pThis->INetworkUp.pfnNotifyLinkChanged = drvUDPTunnelUp_NotifyLinkChanged;
485
486#ifdef VBOX_WITH_STATISTICS
487 /*
488 * Statistics.
489 */
490 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/UDPTunnel%d/Packets/Sent", pDrvIns->iInstance);
491 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/UDPTunnel%d/Bytes/Sent", pDrvIns->iInstance);
492 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/UDPTunnel%d/Packets/Received", pDrvIns->iInstance);
493 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/UDPTunnel%d/Bytes/Received", pDrvIns->iInstance);
494 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/UDPTunnel%d/Transmit", pDrvIns->iInstance);
495 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/UDPTunnel%d/Receive", pDrvIns->iInstance);
496#endif /* VBOX_WITH_STATISTICS */
497
498 /*
499 * Validate the config.
500 */
501 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "sport"
502 "|dest"
503 "|dport",
504 "");
505
506 /*
507 * Check that no-one is attached to us.
508 */
509 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
510 ("Configuration error: Not possible to attach anything to this driver!\n"),
511 VERR_PDM_DRVINS_NO_ATTACH);
512
513 /*
514 * Query the network port interface.
515 */
516 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
517 if (!pThis->pIAboveNet)
518 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
519 N_("Configuration error: The above device/driver didn't export the network port interface"));
520
521 /*
522 * Read the configuration.
523 */
524 int rc;
525 char szVal[16];
526 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "sport", szVal, sizeof(szVal), "4444");
527 if (RT_FAILURE(rc))
528 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
529 N_("DrvUDPTunnel: Configuration error: Querying \"sport\" as string failed"));
530 rc = RTStrToUInt16Full(szVal, 0, &pThis->uSrcPort);
531 if (RT_FAILURE(rc))
532 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
533 N_("DrvUDPTunnel: Configuration error: Converting \"sport\" to integer failed"));
534 if (!pThis->uSrcPort)
535 pThis->uSrcPort = 4444;
536
537 rc = pHlp->pfnCFGMQueryStringDef(pCfg, "dport", szVal, sizeof(szVal), "4445");
538 if (RT_FAILURE(rc))
539 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
540 N_("DrvUDPTunnel: Configuration error: Querying \"dport\" as string failed"));
541 rc = RTStrToUInt16Full(szVal, 0, &pThis->uDestPort);
542 if (RT_FAILURE(rc))
543 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
544 N_("DrvUDPTunnel: Configuration error: Converting \"dport\" to integer failed"));
545 if (!pThis->uDestPort)
546 pThis->uDestPort = 4445;
547
548 rc = pHlp->pfnCFGMQueryStringAllocDef(pCfg, "dest", &pThis->pszDestIP, "127.0.0.1");
549 if (RT_FAILURE(rc))
550 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
551 N_("DrvUDPTunnel: Configuration error: Querying \"dest\" as string failed"));
552
553 LogRel(("UDPTunnel#%d: sport=%d;dest=%s;dport=%d\n", pDrvIns->iInstance, pThis->uSrcPort, pThis->pszDestIP, pThis->uDestPort));
554
555 /*
556 * Set up destination address for UDP.
557 */
558 rc = RTSocketParseInetAddress(pThis->pszDestIP, pThis->uDestPort, &pThis->DestAddress);
559 AssertRCReturn(rc, rc);
560
561 /*
562 * Create unique thread name for the UDP receiver.
563 */
564 rc = RTStrAPrintf(&pThis->pszInstance, "UDPTunnel%d", pDrvIns->iInstance);
565 AssertRC(rc);
566
567 /*
568 * Start the UDP receiving thread.
569 */
570 rc = RTUdpServerCreate("", pThis->uSrcPort, RTTHREADTYPE_IO, pThis->pszInstance,
571 drvUDPTunnelReceive, pDrvIns, &pThis->pServer);
572 if (RT_FAILURE(rc))
573 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
574 N_("UDPTunnel: Failed to start the UDP tunnel server"));
575
576 /*
577 * Create the transmit lock.
578 */
579 rc = RTCritSectInit(&pThis->XmitLock);
580 AssertRCReturn(rc, rc);
581
582 return rc;
583}
584
585
586/**
587 * Suspend notification.
588 *
589 * @param pDrvIns The driver instance.
590 */
591static DECLCALLBACK(void) drvUDPTunnelSuspend(PPDMDRVINS pDrvIns)
592{
593 LogFlowFunc(("\n"));
594 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
595
596 if (pThis->pServer)
597 {
598 RTUdpServerDestroy(pThis->pServer);
599 pThis->pServer = NULL;
600 }
601}
602
603
604/**
605 * Resume notification.
606 *
607 * @param pDrvIns The driver instance.
608 */
609static DECLCALLBACK(void) drvUDPTunnelResume(PPDMDRVINS pDrvIns)
610{
611 LogFlowFunc(("\n"));
612 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
613
614 int rc = RTUdpServerCreate("", pThis->uSrcPort, RTTHREADTYPE_IO, pThis->pszInstance,
615 drvUDPTunnelReceive, pDrvIns, &pThis->pServer);
616 if (RT_FAILURE(rc))
617 PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
618 N_("UDPTunnel: Failed to start the UDP tunnel server"));
619
620}
621
622
623/**
624 * UDP tunnel network transport driver registration record.
625 */
626const PDMDRVREG g_DrvUDPTunnel =
627{
628 /* u32Version */
629 PDM_DRVREG_VERSION,
630 /* szName */
631 "UDPTunnel",
632 /* szRCMod */
633 "",
634 /* szR0Mod */
635 "",
636 /* pszDescription */
637 "UDP Tunnel Network Transport Driver",
638 /* fFlags */
639 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
640 /* fClass. */
641 PDM_DRVREG_CLASS_NETWORK,
642 /* cMaxInstances */
643 ~0U,
644 /* cbInstance */
645 sizeof(DRVUDPTUNNEL),
646 /* pfnConstruct */
647 drvUDPTunnelConstruct,
648 /* pfnDestruct */
649 drvUDPTunnelDestruct,
650 /* pfnRelocate */
651 NULL,
652 /* pfnIOCtl */
653 NULL,
654 /* pfnPowerOn */
655 NULL,
656 /* pfnReset */
657 NULL,
658 /* pfnSuspend */
659 drvUDPTunnelSuspend,
660 /* pfnResume */
661 drvUDPTunnelResume,
662 /* pfnAttach */
663 NULL,
664 /* pfnDetach */
665 NULL,
666 /* pfnPowerOff */
667 NULL,
668 /* pfnSoftReset */
669 NULL,
670 /* u32EndVersion */
671 PDM_DRVREG_VERSION
672};
673
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