VirtualBox

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

Last change on this file since 1599 was 1599, checked in by vboxsync, 18 years ago

added RestrictAccess key to allow to disable the policy that only VMs of the same user may attach to an internal network

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