VirtualBox

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

Last change on this file since 40754 was 40282, checked in by vboxsync, 12 years ago

*: gcc-4.7: ~0 => ~0U in initializers (warning: narrowing conversion of -1' from int' to `unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing])

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

© 2023 Oracle
ContactPrivacy policyTerms of Use