VirtualBox

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

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

We 'connect' to an internal network, not 'attach'. (Both terms was used.)

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