SrvIntNetR0.cpp revision 2622c26c6b4105d944a29c5e2c77b6ef26e10101
* Structures and Typedefs * *******************************************************************************/ * MAC address lookup table entry. /** The MAC address of this entry. */ /** Is it is effectively promiscuous mode. */ /** Is it promiscuous and should it see unrelated trunk traffic. */ * We ignore the entry if this is clear and may end up sending packets addressed * to this interface onto the trunk. The reasoning for this is that this could * be the interface of a VM that just has been teleported to a different host. */ /** Pointer to the network interface. */ /** Pointer to a MAC address lookup table entry. */ * MAC address lookup table. * @todo Having this in a separate structure didn't work out as well as it * should. Consider merging it into INTNETNETWORK. /** The current number of entries. */ /** The number of entries we've allocated space for. */ /** The number of interface entries currently in promicuous mode. */ /** The number of interface entries currently in promicuous mode that * shall not see unrelated trunk traffic. */ /** The host MAC address (reported). */ /** The effective host promiscuous setting (reported). */ /** The real host promiscuous setting (reported). */ /** Whether the host is active. */ /** Whether the wire is promiscuous (config). */ /** Whether the wire is promiscuous (config). * (Shadows INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE in * INTNETNETWORK::fFlags.) */ /** Whether the wire is active. */ /** Pointer to the trunk interface. */ /** Pointer to a MAC address . */ /** The trunk destinations. */ /** Pointer to the trunk interface (referenced) if fTrunkDst is non-zero. */ /** The number of destination interfaces. */ /** The interfaces (referenced). Variable sized array. */ /** The destination interface. */ /** Whether to replace the destination MAC address. * This is used when sharing MAC address with the host on the wire(less). */ /** Pointer to a destination table. */ /** Pointer to a const destination table. */ /** Network layer address type. */ /** The invalid 0 entry. */ /** The end of the valid values. */ /** The usual 32-bit hack. */ /** Pointer to a network layer address type. */ /** Pointer to an address. */ /** Pointer to a const address. */ * Address cache for a specific network layer. /** Pointer to the table of addresses. */ /** The number of valid address entries. */ /** The number of allocated address entries. */ /** The size of an entry. */ /** Pointer to an address cache. */ /** Pointer to a const address cache. */ * Unless explicitly stated, all members are protect by the network semaphore. * This is shadowed by INTNETMACTABENTRY::MacAddr. */ /** Set if the INTNET::MacAddr member has been explicitly set. */ /** Tracks the desired promiscuous setting of the interface. */ /** Whether the interface is active or not. * This is shadowed by INTNETMACTABENTRY::fActive. */ /** Whether someone is currently in the destructor or has indicated that * the end is nigh by means of IntNetR0IfAbortWait. */ /** The flags specified when opening this interface. */ /** Number of yields done to try make the interface read pending data. * We will stop yielding when this reaches a threshold assuming that the VM is * paused or that it simply isn't worth all the delay. It is cleared when a * successful send has been done. */ /** Pointer to the current exchange buffer (ring-0). */ /** Pointer to ring-3 mapping of the current exchange buffer. */ /** Pointer to the default exchange buffer for the interface. */ /** Pointer to ring-3 mapping of the default exchange buffer. */ * waiting for data to arrive. */ /** Number of threads sleeping on the event semaphore. */ /** The interface handle. * When this is INTNET_HANDLE_INVALID a sleeper which is waking up * should return with the appropriate error condition. */ /** Pointer to the network this interface is connected to. * This is protected by the INTNET::hMtxCreateOpenDestroy. */ /** The session this interface is associated with. */ /** The SUPR0 object id. */ /** The network layer address cache. (Indexed by type, 0 entry isn't used.) * This is protected by the address spinlock of the network. */ /** Spinlock protecting the input (producer) side of the receive ring. */ /** Busy count for tracking destination table references and active sends. * Usually incremented while owning the switch table spinlock. The 30th bit * is used to indicate wakeup. */ /** The preallocated destination table. * This is NULL when it's in use as a precaution against unserialized * transmitting. This is grown when new interfaces are added to the network. */ /** Pointer to the trunk's per interface data. Can be NULL. */ /** Header buffer for when we're carving GSO frames. */ /** Pointer to an internal network interface. */ /** The port interface we present to the component. */ /** The port interface we get from the component. */ /** Pointer to the network we're connect to. * This may be NULL if we're orphaned? */ /** The current MAC address for the interface. (reported) * Updated while owning the switch table spinlock. */ /** Whether to supply physical addresses with the outbound SGs. (reported) */ /** Explicit alignment. */ /** Busy count for tracking destination table references and active sends. * Usually incremented while owning the switch table spinlock. The 30th bit * is used to indicate wakeup. */ /** Mask of destinations that pfnXmit cope with disabled preemption for. */ /** The GSO capabilities of the wire destination. (reported) */ /** The GSO capabilities of the host destination. (reported) * This is as bit map where each bit represents the GSO type with the same /** The destination table spinlock, interrupt safe. * Protects apTaskDstTabs and apIntDstTabs. */ /** The number of entries in apIntDstTabs. */ /** The task time destination tables. * @remarks intnetR0NetworkEnsureTabSpace and others ASSUMES this immediately * precedes apIntDstTabs so that these two tables can be used as one /** The interrupt / disabled-preemption time destination tables. * This is a variable sized array. */ /** Pointer to a trunk interface. */ /** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */ * Internal representation of a network. /** The Next network in the chain. * This is protected by the INTNET::hMtxCreateOpenDestroy. */ /** The spinlock protecting MacTab and INTNETTRUNKIF::aAddrCache. * This doubles as interface collection. */ /** Wait for an interface to stop being busy so it can be removed or have its * destination table replaced. We have to wait upon this while owning the * network mutex. Will only ever have one waiter because of the big mutex. */ /** Pointer to the instance data. */ /** The SUPR0 object id. */ /** Pointer to the temporary buffer that is used when snooping fragmented packets. * This is allocated after this structure if we're sharing the MAC address with * the host. The buffer is INTNETNETWORK_TMP_SIZE big and aligned on a 64-byte boundary. */ /** Network creation flags (INTNET_OPEN_FLAGS_*). */ /** Any restrictive policies required as a minimum by some interface. * (INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES) */ /** The number of active interfaces (excluding the trunk). */ /** The length of the network name. */ /** Pointer to an internal network. */ /** Pointer to a const internal network. */ /** The size of the buffer INTNETNETWORK::pbTmp points at. */ * Internal networking instance. /** Magic number (INTNET_MAGIC). */ /** Mutex protecting the creation, opening and destruction of both networks and * interfaces. (This means all operations affecting the pNetworks list.) */ /** List of networks. Protected by INTNET::Spinlock. */ /** Handle table for the interfaces. */ /** Pointer to an internal network ring-0 instance. */ /** Magic number for the internal network instance data (Hayao Miyazaki). */ /******************************************************************************* *******************************************************************************/ /** Pointer to the internal network instance data. */ uint32_t fPair;
/**< The pair of restrictive and relaxed flags. */ /** Open network policy flags relating to the network. */ /** Open network policy flags relating to the new interface. */ * Worker for intnetR0SgWritePart that deals with the case where the * request doesn't fit into the first segment. * @returns true, unless the request or SG invalid. * @param pSG The SG list to write to. * @param off Where to start writing (offset into the SG). * @param cb How much to write. * @param pvBuf The buffer to containing the bits to write. * Skip ahead to the segment where off starts. * Copy the data, hoping that it's all from one segment... /* copy the portion in the current segment. */ /* copy the portions in the other segments. */ * Writes to a part of an SG. * @returns true on success, false on failure (out of bounds). * @param pSG The SG list to write to. * @param off Where to start writing (offset into the SG). * @param cb How much to write. * @param pvBuf The buffer to containing the bits to write. /* The optimized case. */ * Reads a byte from a SG list. * @returns The byte on success. 0xff on failure. * @param pSG The SG list to read. * @param off The offset (into the SG) off the byte. * Worker for intnetR0SgReadPart that deals with the case where the * requested data isn't in the first segment. * @returns true, unless the SG is invalid. * @param pSG The SG list to read. * @param off Where to start reading (offset into the SG). * @param cb How much to read. * @param pvBuf The buffer to read into. * Skip ahead to the segment where off starts. * Copy the data, hoping that it's all from one segment... /* copy the portion in the current segment. */ /* copy the portions in the other segments. */ * Reads a part of an SG into a buffer. * @returns true on success, false on failure (out of bounds). * @param pSG The SG list to read. * @param off Where to start reading (offset into the SG). * @param cb How much to read. * @param pvBuf The buffer to read into. /* The optimized case. */ * Wait for a busy counter to reach zero. * @param pNetwork The network. * @param pcBusy The busy counter. * We have to be a bit cautious here so we don't destroy the network or the * semaphore before intnetR0BusyDec has signalled us. /* Reset the semaphore and flip the wakeup bit. */ /* Wait for the count to reach zero. */ //AssertMsg(RT_SUCCESS(rc2), ("rc=%Rrc *pcBusy=%#x (%#x)\n", rc2, ASMAtomicReadU32(pcBusy), cCurBusy )); * Decrements the busy counter and maybe wakes up any threads waiting for it to * @param pNetwork The network. * @param pcBusy The busy counter. * Increments the busy count of the specified interface. * The caller must own the MAC address table spinlock. * @param pIf The interface. * Increments the busy count of the specified interface. * The caller must own the MAC address table spinlock or an explicity reference. * @param pTrunk The trunk. * Increments the busy count of the specified interface. * The caller must own the MAC address table spinlock or an explicity reference. * @param pIf The interface. * Increments the busy count of the specified interface. * The caller must own the MAC address table spinlock or an explicity reference. * @param pTrunk The trunk. * @returns VBox status code, can assume success in most situations. * @param pIf The interface instance. * @param pSession The current session. * Release an interface previously retained by intnetR0IfRetain or * @returns true if destroyed, false if not. * @param pIf The interface instance. * @param pSession The current session. * RTHandleCreateEx callback that retains an object in the * handle table before returning it. * (Avoids racing the freeing of the handle.) * @returns VBox status code. * @param hHandleTable The handle table (ignored). * @param pvObj The object (INTNETIF). * @param pvCtx The context (SUPDRVSESSION). * @param pvUser The user context (ignored). * Checks if the interface has a usable MAC address or not. * @returns true if MacAddr is usable, false if not. * @param pIf The interface. * Locates the MAC address table entry for the given interface. * The caller holds the MAC address table spinlock, obviously. * @returns Pointer to the entry on if found, NULL if not. * @param pNetwork The network. * @param pIf The interface. * Checks if the IPv4 address is a broadcast address. * @param Addr The address, network endian. /* Just check for 255.255.255.255 atm. */ * Checks if the IPv4 address is a good interface address. * @param Addr The address, network endian. ||
Addr.
au8[0] == 0)
/* Current network, can be used as source address. */ || (
Addr.
au8[0] &
0xf0) ==
224 /* Multicast */ * Gets the address size of a network layer type. * @returns size in bytes. * @param enmType The type. * Compares two address to see if they are equal, assuming naturally align structures. * @returns true if equal, false if not. * @param pAddr1 The first address. * @param pAddr2 The second address. * @param cbAddr The address size. * Worker for intnetR0IfAddrCacheLookup that performs the lookup * in the remaining cache entries after the caller has check the * @returns -1 if not found, the index of the cache entry if found. * @param pCache The cache. * @param pAddr The address. * @param cbAddr The address size (optimization). * Lookup an address in a cache without any expectations. * @returns -1 if not found, the index of the cache entry if found. * @param pCache The cache. * @param pAddr The address. * @param cbAddr The address size (optimization). * The optimized case is when there is one cache entry and /** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */ /** @todo implement this. */ * Worker for intnetR0IfAddrCacheLookupUnlikely that performs * the lookup in the remaining cache entries after the caller * has check the most likely ones. * The routine is expecting not to find the address. * @returns -1 if not found, the index of the cache entry if found. * @param pCache The cache. * @param pAddr The address. * @param cbAddr The address size (optimization). * Perform a full table lookup. * Lookup an address in a cache expecting not to find it. * @returns -1 if not found, the index of the cache entry if found. * @param pCache The cache. * @param pAddr The address. * @param cbAddr The address size (optimization). * The optimized case is when there is one cache entry and * Then check the last entry and return if there are just two cache entries. * Deletes a specific cache entry. * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf. * @param pIf The interface (for logging). * @param pCache The cache. * @param iEntry The entry to delete. * @param pszMsg Log message. Log((
"intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
Log((
"intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",
* Deletes an address from the cache, assuming it isn't actually in the cache. * May or may not own the spinlock when calling this. * @param pIf The interface (for logging). * @param pCache The cache. * @param pAddr The address. * @param cbAddr The address size (optimization). * Deletes the address from all the interface caches. * This is used to remove stale entries that has been reassigned to * other machines on the network. * @param pNetwork The network. * @param pAddr The address. * @param enmType The address type. * @param cbAddr The address size (optimization). * @param pszMsg Log message. * Deletes the address from all the interface caches except the specified one. * This is used to remove stale entries that has been reassigned to * other machines on the network. * @param pNetwork The network. * @param pAddr The address. * @param enmType The address type. * @param cbAddr The address size (optimization). * @param pszMsg Log message. * Lookup an address on the network, returning the (first) interface having it * @returns Pointer to the interface on success, NULL if not found. The caller * must release the interface by calling intnetR0BusyDecIf. * @param pNetwork The network. * @param pAddr The address to lookup. * @param enmType The address type. * @param cbAddr The size of the address. * Adds an address to the cache, the caller is responsible for making sure it's * not already in the cache. * @param pIf The interface (for logging). * @param pCache The address cache. * @param pAddr The address. * @param pszMsg log message. /* This shouldn't happen*/ /* When the table is full, drop the older entry (FIFO). Do proper ageing? */ Log((
"intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
* Add the new entry to the end of the array. Log((
"intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
Log((
"intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n",
* A intnetR0IfAddrCacheAdd worker that performs the rest of the lookup. * @param pIf The interface (for logging). * @param pCache The address cache. * @param pAddr The address. * @param cbAddr The size of the address (optimization). * @param pszMsg Log message. * Check all but the first and last entries, the caller * has already checked those. * Adds an address to the cache if it's not already there. * Must not own any spinlocks when calling this function. * @param pIf The interface (for logging). * @param pCache The address cache. * @param pAddr The address. * @param cbAddr The size of the address (optimization). * @param pszMsg Log message. * The optimized case is when the address the first or last cache entry. * Destroys the specified address cache. * @param pCache The address cache. * Initialize the address cache for the specified address type. * The cache storage is preallocated and fixed size so that we can handle * inserts from problematic contexts. * @returns VINF_SUCCESS or VERR_NO_MEMORY. * @param pCache The cache to initialize. * @param enmAddrType The address type. * @param fEnabled Whether the address cache is enabled or not. * Is it a multicast or broadcast MAC address? * @returns true if multicast, false if not. * @param pMacAddr The address to inspect. * Is it a dummy MAC address? * We use dummy MAC addresses for interfaces which we don't know the MAC * address of because they haven't sent anything (learning) or explicitly set * @returns true if dummy, false if not. * @param pMacAddr The address to inspect. /* The dummy address are broadcast addresses, don't bother check it all. */ * Compares two MAC addresses. * @returns true if equal, false if not. * @param pDstAddr1 Address 1. * @param pDstAddr2 Address 2. * Switch a unicast frame based on the network layer address (OSI level 3) and * return a destination table. * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). * @param pNetwork The network to switch on. * @param pDstMacAddr The destination MAC address. * @param enmL3AddrType The level-3 destination address type. * @param pL3Addr The level-3 destination address. * @param cbL3Addr The size of the level-3 destination address. * @param fSrc The frame source (INTNETTRUNKDIR_WIRE). * @param pDstTab The destination output table. * Grab the spinlock first and do the switching. /* Find exactly matching or promiscuous interfaces. */ /* Network only promicuous mode ifs should see related trunk traffic. */ /* Does it match the host, or is the host promiscuous? */ /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */ * Pre-switch a unicast MAC address. * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). * @param pNetwork The network to switch on. * @param fSrc The frame source. * @param pSrcAddr The source address of the frame. * @param pDstAddr The destination address of the frame. * Grab the spinlock first and do the switching. /* Iterate the internal network interfaces and look for matching source and destination addresses. */ /* Unknown interface address? */ /* Paranoia - this shouldn't happen, right? */ * Switch a unicast MAC address and return a destination table. * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). * @param pNetwork The network to switch on. * @param fSrc The frame source. * @param pIfSender The sender interface, NULL if trunk. Used to * prevent sending an echo to the sender. * @param pDstAddr The destination address of the frame. * @param pDstTab The destination output table. * Grab the spinlock first and do the switching. /* Find exactly matching or promiscuous interfaces. */ /* Network only promicuous mode ifs should see related trunk traffic. */ /* Does it match the host, or is the host promiscuous? */ /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */ /* Grab the trunk if we're sending to it. */ * Create a destination table for a broadcast frame. * @returns INTNETSWDECISION_BROADCAST. * @param pNetwork The network to switch on. * @param fSrc The frame source. * @param pIfSender The sender interface, NULL if trunk. Used to * prevent sending an echo to the sender. * @param pDstTab The destination output table. * Grab the spinlock first and record all active interfaces. /* Regular interfaces. */ /* The trunk interface. */ * Create a destination table with the trunk and any promiscuous interfaces. * This is only used in a fallback case of the level-3 switching, so we can * assume the wire as source and skip the sender interface filtering. * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK, * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer). * @param pNetwork The network to switch on. * @param fSrc The frame source. * @param pDstTab The destination output table. * Grab the spinlock first and do the switching. /* Find promiscuous interfaces. */ /* The trunk interface. */ * Create a destination table for a trunk frame. * @returns INTNETSWDECISION_BROADCAST. * @param pNetwork The network to switch on. * @param fSrc The frame source. * @param pDstTab The destination output table. * Grab the spinlock first and record all active interfaces. /* The trunk interface. */ * Wrapper around RTMemAlloc for allocating a destination table. * @returns VINF_SUCCESS or VERR_NO_MEMORY. * @param cEntries The size given as an entry count. * @param ppDstTab Where to store the pointer (always). * Ensures that there is space for another interface in the MAC address lookup * table as well as all the destination tables. * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_OUT_OF_RANGE. * @param pNetwork The network to operate on. * The cEntries and cEntriesAllocated members are only updated while * owning the big mutex, so we only need the spinlock when doing the * actual table replacing. * Resize the destination tables first, this can be kind of tedious. * The MAC Address table itself. * Snoops IP assignments and releases from the DHCPv4 traffic. * The caller is responsible for making sure this traffic between the * BOOTPS and BOOTPC ports and validate the IP header. The UDP packet * need not be validated beyond the ports. * @param pNetwork The network this frame was seen on. * @param pIpHdr Pointer to a valid IP header. This is for pseudo * header validation, so only the minimum header size * needs to be available and valid here. * @param pUdpHdr Pointer to the UDP header in the frame. * @param cbUdpPkt What's left of the frame when starting at the UDP header. * @param fGso Set if this is a GSO frame, clear if regular. * Check if the DHCP message is valid and get the type. Log6((
"Bad UDP packet\n"));
Log6((
"Bad DHCP packet\n"));
/** @todo Check for valid non-broadcast requests w/ IP for any of the MACs we * know, and add the IP to the cache. */ * Lookup the interface by its MAC address and insert the IPv4 address into the cache. * Delete the old client address first, just in case it changed in a renewal. * Lookup the interface by its MAC address and remove the IPv4 address(es) from the cache. * Worker for intnetR0TrunkIfSnoopAddr that takes care of what * is likely to be a DHCP message. * The caller has already check that the UDP source and destination ports * @param pNetwork The network this frame was seen on. * @param pSG The gather list for the frame. * Get a pointer to a linear copy of the full packet, using the * temporary buffer if necessary. //pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP; * Validate the IP header and find the UDP packet. Log((
"intnetR0TrunkIfSnoopDhcp: bad ip header\n"));
* Hand it over to the common DHCP snooper. #
endif /* INTNET_WITH_DHCP_SNOOPING */ * Snoops up source addresses from ARP requests and purge these from the address * The purpose of this purging is to get rid of stale addresses. * @param pNetwork The network this frame was seen on. * @param pSG The gather list for the frame. * Check the minimum size first. * Copy to temporary buffer if necessary. * Ignore packets which doesn't interest us or we perceive as malformed. * Delete the source address if it's OK. * Snoop up addresses from ARP and DHCP traffic from frames coming * over the trunk connection. * The caller is responsible for do some basic filtering before calling * For IPv4 this means checking against the minimum DHCPv4 frame size. * @param pNetwork The network. * @param pSG The SG list for the frame. * @param EtherType The Ethertype of the frame. /* check if the protocol is UDP */ /* get the TCP header length */ /* check if the protocol is UDP */ /* get the TCP header length */ /* get the lower byte of the UDP source port number. */ /* get the lower byte of the UDP destination port number. */ /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might * need to be edited. Check out how NDP works... */ #
endif /* INTNET_WITH_DHCP_SNOOPING */ * Deals with an IPv4 packet. * This will fish out the source IP address and add it to the cache. * Then it will look for DHCPRELEASE requests (?) and anything else * that we might find useful later. * @param pIf The interface that's sending the frame. * @param pIpHdr Pointer to the IPv4 header in the frame. * @param cbPacket The size of the packet, or more correctly the * size of the frame without the ethernet header. * @param fGso Set if this is a GSO frame, clear if regular. * Check the header size first to prevent access invalid data. * If the source address is good (not broadcast or my network) and * not already in the address cache of the sender, add it. Validate * the IP header before adding it. Log((
"intnetR0IfSnoopIPv4SourceAddr: bad ip header\n"));
* Check for potential DHCP packets. && !
fGso)
/* GSO is not applicable to DHCP traffic. */ Log((
"intnetR0IfSnoopIPv4SourceAddr: bad ip header (dhcp)\n"));
#
endif /* INTNET_WITH_DHCP_SNOOPING */ * Snoop up source addresses from an ARP request or reply. * @param pIf The interface that's sending the frame. * @param pHdr The ARP header. * @param cbPacket The size of the packet (might be larger than the ARP * request 'cause of min ethernet frame size). * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we * don't have to repeat the frame parsing in intnetR0TrunkIfSend. * Ignore packets which doesn't interest us or we perceive as malformed. * Tag the SG as ARP IPv4 for later editing, then check for addresses * which can be removed or added to the address cache of the sender. * Checks packets send by a normal interface for new network * @param pIf The interface that's sending the frame. * @param pbFrame The frame. * @param cbFrame The size of the frame. * @param fGso Set if this is a GSO frame, clear if regular. * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we * don't have to repeat the frame parsing in intnetR0TrunkIfSend. * Fish out the ethertype and look for stuff we can handle. #
if 0
/** @todo IntNet: implement IPv6 for wireless MAC sharing. */ /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might * need to be edited. Check out how NDP works... */ #
if 0
/** @todo IntNet: implement IPX for wireless MAC sharing? */ * Writes a frame packet to the ring buffer. * @returns VBox status code. * @param pBuf The buffer. * @param pRingBuf The ring buffer to read from. * @param pSG The gather list. * @param pNewDstMac Set the destination MAC address to the address if specified. * Sends a frame to a specific interface. * @param pIf The interface. * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. * @param pSG The gather buffer which data is being sent to the interface. * @param pNewDstMac Set the destination MAC address to the address if specified. * Scheduling hack, for unicore machines primarily. &&
pIfSender /* but not if it's from the trunk */ /* ok, the frame is lost. */ * Fallback path that does the GSO segmenting before passing the frame on to the * The caller holds the trunk lock. * @param pThis The trunk. * @param pIfSender The IF sending the frame. * @param pSG Pointer to the gather list. * @param fDst The destination flags. * Since we're only using this for GSO frame coming from the internal * network interfaces and never the trunk, we can assume there is only * one segment. This simplifies the code quite a bit. * Carve out the frame segments with the header and frame in different * scatter / gather segments. * Checks if any of the given trunk destinations can handle this kind of GSO SG. * @returns true if it can, false if it cannot. * @param pThis The trunk. * @param pSG The scatter / gather buffer. * @param fDst The destination mask. * Sends a frame down the trunk. * @param pThis The trunk. * @param pNetwork The network the frame is being sent to. * @param pIfSender The IF sending the frame. Used for MAC address * checks in shared MAC mode. * @param fDst The destination flags. * @param pSG Pointer to the gather list. * Edit the frame if we're sharing the MAC address with the host on the wire. * If the frame is headed for both the host and the wire, we'll have to send * it to the host before making any modifications, and force the OS specific * backend to copy it. We do this by marking it as TEMP (which is always the * Dispatch it to the host before making changes. * Edit the source address so that it it's the same as the host. /* ASSUME frame from IntNetR0IfSend! */ * Deal with tags from the snooping phase. * APR IPv4: replace hardware (MAC) addresses because these end up * in ARP caches. So, if we don't the other machines will * send the packets to the MAC address of the guest * instead of the one of the host, which won't work on //else if (pSG->fFlags & INTNETSG_FLAGS_ICMPV6_NDP) //{ /// @todo move the editing into a different function * Send the frame, handling the GSO fallback . * Note! The trunk implementation will re-check that the trunk is active . * before sending, so we don't have to duplicate that effort here. /** @todo failure statistics? */ * Edits an ARP packet arriving from the wire via the trunk connection. * @param pNetwork The network the frame is being sent to. * @param pSG Pointer to the gather list for the frame. * The flags and data content may be updated. * @param pEthHdr Pointer to the ethernet header. This may also be * updated if it's a unicast... * Check the minimum size and get a linear copy of the thing to work on, * using the temporary buffer if necessary. * Ignore packets which doesn't interest us or we perceive as malformed. /* Tag it as ARP IPv4. */ * The thing we're interested in here is a reply to a query made by a guest * since we modified the MAC in the initial request the guest made. /* Write back the packet if we've been making changes to a buffered copy. */ * Detects and edits an DHCP packet arriving from the internal net. * @param pNetwork The network the frame is being sent to. * @param pSG Pointer to the gather list for the frame. * The flags and data content may be updated. * @param pEthHdr Pointer to the ethernet header. This may also be * updated if it's a unicast... * Check the minimum size and get a linear copy of the thing to work on, * using the temporary buffer if necessary. * Get a pointer to a linear copy of the full packet, using the * temporary buffer if necessary. //pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP; * Validate the IP header and find the UDP packet. Log6((
"intnetR0NetworkEditDhcpFromIntNet: bad ip header\n"));
/* We are only interested in DHCP packets coming from client to server. */ * Check if the DHCP message is valid and get the type. Log6((
"intnetR0NetworkEditDhcpFromIntNet: Bad UDP packet\n"));
Log6((
"intnetR0NetworkEditDhcpFromIntNet: Bad DHCP packet\n"));
* Must set the broadcast flag or we won't catch the respons. Log6((
"intnetR0NetworkEditDhcpFromIntNet: Setting broadcast flag in DHCP %#x, previously %x\n",
* Work around little endian checksum issue in mac os x 10.7.0 GM. /* Patch the IP header checksum. */ Log((
"intnetR0NetworkEditDhcpFromIntNet: cleared ip_tos (was %#04x); ip_sum=%#06x -> %#06x\n",
* Checks if the callers context is okay for sending to the specified * @returns true if it's okay, false if it isn't. * @param pNetwork The network. * @param pIfSender The interface sending or NULL if it's the trunk. * @param pDstTab The destination table. /* Sending to the trunk is the problematic path. If the trunk is the sender we won't be sending to it, so no problem.. Note! fTrunkDst may be set event if if the trunk is the sender. */ /* ASSUMES: that the trunk won't change its report while we're checking. */ /* ASSUMES: That a preemption test detects HM contexts. (Will work on non-preemptive systems as well.) */ * Checks if the callers context is okay for doing a broadcast given the * @returns true if it's okay, false if it isn't. * @param pNetwork The network. * @param fSrc The source of the packet. (0 (intnet), * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE). /* Sending to the trunk is the problematic path. If the trunk is the sender we won't be sending to it, so no problem. */ /* ASSUMES: That a preemption test detects HM contexts. (Will work on non-preemptive systems as well.) */ /* PARANOIA: Grab the spinlock to make sure the trunk structure cannot be freed while we're touching it. */ * Check context, edit, snoop and switch a broadcast frame when sharing MAC * The caller must hold at least one interface on the network busy to prevent it * from destructing beath us. * @param pNetwork The network the frame is being sent to. * @param fSrc The source of the packet. (0 (intnet), * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE). * @param pIfSender The sender interface, NULL if trunk. Used to * prevent sending an echo to the sender. * @param pSG Pointer to the gather list. * @param pEthHdr Pointer to the ethernet header. * @param pDstTab The destination output table. * Before doing any work here, we need to figure out if we can handle it * in the current context. The restrictions are solely on the trunk. * Note! Since at least one interface is busy, there won't be any changes * to the parameters here (unless the trunk changes its capability * report, which it shouldn't). * Check for ARP packets from the wire since we'll have to make * modification to them if we're sharing the MAC address with the host. * Check for DHCP packets from the internal net since we'll have to set * broadcast flag in DHCP requests if we're sharing the MAC address with * the host. GSO is not applicable to DHCP traffic. * Snoop address info from packet originating from the trunk connection. * Create the broadcast destination table. * Check context, snoop and switch a unicast frame using the network layer * address of the link layer one (when sharing MAC address on the wire). * This function is only used for frames coming from the wire (trunk). * @returns true if it's addressed to someone on the network, otherwise false. * @param pNetwork The network the frame is being sent to. * @param pSG Pointer to the gather list. * @param pEthHdr Pointer to the ethernet header. * @param pDstTab The destination output table. * Extract the network address from the packet. Log((
"intnetshareduni: failed to read ip_dst! cbTotal=%#x\n",
pSG->
cbTotal));
#
if 0
/** @todo IntNet: implement IPv6 for wireless MAC sharing. */ Log((
"intnetshareduni: failed to read ip6_dst! cbTotal=%#x\n",
pSG->
cbTotal));
#
if 0
/** @todo IntNet: implement IPX for wireless MAC sharing? */ Log((
"intnetshareduni: failed to read ipx_dstnet! cbTotal=%#x\n",
pSG->
cbTotal));
* Treat ARP as broadcast (it shouldn't end up here normally, * so it goes last in the switch). Log6((
"intnetshareduni: ARP\n"));
/** @todo revisit this broadcasting of unicast ARP frames! */ * Unknown packets are sent to the trunk and any promiscuous interfaces. * Perform DHCP snooping. GSO is not applicable to DHCP traffic #
endif /* INTNET_WITH_DHCP_SNOOPING */ * Release all the interfaces in the destination table when we realize that * we're in a context where we cannot get the job done. * @param pNetwork The network. * @param pDstTab The destination table. /* The trunk interface. */ /* Regular interfaces. */ * Deliver the frame to the interfaces specified in the destination table. * @param pNetwork The network. * @param pDstTab The destination table. * @param pSG The frame to send. * @param pIfSender The sender interface. NULL if it originated via * Do the interfaces first before sending it to the wire and risk having to * Note! The switching functions will include the trunk even when the frame * source is the trunk. This is because we need it to figure out * whether the other half of the trunk should see the frame or not * and let the caller know. * So, we'll ignore trunk sends here if the frame origin is * INTNETTRUNKSWPORT::pfnRecv. * This function will distribute the frame to the interfaces it is addressed to. * It will also update the MAC address of the sender. * The caller must own the network mutex. * @returns The switching decision. * @param pNetwork The network the frame is being sent to. * @param pIfSender The interface sending the frame. This is NULL if it's the trunk. * @param fSrc The source flags. This 0 if it's not from the trunk. * @param pSG Pointer to the gather list. * @param pDstTab The destination table to use. * Get the ethernet header (might theoretically involve multiple segments). Log2((
"D=%.6Rhxs S=%.6Rhxs T=%04x f=%x z=%x\n",
* Learn the MAC address of the sender. No re-learning as the interface * user will normally tell us the right MAC address. * Note! We don't notify the trunk about these mainly because of the * problematic contexts we might be called in. * Deal with MAC address sharing as that may required editing of the * packets before we dispatch them anywhere. * Deliver to the destinations if we can. * Sends one or more frames. * The function will first the frame which is passed as the optional arguments * pvFrame and cbFrame. These are optional since it also possible to chain * together one or more frames in the send buffer which the function will * process after considering it's arguments. * The caller is responsible for making sure that there are no concurrent calls * to this method (with the same handle). * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. Log5((
"IntNetR0IfSend: hIf=%RX32\n",
hIf));
* Validate input and translate the handle. * Make sure we've got a network. * Grab the destination table. * Process the send buffer. INTNETSG Sg;
/** @todo this will have to be changed if we're going to use async sending * with buffer sharing for some OS or service. Darwin copies everything so * I won't bother allocating and managing SGs right now. Sorry. */ /* Send regular frame. */ /* Send GSO frame if sane. */ /* Unless it's a padding frame, we're getting babble from the producer. */ /* Skip to the next frame. */ * Put back the destination table. * VMMR0 request wrapper for IntNetR0IfSend. * @returns see IntNetR0IfSend. * @param pSession The caller's session. * @param pReq The request packet. * Maps the default buffer into ring 3. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param ppRing3Buf Where to store the address of the ring-3 mapping * @param ppRing0Buf Where to store the address of the ring-0 mapping * ASSUMES that only the process that created an interface can use it. * ASSUMES that we created the ring-3 mapping when selecting or LogFlow((
"IntNetR0IfGetBufferPtrs: returns %Rrc *ppRing3Buf=%p *ppRing0Buf=%p\n",
* VMMR0 request wrapper for IntNetR0IfGetBufferPtrs. * @returns see IntNetR0IfGetRing3Buffer. * @param pSession The caller's session. * @param pReq The request packet. * Gets the physical addresses of the default interface buffer. * @returns VBox status code. * @param hIF The interface handle. * @param paPages Where to store the addresses. (The reserved fields will be set to zero.) * Grab the lock and get the data. * ASSUMES that the handle isn't closed while we're here. /** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there * is no need for any extra bookkeeping here.. */ * Sets the promiscuous mode property of an interface. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not. * Validate & translate input. Log((
"IntNetR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
* Get the network, take the address spinlock, and make the change. * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed. Log((
"IntNetR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d (%d)\n",
* VMMR0 request wrapper for IntNetR0IfSetPromiscuousMode. * @returns see IntNetR0IfSetPromiscuousMode. * @param pSession The caller's session. * @param pReq The request packet. * Sets the MAC address of an interface. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param pMAC The new MAC address. * Validate & translate input. Log((
"IntNetR0IfSetMacAddress: returns VERR_INVALID_HANDLE\n"));
* Get the network, take the address spinlock, and make the change. * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed. Log((
"IntNetR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
/* Update the two copies. */ /* Grab a busy reference to the trunk so we release the lock before notifying it. */ Log((
"IntNetR0IfSetMacAddress: pfnNotifyMacAddress hIf=%RX32\n",
hIf));
* VMMR0 request wrapper for IntNetR0IfSetMacAddress. * @returns see IntNetR0IfSetMacAddress. * @param pSession The caller's session. * @param pReq The request packet. * Worker for intnetR0IfSetActive and intnetR0IfDestruct. * This function will update the active interface count on the network and * activate or deactivate the trunk connection if necessary. * The call must own the giant lock (we cannot take it here). * @returns VBox status code. * @param pNetwork The network. * @param fIf The interface. * @param fActive What to do. * The address spinlock of the network protects the variables, while the * big lock protects the calling of pfnSetState. Grab both lock at once * to save us the extra hassle. * Tell the trunk if necessary. * The wait for !busy is for the Solaris streams trunk driver (mostly). * Sets the active property of an interface. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param fActive The new state. * Validate & translate input. Log((
"IntNetR0IfSetActive: returns VERR_INVALID_HANDLE\n"));
* Hand it to the network since it might involve the trunk and things are * tricky there wrt to locking order. * 1. We take the giant lock here. This makes sure nobody is re-enabling * the network while we're pausing it and vice versa. This also enables * us to wait for the network to become idle before telling the trunk. * (Important on Solaris.) * 2. For paranoid reasons, we grab a busy reference to the calling * interface. This is totally unnecessary but should hurt (when done * after grabbing the giant lock). LogFlow((
"IntNetR0IfSetActive: returns %Rrc\n",
rc));
* VMMR0 request wrapper for IntNetR0IfSetActive. * @returns see IntNetR0IfSetActive. * @param pIntNet The internal networking instance. * @param pSession The caller's session. * @param pReq The request packet. * Wait for the interface to get signaled. * The interface will be signaled when is put into the receive buffer. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be * used if indefinite wait is desired. * Get and validate essential handles. Log((
"IntNetR0IfWait: returns VERR_INVALID_HANDLE\n"));
Log((
"IntNetR0IfWait: returns VERR_SEM_DESTROYED\n"));
* It is tempting to check if there is data to be read here, * but the problem with such an approach is that it will cause * one unnecessary supervisor->user->supervisor trip. There is * already a slight risk for such, so no need to increase it. * Increment the number of waiters before starting the wait. * Upon wakeup we must assert reality, checking that we're not * already destroyed or in the process of being destroyed. This * code must be aligned with the waiting code in intnetR0IfDestruct. Log4((
"IntNetR0IfWait: returns %Rrc\n",
rc));
* VMMR0 request wrapper for IntNetR0IfWait. * @returns see IntNetR0IfWait. * @param pSession The caller's session. * @param pReq The request packet. * Wake up any threads waiting on the interface. * @returns VBox status code. * @param hIf The interface handle. * @param pSession The caller's session. * @param fNoMoreWaits When set, no more waits are permitted. * Get and validate essential handles. Log((
"IntNetR0IfAbortWait: returns VERR_INVALID_HANDLE\n"));
Log((
"IntNetR0IfAbortWait: returns VERR_SEM_DESTROYED\n"));
* Set fDestroying if requested to do so and then wake up all the sleeping * threads (usually just one). We leave the semaphore in the signalled * state so the next caller will return immediately. * VMMR0 request wrapper for IntNetR0IfAbortWait. * @returns see IntNetR0IfWait. * @param pSession The caller's session. * @param pReq The request packet. * @returns VBox status code. * @param pIntNet The instance handle. * @param hIf The interface handle. * @param pSession The caller's session. * Validate and free the handle. /* Mark the handle as freed so intnetR0IfDestruct won't free it again. */ * Signal the event semaphore to wake up any threads in IntNetR0IfWait * and give them a moment to get out and release the interface. * Release the references to the interface object (handle + free lookup). LogFlow((
"IntNetR0IfClose: returns %Rrc\n",
rc));
* VMMR0 request wrapper for IntNetR0IfCloseReq. * @returns see IntNetR0IfClose. * @param pSession The caller's session. * @param pReq The request packet. * 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. * adding or removing interface while we're in here. For paranoid reasons * we also mark the interface as destroyed here so any waiting threads can * take evasive action (theoretical case). * Delete the interface handle so the object no longer can be used. * (Can happen if the client didn't close its session.) * If we've got a network deactivate and detach ourselves from it. Because * of cleanup order we might have been orphaned by the network destructor. /* remove ourselves from the switch table. */ /* recalc the min flags. */ /* Notify the trunk about the interface being destroyed. */ /* Wait for the interface to quiesce while we still can. */ /* Release our reference to the network. */ * Wakeup anyone waiting on this interface. * We *must* make sure they have woken up properly and realized * that the interface is no longer valid. * Unmap and Free the default buffer. * Free remaining resources * 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, referenced. The reference is consumed on * @param pSession The session handle. * @param cbSend The size of the send buffer. * @param cbRecv The size of the receive buffer. * @param fFlags The open network flags. * @param phIf Where to store the interface handle. LogFlow((
"intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u fFlags=%#x phIf=%p\n",
* Adjust the flags with defaults for the interface policies. * Note: Main restricts promiscuous mode per interface. * Make sure that all destination tables as well as the have space of * Allocate the interface and initialize it. //pIf->fPromiscuousReal = false; //pIf->fDestroying = false; //pIf->pIntBufR3 = NIL_RTR3PTR; //pIf->pIntBufDefault = 0; //pIf->pIntBufDefaultR3 = NIL_RTR3PTR; * Create the default buffer. /** @todo adjust with minimums and apply defaults here. */ * Register the interface with the session and create a handle for it. * Finally add the interface to the network, consuming the * network reference of the caller. * Grab a busy reference (paranoia) to the trunk before releasing * the spinlock and then notify it about the new interface. Log((
"intnetR0NetworkCreateIf: pfnConnectInterface hIf=%RX32\n",
pIf->
hIf));
Log((
"intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
LogFlow((
"intnetR0NetworkCreateIf: returns %Rrc\n",
rc));
LogFlow((
"intnetR0NetworkCreateIf: returns %Rrc\n",
rc));
/** @copydoc INTNETTRUNKSWPORT::pfnSetSGPhys */ AssertMsgFailed((
"Not implemented because it wasn't required on Darwin\n"));
/** @copydoc INTNETTRUNKSWPORT::pfnReportMacAddress */ * Get the network instance and grab the address spinlock before making /** @copydoc INTNETTRUNKSWPORT::pfnReportPromiscuousMode */ * Get the network instance and grab the address spinlock before making /** @copydoc INTNETTRUNKSWPORT::pfnReportGsoCapabilities */ /** @copydoc INTNETTRUNKSWPORT::pfnReportNoPreemptDsts */ /** @copydoc INTNETTRUNKSWPORT::pfnPreRecv */ * Mark the trunk as busy, make sure we've got a network and that there are * some active interfaces around. * Lazy bird! No pre-switching of multicast and shared-MAC-on-wire. /** @copydoc INTNETTRUNKSWPORT::pfnRecv */ * Mark the trunk as busy, make sure we've got a network and that there are * some active interfaces around. bool fRc =
false /* don't drop it */;
* Grab or allocate a destination table. /* Interrupt or restricted context. */ /* Task context, fallback is to allocate a table. */ * Finally, get down to business of sending the frame. fRc =
true;
/* drop it */ * Free the destination table. /* this shouldn't happen! */ /** @copydoc INTNETTRUNKSWPORT::pfnSGRetain */ /** @copydoc INTNETTRUNKSWPORT::pfnSGRelease */ * Shutdown the trunk interface. * @param pThis The trunk. * @param pNetworks The network. * @remarks The caller must hold the global lock. * The interface has already been deactivated, we just to wait for * it to become idle before we can disconnect and release it. /* wait in portions so we can complain ever now an then. */ LogRel((
"intnet: '%s' didn't become idle in %RU64 ns (%Rrc).\n",
LogRel((
"intnet: '%s' didn't become idle in %RU64 ns (%Rrc).\n",
LogRel((
"intnet: '%s' didn't become idle in %RU64 ns (%Rrc), giving up.\n",
/* disconnect & release it. */ * Creates the trunk connection (if any). * @returns VBox status code. * @param pNetwork The newly created network. * @param pSession The session handle. * The 'None' case, simple. * Well, here we don't want load anything special, * just communicate between processes via internal network. /* Can't happen, but makes GCC happy. */ * Translate enum to component factory name. #
else /* VBOXNETADP_DO_NOT_USE_NETFLT */#
endif /* VBOXNETADP_DO_NOT_USE_NETFLT */ * Allocate the trunk interface and associated destination tables. * We take a very optimistic view on the parallelism of the host * network stack and NIC driver. So, we allocate one table for each * possible CPU to deal with interrupt time requests and one for task //pTrunk->pIfPort = NULL; //pTrunk->fPhysSG = false; //pTrunk->fUnused = false; //pTrunk->fNoPreemptDsts = 0; //pTrunk->fWireGsoCapabilites = 0; //pTrunk->fHostGsoCapabilites = 0; //pTrunk->abGsoHdrs = {0}; //pTrunk->apTaskDstTabs = above; //pTrunk->cIntDstTabs = above; //pTrunk->apIntDstTabs = above; * Create the lock (we've NIL'ed the members above to simplify cleanup). * There are a couple of bits in MacTab as well pertaining to the * trunk. We have to set this before it's reported. * Note! We don't need to lock the MacTab here - creation time. #
ifdef IN_RING0 /* (testcase is ring-3) */ * Query the factory we want, then use it create and connect the trunk. Log((
"intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n",
/* bail out and clean up. */ LogFlow((
"intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
* 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. * Tell the trunk, if present, that we're about to disconnect it and wish * no further calls from it. * Deactivate and orphan any remaining interfaces and wait for them to idle. * Note! Normally there are no more interfaces at this point, however, when * supdrvCloseSession / supdrvCleanupSession release the objects the * order is undefined. So, it's quite possible that the network will * be dereference and destroyed before the interfaces. /* Wait for all the interfaces to quiesce. (Interfaces cannot be removed / added since we're holding the big lock.) */ /* Orphan the interfaces (not trunk). Don't bother with calling pfnDisconnectInterface here since the networking is going away. */ * Zap the trunk pointer while we still own the spinlock, destroy the * trunk after we've left it. Note that this might take a while... * Note that it needn't be in the list if we failed during creation. * Checks if the open network flags are compatible. * @returns VBox status code. * @param pNetwork The network. * @param fFlags The open network flags. * Adapts flag changes on network opening. * @returns VBox status code. * @param pNetwork The network. * @param fFlags The open network flags. * Upgrade the minimum policy flags. * Calculate the new network flags. * (Depends on fNetMinFlags being recalculated first.) * Apply the flags if they changed. /* Recalculate some derived switcher variables. */ * Opens an existing network. * The call must own the INTNET::hMtxCreateOpenDestroy. * @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 enmTrunkType The trunk type. * @param pszTrunk The trunk name. Its meaning is specific to the type. * @param fFlags Flags, see INTNET_OPEN_FLAGS_*. * @param ppNetwork Where to store the pointer to the network on success. LogFlow((
"intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
/* just pro forma validation, the caller is internal. */ * Search networks by name. * Found the network, now check that we have the same ideas * about the trunk setup and security. * Increment the reference and check that the session * can access this network. LogRel((
"intnetR0OpenNetwork failed. rc=%Rrc pCur->szTrunk=%s pszTrunk=%s pCur->enmTrunkType=%d enmTrunkType=%d\n",
LogFlow((
"intnetR0OpenNetwork: returns VERR_NOT_FOUND\n"));
* The call must own the INTNET::hMtxCreateOpenDestroy and has already attempted * opening the network and found it to be non-existing. * @returns VBox status code. * @param pIntNet The instance data. * @param pSession The session handle. * @param pszNetwork The name of the network. This must be at least one character long and no longer * than the INTNETNETWORK::szName. * @param enmTrunkType The trunk type. * @param pszTrunk The trunk name. Its meaning is specific to the type. * @param fFlags Flags, see INTNET_OPEN_FLAGS_*. * @param ppNetwork Where to store the network. In the case of failure * whatever is returned here should be dereferenced * outside the INTNET::hMtxCreateOpenDestroy. LogFlow((
"intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
/* just pro forma validation, the caller is internal. */ * Adjust the flags with defaults for the network policies. * Note: Main restricts promiscuous mode on the per interface level. * Allocate and initialize. //pNetwork->pNext = NULL; //pNetwork->MacTab.cPromiscuousEntries = 0; //pNetwork->MacTab.cPromiscuousNoTrunkEntries = 0; //pNetwork->pvObj = NULL; // pNetwork->pbTmp = NULL; //pNetwork->fMinFlags = 0; //pNetwork->cActiveIFs = 0; * Create the semaphore, spinlock and allocate the interface table. * Register the object in the current session and link it into the network list. * 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 LogFlow((
"intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n",
pNetwork));
LogFlow((
"intnetR0CreateNetwork: returns %Rrc\n",
rc));
LogFlow((
"intnetR0CreateNetwork: returns %Rrc\n",
rc));
* Opens a network interface and connects it to the specified network. * @returns VBox status code. * @param pSession The session handle. * @param pszNetwork The network name. * @param enmTrunkType The trunk type. * @param pszTrunk The trunk name. Its meaning is specific to the type. * @param fFlags Flags, see INTNET_OPEN_FLAGS_*. * @param fRestrictAccess Whether new participants should be subjected to access check or not. * @param cbSend The send buffer size. * @param cbRecv The receive buffer size. * @param phIf Where to store the handle to the network interface. LogFlow((
"IntNetR0Open: pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
* Try open / create the network and create an interface on it for the * VMMR0 request wrapper for IntNetR0Open. * @returns see GMMR0MapUnmapChunk. * @param pSession The caller's session. * @param pReq The request packet. * Count the internal networks. * This is mainly for providing the testcase with some introspection to validate * behavior when closing interfaces. * @returns The number of networks. * Grab the mutex and count the networks. * Destroys an instance of the Ring-0 internal networking service. * Zap the global pointer and validate it. * There is not supposed to be any networks hanging around at this time. /** @todo does it make sense to have a deleter here? */ * Initializes the internal network ring-0 service. * @returns VBox status code. //pIntNet->pNetworks = NULL; LogFlow((
"IntNetR0Init: returns VINF_SUCCESS pIntNet=%p\n",
pIntNet));
LogFlow((
"IntNetR0Init: returns %Rrc\n",
rc));