SrvIntNetR0.cpp revision 93793641488de08fd9526ca9707da8d041d552d5
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * Internal networking - The ring 0 service.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Copyright (C) 2006-2008 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* Defined Constants And Macros *
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync*******************************************************************************/
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/** @def INTNET_WITH_DHCP_SNOOPING
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Enabled DHCP snooping when in shared-mac-on-the-wire mode. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/*******************************************************************************
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync* Structures and Typedefs *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync*******************************************************************************/
c889bbab784ba8552102ce776b6c67b982017861vboxsync /** The invalid 0 entry. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** IP version 4. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** IP version 6. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** IPX. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The end of the valid values. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The usual 32-bit hack. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync/** Pointer to a network layer address type. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Address and type.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsynctypedef struct INTNETADDR
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The address type. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** The address. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync/** Pointer to an address. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/** Pointer to a const address. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Address cache for a specific network layer.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the table of addresses. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The number of valid address entries. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The number of allocated address entries. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The address size. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The size of an entry. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/** Pointer to an address cache. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/** Pointer to a const address cache. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * A network interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Unless explicitly stated, all members are protect by the network semaphore.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNETIF
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the next interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * This is protected by the INTNET::FastMutex. */
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. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Whether the interface is active or not. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Whether someone is currently in the destructor. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync bool volatile fDestroying;
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. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** Pointer to the default exchange buffer for the interface. */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync /** Pointer to ring-3 mapping of the default exchange buffer. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Event semaphore which a receiver thread will sleep on while waiting for data to arrive. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Number of threads sleeping on the Event semaphore. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The interface handle.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * should return with the appropriate error condition. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** Pointer to the network this interface is connected to.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * This is protected by the INTNET::FastMutex. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The session this interface is associated with. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The SUPR0 object id. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network layer address cache. (Indexed by type, 0 entry isn't used.) */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/** Pointer to an internal network interface. */
445661c86e95894713da707c6c9787b7507dfce6vboxsync * A trunk interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The port interface we present to the component. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The port interface we get from the component. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The trunk mutex that serializes all calls <b>to</b> the component. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** Pointer to the network we're connect to.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * This may be NULL if we're orphaned? */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** The cached MAC address of the interface the trunk is attached to.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * This is for the situations where we cannot take the out-bound
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * semaphore (the recv case) but need to make frame edits (ARP). */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** Whether to supply physical addresses with the outbound SGs. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync bool volatile fPhysSG;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** Set if the 'wire' is in promiscuous mode.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * The state of the 'host' is queried each time. */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync/** Pointer to a trunk interface. */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Internal representation of a network.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /** The Next network in the chain.
c5d2523548cc57504b829f53f1362b848a84542cvboxsync * This is protected by the INTNET::FastMutex. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of interfaces connected to the network.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * This is protected by the INTNET::FastMutex. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Pointer to the trunk interface.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Can be NULL if there is no trunk connection. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** The network mutex.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * It protects everything dealing with this network. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /** Pointer to the instance data. */
234af146205f61c4aa0be736abb06601a89facb8vboxsync /** The SUPR0 object id. */
234af146205f61c4aa0be736abb06601a89facb8vboxsync /** Pointer to the temporary buffer that is used when snooping fragmented packets.
234af146205f61c4aa0be736abb06601a89facb8vboxsync * This is allocated after this structure if we're sharing the MAC address with
234af146205f61c4aa0be736abb06601a89facb8vboxsync * the host. The buffer is INTNETNETWORK_TMP_SIZE big and aligned on a 64-byte boundrary. */
234af146205f61c4aa0be736abb06601a89facb8vboxsync /** Network creation flags (INTNET_OPEN_FLAGS_*). */
234af146205f61c4aa0be736abb06601a89facb8vboxsync /** The number of active interfaces (excluding the trunk). */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The length of the network name. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The network name. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The trunk type. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync /** The trunk name. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync/** Pointer to an internal network. */
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync/** The size of the buffer INTNETNETWORK::pbTmp points at. */
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * Internal networking instance.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsynctypedef struct INTNET
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Mutex protecting the network creation, opening and destruction.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * (This means all operations affecting the pNetworks list.) */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** List of networks. Protected by INTNET::Spinlock. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /** Handle table for the interfaces. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync/*******************************************************************************
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync* Internal Functions *
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync*******************************************************************************/
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsyncstatic PINTNETTRUNKIF intnetR0TrunkIfRetain(PINTNETTRUNKIF pThis);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncstatic void intnetR0TrunkIfRelease(PINTNETTRUNKIF pThis);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncstatic bool intnetR0TrunkIfOutLock(PINTNETTRUNKIF pThis);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncstatic void intnetR0TrunkIfOutUnlock(PINTNETTRUNKIF pThis);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Initializes a scatter / gather buffer from a simple linear buffer.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns Pointer to the start of the frame.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pSG Pointer to the scatter / gather structure.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pvFrame Pointer to the frame
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param cbFrame The size of the frame.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncDECLINLINE(void) intnetR0SgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Initializes a scatter / gather buffer from a internal networking packet.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @returns Pointer to the start of the frame.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pSG Pointer to the scatter / gather structure.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * (The pvOwnerData, fFlags, cUsers, and cSegsAlloc members are left untouched.)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pHdr Pointer to the packet header.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pBuf The buffer the header is within. Only used in strict builds.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncDECLINLINE(void) intnetR0SgInitFromPkt(PINTNETSG pSG, PCINTNETHDR pPktHdr, PCINTNETBUF pBuf)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pSG->cbTotal = pSG->aSegs[0].cb = pPktHdr->cbFrame;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync pSG->aSegs[0].pv = INTNETHdrGetFramePtr(pPktHdr, pBuf);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Worker for intnetR0SgWritePart that deals with the case where the
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * request doesn't fit into the first segment.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns true, unless the request or SG invalid.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pSG The SG list to write to.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param off Where to start writing (offset into the SG).
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param cb How much to write.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pvBuf The buffer to containing the bits to write.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncstatic bool intnetR0SgWritePartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
234af146205f61c4aa0be736abb06601a89facb8vboxsync return false;
234af146205f61c4aa0be736abb06601a89facb8vboxsync * Skip ahead to the segment where off starts.
234af146205f61c4aa0be736abb06601a89facb8vboxsync unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
234af146205f61c4aa0be736abb06601a89facb8vboxsync unsigned iSeg = 0;
234af146205f61c4aa0be736abb06601a89facb8vboxsync * Copy the data, hoping that it's all from one segment...
234af146205f61c4aa0be736abb06601a89facb8vboxsync memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cb);
234af146205f61c4aa0be736abb06601a89facb8vboxsync /* copy the portion in the current segment. */
234af146205f61c4aa0be736abb06601a89facb8vboxsync memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cbCanCopy);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync /* copy the portions in the other segments. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync } while (cb > 0);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return true;
234af146205f61c4aa0be736abb06601a89facb8vboxsync * Writes to a part of an SG.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns true on success, false on failure (out of bounds).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pSG The SG list to write to.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param off Where to start writing (offset into the SG).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param cb How much to write.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pvBuf The buffer to containing the bits to write.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncDECLINLINE(bool) intnetR0SgWritePart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync /* The optimized case. */
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync memcpy((uint8_t *)pSG->aSegs[0].pv + off, pvBuf, cb);
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync return true;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync return intnetR0SgWritePartSlow(pSG, off, cb, pvBuf);
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * Reads a byte from a SG list.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns The byte on success. 0xff on failure.
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync * @param pSG The SG list to read.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param off The offset (into the SG) off the byte.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncDECLINLINE(uint8_t) intnetR0SgReadByte(PCINTNETSG pSG, uint32_t off)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return ((uint8_t const *)pSG->aSegs[iSeg].pv)[off];
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return false;
041d531fb5794a8a4cf6c35886d89ec25cbbdde2vboxsync * Worker for intnetR0SgReadPart that deals with the case where the
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * requested data isn't in the first segment.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @returns true, unless the SG is invalid.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pSG The SG list to read.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param off Where to start reading (offset into the SG).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param cb How much to read.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param pvBuf The buffer to read into.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsyncstatic bool intnetR0SgReadPartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return false;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Skip ahead to the segment where off starts.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync unsigned iSeg = 0;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Copy the data, hoping that it's all from one segment...
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cb);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /* copy the portion in the current segment. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cbCanCopy);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /* copy the portions in the other segments. */
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv, cbCanCopy);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync } while (cb > 0);
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return true;
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Reads a part of an SG into a buffer.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @returns true on success, false on failure (out of bounds).
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param pSG The SG list to read.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param off Where to start reading (offset into the SG).
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param cb How much to read.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * @param pvBuf The buffer to read into.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncDECLINLINE(bool) intnetR0SgReadPart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync /* The optimized case. */
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync memcpy(pvBuf, (uint8_t const *)pSG->aSegs[0].pv + off, cb);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync return true;
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync return intnetR0SgReadPartSlow(pSG, off, cb, pvBuf);
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Reads an entire SG into a fittingly size buffer.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pSG The SG list to read.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pvBuf The buffer to read into (at least pSG->cbTotal in size).
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsyncDECLINLINE(void) intnetR0SgRead(PCINTNETSG pSG, void *pvBuf)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
c5d2523548cc57504b829f53f1362b848a84542cvboxsync Assert(cbSeg <= pSG->cbTotal && (uintptr_t)(pbDst - (uint8_t *)pvBuf) + cbSeg <= pSG->cbTotal);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Retain an interface.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @returns VBox status code, can assume success in most situations.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pIf The interface instance.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pSession The current session.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncDECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession)
e4527e0a08e2d635a679ae2947d42195f30a2ce2vboxsync int rc = SUPR0ObjAddRefEx(pIf->pvObj, pSession, true /* fNoBlocking */);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Release an interface previously retained by intnetR0IfRetain or
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns true if destroyed, false if not.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param pIf The interface instance.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pSession The current session.
db3d025f28c59aececbbda4174fa513496c89b2bvboxsyncDECLINLINE(bool) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * RTHandleCreateEx callback that retains an object in the
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * handle table before returning it.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * (Avoids racing the freeing of the handle.)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @returns VBox status code.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param hHandleTable The handle table (ignored).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pvObj The object (INTNETIF).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pvCtx The context (SUPDRVSESSION).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pvUser The user context (ignored).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncstatic DECLCALLBACK(int) intnetR0IfRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (pIf->hIf != INTNET_HANDLE_INVALID) /* Don't try retain it if called from intnetR0IfDestruct. */
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Checks if the IPv4 address is a broadcast address.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * @param Addr The address, network endian.
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncDECLINLINE(bool) intnetR0IPv4AddrIsBroadcast(RTNETADDRIPV4 Addr)
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync /* Just check for 255.255.255.255 atm. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Checks if the IPv4 address is a good interface address.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param Addr The address, network endian.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncDECLINLINE(bool) intnetR0IPv4AddrIsGood(RTNETADDRIPV4 Addr)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Usual suspects. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if ( Addr.u == UINT32_MAX /* 255.255.255.255 - broadcast. */
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync || Addr.au8[0] == 0) /* Current network, can be used as source address. */
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync return false;
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync /* Unusual suspects. */
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync return false;
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync return true;
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync * Gets the address size of a network layer type.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @returns size in bytes.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param enmType The type.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncDECLINLINE(uint8_t) intnetR0AddrSize(INTNETADDRTYPE enmType)
0ff2f0d33dea0e82857c2131d43f637c206a8163vboxsync * Compares two address to see if they are equal, assuming naturally align structures.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns true if equal, false if not.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pAddr1 The first address.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param pAddr2 The second address.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param cbAddr The address size.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncDECLINLINE(bool) intnetR0AddrUIsEqualEx(PCRTNETADDRU pAddr1, PCRTNETADDRU pAddr2, uint8_t const cbAddr)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Worker for intnetR0IfAddrCacheLookup that performs the lookup
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * in the remaining cache entries after the caller has check the
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * most likely ones.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @returns -1 if not found, the index of the cache entry if found.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pCache The cache.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param pAddr The address.
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * @param cbAddr The address size (optimization).
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsyncstatic int intnetR0IfAddrCacheLookupSlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync while (i >= 1)
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr))
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * Lookup an address in a cache without any expectations.
fbb3513a43135c633f7f51544c4bdfce748929bfvboxsync * @returns -1 if not found, the index of the cache entry if found.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pCache The cache.
fbb3513a43135c633f7f51544c4bdfce748929bfvboxsync * @param pAddr The address.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param cbAddr The address size (optimization).
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsyncDECLINLINE(int) intnetR0IfAddrCacheLookup(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync * The optimized case is when there is one cache entry and
ee6e48c229ef52aee5e968d956ebd066073811abvboxsync * it doesn't match.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr))
c889bbab784ba8552102ce776b6c67b982017861vboxsync if (i <= 1)
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync * Check the last entry.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))
ad1e35f9fb71d147c2126449a25adf0f8e155aaavboxsync if (i <= 1)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync return intnetR0IfAddrCacheLookupSlow(pCache, pAddr, cbAddr);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync/** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */
c889bbab784ba8552102ce776b6c67b982017861vboxsyncDECLINLINE(int) intnetR0IfAddrCacheLookupLikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync /** @todo implement this. */
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync return intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Worker for intnetR0IfAddrCacheLookupUnlikely that performs
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * the lookup in the remaining cache entries after the caller
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * has check the most likely ones.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * The routine is expecting not to find the address.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @returns -1 if not found, the index of the cache entry if found.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pCache The cache.
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync * @param pAddr The address.
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync * @param cbAddr The address size (optimization).
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsyncstatic int intnetR0IfAddrCacheInCacheUnlikelySlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync * Perform a full table lookup.
4d32c71a938b979c6aeee321ae325d5793a5ccdbvboxsync uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync while (i >= 1)
81fcf0038d2d6c76ab2c8b02103dc18c24efe0a1vboxsync if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Lookup an address in a cache expecting not to find it.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @returns -1 if not found, the index of the cache entry if found.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pCache The cache.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param pAddr The address.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * @param cbAddr The address size (optimization).
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsyncDECLINLINE(int) intnetR0IfAddrCacheLookupUnlikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * The optimized case is when there is one cache entry and
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * it doesn't match.
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync * Then check the last entry and return if there are just two cache entries.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr)))
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync if (i <= 1)
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync return intnetR0IfAddrCacheInCacheUnlikelySlow(pCache, pAddr, cbAddr);
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * Deletes a specific cache entry.
c889bbab784ba8552102ce776b6c67b982017861vboxsync * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param pIf The interface (for logging).
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param pCache The cache.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param iEntry The entry to delete.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsync * @param pszMsg Log message.
ab02aeaf2a0312fe9267a292e3911728e4531332vboxsyncstatic void intnetR0IfAddrCacheDeleteIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, int iEntry, const char *pszMsg)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync INTNETADDRTYPE enmAddrType = (INTNETADDRTYPE)(uintptr_t)(pCache - &pIf->aAddrCache[0]);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync PCRTNETADDRU pAddr = (PCRTNETADDRU)(pCache->pbEntries + iEntry * pCache->cbEntry);
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pIf->hIf, &pIf->Mac, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pIf->hIf, &pIf->Mac, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync memmove(pCache->pbEntries + iEntry * pCache->cbEntry,
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync pCache->pbEntries + (iEntry + 1) * pCache->cbEntry,
7f4b4ec1cadbf891d2756ce77dc4a4ec220a03bcvboxsync * Deletes an address from the cache, assuming it isn't actually in the cache.
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync * @param pIf The interface (for logging).
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync * @param pCache The cache.
31cda52093d58f5c604589fa74949c5fddcbde70vboxsync * @param pAddr The address.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * @param cbAddr The address size (optimization).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsyncDECLINLINE(void) intnetR0IfAddrCacheDelete(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync int i = intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync intnetR0IfAddrCacheDeleteIt(pIf, pCache, i, pszMsg);
d60d5da33bb93fc7a8717802f21b13aa37914799vboxsync * Deletes the address from all the interface caches.
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * This is used to remove stale entries that has been reassigned to
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * other machines on the network.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param pNetwork The network.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param pAddr The address.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param enmType The address type.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param cbAddr The address size (optimization).
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsync * @param pszMsg Log message.
6f058039e7b13efc3278b9bc84cf0fd135614b67vboxsyncDECLINLINE(void) intnetR0NetworkAddrCacheDelete(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType,
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync * Deletes the address from all the interface caches except the specified one.
82c6fd518728c98e8bae58f3c5e55c5efa160878vboxsync * This is used to remove stale entries that has been reassigned to
e5bfc5c34142a7550be3564a8e01a037b1db5b31vboxsync * other machines on the network.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pNetwork The network.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pAddr The address.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param enmType The address type.
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param cbAddr The address size (optimization).
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync * @param pszMsg Log message.
c5d2523548cc57504b829f53f1362b848a84542cvboxsyncDECLINLINE(void) intnetR0NetworkAddrCacheDeleteMinusIf(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCRTNETADDRU pAddr,
00cc5d93f7446d9394a0f6b7ad790b9fb9d6005cvboxsync INTNETADDRTYPE const enmType, uint8_t const cbAddr, const char *pszMsg)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync for (PINTNETIF pIf = pNetwork->pIFs; pIf; pIf = pIf->pNext)
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
833f83ce101b6e9168f519decc0dc7a1079d35f7vboxsync intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
DECLINLINE(PINTNETIF) intnetR0NetworkAddrCacheLookupIf(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType, uint8_t const cbAddr)
return pIf;
return NULL;
static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, const char *pszMsg)
bool fReplace = true;
if (pvNew)
fReplace = false;
if (fReplace)
memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
#ifdef LOG_ENABLED
switch (enmAddrType)
case kIntNetAddrType_IPv4:
pIf->hIf, &pIf->Mac, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
static void intnetR0IfAddrCacheAddSlow(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
if (RT_LIKELY( i > 0
&& intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))) ))
#ifdef INTNET_WITH_DHCP_SNOOPING
static void intnetR0NetworkSnoopDhcp(PINTNETNETWORK pNetwork, PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, uint32_t cbUdpPkt)
#ifdef LOG_ENABLED
switch (MsgType)
Log6(("DHCP msg: %d (%s) client %.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d\n", MsgType, pszType, &pDhcp->bp_chaddr,
pDhcp->bp_yiaddr.au8[0], pDhcp->bp_yiaddr.au8[1], pDhcp->bp_yiaddr.au8[2], pDhcp->bp_yiaddr.au8[3]));
switch (MsgType)
case RTNET_DHCP_MT_REQUEST:
case RTNET_DHCP_MT_ACK:
case RTNET_DHCP_MT_RELEASE:
intnetR0NetworkSnoopDhcp(pNetwork, pIpHdr, (PCRTNETUDP)((uintptr_t)pIpHdr + cbIpHdr), cbPacket - cbIpHdr);
#ifdef INTNET_WITH_DHCP_SNOOPING
switch (EtherType)
case RTNET_ETHERTYPE_IPV4:
uint8_t b;
Assert(pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN);
PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t const *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR) + cbIpHdr);
if ( b != RTNETIPV4_PORT_BOOTPS
&& b != RTNETIPV4_PORT_BOOTPC)
if ( b != RTNETIPV4_PORT_BOOTPS
&& b != RTNETIPV4_PORT_BOOTPC)
if (b == SrcPort)
case RTNET_ETHERTYPE_IPV6:
case RTNET_ETHERTYPE_ARP:
bool fValidatedIpHdr = false;
&& intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(Addr.IPv4)) < 0)
fValidatedIpHdr = true;
#ifdef INTNET_WITH_DHCP_SNOOPING
if ( fValidatedIpHdr
static void intnetR0IfSnoopArpAddr(PINTNETIF pIf, PCRTNETARPIPV4 pArpIPv4, uint32_t cbPacket, uint16_t *pfSgFlags)
static void intnetR0IfSnoopAddr(PINTNETIF pIf, uint8_t const *pbFrame, uint32_t cbFrame, uint16_t *pfSgFlags)
switch (EtherType)
case RTNET_ETHERTYPE_IPV4:
case RTNET_ETHERTYPE_IPV6:
intnetR0IfSnoopIPv6SourceAddr(pIf, (PCINTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, pfSgFlags);
case RTNET_ETHERTYPE_IPX_1:
case RTNET_ETHERTYPE_IPX_2:
case RTNET_ETHERTYPE_IPX_3:
case RTNET_ETHERTYPE_ARP:
#ifdef IN_INTNET_TESTCASE
return cb;
static int intnetR0RingWriteFrame(PINTNETBUF pBuf, PINTNETRINGBUF pRingBuf, PCINTNETSG pSG, PCRTMAC pNewDstMac)
if (pNewDstMac)
return VINF_SUCCESS;
AssertMsg(pRingBuf->offEnd - offWrite >= sizeof(INTNETHDR), ("offEnd=%x offWrite=%x\n", pRingBuf->offEnd, offWrite));
if (pNewDstMac)
return VINF_SUCCESS;
if (pNewDstMac)
return VINF_SUCCESS;
return VERR_BUFFER_OVERFLOW;
while (--cYields > 0)
int rc;
if ( fTrunkLocked
if ( fTrunkLocked
if (!fTrunkLocked)
AssertFailed();
if (!fTrunkLocked)
AssertFailed();
static void intnetR0NetworkEditArpFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
if (pIf)
static void intnetR0NetworkEditDhcpFromIntNet(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN))
switch (MsgType)
case RTNET_DHCP_MT_DISCOVER:
case RTNET_DHCP_MT_REQUEST:
Log6(("intnetR0NetworkEditDhcpFromIntNet: Setting broadcast flag in DHCP %#x, previously %x\n", MsgType, pDhcp->bp_flags));
intnetR0SgWritePart(pSG, (uint8_t*)&pDhcp->bp_flags - (uint8_t*)pIpHdr + sizeof(RTNETETHERHDR), sizeof(uFlags), &uFlags);
intnetR0SgWritePart(pSG, (uint8_t*)&pUdpHdr->uh_sum - (uint8_t*)pIpHdr + sizeof(RTNETETHERHDR), sizeof(pUdpHdr->uh_sum), &uChecksum);
static bool intnetR0NetworkSendBroadcast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc,
&& !fSrc
if ( pIfSender
&& pTrunkIf)
intnetR0TrunkIfSend(pTrunkIf, pNetwork, pIfSender, INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked);
&& !pIfSender)
#ifdef INTNET_WITH_DHCP_SNOOPING
&& pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN)
static bool intnetR0NetworkSendMulticast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr)
static bool intnetR0NetworkSendUnicastWithSharedMac(PINTNETNETWORK pNetwork, PINTNETSG pSG, bool fTrunkLocked, PRTNETETHERHDR pEthHdr)
case RTNET_ETHERTYPE_IPV4:
if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV4, ip_dst), sizeof(Addr.IPv4), &Addr)))
case RTNET_ETHERTYPE_IPV6
if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV6, ip6_dst), sizeof(Addr.IPv6), &Addr)))
case RTNET_ETHERTYPE_IPX_1:
case RTNET_ETHERTYPE_IPX_2:
case RTNET_ETHERTYPE_IPX_3:
if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPX, ipx_dstnet), sizeof(Addr.IPX), &Addr)))
case RTNET_ETHERTYPE_ARP:
return intnetR0NetworkSendBroadcast(pNetwork, NULL, INTNETTRUNKDIR_WIRE, pSG, fTrunkLocked, pEthHdr);
if (!(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC)))
bool fExactIntNetRecipient = false;
if ( fIt
&& !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))))
#ifdef INTNET_WITH_DHCP_SNOOPING
&& pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN)
return fExactIntNetRecipient;
static bool intnetR0NetworkSendUnicast(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked, PCRTNETETHERHDR pEthHdr)
bool fExactIntNetRecipient = false;
bool fIt = false;
&& !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC))
if ( pIfSender
&& pTrunkIf
&& !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_WIRE | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_WIRE)) )
if ( !(pNetwork->fFlags & (INTNET_OPEN_FLAGS_IGNORE_PROMISC | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC | INTNET_OPEN_FLAGS_IGNORE_PROMISC_TRUNK_HOST | INTNET_OPEN_FLAGS_QUIETLY_IGNORE_PROMISC_TRUNK_HOST))
if (fDst)
if ( !fExactIntNetRecipient
&& !fDst
&& ( (pEthHdr->DstMac.au8[0] == 0x08 && pEthHdr->DstMac.au8[1] == 0x00 && pEthHdr->DstMac.au8[2] == 0x27)
|| (pEthHdr->SrcMac.au8[0] == 0x08 && pEthHdr->SrcMac.au8[1] == 0x00 && pEthHdr->SrcMac.au8[2] == 0x27)))
return fExactIntNetRecipient;
static bool intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc, PINTNETSG pSG, bool fTrunkLocked)
bool fRc = false;
return fRc;
if (pIfSender)
if ( pIfSender
return fRc;
INTNETR0DECL(int) INTNETR0IfSend(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, const void *pvFrame, unsigned cbFrame)
Log5(("INTNETR0IfSend: pIntNet=%p hIf=%RX32 pvFrame=%p cbFrame=%u\n", pIntNet, hIf, pvFrame, cbFrame));
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
if (pTrunkIf)
return VERR_SEM_DESTROYED;
return rc;
if (pvCurFrame)
if (pTrunkIf)
return rc;
INTNETR0DECL(int) INTNETR0IfSendReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq)
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) INTNETR0IfGetRing3Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, R3PTRTYPE(PINTNETBUF) *ppRing3Buf)
LogFlow(("INTNETR0IfGetRing3Buffer: pIntNet=%p hIf=%RX32 ppRing3Buf=%p\n", pIntNet, hIf, ppRing3Buf));
*ppRing3Buf = 0;
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
INTNETR0DECL(int) INTNETR0IfGetRing3BufferReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFGETRING3BUFFERREQ pReq)
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) INTNETR0IfGetRing0Buffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PINTNETBUF *ppRing0Buf)
LogFlow(("INTNETR0IfGetRing0Buffer: pIntNet=%p hIf=%RX32 ppRing0Buf=%p\n", pIntNet, hIf, ppRing0Buf));
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
INTNETR0DECL(int) INTNETR0IfGetPhysBuffer(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
if (!pIf)
return VERR_INVALID_HANDLE;
/** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there
return VERR_NOT_IMPLEMENTED;
INTNETR0DECL(int) INTNETR0IfSetPromiscuousMode(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous)
LogFlow(("INTNETR0IfSetPromiscuousMode: pIntNet=%p hIf=%RX32 fPromiscuous=%d\n", pIntNet, hIf, fPromiscuous));
if (!pIf)
return VERR_INVALID_HANDLE;
int rc;
if (pNetwork)
return rc;
INTNETR0DECL(int) INTNETR0IfSetPromiscuousModeReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) INTNETR0IfSetMacAddress(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac)
LogFlow(("INTNETR0IfSetMacAddress: pIntNet=%p hIf=%RX32 pMac=%p:{%.6Rhxs}\n", pIntNet, hIf, pMac, pMac));
if (!pIf)
return VERR_INVALID_HANDLE;
int rc;
if (pNetwork)
return rc;
INTNETR0DECL(int) INTNETR0IfSetMacAddressReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq)
return VERR_INVALID_PARAMETER;
return VERR_SEM_DESTROYED;
bool fNetworkLocked = true;
if ( pTrunkIf
|| !cActiveIFs))
fNetworkLocked = false;
if (fNetworkLocked)
if (pTrunkIf)
return rc;
if (!pNetwork)
return VERR_WRONG_ORDER;
INTNETR0DECL(int) INTNETR0IfSetActive(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive)
if (!pIf)
return VERR_INVALID_HANDLE;
int rc;
if (pNetwork)
return rc;
INTNETR0DECL(int) INTNETR0IfSetActiveReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq)
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) INTNETR0IfWait(PINTNET pIntNet, INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies)
if (!pIf)
return VERR_INVALID_HANDLE;
return VERR_SEM_DESTROYED;
return rc;
INTNETR0DECL(int) INTNETR0IfWaitReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq)
return VERR_INVALID_PARAMETER;
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
INTNETR0DECL(int) INTNETR0IfCloseReq(PINTNET pIntNet, PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq)
return VERR_INVALID_PARAMETER;
if (pNetwork)
while (pPrev)
static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv, bool *pfCloseNetwork, PINTNETIFHANDLE phIf)
*pfCloseNetwork = false;
if (!pIf)
return VERR_NO_MEMORY;
pIf->aAddrCache[kIntNetAddrType_IPX].cbEntry = RT_ALIGN_32(intnetR0AddrSize(kIntNetAddrType_IPv4), 16);
rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
ASMMemZero32(pIf->pIntBufDefault, cbBuf); /** @todo I thought I specified these buggers as clearing the memory... */
pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, intnetR0IfDestruct, pIf, pNetwork->pIntNet);
return VINF_SUCCESS;
return rc;
*pfCloseNetwork = true;
return rc;
#ifdef RT_WITH_W64_UNWIND_HACK
INTNET_DECL_CALLBACK(bool) INTNET_CALLBACK(intnetR0TrunkIfPortSetSGPhys)(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable);
INTNET_DECL_CALLBACK(bool) INTNET_CALLBACK(intnetR0TrunkIfPortRecv)(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc);
INTNET_DECL_CALLBACK(void) INTNET_CALLBACK(intnetR0TrunkIfPortSGRetain)(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG);
INTNET_DECL_CALLBACK(void) INTNET_CALLBACK(intnetR0TrunkIfPortSGRelease)(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG);
INTNET_DECL_CALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
INTNET_DECL_CALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG, uint32_t fSrc)
bool fRc;
return fRc;
INTNET_DECL_CALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
INTNET_DECL_CALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
return pThis;
return NULL;
if (pThis)
if (!pThis)
if (pIfPort)
const char *pszName;
case kIntNetTrunkType_None:
return VINF_SUCCESS;
return VERR_NOT_IMPLEMENTED;
case kIntNetTrunkType_NetFlt:
case kIntNetTrunkType_NetAdp:
case kIntNetTrunkType_SrvNat:
if (!pTrunkIF)
return VERR_NO_MEMORY;
rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory, pNetwork->szTrunk, &pTrunkIF->SwitchPort, &pTrunkIF->pIfPort, !!(pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE));
pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName));
return VINF_SUCCESS;
return rc;
return rc;
Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
while (pCur)
if (pTrunkIF)
static int intnetR0OpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
LogFlow(("intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
while (pCur)
int rc;
return rc;
return VERR_NOT_FOUND;
static int intnetR0CreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
LogFlow(("intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
if (!pNew)
return VERR_NO_MEMORY;
pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNew, pIntNet);
return VINF_SUCCESS;
return rc;
return rc;
LogFlow(("INTNETR0Open: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
pIntNet, pSession, pszNetwork, pszNetwork, pszTrunk, pszTrunk, enmTrunkType, fFlags, cbSend, cbRecv, phIf));
if (pszTrunk)
switch (enmTrunkType)
case kIntNetTrunkType_None:
case kIntNetTrunkType_NetFlt:
return VERR_NOT_IMPLEMENTED;
return rc;
bool fCloseNetwork = true;
rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
return rc;
return VERR_INVALID_PARAMETER;
if (!pIntNet)
if (pIntNet)
rc = RTHandleTableCreateEx(&pIntNet->hHtIfs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
return VINF_SUCCESS;
return rc;