VirtualBox

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

Last change on this file since 10734 was 10734, checked in by vboxsync, 16 years ago

intnet: Implemented intnetR0TrunkIfSend().

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