VirtualBox

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

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

Corrected some more log statements and synced some function docs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.3 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 fRestrictAccess Whether new participants should be subjected to access check or not.
1272 * @param pSession The session handle.
1273 * @param ppNetwork Where to store the network.
1274 */
1275static int INTNETCreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, bool fRestrictAccess, PINTNETNETWORK *ppNetwork)
1276{
1277 LogFlow(("INTNETCreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} ppNetwork=%p\n",
1278 pIntNet, pSession, pszNetwork, pszNetwork, ppNetwork));
1279
1280 Assert(VALID_PTR(pIntNet));
1281 Assert(VALID_PTR(pSession));
1282 Assert(VALID_PTR(pszNetwork));
1283 Assert(VALID_PTR(ppNetwork));
1284 *ppNetwork = NULL;
1285
1286 /*
1287 * Verify that the network doesn't exist.
1288 */
1289 const uint8_t cchName = strlen(pszNetwork);
1290 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1291 RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
1292 for (PINTNETNETWORK pCur = pIntNet->pNetworks; pCur; pCur = pCur->pNext)
1293 if ( pCur->cchName == cchName
1294 && !memcmp(pCur->szName, pszNetwork, cchName))
1295 {
1296 RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
1297 LogFlow(("INTNETCreateNetwork: returns VERR_ALREADY_EXISTS\n"));
1298 return VERR_ALREADY_EXISTS;
1299 }
1300 RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
1301
1302 /*
1303 * Allocate and initialize.
1304 */
1305 PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(sizeof(*pNew));
1306 if (!pNew)
1307 return VERR_NO_MEMORY;
1308 int rc = RTSemFastMutexCreate(&pNew->FastMutex);
1309 if (VBOX_SUCCESS(rc))
1310 {
1311 //pNew->pIFs = NULL;
1312 pNew->pIntNet = pIntNet;
1313 pNew->cchName = cchName;
1314 pNew->fRestrictAccess = fRestrictAccess;
1315 Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */
1316 memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */
1317
1318 /*
1319 * Register the object in the current session.
1320 */
1321 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, INTNETNetworkDestruct, pNew, pIntNet);
1322 if (pNew->pvObj)
1323 {
1324 /*
1325 * Insert the network into the list.
1326 * This must be done before we attempt any SUPR0ObjRelease call.
1327 */
1328 RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
1329 pNew->pNext = pIntNet->pNetworks;
1330 pIntNet->pNetworks = pNew;
1331 RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
1332
1333 /*
1334 * Check if the current session is actually allowed to create and open
1335 * the network. It is possible to implement network name based policies
1336 * and these must be checked now. SUPR0ObjRegister does no such checks.
1337 */
1338 rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
1339 if (VBOX_SUCCESS(rc))
1340 {
1341 *ppNetwork = pNew;
1342 LogFlow(("INTNETCreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
1343 return VINF_SUCCESS;
1344 }
1345
1346 /* The release will destroy the object. */
1347 SUPR0ObjRelease(pNew->pvObj, pSession);
1348 LogFlow(("INTNETCreateNetwork: returns %Vrc\n", rc));
1349 return rc;
1350 }
1351 rc = VERR_NO_MEMORY;
1352
1353 RTSemFastMutexDestroy(pNew->FastMutex);
1354 pNew->FastMutex = NIL_RTSEMFASTMUTEX;
1355 }
1356 RTMemFree(pNew);
1357 LogFlow(("INTNETCreateNetwork: returns %Vrc\n", rc));
1358 return rc;
1359}
1360
1361
1362/**
1363 * Opens a network interface and attaches it to the specified network.
1364 *
1365 * @returns VBox status code.
1366 * @param pIntNet The internal network instance.
1367 * @param pSession The session handle.
1368 * @param pszNetwork The network name.
1369 * @param cbSend The send buffer size.
1370 * @param cbRecv The receive buffer size.
1371 * @param fRestrictAccess Whether new participants should be subjected to access check or not.
1372 * @param phIf Where to store the handle to the network interface.
1373 */
1374INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, unsigned cbSend, unsigned cbRecv, bool fRestrictAccess, PINTNETIFHANDLE phIf)
1375{
1376 LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} cbSend=%u cbRecv=%u phIf=%p\n",
1377 pIntNet, pSession, pszNetwork, pszNetwork, cbSend, cbRecv, phIf));
1378
1379 /*
1380 * Validate input.
1381 */
1382 AssertReturn(VALID_PTR(pIntNet), VERR_INVALID_PARAMETER);
1383 AssertReturn(VALID_PTR(pszNetwork), VERR_INVALID_PARAMETER);
1384 const char *pszNetworkEnd = (const char *)memchr(pszNetwork, '\0', INTNET_MAX_NETWORK_NAME);
1385 AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
1386 size_t cchNetwork = pszNetworkEnd - pszNetwork;
1387 AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
1388 AssertReturn(VALID_PTR(phIf), VERR_INVALID_PARAMETER);
1389
1390 /*
1391 * Acquire the mutex to serialize open/create.
1392 */
1393 int rc = RTSemFastMutexRequest(pIntNet->FastMutex);
1394 if (VBOX_FAILURE(rc))
1395 return rc;
1396
1397 /*
1398 * Try open/create the network.
1399 */
1400 PINTNETNETWORK pNetwork;
1401 rc = INTNETOpenNetwork(pIntNet, pSession, pszNetwork, &pNetwork);
1402 if (rc == VERR_FILE_NOT_FOUND)
1403 rc = INTNETCreateNetwork(pIntNet, pSession, pszNetwork, fRestrictAccess, &pNetwork);
1404 if (VBOX_SUCCESS(rc))
1405 {
1406 /*
1407 * Create a new interface to this network.
1408 * On failure we close the network. On success it remains open untill the
1409 * interface is destroyed or the last session is doing cleanup (order problems).
1410 */
1411 rc = INTNETNetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, phIf);
1412 if (VBOX_FAILURE(rc))
1413 INTNETNetworkClose(pNetwork, pSession);
1414 }
1415
1416 RTSemFastMutexRelease(pIntNet->FastMutex);
1417
1418 LogFlow(("INTNETR0Open: return %Vrc *phIf=%RX32\n", rc, *phIf));
1419 return rc;
1420}
1421
1422
1423/**
1424 * Destroys an instance of the Ring-0 internal networking service.
1425 *
1426 * @param pIntNet Pointer to the instance data.
1427 */
1428INTNETR0DECL(void) INTNETR0Destroy(PINTNET pIntNet)
1429{
1430 LogFlow(("INTNETR0Destroy: pIntNet=%p\n", pIntNet));
1431
1432 /*
1433 * Allow NULL pointers.
1434 */
1435 if (!pIntNet)
1436 return;
1437
1438 /*
1439 * There is not supposed to be any networks hanging around at this time.
1440 */
1441 Assert(pIntNet->pNetworks == NULL);
1442 if (pIntNet->FastMutex != NIL_RTSEMFASTMUTEX)
1443 {
1444 RTSemFastMutexDestroy(pIntNet->FastMutex);
1445 pIntNet->FastMutex = NIL_RTSEMFASTMUTEX;
1446 }
1447 if (pIntNet->Spinlock != NIL_RTSPINLOCK)
1448 {
1449 RTSpinlockDestroy(pIntNet->Spinlock);
1450 pIntNet->Spinlock = NIL_RTSPINLOCK;
1451 }
1452
1453 RTMemFree(pIntNet);
1454}
1455
1456
1457/**
1458 * Create an instance of the Ring-0 internal networking service.
1459 *
1460 * @returns VBox status code.
1461 * @param ppIntNet Where to store the instance pointer.
1462 */
1463INTNETR0DECL(int) INTNETR0Create(PINTNET *ppIntNet)
1464{
1465 LogFlow(("INTNETR0Create: ppIntNet=%p\n", ppIntNet));
1466 int rc = VERR_NO_MEMORY;
1467 PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
1468 if (pIntNet)
1469 {
1470 //pIntNet->pNetworks = NULL;
1471 //pIntNet->IfHandles.paEntries = NULL;
1472 //pIntNet->IfHandles.cAllocated = 0;
1473 pIntNet->IfHandles.iHead = ~0U;
1474 pIntNet->IfHandles.iTail = ~0U;
1475
1476 rc = RTSemFastMutexCreate(&pIntNet->FastMutex);
1477 if (VBOX_SUCCESS(rc))
1478 {
1479 rc = RTSpinlockCreate(&pIntNet->Spinlock);
1480 if (VBOX_SUCCESS(rc))
1481 {
1482 *ppIntNet = pIntNet;
1483 LogFlow(("INTNETR0Create: returns VINF_SUCCESS *ppIntNet=%p\n", pIntNet));
1484 return VINF_SUCCESS;
1485 }
1486 RTSemFastMutexDestroy(pIntNet->FastMutex);
1487 }
1488 RTMemFree(pIntNet);
1489 }
1490 *ppIntNet = NULL;
1491 LogFlow(("INTNETR0Create: returns %Vrc\n", rc));
1492 return rc;
1493}
1494
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