VirtualBox

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

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

intnet: More TrunkIf code.

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

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