VirtualBox

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

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

Internal Network: Don't echo outgoing packets to the sender in promiscuous mode

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