SrvIntNetR0.cpp revision 5233d97903d9bb60831b9b555d23771c60b78722
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/* $Id$ */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * Internal networking - The ring 0 service.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * available from http://www.virtualbox.org. This file is free software;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * General Public License (GPL) as published by the Free Software
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * additional information or have any questions.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/*******************************************************************************
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync* Header Files *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync*******************************************************************************/
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#define LOG_GROUP LOG_GROUP_SRV_INTNET
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <VBox/intnet.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <VBox/sup.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <VBox/pdm.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <VBox/log.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/asm.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/alloc.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/semaphore.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/spinlock.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/thread.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/assert.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync#include <iprt/string.h>
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/*******************************************************************************
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync* Structures and Typedefs *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync*******************************************************************************/
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/**
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * A network interface.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNETIF
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the next interface. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync struct INTNETIF *pNext;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The current MAC address for the interface. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PDMMAC Mac;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Set if the INTNET::Mac member is valid. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync bool fMacSet;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Set if the interface is in promiscuous mode.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * In promiscuous mode the interface will receive all packages except the one it's sending. */
c889bbab784ba8552102ce776b6c67b982017861vboxsync bool fPromiscuous;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Number of yields done to try make the interface read pending data.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * We will stop yeilding when this reaches a threshold assuming that the VM is paused or
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * that it simply isn't worth all the delay. It is cleared when a successful send has been done.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync uint32_t cYields;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to the current exchange buffer (ring-0). */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETBUF pIntBuf;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to ring-3 mapping of the current exchange buffer. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync R3PTRTYPE(PINTNETBUF) pIntBufR3;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to the default exchange buffer for the interface. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PINTNETBUF pIntBufDefault;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Pointer to ring-3 mapping of the default exchange buffer. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync RTSEMEVENT Event;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Number of threads sleeping on the Event semaphore. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync uint32_t cSleepers;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The interface handle.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * should return with the appropriate error condition. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync INTNETIFHANDLE hIf;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Pointer to the network this interface is connected to. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync struct INTNETNETWORK *pNetwork;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The session this interface is associated with. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync PSUPDRVSESSION pSession;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The SUPR0 object id. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync void *pvObj;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync} INTNETIF;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsynctypedef INTNETIF *PINTNETIF;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync/**
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync * Internal representation of a network.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsynctypedef struct INTNETNETWORK
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync{
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The Next network in the chain.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * This is protected by the INTNET::Spinlock. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync struct INTNETNETWORK *pNext;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network mutex.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * It protects everything dealing with this network. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSEMFASTMUTEX FastMutex;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of interfaces attached to the network. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETIF pIFs;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the instance data. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync struct INTNET *pIntNet;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The SUPR0 object id. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync void *pvObj;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Access restricted? */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync bool fRestrictAccess;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The length of the network name. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync uint8_t cchName;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network name. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync char szName[INTNET_MAX_NETWORK_NAME];
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync} INTNETNETWORK;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef INTNETNETWORK *PINTNETNETWORK;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Handle table entry.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef union INTNETHTE
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the object we're a handle for. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETIF pIF;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Index to the next free entry. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync uintptr_t iNext;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync} INTNETHTE;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef INTNETHTE *PINTNETHTE;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Handle table.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNETHT
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync{
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to the handle table. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETHTE paEntries;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The number of allocated handles. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync uint32_t cAllocated;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The index of the first free handle entry.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * UINT32_MAX means empty list. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync uint32_t volatile iHead;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync /** The index of the last free handle entry.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * UINT32_MAX means empty list. */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync uint32_t volatile iTail;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync} INTNETHT;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsynctypedef INTNETHT *PINTNETHT;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Internal networking instance.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNET
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Mutex protecting the network creation. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync RTSEMFASTMUTEX FastMutex;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Spinlock protecting the linked list of networks and the interface handle translation table. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSPINLOCK Spinlock;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of networks. Protected by INTNET::Spinlock. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync PINTNETNETWORK volatile pNetworks;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Handle table for the interfaces. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync INTNETHT IfHandles;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync} INTNET;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
445661c86e95894713da707c6c9787b7507dfce6vboxsync/**
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Validates and translates an interface handle to a interface pointer.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync *
445661c86e95894713da707c6c9787b7507dfce6vboxsync * @returns Pointer to interface.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @returns NULL if the handle is invalid.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param pIntNet Pointer to the instance data.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param hIF The interface handle to validate and translate.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncDECLINLINE(PINTNETIF) INTNETHandle2IFPtr(PINTNET pIntNet, INTNETIFHANDLE hIF)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync{
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync Assert(pIntNet);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if ((hIF & INTNET_HANDLE_MAGIC) != INTNET_HANDLE_MAGIC)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync return NULL;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync PINTNETHT pHT = &pIntNet->IfHandles;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync const uint32_t i = hIF & INTNET_HANDLE_INDEX_MASK;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync PINTNETIF pIF = NULL;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if ( i < pHT->cAllocated
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync && pHT->paEntries[i].iNext >= INTNET_HANDLE_MAX
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync && pHT->paEntries[i].iNext != UINT32_MAX)
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync pIF = pHT->paEntries[i].pIF;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync return pIF;
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync}
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync/**
c889bbab784ba8552102ce776b6c67b982017861vboxsync * Allocates a handle for an interface.
c889bbab784ba8552102ce776b6c67b982017861vboxsync *
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns Handle on success.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns Invalid handle on failure.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pIntNet Pointer to the instance data.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param pIF The interface which we're allocating a handle for.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
c5d2523548cc57504b829f53f1362b848a84542cvboxsyncstatic INTNETIFHANDLE INTNETHandleAllocate(PINTNET pIntNet, PINTNETIF pIF)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Assert(pIF);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync Assert(pIntNet);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync unsigned cTries = 10;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETHT pHT = &pIntNet->IfHandles;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETHTE paNew = NULL;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync for (;;)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync {
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /*
234af146205f61c4aa0be736abb06601a89facb8vboxsync * Check the free list.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
234af146205f61c4aa0be736abb06601a89facb8vboxsync uint32_t i = pHT->iHead;
234af146205f61c4aa0be736abb06601a89facb8vboxsync if (i != UINT32_MAX)
234af146205f61c4aa0be736abb06601a89facb8vboxsync {
234af146205f61c4aa0be736abb06601a89facb8vboxsync pHT->iHead = pHT->paEntries[i].iNext;
234af146205f61c4aa0be736abb06601a89facb8vboxsync if (pHT->iHead == UINT32_MAX)
234af146205f61c4aa0be736abb06601a89facb8vboxsync pHT->iTail = UINT32_MAX;
234af146205f61c4aa0be736abb06601a89facb8vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync pHT->paEntries[i].pIF = pIF;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (paNew)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync RTMemFree(paNew);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync return i | INTNET_HANDLE_MAGIC;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync }
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Leave the spinlock and allocate a new array.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync const unsigned cNew = pHT->cAllocated + 128;
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (--cTries <= 0)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync AssertMsgFailed(("Giving up!\n"));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync break;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync }
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync paNew = (PINTNETHTE)RTMemAlloc(sizeof(*paNew) * cNew);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync if (!paNew)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync break;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /*
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Acquire the spinlock and check if someone raced us.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (pHT->cAllocated < cNew)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* copy the current table. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync memcpy(paNew, pHT->paEntries, pHT->cAllocated * sizeof(*paNew));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* link the new entries into the free chain. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync i = pHT->cAllocated;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync uint32_t iTail = pHT->iTail;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (iTail == UINT32_MAX)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync pHT->iHead = iTail = i++;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync while (i < cNew)
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync paNew[iTail].iNext = i;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync iTail = i++;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync paNew[iTail].iNext = UINT32_MAX;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pHT->iTail = iTail;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* update the handle table. */
1829a716128b3e2d42bcee064a15c553dbd44798vboxsync pHT->cAllocated = cNew;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync paNew = (PINTNETHTE)ASMAtomicXchgPtr((void * volatile *)&pHT->paEntries, paNew);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (paNew)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTMemFree(paNew);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync return INTNET_HANDLE_INVALID;
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync}
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Frees a handle.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync *
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync * @returns Handle on success.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns Invalid handle on failure.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIntNet Pointer to the instance data.
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync * @param h The handle we're freeing.
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncstatic void INTNETHandleFree(PINTNET pIntNet, INTNETIFHANDLE h)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Assert(INTNETHandle2IFPtr(pIntNet, h));
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync PINTNETHT pHT = &pIntNet->IfHandles;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync const uint32_t i = h & INTNET_HANDLE_INDEX_MASK;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (i < pHT->cAllocated)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync {
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /*
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Insert at the end of the free list.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pHT->paEntries[i].iNext = UINT32_MAX;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync const uint32_t iTail = pHT->iTail;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (iTail != UINT32_MAX)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync pHT->paEntries[iTail].iNext = i;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync else
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync pHT->iHead = i;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pHT->iTail = i;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync else
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync AssertMsgFailed(("%d >= %d\n", i, pHT->cAllocated));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync}
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync#ifdef IN_INTNET_TESTCASE
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/**
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Reads the next frame in the buffer.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The caller is responsible for ensuring that there is a valid frame in the buffer.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns Size of the frame in bytes.
234af146205f61c4aa0be736abb06601a89facb8vboxsync * @param pBuf The buffer.
234af146205f61c4aa0be736abb06601a89facb8vboxsync * @param pRingBuff The ring buffer to read from.
234af146205f61c4aa0be736abb06601a89facb8vboxsync * @param pvFrame Where to put the frame. The caller is responsible for
234af146205f61c4aa0be736abb06601a89facb8vboxsync * ensuring that there is sufficient space for the frame.
234af146205f61c4aa0be736abb06601a89facb8vboxsync */
234af146205f61c4aa0be736abb06601a89facb8vboxsyncstatic unsigned INTNETRingReadFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, void *pvFrame)
234af146205f61c4aa0be736abb06601a89facb8vboxsync{
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(pRingBuf->offRead < pBuf->cbBuf);
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(pRingBuf->offRead >= pRingBuf->offStart);
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(pRingBuf->offRead < pRingBuf->offEnd);
234af146205f61c4aa0be736abb06601a89facb8vboxsync uint32_t offRead = pRingBuf->offRead;
234af146205f61c4aa0be736abb06601a89facb8vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offRead);
234af146205f61c4aa0be736abb06601a89facb8vboxsync const void *pvFrameIn = INTNETHdrGetFramePtr(pHdr, pBuf);
234af146205f61c4aa0be736abb06601a89facb8vboxsync unsigned cb = pHdr->cbFrame;
234af146205f61c4aa0be736abb06601a89facb8vboxsync memcpy(pvFrame, pvFrameIn, cb);
234af146205f61c4aa0be736abb06601a89facb8vboxsync
234af146205f61c4aa0be736abb06601a89facb8vboxsync /* skip the frame */
234af146205f61c4aa0be736abb06601a89facb8vboxsync offRead += pHdr->offFrame + cb;
234af146205f61c4aa0be736abb06601a89facb8vboxsync offRead = RT_ALIGN_32(offRead, sizeof(INTNETHDR));
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
234af146205f61c4aa0be736abb06601a89facb8vboxsync if (offRead >= pRingBuf->offEnd)
234af146205f61c4aa0be736abb06601a89facb8vboxsync offRead = pRingBuf->offStart;
234af146205f61c4aa0be736abb06601a89facb8vboxsync ASMAtomicXchgU32(&pRingBuf->offRead, offRead);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return cb;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync}
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync#endif
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/**
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Writes a frame packet to the buffer.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns VBox status code.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pBuf The buffer.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pRingBuf The ring buffer to read from.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pvFrame The frame to write.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param cbFrame The size of the frame.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncstatic int INTNETRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync{
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Validate input.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync Assert(pBuf);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync Assert(pRingBuf);
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(pvFrame);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(cbFrame >= sizeof(PDMMAC) * 2);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync uint32_t offWrite = pRingBuf->offWrite;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync uint32_t offRead = pRingBuf->offRead;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (offRead <= offWrite)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Try fit it all before the end of the buffer.
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync {
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync pHdr->u16Type = INTNETHDR_TYPE_FRAME;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync pHdr->cbFrame = cbFrame;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync pHdr->offFrame = sizeof(INTNETHDR);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync memcpy(pHdr + 1, pvFrame, cbFrame);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync offWrite += cb + sizeof(INTNETHDR);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (offWrite >= pRingBuf->offEnd)
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync offWrite = pRingBuf->offStart;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync return VINF_SUCCESS;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync }
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /*
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Try fit the frame at the start of the buffer.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * (The header fits before the end of the buffer because of alignment.)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (offRead - pRingBuf->offStart > cb) /* not >= ! */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pHdr->u16Type = INTNETHDR_TYPE_FRAME;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->cbFrame = cbFrame;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync memcpy(pvFrameOut, pvFrame, cbFrame);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync offWrite = pRingBuf->offStart + cb;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
041d531fb5794a8a4cf6c35886d89ec25cbbdde2vboxsync return VINF_SUCCESS;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync }
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync }
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The reader is ahead of the writer, try fit it into that space.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync {
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->u16Type = INTNETHDR_TYPE_FRAME;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->cbFrame = cbFrame;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->offFrame = sizeof(INTNETHDR);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync memcpy(pHdr + 1, pvFrame, cbFrame);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync offWrite += cb + sizeof(INTNETHDR);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync ASMAtomicXchgU32(&pRingBuf->offWrite, offWrite);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return VINF_SUCCESS;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* (it didn't fit) */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** @todo stats */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync return VERR_BUFFER_OVERFLOW;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync}
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync/**
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Ethernet header.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync#pragma pack(1)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsynctypedef struct INTNETETHERHDR
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync{
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PDMMAC MacDst;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PDMMAC MacSrc;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync} INTNETETHERHDR;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync#pragma pack()
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsynctypedef INTNETETHERHDR *PINTNETETHERHDR;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Sends a frame to a specific interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIf The interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pvFrame The frame data.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param cbFrame The size of the frame.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsyncstatic void intnetIfSend(PINTNETIF pIf, const void *pvFrame, unsigned cbFrame)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync LogFlow(("intnetIfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync int rc = INTNETRingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync if (VBOX_SUCCESS(rc))
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync {
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pIf->cYields = 0;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync RTSemEventSignal(pIf->Event);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync }
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /*
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Retry a few times, yielding the CPU in between.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * But don't let a unresponsive VM harm performance, so give up after a short while.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (pIf->cYields < 100)
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync {
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync unsigned cYields = 10;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync do
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync {
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync RTSemEventSignal(pIf->Event);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync RTThreadYield();
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync rc = INTNETRingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync if (VBOX_SUCCESS(rc))
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync {
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatRecvs);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync RTSemEventSignal(pIf->Event);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync return;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync }
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync pIf->cYields++;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync } while (--cYields > 0);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync }
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /* ok, the frame is lost. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync RTSemEventSignal(pIf->Event);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync}
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync/**
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Sends a frame.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync *
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * This function will distribute the frame to the interfaces it is addressed to.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * It will also update the MAC address of the sender.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The caller must own the network mutex.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pNetwork The network the frame is being sent to.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * @param pIfSender The interface sending the frame.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * @param pvFrame The frame data.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param cbFrame The size of the frame.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsyncstatic void intnetNetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, const void *pvFrame, unsigned cbFrame)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync{
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /*
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * Assert reality.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync */
c5d2523548cc57504b829f53f1362b848a84542cvboxsync Assert(pNetwork);
e4527e0a08e2d635a679ae2947d42195f30a2ce2vboxsync Assert(pIfSender);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(pNetwork == pIfSender->pNetwork);
e4527e0a08e2d635a679ae2947d42195f30a2ce2vboxsync Assert(pvFrame);
8929a16e87a515b7071399479548158b8c5fbdd2vboxsync if (cbFrame < sizeof(PDMMAC) * 2)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync return;
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Send statistics.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync STAM_REL_COUNTER_INC(&pIfSender->pIntBuf->cStatSends);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync STAM_REL_COUNTER_ADD(&pIfSender->pIntBuf->cbStatSend, cbFrame);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
e4527e0a08e2d635a679ae2947d42195f30a2ce2vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Inspect the header updating the mac address of the sender in the process.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETETHERHDR pEthHdr = (PINTNETETHERHDR)pvFrame;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (memcmp(&pEthHdr->MacSrc, &pIfSender->Mac, sizeof(pIfSender->Mac)))
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** @todo stats */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &pEthHdr->MacSrc));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pIfSender->Mac = pEthHdr->MacSrc;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pIfSender->fMacSet = true;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if ( (pEthHdr->MacDst.au8[0] & 1) /* multicast address */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync || ( pEthHdr->MacDst.au16[0] == 0xffff /* broadcast address. s*/
db3d025f28c59aececbbda4174fa513496c89b2bvboxsync && pEthHdr->MacDst.au16[1] == 0xffff
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync && pEthHdr->MacDst.au16[2] == 0xffff)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync )
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync {
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * This is a broadcast or multicast address. For the present we treat those
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * two as the same - investigating multicast is left for later.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync *
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * Write the packet to all the interfaces and signal them.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync Log2(("Broadcast\n"));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (pIf != pIfSender)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync intnetIfSend(pIf, pvFrame, cbFrame);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync else
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Only send to the interfaces with matching a MAC address.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Log2(("Dst=%.6Rhxs\n", &pEthHdr->MacDst));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync {
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Log2(("Dst=%.6Rhxs ?==? %.6Rhxs\n", &pEthHdr->MacDst, &pIf->Mac));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if ( ( !pIf->fMacSet
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync || !memcmp(&pIf->Mac, &pEthHdr->MacDst, sizeof(pIf->Mac)))
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync || ( pIf->fPromiscuous
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync && pIf != pIfSender /* promiscuous mode: omit the sender */))
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync intnetIfSend(pIf, pvFrame, cbFrame);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync}
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Sends one or more frames.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * The function will first the frame which is passed as the optional
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * arguments pvFrame and cbFrame. These are optional since it also
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * possible to chain together one or more frames in the send buffer
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * which the function will process after considering it's arguments.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns VBox status code.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIntNet The instance data.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param hIf The interface handle.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pvFrame Pointer to the frame.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param cbFrame Size of the frame.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, const void *pvFrame, unsigned cbFrame)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync{
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync LogFlow(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /*
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Validate input.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync if (!pIf)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return VERR_INVALID_HANDLE;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (pvFrame && cbFrame)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync {
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync AssertReturn(cbFrame < 0x8000, VERR_INVALID_PARAMETER);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync AssertReturn(VALID_PTR(pvFrame), VERR_INVALID_PARAMETER);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync AssertReturn(VALID_PTR((uint8_t *)pvFrame + cbFrame - 1), VERR_INVALID_PARAMETER);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync /* This is the better place to crash, probe the buffer. */
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync ASMProbeReadBuffer(pvFrame, cbFrame);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync }
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync if (VBOX_FAILURE(rc))
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync return rc;
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /*
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Process the argument.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (pvFrame && cbFrame)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync intnetNetworkSend(pIf->pNetwork, pIf, pvFrame, cbFrame);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /*
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Process the send buffer.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync while (pIf->pIntBuf->Send.offRead != pIf->pIntBuf->Send.offWrite)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync {
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Send the frame if the type is sane. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pIf->pIntBuf + pIf->pIntBuf->Send.offRead);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync if (pHdr->u16Type == INTNETHDR_TYPE_FRAME)
0ff2f0d33dea0e82857c2131d43f637c206a8163vboxsync {
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (pvCurFrame)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync intnetNetworkSend(pIf->pNetwork, pIf, pvCurFrame, pHdr->cbFrame);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync }
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync /* else: ignore the frame */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Skip to the next frame. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync INTNETRingSkipFrame(pIf->pIntBuf, &pIf->pIntBuf->Send);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync }
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync}
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/**
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * VMMR0 request wrapper for INTNETR0IfSend.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync *
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns see INTNETR0IfSend.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pIntNet The internal networking instance.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pReq The request packet.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PINTNETIFSENDREQ pReq)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync{
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return VERR_INVALID_PARAMETER;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return INTNETR0IfSend(pIntNet, pReq->hIf, NULL, 0);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync}
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/**
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Maps the default buffer into ring 3.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync *
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns VBox status code.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pIntNet The instance data.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param hIf The interface handle.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param ppRing3Buf Where to store the address of the ring-3 mapping.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync{
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Validate input.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
c5d2523548cc57504b829f53f1362b848a84542cvboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
c5d2523548cc57504b829f53f1362b848a84542cvboxsync if (!pIf)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return VERR_INVALID_HANDLE;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync AssertReturn(VALID_PTR(ppRing3Buf), VERR_INVALID_PARAMETER);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
fbb3513a43135c633f7f51544c4bdfce748929bfvboxsync * ASSUMES that only the process that created an interface can use it.
fbb3513a43135c633f7f51544c4bdfce748929bfvboxsync * ASSUMES that we created the ring-3 mapping when selecting or
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * allocating the buffer.
fbb3513a43135c633f7f51544c4bdfce748929bfvboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (VBOX_FAILURE(rc))
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync return rc;
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync *ppRing3Buf = pIf->pIntBufR3;
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync LogFlow(("INTNETR0IfGetRing3Buffer: returns %Vrc *ppRing3Buf=%p\n", rc, *ppRing3Buf));
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync return rc;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync}
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/**
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * VMMR0 request wrapper for INTNETR0IfGetRing3Buffer.
c889bbab784ba8552102ce776b6c67b982017861vboxsync *
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns see INTNETR0IfGetRing3Buffer.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * @param pIntNet The internal networking instance.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pReq The request packet.
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync */
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsyncINTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PINTNETIFGETRING3BUFFERREQ pReq)
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync{
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
c5d2523548cc57504b829f53f1362b848a84542cvboxsync return VERR_INVALID_PARAMETER;
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync return INTNETR0IfGetRing3Buffer(pIntNet, pReq->hIf, &pReq->pRing3Buf);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync}
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync/**
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Gets the ring-0 address of the current buffer.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync *
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns VBox status code.
c889bbab784ba8552102ce776b6c67b982017861vboxsync * @param pIntNet The instance data.
c889bbab784ba8552102ce776b6c67b982017861vboxsync * @param hIf The interface handle.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param ppRing0Buf Where to store the address of the ring-3 mapping.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsyncINTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PINTNETBUF *ppRing0Buf)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync{
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync /*
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Validate input.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync */
c889bbab784ba8552102ce776b6c67b982017861vboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
c889bbab784ba8552102ce776b6c67b982017861vboxsync if (!pIf)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync return VERR_INVALID_HANDLE;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync AssertReturn(VALID_PTR(ppRing0Buf), VERR_INVALID_PARAMETER);
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync /*
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Assuming that we're in Ring-0, this should be rather simple :-)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync if (VBOX_FAILURE(rc))
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return rc;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync *ppRing0Buf = pIf->pIntBuf;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync LogFlow(("INTNETR0IfGetRing0Buffer: returns %Vrc *ppRing0Buf=%p\n", rc, *ppRing0Buf));
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync return rc;
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync}
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync#if 0
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync/**
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Gets the physical addresses of the default interface buffer.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns VBox status code.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pIntNet The instance data.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param hIF The interface handle.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param paPages Where to store the addresses. (The reserved fields will be set to zero.)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param cPages
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsyncINTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync{
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /*
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Validate input.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync if (!pIf)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync return VERR_INVALID_HANDLE;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync AssertReturn(VALID_PTR(paPages), VERR_INVALID_PARAMETER);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync AssertReturn(VALID_PTR((uint8_t *)&paPages[cPages] - 1), VERR_INVALID_PARAMETER);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /*
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Assuming that we're in Ring-0, this should be rather simple :-)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (VBOX_FAILURE(rc))
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync return rc;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /** @todo make a SUPR0 api for obtaining the array. SUPR0 is keeping track of everything, there
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * is no need for any extra bookkeeping here.. */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync //*ppRing0Buf = pIf->pIntBuf;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync //return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync return VERR_NOT_IMPLEMENTED;
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync}
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync#endif
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
c889bbab784ba8552102ce776b6c67b982017861vboxsync/**
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Sets the promiscuous mode property of an interface.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync *
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns VBox status code.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param pIntNet The instance handle.
c889bbab784ba8552102ce776b6c67b982017861vboxsync * @param hIf The interface handle.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsyncINTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, bool fPromiscuous)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync{
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Get and validate essential handles.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (!pIf)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync LogFlow(("INTNETR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync return VERR_INVALID_HANDLE;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (pIf->fPromiscuous != fPromiscuous)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync {
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync hIf, !fPromiscuous, !!fPromiscuous));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync ASMAtomicXchgSize(&pIf->fPromiscuous, !!fPromiscuous);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync }
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync return VINF_SUCCESS;
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync}
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/**
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * VMMR0 request wrapper for INTNETR0IfSetPromiscuousMode.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns see INTNETR0IfSetPromiscuousMode.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIntNet The internal networking instance.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pReq The request packet.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncINTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync{
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync return VERR_INVALID_PARAMETER;
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync return INTNETR0IfSetPromiscuousMode(pIntNet, pReq->hIf, pReq->fPromiscuous);
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync}
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/**
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Wait for the interface to get signaled.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The interface will be signaled when is put into the receive buffer.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns VBox status code.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pIntNet The instance handle.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param hIf The interface handle.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * used if indefinite wait is desired.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, uint32_t cMillies)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync{
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync LogFlow(("INTNETR0IfWait: pIntNet=%p hIf=%RX32 cMillies=%u\n", pIntNet, hIf, cMillies));
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync /*
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * Get and validate essential handles.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync */
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync AssertReturn(pIntNet, VERR_INVALID_PARAMETER);
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync if (!pIf)
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync {
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync LogFlow(("INTNETR0IfWait: returns VERR_INVALID_HANDLE\n"));
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync return VERR_INVALID_HANDLE;
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync }
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync const INTNETIFHANDLE hIfSelf = pIf->hIf;
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync const RTSEMEVENT Event = pIf->Event;
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync if ( hIfSelf != hIf
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync && Event != NIL_RTSEMEVENT)
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync {
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync LogFlow(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync return VERR_SEM_DESTROYED;
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync }
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync /*
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync * It is tempting to check if there is data to be read here,
d9a86bd327291cd44d5f6da6e08bec728aae68bbvboxsync * but the problem with such an approach is that it will cause
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync * one unnecessary supervisor->user->supervisor trip. There is
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * already a risk for such, so we don't need to increase this.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /*
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Increment the number of waiters before starting the wait.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Upon wakeup we must assert reality checking that we're not
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * already destroyed or in the process of being destroyed.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync */
c5d2523548cc57504b829f53f1362b848a84542cvboxsync ASMAtomicIncU32(&pIf->cSleepers);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync int rc = RTSemEventWaitNoResume(Event, cMillies);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync if (pIf->Event == Event)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync {
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync ASMAtomicDecU32(&pIf->cSleepers);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (pIf->hIf != hIf)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync rc = VERR_SEM_DESTROYED;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync }
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync else
c889bbab784ba8552102ce776b6c67b982017861vboxsync rc = VERR_SEM_DESTROYED;
LogFlow(("INTNETR0IfWait: returns %Vrc\n", rc));
return rc;
}
/**
* VMMR0 request wrapper for INTNETR0IfWait.
*
* @returns see INTNETR0IfWait.
* @param pIntNet The internal networking instance.
* @param pReq The request packet.
*/
INTNETR0DECL(int) INTNETR0IfWaitReq(PINTNET pIntNet, PINTNETIFWAITREQ pReq)
{
if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
return VERR_INVALID_PARAMETER;
return INTNETR0IfWait(pIntNet, pReq->hIf, pReq->cMillies);
}
/**
* Close an interface.
*
* @returns VBox status code.
* @param pIntNet The instance handle.
* @param hIf The interface handle.
*/
INTNETR0DECL(int) INTNETR0IfClose(PINTNET pIntNet, INTNETIFHANDLE hIf)
{
LogFlow(("INTNETR0IfClose: pIntNet=%p hIf=%RX32\n", pIntNet, hIf));
/*
* Get and validate essential handles.
*/
AssertReturn(VALID_PTR(pIntNet), VERR_INVALID_PARAMETER);
PINTNETIF pIf = INTNETHandle2IFPtr(pIntNet, hIf);
if (!pIf)
return VERR_INVALID_HANDLE;
int rc = SUPR0ObjRelease(pIf->pvObj, pIf->pSession);
LogFlow(("INTNETR0IfClose: returns %Vrc\n", rc));
return rc;
}
/**
* VMMR0 request wrapper for INTNETR0IfCloseReq.
*
* @returns see INTNETR0IfClose.
* @param pIntNet The internal networking instance.
* @param pReq The request packet.
*/
INTNETR0DECL(int) INTNETR0IfCloseReq(PINTNET pIntNet, PINTNETIFCLOSEREQ pReq)
{
if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
return VERR_INVALID_PARAMETER;
return INTNETR0IfClose(pIntNet, pReq->hIf);
}
/**
* Interface destructor callback.
* This is called for reference counted objectes when the count reaches 0.
*
* @param pvObj The object pointer.
* @param pvUser1 Pointer to the interface.
* @param pvUser2 Pointer to the INTNET instance data.
*/
static DECLCALLBACK(void) INTNETIfDestruct(void *pvObj, void *pvUser1, void *pvUser2)
{
LogFlow(("INTNETIfDestruct: pvObj=%p pvUser1=%p pvUser2=%p\n", pvObj, pvUser1, pvUser2));
PINTNETIF pIf = (PINTNETIF)pvUser1;
PINTNET pIntNet = (PINTNET)pvUser2;
/*
* Delete the interface handle so the object no longer can be opened.
*/
if (pIf->hIf != INTNET_HANDLE_INVALID)
{
INTNETHandleFree(pIntNet, pIf->hIf);
ASMAtomicXchgSize(&pIf->hIf, INTNET_HANDLE_INVALID);
}
/*
* If we've got a network unlink ourselves from it.
* Because of cleanup order we might be an orphan now.
*/
if (pIf->pNetwork)
SUPR0ObjRelease(pIf->pNetwork->pvObj, pIf->pSession);
if (pIf->pNetwork)
{
PINTNETNETWORK pNetwork = pIf->pNetwork;
RTSemFastMutexRequest(pNetwork->FastMutex);
if (pNetwork->pIFs == pIf)
pNetwork->pIFs = pIf->pNext;
else
{
PINTNETIF pPrev = pNetwork->pIFs;
while (pPrev)
{
if (pPrev->pNext == pIf)
{
pPrev->pNext = pIf->pNext;
break;
}
pPrev = pPrev->pNext;
}
Assert(pPrev);
}
RTSemFastMutexRelease(pNetwork->FastMutex);
pIf->pNext = NULL;
}
/*
* Wakeup anyone waiting on this interface.
*
* We *must* make sure they have woken up properly and realized
* that the interface is no longer valid.
*/
if (pIf->Event != NIL_RTSEMEVENT)
{
RTSEMEVENT Event = pIf->Event;
ASMAtomicXchgSize(&pIf->Event, NIL_RTSEMEVENT);
unsigned cMaxWait = 0x1000;
while (pIf->cSleepers && cMaxWait-- > 0)
{
RTSemEventSignal(Event);
RTThreadYield();
}
if (pIf->cSleepers)
{
RTThreadSleep(1);
cMaxWait = pIf->cSleepers;
while (pIf->cSleepers && cMaxWait-- > 0)
{
RTSemEventSignal(Event);
RTThreadSleep(10);
}
}
RTSemEventDestroy(Event);
}
/*
* Unmap user buffer.
*/
if (pIf->pIntBuf != pIf->pIntBufDefault)
{
/** @todo user buffer */
}
/*
* Unmap and Free the default buffer.
*/
if (pIf->pIntBufDefault)
{
SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
pIf->pIntBufDefault = NULL;
pIf->pIntBufDefaultR3 = 0;
pIf->pIntBuf = NULL;
pIf->pIntBufR3 = 0;
}
/*
* The interface.
*/
pIf->pvObj = NULL;
RTMemFree(pIf);
}
/**
* Creates a new network interface.
*
* The call must have opened the network for the new interface
* and is responsible for closing it on failure. On success
* it must leave the network opened so the interface destructor
* can close it.
*
* @returns VBox status code.
* @param pNetwork The network.
* @param pSession The session handle.
* @param cbSend The size of the send buffer.
* @param cbRecv The size of the receive buffer.
* @param phIf Where to store the interface handle.
*/
static int INTNETNetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
{
LogFlow(("INTNETNetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u phIf=%p\n",
pNetwork, pSession, cbSend, cbRecv, phIf));
/*
* Assert input.
*/
Assert(VALID_PTR(pNetwork));
Assert(VALID_PTR(phIf));
/*
* Allocate and initialize the interface structure.
*/
PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
if (!pIf)
return VERR_NO_MEMORY;
memset(&pIf->Mac, 0xff, sizeof(pIf->Mac)); /* broadcast */
//pIf->fMacSet = 0;
int rc = RTSemEventCreate(&pIf->Event);
if (VBOX_SUCCESS(rc))
{
pIf->pSession = pSession;
pIf->pNetwork = pNetwork;
/*
* Create the default buffer.
*/
cbRecv = RT_ALIGN(RT_MAX(cbRecv, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
cbSend = RT_ALIGN(RT_MAX(cbSend, sizeof(INTNETHDR) * 4), sizeof(INTNETHDR));
const unsigned cbBuf = RT_ALIGN(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR)) + cbRecv + cbSend;
rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
if (VBOX_SUCCESS(rc))
{
pIf->pIntBuf = pIf->pIntBufDefault;
pIf->pIntBufR3 = pIf->pIntBufDefaultR3;
pIf->pIntBuf->cbBuf = cbBuf;
pIf->pIntBuf->cbRecv = cbRecv;
pIf->pIntBuf->cbSend = cbSend;
/* receive ring buffer. */
pIf->pIntBuf->Recv.offStart = RT_ALIGN_32(sizeof(*pIf->pIntBuf), sizeof(INTNETHDR));
pIf->pIntBuf->Recv.offRead = pIf->pIntBuf->Recv.offStart;
pIf->pIntBuf->Recv.offWrite = pIf->pIntBuf->Recv.offStart;
pIf->pIntBuf->Recv.offEnd = pIf->pIntBuf->Recv.offStart + cbRecv;
/* send ring buffer. */
pIf->pIntBuf->Send.offStart = pIf->pIntBuf->Recv.offEnd;
pIf->pIntBuf->Send.offRead = pIf->pIntBuf->Send.offStart;
pIf->pIntBuf->Send.offWrite = pIf->pIntBuf->Send.offStart;
pIf->pIntBuf->Send.offEnd = pIf->pIntBuf->Send.offStart + cbSend;
/*
* Link the interface to the network.
*/
rc = RTSemFastMutexRequest(pNetwork->FastMutex);
if (VBOX_SUCCESS(rc))
{
pIf->pNext = pNetwork->pIFs;
pNetwork->pIFs = pIf;
RTSemFastMutexRelease(pNetwork->FastMutex);
/*
* Register the interface with the session.
*/
pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, INTNETIfDestruct, pIf, pNetwork->pIntNet);
if (pIf->pvObj)
{
pIf->hIf = INTNETHandleAllocate(pNetwork->pIntNet, pIf);
if (pIf->hIf != INTNET_HANDLE_INVALID)
{
*phIf = pIf->hIf;
LogFlow(("INTNETNetworkCreateIf: returns VINF_SUCCESS *phIf=%p\n", *phIf));
return VINF_SUCCESS;
}
rc = VERR_NO_MEMORY;
SUPR0ObjRelease(pIf->pvObj, pSession);
LogFlow(("INTNETNetworkCreateIf: returns %Vrc\n", rc));
return rc;
}
rc = VERR_NO_MEMORY;
RTSemFastMutexDestroy(pNetwork->FastMutex);
pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
}
SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
pIf->pIntBufDefault = NULL;
pIf->pIntBuf = NULL;
}
RTSemEventDestroy(pIf->Event);
pIf->Event = NIL_RTSEMEVENT;
}
RTMemFree(pIf);
LogFlow(("INTNETNetworkCreateIf: returns %Vrc\n", rc));
return rc;
}
/**
* Close a network which was opened/created using INTNETOpenNetwork()/INTNETCreateNetwork().
*
* @param pNetwork The network to close.
* @param pSession The session handle.
*/
static int INTNETNetworkClose(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
{
LogFlow(("INTNETNetworkClose: pNetwork=%p pSession=%p\n", pNetwork, pSession));
AssertReturn(VALID_PTR(pSession), VERR_INVALID_PARAMETER);
AssertReturn(VALID_PTR(pNetwork), VERR_INVALID_PARAMETER);
PINTNET pIntNet = pNetwork->pIntNet;
RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
int rc = SUPR0ObjRelease(pNetwork->pvObj, pSession);
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
LogFlow(("INTNETNetworkClose: return %Vrc\n", rc));
return rc;
}
/**
* Object destructor callback.
* This is called for reference counted objectes when the count reaches 0.
*
* @param pvObj The object pointer.
* @param pvUser1 Pointer to the network.
* @param pvUser2 Pointer to the INTNET instance data.
*/
static DECLCALLBACK(void) INTNETNetworkDestruct(void *pvObj, void *pvUser1, void *pvUser2)
{
LogFlow(("INTNETNetworkDestruct: pvObj=%p pvUser1=%p pvUser2=%p\n", pvObj, pvUser1, pvUser2));
RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1;
PINTNET pIntNet = (PINTNET)pvUser2;
Assert(pNetwork->pIntNet == pIntNet);
/*
* Unlink the network.s
*/
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
PINTNETNETWORK pPrev = pIntNet->pNetworks;
if (pPrev == pNetwork)
pIntNet->pNetworks = pNetwork->pNext;
else
{
for (; pPrev; pPrev = pPrev->pNext)
if (pPrev->pNext == pNetwork)
{
pPrev->pNext = pNetwork->pNext;
break;
}
Assert(pPrev);
}
pNetwork->pNext = NULL;
pNetwork->pvObj = NULL;
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
/*
* Because of the undefined order of the per session object dereferencing when closing a session,
* we have to handle the case where the network is destroyed before the interfaces. We'll
* deal with this by simply orphaning the interfaces.
*/
RTSemFastMutexRequest(pNetwork->FastMutex);
PINTNETIF pCur = pNetwork->pIFs;
while (pCur)
{
PINTNETIF pNext = pCur->pNext;
pCur->pNext = NULL;
pCur->pNetwork = NULL;
pCur = pNext;
}
RTSemFastMutexRelease(pNetwork->FastMutex);
/*
* Free resources.
*/
RTSemFastMutexDestroy(pNetwork->FastMutex);
pNetwork->FastMutex = NIL_RTSEMFASTMUTEX;
RTMemFree(pNetwork);
}
/**
* Opens an existing network.
*
* @returns VBox status code.
* @param pIntNet The instance data.
* @param pSession The current session.
* @param pszNetwork The network name. This has a valid length.
* @param ppNetwork Where to store the pointer to the network on success.
*/
static int INTNETOpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, PINTNETNETWORK *ppNetwork)
{
LogFlow(("INTNETOpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} ppNetwork=%p\n",
pIntNet, pSession, pszNetwork, pszNetwork, ppNetwork));
Assert(VALID_PTR(pIntNet));
Assert(VALID_PTR(pSession));
Assert(VALID_PTR(pszNetwork));
Assert(VALID_PTR(ppNetwork));
*ppNetwork = NULL;
/*
* Search networks by name.
*/
PINTNETNETWORK pCur;
uint8_t cchName = strlen(pszNetwork);
Assert(cchName && cchName < sizeof(pCur->szName)); /* caller ensures this */
RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
pCur = pIntNet->pNetworks;
while (pCur)
{
if ( pCur->cchName == cchName
&& !memcmp(pCur->szName, pszNetwork, cchName))
{
/*
* Increment the reference and check that the
* session can access this network.
*/
int rc = SUPR0ObjAddRef(pCur->pvObj, pSession);
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
if (VBOX_SUCCESS(rc))
{
if (pCur->fRestrictAccess)
rc = SUPR0ObjVerifyAccess(pCur->pvObj, pSession, pCur->szName);
if (VBOX_SUCCESS(rc))
*ppNetwork = pCur;
else
{
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
SUPR0ObjRelease(pCur->pvObj, pSession);
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
}
}
LogFlow(("INTNETOpenNetwork: returns %Vrc *ppNetwork=%p\n", rc, *ppNetwork));
return rc;
}
pCur = pCur->pNext;
}
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
LogFlow(("INTNETOpenNetwork: returns VERR_FILE_NOT_FOUND\n"));
return VERR_FILE_NOT_FOUND;
}
/**
* Creates a new network.
*
* The call must own the INTNET::FastMutex and has already
* attempted opening the network.
*
* @returns VBox status code.
* @param pIntNet The instance data.
* @param pszNetwork The name of the network. This must be at least one character long and no longer
* than the INTNETNETWORK::szName.
* @param fRestrictAccess Whether new participants should be subjected to access check or not.
* @param pSession The session handle.
* @param ppNetwork Where to store the network.
*/
static int INTNETCreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, bool fRestrictAccess, PINTNETNETWORK *ppNetwork)
{
LogFlow(("INTNETCreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} ppNetwork=%p\n",
pIntNet, pSession, pszNetwork, pszNetwork, ppNetwork));
Assert(VALID_PTR(pIntNet));
Assert(VALID_PTR(pSession));
Assert(VALID_PTR(pszNetwork));
Assert(VALID_PTR(ppNetwork));
*ppNetwork = NULL;
/*
* Verify that the network doesn't exist.
*/
const uint8_t cchName = strlen(pszNetwork);
RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
for (PINTNETNETWORK pCur = pIntNet->pNetworks; pCur; pCur = pCur->pNext)
if ( pCur->cchName == cchName
&& !memcmp(pCur->szName, pszNetwork, cchName))
{
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
LogFlow(("INTNETCreateNetwork: returns VERR_ALREADY_EXISTS\n"));
return VERR_ALREADY_EXISTS;
}
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
/*
* Allocate and initialize.
*/
PINTNETNETWORK pNew = (PINTNETNETWORK)RTMemAllocZ(sizeof(*pNew));
if (!pNew)
return VERR_NO_MEMORY;
int rc = RTSemFastMutexCreate(&pNew->FastMutex);
if (VBOX_SUCCESS(rc))
{
//pNew->pIFs = NULL;
pNew->pIntNet = pIntNet;
pNew->cchName = cchName;
pNew->fRestrictAccess = fRestrictAccess;
Assert(cchName && cchName < sizeof(pNew->szName)); /* caller's responsibility. */
memcpy(pNew->szName, pszNetwork, cchName); /* '\0' by alloc. */
/*
* Register the object in the current session.
*/
pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, INTNETNetworkDestruct, pNew, pIntNet);
if (pNew->pvObj)
{
/*
* Insert the network into the list.
* This must be done before we attempt any SUPR0ObjRelease call.
*/
RTSpinlockAcquire(pIntNet->Spinlock, &Tmp);
pNew->pNext = pIntNet->pNetworks;
pIntNet->pNetworks = pNew;
RTSpinlockRelease(pIntNet->Spinlock, &Tmp);
/*
* Check if the current session is actually allowed to create and open
* the network. It is possible to implement network name based policies
* and these must be checked now. SUPR0ObjRegister does no such checks.
*/
rc = SUPR0ObjVerifyAccess(pNew->pvObj, pSession, pNew->szName);
if (VBOX_SUCCESS(rc))
{
*ppNetwork = pNew;
LogFlow(("INTNETCreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNew));
return VINF_SUCCESS;
}
/* The release will destroy the object. */
SUPR0ObjRelease(pNew->pvObj, pSession);
LogFlow(("INTNETCreateNetwork: returns %Vrc\n", rc));
return rc;
}
rc = VERR_NO_MEMORY;
RTSemFastMutexDestroy(pNew->FastMutex);
pNew->FastMutex = NIL_RTSEMFASTMUTEX;
}
RTMemFree(pNew);
LogFlow(("INTNETCreateNetwork: returns %Vrc\n", rc));
return rc;
}
/**
* Opens a network interface and attaches it to the specified network.
*
* @returns VBox status code.
* @param pIntNet The internal network instance.
* @param pSession The session handle.
* @param pszNetwork The network name.
* @param cbSend The send buffer size.
* @param cbRecv The receive buffer size.
* @param fRestrictAccess Whether new participants should be subjected to access check or not.
* @param phIf Where to store the handle to the network interface.
*/
INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, unsigned cbSend, unsigned cbRecv, bool fRestrictAccess, PINTNETIFHANDLE phIf)
{
LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} cbSend=%u cbRecv=%u phIf=%p\n",
pIntNet, pSession, pszNetwork, pszNetwork, cbSend, cbRecv, phIf));
/*
* Validate input.
*/
AssertReturn(VALID_PTR(pIntNet), VERR_INVALID_PARAMETER);
AssertReturn(VALID_PTR(pszNetwork), VERR_INVALID_PARAMETER);
const char *pszNetworkEnd = (const char *)memchr(pszNetwork, '\0', INTNET_MAX_NETWORK_NAME);
AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
size_t cchNetwork = pszNetworkEnd - pszNetwork;
AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
AssertReturn(VALID_PTR(phIf), VERR_INVALID_PARAMETER);
/*
* Acquire the mutex to serialize open/create.
*/
int rc = RTSemFastMutexRequest(pIntNet->FastMutex);
if (VBOX_FAILURE(rc))
return rc;
/*
* Try open/create the network.
*/
PINTNETNETWORK pNetwork;
rc = INTNETOpenNetwork(pIntNet, pSession, pszNetwork, &pNetwork);
if (rc == VERR_FILE_NOT_FOUND)
rc = INTNETCreateNetwork(pIntNet, pSession, pszNetwork, fRestrictAccess, &pNetwork);
if (VBOX_SUCCESS(rc))
{
/*
* Create a new interface to this network.
* On failure we close the network. On success it remains open until the
* interface is destroyed or the last session is doing cleanup (order problems).
*/
rc = INTNETNetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, phIf);
if (VBOX_FAILURE(rc))
INTNETNetworkClose(pNetwork, pSession);
}
RTSemFastMutexRelease(pIntNet->FastMutex);
LogFlow(("INTNETR0Open: return %Vrc *phIf=%RX32\n", rc, *phIf));
return rc;
}
/**
* VMMR0 request wrapper for GMMR0MapUnmapChunk.
*
* @returns see GMMR0MapUnmapChunk.
* @param pIntNet The internal networking instance.
* @param pSession The session handle.
* @param pReq The request packet.
*/
INTNETR0DECL(int) INTNETR0OpenReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETOPENREQ pReq)
{
if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
return VERR_INVALID_PARAMETER;
return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->cbSend, pReq->cbRecv, pReq->fRestrictAccess, &pReq->hIf);
}
/**
* Destroys an instance of the Ring-0 internal networking service.
*
* @param pIntNet Pointer to the instance data.
*/
INTNETR0DECL(void) INTNETR0Destroy(PINTNET pIntNet)
{
LogFlow(("INTNETR0Destroy: pIntNet=%p\n", pIntNet));
/*
* Allow NULL pointers.
*/
if (!pIntNet)
return;
/*
* There is not supposed to be any networks hanging around at this time.
*/
Assert(pIntNet->pNetworks == NULL);
if (pIntNet->FastMutex != NIL_RTSEMFASTMUTEX)
{
RTSemFastMutexDestroy(pIntNet->FastMutex);
pIntNet->FastMutex = NIL_RTSEMFASTMUTEX;
}
if (pIntNet->Spinlock != NIL_RTSPINLOCK)
{
RTSpinlockDestroy(pIntNet->Spinlock);
pIntNet->Spinlock = NIL_RTSPINLOCK;
}
RTMemFree(pIntNet);
}
/**
* Create an instance of the Ring-0 internal networking service.
*
* @returns VBox status code.
* @param ppIntNet Where to store the instance pointer.
*/
INTNETR0DECL(int) INTNETR0Create(PINTNET *ppIntNet)
{
LogFlow(("INTNETR0Create: ppIntNet=%p\n", ppIntNet));
int rc = VERR_NO_MEMORY;
PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
if (pIntNet)
{
//pIntNet->pNetworks = NULL;
//pIntNet->IfHandles.paEntries = NULL;
//pIntNet->IfHandles.cAllocated = 0;
pIntNet->IfHandles.iHead = UINT32_MAX;
pIntNet->IfHandles.iTail = UINT32_MAX;
rc = RTSemFastMutexCreate(&pIntNet->FastMutex);
if (VBOX_SUCCESS(rc))
{
rc = RTSpinlockCreate(&pIntNet->Spinlock);
if (VBOX_SUCCESS(rc))
{
*ppIntNet = pIntNet;
LogFlow(("INTNETR0Create: returns VINF_SUCCESS *ppIntNet=%p\n", pIntNet));
return VINF_SUCCESS;
}
RTSemFastMutexDestroy(pIntNet->FastMutex);
}
RTMemFree(pIntNet);
}
*ppIntNet = NULL;
LogFlow(("INTNETR0Create: returns %Vrc\n", rc));
return rc;
}