VirtualBox

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

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

intnet: Implemented activation on power on & resume, deactivation on power off and suspend, and setting/updating of the mac address.

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