VirtualBox

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

Last change on this file since 72278 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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