VirtualBox

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

Last change on this file since 10547 was 10547, checked in by vboxsync, 16 years ago

Don't release the network before unlink the interface, it must be the other way around.

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