VirtualBox

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

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

logging changes.

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