VirtualBox

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

Last change on this file since 46935 was 45061, checked in by vboxsync, 12 years ago

Review of PDM driver destructors making sure that variables they use are correctly initialized in the constructor. Found several RTFileClose(0) cases.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.2 KB
Line 
1/* $Id: DrvUDPTunnel.cpp 45061 2013-03-18 14:09:03Z 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-2012 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 {
407 RTStrFree(pThis->pszInstance);
408 pThis->pszInstance = NULL;
409 }
410
411 if (pThis->pszDestIP)
412 {
413 MMR3HeapFree(pThis->pszDestIP);
414 pThis->pszDestIP = NULL;
415 }
416
417 if (pThis->pServer)
418 {
419 RTUdpServerDestroy(pThis->pServer);
420 pThis->pServer = NULL;
421 }
422
423 /*
424 * Kill the xmit lock.
425 */
426 if (RTCritSectIsInitialized(&pThis->XmitLock))
427 RTCritSectDelete(&pThis->XmitLock);
428
429#ifdef VBOX_WITH_STATISTICS
430 /*
431 * Deregister statistics.
432 */
433 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSent);
434 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktSentBytes);
435 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecv);
436 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatPktRecvBytes);
437 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatTransmit);
438 PDMDrvHlpSTAMDeregister(pDrvIns, &pThis->StatReceive);
439#endif /* VBOX_WITH_STATISTICS */
440}
441
442
443/**
444 * Construct a UDP tunnel network transport driver instance.
445 *
446 * @copydoc FNPDMDRVCONSTRUCT
447 */
448static DECLCALLBACK(int) drvUDPTunnelConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
449{
450 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
451 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
452
453 /*
454 * Init the static parts.
455 */
456 pThis->pDrvIns = pDrvIns;
457 pThis->pszDestIP = NULL;
458 pThis->pszInstance = NULL;
459
460 /* IBase */
461 pDrvIns->IBase.pfnQueryInterface = drvUDPTunnelQueryInterface;
462 /* INetwork */
463 pThis->INetworkUp.pfnBeginXmit = drvUDPTunnelUp_BeginXmit;
464 pThis->INetworkUp.pfnAllocBuf = drvUDPTunnelUp_AllocBuf;
465 pThis->INetworkUp.pfnFreeBuf = drvUDPTunnelUp_FreeBuf;
466 pThis->INetworkUp.pfnSendBuf = drvUDPTunnelUp_SendBuf;
467 pThis->INetworkUp.pfnEndXmit = drvUDPTunnelUp_EndXmit;
468 pThis->INetworkUp.pfnSetPromiscuousMode = drvUDPTunnelUp_SetPromiscuousMode;
469 pThis->INetworkUp.pfnNotifyLinkChanged = drvUDPTunnelUp_NotifyLinkChanged;
470
471#ifdef VBOX_WITH_STATISTICS
472 /*
473 * Statistics.
474 */
475 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/UDPTunnel%d/Packets/Sent", pDrvIns->iInstance);
476 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/UDPTunnel%d/Bytes/Sent", pDrvIns->iInstance);
477 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/UDPTunnel%d/Packets/Received", pDrvIns->iInstance);
478 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/UDPTunnel%d/Bytes/Received", pDrvIns->iInstance);
479 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/UDPTunnel%d/Transmit", pDrvIns->iInstance);
480 PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/UDPTunnel%d/Receive", pDrvIns->iInstance);
481#endif /* VBOX_WITH_STATISTICS */
482
483 /*
484 * Validate the config.
485 */
486 if (!CFGMR3AreValuesValid(pCfg, "sport\0dest\0dport"))
487 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES, "");
488
489 /*
490 * Check that no-one is attached to us.
491 */
492 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
493 ("Configuration error: Not possible to attach anything to this driver!\n"),
494 VERR_PDM_DRVINS_NO_ATTACH);
495
496 /*
497 * Query the network port interface.
498 */
499 pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
500 if (!pThis->pIAboveNet)
501 return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
502 N_("Configuration error: The above device/driver didn't export the network port interface"));
503
504 /*
505 * Read the configuration.
506 */
507 int rc;
508 char szVal[16];
509 rc = CFGMR3QueryStringDef(pCfg, "sport", szVal, sizeof(szVal), "4444");
510 if (RT_FAILURE(rc))
511 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
512 N_("DrvUDPTunnel: Configuration error: Querying \"sport\" as string failed"));
513 rc = RTStrToUInt16Full(szVal, 0, &pThis->uSrcPort);
514 if (RT_FAILURE(rc))
515 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
516 N_("DrvUDPTunnel: Configuration error: Converting \"sport\" to integer failed"));
517 if (!pThis->uSrcPort)
518 pThis->uSrcPort = 4444;
519
520 rc = CFGMR3QueryStringDef(pCfg, "dport", szVal, sizeof(szVal), "4445");
521 if (RT_FAILURE(rc))
522 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
523 N_("DrvUDPTunnel: Configuration error: Querying \"dport\" as string failed"));
524 rc = RTStrToUInt16Full(szVal, 0, &pThis->uDestPort);
525 if (RT_FAILURE(rc))
526 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
527 N_("DrvUDPTunnel: Configuration error: Converting \"dport\" to integer failed"));
528 if (!pThis->uDestPort)
529 pThis->uDestPort = 4445;
530
531 rc = CFGMR3QueryStringAllocDef(pCfg, "dest", &pThis->pszDestIP, "127.0.0.1");
532 if (RT_FAILURE(rc))
533 rc = PDMDRV_SET_ERROR(pDrvIns, rc,
534 N_("DrvUDPTunnel: Configuration error: Querying \"dest\" as string failed"));
535
536 LogRel(("UDPTunnel#%d: sport=%d;dest=%s;dport=%d\n", pDrvIns->iInstance, pThis->uSrcPort, pThis->pszDestIP, pThis->uDestPort));
537
538 /*
539 * Set up destination address for UDP.
540 */
541 rc = RTSocketParseInetAddress(pThis->pszDestIP, pThis->uDestPort, &pThis->DestAddress);
542 AssertRCReturn(rc, rc);
543
544 /*
545 * Create unique thread name for the UDP receiver.
546 */
547 rc = RTStrAPrintf(&pThis->pszInstance, "UDPTunnel%d", pDrvIns->iInstance);
548 AssertRC(rc);
549
550 /*
551 * Start the UDP receiving thread.
552 */
553 rc = RTUdpServerCreate("", pThis->uSrcPort, RTTHREADTYPE_IO, pThis->pszInstance,
554 drvUDPTunnelReceive, pDrvIns, &pThis->pServer);
555 if (RT_FAILURE(rc))
556 return PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
557 N_("UDPTunnel: Failed to start the UDP tunnel server"));
558
559 /*
560 * Create the transmit lock.
561 */
562 rc = RTCritSectInit(&pThis->XmitLock);
563 AssertRCReturn(rc, rc);
564
565 return rc;
566}
567
568
569/**
570 * Suspend notification.
571 *
572 * @param pDrvIns The driver instance.
573 */
574static DECLCALLBACK(void) drvUDPTunnelSuspend(PPDMDRVINS pDrvIns)
575{
576 LogFlowFunc(("\n"));
577 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
578
579 if (pThis->pServer)
580 {
581 RTUdpServerDestroy(pThis->pServer);
582 pThis->pServer = NULL;
583 }
584}
585
586
587/**
588 * Resume notification.
589 *
590 * @param pDrvIns The driver instance.
591 */
592static DECLCALLBACK(void) drvUDPTunnelResume(PPDMDRVINS pDrvIns)
593{
594 LogFlowFunc(("\n"));
595 PDRVUDPTUNNEL pThis = PDMINS_2_DATA(pDrvIns, PDRVUDPTUNNEL);
596
597 int rc = RTUdpServerCreate("", pThis->uSrcPort, RTTHREADTYPE_IO, pThis->pszInstance,
598 drvUDPTunnelReceive, pDrvIns, &pThis->pServer);
599 if (RT_FAILURE(rc))
600 PDMDrvHlpVMSetError(pThis->pDrvIns, VERR_PDM_HIF_OPEN_FAILED, RT_SRC_POS,
601 N_("UDPTunnel: Failed to start the UDP tunnel server"));
602
603}
604
605
606/**
607 * UDP tunnel network transport driver registration record.
608 */
609const PDMDRVREG g_DrvUDPTunnel =
610{
611 /* u32Version */
612 PDM_DRVREG_VERSION,
613 /* szName */
614 "UDPTunnel",
615 /* szRCMod */
616 "",
617 /* szR0Mod */
618 "",
619 /* pszDescription */
620 "UDP Tunnel Network Transport Driver",
621 /* fFlags */
622 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
623 /* fClass. */
624 PDM_DRVREG_CLASS_NETWORK,
625 /* cMaxInstances */
626 ~0U,
627 /* cbInstance */
628 sizeof(DRVUDPTUNNEL),
629 /* pfnConstruct */
630 drvUDPTunnelConstruct,
631 /* pfnDestruct */
632 drvUDPTunnelDestruct,
633 /* pfnRelocate */
634 NULL,
635 /* pfnIOCtl */
636 NULL,
637 /* pfnPowerOn */
638 NULL,
639 /* pfnReset */
640 NULL,
641 /* pfnSuspend */
642 drvUDPTunnelSuspend,
643 /* pfnResume */
644 drvUDPTunnelResume,
645 /* pfnAttach */
646 NULL,
647 /* pfnDetach */
648 NULL,
649 /* pfnPowerOff */
650 NULL,
651 /* pfnSoftReset */
652 NULL,
653 /* u32EndVersion */
654 PDM_DRVREG_VERSION
655};
656
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