VirtualBox

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

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

Created tstIntNet-1 for checking that capturing an interface works on darwin.

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