VBoxNetFlt.c revision 600ca2b7e602079abfd45de5979a4c9352c54e2e
c74832c7184337c330041742d88e6dacaa07b378vboxsync/* $Id$ */
c74832c7184337c330041742d88e6dacaa07b378vboxsync/** @file
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * VBoxNetFlt - Network Filter Driver (Host), Common Code.
d192cc72774b02a0df2fdd46350d418236ac09aevboxsync */
d192cc72774b02a0df2fdd46350d418236ac09aevboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Copyright (C) 2008-2009 Oracle Corporation
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * available from http://www.virtualbox.org. This file is free software;
c74832c7184337c330041742d88e6dacaa07b378vboxsync * you can redistribute it and/or modify it under the terms of the GNU
c74832c7184337c330041742d88e6dacaa07b378vboxsync * General Public License (GPL) as published by the Free Software
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync */
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync/** @page pg_netflt VBoxNetFlt - Network Interface Filter
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * This is a kernel module that attaches to a real interface on the host and
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * filters and injects packets.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * In the big picture we're one of the three trunk interface on the internal
c74832c7184337c330041742d88e6dacaa07b378vboxsync * network, the one named "NIC Filter Driver": @image html Networking_Overview.gif
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @section sec_netflt_locking Locking and Potential Races
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsync * The main challenge here is to make sure the netfilter and internal network
c74832c7184337c330041742d88e6dacaa07b378vboxsync * instances won't be destroyed while someone is calling into them.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The main calls into or out of of the filter driver are:
c74832c7184337c330041742d88e6dacaa07b378vboxsync * - Send.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * - Async send completion (not implemented yet)
c74832c7184337c330041742d88e6dacaa07b378vboxsync * - Release by the internal network.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * - Receive.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * - Disappearance of the host networking interface.
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * - Reappearance of the host networking interface.
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * The latter two calls are can be caused by driver unloading/loading or the
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * device being physical unplugged (e.g. a USB network device). Actually, the
c74832c7184337c330041742d88e6dacaa07b378vboxsync * unload scenario must fervently be prevent as it will cause panics because the
c74832c7184337c330041742d88e6dacaa07b378vboxsync * internal network will assume the trunk is around until it releases it.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @todo Need to figure which host allow unloading and block/fix it.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Currently the netfilter instance lives until the internal network releases
c74832c7184337c330041742d88e6dacaa07b378vboxsync * it. So, it is the internal networks responsibility to make sure there are no
c74832c7184337c330041742d88e6dacaa07b378vboxsync * active calls when it releases the trunk and destroys the network. The
c74832c7184337c330041742d88e6dacaa07b378vboxsync * netfilter assists in this by providing INTNETTRUNKIFPORT::pfnSetState and
c74832c7184337c330041742d88e6dacaa07b378vboxsync * INTNETTRUNKIFPORT::pfnWaitForIdle. The trunk state is used to enable/disable
c74832c7184337c330041742d88e6dacaa07b378vboxsync * promiscuous mode on the hardware NIC (or similar activation) as well
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * indicating that disconnect is imminent and no further calls shall be made
c74832c7184337c330041742d88e6dacaa07b378vboxsync * into the internal network. After changing the state to disconnecting and
c74832c7184337c330041742d88e6dacaa07b378vboxsync * prior to invoking INTNETTRUNKIFPORT::pfnDisconnectAndRelease, the internal
c74832c7184337c330041742d88e6dacaa07b378vboxsync * network will use INTNETTRUNKIFPORT::pfnWaitForIdle to wait for any still
c74832c7184337c330041742d88e6dacaa07b378vboxsync * active calls to complete.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The netfilter employs a busy counter and an internal state in addition to the
c74832c7184337c330041742d88e6dacaa07b378vboxsync * public trunk state. All these variables are protected using a spinlock.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @section sec_netflt_msc Locking / Sequence Diagrams - OBSOLETE
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * !OBSOLETE! - THIS WAS THE OLD APPROACH!
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * This secion contains a few sequence diagrams describing the problematic
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * transitions of a host interface filter instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * The thing that makes it all a bit problematic is that multiple events may
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * happen at the same time, and that we have to be very careful to avoid
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * deadlocks caused by mixing our locks with the ones in the host kernel. The
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * main events are receive, send, async send completion, disappearance of the
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * host networking interface and its reappearance. The latter two events are
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * can be caused by driver unloading/loading or the device being physical
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * unplugged (e.g. a USB network device).
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * The strategy for dealing with these issues are:
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * - Use a simple state machine.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * - Require the user (IntNet) to serialize all its calls to us,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * while at the same time not owning any lock used by any of the
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * the callbacks we might call on receive and async send completion.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * - Make sure we're 100% idle before disconnecting, and have a
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * disconnected status on both sides to fend off async calls.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * - Protect the host specific interface handle and the state variables
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * using a spinlock.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @subsection subsec_netflt_msc_dis_rel Disconnect from the network and release - OBSOLETE
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @msc
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * VM, IntNet, NetFlt, Kernel, Wire;
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="pkt0 to wire", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Kernel->Wire [label="pkt0 to wire", linecolor="green", textcolor="green"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * --- [label="Suspending the trunk interface"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * IntNet=>IntNet [label="Lock Network"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Wire->Kernel [label="pkt1 - racing us", linecolor="red", textcolor="red"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Kernel=>>NetFlt [label="pkt1 - racing us", linecolor="red", textcolor="red"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * NetFlt=>>IntNet [label="pkt1 recv - blocks", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * IntNet=>IntNet [label="Mark Trunk Suspended"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>NetFlt [label="pfnSetActive(false)"];
0c34933fc8f84dd5183d1897881bbc7683d24541vboxsync * NetFlt=>NetFlt [label="Mark inactive (atomic)"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<<NetFlt;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>NetFlt [label="pfnWaitForIdle(forever)"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * IntNet=>>NetFlt [label="pkt1 to host", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>>Kernel [label="pkt1 to host", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Kernel<-Wire [label="pkt0 on wire", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<Kernel [label="pkt0 on wire", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet<<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet<<=IntNet [label="Lock Net, free SG, Unlock Net", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt<-NetFlt [label="idle", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet<<NetFlt [label="idle (pfnWaitForIdle)"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Wire->Kernel [label="pkt2", linecolor="red", textcolor="red"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Kernel=>>NetFlt [label="pkt2", linecolor="red", textcolor="red"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>>Kernel [label="pkt2 to host", linecolor="red", textcolor="red"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VM->IntNet [label="pkt3", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Route packet -> drop", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * --- [label="The trunk interface is idle now, disconnect it"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * IntNet=>IntNet [label="Lock Network"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlink Trunk"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>NetFlt [label="pfnDisconnectAndRelease"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="iflt_detach"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<=Kernel [label="iff_detached"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt>>Kernel [label="iff_detached"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<Kernel [label="iflt_detach"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Release"];
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * IntNet<<NetFlt [label="pfnDisconnectAndRelease"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * @endmsc
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync *
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * @subsection subsec_netflt_msc_hif_rm Host Interface Removal - OBSOLETE
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The ifnet_t (pIf) is a tricky customer as any reference to it can potentially
c74832c7184337c330041742d88e6dacaa07b378vboxsync * race the filter detaching. The simple way of solving it on Darwin is to guard
c74832c7184337c330041742d88e6dacaa07b378vboxsync * all access to the pIf member with a spinlock. The other host systems will
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * probably have similar race conditions, so the spinlock is a generic thing.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @msc
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * VM, IntNet, NetFlt, Kernel;
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VM->IntNet [label="pkt0", linecolor="green", textcolor="green"];
a6e58d30b4d856cf924fda15cd743fed386fff93vboxsync * IntNet=>IntNet [label="Lock Network", linecolor="green", textcolor="green" ];
509c0d9c2c05b40f3f07f79e44c06c9395c1b293vboxsync * IntNet=>IntNet [label="Route packet -> wire", linecolor="green", textcolor="green" ];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green" ];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>Kernel [label="ifnet_reference w/ spinlock", linecolor="green", textcolor="green" ];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt<<Kernel [label="ifnet_reference", linecolor="green", textcolor="green" ];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="pkt0 to wire (blocks)", linecolor="green", textcolor="green" ];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * --- [label="The host interface is being disconnected"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Kernel->NetFlt [label="iff_detached"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="ifnet_release w/ spinlock"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt<<Kernel [label="ifnet_release"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>NetFlt [label="fDisconnectedFromHost=true"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt>>Kernel [label="iff_detached"];
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt<<Kernel [label="dropped", linecolor="green", textcolor="green"];
509c0d9c2c05b40f3f07f79e44c06c9395c1b293vboxsync * NetFlt=>NetFlt [label="Acquire spinlock", linecolor="green", textcolor="green"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<Kernel [label="ifnet_release", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="pIf=NULL", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Release spinlock", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<=NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet>>NetFlt [label="pfnSGRelease", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<<NetFlt [label="pkt0 to wire", linecolor="green", textcolor="green"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @endmsc
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @subsection subsec_netflt_msc_hif_rm Host Interface Rediscovery - OBSOLETE
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The rediscovery is performed when we receive a send request and a certain
c74832c7184337c330041742d88e6dacaa07b378vboxsync * period have elapsed since the last attempt, i.e. we're polling it. We
c74832c7184337c330041742d88e6dacaa07b378vboxsync * synchronize the rediscovery with disconnection from the internal network
c74832c7184337c330041742d88e6dacaa07b378vboxsync * by means of the pfnWaitForIdle call, so no special handling is required.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @msc
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VM2, VM1, IntNet, NetFlt, Kernel, Wire;
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * --- [label="Rediscovery conditions are not met"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VM1->IntNet [label="pkt0"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Lock Network"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Route packet -> wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>NetFlt [label="pkt0 to wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<<NetFlt [label="pkt0 to wire (dropped)"];
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * --- [label="Rediscovery conditions"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * VM1->IntNet [label="pkt1"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Lock Network"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Route packet -> wire"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Unlock Network"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>NetFlt [label="pkt1 to wire"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>NetFlt [label="Read pIf(==NULL) w/ spinlock"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>NetFlt [label="fRediscoveryPending=true w/ spinlock"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt=>Kernel [label="ifnet_find_by_name"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * NetFlt<<Kernel [label="ifnet_find_by_name (success)"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * VM2->IntNet [label="pkt2", linecolor="red", textcolor="red"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>IntNet [label="Lock Network", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Route packet -> wire", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet=>IntNet [label="Unlock Network", linecolor="red", textcolor="red"];
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * IntNet=>NetFlt [label="pkt2 to wire", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="!pIf || fRediscoveryPending (w/ spinlock)", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<<NetFlt [label="pkt2 to wire (dropped)", linecolor="red", textcolor="red"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="iflt_attach"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<Kernel [label="iflt_attach (success)"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Acquire spinlock"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Set pIf and update flags"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>NetFlt [label="Release spinlock"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt=>Kernel [label="pkt1 to wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Kernel->Wire [label="pkt1 to wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * NetFlt<<Kernel [label="pkt1 to wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync * IntNet<<NetFlt [label="pkt1 to wire"];
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @endmsc
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/*******************************************************************************
c74832c7184337c330041742d88e6dacaa07b378vboxsync* Header Files *
c74832c7184337c330041742d88e6dacaa07b378vboxsync*******************************************************************************/
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#include "VBoxNetFltInternal.h"
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#include <VBox/sup.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <VBox/log.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <VBox/err.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/assert.h>
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#include <iprt/string.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/spinlock.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/uuid.h>
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#include <iprt/mem.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/time.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/semaphore.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync#include <iprt/thread.h>
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/*******************************************************************************
c74832c7184337c330041742d88e6dacaa07b378vboxsync* Defined Constants And Macros *
c74832c7184337c330041742d88e6dacaa07b378vboxsync*******************************************************************************/
4fbca3751fe239da5934c23a783c3422618336e8vboxsync#define IFPORT_2_VBOXNETFLTINS(pIfPort) \
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ( (PVBOXNETFLTINS)((uint8_t *)pIfPort - RT_OFFSETOF(VBOXNETFLTINS, MyPort)) )
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncAssertCompileMemberSize(VBOXNETFLTINS, enmState, sizeof(uint32_t));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Sets the enmState member atomically.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Used for all updates.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pThis The instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param enmNewState The new value.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncDECLINLINE(void) vboxNetFltSetState(PVBOXNETFLTINS pThis, VBOXNETFTLINSSTATE enmNewState)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, enmNewState);
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Gets the enmState member atomically.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Used for all reads.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns The enmState value.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pThis The instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncDECLINLINE(VBOXNETFTLINSSTATE) vboxNetFltGetState(PVBOXNETFLTINS pThis)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync return (VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState);
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Finds a instance by its name, the caller does the locking.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns Pointer to the instance by the given name. NULL if not found.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pGlobals The globals.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pszName The name of the instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic PVBOXNETFLTINS vboxNetFltFindInstanceLocked(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PVBOXNETFLTINS pCur;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (!strcmp(pszName, pCur->szName))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return pCur;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return NULL;
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync/**
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync * Finds a instance by its name, will request the mutex.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync * No reference to the instance is retained, we're assuming the caller to
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * already have one but just for some reason doesn't have the pointer to it.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns Pointer to the instance by the given name. NULL if not found.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pGlobals The globals.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pszName The name of the instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncDECLHIDDEN(PVBOXNETFLTINS) vboxNetFltFindInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PVBOXNETFLTINS pRet;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertRCReturn(rc, NULL);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pRet = vboxNetFltFindInstanceLocked(pGlobals, pszName);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync rc = RTSemFastMutexRelease(pGlobals->hFastMtx);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertRC(rc);
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync return pRet;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync * Unlinks an instance from the chain.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pGlobals The globals.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pToUnlink The instance to unlink.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic void vboxNetFltUnlinkLocked(PVBOXNETFLTGLOBALS pGlobals, PVBOXNETFLTINS pToUnlink)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (pGlobals->pInstanceHead == pToUnlink)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pGlobals->pInstanceHead = pToUnlink->pNext;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync else
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PVBOXNETFLTINS pCur;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync for (pCur = pGlobals->pInstanceHead; pCur; pCur = pCur->pNext)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (pCur->pNext == pToUnlink)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pCur->pNext = pToUnlink->pNext;
c74832c7184337c330041742d88e6dacaa07b378vboxsync break;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(pCur);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync pToUnlink->pNext = NULL;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Performs interface rediscovery if it was disconnected from the host.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns true if successfully rediscovered and connected, false if not.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @param pThis The instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic bool vboxNetFltMaybeRediscovered(PVBOXNETFLTINS pThis)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint64_t Now;
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync bool fRediscovered;
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync bool fDoIt;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Don't do rediscovery if we're called with preemption disabled.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync * Note! This may cause trouble if we're always called with preemptioni
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * disabled and vboxNetFltOsMaybeRediscovered actually does some real
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * work. For the time being though, only Darwin and FreeBSD depends
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * on these call outs and neither supports sending with preemption
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * disabled.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (!RTThreadPreemptIsEnabled(NIL_RTTHREAD))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return false;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Rediscovered already? Time to try again?
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Now = RTTimeNanoTS();
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync fRediscovered = !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync fDoIt = !fRediscovered
4fbca3751fe239da5934c23a783c3422618336e8vboxsync && !ASMAtomicUoReadBool(&pThis->fRediscoveryPending)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync && Now - ASMAtomicUoReadU64(&pThis->NanoTSLastRediscovery) > UINT64_C(5000000000); /* 5 sec */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (fDoIt)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ASMAtomicWriteBool(&pThis->fRediscoveryPending, true);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Call the OS specific code to do the job.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Update the state when the call returns, that is everything except for
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * the fDisconnectedFromHost flag which the OS specific code shall set.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (fDoIt)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync fRediscovered = vboxNetFltOsMaybeRediscovered(pThis);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(!fRediscovered || !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost));
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ASMAtomicUoWriteU64(&pThis->NanoTSLastRediscovery, RTTimeNanoTS());
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync ASMAtomicWriteBool(&pThis->fRediscoveryPending, false);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (fRediscovered)
c74832c7184337c330041742d88e6dacaa07b378vboxsync /** @todo this isn't 100% serialized. */
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltPortOsSetActive(pThis, pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return fRediscovered;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc INTNETTRUNKIFPORT::pfnXmit
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) vboxNetFltPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Input validation.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pSG);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Do a busy retain and then make sure we're connected to the interface
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * before invoking the OS specific code.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (RT_LIKELY(vboxNetFltTryRetainBusyActive(pThis)))
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync if ( !ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost)
c74832c7184337c330041742d88e6dacaa07b378vboxsync || vboxNetFltMaybeRediscovered(pThis))
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = vboxNetFltPortOsXmit(pThis, pSG, fDst);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRelease(pThis, true /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) vboxNetFltPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Input validation.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, VERR_INVALID_STATE);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertReturn(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING, VERR_INVALID_STATE);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Go to sleep on the semaphore after checking the busy count.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRetain(pThis, false /* fBusy */);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync while (pThis->cBusy && RT_SUCCESS(rc))
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = RTSemEventWait(pThis->hEventIdle, cMillies); /** @todo make interruptible? */
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @copydoc INTNETTRUNKIFPORT::pfnSetState
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic DECLCALLBACK(INTNETTRUNKIFSTATE) vboxNetFltPortSetState(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync INTNETTRUNKIFSTATE enmOldTrunkState;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Input validation.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertPtr(pThis);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertPtr(pThis->pGlobals);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertReturn(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected, INTNETTRUNKIFSTATE_INVALID);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertReturn(enmState > INTNETTRUNKIFSTATE_INVALID && enmState < INTNETTRUNKIFSTATE_END,
4fbca3751fe239da5934c23a783c3422618336e8vboxsync INTNETTRUNKIFSTATE_INVALID);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Take the lock and change the state.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync enmOldTrunkState = pThis->enmTrunkState;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (enmOldTrunkState != enmState)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmTrunkState, enmState);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * If the state change indicates that the trunk has become active or
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * inactive, call the OS specific part so they can work the promiscuous
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * settings and such.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Note! The caller makes sure there are no concurrent pfnSetState calls.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if ((enmOldTrunkState == INTNETTRUNKIFSTATE_ACTIVE) != (enmState == INTNETTRUNKIFSTATE_ACTIVE))
4fbca3751fe239da5934c23a783c3422618336e8vboxsync vboxNetFltPortOsSetActive(pThis, (enmState == INTNETTRUNKIFSTATE_ACTIVE));
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync return enmOldTrunkState;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @copydoc INTNETTRUNKIFPORT::pfnNotifyMacAddress
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic DECLCALLBACK(void) vboxNetFltPortNotifyMacAddress(PINTNETTRUNKIFPORT pIfPort, INTNETIFHANDLE hIf, PCRTMAC pMac)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Input validation.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync AssertPtr(pThis);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync vboxNetFltRetain(pThis, false /* fBusy */);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync vboxNetFltPortOsNotifyMacAddress(pThis, hIf, pMac);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @copydoc INTNETTRUNKIFPORT::pfnConnectInterface
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsyncstatic DECLCALLBACK(int) vboxNetFltPortConnectInterface(PINTNETTRUNKIFPORT pIfPort, INTNETIFHANDLE hIf)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Input validation.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRetain(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = vboxNetFltPortOsConnectInterface(pThis, hIf);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync/**
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @copydoc INTNETTRUNKIFPORT::pfnDisconnectInterface
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(int) vboxNetFltPortDisconnectInterface(PINTNETTRUNKIFPORT pIfPort, INTNETIFHANDLE hIf)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc = VINF_SUCCESS;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Input validation.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRetain(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = vboxNetFltPortOsDisconnectInterface(pThis, hIf);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(void) vboxNetFltPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /*
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Serious paranoia.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis->pGlobals);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->szName[0]);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Connected);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(!pThis->fRediscoveryPending);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(!pThis->cBusy);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /*
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Disconnect and release it.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltOsDisconnectIt(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync pThis->pSwitchPort = NULL;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifdef VBOXNETFLT_STATIC_CONFIG
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync vboxNetFltSetState(pThis, kVBoxNetFltInsState_Unconnected);
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Destroy a device that has been disconnected from the switch.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * @returns true if the instance is destroyed, false otherwise.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param pThis The instance to be destroyed. This is
c74832c7184337c330041742d88e6dacaa07b378vboxsync * no longer valid when this function returns.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic bool vboxNetFltDestroyInstance(PVBOXNETFLTINS pThis)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTGLOBALS pGlobals = pThis->pGlobals;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t cRefs = ASMAtomicUoReadU32((uint32_t volatile *)&pThis->cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync int rc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync LogFlow(("vboxNetFltDestroyInstance: pThis=%p (%s)\n", pThis, pThis->szName));
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Validate the state.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync#ifdef VBOXNETFLT_STATIC_CONFIG
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert( vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting
c74832c7184337c330041742d88e6dacaa07b378vboxsync || vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
c74832c7184337c330041742d88e6dacaa07b378vboxsync#else
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Disconnecting);
c74832c7184337c330041742d88e6dacaa07b378vboxsync#endif
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync Assert(!pThis->fRediscoveryPending);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(!pThis->cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(!pThis->cBusy);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(!pThis->pSwitchPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Make sure the state is 'disconnecting' / 'destroying' and let the OS
c74832c7184337c330041742d88e6dacaa07b378vboxsync * specific code do its part of the cleanup outside the mutex.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltSetState(pThis, kVBoxNetFltInsState_Disconnecting);
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSemFastMutexRelease(pGlobals->hFastMtx);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltOsDeleteInstance(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Unlink the instance and free up its resources.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync rc = RTSemFastMutexRequest(pGlobals->hFastMtx); AssertRC(rc);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltSetState(pThis, kVBoxNetFltInsState_Destroyed);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltUnlinkLocked(pGlobals, pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSemFastMutexRelease(pGlobals->hFastMtx);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSemEventDestroy(pThis->hEventIdle);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync pThis->hEventIdle = NIL_RTSEMEVENT;
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockDestroy(pThis->hSpinlock);
c74832c7184337c330041742d88e6dacaa07b378vboxsync pThis->hSpinlock = NIL_RTSPINLOCK;
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTMemFree(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync NOREF(cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync return true;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync}
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Releases a reference to the specified instance.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * This method will destroy the instance when the count reaches 0.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * It will also take care of decrementing the counter and idle wakeup.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pThis The instance.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @param fBusy Whether the busy counter should be decremented too.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsyncDECLHIDDEN(void) vboxNetFltRelease(PVBOXNETFLTINS pThis, bool fBusy)
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync{
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync uint32_t cRefs;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Paranoid Android.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync AssertPtr(pThis);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync AssertPtr(pThis->pGlobals);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->szName[0]);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /*
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Work the busy counter.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync if (fBusy)
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync {
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync cRefs = ASMAtomicDecU32(&pThis->cBusy);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync if (!cRefs)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
4fbca3751fe239da5934c23a783c3422618336e8vboxsync int rc = RTSemEventSignal(pThis->hEventIdle);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertRC(rc);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync }
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync else
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(cRefs < UINT32_MAX / 2);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * The object reference counting.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync cRefs = ASMAtomicDecU32(&pThis->cRefs);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (!cRefs)
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync vboxNetFltDestroyInstance(pThis);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync else
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(cRefs < UINT32_MAX / 2);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync}
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/**
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @copydoc INTNETTRUNKIFPORT::pfnRetain
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsyncstatic DECLCALLBACK(void) vboxNetFltPortRelease(PINTNETTRUNKIFPORT pIfPort)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync{
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync vboxNetFltRelease(pThis, false /* fBusy */);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync}
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync/**
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Retains a reference to the specified instance and a busy reference too.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pThis The instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param fBusy Whether the busy counter should be incremented as well.
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncDECLHIDDEN(void) vboxNetFltRetain(PVBOXNETFLTINS pThis, bool fBusy)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
4fbca3751fe239da5934c23a783c3422618336e8vboxsync uint32_t cRefs;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Paranoid Android.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync AssertPtr(pThis);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync AssertPtr(pThis->pGlobals);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync Assert(pThis->szName[0]);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Retain the object.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
4fbca3751fe239da5934c23a783c3422618336e8vboxsync cRefs = ASMAtomicIncU32(&pThis->cRefs);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync Assert(cRefs > 1 && cRefs < UINT32_MAX / 2);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync /*
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Work the busy counter.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync if (fBusy)
4fbca3751fe239da5934c23a783c3422618336e8vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync cRefs = ASMAtomicIncU32(&pThis->cBusy);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(cRefs > 0 && cRefs < UINT32_MAX / 2);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync }
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync NOREF(cRefs);
4fbca3751fe239da5934c23a783c3422618336e8vboxsync}
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
4fbca3751fe239da5934c23a783c3422618336e8vboxsync
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync/**
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * Tries to retain the device as busy if the trunk is active.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync *
4fbca3751fe239da5934c23a783c3422618336e8vboxsync * This is used before calling pfnRecv or pfnPreRecv.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @returns true if we succeeded in retaining a busy reference to the active
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * device. false if we failed.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * @param pThis The instance.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsyncDECLHIDDEN(bool) vboxNetFltTryRetainBusyActive(PVBOXNETFLTINS pThis)
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync{
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync uint32_t cRefs;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync bool fRc;
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync /*
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync * Paranoid Android.
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync */
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync AssertPtr(pThis);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync AssertPtr(pThis->pGlobals);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
120ee2736ed70b5ce8b0b4dd73cc4f8b4b9416c1vboxsync Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync Assert(pThis->szName[0]);
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Do the retaining and checking behind the spinlock.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync fRc = pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE;
4fbca3751fe239da5934c23a783c3422618336e8vboxsync if (fRc)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync cRefs = ASMAtomicIncU32(&pThis->cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsg(cRefs > 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync cRefs = ASMAtomicIncU32(&pThis->cBusy);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsg(cRefs >= 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync }
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return fRc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
fe813b3594039ba864493438e78ee0e7132bc445vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
a40c05ca69e15a5efdd0796ef52e26ec0b1bc4d2vboxsync * Tries to retain the device as busy if the trunk is not disconnecting.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * This is used before reporting stuff to the internal network.
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync *
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @returns true if we succeeded in retaining a busy reference to the active
6f8a1ec7a08590986f176ea072ad499630fe5b6evboxsync * device. false if we failed.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param pThis The instance.
4fbca3751fe239da5934c23a783c3422618336e8vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncDECLHIDDEN(bool) vboxNetFltTryRetainBusyNotDisconnected(PVBOXNETFLTINS pThis)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
c74832c7184337c330041742d88e6dacaa07b378vboxsync uint32_t cRefs;
c74832c7184337c330041742d88e6dacaa07b378vboxsync bool fRc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Paranoid Android.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync Assert( vboxNetFltGetState(pThis) > kVBoxNetFltInsState_Invalid
c74832c7184337c330041742d88e6dacaa07b378vboxsync && vboxNetFltGetState(pThis) < kVBoxNetFltInsState_Destroyed);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertPtr(pThis->pGlobals);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hEventIdle != NIL_RTSEMEVENT);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->hSpinlock != NIL_RTSPINLOCK);
c74832c7184337c330041742d88e6dacaa07b378vboxsync Assert(pThis->szName[0]);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync /*
c74832c7184337c330041742d88e6dacaa07b378vboxsync * Do the retaining and checking behind the spinlock.
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockAcquireNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync fRc = pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE
c74832c7184337c330041742d88e6dacaa07b378vboxsync || pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE;
c74832c7184337c330041742d88e6dacaa07b378vboxsync if (fRc)
c74832c7184337c330041742d88e6dacaa07b378vboxsync {
c74832c7184337c330041742d88e6dacaa07b378vboxsync cRefs = ASMAtomicIncU32(&pThis->cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsg(cRefs > 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync cRefs = ASMAtomicIncU32(&pThis->cBusy);
c74832c7184337c330041742d88e6dacaa07b378vboxsync AssertMsg(cRefs >= 1 && cRefs < UINT32_MAX / 2, ("%d\n", cRefs)); NOREF(cRefs);
c74832c7184337c330041742d88e6dacaa07b378vboxsync }
c74832c7184337c330041742d88e6dacaa07b378vboxsync RTSpinlockReleaseNoInts(pThis->hSpinlock, &Tmp);
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync return fRc;
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync
c74832c7184337c330041742d88e6dacaa07b378vboxsync/**
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @copydoc INTNETTRUNKIFPORT::pfnRetain
c74832c7184337c330041742d88e6dacaa07b378vboxsync */
c74832c7184337c330041742d88e6dacaa07b378vboxsyncstatic DECLCALLBACK(void) vboxNetFltPortRetain(PINTNETTRUNKIFPORT pIfPort)
c74832c7184337c330041742d88e6dacaa07b378vboxsync{
c74832c7184337c330041742d88e6dacaa07b378vboxsync PVBOXNETFLTINS pThis = IFPORT_2_VBOXNETFLTINS(pIfPort);
c74832c7184337c330041742d88e6dacaa07b378vboxsync vboxNetFltRetain(pThis, false /* fBusy */);
c74832c7184337c330041742d88e6dacaa07b378vboxsync}
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync/**
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync * Connects the instance to the specified switch port.
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync *
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync * Called while owning the lock. We're ASSUMING that the internal
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync * networking code is already owning an recursive mutex, so, there
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync * will be no deadlocks when vboxNetFltOsConnectIt calls back into
f01175bdcb5e36a1a89fca88f45d7ee7fb034ed6vboxsync * it for setting preferences.
c74832c7184337c330041742d88e6dacaa07b378vboxsync *
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @returns VBox status code.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pThis The instance.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param pSwitchPort The port on the internal network 'switch'.
c74832c7184337c330041742d88e6dacaa07b378vboxsync * @param ppIfPort Where to return our port interface.
*/
static int vboxNetFltConnectIt(PVBOXNETFLTINS pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
{
int rc;
/*
* Validate state.
*/
Assert(!pThis->fRediscoveryPending);
Assert(!pThis->cBusy);
#ifdef VBOXNETFLT_STATIC_CONFIG
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Unconnected);
#else
Assert(vboxNetFltGetState(pThis) == kVBoxNetFltInsState_Initializing);
#endif
Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE);
/*
* Do the job.
* Note that we're calling the os stuff while owning the semaphore here.
*/
pThis->pSwitchPort = pSwitchPort;
rc = vboxNetFltOsConnectIt(pThis);
if (RT_SUCCESS(rc))
{
vboxNetFltSetState(pThis, kVBoxNetFltInsState_Connected);
*ppIfPort = &pThis->MyPort;
}
else
pThis->pSwitchPort = NULL;
Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_INACTIVE);
return rc;
}
/**
* Creates a new instance.
*
* The new instance will be in the suspended state in a dynamic config and in
* the inactive in a static one.
*
* Called without owning the lock, but will request is several times.
*
* @returns VBox status code.
* @param pGlobals The globals.
* @param pszName The instance name.
* @param pSwitchPort The port on the switch that we're connected with (dynamic only).
* @param fNoPromisc Do not attempt going into promiscuous mode.
* @param pvContext Context argument for vboxNetFltOsInitInstance.
* @param ppIfPort Where to store the pointer to our port interface (dynamic only).
*/
static int vboxNetFltNewInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PINTNETTRUNKSWPORT pSwitchPort,
bool fNoPromisc, void *pvContext, PINTNETTRUNKIFPORT *ppIfPort)
{
/*
* Allocate and initialize a new instance before requesting the mutex.
* Note! That in a static config we'll initialize the trunk state to
* disconnecting and flip it in vboxNetFltFactoryCreateAndConnect
* later on. This better reflext the state and it works better with
* assertions in the destruction path.
*/
int rc;
size_t const cchName = strlen(pszName);
PVBOXNETFLTINS pNew = (PVBOXNETFLTINS)RTMemAllocZ(RT_OFFSETOF(VBOXNETFLTINS, szName[cchName + 1]));
if (!pNew)
return VERR_INTNET_FLT_IF_FAILED;
pNew->pNext = NULL;
pNew->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
pNew->MyPort.pfnRetain = vboxNetFltPortRetain;
pNew->MyPort.pfnRelease = vboxNetFltPortRelease;
pNew->MyPort.pfnDisconnectAndRelease= vboxNetFltPortDisconnectAndRelease;
pNew->MyPort.pfnSetState = vboxNetFltPortSetState;
pNew->MyPort.pfnWaitForIdle = vboxNetFltPortWaitForIdle;
pNew->MyPort.pfnXmit = vboxNetFltPortXmit;
pNew->MyPort.pfnNotifyMacAddress = vboxNetFltPortNotifyMacAddress;
pNew->MyPort.pfnConnectInterface = vboxNetFltPortConnectInterface;
pNew->MyPort.pfnDisconnectInterface = vboxNetFltPortDisconnectInterface;
pNew->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
pNew->pSwitchPort = pSwitchPort;
pNew->pGlobals = pGlobals;
pNew->hSpinlock = NIL_RTSPINLOCK;
pNew->enmState = kVBoxNetFltInsState_Initializing;
#ifdef VBOXNETFLT_STATIC_CONFIG
pNew->enmTrunkState = INTNETTRUNKIFSTATE_DISCONNECTING;
#else
pNew->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE;
#endif
pNew->fDisconnectedFromHost = false;
pNew->fRediscoveryPending = false;
pNew->fDisablePromiscuous = fNoPromisc;
pNew->NanoTSLastRediscovery = INT64_MAX;
pNew->cRefs = 1;
pNew->cBusy = 0;
pNew->hEventIdle = NIL_RTSEMEVENT;
memcpy(pNew->szName, pszName, cchName + 1);
rc = RTSpinlockCreate(&pNew->hSpinlock);
if (RT_SUCCESS(rc))
{
rc = RTSemEventCreate(&pNew->hEventIdle);
if (RT_SUCCESS(rc))
{
rc = vboxNetFltOsPreInitInstance(pNew);
if (RT_SUCCESS(rc))
{
/*
* Insert the instance into the chain, checking for
* duplicates first of course (race).
*/
rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
if (RT_SUCCESS(rc))
{
if (!vboxNetFltFindInstanceLocked(pGlobals, pszName))
{
pNew->pNext = pGlobals->pInstanceHead;
pGlobals->pInstanceHead = pNew;
RTSemFastMutexRelease(pGlobals->hFastMtx);
/*
* Call the OS specific initialization code.
*/
rc = vboxNetFltOsInitInstance(pNew, pvContext);
RTSemFastMutexRequest(pGlobals->hFastMtx);
if (RT_SUCCESS(rc))
{
#ifdef VBOXNETFLT_STATIC_CONFIG
/*
* Static instances are unconnected at birth.
*/
Assert(!pSwitchPort);
pNew->enmState = kVBoxNetFltInsState_Unconnected;
RTSemFastMutexRelease(pGlobals->hFastMtx);
*ppIfPort = &pNew->MyPort;
return rc;
#else /* !VBOXNETFLT_STATIC_CONFIG */
/*
* Connect it as well, the OS specific bits has to be done outside
* the lock as they may call back to into intnet.
*/
rc = vboxNetFltConnectIt(pNew, pSwitchPort, ppIfPort);
if (RT_SUCCESS(rc))
{
RTSemFastMutexRelease(pGlobals->hFastMtx);
Assert(*ppIfPort == &pNew->MyPort);
return rc;
}
/* Bail out (failed). */
vboxNetFltOsDeleteInstance(pNew);
#endif /* !VBOXNETFLT_STATIC_CONFIG */
}
vboxNetFltUnlinkLocked(pGlobals, pNew);
}
else
rc = VERR_INTNET_FLT_IF_BUSY;
RTSemFastMutexRelease(pGlobals->hFastMtx);
}
}
RTSemEventDestroy(pNew->hEventIdle);
}
RTSpinlockDestroy(pNew->hSpinlock);
}
RTMemFree(pNew);
return rc;
}
#ifdef VBOXNETFLT_STATIC_CONFIG
/**
* Searches for the NetFlt instance by its name and creates the new one if not found.
*
* @returns VBox status code.
* @retval VINF_SUCCESS and *ppInstance if a new instance was created.
* @retval VINF_ALREADY_INITIALIZED and *ppInstance if an instance already exists.
*
* @param pGlobal Pointer to the globals.
* @param pszName The instance name.
* @param ppInstance Where to return the instance pointer on success.
* @param pvContext Context which needs to be passed along to vboxNetFltOsInitInstance.
*/
DECLHIDDEN(int) vboxNetFltSearchCreateInstance(PVBOXNETFLTGLOBALS pGlobals, const char *pszName, PVBOXNETFLTINS *ppInstance, void *pvContext)
{
PINTNETTRUNKIFPORT pIfPort;
PVBOXNETFLTINS pCur;
VBOXNETFTLINSSTATE enmState;
int rc;
*ppInstance = NULL;
rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
AssertRCReturn(rc, rc);
/*
* Look for an existing instance in the list.
*
* There might be an existing one in the list if the driver was unbound
* while it was connected to an internal network. We're running into
* a destruction race that is a bit similar to the one in
* vboxNetFltFactoryCreateAndConnect, only the roles are reversed
* and we're not in a position to back down. Instead of backing down
* we'll delay a bit giving the other thread time to complete the
* destructor.
*/
pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
while (pCur)
{
uint32_t cRefs = ASMAtomicIncU32(&pCur->cRefs);
if (cRefs > 1)
{
enmState = vboxNetFltGetState(pCur);
switch (enmState)
{
case kVBoxNetFltInsState_Unconnected:
case kVBoxNetFltInsState_Connected:
case kVBoxNetFltInsState_Disconnecting:
if (pCur->fDisconnectedFromHost)
{
/* Wait for it to exit the transitional disconnecting
state. It might otherwise be running the risk of
upsetting the OS specific code... */
/** @todo This reconnect stuff should be serialized correctly for static
* devices. Shouldn't it? In the dynamic case we're using the INTNET
* outbound thrunk lock, but that doesn't quite cut it here, or does
* it? We could either transition to initializing or make a callback
* while owning the mutext here... */
if (enmState == kVBoxNetFltInsState_Disconnecting)
{
do
{
RTSemFastMutexRelease(pGlobals->hFastMtx);
RTThreadSleep(2); /* (2ms) */
RTSemFastMutexRequest(pGlobals->hFastMtx);
enmState = vboxNetFltGetState(pCur);
}
while (enmState == kVBoxNetFltInsState_Disconnecting);
AssertMsg(enmState == kVBoxNetFltInsState_Unconnected, ("%d\n", enmState));
Assert(pCur->fDisconnectedFromHost);
}
RTSemFastMutexRelease(pGlobals->hFastMtx);
*ppInstance = pCur;
return VINF_ALREADY_INITIALIZED;
}
/* fall thru */
default:
{
bool fDfH = pCur->fDisconnectedFromHost;
RTSemFastMutexRelease(pGlobals->hFastMtx);
vboxNetFltRelease(pCur, false /* fBusy */);
LogRel(("VBoxNetFlt: Huh? An instance of '%s' already exists! [pCur=%p cRefs=%d fDfH=%RTbool enmState=%d]\n",
pszName, pCur, cRefs - 1, fDfH, enmState));
*ppInstance = NULL;
return VERR_INTNET_FLT_IF_BUSY;
}
}
}
/* Zero references, it's being destroyed. Delay a bit so the destructor
can finish its work and try again. (vboxNetFltNewInstance will fail
with duplicate name if we don't.) */
# ifdef RT_STRICT
Assert(cRefs == 1);
enmState = vboxNetFltGetState(pCur);
AssertMsg( enmState == kVBoxNetFltInsState_Unconnected
|| enmState == kVBoxNetFltInsState_Disconnecting
|| enmState == kVBoxNetFltInsState_Destroyed, ("%d\n", enmState));
# endif
ASMAtomicDecU32(&pCur->cRefs);
RTSemFastMutexRelease(pGlobals->hFastMtx);
RTThreadSleep(2); /* (2ms) */
rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
AssertRCReturn(rc, rc);
/* try again */
pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
}
RTSemFastMutexRelease(pGlobals->hFastMtx);
/*
* Try create a new instance.
* (fNoPromisc is overridden in the vboxNetFltFactoryCreateAndConnect path, so pass true here.)
*/
rc = vboxNetFltNewInstance(pGlobals, pszName, NULL, true /* fNoPromisc */, pvContext, &pIfPort);
if (RT_SUCCESS(rc))
*ppInstance = IFPORT_2_VBOXNETFLTINS(pIfPort);
else
*ppInstance = NULL;
return rc;
}
#endif /* VBOXNETFLT_STATIC_CONFIG */
/**
* @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
*/
static DECLCALLBACK(int) vboxNetFltFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
PINTNETTRUNKIFPORT *ppIfPort)
{
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
PVBOXNETFLTINS pCur;
int rc;
LogFlow(("vboxNetFltFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
Assert(pGlobals->cFactoryRefs > 0);
AssertMsgReturn(!(fFlags & ~(INTNETTRUNKFACTORY_FLAG_NO_PROMISC)),
("%#x\n", fFlags), VERR_INVALID_PARAMETER);
/*
* Static: Find instance, check if busy, connect if not.
* Dynamic: Check for duplicate / busy interface instance.
*/
rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
AssertRCReturn(rc, rc);
//#if defined(VBOXNETADP) && defined(RT_OS_WINDOWS)
// /* temporary hack to pick up the first adapter */
// pCur = pGlobals->pInstanceHead; /** @todo Don't for get to remove this temporary hack... :-) */
//#else
pCur = vboxNetFltFindInstanceLocked(pGlobals, pszName);
//#endif
if (pCur)
{
#ifdef VBOXNETFLT_STATIC_CONFIG
/* Try grab a reference. If the count had already reached zero we're racing the
destructor code and must back down. */
uint32_t cRefs = ASMAtomicIncU32(&pCur->cRefs);
if (cRefs > 1)
{
if (vboxNetFltGetState(pCur) == kVBoxNetFltInsState_Unconnected)
{
pCur->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE; /** @todo protect me? */
pCur->fDisablePromiscuous = !!(fFlags & INTNETTRUNKFACTORY_FLAG_NO_PROMISC);
rc = vboxNetFltConnectIt(pCur, pSwitchPort, ppIfPort);
if (RT_SUCCESS(rc))
pCur = NULL; /* Don't release it, reference given to the caller. */
else
pCur->enmTrunkState = INTNETTRUNKIFSTATE_DISCONNECTING;
}
else
rc = VERR_INTNET_FLT_IF_BUSY;
}
else
{
Assert(cRefs == 1);
ASMAtomicDecU32(&pCur->cRefs);
pCur = NULL; /* nothing to release */
rc = VERR_INTNET_FLT_IF_NOT_FOUND;
}
RTSemFastMutexRelease(pGlobals->hFastMtx);
if (pCur)
vboxNetFltRelease(pCur, false /* fBusy */);
#else
rc = VERR_INTNET_FLT_IF_BUSY;
RTSemFastMutexRelease(pGlobals->hFastMtx);
#endif
LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
return rc;
}
RTSemFastMutexRelease(pGlobals->hFastMtx);
#ifdef VBOXNETFLT_STATIC_CONFIG
rc = VERR_INTNET_FLT_IF_NOT_FOUND;
#else
/*
* Dynamically create a new instance.
*/
rc = vboxNetFltNewInstance(pGlobals,
pszName,
pSwitchPort,
!!(fFlags & INTNETTRUNKFACTORY_FLAG_NO_PROMISC),
NULL,
ppIfPort);
#endif
LogFlow(("vboxNetFltFactoryCreateAndConnect: returns %Rrc\n", rc));
return rc;
}
/**
* @copydoc INTNETTRUNKFACTORY::pfnRelease
*/
static DECLCALLBACK(void) vboxNetFltFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
{
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, TrunkFactory));
int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
Assert(cRefs >= 0); NOREF(cRefs);
LogFlow(("vboxNetFltFactoryRelease: cRefs=%d (new)\n", cRefs));
}
/**
* Implements the SUPDRV component factor interface query method.
*
* @returns Pointer to an interface. NULL if not supported.
*
* @param pSupDrvFactory Pointer to the componet factory registration structure.
* @param pSession The session - unused.
* @param pszInterfaceUuid The factory interface id.
*/
static DECLCALLBACK(void *) vboxNetFltQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
{
PVBOXNETFLTGLOBALS pGlobals = (PVBOXNETFLTGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETFLTGLOBALS, SupDrvFactory));
/*
* Convert the UUID strings and compare them.
*/
RTUUID UuidReq;
int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
if (RT_SUCCESS(rc))
{
if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
{
ASMAtomicIncS32(&pGlobals->cFactoryRefs);
return &pGlobals->TrunkFactory;
}
#ifdef LOG_ENABLED
/* log legacy queries */
/* else if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_V1_UUID_STR))
Log(("VBoxNetFlt: V1 factory query\n"));
*/
else
Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
#endif
}
else
Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
return NULL;
}
/**
* Checks whether the VBoxNetFlt wossname can be unloaded.
*
* This will return false if someone is currently using the module.
*
* @returns true if it's relatively safe to unload it, otherwise false.
* @param pGlobals Pointer to the globals.
*/
DECLHIDDEN(bool) vboxNetFltCanUnload(PVBOXNETFLTGLOBALS pGlobals)
{
int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
bool fRc = !pGlobals->pInstanceHead
&& pGlobals->cFactoryRefs <= 0;
RTSemFastMutexRelease(pGlobals->hFastMtx);
AssertRC(rc);
return fRc;
}
/**
* Try to close the IDC connection to SUPDRV if established.
*
* @returns VBox status code.
* @retval VINF_SUCCESS on success.
* @retval VERR_WRONG_ORDER if we're busy.
*
* @param pGlobals Pointer to the globals.
*
* @sa vboxNetFltTryDeleteIdcAndGlobals()
*/
DECLHIDDEN(int) vboxNetFltTryDeleteIdc(PVBOXNETFLTGLOBALS pGlobals)
{
int rc;
Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
/*
* Check before trying to deregister the factory.
*/
if (!vboxNetFltCanUnload(pGlobals))
return VERR_WRONG_ORDER;
if (!pGlobals->fIDCOpen)
rc = VINF_SUCCESS;
else
{
/*
* Disconnect from SUPDRV and check that nobody raced us,
* reconnect if that should happen.
*/
rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
AssertRC(rc);
if (!vboxNetFltCanUnload(pGlobals))
{
rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
AssertRC(rc);
return VERR_WRONG_ORDER;
}
SUPR0IdcClose(&pGlobals->SupDrvIDC);
pGlobals->fIDCOpen = false;
}
return rc;
}
/**
* Establishes the IDC connection to SUPDRV and registers our component factory.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals.
* @sa vboxNetFltInitGlobalsAndIdc().
*/
DECLHIDDEN(int) vboxNetFltInitIdc(PVBOXNETFLTGLOBALS pGlobals)
{
int rc;
Assert(!pGlobals->fIDCOpen);
/*
* Establish a connection to SUPDRV and register our component factory.
*/
rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
if (RT_SUCCESS(rc))
{
rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
if (RT_SUCCESS(rc))
{
pGlobals->fIDCOpen = true;
Log(("VBoxNetFlt: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
return rc;
}
/* bail out. */
LogRel(("VBoxNetFlt: Failed to register component factory, rc=%Rrc\n", rc));
SUPR0IdcClose(&pGlobals->SupDrvIDC);
}
return rc;
}
/**
* Deletes the globals.
*
* This must be called after the IDC connection has been closed,
* see vboxNetFltTryDeleteIdc().
*
* @param pGlobals Pointer to the globals.
* @sa vboxNetFltTryDeleteIdcAndGlobals()
*/
DECLHIDDEN(void) vboxNetFltDeleteGlobals(PVBOXNETFLTGLOBALS pGlobals)
{
Assert(!pGlobals->fIDCOpen);
/*
* Release resources.
*/
RTSemFastMutexDestroy(pGlobals->hFastMtx);
pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
}
/**
* Initializes the globals.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals.
* @sa vboxNetFltInitGlobalsAndIdc().
*/
DECLHIDDEN(int) vboxNetFltInitGlobals(PVBOXNETFLTGLOBALS pGlobals)
{
/*
* Initialize the common portions of the structure.
*/
int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
if (RT_SUCCESS(rc))
{
pGlobals->pInstanceHead = NULL;
pGlobals->TrunkFactory.pfnRelease = vboxNetFltFactoryRelease;
pGlobals->TrunkFactory.pfnCreateAndConnect = vboxNetFltFactoryCreateAndConnect;
#if defined(RT_OS_WINDOWS) && defined(VBOXNETADP)
memcpy(pGlobals->SupDrvFactory.szName, "VBoxNetAdp", sizeof("VBoxNetAdp"));
#else
memcpy(pGlobals->SupDrvFactory.szName, "VBoxNetFlt", sizeof("VBoxNetFlt"));
#endif
pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxNetFltQueryFactoryInterface;
pGlobals->fIDCOpen = false;
return rc;
}
return rc;
}
/**
* Called by the native part when the OS wants the driver to unload.
*
* @returns VINF_SUCCESS on success, VERR_WRONG_ORDER if we're busy.
*
* @param pGlobals Pointer to the globals.
*/
DECLHIDDEN(int) vboxNetFltTryDeleteIdcAndGlobals(PVBOXNETFLTGLOBALS pGlobals)
{
int rc = vboxNetFltTryDeleteIdc(pGlobals);
if (RT_SUCCESS(rc))
vboxNetFltDeleteGlobals(pGlobals);
return rc;
}
/**
* Called by the native driver/kext module initialization routine.
*
* It will initialize the common parts of the globals, assuming the caller
* has already taken care of the OS specific bits, and establish the IDC
* connection to SUPDRV.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals.
*/
DECLHIDDEN(int) vboxNetFltInitGlobalsAndIdc(PVBOXNETFLTGLOBALS pGlobals)
{
/*
* Initialize the common portions of the structure.
*/
int rc = vboxNetFltInitGlobals(pGlobals);
if (RT_SUCCESS(rc))
{
rc = vboxNetFltInitIdc(pGlobals);
if (RT_SUCCESS(rc))
return rc;
/* bail out. */
vboxNetFltDeleteGlobals(pGlobals);
}
return rc;
}