VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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