VirtualBox

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

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

intnet: trunk activation / deactivation (promisc mode).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.1 KB
Line 
1/* $Id: SrvIntNetR0.cpp 10711 2008-07-16 19:54:17Z 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
40
41/*******************************************************************************
42* Structures and Typedefs *
43*******************************************************************************/
44/**
45 * A network interface.
46 *
47 * Unless explicitly stated, all members are protect by the network semaphore.
48 */
49typedef struct INTNETIF
50{
51 /** Pointer to the next interface.
52 * This is protected by the INTNET::FastMutex. */
53 struct INTNETIF *pNext;
54 /** The current MAC address for the interface. */
55 PDMMAC Mac;
56 /** Set if the INTNET::Mac member is valid. */
57 bool fMacSet;
58 /** Set if the interface is in promiscuous mode.
59 * In promiscuous mode the interface will receive all packages except the one it's sending. */
60 bool fPromiscuous;
61 /** Whether the interface is active or not. */
62 bool fActive;
63 /** Number of yields done to try make the interface read pending data.
64 * We will stop yeilding when this reaches a threshold assuming that the VM is paused or
65 * that it simply isn't worth all the delay. It is cleared when a successful send has been done.
66 */
67 uint32_t cYields;
68 /** Pointer to the current exchange buffer (ring-0). */
69 PINTNETBUF pIntBuf;
70 /** Pointer to ring-3 mapping of the current exchange buffer. */
71 R3PTRTYPE(PINTNETBUF) pIntBufR3;
72 /** Pointer to the default exchange buffer for the interface. */
73 PINTNETBUF pIntBufDefault;
74 /** Pointer to ring-3 mapping of the default exchange buffer. */
75 R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3;
76 /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
77 RTSEMEVENT Event;
78 /** Number of threads sleeping on the Event semaphore. */
79 uint32_t cSleepers;
80 /** The interface handle.
81 * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
82 * should return with the appropriate error condition. */
83 INTNETIFHANDLE hIf;
84 /** Pointer to the network this interface is connected to.
85 * This is protected by the INTNET::FastMutex. */
86 struct INTNETNETWORK *pNetwork;
87 /** The session this interface is associated with. */
88 PSUPDRVSESSION pSession;
89 /** The SUPR0 object id. */
90 void *pvObj;
91} INTNETIF;
92/** Pointer to an internal network interface. */
93typedef INTNETIF *PINTNETIF;
94
95
96/**
97 * A trunk interface.
98 */
99typedef struct INTNETTRUNKIF
100{
101 /** The port interface we present to the component. */
102 INTNETTRUNKSWPORT SwitchPort;
103 /** The port interface we get from the component. */
104 PINTNETTRUNKIFPORT pIfPort;
105 /** The trunk mutex that serializes all calls <b>to</b> the component. */
106 RTSEMFASTMUTEX FastMutex;
107 /** Pointer to the network we're connect to.
108 * This may be NULL if we're orphaned? */
109 struct INTNETNETWORK *pNetwork;
110 /** Whether to supply physical addresses with the outbound SGs. */
111 bool volatile fPhysSG;
112} INTNETTRUNKIF;
113/** Pointer to a trunk interface. */
114typedef INTNETTRUNKIF *PINTNETTRUNKIF;
115
116/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
117#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
118
119
120/**
121 * Internal representation of a network.
122 */
123typedef struct INTNETNETWORK
124{
125 /** The Next network in the chain.
126 * This is protected by the INTNET::FastMutex. */
127 struct INTNETNETWORK *pNext;
128 /** List of interfaces connected to the network.
129 * This is protected by the INTNET::FastMutex. */
130 PINTNETIF pIFs;
131 /** Pointer to the trunk interface.
132 * Can be NULL if there is no trunk connection. */
133 PINTNETTRUNKIF pTrunkIF;
134 /** The network mutex.
135 * It protects everything dealing with this network. */
136 RTSEMFASTMUTEX FastMutex;
137 /** Pointer to the instance data. */
138 struct INTNET *pIntNet;
139 /** The SUPR0 object id. */
140 void *pvObj;
141 /** Network creation flags (INTNET_OPEN_FLAGS_*). */
142 uint32_t fFlags;
143 /** The number of active interfaces (excluding the trunk). */
144 uint32_t cActiveIFs;
145 /** The length of the network name. */
146 uint8_t cchName;
147 /** The network name. */
148 char szName[INTNET_MAX_NETWORK_NAME];
149 /** The trunk type. */
150 INTNETTRUNKTYPE enmTrunkType;
151 /** The trunk name. */
152 char szTrunk[INTNET_MAX_TRUNK_NAME];
153} INTNETNETWORK;
154/** Pointer to an internal network. */
155typedef INTNETNETWORK *PINTNETNETWORK;
156
157
158/**
159 * Handle table entry.
160 * @todo move to IPRT.
161 */
162typedef union INTNETHTE
163{
164 /** Pointer to the object we're a handle for. */
165 PINTNETIF pIF;
166 /** Index to the next free entry. */
167 uintptr_t iNext;
168} INTNETHTE;
169/** Pointer to a handle table entry. */
170typedef INTNETHTE *PINTNETHTE;
171
172
173/**
174 * Handle table.
175 * @todo move to IPRT (RTHandleTableCreate/Destroy/Add/Delete/Lookup).
176 */
177typedef struct INTNETHT
178{
179 /** Spinlock protecting all access. */
180 RTSPINLOCK Spinlock;
181 /** Pointer to the handle table. */
182 PINTNETHTE paEntries;
183 /** The number of allocated handles. */
184 uint32_t cAllocated;
185 /** The index of the first free handle entry.
186 * UINT32_MAX means empty list. */
187 uint32_t volatile iHead;
188 /** The index of the last free handle entry.
189 * UINT32_MAX means empty list. */
190 uint32_t volatile iTail;
191} INTNETHT;
192/** Pointer to a handle table. */
193typedef INTNETHT *PINTNETHT;
194
195
196/**
197 * Internal networking instance.
198 */
199typedef struct INTNET
200{
201 /** Mutex protecting the network creation, opening and destruction.
202 * (This means all operations affecting the pNetworks list.) */
203 RTSEMFASTMUTEX FastMutex;
204 /** List of networks. Protected by INTNET::Spinlock. */
205 PINTNETNETWORK volatile pNetworks;
206 /** Handle table for the interfaces. */
207 INTNETHT IfHandles;
208} INTNET;
209
210
211/*******************************************************************************
212* Internal Functions *
213*******************************************************************************/
214static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis);
215static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis);
216static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis);
217static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis);
218
219
220
221/**
222 * Validates and translates an interface handle to a interface pointer.
223 *
224 * The caller already owns the spinlock, which means this is
225 * for internal use only.
226 *
227 * @returns Pointer to interface.
228 * @returns NULL if the handle is invalid.
229 * @param pHT Pointer to the handle table.
230 * @param hIF The interface handle to validate and translate.
231 *
232 * @internal
233 */
234DECLINLINE(PINTNETIF) intnetR0Handle2IFPtrLocked(PINTNETHT pHT, INTNETIFHANDLE hIF)
235{
236 if (RT_LIKELY((hIF & INTNET_HANDLE_MAGIC) == INTNET_HANDLE_MAGIC))
237 {
238 const uint32_t i = hIF & INTNET_HANDLE_INDEX_MASK;
239 if (RT_LIKELY( i < pHT->cAllocated
240 && pHT->paEntries[i].iNext >= INTNET_HANDLE_MAX
241 && pHT->paEntries[i].iNext != UINT32_MAX))
242 return pHT->paEntries[i].pIF;
243 }
244 return NULL;
245}
246
247
248/**
249 * Validates and translates an interface handle to a interface pointer.
250 *
251 * @returns Pointer to interface.
252 * @returns NULL if the handle is invalid.
253 * @param pHT Pointer to the handle table.
254 * @param hIF The interface handle to validate and translate.
255 */
256DECLINLINE(PINTNETIF) intnetR0Handle2IFPtr(PINTNETHT pHT, INTNETIFHANDLE hIF)
257{
258 AssertPtr(pHT);
259 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
260 RTSpinlockAcquire(pHT->Spinlock, &Tmp);
261 PINTNETIF pIF = intnetR0Handle2IFPtrLocked(pHT, hIF);
262 RTSpinlockRelease(pHT->Spinlock, &Tmp);
263
264 return pIF;
265}
266
267
268/**
269 * Allocates a handle for an interface.
270 *
271 * @returns Handle on success.
272 * @returns Invalid handle on failure.
273 * @param pIntNet Pointer to the instance data.
274 * @param pIF The interface which we're allocating a handle for.
275 */
276static INTNETIFHANDLE intnetR0HandleAllocate(PINTNET pIntNet, PINTNETIF pIF)
277{
278 Assert(pIF);
279 Assert(pIntNet);
280 unsigned cTries = 10;
281 PINTNETHT pHT = &pIntNet->IfHandles;
282 PINTNETHTE paNew = NULL;
283
284 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
285 RTSpinlockAcquire(pHT->Spinlock, &Tmp);
286 for (;;)
287 {
288 /*
289 * Check the free list.
290 */
291 uint32_t i = pHT->iHead;
292 if (i != UINT32_MAX)
293 {
294 pHT->iHead = pHT->paEntries[i].iNext;
295 if (pHT->iHead == UINT32_MAX)
296 pHT->iTail = UINT32_MAX;
297
298 pHT->paEntries[i].pIF = pIF;
299 RTSpinlockRelease(pHT->Spinlock, &Tmp);
300 if (paNew)
301 RTMemFree(paNew);
302 return i | INTNET_HANDLE_MAGIC;
303 }
304
305 /*
306 * Leave the spinlock and allocate a new array.
307 */
308 const unsigned cNew = pHT->cAllocated + 128;
309 RTSpinlockRelease(pHT->Spinlock, &Tmp);
310 if (--cTries <= 0)
311 {
312 AssertMsgFailed(("Giving up!\n"));
313 break;
314 }
315 paNew = (PINTNETHTE)RTMemAlloc(sizeof(*paNew) * cNew);
316 if (!paNew)
317 break;
318
319 /*
320 * Acquire the spinlock and check if someone raced us.
321 */
322 RTSpinlockAcquire(pHT->Spinlock, &Tmp);
323 if (pHT->cAllocated < cNew)
324 {
325 /* copy the current table. */
326 memcpy(paNew, pHT->paEntries, pHT->cAllocated * sizeof(*paNew));
327
328 /* link the new entries into the free chain. */
329 i = pHT->cAllocated;
330 uint32_t iTail = pHT->iTail;
331 if (iTail == UINT32_MAX)
332 pHT->iHead = iTail = i++;
333 while (i < cNew)
334 {
335 paNew[iTail].iNext = i;
336 iTail = i++;
337 }
338 paNew[iTail].iNext = UINT32_MAX;
339 pHT->iTail = iTail;
340
341 /* update the handle table. */
342 pHT->cAllocated = cNew;
343 paNew = (PINTNETHTE)ASMAtomicXchgPtr((void * volatile *)&pHT->paEntries, paNew);
344 }
345 }
346
347 if (paNew)
348 RTMemFree(paNew);
349 return INTNET_HANDLE_INVALID;
350}
351
352
353/**
354 * Validates and frees a handle.
355 *
356 * @returns Pointer to interface.
357 * @returns NULL if the handle is invalid.
358 * @param pHT Pointer to the handle table.
359 * @param h The handle we're freeing.
360 */
361static PINTNETIF intnetR0HandleFree(PINTNETHT pHT, INTNETIFHANDLE h)
362{
363 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
364 RTSpinlockAcquire(pHT->Spinlock, &Tmp);
365
366 /*
367 * Validate and get it, then insert the handle table entry
368 * at the end of the free list.
369 */
370 PINTNETIF pIF = intnetR0Handle2IFPtrLocked(pHT, h);
371 if (pIF)
372 {
373 const uint32_t i = h & INTNET_HANDLE_INDEX_MASK;
374 pHT->paEntries[i].iNext = UINT32_MAX;
375 const uint32_t iTail = pHT->iTail;
376 if (iTail != UINT32_MAX)
377 pHT->paEntries[iTail].iNext = i;
378 else
379 pHT->iHead = i;
380 pHT->iTail = i;
381 }
382
383 RTSpinlockRelease(pHT->Spinlock, &Tmp);
384
385 AssertMsg(pIF, ("%d >= %d\n", h & INTNET_HANDLE_INDEX_MASK, pHT->cAllocated));
386 return pIF;
387}
388
389
390#ifdef IN_INTNET_TESTCASE
391/**
392 * Reads the next frame in the buffer.
393 * The caller is responsible for ensuring that there is a valid frame in the buffer.
394 *
395 * @returns Size of the frame in bytes.
396 * @param pBuf The buffer.
397 * @param pRingBuff The ring buffer to read from.
398 * @param pvFrame Where to put the frame. The caller is responsible for
399 * ensuring that there is sufficient space for the frame.
400 */
401static unsigned intnetR0RingReadFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, void *pvFrame)
402{
403 Assert(pRingBuf->offRead < pBuf->cbBuf);
404 Assert(pRingBuf->offRead >= pRingBuf->offStart);
405 Assert(pRingBuf->offRead < pRingBuf->offEnd);
406 uint32_t offRead = pRingBuf->offRead;
407 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offRead);
408 const void *pvFrameIn = INTNETHdrGetFramePtr(pHdr, pBuf);
409 unsigned cb = pHdr->cbFrame;
410 memcpy(pvFrame, pvFrameIn, cb);
411
412 /* skip the frame */
413 offRead += pHdr->offFrame + cb;
414 offRead = RT_ALIGN_32(offRead, sizeof(INTNETHDR));
415 Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
416 if (offRead >= pRingBuf->offEnd)
417 offRead = pRingBuf->offStart;
418 ASMAtomicXchgU32(&pRingBuf->offRead, offRead);
419 return cb;
420}
421#endif /* IN_INTNET_TESTCASE */
422
423
424/**
425 * Writes a frame packet to the buffer.
426 *
427 * @returns VBox status code.
428 * @param pBuf The buffer.
429 * @param pRingBuf The ring buffer to read from.
430 * @param pvFrame The frame to write.
431 * @param cbFrame The size of the frame.
432 */
433static int intnetR0RingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
434{
435 /*
436 * Validate input.
437 */
438 Assert(pBuf);
439 Assert(pRingBuf);
440 Assert(pvFrame);
441 Assert(cbFrame >= sizeof(PDMMAC) * 2);
442 uint32_t offWrite = pRingBuf->offWrite;
443 Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
444 uint32_t offRead = pRingBuf->offRead;
445 Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
446
447 const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
448 if (offRead <= offWrite)
449 {
450 /*
451 * Try fit it all before the end of the buffer.
452 */
453 if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
454 {
455 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
456 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
457 pHdr->cbFrame = cbFrame;
458 pHdr->offFrame = sizeof(INTNETHDR);
459
460 memcpy(pHdr + 1, pvFrame, cbFrame);
461
462 offWrite += cb + sizeof(INTNETHDR);
463 Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
464 if (offWrite >= pRingBuf->offEnd)
465 offWrite = pRingBuf->offStart;
466 Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
467 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
468 return VINF_SUCCESS;
469 }
470
471 /*
472 * Try fit the frame at the start of the buffer.
473 * (The header fits before the end of the buffer because of alignment.)
474 */
475 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
476 if (offRead - pRingBuf->offStart > cb) /* not >= ! */
477 {
478 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
479 void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
480 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
481 pHdr->cbFrame = cbFrame;
482 pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
483
484 memcpy(pvFrameOut, pvFrame, cbFrame);
485
486 offWrite = pRingBuf->offStart + cb;
487 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
488 Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
489 return VINF_SUCCESS;
490 }
491 }
492 /*
493 * The reader is ahead of the writer, try fit it into that space.
494 */
495 else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
496 {
497 PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
498 pHdr->u16Type = INTNETHDR_TYPE_FRAME;
499 pHdr->cbFrame = cbFrame;
500 pHdr->offFrame = sizeof(INTNETHDR);
501
502 memcpy(pHdr + 1, pvFrame, cbFrame);
503
504 offWrite += cb + sizeof(INTNETHDR);
505 ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
506 Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
507 return VINF_SUCCESS;
508 }
509
510 /* (it didn't fit) */
511 /** @todo stats */
512 return VERR_BUFFER_OVERFLOW;
513}
514
515
516/**
517 * Ethernet header.
518 */
519#pragma pack(1)
520typedef struct INTNETETHERHDR
521{
522 PDMMAC MacDst;
523 PDMMAC MacSrc;
524} INTNETETHERHDR;
525#pragma pack()
526typedef INTNETETHERHDR *PINTNETETHERHDR;
527
528
529/**
530 * Sends a frame to a specific interface.
531 *
532 * @param pIf The interface.
533 * @param pvFrame The frame data.
534 * @param cbFrame The size of the frame.
535 */
536static void intnetR0IfSend(PINTNETIF pIf, const void *pvFrame, unsigned cbFrame)
537{
538 LogFlow(("intnetR0IfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
539 int rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
540 if (RT_SUCCESS(rc))
541 {
542 pIf->cYields = 0;
543 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
544 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
545 RTSemEventSignal(pIf->Event);
546 return;
547 }
548
549 /*
550 * Retry a few times, yielding the CPU in between.
551 * But don't let a unresponsive VM harm performance, so give up after a short while.
552 */
553 if (pIf->cYields < 100)
554 {
555 unsigned cYields = 10;
556 do
557 {
558 RTSemEventSignal(pIf->Event);
559 RTThreadYield();
560 rc = intnetR0RingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
561 if (RT_SUCCESS(rc))
562 {
563 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
564 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
565 STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
566 RTSemEventSignal(pIf->Event);
567 return;
568 }
569 pIf->cYields++;
570 } while (--cYields > 0);
571 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
572 }
573
574 /* ok, the frame is lost. */
575 STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
576 RTSemEventSignal(pIf->Event);
577}
578
579
580/**
581 * Sends a frame.
582 *
583 * This function will distribute the frame to the interfaces it is addressed to.
584 * It will also update the MAC address of the sender.
585 *
586 * The caller must own the network mutex.
587 *
588 * @param pNetwork The network the frame is being sent to.
589 * @param pIfSender The interface sending the frame.
590 * @param pvFrame The frame data.
591 * @param cbFrame The size of the frame.
592 */
593static void intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, const void *pvFrame, unsigned cbFrame)
594{
595 /*
596 * Assert reality.
597 */
598 Assert(pNetwork);
599 Assert(pIfSender);
600 Assert(pNetwork == pIfSender->pNetwork);
601 Assert(pvFrame);
602 if (cbFrame < sizeof(PDMMAC) * 2)
603 return;
604
605 /*
606 * Send statistics.
607 */
608 STAM_REL_COUNTER_INC(&pIfSender->pIntBuf->cStatSends);
609 STAM_REL_COUNTER_ADD(&pIfSender->pIntBuf->cbStatSend, cbFrame);
610
611 /*
612 * Inspect the header updating the mac address of the sender in the process.
613 */
614 PINTNETETHERHDR pEthHdr = (PINTNETETHERHDR)pvFrame;
615 if (memcmp(&pEthHdr->MacSrc, &pIfSender->Mac, sizeof(pIfSender->Mac)))
616 {
617 /** @todo stats */
618 Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &pEthHdr->MacSrc));
619 pIfSender->Mac = pEthHdr->MacSrc;
620 pIfSender->fMacSet = true;
621 }
622
623 if ( (pEthHdr->MacDst.au8[0] & 1) /* multicast address */
624 || ( pEthHdr->MacDst.au16[0] == 0xffff /* broadcast address. s*/
625 && pEthHdr->MacDst.au16[1] == 0xffff
626 && pEthHdr->MacDst.au16[2] == 0xffff)
627 )
628 {
629 /*
630 * This is a broadcast or multicast address. For the present we treat those
631 * two as the same - investigating multicast is left for later.
632 *
633 * Write the packet to all the interfaces and signal them.
634 */
635 Log2(("Broadcast\n"));
636 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
637 if (pIf != pIfSender)
638 intnetR0IfSend(pIf, pvFrame, cbFrame);
639 }
640 else
641 {
642 /*
643 * Only send to the interfaces with matching a MAC address.
644 */
645 Log2(("Dst=%.6Rhxs\n", &pEthHdr->MacDst));
646 for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
647 {
648 Log2(("Dst=%.6Rhxs ?==? %.6Rhxs\n", &pEthHdr->MacDst, &pIf->Mac));
649 if ( ( !pIf->fMacSet
650 || !memcmp(&pIf->Mac, &pEthHdr->MacDst, sizeof(pIf->Mac)))
651 || ( pIf->fPromiscuous
652 && pIf != pIfSender /* promiscuous mode: omit the sender */))
653 intnetR0IfSend(pIf, pvFrame, cbFrame);
654 }
655 }
656}
657
658
659/**
660 * Sends one or more frames.
661 *
662 * The function will first the frame which is passed as the optional
663 * arguments pvFrame and cbFrame. These are optional since it also
664 * possible to chain together one or more frames in the send buffer
665 * which the function will process after considering it's arguments.
666 *
667 * @returns VBox status code.
668 * @param pIntNet The instance data.
669 * @param hIf The interface handle.
670 * @param pvFrame Pointer to the frame.
671 * @param cbFrame Size of the frame.
672 */
673INTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, const void *pvFrame, unsigned cbFrame)
674{
675 LogFlow(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
676
677 /*
678 * Validate input.
679 */
680 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
681 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
682 if (!pIf)
683 return VERR_INVALID_HANDLE;
684 if (pvFrame && cbFrame)
685 {
686 AssertReturn(cbFrame < 0x8000, VERR_INVALID_PARAMETER);
687 AssertPtrReturn(pvFrame, VERR_INVALID_PARAMETER);
688 AssertPtrReturn((uint8_t *)pvFrame + cbFrame - 1, VERR_INVALID_PARAMETER);
689
690 /* This is the better place to crash, probe the buffer. */
691 ASMProbeReadBuffer(pvFrame, cbFrame);
692 }
693
694 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
695 if (RT_FAILURE(rc))
696 return rc;
697
698 /*
699 * Process the argument.
700 */
701 if (pvFrame && cbFrame)
702 intnetR0NetworkSend(pIf->pNetwork, pIf, pvFrame, cbFrame);
703
704 /*
705 * Process the send buffer.
706 */
707 while (pIf->pIntBuf->Send.offRead != pIf->pIntBuf->Send.offWrite)
708 {
709 /* Send the frame if the type is sane. */
710 PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pIf->pIntBuf + pIf->pIntBuf->Send.offRead);
711 if (pHdr->u16Type == INTNETHDR_TYPE_FRAME)
712 {
713 void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
714 if (pvCurFrame)
715 intnetR0NetworkSend(pIf->pNetwork, pIf, pvCurFrame, pHdr->cbFrame);
716 }
717 /* else: ignore the frame */
718
719 /* Skip to the next frame. */
720 INTNETRingSkipFrame(pIf->pIntBuf, &pIf->pIntBuf->Send);
721 }
722
723 return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
724}
725
726
727/**
728 * VMMR0 request wrapper for INTNETR0IfSend.
729 *
730 * @returns see INTNETR0IfSend.
731 * @param pIntNet The internal networking instance.
732 * @param pReq The request packet.
733 */
734INTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PINTNETIFSENDREQ pReq)
735{
736 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
737 return VERR_INVALID_PARAMETER;
738 return INTNETR0IfSend(pIntNet, pReq->hIf, NULL, 0);
739}
740
741
742/**
743 * Maps the default buffer into ring 3.
744 *
745 * @returns VBox status code.
746 * @param pIntNet The instance data.
747 * @param hIf The interface handle.
748 * @param ppRing3Buf Where to store the address of the ring-3 mapping.
749 */
750INTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
751{
752 LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
753
754 /*
755 * Validate input.
756 */
757 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
758 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
759 if (!pIf)
760 return VERR_INVALID_HANDLE;
761 AssertPtrReturn(ppRing3Buf, VERR_INVALID_PARAMETER);
762
763 /*
764 * ASSUMES that only the process that created an interface can use it.
765 * ASSUMES that we created the ring-3 mapping when selecting or
766 * allocating the buffer.
767 */
768 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
769 if (RT_FAILURE(rc))
770 return rc;
771
772 *ppRing3Buf = pIf->pIntBufR3;
773
774 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
775 LogFlow(("INTNETR0IfGetRing3Buffer: returns %Rrc *ppRing3Buf=%p\n", rc, *ppRing3Buf));
776 return rc;
777}
778
779
780/**
781 * VMMR0 request wrapper for INTNETR0IfGetRing3Buffer.
782 *
783 * @returns see INTNETR0IfGetRing3Buffer.
784 * @param pIntNet The internal networking instance.
785 * @param pReq The request packet.
786 */
787INTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PINTNETIFGETRING3BUFFERREQ pReq)
788{
789 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
790 return VERR_INVALID_PARAMETER;
791 return INTNETR0IfGetRing3Buffer(pIntNet, pReq->hIf, &pReq->pRing3Buf);
792}
793
794
795/**
796 * Gets the ring-0 address of the current buffer.
797 *
798 * @returns VBox status code.
799 * @param pIntNet The instance data.
800 * @param hIf The interface handle.
801 * @param ppRing0Buf Where to store the address of the ring-3 mapping.
802 */
803INTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PINTNETBUF *ppRing0Buf)
804{
805 LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
806
807 /*
808 * Validate input.
809 */
810 AssertPtrReturn(ppRing0Buf, VERR_INVALID_PARAMETER);
811 *ppRing0Buf = NULL;
812 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
813 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
814 if (!pIf)
815 return VERR_INVALID_HANDLE;
816
817 /*
818 * Grab the lock and get the data.
819 * ASSUMES that the handle isn't closed while we're here.
820 */
821 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
822 if (RT_FAILURE(rc))
823 return rc;
824
825 *ppRing0Buf = pIf->pIntBuf;
826
827 rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
828 LogFlow(("INTNETR0IfGetRing0Buffer: returns %Rrc *ppRing0Buf=%p\n", rc, *ppRing0Buf));
829 return rc;
830}
831
832
833#if 0
834/**
835 * Gets the physical addresses of the default interface buffer.
836 *
837 * @returns VBox status code.
838 * @param pIntNet The instance data.
839 * @param hIF The interface handle.
840 * @param paPages Where to store the addresses. (The reserved fields will be set to zero.)
841 * @param cPages
842 */
843INTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
844{
845 /*
846 * Validate input.
847 */
848 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
849 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
850 if (!pIf)
851 return VERR_INVALID_HANDLE;
852 AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
853 AssertPtrReturn((uint8_t *)&paPages[cPages] - 1, VERR_INVALID_PARAMETER);
854
855 /*
856 * Grab the lock and get the data.
857 * ASSUMES that the handle isn't closed while we're here.
858 */
859 int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
860 if (RT_FAILURE(rc))
861 return rc;
862
863 /** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there
864 * is no need for any extra bookkeeping here.. */
865 //*ppRing0Buf = pIf->pIntBuf;
866
867 //return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
868 RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
869 return VERR_NOT_IMPLEMENTED;
870}
871#endif
872
873
874/**
875 * Sets the promiscuous mode property of an interface.
876 *
877 * @returns VBox status code.
878 * @param pIntNet The instance handle.
879 * @param hIf The interface handle.
880 * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not.
881 */
882INTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, bool fPromiscuous)
883{
884 LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
885
886 /*
887 * Validate & translate input.
888 */
889 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
890 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
891 if (!pIf)
892 {
893 LogFlow(("INTNETR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
894 return VERR_INVALID_HANDLE;
895 }
896
897 /*
898 * Grab the network semaphore and make the change.
899 */
900 PINTNETNETWORK pNetwork = pIf->pNetwork;
901 if (!pNetwork)
902 return VERR_WRONG_ORDER;
903 int rc = RTSemFastMutexRequest(pNetwork->FastMutex);
904 if (RT_FAILURE(rc))
905 return rc;
906
907 if (pIf->fPromiscuous != fPromiscuous)
908 {
909 Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
910 hIf, !fPromiscuous, !!fPromiscuous));
911 ASMAtomicUoWriteBool(&pIf->fPromiscuous, fPromiscuous);
912 }
913
914 RTSemFastMutexRelease(pNetwork->FastMutex);
915 return VINF_SUCCESS;
916}
917
918
919/**
920 * VMMR0 request wrapper for INTNETR0IfSetPromiscuousMode.
921 *
922 * @returns see INTNETR0IfSetPromiscuousMode.
923 * @param pIntNet The internal networking instance.
924 * @param pReq The request packet.
925 */
926INTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
927{
928 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
929 return VERR_INVALID_PARAMETER;
930 return INTNETR0IfSetPromiscuousMode(pIntNet, pReq->hIf, pReq->fPromiscuous);
931}
932
933
934/**
935 * Worker for intnetR0IfSetActive.
936 *
937 * This function will update the active interface count on the network and
938 * activate or deactivate the trunk connection if necessary. Note that in
939 * order to do this it is necessary to abandond the network semaphore.
940 *
941 * @returns VBox status code.
942 * @param pNetwork The network.
943 * @param fIf The interface.
944 * @param fActive What to do.
945 */
946static int intnetR0NetworkSetIfActive(PINTNETNETWORK pNetwork, PINTNETIF pIf, bool fActive)
947{
948 /* quick santiy check */
949 AssertPtr(pNetwork);
950 AssertPtr(pIf);
951
952 /*
953 * If we've got a trunk, lock it now in case we need to call out, and
954 * then lock the network.
955 */
956 PINTNETTRUNKIF pTrunkIf = pNetwork->pTrunkIF;
957 if (pTrunkIf && !intnetR0TrunkIfOutLock(pTrunkIf))
958 return VERR_SEM_DESTROYED;
959
960 int rc = RTSemFastMutexRequest(pNetwork->FastMutex); AssertRC(rc);
961 if (RT_SUCCESS(rc))
962 {
963 bool fNetworkLocked = true;
964
965 /*
966 * Make the change if necessary.
967 */
968 if (pIf->fActive != fActive)
969 {
970 pIf->fActive = fActive;
971
972 uint32_t const cActiveIFs = pNetwork->cActiveIFs;
973 Assert((int32_t)cActiveIFs + (fActive ? 1 : -1) >= 0);
974 pNetwork->cActiveIFs += fActive ? 1 : -1;
975
976 if ( pTrunkIf
977 && ( !pNetwork->cActiveIFs
978 || !cActiveIFs))
979 {
980 /*
981 * We'll have to change the trunk status, so, leave
982 * the network semaphore so we don't create any deadlocks.
983 */
984 int rc2 = RTSemFastMutexRelease(pNetwork->FastMutex); AssertRC(rc2);
985 fNetworkLocked = false;
986
987 if (pTrunkIf->pIfPort)
988 pTrunkIf->pIfPort->pfnSetActive(pTrunkIf->pIfPort, fActive);
989 }
990 }
991
992 if (fNetworkLocked)
993 RTSemFastMutexRelease(pNetwork->FastMutex);
994 }
995 if (pTrunkIf)
996 intnetR0TrunkIfOutUnlock(pTrunkIf);
997 return rc;
998}
999
1000
1001/**
1002 * Activates or deactivates a interface.
1003 *
1004 * This is used to enable and disable the trunk connection on demans as well as
1005 * know when not to expect an interface to want to receive packets.
1006 *
1007 * @returns VBox status code.
1008 * @param pIf The interface.
1009 * @param fActive What to do.
1010 */
1011static int intnetR0IfSetActive(PINTNETIF pIf, bool fActive)
1012{
1013 /* quick sanity check */
1014 AssertPtrReturn(pIf, VERR_INVALID_POINTER);
1015
1016 /*
1017 * Hand it to the network since it might involve the trunk
1018 * and things are tricky there wrt to locking order.
1019 */
1020 PINTNETNETWORK pNetwork = pIf->pNetwork;
1021 if (!pNetwork)
1022 return VERR_WRONG_ORDER;
1023 return intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
1024}
1025
1026
1027/**
1028 * Wait for the interface to get signaled.
1029 * The interface will be signaled when is put into the receive buffer.
1030 *
1031 * @returns VBox status code.
1032 * @param pIntNet The instance handle.
1033 * @param hIf The interface handle.
1034 * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be
1035 * used if indefinite wait is desired.
1036 */
1037INTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, uint32_t cMillies)
1038{
1039 LogFlow(("INTNETR0IfWait: pIntNet=%p hIf=%RX32 cMillies=%u\n", pIntNet, hIf, cMillies));
1040
1041 /*
1042 * Get and validate essential handles.
1043 */
1044 AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
1045 PINTNETIF pIf = intnetR0Handle2IFPtr(&pIntNet->IfHandles, hIf);
1046 if (!pIf)
1047 {
1048 LogFlow(("INTNETR0IfWait: returns VERR_INVALID_HANDLE\n"));
1049 return VERR_INVALID_HANDLE;
1050 }
1051 const INTNETIFHANDLE hIfSelf = pIf->hIf;
1052 const RTSEMEVENT Event = pIf->Event;
1053 if ( hIfSelf != hIf
1054 && Event != NIL_RTSEMEVENT)
1055 {
1056 LogFlow(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
1057 return VERR_SEM_DESTROYED;
1058 }
1059
1060 /*
1061 * It is tempting to check if there is data to be read here,
1062 * but the problem with such an approach is that it will cause
1063 * one unnecessary supervisor->user->supervisor trip. There is
1064 * already a slight risk for such, so no need to increase it.
1065 */
1066
1067 /*
1068 * Increment the number of waiters before starting the wait.
1069 * Upon wakeup we must assert reality checking that we're not
1070 * already destroyed or in the process of being destroyed.
1071 */
1072 ASMAtomicIncU32(&pIf->cSleepers);
1073 int rc = RTSemEventWaitNoResume(Event, cMillies);
1074 if (pIf->Event == Event)
1075 {
1076 ASMAtomicDecU32(&pIf->cSleepers);
1077 if (pIf->hIf != hIf)
1078 rc = VERR_SEM_DESTROYED;
1079 }
1080 else
1081 rc = VERR_SEM_DESTROYED;
1082 LogFlow(("INTNETR0IfWait: returns %Rrc\n", rc));
1083 return rc;
1084}
1085
1086
1087/**
1088 * VMMR0 request wrapper for INTNETR0IfWait.
1089 *
1090 * @returns see INTNETR0IfWait.
1091 * @param pIntNet The internal networking instance.
1092 * @param pReq The request packet.
1093 */
1094INTNETR0DECL(int) INTNETR0IfWaitReq(PINTNET pIntNet, PINTNETIFWAITREQ pReq)
1095{
1096 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1097 return VERR_INVALID_PARAMETER;
1098 return INTNETR0IfWait(pIntNet, pReq->hIf, pReq->cMillies);
1099}
1100
1101
1102/**
1103 * Close an interface.
1104 *
1105 * @returns VBox status code.
1106 * @param pIntNet The instance handle.
1107 * @param hIf The interface handle.
1108 */
1109INTNETR0DECL(int) INTNETR0IfClose(PINTNET pIntNet, INTNETIFHANDLE hIf)
1110{
1111 LogFlow(("INTNETR0IfClose: pIntNet=%p hIf=%RX32\n", pIntNet, hIf));
1112
1113 /*
1114 * Validate, get and free the handle.
1115 */
1116 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
1117 PINTNETIF pIf = intnetR0HandleFree(&pIntNet->IfHandles, hIf);
1118 if (!pIf)
1119 return VERR_INVALID_HANDLE;
1120 ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
1121
1122 /*
1123 * Release our reference to the interface object.
1124 */
1125 int rc = SUPR0ObjRelease(pIf->pvObj, pIf->pSession);
1126 LogFlow(("INTNETR0IfClose: returns %Rrc\n", rc));
1127 return rc;
1128}
1129
1130
1131/**
1132 * VMMR0 request wrapper for INTNETR0IfCloseReq.
1133 *
1134 * @returns see INTNETR0IfClose.
1135 * @param pIntNet The internal networking instance.
1136 * @param pReq The request packet.
1137 */
1138INTNETR0DECL(int) INTNETR0IfCloseReq(PINTNET pIntNet, PINTNETIFCLOSEREQ pReq)
1139{
1140 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
1141 return VERR_INVALID_PARAMETER;
1142 return INTNETR0IfClose(pIntNet, pReq->hIf);
1143}
1144
1145
1146/**
1147 * Interface destructor callback.
1148 * This is called for reference counted objectes when the count reaches 0.
1149 *
1150 * @param pvObj The object pointer.
1151 * @param pvUser1 Pointer to the interface.
1152 * @param pvUser2 Pointer to the INTNET instance data.
1153 */
1154static DECLCALLBACK(void) intnetR0IfDestruct(void *pvObj, void *pvUser1, void *pvUser2)
1155{
1156 LogFlow(("intnetR0IfDestruct: pvObj=%p pvUser1=%p pvUser2=%p\n", pvObj, pvUser1, pvUser2));
1157 PINTNETIF pIf = (PINTNETIF)pvUser1;
1158 PINTNET pIntNet = (PINTNET)pvUser2;
1159
1160 RTSemFastMutexRequest(pIntNet->FastMutex);
1161
1162 /*
1163 * Delete the interface handle so the object no longer can be opened.
1164 */
1165 INTNETIFHANDLE hIf = ASMAtomicXchgU32(&pIf->hIf, INTNET_HANDLE_INVALID);
1166 if (hIf != INTNET_HANDLE_INVALID)
1167 intnetR0HandleFree(&pIntNet->IfHandles, hIf);
1168
1169 /*
1170 * If we've got a network deactivate and unlink ourselves from it.
1171 * Because of cleanup order we might be an orphan now.
1172 */
1173 PINTNETNETWORK pNetwork = pIf->pNetwork;
1174 if (pNetwork)
1175 {
1176 intnetR0IfSetActive(pIf, false);
1177
1178 if (pNetwork->pIFs == pIf)
1179 pNetwork->pIFs = pIf->pNext;
1180 else
1181 {
1182 PINTNETIF pPrev = pNetwork->pIFs;
1183 while (pPrev)
1184 {
1185 if (pPrev->pNext == pIf)
1186 {
1187 pPrev->pNext = pIf->pNext;
1188 break;
1189 }
1190 pPrev = pPrev->pNext;
1191 }
1192 Assert(pPrev);
1193 }
1194 pIf->pNext = NULL;
1195
1196 /*
1197 * Release our reference to the network.
1198 */
1199 RTSemFastMutexRelease(pIntNet->FastMutex);
1200
1201 SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
1202 pIf->pNetwork = NULL;
1203 }
1204 else
1205 RTSemFastMutexRelease(pIntNet->FastMutex);
1206
1207 /*
1208 * Wakeup anyone waiting on this interface.
1209 *
1210 * We *must* make sure they have woken up properly and realized
1211 * that the interface is no longer valid.
1212 */
1213 if (pIf->Event != NIL_RTSEMEVENT)
1214 {
1215 RTSEMEVENT Event = pIf->Event;
1216 ASMAtomicXchgSize(&pIf->Event, NIL_RTSEMEVENT);
1217 unsigned cMaxWait = 0x1000;
1218 while (pIf->cSleepers && cMaxWait-- > 0)
1219 {
1220 RTSemEventSignal(Event);
1221 RTThreadYield();
1222 }
1223 if (pIf->cSleepers)
1224 {
1225 RTThreadSleep(1);
1226
1227 cMaxWait = pIf->cSleepers;
1228 while (pIf->cSleepers && cMaxWait-- > 0)
1229 {
1230 RTSemEventSignal(Event);
1231 RTThreadSleep(10);
1232 }
1233 }
1234 RTSemEventDestroy(Event);
1235 }
1236
1237 /*
1238 * Unmap user buffer.
1239 */
1240 if (pIf->pIntBuf != pIf->pIntBufDefault)
1241 {
1242 /** @todo user buffer */
1243 }
1244
1245 /*
1246 * Unmap and Free the default buffer.
1247 */
1248 if (pIf->pIntBufDefault)
1249 {
1250 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
1251 pIf->pIntBufDefault = NULL;
1252 pIf->pIntBufDefaultR3 = 0;
1253 pIf->pIntBuf = NULL;
1254 pIf->pIntBufR3 = 0;
1255 }
1256
1257 /*
1258 * The interface.
1259 */
1260 pIf->pvObj = NULL;
1261 RTMemFree(pIf);
1262}
1263
1264
1265/**
1266 * Creates a new network interface.
1267 *
1268 * The call must have opened the network for the new interface
1269 * and is responsible for closing it on failure. On success
1270 * it must leave the network opened so the interface destructor
1271 * can close it.
1272 *
1273 * @returns VBox status code.
1274 * @param pNetwork The network.
1275 * @param pSession The session handle.
1276 * @param cbSend The size of the send buffer.
1277 * @param cbRecv The size of the receive buffer.
1278 * @param phIf Where to store the interface handle.
1279 */
1280static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf)
1281{
1282 LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u phIf=%p\n",
1283 pNetwork, pSession, cbSend, cbRecv, phIf));
1284
1285 /*
1286 * Assert input.
1287 */
1288 AssertPtr(pNetwork);
1289 AssertPtr(phIf);
1290 AssertPtr(pfCloseNetwork);
1291 *pfCloseNetwork = false;
1292
1293 /*
1294 * Allocate and initialize the interface structure.
1295 */
1296 PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
1297 if (!pIf)
1298 return VERR_NO_MEMORY;
1299 //pIf->pNext = NULL;
1300 memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */
1301 //pIf->fMacSet = false;
1302 //pIf->fPromiscuous = false;
1303 //pIf->fActive = false;
1304 //pIf->pIntBuf = 0;
1305 //pIf->pIntBufR3 = NIL_RTR3PTR;
1306 //pIf->pIntBufDefault = 0;
1307 //pIf->pIntBufDefaultR3 = NIL_RTR3PTR;
1308 //pIf->cYields = 0;
1309 pIf->Event = NIL_RTSEMEVENT;
1310 //pIf->cSleepers = 0;
1311 pIf->hIf = INTNET_HANDLE_INVALID;
1312 pIf->pNetwork = pNetwork;
1313 pIf->pSession = pSession;
1314 //pIf->pvObj = NULL;
1315 int rc = RTSemEventCreate(&pIf->Event);
1316 if (RT_SUCCESS(rc))
1317 {
1318 /*
1319 * Create the default buffer.
1320 */
1321 cbRecv = RT_ALIGN(RT_MAX(cbRecv, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
1322 cbSend = RT_ALIGN(RT_MAX(cbSend, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
1323 const unsigned cbBuf = RT_ALIGN(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR)) + cbRecv + cbSend;
1324 rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
1325 if (RT_SUCCESS(rc))
1326 {
1327 pIf->pIntBuf = pIf->pIntBufDefault;
1328 pIf->pIntBufR3 = pIf->pIntBufDefaultR3;
1329 pIf->pIntBuf->cbBuf = cbBuf;
1330 pIf->pIntBuf->cbRecv = cbRecv;
1331 pIf->pIntBuf->cbSend = cbSend;
1332 /* receive ring buffer. */
1333 pIf->pIntBuf->Recv.offStart = RT_ALIGN_32(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR));
1334 pIf->pIntBuf->Recv.offRead = pIf->pIntBuf->Recv.offStart;
1335 pIf->pIntBuf->Recv.offWrite = pIf->pIntBuf->Recv.offStart;
1336 pIf->pIntBuf->Recv.offEnd = pIf->pIntBuf->Recv.offStart + cbRecv;
1337 /* send ring buffer. */
1338 pIf->pIntBuf->Send.offStart = pIf->pIntBuf->Recv.offEnd;
1339 pIf->pIntBuf->Send.offRead = pIf->pIntBuf->Send.offStart;
1340 pIf->pIntBuf->Send.offWrite = pIf->pIntBuf->Send.offStart;
1341 pIf->pIntBuf->Send.offEnd = pIf->pIntBuf->Send.offStart + cbSend;
1342
1343 /*
1344 * Link the interface to the network.
1345 */
1346 rc = RTSemFastMutexRequest(pNetwork->FastMutex);
1347 if (RT_SUCCESS(rc))
1348 {
1349 pIf->pNext = pNetwork->pIFs;
1350 pNetwork->pIFs = pIf;
1351 RTSemFastMutexRelease(pNetwork->FastMutex);
1352
1353 /*
1354 * Register the interface with the session.
1355 */
1356 pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet);
1357 if (pIf->pvObj)
1358 {
1359 pIf->hIf = intnetR0HandleAllocate(pNetwork->pIntNet, pIf);
1360 if (pIf->hIf != INTNET_HANDLE_INVALID)
1361 {
1362 /* auto activation */ /** @todo do this manually in the future, ditto for setting the MAC address. */
1363 rc = intnetR0IfSetActive(pIf, true /* activate */);
1364 AssertRC(rc);
1365
1366 *phIf = pIf->hIf;
1367 LogFlow(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%p\n", *phIf));
1368 return VINF_SUCCESS;
1369 }
1370 rc = VERR_NO_MEMORY;
1371
1372 SUPR0ObjRelease(pIf->pvObj, pSession);
1373 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
1374 return rc;
1375 }
1376
1377 rc = VERR_NO_MEMORY;
1378 RTSemFastMutexDestroy(pNetwork->FastMutex);
1379 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
1380 }
1381
1382 SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
1383 pIf->pIntBufDefault = NULL;
1384 pIf->pIntBuf = NULL;
1385 }
1386
1387 RTSemEventDestroy(pIf->Event);
1388 pIf->Event = NIL_RTSEMEVENT;
1389 }
1390 RTMemFree(pIf);
1391 LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
1392 *pfCloseNetwork = true;
1393 return rc;
1394}
1395
1396
1397
1398
1399
1400/** @copydoc INTNETTRUNKSWPORT::pfnSetSGPhys */
1401static DECLCALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
1402{
1403 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1404 AssertMsgFailed(("Not implemented because it wasn't required on Darwin\n"));
1405 return ASMAtomicXchgBool(&pThis->fPhysSG, fEnable);
1406}
1407
1408
1409/** @copydoc INTNETTRUNKSWPORT::pfnRecv */
1410static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
1411{
1412 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1413 PINTNETNETWORK pNetwork = pThis->pNetwork;
1414
1415 /* assert some sanity */
1416 AssertPtrReturn(pNetwork, false);
1417 AssertReturn(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX, false);
1418 AssertPtr(pSG);
1419 Assert(fSrc);
1420
1421 /*
1422 *
1423 */
1424
1425
1426 return false;
1427}
1428
1429
1430/** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */
1431static DECLCALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
1432{
1433 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1434 PINTNETNETWORK pNetwork = pThis->pNetwork;
1435
1436 /* assert some sanity */
1437 AssertPtrReturnVoid(pNetwork);
1438 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
1439 AssertPtr(pSG);
1440 Assert(pSG->cUsers > 0);
1441
1442 /* do it. */
1443 ++pSG->cUsers;
1444}
1445
1446
1447/** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */
1448static DECLCALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
1449{
1450 PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
1451 PINTNETNETWORK pNetwork = pThis->pNetwork;
1452
1453 /* assert some sanity */
1454 AssertPtrReturnVoid(pNetwork);
1455 AssertReturnVoid(pNetwork->FastMutex != NIL_RTSEMFASTMUTEX);
1456 AssertPtr(pSG);
1457 Assert(pSG->cUsers > 0);
1458
1459 /*
1460 * Free it?
1461 */
1462 if (!--pSG->cUsers)
1463 {
1464 /** @todo later */
1465 }
1466}
1467
1468
1469/**
1470 * Retain the trunk interface.
1471 *
1472 * @returns pThis.
1473 *
1474 * @param pThis The trunk.
1475 *
1476 * @remarks Any locks.
1477 */
1478static PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis)
1479{
1480 if (pThis && pThis->pIfPort)
1481 pThis->pIfPort->pfnRetain(pThis->pIfPort);
1482 return pThis;
1483}
1484
1485
1486/**
1487 * Release the trunk interface.
1488 *
1489 * @param pThis The trunk.
1490 */
1491static void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis)
1492{
1493 if (pThis && pThis->pIfPort)
1494 pThis->pIfPort->pfnRelease(pThis->pIfPort);
1495}
1496
1497
1498/**
1499 * Takes the out-bound trunk lock.
1500 *
1501 * This will ensure that pIfPort is valid.
1502 *
1503 * @returns success indicator.
1504 * @param pThis The trunk.
1505 *
1506 * @remarks No locks other than the create/destroy one.
1507 */
1508static bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis)
1509{
1510 AssertPtrReturn(pThis, false);
1511 int rc = RTSemFastMutexRequest(pThis->FastMutex);
1512 if (RT_SUCCESS(rc))
1513 {
1514 if (RT_LIKELY(pThis->pIfPort))
1515 return true;
1516 RTSemFastMutexRelease(pThis->FastMutex);
1517 }
1518 else
1519 AssertMsg(rc == VERR_SEM_DESTROYED, ("%Rrc\n", rc));
1520 return false;
1521}
1522
1523
1524/**
1525 * Releases the out-bound trunk lock.
1526 *
1527 * @param pThis The trunk.
1528 */
1529static void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis)
1530{
1531 if (pThis)
1532 {
1533 int rc = RTSemFastMutexRelease(pThis->FastMutex);
1534 AssertRC(rc);
1535 }
1536}
1537
1538
1539/**
1540 * Activates the trunk interface.
1541 *
1542 * @param pThis The trunk.
1543 * @param fActive What to do with it.
1544 *
1545 * @remarks Caller may only own the create/destroy lock.
1546 */
1547static void intnetR0TrunkIfActivate(PINTNETTRUNKIF pThis, bool fActive)
1548{
1549 if (intnetR0TrunkIfOutLock(pThis))
1550 {
1551 pThis->pIfPort->pfnSetActive(pThis->pIfPort, fActive);
1552 intnetR0TrunkIfOutUnlock(pThis);
1553 }
1554}
1555
1556
1557/**
1558 * Shutdown the trunk interface.
1559 *
1560 * @param pThis The trunk.
1561 * @param pNetworks The network.
1562 *
1563 * @remarks The caller must *NOT* hold the network lock. The global
1564 * create/destroy lock is fine though.
1565 */
1566static void intnetR0TrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork)
1567{
1568 /* assert sanity */
1569 if (!pThis)
1570 return;
1571 AssertPtr(pThis);
1572 Assert(pThis->pNetwork == pNetwork);
1573 AssertPtrNull(pThis->pIfPort);
1574
1575 /*
1576 * The interface has already been deactivated, we just to wait for
1577 * it to become idle before we can disconnect and release it.
1578 */
1579 PINTNETTRUNKIFPORT pIfPort = pThis->pIfPort;
1580 if (pIfPort)
1581 {
1582 intnetR0TrunkIfOutLock(pThis);
1583
1584 /* unset it */
1585 pThis->pIfPort = NULL;
1586
1587 /* wait in portions so we can complain ever now an then. */
1588 uint64_t StartTS = RTTimeSystemNanoTS();
1589 int rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
1590 if (RT_FAILURE(rc))
1591 {
1592 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
1593 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
1594 Assert(rc == VERR_TIMEOUT);
1595 while ( RT_FAILURE(rc)
1596 && RTTimeSystemNanoTS() - StartTS < UINT64_C(30000000000)) /* 30 sec */
1597 rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
1598 if (rc == VERR_TIMEOUT)
1599 {
1600 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc).\n",
1601 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
1602 while ( rc == VERR_TIMEOUT
1603 && RTTimeSystemNanoTS() - StartTS < UINT64_C(360000000000)) /* 360 sec */
1604 rc = pIfPort->pfnWaitForIdle(pIfPort, 30*1000);
1605 if (RT_FAILURE(rc))
1606 {
1607 LogRel(("intnet: '%s' did't become idle in %RU64 ns (%Rrc), giving up.\n",
1608 pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
1609 AssertRC(rc);
1610 }
1611 }
1612 }
1613
1614 /* disconnect & release it. */
1615 pIfPort->pfnDisconnectAndRelease(pIfPort);
1616 }
1617
1618 /*
1619 * Free up the resources.
1620 */
1621 RTSEMFASTMUTEX FastMutex = pThis->FastMutex;
1622 pThis->FastMutex = NIL_RTSEMFASTMUTEX;
1623 pThis->pNetwork = NULL;
1624 RTSemFastMutexRelease(FastMutex);
1625 RTSemFastMutexDestroy(FastMutex);
1626 RTMemFree(pThis);
1627}
1628
1629
1630/**
1631 * Creates the trunk connection (if any).
1632 *
1633 * @returns VBox status code.
1634 *
1635 * @param pNetwork The newly created network.
1636 * @param pSession The session handle.
1637 */
1638static int intnetR0NetworkCreateTrunkIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
1639{
1640 const char *pszName;
1641 switch (pNetwork->enmTrunkType)
1642 {
1643 /*
1644 * The 'None' case, simple.
1645 */
1646 case kIntNetTrunkType_None:
1647 case kIntNetTrunkType_WhateverNone:
1648 return VINF_SUCCESS;
1649
1650 /* Can't happen, but makes GCC happy. */
1651 default:
1652 return VERR_NOT_IMPLEMENTED;
1653
1654 /*
1655 * Translate enum to component factory name.
1656 */
1657 case kIntNetTrunkType_NetFlt:
1658 pszName = "VBoxNetFlt";
1659 break;
1660 case kIntNetTrunkType_NetTap:
1661 pszName = "VBoxNetTap";
1662 break;
1663 case kIntNetTrunkType_SrvNat:
1664 pszName = "VBoxSrvNat";
1665 break;
1666 }
1667
1668 /*
1669 * Allocate the trunk interface.
1670 */
1671 PINTNETTRUNKIF pTrunkIF = (PINTNETTRUNKIF)RTMemAllocZ(sizeof(*pTrunkIF));
1672 if (!pTrunkIF)
1673 return VERR_NO_MEMORY;
1674 pTrunkIF->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION;
1675 pTrunkIF->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys;
1676 pTrunkIF->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv;
1677 pTrunkIF->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain;
1678 pTrunkIF->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease;
1679 pTrunkIF->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION;
1680 //pTrunkIF->pIfPort = NULL;
1681 pTrunkIF->pNetwork = pNetwork;
1682 //pTrunkIF->fPhysSG = false;
1683 int rc = RTSemFastMutexCreate(&pTrunkIF->FastMutex);
1684 if (RT_SUCCESS(rc))
1685 {
1686#ifdef IN_RING0 /* (testcase is ring-3) */
1687 /*
1688 * Query the factory we want, then use it create and connect the trunk.
1689 */
1690 PINTNETTRUNKFACTORY pTrunkFactory = NULL;
1691 rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
1692 if (RT_SUCCESS(rc))
1693 {
1694 rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort, &pTrunkIF->pIfPort);
1695 pTrunkFactory->pfnRelease(pTrunkFactory);
1696 if (RT_SUCCESS(rc))
1697 {
1698 Assert(pTrunkIF->pIfPort);
1699 pNetwork->pTrunkIF = pTrunkIF;
1700 LogFlow(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s Network=%s\n",
1701 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
1702 return VINF_SUCCESS;
1703 }
1704 }
1705#endif /* IN_RING0 */
1706 RTSemFastMutexDestroy(pTrunkIF->FastMutex);
1707 }
1708 RTMemFree(pTrunkIF);
1709 LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
1710 rc, pszName, pNetwork->szTrunk, pNetwork->szName));
1711 return rc;
1712}
1713
1714
1715
1716/**
1717 * Close a network which was opened/created using intnetR0OpenNetwork()/intnetR0CreateNetwork().
1718 *
1719 * @param pNetwork The network to close.
1720 * @param pSession The session handle.
1721 */
1722static int intnetR0NetworkClose(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
1723{
1724 LogFlow(("intnetR0NetworkClose: pNetwork=%p pSession=%p\n", pNetwork, pSession));
1725 AssertPtrReturn(pSession, VERR_INVALID_PARAMETER);
1726 AssertPtrReturn(pNetwork, VERR_INVALID_PARAMETER);
1727
1728 int rc = SUPR0ObjRelease(pNetwork->pvObj, pSession);
1729 LogFlow(("intnetR0NetworkClose: return %Rrc\n", rc));
1730 return rc;
1731}
1732
1733
1734/**
1735 * Object destructor callback.
1736 * This is called for reference counted objectes when the count reaches 0.
1737 *
1738 * @param pvObj The object pointer.
1739 * @param pvUser1 Pointer to the network.
1740 * @param pvUser2 Pointer to the INTNET instance data.
1741 */
1742static DECLCALLBACK(void) intnetR0NetworkDestruct(void *pvObj, void *pvUser1, void *pvUser2)
1743{
1744 LogFlow(("intnetR0NetworkDestruct: pvObj=%p pvUser1=%p pvUser2=%p\n", pvObj, pvUser1, pvUser2));
1745 PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1;
1746 PINTNET pIntNet = (PINTNET)pvUser2;
1747 Assert(pNetwork->pIntNet == pIntNet);
1748
1749 /* take the create/destroy sem. */
1750 RTSemFastMutexRequest(pIntNet->FastMutex);
1751
1752 /*
1753 * Deactivate the trunk connection first (if any).
1754 */
1755 if (pNetwork->pTrunkIF)
1756 intnetR0TrunkIfActivate(pNetwork->pTrunkIF, false /* fActive */);
1757
1758 /*
1759 * Unlink the network.
1760 * Note that it needn't be in the list if we failed during creation.
1761 */
1762 PINTNETNETWORK pPrev = pIntNet->pNetworks;
1763 if (pPrev == pNetwork)
1764 pIntNet->pNetworks = pNetwork->pNext;
1765 else
1766 {
1767 for (; pPrev; pPrev = pPrev->pNext)
1768 if (pPrev->pNext == pNetwork)
1769 {
1770 pPrev->pNext = pNetwork->pNext;
1771 break;
1772 }
1773 }
1774 pNetwork->pNext = NULL;
1775 pNetwork->pvObj = NULL;
1776
1777 /*
1778 * Because of the undefined order of the per session object dereferencing when closing a session,
1779 * we have to handle the case where the network is destroyed before the interfaces. We'll
1780 * deal with this by simply orphaning the interfaces.
1781 */
1782 RTSemFastMutexRequest(pNetwork->FastMutex);
1783
1784 PINTNETIF pCur = pNetwork->pIFs;
1785 while (pCur)
1786 {
1787 PINTNETIF pNext = pCur->pNext;
1788 pCur->pNext = NULL;
1789 pCur->pNetwork = NULL;
1790 pCur = pNext;
1791 }
1792
1793 /* Grab and zap the trunk pointer before leaving the mutex. */
1794 PINTNETTRUNKIF pTrunkIF = pNetwork->pTrunkIF;
1795 pNetwork->pTrunkIF = NULL;
1796
1797 RTSemFastMutexRelease(pNetwork->FastMutex);
1798
1799 /*
1800 * If there is a trunk, delete it.
1801 * Note that this may tak a while if we're unlucky...
1802 */
1803 if (pTrunkIF)
1804 intnetR0TrunkIfDestroy(pTrunkIF, pNetwork);
1805
1806 /*
1807 * Free resources.
1808 */
1809 RTSemFastMutexDestroy(pNetwork->FastMutex);
1810 pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
1811 RTMemFree(pNetwork);
1812
1813 /* release the create/destroy sem. (can be done before trunk destruction.) */
1814 RTSemFastMutexRelease(pIntNet->FastMutex);
1815}
1816
1817
1818/**
1819 * Opens an existing network.
1820 *
1821 * @returns VBox status code.
1822 * @param pIntNet The instance data.
1823 * @param pSession The current session.
1824 * @param pszNetwork The network name. This has a valid length.
1825 * @param enmTrunkType The trunk type.
1826 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
1827 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
1828 * @param ppNetwork Where to store the pointer to the network on success.
1829 */
1830static int intnetR0OpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
1831 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
1832{
1833 LogFlow(("intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
1834 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
1835
1836 /* just pro forma validation, the caller is internal. */
1837 AssertPtr(pIntNet);
1838 AssertPtr(pSession);
1839 AssertPtr(pszNetwork);
1840 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
1841 AssertPtr(pszTrunk);
1842 Assert(!(fFlags & ~(INTNET_OPEN_FLAGS_PUBLIC)));
1843 AssertPtr(ppNetwork);
1844 *ppNetwork = NULL;
1845
1846 /*
1847 * Search networks by name.
1848 */
1849 PINTNETNETWORK pCur;
1850 uint8_t cchName = strlen(pszNetwork);
1851 Assert(cchName && cchName < sizeof(pCur->szName)); /* caller ensures this */
1852
1853 pCur = pIntNet->pNetworks;
1854 while (pCur)
1855 {
1856 if ( pCur->cchName == cchName
1857 && !memcmp(pCur->szName, pszNetwork, cchName))
1858 {
1859 /*
1860 * Found the network, now check that we have the same ideas
1861 * about the trunk setup and security.
1862 */
1863 int rc;
1864 if ( enmTrunkType == kIntNetTrunkType_WhateverNone
1865 || ( pCur->enmTrunkType == enmTrunkType
1866 && !strcmp(pCur->szTrunk, pszTrunk)))
1867 {
1868 if (!((pCur->fFlags ^ fFlags) & (INTNET_OPEN_FLAGS_PUBLIC)))
1869 {
1870
1871 /*
1872 * Increment the reference and check that the session
1873 * can access this network.
1874 */
1875 rc = SUPR0ObjAddRef(pCur->pvObj, pSession);
1876 if (RT_SUCCESS(rc))
1877 {
1878 if (!(pCur->fFlags & INTNET_OPEN_FLAGS_PUBLIC))
1879 rc = SUPR0ObjVerifyAccess(pCur->pvObj, pSession, pCur->szName);
1880 if (RT_SUCCESS(rc))
1881 *ppNetwork = pCur;
1882 else
1883 SUPR0ObjRelease(pCur->pvObj, pSession);
1884 }
1885 else if (rc == VERR_WRONG_ORDER)
1886 rc = VERR_NOT_FOUND; /* destruction race, pretend the other isn't there. */
1887 }
1888 else
1889 rc = VERR_INTNET_INCOMPATIBLE_FLAGS;
1890 }
1891 else
1892 rc = VERR_INTNET_INCOMPATIBLE_TRUNK;
1893
1894 LogFlow(("intnetR0OpenNetwork: returns %Rrc *ppNetwork=%p\n", rc, *ppNetwork));
1895 return rc;
1896 }
1897 pCur = pCur->pNext;
1898 }
1899
1900 LogFlow(("intnetR0OpenNetwork: returns VERR_NOT_FOUND\n"));
1901 return VERR_NOT_FOUND;
1902}
1903
1904
1905/**
1906 * Creates a new network.
1907 *
1908 * The call must own the INTNET::FastMutex and has already attempted
1909 * opening the network and found it to be non-existing.
1910 *
1911 * @returns VBox status code.
1912 * @param pIntNet The instance data.
1913 * @param pSession The session handle.
1914 * @param pszNetwork The name of the network. This must be at least one character long and no longer
1915 * than the INTNETNETWORK::szName.
1916 * @param enmTrunkType The trunk type.
1917 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
1918 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
1919 * @param ppNetwork Where to store the network. In the case of failure whatever is returned
1920 * here should be dereferenced outside the INTNET::FastMutex.
1921 */
1922static int intnetR0CreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
1923 const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
1924{
1925 LogFlow(("intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
1926 pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
1927
1928 /* just pro forma validation, the caller is internal. */
1929 AssertPtr(pIntNet);
1930 AssertPtr(pSession);
1931 AssertPtr(pszNetwork);
1932 Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
1933 AssertPtr(pszTrunk);
1934 Assert(!(fFlags & ~(INTNET_OPEN_FLAGS_PUBLIC)));
1935 AssertPtr(ppNetwork);
1936 *ppNetwork = NULL;
1937
1938 /*
1939 * Allocate and initialize.
1940 */
1941 PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(sizeof(*pNew));
1942 if (!pNew)
1943 return VERR_NO_MEMORY;
1944 int rc = RTSemFastMutexCreate(&pNew->FastMutex);
1945 if (RT_SUCCESS(rc))
1946 {
1947 //pNew->pIFs = NULL;
1948 pNew->pIntNet = pIntNet;
1949 //pNew->cActiveIFs = 0;
1950 pNew->fFlags = fFlags;
1951 size_t cchName = strlen(pszNetwork);
1952 pNew->cchName = cchName;
1953 Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */
1954 memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */
1955 pNew->enmTrunkType = enmTrunkType;
1956 Assert(strlen(pszTrunk) < sizeof(pNew->szTrunk)); /* caller's responsibility. */
1957 strcpy(pNew->szTrunk, pszTrunk);
1958
1959 /*
1960 * Register the object in the current session and link it into the network list.
1961 */
1962 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);
1963 if (pNew->pvObj)
1964 {
1965 pNew->pNext = pIntNet->pNetworks;
1966 pIntNet->pNetworks = pNew;
1967
1968 /*
1969 * Check if the current session is actually allowed to create and open
1970 * the network. It is possible to implement network name based policies
1971 * and these must be checked now. SUPR0ObjRegister does no such checks.
1972 */
1973 rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
1974 if (RT_SUCCESS(rc))
1975 {
1976 /*
1977 * Connect the trunk.
1978 */
1979 rc = intnetR0NetworkCreateTrunkIf(pNew, pSession);
1980 if (RT_SUCCESS(rc))
1981 {
1982 *ppNetwork = pNew;
1983 LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
1984 return VINF_SUCCESS;
1985 }
1986 }
1987
1988 /*
1989 * We unlink it here so it cannot be opened when the caller leaves
1990 * INTNET::FastMutex before dereferencing it.
1991 */
1992 Assert(pIntNet->pNetworks == pNew);
1993 pIntNet->pNetworks = pNew->pNext;
1994 pNew->pNext = NULL;
1995
1996 *ppNetwork = pNew;
1997 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
1998 return rc;
1999 }
2000 rc = VERR_NO_MEMORY;
2001
2002 RTSemFastMutexDestroy(pNew->FastMutex);
2003 pNew->FastMutex = NIL_RTSEMFASTMUTEX;
2004 }
2005 RTMemFree(pNew);
2006 LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
2007 return rc;
2008}
2009
2010
2011/**
2012 * Opens a network interface and connects it to the specified network.
2013 *
2014 * @returns VBox status code.
2015 * @param pIntNet The internal network instance.
2016 * @param pSession The session handle.
2017 * @param pszNetwork The network name.
2018 * @param enmTrunkType The trunk type.
2019 * @param pszTrunk The trunk name. Its meaning is specfic to the type.
2020 * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
2021 * @param fRestrictAccess Whether new participants should be subjected to access check or not.
2022 * @param cbSend The send buffer size.
2023 * @param cbRecv The receive buffer size.
2024 * @param phIf Where to store the handle to the network interface.
2025 */
2026INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork,
2027 INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
2028 unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
2029{
2030 LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
2031 pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf));
2032
2033 /*
2034 * Validate input.
2035 */
2036 AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
2037
2038 AssertPtrReturn(pszNetwork, VERR_INVALID_PARAMETER);
2039 const char *pszNetworkEnd = (const char *)memchr(pszNetwork, '\0', INTNET_MAX_NETWORK_NAME);
2040 AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
2041 size_t cchNetwork = pszNetworkEnd - pszNetwork;
2042 AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
2043
2044 if (pszTrunk)
2045 {
2046 AssertPtrReturn(pszTrunk, VERR_INVALID_PARAMETER);
2047 const char *pszTrunkEnd = (const char *)memchr(pszTrunk, '\0', INTNET_MAX_TRUNK_NAME);
2048 AssertReturn(pszTrunkEnd, VERR_INVALID_PARAMETER);
2049 }
2050 else
2051 pszTrunk = "";
2052
2053 AssertMsgReturn(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End,
2054 ("%d\n", enmTrunkType), VERR_INVALID_PARAMETER);
2055 switch (enmTrunkType)
2056 {
2057 case kIntNetTrunkType_None:
2058 case kIntNetTrunkType_WhateverNone:
2059 AssertReturn(!*pszTrunk, VERR_INVALID_PARAMETER);
2060 break;
2061
2062 case kIntNetTrunkType_NetFlt:
2063 AssertReturn(pszTrunk, VERR_INVALID_PARAMETER);
2064 break;
2065
2066 default:
2067 return VERR_NOT_IMPLEMENTED;
2068 }
2069
2070 AssertMsgReturn(!(fFlags & ~(INTNET_OPEN_FLAGS_PUBLIC)), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2071 AssertPtrReturn(phIf, VERR_INVALID_PARAMETER);
2072
2073 /*
2074 * Acquire the mutex to serialize open/create.
2075 */
2076 int rc = RTSemFastMutexRequest(pIntNet->FastMutex);
2077 if (RT_FAILURE(rc))
2078 return rc;
2079
2080 /*
2081 * Try open / create the network and create an interface on it for the caller to use.
2082 *
2083 * Note that because of the destructors grabbing INTNET::FastMutex and us being required
2084 * to own this semaphore for the entire network opening / creation and interface creation
2085 * sequence, intnetR0CreateNetwork will have to defer the network cleanup to us on failure.
2086 */
2087 PINTNETNETWORK pNetwork = NULL;
2088 rc = intnetR0OpenNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
2089 if (RT_SUCCESS(rc) || rc == VERR_NOT_FOUND)
2090 {
2091 bool fCloseNetwork = true;
2092 if (rc == VERR_NOT_FOUND)
2093 rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
2094 if (RT_SUCCESS(rc))
2095 rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, &fCloseNetwork, phIf);
2096
2097 RTSemFastMutexRelease(pIntNet->FastMutex);
2098
2099 if (RT_FAILURE(rc) && pNetwork && fCloseNetwork)
2100 intnetR0NetworkClose(pNetwork, pSession);
2101 }
2102 else
2103 RTSemFastMutexRelease(pIntNet->FastMutex);
2104
2105 LogFlow(("INTNETR0Open: return %Rrc *phIf=%RX32\n", rc, *phIf));
2106 return rc;
2107}
2108
2109
2110/**
2111 * VMMR0 request wrapper for GMMR0MapUnmapChunk.
2112 *
2113 * @returns see GMMR0MapUnmapChunk.
2114 * @param pIntNet The internal networking instance.
2115 * @param pSession The session handle.
2116 * @param pReq The request packet.
2117 */
2118INTNETR0DECL(int) INTNETR0OpenReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETOPENREQ pReq)
2119{
2120 if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
2121 return VERR_INVALID_PARAMETER;
2122 return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->enmTrunkType, pReq->szTrunk,
2123 pReq->fFlags, pReq->cbSend, pReq->cbRecv, &pReq->hIf);
2124}
2125
2126
2127/**
2128 * Destroys an instance of the Ring-0 internal networking service.
2129 *
2130 * @param pIntNet Pointer to the instance data.
2131 */
2132INTNETR0DECL(void) INTNETR0Destroy(PINTNET pIntNet)
2133{
2134 LogFlow(("INTNETR0Destroy: pIntNet=%p\n", pIntNet));
2135
2136 /*
2137 * Allow NULL pointers.
2138 */
2139 if (!pIntNet)
2140 return;
2141 AssertPtrReturnVoid(pIntNet);
2142
2143 /*
2144 * There is not supposed to be any networks hanging around at this time.
2145 */
2146 Assert(pIntNet->pNetworks == NULL);
2147 if (pIntNet->FastMutex != NIL_RTSEMFASTMUTEX)
2148 {
2149 RTSemFastMutexDestroy(pIntNet->FastMutex);
2150 pIntNet->FastMutex = NIL_RTSEMFASTMUTEX;
2151 }
2152 if (pIntNet->IfHandles.Spinlock != NIL_RTSPINLOCK)
2153 {
2154 RTSpinlockDestroy(pIntNet->IfHandles.Spinlock);
2155 pIntNet->IfHandles.Spinlock = NIL_RTSPINLOCK;
2156 }
2157
2158 RTMemFree(pIntNet);
2159}
2160
2161
2162/**
2163 * Create an instance of the Ring-0 internal networking service.
2164 *
2165 * @returns VBox status code.
2166 * @param ppIntNet Where to store the instance pointer.
2167 */
2168INTNETR0DECL(int) INTNETR0Create(PINTNET *ppIntNet)
2169{
2170 LogFlow(("INTNETR0Create: ppIntNet=%p\n", ppIntNet));
2171 int rc = VERR_NO_MEMORY;
2172 PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
2173 if (pIntNet)
2174 {
2175 //pIntNet->pNetworks = NULL;
2176 //pIntNet->IfHandles.paEntries = NULL;
2177 //pIntNet->IfHandles.cAllocated = 0;
2178 pIntNet->IfHandles.iHead = UINT32_MAX;
2179 pIntNet->IfHandles.iTail = UINT32_MAX;
2180
2181 rc = RTSemFastMutexCreate(&pIntNet->FastMutex);
2182 if (RT_SUCCESS(rc))
2183 {
2184 rc = RTSpinlockCreate(&pIntNet->IfHandles.Spinlock);
2185 if (RT_SUCCESS(rc))
2186 {
2187 *ppIntNet = pIntNet;
2188 LogFlow(("INTNETR0Create: returns VINF_SUCCESS *ppIntNet=%p\n", pIntNet));
2189 return VINF_SUCCESS;
2190 }
2191 RTSemFastMutexDestroy(pIntNet->FastMutex);
2192 }
2193 RTMemFree(pIntNet);
2194 }
2195 *ppIntNet = NULL;
2196 LogFlow(("INTNETR0Create: returns %Rrc\n", rc));
2197 return rc;
2198}
2199
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