SrvIntNetR0.cpp revision f091ce66ee934d599f16056078a9a76d7286b959
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Internal networking - The ring 0 service.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copyright (C) 2006-2011 Oracle Corporation
fa9e4066f08beec538e775443c5be79dd423fcabahrens * This file is part of VirtualBox Open Source Edition (OSE), as
fa9e4066f08beec538e775443c5be79dd423fcabahrens * available from http://www.virtualbox.org. This file is free software;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * you can redistribute it and/or modify it under the terms of the GNU
fa9e4066f08beec538e775443c5be79dd423fcabahrens * General Public License (GPL) as published by the Free Software
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Foundation, in version 2 as it comes in the "COPYING" file of the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*******************************************************************************
fa9e4066f08beec538e775443c5be79dd423fcabahrens* Header Files *
99653d4ee642c6528e88224f12409a5f23060994eschrock*******************************************************************************/
fa9e4066f08beec538e775443c5be79dd423fcabahrens/*******************************************************************************
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock* Defined Constants And Macros *
06eeb2ad640ce72d394ac521094bed7681044408ek*******************************************************************************/
fa9e4066f08beec538e775443c5be79dd423fcabahrens/** @def INTNET_WITH_DHCP_SNOOPING
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Enabled DHCP snooping when in shared-mac-on-the-wire mode. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens/** The maximum number of interface in a network. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** The number of entries to grow the destination tables with. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** The wakeup bit in the INTNETIF::cBusy and INTNETRUNKIF::cBusy counters. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/*******************************************************************************
990b4856d0eaada6f8140335733a1b1771ed2746lling* Structures and Typedefs *
990b4856d0eaada6f8140335733a1b1771ed2746lling*******************************************************************************/
990b4856d0eaada6f8140335733a1b1771ed2746lling * MAC address lookup table entry.
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The MAC address of this entry. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Is it is effectively promiscuous mode. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Is it promiscuous and should it see unrelated trunk traffic. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Is it active.
990b4856d0eaada6f8140335733a1b1771ed2746lling * We ignore the entry if this is clear and may end up sending packets addressed
990b4856d0eaada6f8140335733a1b1771ed2746lling * to this interface onto the trunk. The reasoning for this is that this could
990b4856d0eaada6f8140335733a1b1771ed2746lling * be the interface of a VM that just has been teleported to a different host. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the network interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a MAC address lookup table entry. */
990b4856d0eaada6f8140335733a1b1771ed2746lling * MAC address lookup table.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @todo Having this in a separate structure didn't work out as well as it
990b4856d0eaada6f8140335733a1b1771ed2746lling * should. Consider merging it into INTNETNETWORK.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETMACTAB
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The current number of entries. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of entries we've allocated space for. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Table entries. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of interface entries currently in promicuous mode. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of interface entries currently in promicuous mode that
990b4856d0eaada6f8140335733a1b1771ed2746lling * shall not see unrelated trunk traffic. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The host MAC address (reported). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The effective host promiscuous setting (reported). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The real host promiscuous setting (reported). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether the host is active. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether the wire is promiscuous (config). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether the wire is promiscuous (config).
990b4856d0eaada6f8140335733a1b1771ed2746lling * (Shadows INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE in
990b4856d0eaada6f8140335733a1b1771ed2746lling * INTNETNETWORK::fFlags.) */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether the wire is active. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the trunk interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a MAC address . */
990b4856d0eaada6f8140335733a1b1771ed2746lling * Destination table.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETDSTTAB
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The trunk destinations. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the trunk interface (referenced) if fTrunkDst is non-zero. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of destination interfaces. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The interfaces (referenced). Variable sized array. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The destination interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether to replace the destination MAC address.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is used when sharing MAC address with the host on the wire(less). */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a destination table. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a const destination table. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Network layer address type. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The invalid 0 entry. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** IP version 4. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** IP version 6. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** IPX. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The end of the valid values. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The usual 32-bit hack. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a network layer address type. */
990b4856d0eaada6f8140335733a1b1771ed2746lling * Address and type.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETADDR
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The address type. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The address. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to an address. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a const address. */
990b4856d0eaada6f8140335733a1b1771ed2746lling * Address cache for a specific network layer.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETADDRCACHE
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the table of addresses. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of valid address entries. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of allocated address entries. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The address size. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The size of an entry. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to an address cache. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a const address cache. */
990b4856d0eaada6f8140335733a1b1771ed2746lling * A network interface.
990b4856d0eaada6f8140335733a1b1771ed2746lling * Unless explicitly stated, all members are protect by the network semaphore.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETIF
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The MAC address.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is shadowed by INTNETMACTABENTRY::MacAddr. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Set if the INTNET::MacAddr member has been explicitly set. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Tracks the desired promiscuous setting of the interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether the interface is active or not.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is shadowed by INTNETMACTABENTRY::fActive. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Whether someone is currently in the destructor or has indicated that
990b4856d0eaada6f8140335733a1b1771ed2746lling * the end is nigh by means of IntNetR0IfAbortWait. */
990b4856d0eaada6f8140335733a1b1771ed2746lling bool volatile fDestroying;
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The flags specified when opening this interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Number of yields done to try make the interface read pending data.
990b4856d0eaada6f8140335733a1b1771ed2746lling * We will stop yielding when this reaches a threshold assuming that the VM is
990b4856d0eaada6f8140335733a1b1771ed2746lling * paused or that it simply isn't worth all the delay. It is cleared when a
990b4856d0eaada6f8140335733a1b1771ed2746lling * successful send has been done. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the current exchange buffer (ring-0). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to ring-3 mapping of the current exchange buffer. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the default exchange buffer for the interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to ring-3 mapping of the default exchange buffer. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Event semaphore which a receiver/consumer thread will sleep on while
990b4856d0eaada6f8140335733a1b1771ed2746lling * waiting for data to arrive. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Number of threads sleeping on the event semaphore. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The interface handle.
990b4856d0eaada6f8140335733a1b1771ed2746lling * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
990b4856d0eaada6f8140335733a1b1771ed2746lling * should return with the appropriate error condition. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the network this interface is connected to.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is protected by the INTNET::hMtxCreateOpenDestroy. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The session this interface is associated with. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The SUPR0 object id. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The network layer address cache. (Indexed by type, 0 entry isn't used.)
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is protected by the address spinlock of the network. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Spinlock protecting the input (producer) side of the receive ring. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Busy count for tracking destination table references and active sends.
990b4856d0eaada6f8140335733a1b1771ed2746lling * Usually incremented while owning the switch table spinlock. The 30th bit
990b4856d0eaada6f8140335733a1b1771ed2746lling * is used to indicate wakeup. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The preallocated destination table.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is NULL when it's in use as a precaution against unserialized
990b4856d0eaada6f8140335733a1b1771ed2746lling * transmitting. This is grown when new interfaces are added to the network. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the trunk's per interface data. Can be NULL. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Header buffer for when we're carving GSO frames. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw/** Pointer to an internal network interface. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * A trunk interface.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgwtypedef struct INTNETTRUNKIF
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** The port interface we present to the component. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** The port interface we get from the component. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** Pointer to the network we're connect to.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * This may be NULL if we're orphaned? */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** The current MAC address for the interface. (reported)
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * Updated while owning the switch table spinlock. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** Whether to supply physical addresses with the outbound SGs. (reported) */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Explicit alignment. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Busy count for tracking destination table references and active sends.
990b4856d0eaada6f8140335733a1b1771ed2746lling * Usually incremented while owning the switch table spinlock. The 30th bit
990b4856d0eaada6f8140335733a1b1771ed2746lling * is used to indicate wakeup. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Mask of destinations that pfnXmit cope with disabled preemption for. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The GSO capabilities of the wire destination. (reported) */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The GSO capabilities of the host destination. (reported)
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is as bit map where each bit represents the GSO type with the same
990b4856d0eaada6f8140335733a1b1771ed2746lling * number. */
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock /** The destination table spinlock, interrupt safe.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * Protects apTaskDstTabs and apIntDstTabs. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of entries in apIntDstTabs. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The task time destination tables.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @remarks intnetR0NetworkEnsureTabSpace and others ASSUMES this immediately
990b4856d0eaada6f8140335733a1b1771ed2746lling * precedes apIntDstTabs so that these two tables can be used as one
990b4856d0eaada6f8140335733a1b1771ed2746lling * contiguous one. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The interrupt / disabled-preemption time destination tables.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is a variable sized array. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a trunk interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
990b4856d0eaada6f8140335733a1b1771ed2746lling#define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
990b4856d0eaada6f8140335733a1b1771ed2746lling * Internal representation of a network.
990b4856d0eaada6f8140335733a1b1771ed2746llingtypedef struct INTNETNETWORK
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The Next network in the chain.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is protected by the INTNET::hMtxCreateOpenDestroy. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The spinlock protecting MacTab and INTNETTRUNKIF::aAddrCache.
990b4856d0eaada6f8140335733a1b1771ed2746lling * Interrupt safe. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** MAC address table.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This doubles as interface collection. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Wait for an interface to stop being busy so it can be removed or have its
990b4856d0eaada6f8140335733a1b1771ed2746lling * destination table replaced. We have to wait upon this while owning the
990b4856d0eaada6f8140335733a1b1771ed2746lling * network mutex. Will only ever have one waiter because of the big mutex. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the instance data. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The SUPR0 object id. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Pointer to the temporary buffer that is used when snooping fragmented packets.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is allocated after this structure if we're sharing the MAC address with
990b4856d0eaada6f8140335733a1b1771ed2746lling * the host. The buffer is INTNETNETWORK_TMP_SIZE big and aligned on a 64-byte boundary. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Network creation flags (INTNET_OPEN_FLAGS_*). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** Any restrictive policies required as a minimum by some interface.
990b4856d0eaada6f8140335733a1b1771ed2746lling * (INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES) */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The number of active interfaces (excluding the trunk). */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The length of the network name. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The network name. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The trunk type. */
990b4856d0eaada6f8140335733a1b1771ed2746lling /** The trunk name. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to an internal network. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to a const internal network. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** The size of the buffer INTNETNETWORK::pbTmp points at. */
990b4856d0eaada6f8140335733a1b1771ed2746lling * Internal networking instance.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgwtypedef struct INTNET
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** Magic number (INTNET_MAGIC). */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** Mutex protecting the creation, opening and destruction of both networks and
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * interfaces. (This means all operations affecting the pNetworks list.) */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** List of networks. Protected by INTNET::Spinlock. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw /** Handle table for the interfaces. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw/** Pointer to an internal network ring-0 instance. */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw/** Magic number for the internal network instance data (Hayao Miyazaki). */
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw/*******************************************************************************
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw* Global Variables *
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw*******************************************************************************/
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Pointer to the internal network instance data. */
990b4856d0eaada6f8140335733a1b1771ed2746llingstatic const struct INTNETOPENNETWORKFLAGS
990b4856d0eaada6f8140335733a1b1771ed2746lling uint32_t fRestrictive; /**< The restrictive flag (deny/disabled). */
990b4856d0eaada6f8140335733a1b1771ed2746lling uint32_t fRelaxed; /**< The relaxed flag (allow/enabled). */
990b4856d0eaada6f8140335733a1b1771ed2746lling uint32_t fPair; /**< The pair of restrictive and relaxed flags. */
990b4856d0eaada6f8140335733a1b1771ed2746lling/** Open network policy flags relating to the network. */
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_ACCESS_RESTRICTED, INTNET_OPEN_FLAGS_ACCESS_PUBLIC, INTNET_OPEN_FLAGS_ACCESS_FIXED, INTNET_OPEN_FLAGS_ACCESS_RESTRICTED | INTNET_OPEN_FLAGS_ACCESS_PUBLIC },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS, INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS },
990b4856d0eaada6f8140335733a1b1771ed2746lling { INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST, INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST },
990b4856d0eaada6f8140335733a1b1771ed2746lling { INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE, INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED, INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE, INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE | INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED, INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock { INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE, INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE },
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock/** Open network policy flags relating to the new interface. */
990b4856d0eaada6f8140335733a1b1771ed2746lling { INTNET_OPEN_FLAGS_IF_PROMISC_DENY, INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW, INTNET_OPEN_FLAGS_IF_FIXED, INTNET_OPEN_FLAGS_IF_PROMISC_DENY | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW },
990b4856d0eaada6f8140335733a1b1771ed2746lling { INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK, INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK, INTNET_OPEN_FLAGS_IF_FIXED, INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK },
990b4856d0eaada6f8140335733a1b1771ed2746lling * Worker for intnetR0SgWritePart that deals with the case where the
990b4856d0eaada6f8140335733a1b1771ed2746lling * request doesn't fit into the first segment.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @returns true, unless the request or SG invalid.
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock * @param pSG The SG list to write to.
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock * @param off Where to start writing (offset into the SG).
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock * @param cb How much to write.
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock * @param pvBuf The buffer to containing the bits to write.
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrockstatic bool intnetR0SgWritePartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock return false;
2c32020f848d8e5619a1f441a92f0ee4aca1b297eschrock * Skip ahead to the segment where off starts.
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
2f8aaab38e6371ad39ed90a1211ba8921acbb4d5eschrock unsigned iSeg = 0;
990b4856d0eaada6f8140335733a1b1771ed2746lling * Copy the data, hoping that it's all from one segment...
990b4856d0eaada6f8140335733a1b1771ed2746lling memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cb);
990b4856d0eaada6f8140335733a1b1771ed2746lling /* copy the portion in the current segment. */
990b4856d0eaada6f8140335733a1b1771ed2746lling memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cbCanCopy);
990b4856d0eaada6f8140335733a1b1771ed2746lling /* copy the portions in the other segments. */
990b4856d0eaada6f8140335733a1b1771ed2746lling } while (cb > 0);
990b4856d0eaada6f8140335733a1b1771ed2746lling return true;
990b4856d0eaada6f8140335733a1b1771ed2746lling * Writes to a part of an SG.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @returns true on success, false on failure (out of bounds).
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pSG The SG list to write to.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param off Where to start writing (offset into the SG).
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param cb How much to write.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pvBuf The buffer to containing the bits to write.
990b4856d0eaada6f8140335733a1b1771ed2746llingDECLINLINE(bool) intnetR0SgWritePart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
990b4856d0eaada6f8140335733a1b1771ed2746lling /* The optimized case. */
990b4856d0eaada6f8140335733a1b1771ed2746lling return true;
990b4856d0eaada6f8140335733a1b1771ed2746lling * Reads a byte from a SG list.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @returns The byte on success. 0xff on failure.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pSG The SG list to read.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param off The offset (into the SG) off the byte.
990b4856d0eaada6f8140335733a1b1771ed2746llingDECLINLINE(uint8_t) intnetR0SgReadByte(PCINTNETSG pSG, uint32_t off)
990b4856d0eaada6f8140335733a1b1771ed2746lling unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
990b4856d0eaada6f8140335733a1b1771ed2746lling return false;
990b4856d0eaada6f8140335733a1b1771ed2746lling * Worker for intnetR0SgReadPart that deals with the case where the
990b4856d0eaada6f8140335733a1b1771ed2746lling * requested data isn't in the first segment.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @returns true, unless the SG is invalid.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pSG The SG list to read.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param off Where to start reading (offset into the SG).
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param cb How much to read.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pvBuf The buffer to read into.
990b4856d0eaada6f8140335733a1b1771ed2746llingstatic bool intnetR0SgReadPartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
990b4856d0eaada6f8140335733a1b1771ed2746lling return false;
990b4856d0eaada6f8140335733a1b1771ed2746lling * Skip ahead to the segment where off starts.
990b4856d0eaada6f8140335733a1b1771ed2746lling unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
fa9e4066f08beec538e775443c5be79dd423fcabahrens unsigned iSeg = 0;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Copy the data, hoping that it's all from one segment...
b468a217b67dc26ce21da5d5a2ca09bb6249e4faeschrock memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cb);
b468a217b67dc26ce21da5d5a2ca09bb6249e4faeschrock /* copy the portion in the current segment. */
b468a217b67dc26ce21da5d5a2ca09bb6249e4faeschrock memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cbCanCopy);
b468a217b67dc26ce21da5d5a2ca09bb6249e4faeschrock /* copy the portions in the other segments. */
99653d4ee642c6528e88224f12409a5f23060994eschrock memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv, cbCanCopy);
fa9e4066f08beec538e775443c5be79dd423fcabahrens } while (cb > 0);
fa9e4066f08beec538e775443c5be79dd423fcabahrens return true;
b81d61a68b235e0529ebadc18e14d9d1dd52a258lling * Reads a part of an SG into a buffer.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @returns true on success, false on failure (out of bounds).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pSG The SG list to read.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param off Where to start reading (offset into the SG).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param cb How much to read.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pvBuf The buffer to read into.
99653d4ee642c6528e88224f12409a5f23060994eschrockDECLINLINE(bool) intnetR0SgReadPart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* The optimized case. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens memcpy(pvBuf, (uint8_t const *)pSG->aSegs[0].pv + off, cb);
99653d4ee642c6528e88224f12409a5f23060994eschrock return true;
5ad820458efd0fdb914baff9c1447c22b819fa23nd * Wait for a busy counter to reach zero.
5ad820458efd0fdb914baff9c1447c22b819fa23nd * @param pNetwork The network.
5ad820458efd0fdb914baff9c1447c22b819fa23nd * @param pcBusy The busy counter.
5ad820458efd0fdb914baff9c1447c22b819fa23ndstatic void intnetR0BusyWait(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
5ad820458efd0fdb914baff9c1447c22b819fa23nd * We have to be a bit cautious here so we don't destroy the network or the
5ad820458efd0fdb914baff9c1447c22b819fa23nd * semaphore before intnetR0BusyDec has signalled us.
5ad820458efd0fdb914baff9c1447c22b819fa23nd /* Reset the semaphore and flip the wakeup bit. */
99653d4ee642c6528e88224f12409a5f23060994eschrock AssertMsg(!(cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens } while (!ASMAtomicCmpXchgExU32(pcBusy, cCurBusy | INTNET_BUSY_WAKEUP_MASK, cCurBusy, &cCurBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Wait for the count to reach zero. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rc2 = RTSemEventWait(pNetwork->hEvtBusyIf, 30000); NOREF(rc2);
99653d4ee642c6528e88224f12409a5f23060994eschrock //AssertMsg(RT_SUCCESS(rc2), ("rc=%Rrc *pcBusy=%#x (%#x)\n", rc2, ASMAtomicReadU32(pcBusy), cCurBusy ));
fa9e4066f08beec538e775443c5be79dd423fcabahrens AssertMsg((cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens || !ASMAtomicCmpXchgU32(pcBusy, 0, INTNET_BUSY_WAKEUP_MASK));
99653d4ee642c6528e88224f12409a5f23060994eschrock * Decrements the busy counter and maybe wakes up any threads waiting for it to
99653d4ee642c6528e88224f12409a5f23060994eschrock * reach zero.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pNetwork The network.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pcBusy The busy counter.
99653d4ee642c6528e88224f12409a5f23060994eschrockDECLINLINE(void) intnetR0BusyDec(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
990b4856d0eaada6f8140335733a1b1771ed2746lling * Increments the busy count of the specified interface.
990b4856d0eaada6f8140335733a1b1771ed2746lling * The caller must own the MAC address table spinlock.
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock * @param pIf The interface.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Increments the busy count of the specified interface.
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock * The caller must own the MAC address table spinlock or an explicity reference.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pTrunk The trunk.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(void) intnetR0BusyDecTrunk(PINTNETTRUNKIF pTrunk)
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock * Increments the busy count of the specified interface.
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock * The caller must own the MAC address table spinlock or an explicity reference.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface.
94de1d4cf6ec0a3bf040dcc4b8df107c4ed36b51eschrock AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Increments the busy count of the specified interface.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The caller must own the MAC address table spinlock or an explicity reference.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pTrunk The trunk.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(void) intnetR0BusyIncTrunk(PINTNETTRUNKIF pTrunk)
99653d4ee642c6528e88224f12409a5f23060994eschrock AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Retain an interface.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns VBox status code, can assume success in most situations.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface instance.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pSession The current session.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession)
fa9e4066f08beec538e775443c5be79dd423fcabahrens int rc = SUPR0ObjAddRefEx(pIf->pvObj, pSession, true /* fNoBlocking */);
088e9d477eee66081e407fbc5a33c4da25f66f6aeschrock * Release an interface previously retained by intnetR0IfRetain or
b1b8ab34de515a5e83206da22c3d7e563241b021lling * @returns true if destroyed, false if not.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface instance.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pSession The current session.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(bool) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * RTHandleCreateEx callback that retains an object in the
fa9e4066f08beec538e775443c5be79dd423fcabahrens * handle table before returning it.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * (Avoids racing the freeing of the handle.)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns VBox status code.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param hHandleTable The handle table (ignored).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pvObj The object (INTNETIF).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pvCtx The context (SUPDRVSESSION).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pvUser The user context (ignored).
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic DECLCALLBACK(int) intnetR0IfRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
99653d4ee642c6528e88224f12409a5f23060994eschrock if (pIf->hIf != INTNET_HANDLE_INVALID) /* Don't try retain it if called from intnetR0IfDestruct. */
99653d4ee642c6528e88224f12409a5f23060994eschrock * Checks if the interface has a usable MAC address or not.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @returns true if MacAddr is usable, false if not.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pIf The interface.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0llingDECL_FORCE_INLINE(bool) intnetR0IfHasMacAddr(PINTNETIF pIf)
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * Locates the MAC address table entry for the given interface.
990b4856d0eaada6f8140335733a1b1771ed2746lling * The caller holds the MAC address table spinlock, obviously.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns Pointer to the entry on if found, NULL if not.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pNetwork The network.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0llingDECLINLINE(PINTNETMACTABENTRY) intnetR0NetworkFindMacAddrEntry(PINTNETNETWORK pNetwork, PINTNETIF pIf)
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (iIf-- > 0)
99653d4ee642c6528e88224f12409a5f23060994eschrock * Checks if the IPv4 address is a broadcast address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param Addr The address, network endian.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(bool) intnetR0IPv4AddrIsBroadcast(RTNETADDRIPV4 Addr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Just check for 255.255.255.255 atm. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Checks if the IPv4 address is a good interface address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns true/false.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param Addr The address, network endian.
99653d4ee642c6528e88224f12409a5f23060994eschrockDECLINLINE(bool) intnetR0IPv4AddrIsGood(RTNETADDRIPV4 Addr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Usual suspects. */
99653d4ee642c6528e88224f12409a5f23060994eschrock if ( Addr.u == UINT32_MAX /* 255.255.255.255 - broadcast. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens || Addr.au8[0] == 0) /* Current network, can be used as source address. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return false;
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Unusual suspects. */
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan return false;
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan return true;
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Gets the address size of a network layer type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns size in bytes.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param enmType The type.
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrockDECLINLINE(uint8_t) intnetR0AddrSize(INTNETADDRTYPE enmType)
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * Compares two address to see if they are equal, assuming naturally align structures.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns true if equal, false if not.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pAddr1 The first address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pAddr2 The second address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param cbAddr The address size.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(bool) intnetR0AddrUIsEqualEx(PCRTNETADDRU pAddr1, PCRTNETADDRU pAddr2, uint8_t const cbAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Worker for intnetR0IfAddrCacheLookup that performs the lookup
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * in the remaining cache entries after the caller has check the
99653d4ee642c6528e88224f12409a5f23060994eschrock * most likely ones.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns -1 if not found, the index of the cache entry if found.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pCache The cache.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pAddr The address.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param cbAddr The address size (optimization).
99653d4ee642c6528e88224f12409a5f23060994eschrockstatic int intnetR0IfAddrCacheLookupSlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (i >= 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr))
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Lookup an address in a cache without any expectations.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns -1 if not found, the index of the cache entry if found.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pCache The cache.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pAddr The address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param cbAddr The address size (optimization).
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(int) intnetR0IfAddrCacheLookup(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * The optimized case is when there is one cache entry and
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * it doesn't match.
99653d4ee642c6528e88224f12409a5f23060994eschrock && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr))
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan if (i <= 1)
99653d4ee642c6528e88224f12409a5f23060994eschrock * Check the last entry.
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan if (i <= 1)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan return intnetR0IfAddrCacheLookupSlow(pCache, pAddr, cbAddr);
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan/** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */
990b4856d0eaada6f8140335733a1b1771ed2746llingDECLINLINE(int) intnetR0IfAddrCacheLookupLikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /** @todo implement this. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens return intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Worker for intnetR0IfAddrCacheLookupUnlikely that performs
fa9e4066f08beec538e775443c5be79dd423fcabahrens * the lookup in the remaining cache entries after the caller
fa9e4066f08beec538e775443c5be79dd423fcabahrens * has check the most likely ones.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * The routine is expecting not to find the address.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @returns -1 if not found, the index of the cache entry if found.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pCache The cache.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pAddr The address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param cbAddr The address size (optimization).
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic int intnetR0IfAddrCacheInCacheUnlikelySlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Perform a full table lookup.
fa9e4066f08beec538e775443c5be79dd423fcabahrens uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (i >= 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
8654d0253136055bd4cc2423d87378e8a37f2eb5perrin * Lookup an address in a cache expecting not to find it.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns -1 if not found, the index of the cache entry if found.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pCache The cache.
b1b8ab34de515a5e83206da22c3d7e563241b021lling * @param pAddr The address.
b1b8ab34de515a5e83206da22c3d7e563241b021lling * @param cbAddr The address size (optimization).
8654d0253136055bd4cc2423d87378e8a37f2eb5perrinDECLINLINE(int) intnetR0IfAddrCacheLookupUnlikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * The optimized case is when there is one cache entry and
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * it doesn't match.
fa9e4066f08beec538e775443c5be79dd423fcabahrens && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
99653d4ee642c6528e88224f12409a5f23060994eschrock * Then check the last entry and return if there are just two cache entries.
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr)))
99653d4ee642c6528e88224f12409a5f23060994eschrock if (i <= 1)
fa9e4066f08beec538e775443c5be79dd423fcabahrens return intnetR0IfAddrCacheInCacheUnlikelySlow(pCache, pAddr, cbAddr);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Deletes a specific cache entry.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface (for logging).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pCache The cache.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param iEntry The entry to delete.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pszMsg Log message.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarksstatic void intnetR0IfAddrCacheDeleteIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, int iEntry, const char *pszMsg)
fa9e4066f08beec538e775443c5be79dd423fcabahrens INTNETADDRTYPE enmAddrType = (INTNETADDRTYPE)(uintptr_t)(pCache - &pIf->aAddrCache[0]);
fa9e4066f08beec538e775443c5be79dd423fcabahrens PCRTNETADDRU pAddr = (PCRTNETADDRU)(pCache->pbEntries + iEntry * pCache->cbEntry);
990b4856d0eaada6f8140335733a1b1771ed2746lling Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
990b4856d0eaada6f8140335733a1b1771ed2746lling pIf->hIf, &pIf->MacAddr, iEntry, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
fa9e4066f08beec538e775443c5be79dd423fcabahrens Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",
99653d4ee642c6528e88224f12409a5f23060994eschrock pIf->hIf, &pIf->MacAddr, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));
990b4856d0eaada6f8140335733a1b1771ed2746lling * Deletes an address from the cache, assuming it isn't actually in the cache.
990b4856d0eaada6f8140335733a1b1771ed2746lling * May or may not own the spinlock when calling this.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pIf The interface (for logging).
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pCache The cache.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pAddr The address.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param cbAddr The address size (optimization).
990b4856d0eaada6f8140335733a1b1771ed2746llingDECLINLINE(void) intnetR0IfAddrCacheDelete(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
990b4856d0eaada6f8140335733a1b1771ed2746lling int i = intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
990b4856d0eaada6f8140335733a1b1771ed2746lling if (RT_UNLIKELY(i >= 0))
990b4856d0eaada6f8140335733a1b1771ed2746lling * Deletes the address from all the interface caches.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is used to remove stale entries that has been reassigned to
990b4856d0eaada6f8140335733a1b1771ed2746lling * other machines on the network.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pNetwork The network.
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock * @param pAddr The address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param enmType The address type.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param cbAddr The address size (optimization).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pszMsg Log message.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECLINLINE(void) intnetR0NetworkAddrCacheDelete(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType,
99653d4ee642c6528e88224f12409a5f23060994eschrock PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
ece3d9b3bacef51a5f34d993935eedbb7bb87059lling int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
99653d4ee642c6528e88224f12409a5f23060994eschrock intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Deletes the address from all the interface caches except the specified one.
990b4856d0eaada6f8140335733a1b1771ed2746lling * This is used to remove stale entries that has been reassigned to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * other machines on the network.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * @param pNetwork The network.
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pAddr The address.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * @param enmType The address type.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * @param cbAddr The address size (optimization).
990b4856d0eaada6f8140335733a1b1771ed2746lling * @param pszMsg Log message.
990b4856d0eaada6f8140335733a1b1771ed2746llingDECLINLINE(void) intnetR0NetworkAddrCacheDeleteMinusIf(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCRTNETADDRU pAddr,
990b4856d0eaada6f8140335733a1b1771ed2746lling INTNETADDRTYPE const enmType, uint8_t const cbAddr, const char *pszMsg)
fa9e4066f08beec538e775443c5be79dd423fcabahrens int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
fa9e4066f08beec538e775443c5be79dd423fcabahrens intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Lookup an address on the network, returning the (first) interface having it
fa9e4066f08beec538e775443c5be79dd423fcabahrens * in its address cache.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns Pointer to the interface on success, NULL if not found. The caller
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * must release the interface by calling intnetR0BusyDecIf.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pNetwork The network.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pAddr The address to lookup.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param enmType The address type.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param cbAddr The size of the address.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockDECLINLINE(PINTNETIF) intnetR0NetworkAddrCacheLookupIf(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType, uint8_t const cbAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (i >= 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Adds an address to the cache, the caller is responsible for making sure it's
fa9e4066f08beec538e775443c5be79dd423fcabahrens * not already in the cache.
351420b34707afeafa8d5c3e0c77b7bcffb1edc0lling * The caller must not
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIf The interface (for logging).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pCache The address cache.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pAddr The address.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pszMsg log message.
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, const char *pszMsg)
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* This shouldn't happen*/
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* When the table is full, drop the older entry (FIFO). Do proper ageing? */
fa9e4066f08beec538e775443c5be79dd423fcabahrens Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
99653d4ee642c6528e88224f12409a5f23060994eschrock (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
99653d4ee642c6528e88224f12409a5f23060994eschrock memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
a43d325b828008a3ab54eed57fd7c00b6470172bek * Add the new entry to the end of the array.
a43d325b828008a3ab54eed57fd7c00b6470172bek uint8_t *pbEntry = pCache->pbEntries + pCache->cEntries * pCache->cbEntry;
99653d4ee642c6528e88224f12409a5f23060994eschrock memset(pbEntry + pCache->cbAddress, '\0', pCache->cbEntry - pCache->cbAddress);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock INTNETADDRTYPE enmAddrType = (INTNETADDRTYPE)(uintptr_t)(pCache - &pIf->aAddrCache[0]);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %d.%d.%d.%d %s\n",
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->au8[0], pAddr->au8[1], pAddr->au8[2], pAddr->au8[3], pszMsg));
99653d4ee642c6528e88224f12409a5f23060994eschrock Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n",
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock pIf->hIf, &pIf->MacAddr, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg));
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * A intnetR0IfAddrCacheAdd worker that performs the rest of the lookup.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pIf The interface (for logging).
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pCache The address cache.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pAddr The address.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param cbAddr The size of the address (optimization).
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pszMsg Log message.
99653d4ee642c6528e88224f12409a5f23060994eschrockstatic void intnetR0IfAddrCacheAddSlow(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Check all but the first and last entries, the caller
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * has already checked those.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry;
99653d4ee642c6528e88224f12409a5f23060994eschrock while (i >= 1)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
99653d4ee642c6528e88224f12409a5f23060994eschrock * Not found, add it.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan intnetR0IfAddrCacheAddIt(pIf, pCache, pAddr, pszMsg);
99653d4ee642c6528e88224f12409a5f23060994eschrock * Adds an address to the cache if it's not already there.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * Must not own any spinlocks when calling this function.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param pIf The interface (for logging).
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param pCache The address cache.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param pAddr The address.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param cbAddr The size of the address (optimization).
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param pszMsg Log message.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendanDECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr,
99653d4ee642c6528e88224f12409a5f23060994eschrock * The optimized case is when the address the first or last cache entry.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock && ( intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock && intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))) ))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock intnetR0IfAddrCacheAddSlow(pIf, pCache, pAddr, cbAddr, pszMsg);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Destroys the specified address cache.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pCache The address cache.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockstatic void intnetR0IfAddrCacheDestroy(PINTNETADDRCACHE pCache)
a43d325b828008a3ab54eed57fd7c00b6470172bek * Initialize the address cache for the specified address type.
a43d325b828008a3ab54eed57fd7c00b6470172bek * The cache storage is preallocated and fixed size so that we can handle
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * inserts from problematic contexts.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @returns VINF_SUCCESS or VERR_NO_MEMORY.
a43d325b828008a3ab54eed57fd7c00b6470172bek * @param pCache The cache to initialize.
a43d325b828008a3ab54eed57fd7c00b6470172bek * @param enmAddrType The address type.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param fEnabled Whether the address cache is enabled or not.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendanstatic int intnetR0IfAddrCacheInit(PINTNETADDRCACHE pCache, INTNETADDRTYPE enmAddrType, bool fEnabled)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cEntriesAlloc * pCache->cbEntry);
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * Is it a multicast or broadcast MAC address?
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns true if multicast, false if not.
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * @param pMacAddr The address to inspect.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECL_FORCE_INLINE(bool) intnetR0IsMacAddrMulticast(PCRTMAC pMacAddr)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Is it a dummy MAC address?
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * We use dummy MAC addresses for interfaces which we don't know the MAC
fa9e4066f08beec538e775443c5be79dd423fcabahrens * address of because they haven't sent anything (learning) or explicitly set
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns true if dummy, false if not.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pMacAddr The address to inspect.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendanDECL_FORCE_INLINE(bool) intnetR0IsMacAddrDummy(PCRTMAC pMacAddr)
a43d325b828008a3ab54eed57fd7c00b6470172bek /* The dummy address are broadcast addresses, don't bother check it all. */
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * Compares two MAC addresses.
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * @returns true if equal, false if not.
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * @param pDstAddr1 Address 1.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pDstAddr2 Address 2.
fa9e4066f08beec538e775443c5be79dd423fcabahrensDECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * Switch a unicast frame based on the network layer address (OSI level 3) and
99653d4ee642c6528e88224f12409a5f23060994eschrock * return a destination table.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pNetwork The network to switch on.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pDstMacAddr The destination MAC address.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @param enmL3AddrType The level-3 destination address type.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pL3Addr The level-3 destination address.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param cbL3Addr The size of the level-3 destination address.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param fSrc The frame source (INTNETTRUNKDIR_WIRE).
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pDstTab The destination output table.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendanstatic INTNETSWDECISION intnetR0NetworkSwitchLevel3(PINTNETNETWORK pNetwork, PCRTMAC pDstMacAddr,
a43d325b828008a3ab54eed57fd7c00b6470172bek INTNETADDRTYPE enmL3AddrType, PCRTNETADDRU pL3Addr, uint8_t cbL3Addr,
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * Grab the spinlock first and do the switching.
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock /* Find exactly matching or promiscuous interfaces. */
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock while (iIfMac-- > 0)
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock bool fExact = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr) >= 0;
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock if (fExact || pTab->paEntries[iIfMac].fPromiscuousSeeTrunk)
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock pDstMacAddr = &pIf->MacAddr; /* Avoids duplicates being sent to the host. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Network only promicuous mode ifs should see related trunk traffic. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens while (iIfMac-- > 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock if (intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr) < 0)
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock /* Does it match the host, or is the host promiscuous? */
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstMacAddr);
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
99653d4ee642c6528e88224f12409a5f23060994eschrock if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuousEff))
99653d4ee642c6528e88224f12409a5f23060994eschrock ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
99653d4ee642c6528e88224f12409a5f23060994eschrock : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK);
99653d4ee642c6528e88224f12409a5f23060994eschrock * Pre-switch a unicast MAC address.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
99653d4ee642c6528e88224f12409a5f23060994eschrock * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pNetwork The network to switch on.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param fSrc The frame source.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pSrcAddr The source address of the frame.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pDstAddr The destination address of the frame.
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic INTNETSWDECISION intnetR0NetworkPreSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PCRTMAC pSrcAddr,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Grab the spinlock first and do the switching.
fa9e4066f08beec538e775443c5be79dd423fcabahrens INTNETSWDECISION enmSwDecision = INTNETSWDECISION_BROADCAST;
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Iterate the internal network interfaces and look for matching source and
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan destination addresses. */
0430f8daa551890e0788d3fd28aef3be44cf8730eschrock while (iIfMac-- > 0)
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Unknown interface address? */
fa9e4066f08beec538e775443c5be79dd423fcabahrens if (intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* Promiscuous mode? */
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* Paranoia - this shouldn't happen, right? */
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan && intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pSrcAddr))
a43d325b828008a3ab54eed57fd7c00b6470172bek /* Exact match? */
99653d4ee642c6528e88224f12409a5f23060994eschrock if (intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr))
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan enmSwDecision = pTab->fHostPromiscuousEff && fSrc == INTNETTRUNKDIR_WIRE
99653d4ee642c6528e88224f12409a5f23060994eschrock * Switch a unicast MAC address and return a destination table.
0430f8daa551890e0788d3fd28aef3be44cf8730eschrock * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
0430f8daa551890e0788d3fd28aef3be44cf8730eschrock * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
0430f8daa551890e0788d3fd28aef3be44cf8730eschrock * @param pNetwork The network to switch on.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param fSrc The frame source.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pIfSender The sender interface, NULL if trunk. Used to
99653d4ee642c6528e88224f12409a5f23060994eschrock * prevent sending an echo to the sender.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pDstAddr The destination address of the frame.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pDstTab The destination output table.
0430f8daa551890e0788d3fd28aef3be44cf8730eschrockstatic INTNETSWDECISION intnetR0NetworkSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
99653d4ee642c6528e88224f12409a5f23060994eschrock * Grab the spinlock first and do the switching.
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Find exactly matching or promiscuous interfaces. */
99653d4ee642c6528e88224f12409a5f23060994eschrock while (iIfMac-- > 0)
0430f8daa551890e0788d3fd28aef3be44cf8730eschrock bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr);
99653d4ee642c6528e88224f12409a5f23060994eschrock || intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr)
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks || (!fSrc && pTab->paEntries[iIfMac].fPromiscuousEff) )
fa9e4066f08beec538e775443c5be79dd423fcabahrens PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
8654d0253136055bd4cc2423d87378e8a37f2eb5perrin /* Network only promicuous mode ifs should see related trunk traffic. */
99653d4ee642c6528e88224f12409a5f23060994eschrock while (iIfMac-- > 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens && !intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr)
fa9e4066f08beec538e775443c5be79dd423fcabahrens && !intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr) )
fa9e4066f08beec538e775443c5be79dd423fcabahrens PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Does it match the host, or is the host promiscuous? */
fa9e4066f08beec538e775443c5be79dd423fcabahrens bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
fa9e4066f08beec538e775443c5be79dd423fcabahrens /* Grab the trunk if we're sending to it. */
99653d4ee642c6528e88224f12409a5f23060994eschrock ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
fa9e4066f08beec538e775443c5be79dd423fcabahrens : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK);
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Create a destination table for a broadcast frame.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns INTNETSWDECISION_BROADCAST.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pNetwork The network to switch on.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param fSrc The frame source.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pIfSender The sender interface, NULL if trunk. Used to
fa9e4066f08beec538e775443c5be79dd423fcabahrens * prevent sending an echo to the sender.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pDstTab The destination output table.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendanstatic INTNETSWDECISION intnetR0NetworkSwitchBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Grab the spinlock first and record all active interfaces.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan /* Regular interfaces. */
99653d4ee642c6528e88224f12409a5f23060994eschrock while (iIfMac-- > 0)
fa9e4066f08beec538e775443c5be79dd423fcabahrens PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* The trunk interface. */
99653d4ee642c6528e88224f12409a5f23060994eschrock * Create a destination table with the trunk and any promiscuous interfaces.
99653d4ee642c6528e88224f12409a5f23060994eschrock * This is only used in a fallback case of the level-3 switching, so we can
99653d4ee642c6528e88224f12409a5f23060994eschrock * assume the wire as source and skip the sender interface filtering.
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
99653d4ee642c6528e88224f12409a5f23060994eschrock * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pNetwork The network to switch on.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param fSrc The frame source.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pDstTab The destination output table.
99653d4ee642c6528e88224f12409a5f23060994eschrockstatic INTNETSWDECISION intnetR0NetworkSwitchTrunkAndPromisc(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
99653d4ee642c6528e88224f12409a5f23060994eschrock * Grab the spinlock first and do the switching.
99653d4ee642c6528e88224f12409a5f23060994eschrock /* Find promiscuous interfaces. */
99653d4ee642c6528e88224f12409a5f23060994eschrock while (iIfMac-- > 0)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock || (!fSrc && pTab->paEntries[iIfMac].fPromiscuousEff) )
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock /* The trunk interface. */
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK)
fa94a07fd0519b8abfd871ad8fe60e6bebe1e2bbbrendan : (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Create a destination table for a trunk frame.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @returns INTNETSWDECISION_BROADCAST.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param pNetwork The network to switch on.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param fSrc The frame source.
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * @param pDstTab The destination output table.
99653d4ee642c6528e88224f12409a5f23060994eschrockstatic INTNETSWDECISION intnetR0NetworkSwitchTrunk(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * Grab the spinlock first and record all active interfaces.
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock /* The trunk interface. */
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl return pDstTab->fTrunkDst ? INTNETSWDECISION_TRUNK : INTNETSWDECISION_DROP;
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * Wrapper around RTMemAlloc for allocating a destination table.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @returns VINF_SUCCESS or VERR_NO_MEMORY.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param cEntries The size given as an entry count.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param ppDstTab Where to store the pointer (always).
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahlDECLINLINE(int) intnetR0AllocDstTab(uint32_t cEntries, PINTNETDSTTAB *ppDstTab)
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl *ppDstTab = pDstTab = (PINTNETDSTTAB)RTMemAlloc(RT_OFFSETOF(INTNETDSTTAB, aIfs[cEntries]));
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * Ensures that there is space for another interface in the MAC address lookup
fa9e4066f08beec538e775443c5be79dd423fcabahrens * table as well as all the destination tables.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * The caller must own the create/open/destroy mutex.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_OUT_OF_RANGE.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param pNetwork The network to operate on.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahlstatic int intnetR0NetworkEnsureTabSpace(PINTNETNETWORK pNetwork)
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * The cEntries and cEntriesAllocated members are only updated while
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * owning the big mutex, so we only need the spinlock when doing the
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * actual table replacing.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl AssertReturn(pTab->cEntries <= pTab->cEntriesAllocated, VERR_INTERNAL_ERROR_2);
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl uint32_t const cAllocated = pTab->cEntriesAllocated + INTNET_GROW_DSTTAB_SIZE;
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * Resize the destination tables first, this can be kind of tedious.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * The trunk.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl AssertCompileAdjacentMembers(INTNETTRUNKIF, apTaskDstTabs, apIntDstTabs);
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl PINTNETDSTTAB * const ppEndDstTab = &pTrunk->apIntDstTabs[pTrunk->cIntDstTabs];
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl for (PINTNETDSTTAB *ppDstTab = &pTrunk->apTaskDstTabs[0];
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * The MAC Address table itself.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl PINTNETMACTABENTRY paNew = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * cAllocated);
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl while (i-- > 0)
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * Snoops IP assignments and releases from the DHCPv4 traffic.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * The caller is responsible for making sure this traffic between the
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * BOOTPS and BOOTPC ports and validate the IP header. The UDP packet
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * need not be validated beyond the ports.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param pNetwork The network this frame was seen on.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param pIpHdr Pointer to a valid IP header. This is for pseudo
fa9e4066f08beec538e775443c5be79dd423fcabahrens * header validation, so only the minimum header size
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * needs to be available and valid here.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param pUdpHdr Pointer to the UDP header in the frame.
f3861e1a2ceec23a5b699c24d814b7775a9e0b52ahl * @param cbUdpPkt What's left of the frame when starting at the UDP header.
fa9e4066f08beec538e775443c5be79dd423fcabahrens * @param fGso Set if this is a GSO frame, clear if regular.
fa9e4066f08beec538e775443c5be79dd423fcabahrensstatic void intnetR0NetworkSnoopDhcp(PINTNETNETWORK pNetwork, PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, uint32_t cbUdpPkt)
fa9e4066f08beec538e775443c5be79dd423fcabahrens * Check if the DHCP message is valid and get the type.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock if (!RTNetIPv4IsUDPValid(pIpHdr, pUdpHdr, pUdpHdr + 1, cbUdpPkt, true /*fCheckSum*/))
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock if (!RTNetIPv4IsDHCPValid(pUdpHdr, pDhcp, cbUdpPkt - sizeof(*pUdpHdr), &MsgType))
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock case RTNET_DHCP_MT_DISCOVER: pszType = "discover"; break;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock case RTNET_DHCP_MT_OFFER: pszType = "offer"; break;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock case RTNET_DHCP_MT_REQUEST: pszType = "request"; break;
99653d4ee642c6528e88224f12409a5f23060994eschrock case RTNET_DHCP_MT_DECLINE: pszType = "decline"; break;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock case RTNET_DHCP_MT_RELEASE: pszType = "release"; break;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock case RTNET_DHCP_MT_INFORM: pszType = "inform"; break;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock Log6(("DHCP msg: %d (%s) client %.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d\n", MsgType, pszType, &pDhcp->bp_chaddr,
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock pDhcp->bp_ciaddr.au8[0], pDhcp->bp_ciaddr.au8[1], pDhcp->bp_ciaddr.au8[2], pDhcp->bp_ciaddr.au8[3],
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock pDhcp->bp_yiaddr.au8[0], pDhcp->bp_yiaddr.au8[1], pDhcp->bp_yiaddr.au8[2], pDhcp->bp_yiaddr.au8[3]));
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock#endif /* LOG_EANBLED */
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Act upon the message.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock /** @todo Check for valid non-broadcast requests w/ IP for any of the MACs we
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * know, and add the IP to the cache. */
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Lookup the interface by its MAC address and insert the IPv4 address into the cache.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Delete the old client address first, just in case it changed in a renewal.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock while (iIf-- > 0)
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock intnetR0IfAddrCacheAdd(pMatchingIf, &pMatchingIf->aAddrCache[kIntNetAddrType_IPv4],
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Lookup the interface by its MAC address and remove the IPv4 address(es) from the cache.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock while (iIf-- > 0)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE");
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE");
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * Worker for intnetR0TrunkIfSnoopAddr that takes care of what
3d7072f8bd27709dba14f6fe336f149d25d9e207eschrock * is likely to be a DHCP message.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * The caller has already check that the UDP source and destination ports
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * are BOOTPS or BOOTPC.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * @param pNetwork The network this frame was seen on.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * @param pSG The gather list for the frame.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrockstatic void intnetR0TrunkIfSnoopDhcp(PINTNETNETWORK pNetwork, PCINTNETSG pSG)
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Get a pointer to a linear copy of the full packet, using the
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * temporary buffer if necessary.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock PCRTNETIPV4 pIpHdr = (PCRTNETIPV4)((PCRTNETETHERHDR)pSG->aSegs[0].pv + 1);
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock uint32_t cbPacket = pSG->cbTotal - sizeof(RTNETETHERHDR);
99653d4ee642c6528e88224f12409a5f23060994eschrock cbPacket = RT_MIN(cbPacket, INTNETNETWORK_TMP_SIZE);
99653d4ee642c6528e88224f12409a5f23060994eschrock Log6(("intnetR0TrunkIfSnoopDhcp: Copying IPv4/UDP/DHCP pkt %u\n", cbPacket));
99653d4ee642c6528e88224f12409a5f23060994eschrock if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), cbPacket, pNetwork->pbTmp))
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock //pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
99653d4ee642c6528e88224f12409a5f23060994eschrock * Validate the IP header and find the UDP packet.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, pSG->cbTotal - sizeof(RTNETETHERHDR), true /*fChecksum*/))
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock Log(("intnetR0TrunkIfSnoopDhcp: bad ip header\n"));
99653d4ee642c6528e88224f12409a5f23060994eschrock * Hand it over to the common DHCP snooper.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock intnetR0NetworkSnoopDhcp(pNetwork, pIpHdr, (PCRTNETUDP)((uintptr_t)pIpHdr + cbIpHdr), cbPacket - cbIpHdr);
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock#endif /* INTNET_WITH_DHCP_SNOOPING */
99653d4ee642c6528e88224f12409a5f23060994eschrock * Snoops up source addresses from ARP requests and purge these from the address
99653d4ee642c6528e88224f12409a5f23060994eschrock * The purpose of this purging is to get rid of stale addresses.
5ad820458efd0fdb914baff9c1447c22b819fa23nd * @param pNetwork The network this frame was seen on.
99653d4ee642c6528e88224f12409a5f23060994eschrock * @param pSG The gather list for the frame.
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrockstatic void intnetR0TrunkIfSnoopArp(PINTNETNETWORK pNetwork, PCINTNETSG pSG)
c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07eschrock * Check the minimum size first.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4)))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Copy to temporary buffer if necessary.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock uint32_t cbPacket = RT_MIN(pSG->cbTotal, sizeof(RTNETARPIPV4));
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock PCRTNETARPIPV4 pArpIPv4 = (PCRTNETARPIPV4)((uintptr_t)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
55434c770c89aa1b84474f2559a106803511aba0ek if ( (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4 | INTNETSG_FLAGS_PKT_CP_IN_TMP))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock != (INTNETSG_FLAGS_ARP_IPV4 | INTNETSG_FLAGS_PKT_CP_IN_TMP)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock && !intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), cbPacket, pNetwork->pbTmp))
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * Ignore packets which doesn't interest us or we perceive as malformed.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (RT_UNLIKELY( pArpIPv4->Hdr.ar_hlen != sizeof(RTMAC)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock * Delete the source address if it's OK.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock Log6(("ts-ar: %d.%d.%d.%d / %.6Rhxs\n", pArpIPv4->ar_spa.au8[0], pArpIPv4->ar_spa.au8[1],
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock pArpIPv4->ar_spa.au8[2], pArpIPv4->ar_spa.au8[3], &pArpIPv4->ar_sha));
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock intnetR0NetworkAddrCacheDelete(pNetwork, (PCRTNETADDRU)&pArpIPv4->ar_spa,
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock kIntNetAddrType_IPv4, sizeof(pArpIPv4->ar_spa), "tif/arp");
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock * Snoop up addresses from ARP and DHCP traffic from frames coming
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * over the trunk connection.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * The caller is responsible for do some basic filtering before calling
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock * this function.
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock * For IPv4 this means checking against the minimum DHCPv4 frame size.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pNetwork The network.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param pSG The SG list for the frame.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock * @param EtherType The Ethertype of the frame.
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrockstatic void intnetR0TrunkIfSnoopAddr(PINTNETNETWORK pNetwork, PCINTNETSG pSG, uint16_t EtherType)
c0a81264b59ba24de8701436570c3aae5689dc89ek Assert(pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN);
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock if (pSG->aSegs[0].cb >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN)
55434c770c89aa1b84474f2559a106803511aba0ek /* check if the protocol is UDP */
55434c770c89aa1b84474f2559a106803511aba0ek PCRTNETIPV4 pIpHdr = (PCRTNETIPV4)((uint8_t const *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
99653d4ee642c6528e88224f12409a5f23060994eschrock /* get the TCP header length */
55434c770c89aa1b84474f2559a106803511aba0ek /* check if the protocol is UDP */
55434c770c89aa1b84474f2559a106803511aba0ek if ( intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPV4, ip_p))
55434c770c89aa1b84474f2559a106803511aba0ek /* get the TCP header length */
55434c770c89aa1b84474f2559a106803511aba0ek b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + 0); /* (IPv4 first byte, a bitfield) */
99653d4ee642c6528e88224f12409a5f23060994eschrock /* compare the ports. */
e9dbad6f263d5570ed7ff5443ec5b958af8c24d7eschrock if (pSG->aSegs[0].cb >= sizeof(RTNETETHERHDR) + cbIpHdr + RTNETUDP_MIN_LEN)
ea8dc4b6d2251b437950c0056bc626b311c73c27eschrock PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t const *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR) + cbIpHdr);
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock if ( ( RT_BE2H_U16(pUdpHdr->uh_sport) != RTNETIPV4_PORT_BOOTPS
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock && RT_BE2H_U16(pUdpHdr->uh_dport) != RTNETIPV4_PORT_BOOTPS)
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock || ( RT_BE2H_U16(pUdpHdr->uh_dport) != RTNETIPV4_PORT_BOOTPC
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock && RT_BE2H_U16(pUdpHdr->uh_sport) != RTNETIPV4_PORT_BOOTPC))
99653d4ee642c6528e88224f12409a5f23060994eschrock /* get the lower byte of the UDP source port number. */
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_OFFSETOF(RTNETUDP, uh_sport) + 1);
ece3d9b3bacef51a5f34d993935eedbb7bb87059lling b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_OFFSETOF(RTNETUDP, uh_sport));
eaca9bbd5f5d1e4e554da4c7108e8a03c8c33481eschrock /* get the lower byte of the UDP destination port number. */
06eeb2ad640ce72d394ac521094bed7681044408ek b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_OFFSETOF(RTNETUDP, uh_dport) + 1);
06eeb2ad640ce72d394ac521094bed7681044408ek b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_OFFSETOF(RTNETUDP, uh_dport));
2a6b87f07ac0c0b819179c84afe5a60afa04cfa5ek /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might
2a6b87f07ac0c0b819179c84afe5a60afa04cfa5ek * need to be edited. Check out how NDP works... */
2a6b87f07ac0c0b819179c84afe5a60afa04cfa5ek#endif /* INTNET_WITH_DHCP_SNOOPING */
ecd6cf800b63704be73fb264c3f5b6e0dafc068dmarks * Deals with an IPv4 packet.
2a6b87f07ac0c0b819179c84afe5a60afa04cfa5ek * This will fish out the source IP address and add it to the cache.
2a6b87f07ac0c0b819179c84afe5a60afa04cfa5ek * Then it will look for DHCPRELEASE requests (?) and anything else
06eeb2ad640ce72d394ac521094bed7681044408ek * that we might find useful later.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pIf The interface that's sending the frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pIpHdr Pointer to the IPv4 header in the frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param cbPacket The size of the packet, or more correctly the
06eeb2ad640ce72d394ac521094bed7681044408ek * size of the frame without the ethernet header.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param fGso Set if this is a GSO frame, clear if regular.
06eeb2ad640ce72d394ac521094bed7681044408ekstatic void intnetR0IfSnoopIPv4SourceAddr(PINTNETIF pIf, PCRTNETIPV4 pIpHdr, uint32_t cbPacket, bool fGso)
06eeb2ad640ce72d394ac521094bed7681044408ek * Check the header size first to prevent access invalid data.
06eeb2ad640ce72d394ac521094bed7681044408ek * If the source address is good (not broadcast or my network) and
06eeb2ad640ce72d394ac521094bed7681044408ek * not already in the address cache of the sender, add it. Validate
06eeb2ad640ce72d394ac521094bed7681044408ek * the IP header before adding it.
06eeb2ad640ce72d394ac521094bed7681044408ek bool fValidatedIpHdr = false;
ece3d9b3bacef51a5f34d993935eedbb7bb87059lling && intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(Addr.IPv4)) < 0)
06eeb2ad640ce72d394ac521094bed7681044408ek if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, cbPacket, !fGso /*fChecksum*/))
ece3d9b3bacef51a5f34d993935eedbb7bb87059lling Log(("intnetR0IfSnoopIPv4SourceAddr: bad ip header\n"));
d7306b64c847d897abb9ece8624fca9cf28d358fek intnetR0IfAddrCacheAddIt(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, "if/ipv4");
06eeb2ad640ce72d394ac521094bed7681044408ek * Check for potential DHCP packets.
06eeb2ad640ce72d394ac521094bed7681044408ek if ( pIpHdr->ip_p == RTNETIPV4_PROT_UDP /* DHCP is UDP. */
06eeb2ad640ce72d394ac521094bed7681044408ek && cbPacket >= cbHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN /* Min DHCP packet len. */
06eeb2ad640ce72d394ac521094bed7681044408ek PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t const *)pIpHdr + cbHdr);
06eeb2ad640ce72d394ac521094bed7681044408ek if ( ( RT_BE2H_U16(pUdpHdr->uh_dport) == RTNETIPV4_PORT_BOOTPS
06eeb2ad640ce72d394ac521094bed7681044408ek || RT_BE2H_U16(pUdpHdr->uh_sport) == RTNETIPV4_PORT_BOOTPS)
06eeb2ad640ce72d394ac521094bed7681044408ek && ( RT_BE2H_U16(pUdpHdr->uh_sport) == RTNETIPV4_PORT_BOOTPC
06eeb2ad640ce72d394ac521094bed7681044408ek || RT_BE2H_U16(pUdpHdr->uh_dport) == RTNETIPV4_PORT_BOOTPC))
06eeb2ad640ce72d394ac521094bed7681044408ek || RTNetIPv4IsHdrValid(pIpHdr, cbPacket, cbPacket, !fGso /*fChecksum*/))
06eeb2ad640ce72d394ac521094bed7681044408ek intnetR0NetworkSnoopDhcp(pIf->pNetwork, pIpHdr, pUdpHdr, cbPacket - cbHdr);
06eeb2ad640ce72d394ac521094bed7681044408ek Log(("intnetR0IfSnoopIPv4SourceAddr: bad ip header (dhcp)\n"));
06eeb2ad640ce72d394ac521094bed7681044408ek#endif /* INTNET_WITH_DHCP_SNOOPING */
06eeb2ad640ce72d394ac521094bed7681044408ek * Snoop up source addresses from an ARP request or reply.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pIf The interface that's sending the frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pHdr The ARP header.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param cbPacket The size of the packet (might be larger than the ARP
06eeb2ad640ce72d394ac521094bed7681044408ek * request 'cause of min ethernet frame size).
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we
06eeb2ad640ce72d394ac521094bed7681044408ek * don't have to repeat the frame parsing in intnetR0TrunkIfSend.
06eeb2ad640ce72d394ac521094bed7681044408ekstatic void intnetR0IfSnoopArpAddr(PINTNETIF pIf, PCRTNETARPIPV4 pArpIPv4, uint32_t cbPacket, uint16_t *pfSgFlags)
06eeb2ad640ce72d394ac521094bed7681044408ek * Ignore packets which doesn't interest us or we perceive as malformed.
06eeb2ad640ce72d394ac521094bed7681044408ek || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
06eeb2ad640ce72d394ac521094bed7681044408ek || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
06eeb2ad640ce72d394ac521094bed7681044408ek * Tag the SG as ARP IPv4 for later editing, then check for addresses
06eeb2ad640ce72d394ac521094bed7681044408ek * which can be removed or added to the address cache of the sender.
06eeb2ad640ce72d394ac521094bed7681044408ek intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4],
06eeb2ad640ce72d394ac521094bed7681044408ek (PCRTNETADDRU)&pArpIPv4->ar_tpa, sizeof(RTNETADDRIPV4), "if/arp");
06eeb2ad640ce72d394ac521094bed7681044408ek if ( !memcmp(&pArpIPv4->ar_sha, &pIf->MacAddr, sizeof(RTMAC))
06eeb2ad640ce72d394ac521094bed7681044408ek intnetR0IfAddrCacheAdd(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4],
06eeb2ad640ce72d394ac521094bed7681044408ek (PCRTNETADDRU)&pArpIPv4->ar_spa, sizeof(RTNETADDRIPV4), "if/arp");
06eeb2ad640ce72d394ac521094bed7681044408ek * Checks packets send by a normal interface for new network
06eeb2ad640ce72d394ac521094bed7681044408ek * layer addresses.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pIf The interface that's sending the frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pbFrame The frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param cbFrame The size of the frame.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param fGso Set if this is a GSO frame, clear if regular.
06eeb2ad640ce72d394ac521094bed7681044408ek * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we
06eeb2ad640ce72d394ac521094bed7681044408ek * don't have to repeat the frame parsing in intnetR0TrunkIfSend.
06eeb2ad640ce72d394ac521094bed7681044408ekstatic void intnetR0IfSnoopAddr(PINTNETIF pIf, uint8_t const *pbFrame, uint32_t cbFrame, bool fGso, uint16_t *pfSgFlags)
06eeb2ad640ce72d394ac521094bed7681044408ek * Fish out the ethertype and look for stuff we can handle.
55434c770c89aa1b84474f2559a106803511aba0ek uint16_t EtherType = RT_H2BE_U16(((PCRTNETETHERHDR)pbFrame)->EtherType);
55434c770c89aa1b84474f2559a106803511aba0ek intnetR0IfSnoopIPv4SourceAddr(pIf, (PCRTNETIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso);
55434c770c89aa1b84474f2559a106803511aba0ek#if 0 /** @todo IntNet: implement IPv6 for wireless MAC sharing. */
55434c770c89aa1b84474f2559a106803511aba0ek /** @todo IPv6: Check for ICMPv6. It looks like type 133 (Router solicitation) might
55434c770c89aa1b84474f2559a106803511aba0ek * need to be edited. Check out how NDP works... */
55434c770c89aa1b84474f2559a106803511aba0ek intnetR0IfSnoopIPv6SourceAddr(pIf, (PCINTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso, pfSgFlags);
55434c770c89aa1b84474f2559a106803511aba0ek#if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
55434c770c89aa1b84474f2559a106803511aba0ek intnetR0IfSnoopIpxSourceAddr(pIf, (PCINTNETIPX)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, pfSgFlags);
55434c770c89aa1b84474f2559a106803511aba0ek intnetR0IfSnoopArpAddr(pIf, (PCRTNETARPIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, pfSgFlags);
55434c770c89aa1b84474f2559a106803511aba0ek * Writes a frame packet to the ring buffer.
55434c770c89aa1b84474f2559a106803511aba0ek * @returns VBox status code.
55434c770c89aa1b84474f2559a106803511aba0ek * @param pBuf The buffer.
55434c770c89aa1b84474f2559a106803511aba0ek * @param pRingBuf The ring buffer to read from.
55434c770c89aa1b84474f2559a106803511aba0ek * @param pSG The gather list.
55434c770c89aa1b84474f2559a106803511aba0ek * @param pNewDstMac Set the destination MAC address to the address if specified.
55434c770c89aa1b84474f2559a106803511aba0ekstatic int intnetR0RingWriteFrame(PINTNETRINGBUF pRingBuf, PCINTNETSG pSG, PCRTMAC pNewDstMac)
55434c770c89aa1b84474f2559a106803511aba0ek rc = IntNetRingAllocateFrame(pRingBuf, pSG->cbTotal, &pHdr, &pvDst);
55434c770c89aa1b84474f2559a106803511aba0ek rc = IntNetRingAllocateGsoFrame(pRingBuf, pSG->cbTotal, &pSG->GsoCtx, &pHdr, &pvDst);
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * Sends a frame to a specific interface.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * @param pIf The interface.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * @param pSG The gather buffer which data is being sent to the interface.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * @param pNewDstMac Set the destination MAC address to the address if specified.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgwstatic void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG, PCRTMAC pNewDstMac)
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * Grab the receive/producer lock and copy over the frame.
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw int rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf));
15e6edf145a9c2bb0e0272cf8debe823bb97529bgw * Scheduling hack, for unicore machines primarily.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor while (--cYields > 0)
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor /* ok, the frame is lost. */
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Fallback path that does the GSO segmenting before passing the frame on to the
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * trunk interface.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * The caller holds the trunk lock.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pThis The trunk.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pIfSender The IF sending the frame.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pSG Pointer to the gather list.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param fDst The destination flags.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylorstatic int intnetR0TrunkIfSendGsoFallback(PINTNETTRUNKIF pThis, PINTNETIF pIfSender, PINTNETSG pSG, uint32_t fDst)
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Since we're only using this for GSO frame coming from the internal
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * network interfaces and never the trunk, we can assume there is only
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * one segment. This simplifies the code quite a bit.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor Assert(PDMNetGsoIsValid(&pSG->GsoCtx, sizeof(pSG->GsoCtx), pSG->cbTotal));
c6ef114f2f708797a9cba68e8c08f42a03f094bbmmusante AssertReturn(pSG->cSegsUsed == 1, VERR_INTERNAL_ERROR_4);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Carve out the frame segments with the header and frame in different
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * scatter / gather segments.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor uint32_t const cSegs = PDMNetGsoCalcSegmentCount(&pSG->GsoCtx, pSG->cbTotal);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor uint32_t offSegPayload = PDMNetGsoCarveSegment(&pSG->GsoCtx, (uint8_t *)pSG->aSegs[0].pv, pSG->cbTotal, iSeg, cSegs,
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor IntNetSgInitTempSegs(&u.SG, cbSegHdrs + cbSegPayload, 2, 2);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor u.SG.aSegs[1].pv = (uint8_t *)pSG->aSegs[0].pv + offSegPayload;
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor int rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, &u.SG, fDst);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Checks if any of the given trunk destinations can handle this kind of GSO SG.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @returns true if it can, false if it cannot.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pThis The trunk.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pSG The scatter / gather buffer.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param fDst The destination mask.
c6ef114f2f708797a9cba68e8c08f42a03f094bbmmusanteDECLINLINE(bool) intnetR0TrunkIfCanHandleGsoFrame(PINTNETTRUNKIF pThis, PINTNETSG pSG, uint32_t fDst)
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor Assert(fDst == (INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST));
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor return !!(pThis->fHostGsoCapabilites & pThis->fWireGsoCapabilites & fMask);
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Sends a frame down the trunk.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pThis The trunk.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pNetwork The network the frame is being sent to.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pIfSender The IF sending the frame. Used for MAC address
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * checks in shared MAC mode.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param fDst The destination flags.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * @param pSG Pointer to the gather list.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylorstatic void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, PINTNETIF pIfSender,
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Quick sanity check.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * Edit the frame if we're sharing the MAC address with the host on the wire.
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * If the frame is headed for both the host and the wire, we'll have to send
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * it to the host before making any modifications, and force the OS specific
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * backend to copy it. We do this by marking it as TEMP (which is always the
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor * case right now).
8488aeb5df27784d479c16cde06a9e25cd9a1152taylor if ( (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Dispatch it to the host before making changes.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw Assert(pSG->fFlags & INTNETSG_FLAGS_TEMP); /* make sure copy is forced */
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Edit the source address so that it it's the same as the host.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw /* ASSUME frame from IntNetR0IfSend! */
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv;
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Deal with tags from the snooping phase.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * APR IPv4: replace hardware (MAC) addresses because these end up
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * in ARP caches. So, if we don't the other machines will
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * send the packets to the MAC address of the guest
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * instead of the one of the host, which won't work on
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * wireless of course...
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw if (!memcmp(&pArp->ar_sha, &pIfSender->MacAddr, sizeof(RTMAC)))
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis->MacAddr));
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw if (!memcmp(&pArp->ar_tha, &pIfSender->MacAddr, sizeof(RTMAC))) /* just in case... */
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis->MacAddr));
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw //else if (pSG->fFlags & INTNETSG_FLAGS_ICMPV6_NDP)
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw //{ /// @todo move the editing into a different function
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Send the frame, handling the GSO fallback .
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Note! The trunk implementation will re-check that the trunk is active .
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * before sending, so we don't have to duplicate that effort here.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw STAM_REL_PROFILE_START(&pIfSender->pIntBuf->StatSend2, a);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, pSG, fDst);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw rc = intnetR0TrunkIfSendGsoFallback(pThis, pIfSender, pSG, fDst);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw STAM_REL_PROFILE_STOP(&pIfSender->pIntBuf->StatSend2, a);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw /** @todo failure statistics? */
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); NOREF(rc);
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Edits an ARP packet arriving from the wire via the trunk connection.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * @param pNetwork The network the frame is being sent to.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * @param pSG Pointer to the gather list for the frame.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * The flags and data content may be updated.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * @param pEthHdr Pointer to the ethernet header. This may also be
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * updated if it's a unicast...
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gwstatic void intnetR0NetworkEditArpFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Check the minimum size and get a linear copy of the thing to work on,
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * using the temporary buffer if necessary.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4)))
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw PRTNETARPIPV4 pArpIPv4 = (PRTNETARPIPV4)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw && pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4))
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw Log6(("fw: Copying ARP pkt %u\n", sizeof(RTNETARPIPV4)));
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETARPIPV4), pNetwork->pbTmp))
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw * Ignore packets which doesn't interest us or we perceive as malformed.
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
e7cbe64f7a72dae5cb44f100db60ca88f3313c65gw || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
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))
if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, pSG->cbTotal - sizeof(RTNETETHERHDR), true /*fCheckSum*/))
switch (bMsgType)
case RTNET_DHCP_MT_DISCOVER:
case RTNET_DHCP_MT_REQUEST:
intnetR0SgWritePart(pSG, (uintptr_t)&pDhcp->bp_flags - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR), sizeof(uFlags), &uFlags);
intnetR0SgWritePart(pSG, (uintptr_t)&pUdpHdr->uh_sum - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR), sizeof(pUdpHdr->uh_sum), &uChecksum);
#ifdef RT_OS_DARWIN
DECLINLINE(bool) intnetR0NetworkIsContextOk(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCINTNETDSTTAB pDstTab)
if (!pIfSender)
if (!fTrunkDst)
if (fSrc)
return fRc;
return INTNETSWDECISION_BAD_CONTEXT;
if ( !fSrc
if (fSrc)
#ifdef INTNET_WITH_DHCP_SNOOPING
&& pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchUnicast(PINTNETNETWORK pNetwork, PINTNETSG pSG,
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 intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, INTNETTRUNKDIR_WIRE, NULL, pSG, pEthHdr, pDstTab);
#ifdef INTNET_WITH_DHCP_SNOOPING
&& pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
return enmSwDecision;
while (iIf-- > 0)
static void intnetR0NetworkDeliver(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab, PINTNETSG pSG, PINTNETIF pIfSender)
while (iIf-- > 0)
if (pIfSender)
static INTNETSWDECISION intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc,
return INTNETSWDECISION_INVALID;
return INTNETSWDECISION_INVALID;
if (pIfEntry)
enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
return enmSwDecision;
if (!pIf)
return VERR_INVALID_HANDLE;
intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&Sg.fFlags);
return rc;
return VERR_INVALID_PARAMETER;
LogFlow(("IntNetR0IfGetBufferPtrs: hIf=%RX32 ppRing3Buf=%p ppRing0Buf=%p\n", hIf, ppRing3Buf, ppRing0Buf));
if (ppRing3Buf)
*ppRing3Buf = 0;
if (ppRing0Buf)
*ppRing0Buf = 0;
if (!pIf)
return VERR_INVALID_HANDLE;
if (ppRing3Buf)
if (ppRing0Buf)
return rc;
INTNETR0DECL(int) IntNetR0IfGetBufferPtrsReq(PSUPDRVSESSION pSession, PINTNETIFGETBUFFERPTRSREQ pReq)
return VERR_INVALID_PARAMETER;
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(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous)
if (!pIf)
return VERR_INVALID_HANDLE;
if (pNetwork)
return rc;
INTNETR0DECL(int) IntNetR0IfSetPromiscuousModeReq(PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) IntNetR0IfSetMacAddress(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac)
if (!pIf)
return VERR_INVALID_HANDLE;
if (pNetwork)
if (pTrunk)
if (pTrunk)
if (pIfPort)
return rc;
INTNETR0DECL(int) IntNetR0IfSetMacAddressReq(PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq)
return VERR_INVALID_PARAMETER;
if (fActive)
if (pTrunk)
if (!fActive)
pTrunk->pIfPort->pfnSetState(pTrunk->pIfPort, fActive ? INTNETTRUNKIFSTATE_ACTIVE : INTNETTRUNKIFSTATE_INACTIVE);
return VINF_SUCCESS;
if (!pIf)
return VERR_INVALID_HANDLE;
if (pNetwork)
return rc;
return VERR_INVALID_PARAMETER;
if (!pIf)
return VERR_INVALID_HANDLE;
|| fDestroying
return VERR_SEM_DESTROYED;
return rc;
return VERR_INVALID_PARAMETER;
INTNETR0DECL(int) IntNetR0IfAbortWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fNoMoreWaits)
if (!pIf)
return VERR_INVALID_HANDLE;
|| fDestroying
return VERR_SEM_DESTROYED;
if (fNoMoreWaits)
while (cSleepers-- > 0)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
if (!pIf)
return VERR_INVALID_HANDLE;
return rc;
return VERR_INVALID_PARAMETER;
if (pNetwork)
while (iIf-- > 0)
while (iIf-- > 0)
LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u fFlags=%#x phIf=%p\n",
return rc;
if (!pIf)
return VERR_NO_MEMORY;
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... */
if (pTrunk)
if (pTrunk)
return VINF_SUCCESS;
return rc;
return rc;
static DECLCALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
static DECLCALLBACK(void) intnetR0TrunkIfPortReportMacAddress(PINTNETTRUNKSWPORT pSwitchPort, PCRTMAC pMacAddr)
if (pNetwork)
static DECLCALLBACK(void) intnetR0TrunkIfPortReportPromiscuousMode(PINTNETTRUNKSWPORT pSwitchPort, bool fPromiscuous)
if (pNetwork)
static DECLCALLBACK(void) intnetR0TrunkIfPortReportNoPreemptDsts(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fNoPreemptDsts)
fSrc,
return enmSwDecision;
static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, void *pvIf, PINTNETSG pSG, uint32_t fSrc)
unsigned iDstTab = 0;
if (fIntCtx)
while (iDstTab-- > 0)
if (pDstTab)
if (!pDstTab)
if (pDstTab)
AssertMsg(enmSwDecision != INTNETSWDECISION_BAD_CONTEXT, ("fSrc=%#x fTrunkDst=%#x hdr=%.14Rhxs\n", fSrc, pDstTab->fTrunkDst, pSG->aSegs[0].pv));
while (iDstTab-- > 0)
return fRc;
static DECLCALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
static DECLCALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
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:
PINTNETTRUNKIF pTrunk = (PINTNETTRUNKIF)RTMemAllocZ(RT_OFFSETOF(INTNETTRUNKIF, apIntDstTabs[cCpus]));
if (!pTrunk)
return VERR_NO_MEMORY;
rc = RTSpinlockCreate(&pTrunk->hDstTabSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "hDstTabSpinlock");
pNetwork->MacTab.fHostPromiscuousEff = (pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE)
pNetwork->MacTab.fWirePromiscuousReal = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE);
rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName));
return VINF_SUCCESS;
return rc;
Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
if (pTrunk)
while (iIf-- > 0)
if (pTrunk)
while (iIf-- > 0)
if (pTrunk)
return VERR_INTNET_INCOMPATIBLE_FLAGS;
return VERR_INTNET_INCOMPATIBLE_FLAGS;
return VERR_INTNET_INCOMPATIBLE_FLAGS;
return VINF_SUCCESS;
LogRel(("INTNET: %s - min flags changed %#x -> %#x\n", pNetwork->szName, pNetwork->fMinFlags, fNetMinFlags));
pNetwork->MacTab.fWirePromiscuousReal= RT_BOOL(fNetFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE);
while (iIf-- > 0)
return VINF_SUCCESS;
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;
LogRel(("intnetR0OpenNetwork failed. rc=%Rrc pCur->szTrunk=%s pszTrunk=%s pCur->enmTrunkType=%d enmTrunkType=%d\n",
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 (!pNetwork)
return VERR_NO_MEMORY;
//pNetwork->MacTab.cPromiscuousEntries = 0;
//pNetwork->MacTab.cPromiscuousNoTrunkEntries = 0;
pNetwork->MacTab.paEntries = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * pNetwork->MacTab.cEntriesAllocated);
pNetwork->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNetwork, pIntNet);
return VINF_SUCCESS;
return rc;
return rc;
LogFlow(("IntNetR0Open: pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
if (pszTrunk)
switch (enmTrunkType)
case kIntNetTrunkType_None:
if (*pszTrunk)
return VERR_INVALID_PARAMETER;
case kIntNetTrunkType_NetFlt:
case kIntNetTrunkType_NetAdp:
if (!*pszTrunk)
return VERR_INVALID_PARAMETER;
return VERR_NOT_IMPLEMENTED;
AssertMsgReturn((fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair) != g_afIntNetOpenNetworkNetFlags[i].fPair,
AssertMsgReturn((fFlags & g_afIntNetOpenNetworkIfFlags[i].fPair) != g_afIntNetOpenNetworkIfFlags[i].fPair,
return rc;
rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
return rc;
return VERR_INVALID_PARAMETER;
if (!pIntNet)
cNetworks++;
return cNetworks;
if (!pIntNet)
if (pIntNet)
rc = RTHandleTableCreateEx(&pIntNet->hHtIfs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
return VINF_SUCCESS;
return rc;