VirtualBox

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

Last change on this file since 37198 was 37198, checked in by vboxsync, 14 years ago

Devices/Network/DrvUDPTunnel: new network transport which sends ethernet frames encapsulated in UDP. Contributed by Christophe Devriese, and much cleaned up.

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