VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/SrvIntNetR0.cpp@ 10846

Last change on this file since 10846 was 10846, checked in by vboxsync, 17 years ago

intnet: removed autoactivation of the interface on open.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 87.7 KB
Line 
1/* $Id: SrvIntNetR0.cpp 10846 2008-07-23 22:03:16Z vboxsync $ */
2/** @file
3 * Internal networking - The ring 0 service.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_SRV_INTNET
27#include <VBox/intnet.h>
28#include <VBox/sup.h>
29#include <VBox/pdm.h>
30#include <VBox/log.h>
31#include <iprt/asm.h>
32#include <iprt/alloc.h>
33#include <iprt/semaphore.h>
34#include <iprt/spinlock.h>
35#include <iprt/thread.h>
36#include <iprt/assert.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#include <iprt/handletable.h>
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * A network interface.
47 *
48 * Unless explicitly stated, all members are protect by the network semaphore.
49 */
50typedef struct INTNETIF
51{
52 /** Pointer to the next interface.
53 * This is protected by the INTNET::FastMutex. */
54 struct INTNETIF *pNext;
55 /** The current MAC address for the interface. */
56 PDMMAC Mac;
57 /** Set if the INTNET::Mac member is valid. */
58 bool fMacSet;
59 /** Set if the interface is in promiscuous mode.
60 * In promiscuous mode the interface will receive all packages except the one it's sending. */
61 bool fPromiscuous;
62 /** Whether the interface is active or not. */
63 bool fActive;
64 /** Whether someone is currently in the destructor. */
65 bool volatile fDestroying;
66 /** Number of yields done to try make the interface read pending data.
67 * We will stop yeilding when this reaches a threshold assuming that the VM is paused or
68 * that it simply isn't worth all the delay. It is cleared when a successful send has been done.
69 */
70 uint32_t cYields;
71 /** Pointer to the current exchange buffer (ring-0). */
72 PINTNETBUF pIntBuf;
73 /** Pointer to ring-3 mapping of the current exchange buffer. */
74 R3PTRTYPE(PINTNETBUF) pIntBufR3;
75 /** Pointer to the default exchange buffer for the interface. */
76 PINTNETBUF pIntBufDefault;
77 /** Pointer to ring-3 mapping of the default exchange buffer. */
78 R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3;
79 /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
80 RTSEMEVENT volatile Event;
81 /** Number of threads sleeping on the Event semaphore. */
82 uint32_t cSleepers;
83 /** The interface handle.
84 * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
85 * should return with the appropriate error condition. */
86 INTNETIFHANDLE volatile hIf;
87 /** Pointer to the network this interface is connected to.
88 * This is protected by the INTNET::FastMutex. */
89 struct INTNETNETWORK *pNetwork;
90 /** The session this interface is associated with. */
91 PSUPDRVSESSION pSession;
92 /** The SUPR0 object id. */
93 void *pvObj;
94} INTNETIF;
95/** Pointer to an internal network interface. */
96typedef INTNETIF *PINTNETIF;
97
98
99/**
100 * A trunk interface.
101 */
102typedef struct INTNETTRUNKIF
103{
104 /** The port interface we present to the component. */
105 INTNETTRUNKSWPORT SwitchPort;
106 /** The port interface we get from the component. */
107 PINTNETTRUNKIFPORT pIfPort;
108 /** The trunk mutex that serializes all calls <b>to</b> the component. */
109 RTSEMFASTMUTEX FastMutex;
110 /** Pointer to the network we're connect to.
111 * This may be NULL if we're orphaned? */
112 struct INTNETNETWORK *pNetwork;
113 /** Whether to supply physical addresses with the outbound SGs. */
114 bool volatile fPhysSG;
115 /** Set if the 'wire' is in promiscuous mode.
116 * The state of the 'host' is queried each time. */
117 bool fPromiscuousWire;
118} INTNETTRUNKIF;
119/** Pointer to a trunk interface. */
120typedef INTNETTRUNKIF *PINTNETTRUNKIF;
121
122/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
123#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
124
125
126/**
127 * Internal representation of a network.
128 */
129typedef struct INTNETNETWORK
130{
131 /** The Next network in the chain.
132 * This is protected by the INTNET::FastMutex. */
133 struct INTNETNETWORK *pNext;
134 /** List of interfaces connected to the network.
135 * This is protected by the INTNET::FastMutex. */
136 PINTNETIF pIFs;
137 /** Pointer to the trunk interface.
138 * Can be NULL if there is no trunk connection. */
139 PINTNETTRUNKIF pTrunkIF;
140 /** The network mutex.
141 * It protects everything dealing with this network. */
142 RTSEMFASTMUTEX FastMutex;
143 /** Pointer to the instance data. */
144 struct INTNET *pIntNet;
145 /** The SUPR0 object id. */
146 void *pvObj;
147 /** Network creation flags (INTNET_OPEN_FLAGS_*). */
148 uint32_t fFlags;
149 /** The number of active interfaces (excluding the trunk). */
150 uint32_t cActiveIFs;
151 /** The length of the network name. */
152 uint8_t cchName;
153 /** The network name. */
154 char szName[INTNET_MAX_NETWORK_NAME];
155 /** The trunk type. */
156 INTNETTRUNKTYPE enmTrunkType;
157 /** The trunk name. */
158 char szTrunk[INTNET_MAX_TRUNK_NAME];
159} INTNETNETWORK;
160/** Pointer to an internal network. */
161typedef INTNETNETWORK *PINTNETNETWORK;
162
163
164/**
165 * Internal networking instance.
166 */
167typedef struct INTNET
168{
169 /** Mutex protecting the network creation, opening and destruction.
170 * (This means all operations affecting the pNetworks list.) */
171 RTSEMFASTMUTEX FastMutex;
172 /** List of networks. Protected by INTNET::Spinlock. */
173 PINTNETNETWORK volatile pNetworks;
174 /** Handle table for the interfaces. */
175 RTHANDLETABLE hHtIfs;
176} INTNET;
177
178
179/*******************************************************************************
180* Internal Functions *
181*******************************************************************************/
182static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis);
183static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis);
184static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis);
185static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis);
186
187
188
189/**
190 * Retain an interface.
191 *
192 * @returns VBox status code, can assume success in most situations.
193 * @param pIf The interface instance.
194 * @param pSession The current session.
195 */
196DECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession)
197{
198 int rc = SUPR0ObjAddRef(pIf->pvObj, pSession);
199 AssertRCReturn(rc, rc);
200 return VINF_SUCCESS;
201}
202
203
204/**
205 * Release an interface previously retained by intnetR0IfRetain or
206 * by handle lookup/freeing.
207 *
208 * @returns VBox status code, can assume success in most situations.
209 * @param pIf The interface instance.
210 * @param pSession The current session.
211 */
212DECLINLINE(void) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession)
213{
214 int rc = SUPR0ObjRelease(pIf->pvObj, pSession);
215 AssertRC(rc);
216}
217
218
219/**
220 * RTHandleCreateEx callback that retains an object in the
221 * handle table before returning it.
222 *
223 * (Avoids racing the freeing of the handle.)
224 *
225 * @returns VBox status code.
226 * @param hHandleTable The handle table (ignored).
227 * @param pvObj The object (INTNETIF).
228 * @param pvCtx The context (SUPDRVSESSION).
229 * @param pvUser The user context (ignored).
230 */
231static DECLCALLBACK(int) intnetR0IfRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
232{
233 NOREF(pvUser);
234 NOREF(hHandleTable);
235 PINTNETIF pIf = (PINTNETIF)pvObj;
236 if (pIf->hIf != INTNET_HANDLE_INVALID) /* Don't try retain it if called from intnetR0IfDestruct. */
237 return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx);
238 return VINF_SUCCESS;
239}
240
241
242/**
243 * Initializes a scatter / gather buffer from a simple linear buffer.
244 *
245 * @returns Pointer to the start of the frame.
246 * @param pSG Pointer to the scatter / gather structure.
247 * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
248 * @param pvFrame Pointer to the frame
249 * @param cbFrame The size of the frame.
250 */
251DECLINLINE(void) intnetR0SgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame)
252{
253 pSG->pvOwnerData = NULL;
254 pSG->pvUserData = NULL;
255 pSG->pvUserData2 = NULL;
256 pSG->cbTotal = cbFrame;
257 pSG->cUsers = 1;
258 pSG->fFlags = INTNETSG_FLAGS_TEMP;
259 pSG->cSegsAlloc = 1;
260 pSG->cSegsUsed = 1;
261 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
262 pSG->aSegs[0].pv = pvFrame;
263 pSG->aSegs[0].cb = cbFrame;
264}
265
266
267/**
268 * Initializes a scatter / gather buffer from a internal networking packet.
269 *
270 * @returns Pointer to the start of the frame.
271 * @param pSG Pointer to the scatter / gather structure.
272 * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
273 * @param pHdr Pointer to the packet header.
274 * @param pBuf The buffer the header is within. Only used in strict builds.
275 */
276DECLINLINE(void) intnetR0SgInitFromPkt(PINTNETSG pSG, PCINTNETHDR pPktHdr, PCINTNETBUF pBuf)
277{
278 pSG->cSegsUsed = 1;
279 pSG->cbTotal = pSG->aSegs[0].cb = pPktHdr->cbFrame;
280 pSG->aSegs[0].pv = INTNETHdrGetFramePtr(pPktHdr, pBuf);
281 pSG->aSegs[0].Phys = NIL_RTHCPHYS;
282}
283
284
285#ifdef IN_INTNET_TESTCASE
286/**
287 * Reads the next frame in the buffer.
288 * The caller is responsible for ensuring that there is a valid frame in the buffer.
289 *
290 * @returns Size of the frame in bytes.
291 * @param pBuf The buffer.
292 * @param pRingBuff The ring buffer to read from.
293 * @param pvFrame Where to put the frame. The caller is responsible for
294 * ensuring that there is sufficient space for the frame.
295 */
296static unsigned intnetR0RingReadFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, void *pvFrame)
297{
298 Assert(pRingBuf->offRead < pBuf->cbBuf);
299 Assert(pRingBuf->offRead >= pRingBuf->offStart);
300 Assert(pRingBuf->offRead < pRingBuf->offEnd);
301 uint32_t offRead = pRingBuf->offRead;
302 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offRead);
303 const void *pvFrameIn = INTNETHdrGetFramePtr(pHdr, pBuf);
304 unsigned cb = pHdr->cbFrame;
305 memcpy(pvFrame, pvFrameIn, cb);
306
307 /* skip the frame */
308 offRead += pHdr->offFrame + cb;
309 offRead = RT_ALIGN_32(offRead, sizeof(INTNETHDR));
310 Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
311 if (offRead >= pRingBuf->offEnd)
312 offRead = pRingBuf->offStart;
313 ASMAtomicXchgU32(&pRingBuf->offRead, offRead);
314 return cb;
315}
316#endif /* IN_INTNET_TESTCASE */
317
318
319/**
320 * Reads an entire SG into a fittingly size buffer.
321 *
322 * @param pSG The SG list to read.
323 * @param pvBuf The buffer to read into (at least pSG->cbTotal in size).
324 */
325DECLINLINE(void) intnetR0SgRead(PCINTNETSG pSG, void *pvBuf)
326{
327 if (pSG->cSegsUsed == 1)
328 {
329 Assert(pSG->cbTotal == pSG->aSegs[0].cb);
330 memcpy(pvBuf, pSG->aSegs[0].pv, pSG->cbTotal);
331 }
332 else
333 {
334 uint8_t *pbDst = (uint8_t *)pvBuf;
335 unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
336 for (unsigned iSeg = 0; iSeg < cSegs; iSeg++)
337 {
338 uint32_t cbSeg = pSG->aSegs[iSeg].cb;
339 Assert(cbSeg <= pSG->cbTotal && (uintptr_t)(pbDst - (uint8_t *)pvBuf) + cbSeg <= pSG->cbTotal);
340 memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg);
341 pbDst += cbSeg;
342 }
343 }
344}
345
346
347/**
348 * Writes a frame packet to the buffer.
349 *
350 * @returns VBox status code.
351 * @param pBuf The buffer.
352 * @param pRingBuf The ring buffer to read from.
353 * @param pSG The gatter list.
354 */
355static int intnetR0RingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, PCINTNETSG pSG)
356{
357 /*
358 * Validate input.
359 */
360 AssertPtr(pBuf);
361 AssertPtr(pRingBuf);
362 AssertPtr(pSG);
363 Assert(pSG->cbTotal >= sizeof(PDMMAC) * 2);
364 uint32_t offWrite = pRingBuf->offWrite;
365 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
366 uint32_t offRead = pRingBuf->offRead;
367 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
368
369 const uint32_t cb = RT_ALIGN_32(pSG->cbTotal, sizeof(INTNETHDR));
370 if (offRead <= offWrite)
371 {
372 /*
373 * Try fit it all before the end of the buffer.
374 */
375 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
376 {
377 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
378 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
379 pHdr->cbFrame = pSG->cbTotal;
380 pHdr->offFrame = sizeof(INTNETHDR);
381
382 intnetR0SgRead(pSG, pHdr + 1);
383
384 offWrite += cb + sizeof(INTNETHDR);
385 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
386 if (offWrite >= pRingBuf->offEnd)
387 offWrite = pRingBuf->offStart;
388 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
389 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
390 return VINF_SUCCESS;
391 }
392
393 /*
394 * Try fit the frame at the start of the buffer.
395 * (The header fits before the end of the buffer because of alignment.)
396 */
397 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
398 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
399 {
400 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
401 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
402 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
403 pHdr->cbFrame = pSG->cbTotal;
404 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
405
406 intnetR0SgRead(pSG, pvFrameOut);
407
408 offWrite = pRingBuf->offStart + cb;
409 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
410 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
411 return VINF_SUCCESS;
412 }
413 }
414 /*
415 * The reader is ahead of the writer, try fit it into that space.
416 */
417 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
418 {
419 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
420 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
421 pHdr->cbFrame = pSG->cbTotal;
422 pHdr->offFrame = sizeof(INTNETHDR);
423
424 intnetR0SgRead(pSG, pHdr + 1);
425
426 offWrite += cb + sizeof(INTNETHDR);
427 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
428 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
429 return VINF_SUCCESS;
430 }
431
432 /* (it didn't fit) */
433 /** @todo stats */
434 return VERR_BUFFER_OVERFLOW;
435}
436
437
438/**
439 * Ethernet header.
440 */
441#pragma pack(1)
442typedef struct INTNETETHERHDR
443{
444 PDMMAC MacDst;
445 PDMMAC MacSrc;
446 uint16_t EtherType;
447} INTNETETHERHDR;
448#pragma pack()
449typedef INTNETETHERHDR *PINTNETETHERHDR;
450typedef INTNETETHERHDR const *PCINTNETETHERHDR;
451
452
453/**
454 * Sends a frame to a specific interface.
455 *
456 * @param pIf The interface.
457 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
458 * @param pSG The gather buffer which data is being sent to the interface.
459 */
460static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG)
461{
462// LogFlow(("intnetR0IfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
463 int rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pSG);
464 if (RT_SUCCESS(rc))
465 {
466 pIf->cYields = 0;
467 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
468 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, pSG->cbTotal);
469 RTSemEventSignal(pIf->Event);
470 return;
471 }
472
473 Log(("intnetR0IfSend: overflow cb=%d hIf=%#x\n", pSG->cbTotal, pIf->hIf));
474
475#if 0 /* This is bad stuff now as we're blocking while locking down the network.
476 we really shouldn't delay the network traffic on the host just because
477 some bugger isn't responding. Will have to deal with this in a different
478 manner if required. */
479 /*
480 * Retry a few times, yielding the CPU in between.
481 * But don't let a unresponsive VM harm performance, so give up after a couple of tries.
482 */
483 if ( pIf->fActive
484 && pIf->cYields < 100)
485 {
486 unsigned cYields = 10;
487#else
488 /*
489 * Scheduling hack, for unicore machines primarily.
490 */
491 if ( pIf->fActive
492 && pIf->cYields < 4 /* just twice */
493 && pIfSender /* but not if it's from the trunk */)
494 {
495 unsigned cYields = 2;
496#endif
497 while (--cYields > 0)
498 {
499 RTSemEventSignal(pIf->Event);
500 RTThreadYield();
501 rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pSG);
502 if (RT_SUCCESS(rc))
503 {
504 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
505 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
506 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, pSG->cbTotal);
507 RTSemEventSignal(pIf->Event);
508 return;
509 }
510 pIf->cYields++;
511 }
512 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
513 }
514
515 /* ok, the frame is lost. */
516 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
517 RTSemEventSignal(pIf->Event);
518}
519
520
521/**
522 * Sends a frame down the trunk.
523 *
524 * The caller must own the network mutex, might be abandond temporarily.
525 * The fTrunkLock parameter indicates whether the trunk lock is held.
526 *
527 * @param pThis The trunk.
528 * @param pNetwork The network the frame is being sent to.
529 * @param fDst The destination flags.
530 * @param pSG Pointer to the gather list.
531 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
532 */
533static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, uint32_t fDst, PINTNETSG pSG, bool fTrunkLocked)
534{
535 /*
536 * Quick sanity check.
537 */
538 AssertPtr(pThis);
539 AssertPtr(pNetwork);
540 AssertPtr(pSG);
541 Assert(fDst);
542 AssertReturnVoid(pThis->pIfPort);
543
544 /*
545 * Temporarily leave the network lock while transmitting the frame.
546 *
547 * Note that we're relying on the out-bound lock to serialize threads down
548 * in INTNETR0IfSend. It's theoretically possible for there to be race now
549 * because I didn't implement async SG handling yet. Which is why we currently
550 * require the trunk to be locked, well, one of the reasons.
551 *
552 * Another reason is that the intnetR0NetworkSendUnicast code may have to
553 * call into the trunk interface component to do package switching.
554 */
555 AssertReturnVoid(fTrunkLocked); /* to be removed. */
556
557 int rc;
558 if ( fTrunkLocked
559 || intnetR0TrunkIfRetain(pThis))
560 {
561 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
562 AssertRC(rc);
563 if (RT_SUCCESS(rc))
564 {
565 if ( fTrunkLocked
566 || intnetR0TrunkIfOutLock(pThis))
567 {
568 rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pSG, fDst);
569
570 if (!fTrunkLocked)
571 intnetR0TrunkIfOutUnlock(pThis);
572 }
573 else
574 {
575 AssertFailed();
576 rc = VERR_SEM_DESTROYED;
577 }
578
579 int rc2 = RTSemFastMutexRequest(pNetwork->FastMutex);
580 AssertRC(rc2);
581 }
582
583 if (!fTrunkLocked)
584 intnetR0TrunkIfRelease(pThis);
585 }
586 else
587 {
588 AssertFailed();
589 rc = VERR_SEM_DESTROYED;
590 }
591
592 /** @todo failure statistics? */
593 Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst));
594}
595
596
597/**
598 * Sends a broadcast frame.
599 *
600 * The caller must own the network mutex, might be abandond temporarily.
601 * When pIfSender is not NULL, the caller must also own the trunk semaphore.
602 *
603 * @returns true if it's addressed to someone on the network, otherwise false.
604 * @param pNetwork The network the frame is being sent to.
605 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
606 * @param fSrc The source flags. This 0 if it's not from the trunk.
607 * @param pSG Pointer to the gather list.
608 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
609 */
610static bool intnetR0NetworkSendBroadcast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PINTNETSG pSG, bool fTrunkLocked)
611{
612 /*
613 * This is a broadcast or multicast address. For the present we treat those
614 * two as the same - investigating multicast is left for later.
615 *
616 * Write the packet to all the interfaces and signal them.
617 */
618 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
619 if (pIf != pIfSender)
620 intnetR0IfSend(pIf, pIfSender, pSG);
621
622 /*
623 * Unless the trunk is the origin, broadcast it to both the wire
624 * and the host as well.
625 */
626 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
627 if ( pIfSender
628 && pTrunkIf)
629 intnetR0TrunkIfSend(pTrunkIf, pNetwork, INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked);
630 return false; /* broadcast frames are never dropped */
631}
632
633
634/**
635 * Sends a multicast frame.
636 *
637 * The caller must own the network mutex, might be abandond temporarily.
638 *
639 * @returns true if it's addressed to someone on the network, otherwise false.
640 * @param pNetwork The network the frame is being sent to.
641 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
642 * @param fSrc The source flags. This 0 if it's not from the trunk.
643 * @param pSG Pointer to the gather list.
644 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
645 * @param pEthHdr Pointer to the ethernet header.
646 */
647static bool intnetR0NetworkSendMulticast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCINTNETETHERHDR pEthHdr)
648{
649 /** @todo implement multicast */
650 return intnetR0NetworkSendBroadcast(pNetwork, pIfSender, pSG, fTrunkLocked);
651}
652
653
654/**
655 * Sends a unicast frame.
656 *
657 * The caller must own the network mutex, might be abandond temporarily.
658 *
659 * @returns true if it's addressed to someone on the network, otherwise false.
660 * @param pNetwork The network the frame is being sent to.
661 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
662 * @param fSrc The source flags. This 0 if it's not from the trunk.
663 * @param pSG Pointer to the gather list.
664 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
665 * @param pEthHdr Pointer to the ethernet header.
666 */
667static bool intnetR0NetworkSendUnicast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCINTNETETHERHDR pEthHdr)
668{
669 /*
670 * Only send to the interfaces with matching a MAC address.
671 */
672 bool fExactIntNetRecipient = false;
673 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
674 {
675 bool fIt = false;
676 if ( ( !pIf->fMacSet
677 || (fIt = !memcmp(&pIf->Mac, &pEthHdr->MacDst, sizeof(pIf->Mac))) )
678 || ( pIf->fPromiscuous
679 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
680 && pIf != pIfSender /* promiscuous mode: omit the sender */))
681 {
682 Log2(("Dst=%.6Rhxs => %.6Rhxs\n", &pEthHdr->MacDst, &pIf->Mac));
683 fExactIntNetRecipient |= fIt;
684 intnetR0IfSend(pIf, pIfSender, pSG);
685 }
686 }
687
688 /*
689 * Send it to the trunk?
690 * If we didn't find the recipient on the internal network the
691 * frame will hit the wire.
692 */
693 uint32_t fDst = 0;
694 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
695 if ( pIfSender
696 && pTrunkIf
697 && pTrunkIf->pIfPort)
698 {
699 /* promiscuous checks first as they are cheaper than pfnIsHostMac. */
700 if ( pTrunkIf->fPromiscuousWire
701 && !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE)) )
702 fDst |= INTNETTRUNKDIR_WIRE;
703 if ( !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST))
704 || pTrunkIf->pIfPort->pfnIsPromiscuous(pTrunkIf->pIfPort) )
705 fDst |= INTNETTRUNKDIR_HOST;
706
707 if ( fDst != (INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE)
708 && !fExactIntNetRecipient /* if you have duplicate mac addresses, you're screwed. */ )
709 {
710 if (pTrunkIf->pIfPort->pfnIsHostMac(pTrunkIf->pIfPort, &pEthHdr->MacDst))
711 fDst |= INTNETTRUNKDIR_HOST;
712 else
713 fDst |= INTNETTRUNKDIR_WIRE;
714 }
715
716 if (fDst)
717 intnetR0TrunkIfSend(pTrunkIf, pNetwork, fDst, pSG, fTrunkLocked);
718 }
719
720 /* log it */
721 if ( !fExactIntNetRecipient
722 && !fDst
723 && ( (pEthHdr->MacDst.au8[0] == 0x08 && pEthHdr->MacDst.au8[1] == 0x00 && pEthHdr->MacDst.au8[2] == 0x27)
724 || (pEthHdr->MacSrc.au8[0] == 0x08 && pEthHdr->MacSrc.au8[1] == 0x00 && pEthHdr->MacSrc.au8[2] == 0x27)))
725 Log2(("Dst=%.6Rhxs ??\n", &pEthHdr->MacDst));
726
727 return fExactIntNetRecipient;
728}
729
730
731/**
732 * Sends a frame.
733 *
734 * This function will distribute the frame to the interfaces it is addressed to.
735 * It will also update the MAC address of the sender.
736 *
737 * The caller must own the network mutex.
738 *
739 * @returns true if it's addressed to someone on the network, otherwise false.
740 * @param pNetwork The network the frame is being sent to.
741 * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
742 * @param fSrc The source flags. This 0 if it's not from the trunk.
743 * @param pSG Pointer to the gather list.
744 * @param fTrunkLocked Whether the caller owns the out-bound trunk lock.
745 */
746static bool intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked)
747{
748 bool fRc = false;
749
750 /*
751 * Assert reality.
752 */
753 AssertPtr(pNetwork);
754 AssertPtrNull(pIfSender);
755 Assert(pIfSender ? fSrc == 0 : fSrc != 0);
756 Assert(!pIfSender || pNetwork == pIfSender->pNetwork);
757 AssertPtr(pSG);
758 Assert(pSG->cSegsUsed >= 1);
759 Assert(pSG->cSegsUsed <= pSG->cSegsAlloc);
760 if (pSG->cbTotal < sizeof(INTNETETHERHDR))
761 return fRc;
762
763 /*
764 * Send statistics.
765 */
766 if (pIfSender)
767 {
768 STAM_REL_COUNTER_INC(&pIfSender->pIntBuf->cStatSends);
769 STAM_REL_COUNTER_ADD(&pIfSender->pIntBuf->cbStatSend, pSG->cbTotal);
770 }
771
772 /*
773 * Get the ethernet header (might theoretically involve multiple segments).
774 */
775 INTNETETHERHDR EthHdr;
776 if (RT_LIKELY(pSG->aSegs[0].cb >= sizeof(EthHdr)))
777 EthHdr = *(PCINTNETETHERHDR)pSG->aSegs[0].pv;
778 else
779 {
780 uint8_t *pbDst = (uint8_t *)&EthHdr;
781 size_t cbLeft = sizeof(EthHdr);
782 for (unsigned iSeg = 0; cbLeft && iSeg < pSG->cSegsUsed; iSeg++)
783 {
784 size_t cb = RT_MIN(cbLeft, pSG->aSegs[iSeg].cb);
785 memcpy(pbDst, pSG->aSegs[iSeg].pv, cb);
786 pbDst += cb;
787 cbLeft -= cb;
788 }
789 AssertReturn(!cbLeft, false);
790 }
791 if ( (EthHdr.MacDst.au8[0] == 0x08 && EthHdr.MacDst.au8[1] == 0x00 && EthHdr.MacDst.au8[2] == 0x27)
792 || (EthHdr.MacSrc.au8[0] == 0x08 && EthHdr.MacSrc.au8[1] == 0x00 && EthHdr.MacSrc.au8[2] == 0x27)
793 || (EthHdr.MacDst.au8[0] == 0x00 && EthHdr.MacDst.au8[1] == 0x16 && EthHdr.MacDst.au8[2] == 0xcb)
794 || (EthHdr.MacSrc.au8[0] == 0x00 && EthHdr.MacSrc.au8[1] == 0x16 && EthHdr.MacSrc.au8[2] == 0xcb)
795 || EthHdr.MacDst.au8[0] == 0xff
796 || EthHdr.MacSrc.au8[0] == 0xff)
797 Log2(("D=%.6Rhxs S=%.6Rhxs T=%04x f=%x z=%x\n",
798 &EthHdr.MacDst, &EthHdr.MacSrc, RT_BE2H_U16(EthHdr.EtherType), fSrc, pSG->cbTotal));
799
800 /*
801 * Inspect the header updating the mac address of the sender in the process.
802 */
803 if ( pIfSender
804 && memcmp(&EthHdr.MacSrc, &pIfSender->Mac, sizeof(pIfSender->Mac)))
805 {
806 /** @todo stats */
807 Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &EthHdr.MacSrc));
808 pIfSender->Mac = EthHdr.MacSrc;
809 pIfSender->fMacSet = true;
810 }
811
812 /*
813 * Distribute the frame.
814 */
815 if (RT_UNLIKELY(EthHdr.MacDst.au8[0] & 1)) /* multicast address */
816 fRc = intnetR0NetworkSendMulticast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
817 else if ( EthHdr.MacDst.au16[0] == 0xffff /* broadcast address. */
818 && EthHdr.MacDst.au16[1] == 0xffff
819 && EthHdr.MacDst.au16[2] == 0xffff)
820 fRc = intnetR0NetworkSendBroadcast(pNetwork, pIfSender, pSG, fTrunkLocked);
821 else
822 fRc = intnetR0NetworkSendUnicast(pNetwork, pIfSender, fSrc, pSG, fTrunkLocked, &EthHdr);
823 return fRc;
824}
825
826
827/**
828 * Sends one or more frames.
829 *
830 * The function will first the frame which is passed as the optional
831 * arguments pvFrame and cbFrame. These are optional since it also
832 * possible to chain together one or more frames in the send buffer
833 * which the function will process after considering it's arguments.
834 *
835 * @returns VBox status code.
836 * @param pIntNet The instance data.
837 * @param hIf The interface handle.
838 * @param pSession The caller's session.
839 * @param pvFrame Pointer to the frame. Optional, please don't use.
840 * @param cbFrame Size of the frame. Optional, please don't use.
841 */
842INTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, const void *pvFrame, unsigned cbFrame)
843{
844 Log5(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
845
846 /*
847 * Validate input and translate the handle.
848 */
849 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
850 if (pvFrame && cbFrame)
851 {
852 AssertReturn(cbFrame < 0x8000, VERR_INVALID_PARAMETER);
853 AssertPtrReturn(pvFrame, VERR_INVALID_PARAMETER);
854 AssertPtrReturn((uint8_t *)pvFrame + cbFrame - 1, VERR_INVALID_PARAMETER);
855
856 /* This is the better place to crash, probe the buffer. */
857 ASMProbeReadBuffer(pvFrame, cbFrame);
858 }
859 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
860 if (!pIf)
861 return VERR_INVALID_HANDLE;
862
863 /*
864 * Lock the network. If there is a trunk retain it and grab its
865 * out-bound lock (this requires leaving the network lock first).
866 * Grabbing the out-bound lock here simplifies things quite a bit
867 * later on, so while this is excessive and a bit expensive it's
868 * not worth caring about right now.
869 */
870 PINTNETNETWORK pNetwork = pIf->pNetwork;
871 int rc = RTSemFastMutexRequest(pNetwork->FastMutex);
872 if (RT_FAILURE(rc))
873 {
874 intnetR0IfRelease(pIf, pSession);
875 return rc;
876 }
877 PINTNETTRUNKIF pTrunkIf = intnetR0TrunkIfRetain(pNetwork->pTrunkIF);
878 if (pTrunkIf)
879 {
880 RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
881
882 if (!intnetR0TrunkIfOutLock(pTrunkIf))
883 {
884 intnetR0TrunkIfRelease(pTrunkIf);
885 intnetR0IfRelease(pIf, pSession);
886 return VERR_SEM_DESTROYED;
887 }
888
889 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
890 if (RT_FAILURE(rc))
891 {
892 intnetR0TrunkIfOutUnlock(pTrunkIf);
893 intnetR0TrunkIfRelease(pTrunkIf);
894 intnetR0IfRelease(pIf, pSession);
895 return rc;
896 }
897 }
898
899 INTNETSG Sg; /** @todo this will have to be changed if we're going to use async sending
900 * with buffer sharing for some OS or service. Darwin copies everything so
901 * I won't bother allocating and managing SGs rigth now. Sorry. */
902
903 /*
904 * Process the argument.
905 */
906 if (pvFrame && cbFrame)
907 {
908 intnetR0SgInitTemp(&Sg, (void *)pvFrame, cbFrame);
909 intnetR0NetworkSend(pIf->pNetwork, pIf, 0, &Sg, !!pTrunkIf);
910 }
911
912 /*
913 * Process the send buffer.
914 */
915 while (pIf->pIntBuf->Send.offRead != pIf->pIntBuf->Send.offWrite)
916 {
917 /* Send the frame if the type is sane. */
918 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pIf->pIntBuf + pIf->pIntBuf->Send.offRead);
919 if (pHdr->u16Type == INTNETHDR_TYPE_FRAME)
920 {
921 void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
922 if (pvCurFrame)
923 {
924 intnetR0SgInitTemp(&Sg, pvCurFrame, pHdr->cbFrame);
925 intnetR0NetworkSend(pIf->pNetwork, pIf, 0, &Sg, !!pTrunkIf);
926 }
927 }
928 /* else: ignore the frame */
929
930 /* Skip to the next frame. */
931 INTNETRingSkipFrame(pIf->pIntBuf, &pIf->pIntBuf->Send);
932 }
933
934 /*
935 * Release the semaphore(s) and release references.
936 */
937 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
938 if (pTrunkIf)
939 {
940 intnetR0TrunkIfOutUnlock(pTrunkIf);
941 intnetR0TrunkIfRelease(pTrunkIf);
942 }
943
944 intnetR0IfRelease(pIf, pSession);
945 return rc;
946}
947
948
949/**
950 * VMMR0 request wrapper for INTNETR0IfSend.
951 *
952 * @returns see INTNETR0IfSend.
953 * @param pIntNet The internal networking instance.
954 * @param pSession The caller's session.
955 * @param pReq The request packet.
956 */
957INTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq)
958{
959 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
960 return VERR_INVALID_PARAMETER;
961 return INTNETR0IfSend(pIntNet, pReq->hIf, pSession, NULL, 0);
962}
963
964
965/**
966 * Maps the default buffer into ring 3.
967 *
968 * @returns VBox status code.
969 * @param pIntNet The instance data.
970 * @param hIf The interface handle.
971 * @param pSession The caller's session.
972 * @param ppRing3Buf Where to store the address of the ring-3 mapping.
973 */
974INTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
975{
976 LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
977
978 /*
979 * Validate input.
980 */
981 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
982 AssertPtrReturn(ppRing3Buf, VERR_INVALID_PARAMETER);
983 *ppRing3Buf = 0;
984 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
985 if (!pIf)
986 return VERR_INVALID_HANDLE;
987
988 /*
989 * ASSUMES that only the process that created an interface can use it.
990 * ASSUMES that we created the ring-3 mapping when selecting or
991 * allocating the buffer.
992 */
993 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
994 if (RT_SUCCESS(rc))
995 {
996 *ppRing3Buf = pIf->pIntBufR3;
997 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
998 }
999
1000 intnetR0IfRelease(pIf, pSession);
1001 LogFlow(("INTNETR0IfGetRing3Buffer: returns %Rrc *ppRing3Buf=%p\n", rc, *ppRing3Buf));
1002 return rc;
1003}
1004
1005
1006/**
1007 * VMMR0 request wrapper for INTNETR0IfGetRing3Buffer.
1008 *
1009 * @returns see INTNETR0IfGetRing3Buffer.
1010 * @param pIntNet The internal networking instance.
1011 * @param pSession The caller's session.
1012 * @param pReq The request packet.
1013 */
1014INTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFGETRING3BUFFERREQ pReq)
1015{
1016 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1017 return VERR_INVALID_PARAMETER;
1018 return INTNETR0IfGetRing3Buffer(pIntNet, pReq->hIf, pSession, &pReq->pRing3Buf);
1019}
1020
1021
1022/**
1023 * Gets the ring-0 address of the current buffer.
1024 *
1025 * @returns VBox status code.
1026 * @param pIntNet The instance data.
1027 * @param hIf The interface handle.
1028 * @param pSession The caller's session.
1029 * @param ppRing0Buf Where to store the address of the ring-3 mapping.
1030 */
1031INTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF *ppRing0Buf)
1032{
1033 LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
1034
1035 /*
1036 * Validate input.
1037 */
1038 AssertPtrReturn(ppRing0Buf, VERR_INVALID_PARAMETER);
1039 *ppRing0Buf = NULL;
1040 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1041 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1042 if (!pIf)
1043 return VERR_INVALID_HANDLE;
1044
1045 /*
1046 * Grab the lock and get the data.
1047 * ASSUMES that the handle isn't closed while we're here.
1048 */
1049 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
1050 if (RT_SUCCESS(rc))
1051 {
1052 *ppRing0Buf = pIf->pIntBuf;
1053
1054 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1055 }
1056 intnetR0IfRelease(pIf, pSession);
1057 LogFlow(("INTNETR0IfGetRing0Buffer: returns %Rrc *ppRing0Buf=%p\n", rc, *ppRing0Buf));
1058 return rc;
1059}
1060
1061
1062#if 0
1063/**
1064 * Gets the physical addresses of the default interface buffer.
1065 *
1066 * @returns VBox status code.
1067 * @param pIntNet The instance data.
1068 * @param hIF The interface handle.
1069 * @param paPages Where to store the addresses. (The reserved fields will be set to zero.)
1070 * @param cPages
1071 */
1072INTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
1073{
1074 /*
1075 * Validate input.
1076 */
1077 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1078 AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
1079 AssertPtrReturn((uint8_t *)&paPages[cPages] - 1, VERR_INVALID_PARAMETER);
1080 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1081 if (!pIf)
1082 return VERR_INVALID_HANDLE;
1083
1084 /*
1085 * Grab the lock and get the data.
1086 * ASSUMES that the handle isn't closed while we're here.
1087 */
1088 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
1089 if (RT_SUCCESS(rc))
1090 {
1091 /** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there
1092 * is no need for any extra bookkeeping here.. */
1093
1094 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
1095 }
1096 intnetR0IfRelease(pIf, pSession);
1097 return VERR_NOT_IMPLEMENTED;
1098}
1099#endif
1100
1101
1102/**
1103 * Sets the promiscuous mode property of an interface.
1104 *
1105 * @returns VBox status code.
1106 * @param pIntNet The instance handle.
1107 * @param hIf The interface handle.
1108 * @param pSession The caller's session.
1109 * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not.
1110 */
1111INTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous)
1112{
1113 LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
1114
1115 /*
1116 * Validate & translate input.
1117 */
1118 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1119 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1120 if (!pIf)
1121 {
1122 Log(("INTNETR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
1123 return VERR_INVALID_HANDLE;
1124 }
1125
1126 /*
1127 * Grab the network semaphore and make the change.
1128 */
1129 int rc;
1130 PINTNETNETWORK pNetwork = pIf->pNetwork;
1131 if (pNetwork)
1132 {
1133 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1134 if (RT_SUCCESS(rc))
1135 {
1136 if (pIf->fPromiscuous != fPromiscuous)
1137 {
1138 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
1139 hIf, !fPromiscuous, !!fPromiscuous));
1140 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);
1141 }
1142
1143 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1144 }
1145 }
1146 else
1147 rc = VERR_WRONG_ORDER;
1148
1149 intnetR0IfRelease(pIf, pSession);
1150 return rc;
1151}
1152
1153
1154/**
1155 * VMMR0 request wrapper for INTNETR0IfSetPromiscuousMode.
1156 *
1157 * @returns see INTNETR0IfSetPromiscuousMode.
1158 * @param pIntNet The internal networking instance.
1159 * @param pSession The caller's session.
1160 * @param pReq The request packet.
1161 */
1162INTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
1163{
1164 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1165 return VERR_INVALID_PARAMETER;
1166 return INTNETR0IfSetPromiscuousMode(pIntNet, pReq->hIf, pSession, pReq->fPromiscuous);
1167}
1168
1169
1170/**
1171 * Sets the MAC address of an interface.
1172 *
1173 * @returns VBox status code.
1174 * @param pIntNet The instance handle.
1175 * @param hIf The interface handle.
1176 * @param pSession The caller's session.
1177 * @param pMAC The new MAC address.
1178 */
1179INTNETR0DECL(int) INTNETR0IfSetMacAddress(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCPDMMAC pMac)
1180{
1181 LogFlow(("INTNETR0IfSetMacAddress: pIntNet=%p hIf=%RX32 pMac=%p:{%.6Rhxs}\n", pIntNet, hIf, pMac, pMac));
1182
1183 /*
1184 * Validate & translate input.
1185 */
1186 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1187 AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
1188 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1189 if (!pIf)
1190 {
1191 Log(("INTNETR0IfSetMacAddress: returns VERR_INVALID_HANDLE\n"));
1192 return VERR_INVALID_HANDLE;
1193 }
1194
1195 /*
1196 * Grab the network semaphore and make the change.
1197 */
1198 int rc;
1199 PINTNETNETWORK pNetwork = pIf->pNetwork;
1200 if (pNetwork)
1201 {
1202 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1203 if (RT_SUCCESS(rc))
1204 {
1205 if (memcmp(&pIf->Mac, pMac, sizeof(pIf->Mac)))
1206 {
1207 Log(("INTNETR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
1208 hIf, &pIf->Mac, pMac));
1209 pIf->Mac = *pMac;
1210 pIf->fMacSet = true;
1211 }
1212
1213 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1214 }
1215 }
1216 else
1217 rc = VERR_WRONG_ORDER;
1218
1219 intnetR0IfRelease(pIf, pSession);
1220 return rc;
1221}
1222
1223
1224/**
1225 * VMMR0 request wrapper for INTNETR0IfSetMacAddress.
1226 *
1227 * @returns see INTNETR0IfSetMacAddress.
1228 * @param pIntNet The internal networking instance.
1229 * @param pSession The caller's session.
1230 * @param pReq The request packet.
1231 */
1232INTNETR0DECL(int) INTNETR0IfSetMacAddressReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq)
1233{
1234 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1235 return VERR_INVALID_PARAMETER;
1236 return INTNETR0IfSetMacAddress(pIntNet, pReq->hIf, pSession, &pReq->Mac);
1237}
1238
1239
1240/**
1241 * Worker for intnetR0IfSetActive.
1242 *
1243 * This function will update the active interface count on the network and
1244 * activate or deactivate the trunk connection if necessary. Note that in
1245 * order to do this it is necessary to abandond the network semaphore.
1246 *
1247 * @returns VBox status code.
1248 * @param pNetwork The network.
1249 * @param fIf The interface.
1250 * @param fActive What to do.
1251 */
1252static int intnetR0NetworkSetIfActive(PINTNETNETWORK pNetwork, PINTNETIF pIf, bool fActive)
1253{
1254 /* quick santiy check */
1255 AssertPtr(pNetwork);
1256 AssertPtr(pIf);
1257
1258 /*
1259 * If we've got a trunk, lock it now in case we need to call out, and
1260 * then lock the network.
1261 */
1262 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
1263 if (pTrunkIf && !intnetR0TrunkIfOutLock(pTrunkIf))
1264 return VERR_SEM_DESTROYED;
1265
1266 int rc = RTSemFastMutexRequest(pNetwork->FastMutex); AssertRC(rc);
1267 if (RT_SUCCESS(rc))
1268 {
1269 bool fNetworkLocked = true;
1270
1271 /*
1272 * Make the change if necessary.
1273 */
1274 if (pIf->fActive != fActive)
1275 {
1276 pIf->fActive = fActive;
1277
1278 uint32_t const cActiveIFs = pNetwork->cActiveIFs;
1279 Assert((int32_t)cActiveIFs + (fActive ? 1 : -1) >= 0);
1280 pNetwork->cActiveIFs += fActive ? 1 : -1;
1281
1282 if ( pTrunkIf
1283 && ( !pNetwork->cActiveIFs
1284 || !cActiveIFs))
1285 {
1286 /*
1287 * We'll have to change the trunk status, so, leave
1288 * the network semaphore so we don't create any deadlocks.
1289 */
1290 int rc2 = RTSemFastMutexRelease(pNetwork->FastMutex); AssertRC(rc2);
1291 fNetworkLocked = false;
1292
1293 if (pTrunkIf->pIfPort)
1294 pTrunkIf->pIfPort->pfnSetActive(pTrunkIf->pIfPort, fActive);
1295 }
1296 }
1297
1298 if (fNetworkLocked)
1299 RTSemFastMutexRelease(pNetwork->FastMutex);
1300 }
1301 if (pTrunkIf)
1302 intnetR0TrunkIfOutUnlock(pTrunkIf);
1303 return rc;
1304}
1305
1306
1307/**
1308 * Activates or deactivates a interface.
1309 *
1310 * This is used to enable and disable the trunk connection on demans as well as
1311 * know when not to expect an interface to want to receive packets.
1312 *
1313 * @returns VBox status code.
1314 * @param pIf The interface.
1315 * @param fActive What to do.
1316 */
1317static int intnetR0IfSetActive(PINTNETIF pIf, bool fActive)
1318{
1319 /* quick sanity check */
1320 AssertPtrReturn(pIf, VERR_INVALID_POINTER);
1321
1322 /*
1323 * Hand it to the network since it might involve the trunk
1324 * and things are tricky there wrt to locking order.
1325 */
1326 PINTNETNETWORK pNetwork = pIf->pNetwork;
1327 if (!pNetwork)
1328 return VERR_WRONG_ORDER;
1329 return intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
1330}
1331
1332
1333/**
1334 * Sets the active property of an interface.
1335 *
1336 * @returns VBox status code.
1337 * @param pIntNet The instance handle.
1338 * @param hIf The interface handle.
1339 * @param pSession The caller's session.
1340 * @param fActive The new state.
1341 */
1342INTNETR0DECL(int) INTNETR0IfSetActive(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive)
1343{
1344 LogFlow(("INTNETR0IfSetActive: pIntNet=%p hIf=%RX32 fActive=%RTbool\n", pIntNet, hIf, fActive));
1345
1346 /*
1347 * Validate & translate input.
1348 */
1349 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1350 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1351 if (!pIf)
1352 {
1353 Log(("INTNETR0IfSetActive: returns VERR_INVALID_HANDLE\n"));
1354 return VERR_INVALID_HANDLE;
1355 }
1356
1357 /*
1358 * Hand it to the network since it might involve the trunk
1359 * and things are tricky there wrt to locking order.
1360 */
1361 int rc;
1362 PINTNETNETWORK pNetwork = pIf->pNetwork;
1363 if (pNetwork)
1364 rc = intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
1365 else
1366 rc = VERR_WRONG_ORDER;
1367
1368 intnetR0IfRelease(pIf, pSession);
1369 return rc;
1370}
1371
1372
1373/**
1374 * VMMR0 request wrapper for INTNETR0IfSetActive.
1375 *
1376 * @returns see INTNETR0IfSetActive.
1377 * @param pIntNet The internal networking instance.
1378 * @param pSession The caller's session.
1379 * @param pReq The request packet.
1380 */
1381INTNETR0DECL(int) INTNETR0IfSetActiveReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq)
1382{
1383 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1384 return VERR_INVALID_PARAMETER;
1385 return INTNETR0IfSetActive(pIntNet, pReq->hIf, pSession, pReq->fActive);
1386}
1387
1388
1389/**
1390 * Wait for the interface to get signaled.
1391 * The interface will be signaled when is put into the receive buffer.
1392 *
1393 * @returns VBox status code.
1394 * @param pIntNet The instance handle.
1395 * @param hIf The interface handle.
1396 * @param pSession The caller's session.
1397 * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be
1398 * used if indefinite wait is desired.
1399 */
1400INTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies)
1401{
1402 Log4(("INTNETR0IfWait: pIntNet=%p hIf=%RX32 cMillies=%u\n", pIntNet, hIf, cMillies));
1403
1404 /*
1405 * Get and validate essential handles.
1406 */
1407 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1408 PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
1409 if (!pIf)
1410 {
1411 Log(("INTNETR0IfWait: returns VERR_INVALID_HANDLE\n"));
1412 return VERR_INVALID_HANDLE;
1413 }
1414 const INTNETIFHANDLE hIfSelf = pIf->hIf;
1415 const RTSEMEVENT Event = pIf->Event;
1416 if ( hIfSelf != hIf /* paranoia */
1417 && Event != NIL_RTSEMEVENT)
1418 {
1419 Log(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
1420 return VERR_SEM_DESTROYED;
1421 }
1422
1423 /*
1424 * It is tempting to check if there is data to be read here,
1425 * but the problem with such an approach is that it will cause
1426 * one unnecessary supervisor->user->supervisor trip. There is
1427 * already a slight risk for such, so no need to increase it.
1428 */
1429
1430 /*
1431 * Increment the number of waiters before starting the wait.
1432 * Upon wakeup we must assert reality, checking that we're not
1433 * already destroyed or in the process of being destroyed. This
1434 * code must be aligned with the waiting code in intnetR0IfDestruct.
1435 */
1436 ASMAtomicIncU32(&pIf->cSleepers);
1437 int rc = RTSemEventWaitNoResume(Event, cMillies);
1438 if (pIf->Event == Event)
1439 {
1440 ASMAtomicDecU32(&pIf->cSleepers);
1441 if (!pIf->fDestroying)
1442 {
1443 intnetR0IfRelease(pIf, pSession);
1444 if (pIf->hIf != hIf)
1445 rc = VERR_SEM_DESTROYED;
1446 }
1447 else
1448 rc = VERR_SEM_DESTROYED;
1449 }
1450 else
1451 rc = VERR_SEM_DESTROYED;
1452 Log4(("INTNETR0IfWait: returns %Rrc\n", rc));
1453 return rc;
1454}
1455
1456
1457/**
1458 * VMMR0 request wrapper for INTNETR0IfWait.
1459 *
1460 * @returns see INTNETR0IfWait.
1461 * @param pIntNet The internal networking instance.
1462 * @param pSession The caller's session.
1463 * @param pReq The request packet.
1464 */
1465INTNETR0DECL(int) INTNETR0IfWaitReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq)
1466{
1467 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1468 return VERR_INVALID_PARAMETER;
1469 return INTNETR0IfWait(pIntNet, pReq->hIf, pSession, pReq->cMillies);
1470}
1471
1472
1473/**
1474 * Close an interface.
1475 *
1476 * @returns VBox status code.
1477 * @param pIntNet The instance handle.
1478 * @param hIf The interface handle.
1479 * @param pSession The caller's session.
1480 */
1481INTNETR0DECL(int) INTNETR0IfClose(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession)
1482{
1483 LogFlow(("INTNETR0IfClose: pIntNet=%p hIf=%RX32\n", pIntNet, hIf));
1484
1485 /*
1486 * Validate and free the handle.
1487 */
1488 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1489 PINTNETIF pIf = (PINTNETIF)RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pSession);
1490 if (!pIf)
1491 return VERR_INVALID_HANDLE;
1492
1493 /* mark the handle as freed so intnetR0IfDestruct won't free it again. */
1494 ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
1495
1496
1497 /*
1498 * Release the references to the interface object (handle + free lookup).
1499 * But signal the event semaphore first so any waiter holding a reference
1500 * will wake up too (he'll see hIf == invalid and return correctly).
1501 */
1502 RTSemEventSignal(pIf->Event);
1503
1504 void *pvObj = pIf->pvObj;
1505 intnetR0IfRelease(pIf, pSession); /* (RTHandleTableFreeWithCtx) */
1506
1507 int rc = SUPR0ObjRelease(pvObj, pSession);
1508 LogFlow(("INTNETR0IfClose: returns %Rrc\n", rc));
1509 return rc;
1510}
1511
1512
1513/**
1514 * VMMR0 request wrapper for INTNETR0IfCloseReq.
1515 *
1516 * @returns see INTNETR0IfClose.
1517 * @param pIntNet The internal networking instance.
1518 * @param pSession The caller's session.
1519 * @param pReq The request packet.
1520 */
1521INTNETR0DECL(int) INTNETR0IfCloseReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq)
1522{
1523 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1524 return VERR_INVALID_PARAMETER;
1525 return INTNETR0IfClose(pIntNet, pReq->hIf, pSession);
1526}
1527
1528
1529/**
1530 * Interface destructor callback.
1531 * This is called for reference counted objectes when the count reaches 0.
1532 *
1533 * @param pvObj The object pointer.
1534 * @param pvUser1 Pointer to the interface.
1535 * @param pvUser2 Pointer to the INTNET instance data.
1536 */
1537static DECLCALLBACK(void) intnetR0IfDestruct(void *pvObj, void *pvUser1, void *pvUser2)
1538{
1539 PINTNETIF pIf = (PINTNETIF)pvUser1;
1540 PINTNET pIntNet = (PINTNET)pvUser2;
1541 Log(("intnetR0IfDestruct: pvObj=%p pIf=%p pIntNet=%p hIf=%#x\n", pvObj, pIf, pIntNet, pIf->hIf));
1542
1543 RTSemFastMutexRequest(pIntNet->FastMutex);
1544
1545 /*
1546 * Mark the interface as being destroyed so the waiter
1547 * can behave appropriately (theoretical case).
1548 */
1549 ASMAtomicWriteBool(&pIf->fDestroying, true);
1550
1551 /*
1552 * Delete the interface handle so the object no longer can be used.
1553 * (Can happen if the client didn't close its session.)
1554 */
1555 INTNETIFHANDLE hIf = ASMAtomicXchgU32(&pIf->hIf, INTNET_HANDLE_INVALID);
1556 if (hIf != INTNET_HANDLE_INVALID)
1557 {
1558 void *pvObj2 = RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pIf->pSession);
1559 AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%#x pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));
1560 }
1561
1562 /*
1563 * If we've got a network deactivate and unlink ourselves from it.
1564 * Because of cleanup order we might be an orphan now.
1565 */
1566 PINTNETNETWORK pNetwork = pIf->pNetwork;
1567 if (pNetwork)
1568 {
1569 intnetR0IfSetActive(pIf, false);
1570
1571 if (pNetwork->pIFs == pIf)
1572 pNetwork->pIFs = pIf->pNext;
1573 else
1574 {
1575 PINTNETIF pPrev = pNetwork->pIFs;
1576 while (pPrev)
1577 {
1578 if (pPrev->pNext == pIf)
1579 {
1580 pPrev->pNext = pIf->pNext;
1581 break;
1582 }
1583 pPrev = pPrev->pNext;
1584 }
1585 Assert(pPrev);
1586 }
1587 pIf->pNext = NULL;
1588
1589 /*
1590 * Release our reference to the network.
1591 */
1592 RTSemFastMutexRelease(pIntNet->FastMutex);
1593
1594 SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
1595 pIf->pNetwork = NULL;
1596 }
1597 else
1598 RTSemFastMutexRelease(pIntNet->FastMutex);
1599
1600 /*
1601 * Wakeup anyone waiting on this interface.
1602 *
1603 * We *must* make sure they have woken up properly and realized
1604 * that the interface is no longer valid.
1605 */
1606 if (pIf->Event != NIL_RTSEMEVENT)
1607 {
1608 RTSEMEVENT Event = pIf->Event;
1609 unsigned cMaxWait = 0x1000;
1610 while (pIf->cSleepers && cMaxWait-- > 0)
1611 {
1612 RTSemEventSignal(Event);
1613 RTThreadYield();
1614 }
1615 if (pIf->cSleepers)
1616 {
1617 RTThreadSleep(1);
1618
1619 cMaxWait = pIf->cSleepers;
1620 while (pIf->cSleepers && cMaxWait-- > 0)
1621 {
1622 RTSemEventSignal(Event);
1623 RTThreadSleep(10);
1624 }
1625 }
1626
1627 RTSemEventDestroy(Event);
1628 pIf->Event = NIL_RTSEMEVENT;
1629 }
1630
1631 /*
1632 * Unmap user buffer.
1633 */
1634 if (pIf->pIntBuf != pIf->pIntBufDefault)
1635 {
1636 /** @todo user buffer */
1637 }
1638
1639 /*
1640 * Unmap and Free the default buffer.
1641 */
1642 if (pIf->pIntBufDefault)
1643 {
1644 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
1645 pIf->pIntBufDefault = NULL;
1646 pIf->pIntBufDefaultR3 = 0;
1647 pIf->pIntBuf = NULL;
1648 pIf->pIntBufR3 = 0;
1649 }
1650
1651 /*
1652 * The interface.
1653 */
1654 pIf->pvObj = NULL;
1655 RTMemFree(pIf);
1656}
1657
1658
1659/**
1660 * Creates a new network interface.
1661 *
1662 * The call must have opened the network for the new interface
1663 * and is responsible for closing it on failure. On success
1664 * it must leave the network opened so the interface destructor
1665 * can close it.
1666 *
1667 * @returns VBox status code.
1668 * @param pNetwork The network.
1669 * @param pSession The session handle.
1670 * @param cbSend The size of the send buffer.
1671 * @param cbRecv The size of the receive buffer.
1672 * @param phIf Where to store the interface handle.
1673 */
1674static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf)
1675{
1676 LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u phIf=%p\n",
1677 pNetwork, pSession, cbSend, cbRecv, phIf));
1678
1679 /*
1680 * Assert input.
1681 */
1682 AssertPtr(pNetwork);
1683 AssertPtr(phIf);
1684 AssertPtr(pfCloseNetwork);
1685 *pfCloseNetwork = false;
1686
1687 /*
1688 * Allocate and initialize the interface structure.
1689 */
1690 PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
1691 if (!pIf)
1692 return VERR_NO_MEMORY;
1693 //pIf->pNext = NULL;
1694 memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */
1695 //pIf->fMacSet = false;
1696 //pIf->fPromiscuous = false;
1697 //pIf->fActive = false;
1698 //pIf->fDestroying = false;
1699 //pIf->pIntBuf = 0;
1700 //pIf->pIntBufR3 = NIL_RTR3PTR;
1701 //pIf->pIntBufDefault = 0;
1702 //pIf->pIntBufDefaultR3 = NIL_RTR3PTR;
1703 //pIf->cYields = 0;
1704 pIf->Event = NIL_RTSEMEVENT;
1705 //pIf->cSleepers = 0;
1706 pIf->hIf = INTNET_HANDLE_INVALID;
1707 pIf->pNetwork = pNetwork;
1708 pIf->pSession = pSession;
1709 //pIf->pvObj = NULL;
1710 int rc = RTSemEventCreate((PRTSEMEVENT)&pIf->Event);
1711 if (RT_SUCCESS(rc))
1712 {
1713 /*
1714 * Create the default buffer.
1715 */
1716 /** @todo adjust with minimums and apply defaults here. */
1717 cbRecv = RT_ALIGN(RT_MAX(cbRecv, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
1718 cbSend = RT_ALIGN(RT_MAX(cbSend, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
1719 const unsigned cbBuf = RT_ALIGN(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR)) + cbRecv + cbSend;
1720 rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
1721 if (RT_SUCCESS(rc))
1722 {
1723 ASMMemZero32(pIf->pIntBufDefault, cbBuf); /** @todo I thought I specified these buggers as clearing the memory... */
1724
1725 pIf->pIntBuf = pIf->pIntBufDefault;
1726 pIf->pIntBufR3 = pIf->pIntBufDefaultR3;
1727 pIf->pIntBuf->cbBuf = cbBuf;
1728 pIf->pIntBuf->cbRecv = cbRecv;
1729 pIf->pIntBuf->cbSend = cbSend;
1730 /* receive ring buffer. */
1731 pIf->pIntBuf->Recv.offStart = RT_ALIGN_32(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR));
1732 pIf->pIntBuf->Recv.offRead = pIf->pIntBuf->Recv.offStart;
1733 pIf->pIntBuf->Recv.offWrite = pIf->pIntBuf->Recv.offStart;
1734 pIf->pIntBuf->Recv.offEnd = pIf->pIntBuf->Recv.offStart + cbRecv;
1735 /* send ring buffer. */
1736 pIf->pIntBuf->Send.offStart = pIf->pIntBuf->Recv.offEnd;
1737 pIf->pIntBuf->Send.offRead = pIf->pIntBuf->Send.offStart;
1738 pIf->pIntBuf->Send.offWrite = pIf->pIntBuf->Send.offStart;
1739 pIf->pIntBuf->Send.offEnd = pIf->pIntBuf->Send.offStart + cbSend;
1740
1741 /*
1742 * Link the interface to the network.
1743 */
1744 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1745 if (RT_SUCCESS(rc))
1746 {
1747 pIf->pNext = pNetwork->pIFs;
1748 pNetwork->pIFs = pIf;
1749 RTSemFastMutexRelease(pNetwork->FastMutex);
1750
1751 /*
1752 * Register the interface with the session.
1753 */
1754 pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet);
1755 if (pIf->pvObj)
1756 {
1757 rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf);
1758 if (RT_SUCCESS(rc))
1759 {
1760 *phIf = pIf->hIf;
1761 Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%p cbSend=%u cbRecv=%u cbBuf=%u\n",
1762 *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
1763 return VINF_SUCCESS;
1764 }
1765
1766 SUPR0ObjRelease(pIf->pvObj, pSession);
1767 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
1768 return rc;
1769 }
1770
1771 RTSemFastMutexDestroy(pNetwork->FastMutex);
1772 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
1773 }
1774
1775 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
1776 pIf->pIntBufDefault = NULL;
1777 pIf->pIntBuf = NULL;
1778 }
1779
1780 RTSemEventDestroy(pIf->Event);
1781 pIf->Event = NIL_RTSEMEVENT;
1782 }
1783 RTMemFree(pIf);
1784 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
1785 *pfCloseNetwork = true;
1786 return rc;
1787}
1788
1789
1790
1791
1792
1793/** @copydoc INTNETTRUNKSWPORT::pfnSetSGPhys */
1794static DECLCALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
1795{
1796 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1797 AssertMsgFailed(("Not implemented because it wasn't required on Darwin\n"));
1798 return ASMAtomicXchgBool(&pThis->fPhysSG, fEnable);
1799}
1800
1801
1802/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
1803static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
1804{
1805 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1806 PINTNETNETWORK pNetwork = pThis->pNetwork;
1807
1808 /* assert some sanity */
1809 AssertPtrReturn(pNetwork, false);
1810 AssertReturn(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX, false);
1811 AssertPtr(pSG);
1812 Assert(fSrc);
1813
1814 /*
1815 * Lock the network and send the frame to it.
1816 */
1817 int rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1818 AssertRCReturn(rc, false);
1819
1820 bool fRc;
1821 if (RT_LIKELY(pNetwork->cActiveIFs > 0))
1822 fRc = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, false /* fTrunkLocked */);
1823 else
1824 fRc = false; /* don't drop it */
1825
1826 rc = RTSemFastMutexRelease(pNetwork->FastMutex);
1827 AssertRC(rc);
1828
1829 return fRc;
1830}
1831
1832
1833/** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */
1834static DECLCALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
1835{
1836 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1837 PINTNETNETWORK pNetwork = pThis->pNetwork;
1838
1839 /* assert some sanity */
1840 AssertPtrReturnVoid(pNetwork);
1841 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
1842 AssertPtr(pSG);
1843 Assert(pSG->cUsers > 0);
1844
1845 /* do it. */
1846 ++pSG->cUsers;
1847}
1848
1849
1850/** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */
1851static DECLCALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
1852{
1853 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1854 PINTNETNETWORK pNetwork = pThis->pNetwork;
1855
1856 /* assert some sanity */
1857 AssertPtrReturnVoid(pNetwork);
1858 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
1859 AssertPtr(pSG);
1860 Assert(pSG->cUsers > 0);
1861
1862 /*
1863 * Free it?
1864 */
1865 if (!--pSG->cUsers)
1866 {
1867 /** @todo later */
1868 }
1869}
1870
1871
1872/**
1873 * Retain the trunk interface.
1874 *
1875 * @returns pThis if retained.
1876 *
1877 * @param pThis The trunk.
1878 *
1879 * @remarks Any locks.
1880 */
1881static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis)
1882{
1883 if (pThis && pThis->pIfPort)
1884 {
1885 pThis->pIfPort->pfnRetain(pThis->pIfPort);
1886 return pThis;
1887 }
1888 return NULL;
1889}
1890
1891
1892/**
1893 * Release the trunk interface.
1894 *
1895 * @param pThis The trunk.
1896 */
1897static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis)
1898{
1899 if (pThis && pThis->pIfPort)
1900 pThis->pIfPort->pfnRelease(pThis->pIfPort);
1901}
1902
1903
1904/**
1905 * Takes the out-bound trunk lock.
1906 *
1907 * This will ensure that pIfPort is valid.
1908 *
1909 * @returns success indicator.
1910 * @param pThis The trunk.
1911 *
1912 * @remarks No locks other than the create/destroy one.
1913 */
1914static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis)
1915{
1916 AssertPtrReturn(pThis, false);
1917 int rc = RTSemFastMutexRequest(pThis->FastMutex);
1918 if (RT_SUCCESS(rc))
1919 {
1920 if (RT_LIKELY(pThis->pIfPort))
1921 return true;
1922 RTSemFastMutexRelease(pThis->FastMutex);
1923 }
1924 else
1925 AssertMsg(rc == VERR_SEM_DESTROYED, ("%Rrc\n", rc));
1926 return false;
1927}
1928
1929
1930/**
1931 * Releases the out-bound trunk lock.
1932 *
1933 * @param pThis The trunk.
1934 */
1935static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis)
1936{
1937 if (pThis)
1938 {
1939 int rc = RTSemFastMutexRelease(pThis->FastMutex);
1940 AssertRC(rc);
1941 }
1942}
1943
1944
1945/**
1946 * Activates the trunk interface.
1947 *
1948 * @param pThis The trunk.
1949 * @param fActive What to do with it.
1950 *
1951 * @remarks Caller may only own the create/destroy lock.
1952 */
1953static void intnetR0TrunkIfActivate(PINTNETTRUNKIF pThis, bool fActive)
1954{
1955 if (intnetR0TrunkIfOutLock(pThis))
1956 {
1957 pThis->pIfPort->pfnSetActive(pThis->pIfPort, fActive);
1958 intnetR0TrunkIfOutUnlock(pThis);
1959 }
1960}
1961
1962
1963/**
1964 * Shutdown the trunk interface.
1965 *
1966 * @param pThis The trunk.
1967 * @param pNetworks The network.
1968 *
1969 * @remarks The caller must *NOT* hold the network lock. The global
1970 * create/destroy lock is fine though.
1971 */
1972static void intnetR0TrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork)
1973{
1974 /* assert sanity */
1975 if (!pThis)
1976 return;
1977 AssertPtr(pThis);
1978 Assert(pThis->pNetwork == pNetwork);
1979 AssertPtrNull(pThis->pIfPort);
1980
1981 /*
1982 * The interface has already been deactivated, we just to wait for
1983 * it to become idle before we can disconnect and release it.
1984 */
1985 PINTNETTRUNKIFPORT pIfPort = pThis->pIfPort;
1986 if (pIfPort)
1987 {
1988 intnetR0TrunkIfOutLock(pThis);
1989
1990 /* unset it */
1991 pThis->pIfPort = NULL;
1992
1993 /* wait in portions so we can complain ever now an then. */
1994 uint64_t StartTS = RTTimeSystemNanoTS();
1995 int rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
1996 if (RT_FAILURE(rc))
1997 {
1998 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
1999 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2000 Assert(rc == VERR_TIMEOUT);
2001 while ( RT_FAILURE(rc)
2002 && RTTimeSystemNanoTS() - StartTS < UINT64_C(30000000000)) /* 30 sec */
2003 rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
2004 if (rc == VERR_TIMEOUT)
2005 {
2006 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
2007 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2008 while ( rc == VERR_TIMEOUT
2009 && RTTimeSystemNanoTS() - StartTS < UINT64_C(360000000000)) /* 360 sec */
2010 rc = pIfPort->pfnWaitForIdle(pIfPort, 30*1000);
2011 if (RT_FAILURE(rc))
2012 {
2013 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc), giving up.\n",
2014 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
2015 AssertRC(rc);
2016 }
2017 }
2018 }
2019
2020 /* disconnect & release it. */
2021 pIfPort->pfnDisconnectAndRelease(pIfPort);
2022 }
2023
2024 /*
2025 * Free up the resources.
2026 */
2027 RTSEMFASTMUTEX FastMutex = pThis->FastMutex;
2028 pThis->FastMutex = NIL_RTSEMFASTMUTEX;
2029 pThis->pNetwork = NULL;
2030 RTSemFastMutexRelease(FastMutex);
2031 RTSemFastMutexDestroy(FastMutex);
2032 RTMemFree(pThis);
2033}
2034
2035
2036/**
2037 * Creates the trunk connection (if any).
2038 *
2039 * @returns VBox status code.
2040 *
2041 * @param pNetwork The newly created network.
2042 * @param pSession The session handle.
2043 */
2044static int intnetR0NetworkCreateTrunkIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
2045{
2046 const char *pszName;
2047 switch (pNetwork->enmTrunkType)
2048 {
2049 /*
2050 * The 'None' case, simple.
2051 */
2052 case kIntNetTrunkType_None:
2053 case kIntNetTrunkType_WhateverNone:
2054 return VINF_SUCCESS;
2055
2056 /* Can't happen, but makes GCC happy. */
2057 default:
2058 return VERR_NOT_IMPLEMENTED;
2059
2060 /*
2061 * Translate enum to component factory name.
2062 */
2063 case kIntNetTrunkType_NetFlt:
2064 pszName = "VBoxNetFlt";
2065 break;
2066 case kIntNetTrunkType_NetTap:
2067 pszName = "VBoxNetTap";
2068 break;
2069 case kIntNetTrunkType_SrvNat:
2070 pszName = "VBoxSrvNat";
2071 break;
2072 }
2073
2074 /*
2075 * Allocate the trunk interface.
2076 */
2077 PINTNETTRUNKIF pTrunkIF = (PINTNETTRUNKIF)RTMemAllocZ(sizeof(*pTrunkIF));
2078 if (!pTrunkIF)
2079 return VERR_NO_MEMORY;
2080 pTrunkIF->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION;
2081 pTrunkIF->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys;
2082 pTrunkIF->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv;
2083 pTrunkIF->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain;
2084 pTrunkIF->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease;
2085 pTrunkIF->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION;
2086 //pTrunkIF->pIfPort = NULL;
2087 pTrunkIF->pNetwork = pNetwork;
2088 //pTrunkIF->fPhysSG = false;
2089 //pTrunkIF->fPromiscuousWire = false;
2090 int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex);
2091 if (RT_SUCCESS(rc))
2092 {
2093#ifdef IN_RING0 /* (testcase is ring-3) */
2094 /*
2095 * Query the factory we want, then use it create and connect the trunk.
2096 */
2097 PINTNETTRUNKFACTORY pTrunkFactory = NULL;
2098 rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
2099 if (RT_SUCCESS(rc))
2100 {
2101 rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort, &pTrunkIF->pIfPort);
2102 pTrunkFactory->pfnRelease(pTrunkFactory);
2103 if (RT_SUCCESS(rc))
2104 {
2105 Assert(pTrunkIF->pIfPort);
2106 pNetwork->pTrunkIF = pTrunkIF;
2107 LogFlow(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s Network=%s\n",
2108 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
2109 return VINF_SUCCESS;
2110 }
2111 }
2112#endif /* IN_RING0 */
2113 RTSemFastMutexDestroy(pTrunkIF->FastMutex);
2114 }
2115 RTMemFree(pTrunkIF);
2116 LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
2117 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
2118 return rc;
2119}
2120
2121
2122
2123/**
2124 * Close a network which was opened/created using intnetR0OpenNetwork()/intnetR0CreateNetwork().
2125 *
2126 * @param pNetwork The network to close.
2127 * @param pSession The session handle.
2128 */
2129static int intnetR0NetworkClose(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
2130{
2131 LogFlow(("intnetR0NetworkClose: pNetwork=%p pSession=%p\n", pNetwork, pSession));
2132 AssertPtrReturn(pSession, VERR_INVALID_PARAMETER);
2133 AssertPtrReturn(pNetwork, VERR_INVALID_PARAMETER);
2134
2135 int rc = SUPR0ObjRelease(pNetwork->pvObj, pSession);
2136 LogFlow(("intnetR0NetworkClose: return %Rrc\n", rc));
2137 return rc;
2138}
2139
2140
2141/**
2142 * Object destructor callback.
2143 * This is called for reference counted objectes when the count reaches 0.
2144 *
2145 * @param pvObj The object pointer.
2146 * @param pvUser1 Pointer to the network.
2147 * @param pvUser2 Pointer to the INTNET instance data.
2148 */
2149static DECLCALLBACK(void) intnetR0NetworkDestruct(void *pvObj, void *pvUser1, void *pvUser2)
2150{
2151 PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1;
2152 PINTNET pIntNet = (PINTNET)pvUser2;
2153 Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
2154 Assert(pNetwork->pIntNet == pIntNet);
2155
2156 /* take the create/destroy sem. */
2157 RTSemFastMutexRequest(pIntNet->FastMutex);
2158
2159 /*
2160 * Deactivate the trunk connection first (if any).
2161 */
2162 if (pNetwork->pTrunkIF)
2163 intnetR0TrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */);
2164
2165 /*
2166 * Unlink the network.
2167 * Note that it needn't be in the list if we failed during creation.
2168 */
2169 PINTNETNETWORK pPrev = pIntNet->pNetworks;
2170 if (pPrev == pNetwork)
2171 pIntNet->pNetworks = pNetwork->pNext;
2172 else
2173 {
2174 for (; pPrev; pPrev = pPrev->pNext)
2175 if (pPrev->pNext == pNetwork)
2176 {
2177 pPrev->pNext = pNetwork->pNext;
2178 break;
2179 }
2180 }
2181 pNetwork->pNext = NULL;
2182 pNetwork->pvObj = NULL;
2183
2184 /*
2185 * Because of the undefined order of the per session object dereferencing when closing a session,
2186 * we have to handle the case where the network is destroyed before the interfaces. We'll
2187 * deal with this by simply orphaning the interfaces.
2188 */
2189 RTSemFastMutexRequest(pNetwork->FastMutex);
2190
2191 PINTNETIF pCur = pNetwork->pIFs;
2192 while (pCur)
2193 {
2194 PINTNETIF pNext = pCur->pNext;
2195 pCur->pNext = NULL;
2196 pCur->pNetwork = NULL;
2197 pCur = pNext;
2198 }
2199
2200 /* Grab and zap the trunk pointer before leaving the mutex. */
2201 PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;
2202 pNetwork->pTrunkIF = NULL;
2203
2204 RTSemFastMutexRelease(pNetwork->FastMutex);
2205
2206 /*
2207 * If there is a trunk, delete it.
2208 * Note that this may tak a while if we're unlucky...
2209 */
2210 if (pTrunkIF)
2211 intnetR0TrunkIfDestroy(pTrunkIF, pNetwork);
2212
2213 /*
2214 * Free resources.
2215 */
2216 RTSemFastMutexDestroy(pNetwork->FastMutex);
2217 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
2218 RTMemFree(pNetwork);
2219
2220 /* release the create/destroy sem. (can be done before trunk destruction.) */
2221 RTSemFastMutexRelease(pIntNet->FastMutex);
2222}
2223
2224
2225/**
2226 * Opens an existing network.
2227 *
2228 * @returns VBox status code.
2229 * @param pIntNet The instance data.
2230 * @param pSession The current session.
2231 * @param pszNetwork The network name. This has a valid length.
2232 * @param enmTrunkType The trunk type.
2233 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
2234 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
2235 * @param ppNetwork Where to store the pointer to the network on success.
2236 */
2237static int intnetR0OpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
2238 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
2239{
2240 LogFlow(("intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
2241 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
2242
2243 /* just pro forma validation, the caller is internal. */
2244 AssertPtr(pIntNet);
2245 AssertPtr(pSession);
2246 AssertPtr(pszNetwork);
2247 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
2248 AssertPtr(pszTrunk);
2249 Assert(!(fFlags & ~(INTNET_OPEN_FLAGS_MASK)));
2250 AssertPtr(ppNetwork);
2251 *ppNetwork = NULL;
2252
2253 /*
2254 * Search networks by name.
2255 */
2256 PINTNETNETWORK pCur;
2257 uint8_t cchName = strlen(pszNetwork);
2258 Assert(cchName && cchName < sizeof(pCur->szName)); /* caller ensures this */
2259
2260 pCur = pIntNet->pNetworks;
2261 while (pCur)
2262 {
2263 if ( pCur->cchName == cchName
2264 && !memcmp(pCur->szName, pszNetwork, cchName))
2265 {
2266 /*
2267 * Found the network, now check that we have the same ideas
2268 * about the trunk setup and security.
2269 */
2270 int rc;
2271 if ( enmTrunkType == kIntNetTrunkType_WhateverNone
2272 || ( pCur->enmTrunkType == enmTrunkType
2273 && !strcmp(pCur->szTrunk, pszTrunk)))
2274 {
2275 if (!((pCur->fFlags ^ fFlags) & INTNET_OPEN_FLAGS_SECURITY_XOR_MASK))
2276 {
2277
2278 /*
2279 * Increment the reference and check that the session
2280 * can access this network.
2281 */
2282 rc = SUPR0ObjAddRef(pCur->pvObj, pSession);
2283 if (RT_SUCCESS(rc))
2284 {
2285 if (!(pCur->fFlags & INTNET_OPEN_FLAGS_PUBLIC))
2286 rc = SUPR0ObjVerifyAccess(pCur->pvObj, pSession, pCur->szName);
2287 if (RT_SUCCESS(rc))
2288 {
2289 pCur->fFlags |= fFlags & INTNET_OPEN_FLAGS_SECURITY_OR_MASK;
2290
2291 *ppNetwork = pCur;
2292 }
2293 else
2294 SUPR0ObjRelease(pCur->pvObj, pSession);
2295 }
2296 else if (rc == VERR_WRONG_ORDER)
2297 rc = VERR_NOT_FOUND; /* destruction race, pretend the other isn't there. */
2298 }
2299 else
2300 rc = VERR_INTNET_INCOMPATIBLE_FLAGS;
2301 }
2302 else
2303 rc = VERR_INTNET_INCOMPATIBLE_TRUNK;
2304
2305 LogFlow(("intnetR0OpenNetwork: returns %Rrc *ppNetwork=%p\n", rc, *ppNetwork));
2306 return rc;
2307 }
2308 pCur = pCur->pNext;
2309 }
2310
2311 LogFlow(("intnetR0OpenNetwork: returns VERR_NOT_FOUND\n"));
2312 return VERR_NOT_FOUND;
2313}
2314
2315
2316/**
2317 * Creates a new network.
2318 *
2319 * The call must own the INTNET::FastMutex and has already attempted
2320 * opening the network and found it to be non-existing.
2321 *
2322 * @returns VBox status code.
2323 * @param pIntNet The instance data.
2324 * @param pSession The session handle.
2325 * @param pszNetwork The name of the network. This must be at least one character long and no longer
2326 * than the INTNETNETWORK::szName.
2327 * @param enmTrunkType The trunk type.
2328 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
2329 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
2330 * @param ppNetwork Where to store the network. In the case of failure whatever is returned
2331 * here should be dereferenced outside the INTNET::FastMutex.
2332 */
2333static int intnetR0CreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
2334 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
2335{
2336 LogFlow(("intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
2337 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
2338
2339 /* just pro forma validation, the caller is internal. */
2340 AssertPtr(pIntNet);
2341 AssertPtr(pSession);
2342 AssertPtr(pszNetwork);
2343 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
2344 AssertPtr(pszTrunk);
2345 Assert(!(fFlags & ~INTNET_OPEN_FLAGS_MASK));
2346 AssertPtr(ppNetwork);
2347 *ppNetwork = NULL;
2348
2349 /*
2350 * Allocate and initialize.
2351 */
2352 PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(sizeof(*pNew));
2353 if (!pNew)
2354 return VERR_NO_MEMORY;
2355 int rc = RTSemFastMutexCreate(&pNew->FastMutex);
2356 if (RT_SUCCESS(rc))
2357 {
2358 //pNew->pIFs = NULL;
2359 pNew->pIntNet = pIntNet;
2360 //pNew->cActiveIFs = 0;
2361 pNew->fFlags = fFlags;
2362 size_t cchName = strlen(pszNetwork);
2363 pNew->cchName = cchName;
2364 Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */
2365 memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */
2366 pNew->enmTrunkType = enmTrunkType;
2367 Assert(strlen(pszTrunk) < sizeof(pNew->szTrunk)); /* caller's responsibility. */
2368 strcpy(pNew->szTrunk, pszTrunk);
2369
2370 /*
2371 * Register the object in the current session and link it into the network list.
2372 */
2373 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);
2374 if (pNew->pvObj)
2375 {
2376 pNew->pNext = pIntNet->pNetworks;
2377 pIntNet->pNetworks = pNew;
2378
2379 /*
2380 * Check if the current session is actually allowed to create and open
2381 * the network. It is possible to implement network name based policies
2382 * and these must be checked now. SUPR0ObjRegister does no such checks.
2383 */
2384 rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
2385 if (RT_SUCCESS(rc))
2386 {
2387 /*
2388 * Connect the trunk.
2389 */
2390 rc = intnetR0NetworkCreateTrunkIf(pNew, pSession);
2391 if (RT_SUCCESS(rc))
2392 {
2393 *ppNetwork = pNew;
2394 LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
2395 return VINF_SUCCESS;
2396 }
2397 }
2398
2399 /*
2400 * We unlink it here so it cannot be opened when the caller leaves
2401 * INTNET::FastMutex before dereferencing it.
2402 */
2403 Assert(pIntNet->pNetworks == pNew);
2404 pIntNet->pNetworks = pNew->pNext;
2405 pNew->pNext = NULL;
2406
2407 *ppNetwork = pNew;
2408 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
2409 return rc;
2410 }
2411 rc = VERR_NO_MEMORY;
2412
2413 RTSemFastMutexDestroy(pNew->FastMutex);
2414 pNew->FastMutex = NIL_RTSEMFASTMUTEX;
2415 }
2416 RTMemFree(pNew);
2417 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
2418 return rc;
2419}
2420
2421
2422/**
2423 * Opens a network interface and connects it to the specified network.
2424 *
2425 * @returns VBox status code.
2426 * @param pIntNet The internal network instance.
2427 * @param pSession The session handle.
2428 * @param pszNetwork The network name.
2429 * @param enmTrunkType The trunk type.
2430 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
2431 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
2432 * @param fRestrictAccess Whether new participants should be subjected to access check or not.
2433 * @param cbSend The send buffer size.
2434 * @param cbRecv The receive buffer size.
2435 * @param phIf Where to store the handle to the network interface.
2436 */
2437INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork,
2438 INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
2439 unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
2440{
2441 LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
2442 pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf));
2443
2444 /*
2445 * Validate input.
2446 */
2447 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2448
2449 AssertPtrReturn(pszNetwork, VERR_INVALID_PARAMETER);
2450 const char *pszNetworkEnd = (const char *)memchr(pszNetwork, '\0', INTNET_MAX_NETWORK_NAME);
2451 AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
2452 size_t cchNetwork = pszNetworkEnd - pszNetwork;
2453 AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
2454
2455 if (pszTrunk)
2456 {
2457 AssertPtrReturn(pszTrunk, VERR_INVALID_PARAMETER);
2458 const char *pszTrunkEnd = (const char *)memchr(pszTrunk, '\0', INTNET_MAX_TRUNK_NAME);
2459 AssertReturn(pszTrunkEnd, VERR_INVALID_PARAMETER);
2460 }
2461 else
2462 pszTrunk = "";
2463
2464 AssertMsgReturn(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End,
2465 ("%d\n", enmTrunkType), VERR_INVALID_PARAMETER);
2466 switch (enmTrunkType)
2467 {
2468 case kIntNetTrunkType_None:
2469 case kIntNetTrunkType_WhateverNone:
2470 AssertReturn(!*pszTrunk, VERR_INVALID_PARAMETER);
2471 break;
2472
2473 case kIntNetTrunkType_NetFlt:
2474 AssertReturn(pszTrunk, VERR_INVALID_PARAMETER);
2475 break;
2476
2477 default:
2478 return VERR_NOT_IMPLEMENTED;
2479 }
2480
2481 AssertMsgReturn(!(fFlags & ~INTNET_OPEN_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2482 AssertPtrReturn(phIf, VERR_INVALID_PARAMETER);
2483
2484 /*
2485 * Acquire the mutex to serialize open/create.
2486 */
2487 int rc = RTSemFastMutexRequest(pIntNet->FastMutex);
2488 if (RT_FAILURE(rc))
2489 return rc;
2490
2491 /*
2492 * Try open / create the network and create an interface on it for the caller to use.
2493 *
2494 * Note that because of the destructors grabbing INTNET::FastMutex and us being required
2495 * to own this semaphore for the entire network opening / creation and interface creation
2496 * sequence, intnetR0CreateNetwork will have to defer the network cleanup to us on failure.
2497 */
2498 PINTNETNETWORK pNetwork = NULL;
2499 rc = intnetR0OpenNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
2500 if (RT_SUCCESS(rc) || rc == VERR_NOT_FOUND)
2501 {
2502 bool fCloseNetwork = true;
2503 if (rc == VERR_NOT_FOUND)
2504 rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
2505 if (RT_SUCCESS(rc))
2506 rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, &fCloseNetwork, phIf);
2507
2508 RTSemFastMutexRelease(pIntNet->FastMutex);
2509
2510 if (RT_FAILURE(rc) && pNetwork && fCloseNetwork)
2511 intnetR0NetworkClose(pNetwork, pSession);
2512 }
2513 else
2514 RTSemFastMutexRelease(pIntNet->FastMutex);
2515
2516 LogFlow(("INTNETR0Open: return %Rrc *phIf=%RX32\n", rc, *phIf));
2517 return rc;
2518}
2519
2520
2521/**
2522 * VMMR0 request wrapper for GMMR0MapUnmapChunk.
2523 *
2524 * @returns see GMMR0MapUnmapChunk.
2525 * @param pIntNet The internal networking instance.
2526 * @param pSession The caller's session.
2527 * @param pReq The request packet.
2528 */
2529INTNETR0DECL(int) INTNETR0OpenReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETOPENREQ pReq)
2530{
2531 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2532 return VERR_INVALID_PARAMETER;
2533 return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->enmTrunkType, pReq->szTrunk,
2534 pReq->fFlags, pReq->cbSend, pReq->cbRecv, &pReq->hIf);
2535}
2536
2537
2538/**
2539 * Destroys an instance of the Ring-0 internal networking service.
2540 *
2541 * @param pIntNet Pointer to the instance data.
2542 */
2543INTNETR0DECL(void) INTNETR0Destroy(PINTNET pIntNet)
2544{
2545 LogFlow(("INTNETR0Destroy: pIntNet=%p\n", pIntNet));
2546
2547 /*
2548 * Allow NULL pointers.
2549 */
2550 if (!pIntNet)
2551 return;
2552 AssertPtrReturnVoid(pIntNet);
2553
2554 /*
2555 * There is not supposed to be any networks hanging around at this time.
2556 */
2557 Assert(pIntNet->pNetworks == NULL);
2558 if (pIntNet->FastMutex != NIL_RTSEMFASTMUTEX)
2559 {
2560 RTSemFastMutexDestroy(pIntNet->FastMutex);
2561 pIntNet->FastMutex = NIL_RTSEMFASTMUTEX;
2562 }
2563 if (pIntNet->hHtIfs != NIL_RTHANDLETABLE)
2564 {
2565 /** @todo does it make sense to have a deleter here? */
2566 RTHandleTableDestroy(pIntNet->hHtIfs, NULL, NULL);
2567 pIntNet->hHtIfs = NIL_RTHANDLETABLE;
2568 }
2569
2570 RTMemFree(pIntNet);
2571}
2572
2573
2574/**
2575 * Create an instance of the Ring-0 internal networking service.
2576 *
2577 * @returns VBox status code.
2578 * @param ppIntNet Where to store the instance pointer.
2579 */
2580INTNETR0DECL(int) INTNETR0Create(PINTNET *ppIntNet)
2581{
2582 LogFlow(("INTNETR0Create: ppIntNet=%p\n", ppIntNet));
2583 int rc = VERR_NO_MEMORY;
2584 PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
2585 if (pIntNet)
2586 {
2587 //pIntNet->pNetworks = NULL;
2588
2589 rc = RTSemFastMutexCreate(&pIntNet->FastMutex);
2590 if (RT_SUCCESS(rc))
2591 {
2592 rc = RTHandleTableCreateEx(&pIntNet->hHtIfs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
2593 UINT32_C(0x8ffe0000), 4096, intnetR0IfRetainHandle, NULL);
2594 if (RT_SUCCESS(rc))
2595 {
2596 *ppIntNet = pIntNet;
2597 LogFlow(("INTNETR0Create: returns VINF_SUCCESS *ppIntNet=%p\n", pIntNet));
2598 return VINF_SUCCESS;
2599 }
2600
2601 RTSemFastMutexDestroy(pIntNet->FastMutex);
2602 }
2603 RTMemFree(pIntNet);
2604 }
2605 *ppIntNet = NULL;
2606 LogFlow(("INTNETR0Create: returns %Rrc\n", rc));
2607 return rc;
2608}
2609
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette