VirtualBox

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

Last change on this file since 698 was 1, checked in by vboxsync, 55 years ago

import

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