SrvIntNetR0.cpp revision 5233d97903d9bb60831b9b555d23771c60b78722
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * Internal networking - The ring 0 service.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * 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* Header Files *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync*******************************************************************************/
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/*******************************************************************************
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync* Structures and Typedefs *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync*******************************************************************************/
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * A network interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNETIF
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the next interface. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The current MAC address for the interface. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Set if the INTNET::Mac member is valid. */
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. */
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 /** Pointer to the current exchange buffer (ring-0). */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to ring-3 mapping of the current exchange buffer. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to the default exchange buffer for the interface. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Pointer to ring-3 mapping of the default exchange buffer. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Number of threads sleeping on the Event semaphore. */
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 /** Pointer to the network this interface is connected to. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The session this interface is associated with. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The SUPR0 object id. */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync * Internal representation of a network.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The Next network in the chain.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * This is protected by the INTNET::Spinlock. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network mutex.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * It protects everything dealing with this network. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of interfaces attached to the network. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the instance data. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The SUPR0 object id. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Access restricted? */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The length of the network name. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network name. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Handle table entry.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the object we're a handle for. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Index to the next free entry. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Handle table.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNETHT
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** Pointer to the handle table. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The number of allocated handles. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The index of the first free handle entry.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * UINT32_MAX means empty list. */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync /** The index of the last free handle entry.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * UINT32_MAX means empty list. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Internal networking instance.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNET
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Mutex protecting the network creation. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Spinlock protecting the linked list of networks and the interface handle translation table. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of networks. Protected by INTNET::Spinlock. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Handle table for the interfaces. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Validates and translates an interface handle to a interface pointer.
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.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncDECLINLINE(PINTNETIF) INTNETHandle2IFPtr(PINTNET pIntNet, INTNETIFHANDLE hIF)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if ((hIF & INTNET_HANDLE_MAGIC) != INTNET_HANDLE_MAGIC)
c889bbab784ba8552102ce776b6c67b982017861vboxsync * Allocates a handle for an interface.
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.
c5d2523548cc57504b829f53f1362b848a84542cvboxsyncstatic INTNETIFHANDLE INTNETHandleAllocate(PINTNET pIntNet, PINTNETIF pIF)
234af146205f61c4aa0be736abb06601a89facb8vboxsync * Check the free list.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Leave the spinlock and allocate a new array.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync paNew = (PINTNETHTE)RTMemAlloc(sizeof(*paNew) * cNew);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Acquire the spinlock and check if someone raced us.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* copy the current table. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync memcpy(paNew, pHT->paEntries, pHT->cAllocated * sizeof(*paNew));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* link the new entries into the free chain. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync while (i < cNew)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* update the handle table. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync paNew = (PINTNETHTE)ASMAtomicXchgPtr((void * volatile *)&pHT->paEntries, paNew);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Frees a handle.
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.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncstatic void INTNETHandleFree(PINTNET pIntNet, INTNETIFHANDLE h)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Insert at the end of the free list.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync AssertMsgFailed(("%d >= %d\n", i, pHT->cAllocated));
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 * @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.
234af146205f61c4aa0be736abb06601a89facb8vboxsyncstatic unsigned INTNETRingReadFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, void *pvFrame)
234af146205f61c4aa0be736abb06601a89facb8vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offRead);
234af146205f61c4aa0be736abb06601a89facb8vboxsync const void *pvFrameIn = INTNETHdrGetFramePtr(pHdr, pBuf);
234af146205f61c4aa0be736abb06601a89facb8vboxsync /* skip the frame */
234af146205f61c4aa0be736abb06601a89facb8vboxsync Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Writes a frame packet to the buffer.
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.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncstatic int INTNETRingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, const void *pvFrame, uint32_t cbFrame)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Validate input.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offWrite == RT_ALIGN_32(offWrite, sizeof(INTNETHDR)));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offRead == RT_ALIGN_32(offRead, sizeof(INTNETHDR)));
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync const uint32_t cb = RT_ALIGN_32(cbFrame, sizeof(INTNETHDR));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Try fit it all before the end of the buffer.
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync if (pRingBuf->offEnd - offWrite >= cb + sizeof(INTNETHDR))
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Assert(offWrite <= pRingBuf->offEnd && offWrite >= pRingBuf->offStart);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (1)\n", pRingBuf->offWrite, offWrite));
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 AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync if (offRead - pRingBuf->offStart > cb) /* not >= ! */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync void *pvFrameOut = (PINTNETHDR)((uint8_t *)pBuf + pRingBuf->offStart);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync pHdr->offFrame = (intptr_t)pvFrameOut - (intptr_t)pHdr;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (2)\n", pRingBuf->offWrite, offWrite));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The reader is ahead of the writer, try fit it into that space.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync else if (offRead - offWrite > cb + sizeof(INTNETHDR)) /* not >= ! */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pBuf + offWrite);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync Log2(("WriteFrame: offWrite: %#x -> %#x (3)\n", pRingBuf->offWrite, offWrite));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* (it didn't fit) */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** @todo stats */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Ethernet header.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Sends a frame to a specific interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIf The interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pvFrame The frame data.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param cbFrame The size of the frame.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsyncstatic void intnetIfSend(PINTNETIF pIf, const void *pvFrame, unsigned cbFrame)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync LogFlow(("intnetIfSend: pIf=%p:{.hIf=%RX32}\n", pIf, pIf->hIf));
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync int rc = INTNETRingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
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.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync rc = INTNETRingWriteFrame(pIf->pIntBuf, &pIf->pIntBuf->Recv, pvFrame, cbFrame);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_ADD(&pIf->pIntBuf->cbStatRecv, cbFrame);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync } while (--cYields > 0);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync /* ok, the frame is lost. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Sends a frame.
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.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The caller must own the network mutex.
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.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsyncstatic void intnetNetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, const void *pvFrame, unsigned cbFrame)
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * Assert reality.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Send statistics.
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync STAM_REL_COUNTER_INC(&pIfSender->pIntBuf->cStatSends);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync STAM_REL_COUNTER_ADD(&pIfSender->pIntBuf->cbStatSend, cbFrame);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Inspect the header updating the mac address of the sender in the process.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PINTNETETHERHDR pEthHdr = (PINTNETETHERHDR)pvFrame;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (memcmp(&pEthHdr->MacSrc, &pIfSender->Mac, sizeof(pIfSender->Mac)))
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** @todo stats */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->Mac, &pEthHdr->MacSrc));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if ( (pEthHdr->MacDst.au8[0] & 1) /* multicast address */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync || ( pEthHdr->MacDst.au16[0] == 0xffff /* broadcast address. s*/
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.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * Write the packet to all the interfaces and signal them.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Only send to the interfaces with matching a MAC address.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync Log2(("Dst=%.6Rhxs ?==? %.6Rhxs\n", &pEthHdr->MacDst, &pIf->Mac));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync || !memcmp(&pIf->Mac, &pEthHdr->MacDst, sizeof(pIf->Mac)))
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync && pIf != pIfSender /* promiscuous mode: omit the sender */))
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Sends one or more frames.
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 * @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.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, const void *pvFrame, unsigned cbFrame)
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync LogFlow(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Validate input.
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);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync /* This is the better place to crash, probe the buffer. */
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Process the argument.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync intnetNetworkSend(pIf->pNetwork, pIf, pvFrame, cbFrame);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Process the send buffer.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync while (pIf->pIntBuf->Send.offRead != pIf->pIntBuf->Send.offWrite)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Send the frame if the type is sane. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync PINTNETHDR pHdr = (PINTNETHDR)((uintptr_t)pIf->pIntBuf + pIf->pIntBuf->Send.offRead);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync void *pvCurFrame = INTNETHdrGetFramePtr(pHdr, pIf->pIntBuf);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync intnetNetworkSend(pIf->pNetwork, pIf, pvCurFrame, pHdr->cbFrame);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync /* else: ignore the frame */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Skip to the next frame. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync INTNETRingSkipFrame(pIf->pIntBuf, &pIf->pIntBuf->Send);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * VMMR0 request wrapper for INTNETR0IfSend.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns see INTNETR0IfSend.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pIntNet The internal networking instance.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pReq The request packet.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PINTNETIFSENDREQ pReq)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return INTNETR0IfSend(pIntNet, pReq->hIf, NULL, 0);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Maps the default buffer into ring 3.
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.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Validate input.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync AssertReturn(VALID_PTR(ppRing3Buf), VERR_INVALID_PARAMETER);
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.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync LogFlow(("INTNETR0IfGetRing3Buffer: returns %Vrc *ppRing3Buf=%p\n", rc, *ppRing3Buf));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * VMMR0 request wrapper for INTNETR0IfGetRing3Buffer.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns see INTNETR0IfGetRing3Buffer.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * @param pIntNet The internal networking instance.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pReq The request packet.
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsyncINTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PINTNETIFGETRING3BUFFERREQ pReq)
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync return INTNETR0IfGetRing3Buffer(pIntNet, pReq->hIf, &pReq->pRing3Buf);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Gets the ring-0 address of the current buffer.
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.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsyncINTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PINTNETBUF *ppRing0Buf)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Validate input.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync AssertReturn(VALID_PTR(ppRing0Buf), VERR_INVALID_PARAMETER);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Assuming that we're in Ring-0, this should be rather simple :-)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync LogFlow(("INTNETR0IfGetRing0Buffer: returns %Vrc *ppRing0Buf=%p\n", rc, *ppRing0Buf));
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Gets the physical addresses of the default interface buffer.
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
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsyncINTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Validate input.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync AssertReturn(VALID_PTR(paPages), VERR_INVALID_PARAMETER);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync AssertReturn(VALID_PTR((uint8_t *)&paPages[cPages] - 1), VERR_INVALID_PARAMETER);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Assuming that we're in Ring-0, this should be rather simple :-)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
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 //return RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Sets the promiscuous mode property of an interface.
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.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsyncINTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, bool fPromiscuous)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Get and validate essential handles.
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync LogFlow(("INTNETR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log(("INTNETR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d\n",
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync ASMAtomicXchgSize(&pIf->fPromiscuous, !!fPromiscuous);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * VMMR0 request wrapper for INTNETR0IfSetPromiscuousMode.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns see INTNETR0IfSetPromiscuousMode.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIntNet The internal networking instance.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pReq The request packet.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncINTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync return INTNETR0IfSetPromiscuousMode(pIntNet, pReq->hIf, pReq->fPromiscuous);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Wait for the interface to get signaled.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * The interface will be signaled when is put into the receive buffer.
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.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncINTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, uint32_t cMillies)
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync LogFlow(("INTNETR0IfWait: pIntNet=%p hIf=%RX32 cMillies=%u\n", pIntNet, hIf, cMillies));
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * Get and validate essential handles.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync LogFlow(("INTNETR0IfWait: returns VERR_INVALID_HANDLE\n"));
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync LogFlow(("INTNETR0IfWait: returns VERR_SEM_DESTROYED\n"));
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 * 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.
return rc;
return VERR_INVALID_PARAMETER;
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
return VERR_INVALID_PARAMETER;
while (pPrev)
static int INTNETNetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, PINTNETIFHANDLE phIf)
if (!pIf)
return VERR_NO_MEMORY;
rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, INTNETIfDestruct, pIf, pNetwork->pIntNet);
return VINF_SUCCESS;
return rc;
return rc;
return rc;
* Unlink the network.s
while (pCur)
static int INTNETOpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, PINTNETNETWORK *ppNetwork)
while (pCur)
return rc;
return VERR_FILE_NOT_FOUND;
static int INTNETCreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, bool fRestrictAccess, PINTNETNETWORK *ppNetwork)
return VERR_ALREADY_EXISTS;
if (!pNew)
return VERR_NO_MEMORY;
pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, INTNETNetworkDestruct, pNew, pIntNet);
return VINF_SUCCESS;
return rc;
return rc;
INTNETR0DECL(int) INTNETR0Open(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, unsigned cbSend, unsigned cbRecv, bool fRestrictAccess, PINTNETIFHANDLE phIf)
return rc;
return rc;
return VERR_INVALID_PARAMETER;
return INTNETR0Open(pIntNet, pSession, &pReq->szNetwork[0], pReq->cbSend, pReq->cbRecv, pReq->fRestrictAccess, &pReq->hIf);
if (!pIntNet)
if (pIntNet)
//pIntNet->IfHandles.cAllocated = 0;
return VINF_SUCCESS;
return rc;