VirtualBox

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

Last change on this file since 60756 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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