VirtualBox

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

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

typos.

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