[9181] | 1 | /* $Id: SrvIntNetR0.cpp 104355 2024-04-17 18:22:32Z vboxsync $ */
|
---|
[1] | 2 | /** @file
|
---|
[9181] | 3 | * Internal networking - The ring 0 service.
|
---|
[52445] | 4 | *
|
---|
| 5 | * @remarks No lazy code changes. If you don't understand exactly what you're
|
---|
[52618] | 6 | * doing, get an understanding or forget it.
|
---|
[52445] | 7 | * All changes shall be reviewed by bird before commit. If not around,
|
---|
| 8 | * email and let Frank and/or Klaus OK the changes before committing.
|
---|
[1] | 9 | */
|
---|
| 10 |
|
---|
| 11 | /*
|
---|
[98103] | 12 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[1] | 13 | *
|
---|
[96407] | 14 | * This file is part of VirtualBox base platform packages, as
|
---|
| 15 | * available from https://www.virtualbox.org.
|
---|
| 16 | *
|
---|
| 17 | * This program is free software; you can redistribute it and/or
|
---|
| 18 | * modify it under the terms of the GNU General Public License
|
---|
| 19 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 20 | * License.
|
---|
| 21 | *
|
---|
| 22 | * This program is distributed in the hope that it will be useful, but
|
---|
| 23 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 25 | * General Public License for more details.
|
---|
| 26 | *
|
---|
| 27 | * You should have received a copy of the GNU General Public License
|
---|
| 28 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 29 | *
|
---|
| 30 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[1] | 31 | */
|
---|
| 32 |
|
---|
| 33 |
|
---|
[57358] | 34 | /*********************************************************************************************************************************
|
---|
| 35 | * Header Files *
|
---|
| 36 | *********************************************************************************************************************************/
|
---|
[1] | 37 | #define LOG_GROUP LOG_GROUP_SRV_INTNET
|
---|
| 38 | #include <VBox/intnet.h>
|
---|
[26574] | 39 | #include <VBox/intnetinline.h>
|
---|
[35346] | 40 | #include <VBox/vmm/pdmnetinline.h>
|
---|
[1] | 41 | #include <VBox/sup.h>
|
---|
[35346] | 42 | #include <VBox/vmm/pdm.h>
|
---|
[1] | 43 | #include <VBox/log.h>
|
---|
[28623] | 44 |
|
---|
[1] | 45 | #include <iprt/asm.h>
|
---|
[28623] | 46 | #include <iprt/assert.h>
|
---|
| 47 | #include <iprt/handletable.h>
|
---|
| 48 | #include <iprt/mp.h>
|
---|
| 49 | #include <iprt/mem.h>
|
---|
| 50 | #include <iprt/net.h>
|
---|
[1] | 51 | #include <iprt/semaphore.h>
|
---|
| 52 | #include <iprt/spinlock.h>
|
---|
[28623] | 53 | #include <iprt/string.h>
|
---|
[1] | 54 | #include <iprt/thread.h>
|
---|
[10681] | 55 | #include <iprt/time.h>
|
---|
[1] | 56 |
|
---|
| 57 |
|
---|
[57358] | 58 | /*********************************************************************************************************************************
|
---|
| 59 | * Defined Constants And Macros *
|
---|
| 60 | *********************************************************************************************************************************/
|
---|
[11074] | 61 | /** @def INTNET_WITH_DHCP_SNOOPING
|
---|
| 62 | * Enabled DHCP snooping when in shared-mac-on-the-wire mode. */
|
---|
[11123] | 63 | #define INTNET_WITH_DHCP_SNOOPING
|
---|
[11074] | 64 |
|
---|
[28623] | 65 | /** The maximum number of interface in a network. */
|
---|
| 66 | #define INTNET_MAX_IFS (1023 + 1 + 16)
|
---|
| 67 |
|
---|
| 68 | /** The number of entries to grow the destination tables with. */
|
---|
[28430] | 69 | #if 0
|
---|
[28623] | 70 | # define INTNET_GROW_DSTTAB_SIZE 16
|
---|
| 71 | #else
|
---|
| 72 | # define INTNET_GROW_DSTTAB_SIZE 1
|
---|
[28430] | 73 | #endif
|
---|
[11074] | 74 |
|
---|
[28623] | 75 | /** The wakeup bit in the INTNETIF::cBusy and INTNETRUNKIF::cBusy counters. */
|
---|
| 76 | #define INTNET_BUSY_WAKEUP_MASK RT_BIT_32(30)
|
---|
[28430] | 77 |
|
---|
| 78 |
|
---|
[57358] | 79 | /*********************************************************************************************************************************
|
---|
| 80 | * Structures and Typedefs *
|
---|
| 81 | *********************************************************************************************************************************/
|
---|
[28430] | 82 | /**
|
---|
| 83 | * MAC address lookup table entry.
|
---|
| 84 | */
|
---|
| 85 | typedef struct INTNETMACTABENTRY
|
---|
| 86 | {
|
---|
| 87 | /** The MAC address of this entry. */
|
---|
| 88 | RTMAC MacAddr;
|
---|
[36089] | 89 | /** Is it is effectively promiscuous mode. */
|
---|
[36075] | 90 | bool fPromiscuousEff;
|
---|
| 91 | /** Is it promiscuous and should it see unrelated trunk traffic. */
|
---|
| 92 | bool fPromiscuousSeeTrunk;
|
---|
[28430] | 93 | /** Is it active.
|
---|
| 94 | * We ignore the entry if this is clear and may end up sending packets addressed
|
---|
| 95 | * to this interface onto the trunk. The reasoning for this is that this could
|
---|
| 96 | * be the interface of a VM that just has been teleported to a different host. */
|
---|
| 97 | bool fActive;
|
---|
| 98 | /** Pointer to the network interface. */
|
---|
| 99 | struct INTNETIF *pIf;
|
---|
| 100 | } INTNETMACTABENTRY;
|
---|
| 101 | /** Pointer to a MAC address lookup table entry. */
|
---|
| 102 | typedef INTNETMACTABENTRY *PINTNETMACTABENTRY;
|
---|
| 103 |
|
---|
| 104 | /**
|
---|
| 105 | * MAC address lookup table.
|
---|
[28623] | 106 | *
|
---|
| 107 | * @todo Having this in a separate structure didn't work out as well as it
|
---|
| 108 | * should. Consider merging it into INTNETNETWORK.
|
---|
[28430] | 109 | */
|
---|
| 110 | typedef struct INTNETMACTAB
|
---|
| 111 | {
|
---|
| 112 | /** The current number of entries. */
|
---|
| 113 | uint32_t cEntries;
|
---|
| 114 | /** The number of entries we've allocated space for. */
|
---|
| 115 | uint32_t cEntriesAllocated;
|
---|
| 116 | /** Table entries. */
|
---|
[28623] | 117 | PINTNETMACTABENTRY paEntries;
|
---|
[28430] | 118 |
|
---|
[36089] | 119 | /** The number of interface entries currently in promicuous mode. */
|
---|
| 120 | uint32_t cPromiscuousEntries;
|
---|
| 121 | /** The number of interface entries currently in promicuous mode that
|
---|
| 122 | * shall not see unrelated trunk traffic. */
|
---|
| 123 | uint32_t cPromiscuousNoTrunkEntries;
|
---|
| 124 |
|
---|
[28623] | 125 | /** The host MAC address (reported). */
|
---|
[28430] | 126 | RTMAC HostMac;
|
---|
[36075] | 127 | /** The effective host promiscuous setting (reported). */
|
---|
| 128 | bool fHostPromiscuousEff;
|
---|
| 129 | /** The real host promiscuous setting (reported). */
|
---|
| 130 | bool fHostPromiscuousReal;
|
---|
[28430] | 131 | /** Whether the host is active. */
|
---|
| 132 | bool fHostActive;
|
---|
| 133 |
|
---|
[28623] | 134 | /** Whether the wire is promiscuous (config). */
|
---|
[36075] | 135 | bool fWirePromiscuousEff;
|
---|
| 136 | /** Whether the wire is promiscuous (config).
|
---|
| 137 | * (Shadows INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE in
|
---|
| 138 | * INTNETNETWORK::fFlags.) */
|
---|
| 139 | bool fWirePromiscuousReal;
|
---|
[28430] | 140 | /** Whether the wire is active. */
|
---|
| 141 | bool fWireActive;
|
---|
| 142 |
|
---|
[41783] | 143 | /** Pointer to the trunk interface. */
|
---|
[28430] | 144 | struct INTNETTRUNKIF *pTrunk;
|
---|
| 145 | } INTNETMACTAB;
|
---|
| 146 | /** Pointer to a MAC address . */
|
---|
| 147 | typedef INTNETMACTAB *PINTNETMACTAB;
|
---|
| 148 |
|
---|
| 149 | /**
|
---|
| 150 | * Destination table.
|
---|
| 151 | */
|
---|
| 152 | typedef struct INTNETDSTTAB
|
---|
| 153 | {
|
---|
| 154 | /** The trunk destinations. */
|
---|
| 155 | uint32_t fTrunkDst;
|
---|
| 156 | /** Pointer to the trunk interface (referenced) if fTrunkDst is non-zero. */
|
---|
| 157 | struct INTNETTRUNKIF *pTrunk;
|
---|
| 158 | /** The number of destination interfaces. */
|
---|
| 159 | uint32_t cIfs;
|
---|
| 160 | /** The interfaces (referenced). Variable sized array. */
|
---|
[28623] | 161 | struct
|
---|
| 162 | {
|
---|
| 163 | /** The destination interface. */
|
---|
| 164 | struct INTNETIF *pIf;
|
---|
| 165 | /** Whether to replace the destination MAC address.
|
---|
| 166 | * This is used when sharing MAC address with the host on the wire(less). */
|
---|
| 167 | bool fReplaceDstMac;
|
---|
| 168 | } aIfs[1];
|
---|
[28430] | 169 | } INTNETDSTTAB;
|
---|
| 170 | /** Pointer to a destination table. */
|
---|
| 171 | typedef INTNETDSTTAB *PINTNETDSTTAB;
|
---|
[28623] | 172 | /** Pointer to a const destination table. */
|
---|
| 173 | typedef INTNETDSTTAB const *PCINTNETDSTTAB;
|
---|
[28430] | 174 |
|
---|
[10923] | 175 | /**
|
---|
| 176 | * Address and type.
|
---|
| 177 | */
|
---|
| 178 | typedef struct INTNETADDR
|
---|
| 179 | {
|
---|
| 180 | /** The address type. */
|
---|
[28430] | 181 | INTNETADDRTYPE enmType;
|
---|
[10923] | 182 | /** The address. */
|
---|
[28430] | 183 | RTNETADDRU Addr;
|
---|
[10923] | 184 | } INTNETADDR;
|
---|
| 185 | /** Pointer to an address. */
|
---|
| 186 | typedef INTNETADDR *PINTNETADDR;
|
---|
| 187 | /** Pointer to a const address. */
|
---|
| 188 | typedef INTNETADDR const *PCINTNETADDR;
|
---|
| 189 |
|
---|
| 190 |
|
---|
| 191 | /**
|
---|
| 192 | * Address cache for a specific network layer.
|
---|
| 193 | */
|
---|
| 194 | typedef struct INTNETADDRCACHE
|
---|
| 195 | {
|
---|
| 196 | /** Pointer to the table of addresses. */
|
---|
[28430] | 197 | uint8_t *pbEntries;
|
---|
[10923] | 198 | /** The number of valid address entries. */
|
---|
[28430] | 199 | uint8_t cEntries;
|
---|
[10923] | 200 | /** The number of allocated address entries. */
|
---|
[28430] | 201 | uint8_t cEntriesAlloc;
|
---|
[10923] | 202 | /** The address size. */
|
---|
[28430] | 203 | uint8_t cbAddress;
|
---|
[10923] | 204 | /** The size of an entry. */
|
---|
[28430] | 205 | uint8_t cbEntry;
|
---|
[10923] | 206 | } INTNETADDRCACHE;
|
---|
| 207 | /** Pointer to an address cache. */
|
---|
| 208 | typedef INTNETADDRCACHE *PINTNETADDRCACHE;
|
---|
| 209 | /** Pointer to a const address cache. */
|
---|
| 210 | typedef INTNETADDRCACHE const *PCINTNETADDRCACHE;
|
---|
| 211 |
|
---|
| 212 |
|
---|
| 213 | /**
|
---|
[1] | 214 | * A network interface.
|
---|
[10557] | 215 | *
|
---|
| 216 | * Unless explicitly stated, all members are protect by the network semaphore.
|
---|
[1] | 217 | */
|
---|
| 218 | typedef struct INTNETIF
|
---|
| 219 | {
|
---|
[28623] | 220 | /** The MAC address.
|
---|
| 221 | * This is shadowed by INTNETMACTABENTRY::MacAddr. */
|
---|
| 222 | RTMAC MacAddr;
|
---|
| 223 | /** Set if the INTNET::MacAddr member has been explicitly set. */
|
---|
[1] | 224 | bool fMacSet;
|
---|
[36075] | 225 | /** Tracks the desired promiscuous setting of the interface. */
|
---|
| 226 | bool fPromiscuousReal;
|
---|
[28623] | 227 | /** Whether the interface is active or not.
|
---|
| 228 | * This is shadowed by INTNETMACTABENTRY::fActive. */
|
---|
[10711] | 229 | bool fActive;
|
---|
[60525] | 230 | /** Whether someone has indicated that the end is nigh by means of IntNetR0IfAbortWait. */
|
---|
| 231 | bool volatile fNoMoreWaits;
|
---|
[36075] | 232 | /** The flags specified when opening this interface. */
|
---|
| 233 | uint32_t fOpenFlags;
|
---|
[1] | 234 | /** Number of yields done to try make the interface read pending data.
|
---|
[28430] | 235 | * We will stop yielding when this reaches a threshold assuming that the VM is
|
---|
| 236 | * paused or that it simply isn't worth all the delay. It is cleared when a
|
---|
| 237 | * successful send has been done. */
|
---|
[1] | 238 | uint32_t cYields;
|
---|
| 239 | /** Pointer to the current exchange buffer (ring-0). */
|
---|
| 240 | PINTNETBUF pIntBuf;
|
---|
| 241 | /** Pointer to ring-3 mapping of the current exchange buffer. */
|
---|
[5283] | 242 | R3PTRTYPE(PINTNETBUF) pIntBufR3;
|
---|
[1] | 243 | /** Pointer to the default exchange buffer for the interface. */
|
---|
| 244 | PINTNETBUF pIntBufDefault;
|
---|
| 245 | /** Pointer to ring-3 mapping of the default exchange buffer. */
|
---|
[5283] | 246 | R3PTRTYPE(PINTNETBUF) pIntBufDefaultR3;
|
---|
[97338] | 247 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[28623] | 248 | /** Event semaphore which a receiver/consumer thread will sleep on while
|
---|
| 249 | * waiting for data to arrive. */
|
---|
| 250 | RTSEMEVENT volatile hRecvEvent;
|
---|
| 251 | /** Number of threads sleeping on the event semaphore. */
|
---|
[60525] | 252 | uint32_t volatile cSleepers;
|
---|
[97338] | 253 | #else
|
---|
| 254 | /** The callback to call when there is something to receive/consume. */
|
---|
| 255 | PFNINTNETIFRECVAVAIL pfnRecvAvail;
|
---|
| 256 | /** Opaque user data to pass to the receive avail callback (pfnRecvAvail). */
|
---|
| 257 | void *pvUserRecvAvail;
|
---|
| 258 | #endif
|
---|
[1] | 259 | /** The interface handle.
|
---|
| 260 | * When this is INTNET_HANDLE_INVALID a sleeper which is waking up
|
---|
| 261 | * should return with the appropriate error condition. */
|
---|
[10819] | 262 | INTNETIFHANDLE volatile hIf;
|
---|
[60525] | 263 | /** The native handle of the destructor thread. This is NIL_RTNATIVETHREAD when
|
---|
| 264 | * the object is valid and set when intnetR0IfDestruct is in progress. This is
|
---|
| 265 | * used to cover an unlikely (impossible?) race between SUPDRVSESSION cleanup
|
---|
| 266 | * and lingering threads waiting for recv or similar. */
|
---|
| 267 | RTNATIVETHREAD volatile hDestructorThread;
|
---|
[10557] | 268 | /** Pointer to the network this interface is connected to.
|
---|
[28623] | 269 | * This is protected by the INTNET::hMtxCreateOpenDestroy. */
|
---|
[1] | 270 | struct INTNETNETWORK *pNetwork;
|
---|
| 271 | /** The session this interface is associated with. */
|
---|
| 272 | PSUPDRVSESSION pSession;
|
---|
| 273 | /** The SUPR0 object id. */
|
---|
| 274 | void *pvObj;
|
---|
[28623] | 275 | /** The network layer address cache. (Indexed by type, 0 entry isn't used.)
|
---|
| 276 | * This is protected by the address spinlock of the network. */
|
---|
[10923] | 277 | INTNETADDRCACHE aAddrCache[kIntNetAddrType_End];
|
---|
[28430] | 278 | /** Spinlock protecting the input (producer) side of the receive ring. */
|
---|
| 279 | RTSPINLOCK hRecvInSpinlock;
|
---|
| 280 | /** Busy count for tracking destination table references and active sends.
|
---|
[28623] | 281 | * Usually incremented while owning the switch table spinlock. The 30th bit
|
---|
| 282 | * is used to indicate wakeup. */
|
---|
[28430] | 283 | uint32_t volatile cBusy;
|
---|
| 284 | /** The preallocated destination table.
|
---|
| 285 | * This is NULL when it's in use as a precaution against unserialized
|
---|
| 286 | * transmitting. This is grown when new interfaces are added to the network. */
|
---|
| 287 | PINTNETDSTTAB volatile pDstTab;
|
---|
[29662] | 288 | /** Pointer to the trunk's per interface data. Can be NULL. */
|
---|
| 289 | void *pvIfData;
|
---|
[37909] | 290 | /** Header buffer for when we're carving GSO frames. */
|
---|
| 291 | uint8_t abGsoHdrs[256];
|
---|
[10031] | 292 | } INTNETIF;
|
---|
[10530] | 293 | /** Pointer to an internal network interface. */
|
---|
[10031] | 294 | typedef INTNETIF *PINTNETIF;
|
---|
[1] | 295 |
|
---|
| 296 |
|
---|
| 297 | /**
|
---|
[10559] | 298 | * A trunk interface.
|
---|
| 299 | */
|
---|
| 300 | typedef struct INTNETTRUNKIF
|
---|
| 301 | {
|
---|
| 302 | /** The port interface we present to the component. */
|
---|
[10681] | 303 | INTNETTRUNKSWPORT SwitchPort;
|
---|
[10559] | 304 | /** The port interface we get from the component. */
|
---|
[10681] | 305 | PINTNETTRUNKIFPORT pIfPort;
|
---|
| 306 | /** Pointer to the network we're connect to.
|
---|
| 307 | * This may be NULL if we're orphaned? */
|
---|
| 308 | struct INTNETNETWORK *pNetwork;
|
---|
[28430] | 309 | /** The current MAC address for the interface. (reported)
|
---|
[28623] | 310 | * Updated while owning the switch table spinlock. */
|
---|
| 311 | RTMAC MacAddr;
|
---|
[28430] | 312 | /** Whether to supply physical addresses with the outbound SGs. (reported) */
|
---|
| 313 | bool fPhysSG;
|
---|
[28722] | 314 | /** Explicit alignment. */
|
---|
| 315 | bool fUnused;
|
---|
[28430] | 316 | /** Busy count for tracking destination table references and active sends.
|
---|
[28623] | 317 | * Usually incremented while owning the switch table spinlock. The 30th bit
|
---|
| 318 | * is used to indicate wakeup. */
|
---|
[28430] | 319 | uint32_t volatile cBusy;
|
---|
[28722] | 320 | /** Mask of destinations that pfnXmit cope with disabled preemption for. */
|
---|
| 321 | uint32_t fNoPreemptDsts;
|
---|
[28430] | 322 | /** The GSO capabilities of the wire destination. (reported) */
|
---|
| 323 | uint32_t fWireGsoCapabilites;
|
---|
| 324 | /** The GSO capabilities of the host destination. (reported)
|
---|
[28120] | 325 | * This is as bit map where each bit represents the GSO type with the same
|
---|
| 326 | * number. */
|
---|
[28430] | 327 | uint32_t fHostGsoCapabilites;
|
---|
[28623] | 328 | /** The destination table spinlock, interrupt safe.
|
---|
| 329 | * Protects apTaskDstTabs and apIntDstTabs. */
|
---|
| 330 | RTSPINLOCK hDstTabSpinlock;
|
---|
| 331 | /** The number of entries in apIntDstTabs. */
|
---|
| 332 | uint32_t cIntDstTabs;
|
---|
| 333 | /** The task time destination tables.
|
---|
| 334 | * @remarks intnetR0NetworkEnsureTabSpace and others ASSUMES this immediately
|
---|
[33540] | 335 | * precedes apIntDstTabs so that these two tables can be used as one
|
---|
[28623] | 336 | * contiguous one. */
|
---|
| 337 | PINTNETDSTTAB apTaskDstTabs[2];
|
---|
| 338 | /** The interrupt / disabled-preemption time destination tables.
|
---|
| 339 | * This is a variable sized array. */
|
---|
| 340 | PINTNETDSTTAB apIntDstTabs[1];
|
---|
[10559] | 341 | } INTNETTRUNKIF;
|
---|
| 342 | /** Pointer to a trunk interface. */
|
---|
| 343 | typedef INTNETTRUNKIF *PINTNETTRUNKIF;
|
---|
| 344 |
|
---|
[10681] | 345 | /** Converts a pointer to INTNETTRUNKIF::SwitchPort to a PINTNETTRUNKIF. */
|
---|
| 346 | #define INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort) ((PINTNETTRUNKIF)(pSwitchPort))
|
---|
[10559] | 347 |
|
---|
[10681] | 348 |
|
---|
[10559] | 349 | /**
|
---|
[1] | 350 | * Internal representation of a network.
|
---|
| 351 | */
|
---|
| 352 | typedef struct INTNETNETWORK
|
---|
| 353 | {
|
---|
| 354 | /** The Next network in the chain.
|
---|
[28623] | 355 | * This is protected by the INTNET::hMtxCreateOpenDestroy. */
|
---|
[1] | 356 | struct INTNETNETWORK *pNext;
|
---|
[28623] | 357 |
|
---|
[55652] | 358 | /** The spinlock protecting MacTab, aAddrBlacklist and INTNETIF::aAddrCache.
|
---|
[28623] | 359 | * Interrupt safe. */
|
---|
| 360 | RTSPINLOCK hAddrSpinlock;
|
---|
| 361 | /** MAC address table.
|
---|
| 362 | * This doubles as interface collection. */
|
---|
| 363 | INTNETMACTAB MacTab;
|
---|
| 364 |
|
---|
[55652] | 365 | /** The network layer address cache. (Indexed by type, 0 entry isn't used.
|
---|
| 366 | * Contains host addresses. We don't let guests spoof them. */
|
---|
| 367 | INTNETADDRCACHE aAddrBlacklist[kIntNetAddrType_End];
|
---|
| 368 |
|
---|
[28430] | 369 | /** Wait for an interface to stop being busy so it can be removed or have its
|
---|
| 370 | * destination table replaced. We have to wait upon this while owning the
|
---|
[28623] | 371 | * network mutex. Will only ever have one waiter because of the big mutex. */
|
---|
[28430] | 372 | RTSEMEVENT hEvtBusyIf;
|
---|
[1] | 373 | /** Pointer to the instance data. */
|
---|
| 374 | struct INTNET *pIntNet;
|
---|
| 375 | /** The SUPR0 object id. */
|
---|
| 376 | void *pvObj;
|
---|
[74484] | 377 | /** The trunk reconnection system thread. The thread gets started at trunk
|
---|
| 378 | * disconnection. It tries to reconnect the trunk to the bridged filter instance.
|
---|
| 379 | * The thread erases this handle right before it terminates.
|
---|
| 380 | */
|
---|
| 381 | RTTHREAD hTrunkReconnectThread;
|
---|
| 382 | /** Trunk reconnection thread termination flag. */
|
---|
| 383 | bool volatile fTerminateReconnectThread;
|
---|
[11057] | 384 | /** Pointer to the temporary buffer that is used when snooping fragmented packets.
|
---|
| 385 | * This is allocated after this structure if we're sharing the MAC address with
|
---|
[33540] | 386 | * the host. The buffer is INTNETNETWORK_TMP_SIZE big and aligned on a 64-byte boundary. */
|
---|
[11057] | 387 | uint8_t *pbTmp;
|
---|
[10530] | 388 | /** Network creation flags (INTNET_OPEN_FLAGS_*). */
|
---|
| 389 | uint32_t fFlags;
|
---|
[36075] | 390 | /** Any restrictive policies required as a minimum by some interface.
|
---|
| 391 | * (INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES) */
|
---|
| 392 | uint32_t fMinFlags;
|
---|
[10711] | 393 | /** The number of active interfaces (excluding the trunk). */
|
---|
| 394 | uint32_t cActiveIFs;
|
---|
[1] | 395 | /** The length of the network name. */
|
---|
| 396 | uint8_t cchName;
|
---|
| 397 | /** The network name. */
|
---|
| 398 | char szName[INTNET_MAX_NETWORK_NAME];
|
---|
[10530] | 399 | /** The trunk type. */
|
---|
| 400 | INTNETTRUNKTYPE enmTrunkType;
|
---|
| 401 | /** The trunk name. */
|
---|
| 402 | char szTrunk[INTNET_MAX_TRUNK_NAME];
|
---|
[10031] | 403 | } INTNETNETWORK;
|
---|
[10530] | 404 | /** Pointer to an internal network. */
|
---|
[10031] | 405 | typedef INTNETNETWORK *PINTNETNETWORK;
|
---|
[36075] | 406 | /** Pointer to a const internal network. */
|
---|
| 407 | typedef const INTNETNETWORK *PCINTNETNETWORK;
|
---|
[1] | 408 |
|
---|
[11057] | 409 | /** The size of the buffer INTNETNETWORK::pbTmp points at. */
|
---|
| 410 | #define INTNETNETWORK_TMP_SIZE 2048
|
---|
[1] | 411 |
|
---|
[11057] | 412 |
|
---|
[1] | 413 | /**
|
---|
| 414 | * Internal networking instance.
|
---|
| 415 | */
|
---|
| 416 | typedef struct INTNET
|
---|
| 417 | {
|
---|
[28706] | 418 | /** Magic number (INTNET_MAGIC). */
|
---|
| 419 | uint32_t volatile u32Magic;
|
---|
[28488] | 420 | /** Mutex protecting the creation, opening and destruction of both networks and
|
---|
| 421 | * interfaces. (This means all operations affecting the pNetworks list.) */
|
---|
| 422 | RTSEMMUTEX hMtxCreateOpenDestroy;
|
---|
[1] | 423 | /** List of networks. Protected by INTNET::Spinlock. */
|
---|
| 424 | PINTNETNETWORK volatile pNetworks;
|
---|
| 425 | /** Handle table for the interfaces. */
|
---|
[10819] | 426 | RTHANDLETABLE hHtIfs;
|
---|
[1] | 427 | } INTNET;
|
---|
[28706] | 428 | /** Pointer to an internal network ring-0 instance. */
|
---|
| 429 | typedef struct INTNET *PINTNET;
|
---|
[1] | 430 |
|
---|
[28706] | 431 | /** Magic number for the internal network instance data (Hayao Miyazaki). */
|
---|
| 432 | #define INTNET_MAGIC UINT32_C(0x19410105)
|
---|
[1] | 433 |
|
---|
[10923] | 434 |
|
---|
[57358] | 435 | /*********************************************************************************************************************************
|
---|
| 436 | * Global Variables *
|
---|
| 437 | *********************************************************************************************************************************/
|
---|
[28706] | 438 | /** Pointer to the internal network instance data. */
|
---|
| 439 | static PINTNET volatile g_pIntNet = NULL;
|
---|
| 440 |
|
---|
[36075] | 441 | static const struct INTNETOPENNETWORKFLAGS
|
---|
| 442 | {
|
---|
| 443 | uint32_t fRestrictive; /**< The restrictive flag (deny/disabled). */
|
---|
| 444 | uint32_t fRelaxed; /**< The relaxed flag (allow/enabled). */
|
---|
| 445 | uint32_t fFixed; /**< The config-fixed flag. */
|
---|
| 446 | uint32_t fPair; /**< The pair of restrictive and relaxed flags. */
|
---|
| 447 | }
|
---|
| 448 | /** Open network policy flags relating to the network. */
|
---|
| 449 | g_afIntNetOpenNetworkNetFlags[] =
|
---|
| 450 | {
|
---|
| 451 | { INTNET_OPEN_FLAGS_ACCESS_RESTRICTED, INTNET_OPEN_FLAGS_ACCESS_PUBLIC, INTNET_OPEN_FLAGS_ACCESS_FIXED, INTNET_OPEN_FLAGS_ACCESS_RESTRICTED | INTNET_OPEN_FLAGS_ACCESS_PUBLIC },
|
---|
| 452 | { INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS, INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS },
|
---|
| 453 | { INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST, INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST },
|
---|
| 454 | { INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE, INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE, INTNET_OPEN_FLAGS_PROMISC_FIXED, INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE },
|
---|
| 455 | { INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED, INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED },
|
---|
| 456 | { INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE, INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE | INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE },
|
---|
| 457 | { INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED, INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED },
|
---|
| 458 | { INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE, INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE, INTNET_OPEN_FLAGS_TRUNK_FIXED, INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE },
|
---|
| 459 | },
|
---|
| 460 | /** Open network policy flags relating to the new interface. */
|
---|
| 461 | g_afIntNetOpenNetworkIfFlags[] =
|
---|
| 462 | {
|
---|
| 463 | { INTNET_OPEN_FLAGS_IF_PROMISC_DENY, INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW, INTNET_OPEN_FLAGS_IF_FIXED, INTNET_OPEN_FLAGS_IF_PROMISC_DENY | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW },
|
---|
| 464 | { INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK, INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK, INTNET_OPEN_FLAGS_IF_FIXED, INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK },
|
---|
| 465 | };
|
---|
[28706] | 466 |
|
---|
[36075] | 467 |
|
---|
[57358] | 468 | /*********************************************************************************************************************************
|
---|
| 469 | * Forward Declarations *
|
---|
| 470 | *********************************************************************************************************************************/
|
---|
[52134] | 471 | static void intnetR0TrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork);
|
---|
[1] | 472 |
|
---|
[52134] | 473 |
|
---|
[11055] | 474 | /**
|
---|
[52134] | 475 | * Checks if a pointer belongs to the list of known networks without
|
---|
| 476 | * accessing memory it points to.
|
---|
| 477 | *
|
---|
| 478 | * @returns true, if such network is in the list.
|
---|
| 479 | * @param pIntNet The pointer to the internal network instance (global).
|
---|
| 480 | * @param pNetwork The pointer that must be validated.
|
---|
| 481 | */
|
---|
| 482 | DECLINLINE(bool) intnetR0NetworkIsValid(PINTNET pIntNet, PINTNETNETWORK pNetwork)
|
---|
| 483 | {
|
---|
| 484 | for (PINTNETNETWORK pCurr = pIntNet->pNetworks; pCurr; pCurr = pCurr->pNext)
|
---|
| 485 | if (pCurr == pNetwork)
|
---|
| 486 | return true;
|
---|
| 487 | return false;
|
---|
| 488 | }
|
---|
| 489 |
|
---|
| 490 |
|
---|
| 491 | /**
|
---|
[11072] | 492 | * Worker for intnetR0SgWritePart that deals with the case where the
|
---|
| 493 | * request doesn't fit into the first segment.
|
---|
| 494 | *
|
---|
| 495 | * @returns true, unless the request or SG invalid.
|
---|
| 496 | * @param pSG The SG list to write to.
|
---|
| 497 | * @param off Where to start writing (offset into the SG).
|
---|
| 498 | * @param cb How much to write.
|
---|
| 499 | * @param pvBuf The buffer to containing the bits to write.
|
---|
| 500 | */
|
---|
| 501 | static bool intnetR0SgWritePartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
|
---|
| 502 | {
|
---|
| 503 | if (RT_UNLIKELY(off + cb > pSG->cbTotal))
|
---|
| 504 | return false;
|
---|
| 505 |
|
---|
| 506 | /*
|
---|
| 507 | * Skip ahead to the segment where off starts.
|
---|
| 508 | */
|
---|
| 509 | unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
|
---|
| 510 | unsigned iSeg = 0;
|
---|
| 511 | while (off > pSG->aSegs[iSeg].cb)
|
---|
| 512 | {
|
---|
| 513 | off -= pSG->aSegs[iSeg++].cb;
|
---|
| 514 | AssertReturn(iSeg < cSegs, false);
|
---|
| 515 | }
|
---|
| 516 |
|
---|
| 517 | /*
|
---|
| 518 | * Copy the data, hoping that it's all from one segment...
|
---|
| 519 | */
|
---|
| 520 | uint32_t cbCanCopy = pSG->aSegs[iSeg].cb - off;
|
---|
| 521 | if (cbCanCopy >= cb)
|
---|
| 522 | memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cb);
|
---|
| 523 | else
|
---|
| 524 | {
|
---|
| 525 | /* copy the portion in the current segment. */
|
---|
| 526 | memcpy((uint8_t *)pSG->aSegs[iSeg].pv + off, pvBuf, cbCanCopy);
|
---|
| 527 | cb -= cbCanCopy;
|
---|
| 528 |
|
---|
| 529 | /* copy the portions in the other segments. */
|
---|
| 530 | do
|
---|
| 531 | {
|
---|
| 532 | pvBuf = (uint8_t const *)pvBuf + cbCanCopy;
|
---|
| 533 | iSeg++;
|
---|
| 534 | AssertReturn(iSeg < cSegs, false);
|
---|
| 535 |
|
---|
| 536 | cbCanCopy = RT_MIN(cb, pSG->aSegs[iSeg].cb);
|
---|
| 537 | memcpy(pSG->aSegs[iSeg].pv, pvBuf, cbCanCopy);
|
---|
| 538 |
|
---|
| 539 | cb -= cbCanCopy;
|
---|
| 540 | } while (cb > 0);
|
---|
| 541 | }
|
---|
| 542 |
|
---|
| 543 | return true;
|
---|
| 544 | }
|
---|
| 545 |
|
---|
| 546 |
|
---|
| 547 | /**
|
---|
| 548 | * Writes to a part of an SG.
|
---|
| 549 | *
|
---|
| 550 | * @returns true on success, false on failure (out of bounds).
|
---|
| 551 | * @param pSG The SG list to write to.
|
---|
| 552 | * @param off Where to start writing (offset into the SG).
|
---|
| 553 | * @param cb How much to write.
|
---|
| 554 | * @param pvBuf The buffer to containing the bits to write.
|
---|
| 555 | */
|
---|
| 556 | DECLINLINE(bool) intnetR0SgWritePart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void const *pvBuf)
|
---|
| 557 | {
|
---|
| 558 | Assert(off + cb > off);
|
---|
| 559 |
|
---|
| 560 | /* The optimized case. */
|
---|
| 561 | if (RT_LIKELY( pSG->cSegsUsed == 1
|
---|
| 562 | || pSG->aSegs[0].cb >= off + cb))
|
---|
| 563 | {
|
---|
| 564 | Assert(pSG->cbTotal == pSG->aSegs[0].cb);
|
---|
| 565 | memcpy((uint8_t *)pSG->aSegs[0].pv + off, pvBuf, cb);
|
---|
| 566 | return true;
|
---|
| 567 | }
|
---|
| 568 | return intnetR0SgWritePartSlow(pSG, off, cb, pvBuf);
|
---|
| 569 | }
|
---|
| 570 |
|
---|
| 571 |
|
---|
| 572 | /**
|
---|
[11055] | 573 | * Reads a byte from a SG list.
|
---|
| 574 | *
|
---|
| 575 | * @returns The byte on success. 0xff on failure.
|
---|
| 576 | * @param pSG The SG list to read.
|
---|
| 577 | * @param off The offset (into the SG) off the byte.
|
---|
| 578 | */
|
---|
| 579 | DECLINLINE(uint8_t) intnetR0SgReadByte(PCINTNETSG pSG, uint32_t off)
|
---|
| 580 | {
|
---|
| 581 | if (RT_LIKELY(pSG->aSegs[0].cb > off))
|
---|
| 582 | return ((uint8_t const *)pSG->aSegs[0].pv)[off];
|
---|
| 583 |
|
---|
[11124] | 584 | off -= pSG->aSegs[0].cb;
|
---|
[11055] | 585 | unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
|
---|
| 586 | for (unsigned iSeg = 1; iSeg < cSegs; iSeg++)
|
---|
| 587 | {
|
---|
[11124] | 588 | if (pSG->aSegs[iSeg].cb > off)
|
---|
[11055] | 589 | return ((uint8_t const *)pSG->aSegs[iSeg].pv)[off];
|
---|
| 590 | off -= pSG->aSegs[iSeg].cb;
|
---|
| 591 | }
|
---|
| 592 | return false;
|
---|
| 593 | }
|
---|
| 594 |
|
---|
| 595 |
|
---|
| 596 | /**
|
---|
| 597 | * Worker for intnetR0SgReadPart that deals with the case where the
|
---|
| 598 | * requested data isn't in the first segment.
|
---|
| 599 | *
|
---|
| 600 | * @returns true, unless the SG is invalid.
|
---|
| 601 | * @param pSG The SG list to read.
|
---|
| 602 | * @param off Where to start reading (offset into the SG).
|
---|
| 603 | * @param cb How much to read.
|
---|
| 604 | * @param pvBuf The buffer to read into.
|
---|
| 605 | */
|
---|
| 606 | static bool intnetR0SgReadPartSlow(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
|
---|
| 607 | {
|
---|
| 608 | if (RT_UNLIKELY(off + cb > pSG->cbTotal))
|
---|
| 609 | return false;
|
---|
| 610 |
|
---|
| 611 | /*
|
---|
| 612 | * Skip ahead to the segment where off starts.
|
---|
| 613 | */
|
---|
| 614 | unsigned const cSegs = pSG->cSegsUsed; Assert(cSegs == pSG->cSegsUsed);
|
---|
| 615 | unsigned iSeg = 0;
|
---|
| 616 | while (off > pSG->aSegs[iSeg].cb)
|
---|
| 617 | {
|
---|
| 618 | off -= pSG->aSegs[iSeg++].cb;
|
---|
| 619 | AssertReturn(iSeg < cSegs, false);
|
---|
| 620 | }
|
---|
| 621 |
|
---|
| 622 | /*
|
---|
| 623 | * Copy the data, hoping that it's all from one segment...
|
---|
| 624 | */
|
---|
| 625 | uint32_t cbCanCopy = pSG->aSegs[iSeg].cb - off;
|
---|
| 626 | if (cbCanCopy >= cb)
|
---|
| 627 | memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cb);
|
---|
| 628 | else
|
---|
| 629 | {
|
---|
| 630 | /* copy the portion in the current segment. */
|
---|
| 631 | memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv + off, cbCanCopy);
|
---|
| 632 | cb -= cbCanCopy;
|
---|
| 633 |
|
---|
| 634 | /* copy the portions in the other segments. */
|
---|
| 635 | do
|
---|
| 636 | {
|
---|
| 637 | pvBuf = (uint8_t *)pvBuf + cbCanCopy;
|
---|
| 638 | iSeg++;
|
---|
| 639 | AssertReturn(iSeg < cSegs, false);
|
---|
| 640 |
|
---|
| 641 | cbCanCopy = RT_MIN(cb, pSG->aSegs[iSeg].cb);
|
---|
[11072] | 642 | memcpy(pvBuf, (uint8_t const *)pSG->aSegs[iSeg].pv, cbCanCopy);
|
---|
[11055] | 643 |
|
---|
| 644 | cb -= cbCanCopy;
|
---|
| 645 | } while (cb > 0);
|
---|
| 646 | }
|
---|
| 647 |
|
---|
| 648 | return true;
|
---|
| 649 | }
|
---|
| 650 |
|
---|
| 651 |
|
---|
| 652 | /**
|
---|
| 653 | * Reads a part of an SG into a buffer.
|
---|
| 654 | *
|
---|
| 655 | * @returns true on success, false on failure (out of bounds).
|
---|
| 656 | * @param pSG The SG list to read.
|
---|
| 657 | * @param off Where to start reading (offset into the SG).
|
---|
| 658 | * @param cb How much to read.
|
---|
| 659 | * @param pvBuf The buffer to read into.
|
---|
| 660 | */
|
---|
| 661 | DECLINLINE(bool) intnetR0SgReadPart(PCINTNETSG pSG, uint32_t off, uint32_t cb, void *pvBuf)
|
---|
| 662 | {
|
---|
| 663 | Assert(off + cb > off);
|
---|
| 664 |
|
---|
| 665 | /* The optimized case. */
|
---|
[88867] | 666 | if (RT_LIKELY(pSG->aSegs[0].cb >= off + cb))
|
---|
[11055] | 667 | {
|
---|
[88867] | 668 | AssertMsg(pSG->cbTotal >= pSG->aSegs[0].cb, ("%#x vs %#x\n", pSG->cbTotal, pSG->aSegs[0].cb));
|
---|
[11055] | 669 | memcpy(pvBuf, (uint8_t const *)pSG->aSegs[0].pv + off, cb);
|
---|
| 670 | return true;
|
---|
| 671 | }
|
---|
| 672 | return intnetR0SgReadPartSlow(pSG, off, cb, pvBuf);
|
---|
| 673 | }
|
---|
| 674 |
|
---|
| 675 |
|
---|
| 676 | /**
|
---|
[28623] | 677 | * Wait for a busy counter to reach zero.
|
---|
[28430] | 678 | *
|
---|
[28623] | 679 | * @param pNetwork The network.
|
---|
| 680 | * @param pcBusy The busy counter.
|
---|
[28430] | 681 | */
|
---|
[28623] | 682 | static void intnetR0BusyWait(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
|
---|
[28430] | 683 | {
|
---|
[28623] | 684 | if (ASMAtomicReadU32(pcBusy) == 0)
|
---|
| 685 | return;
|
---|
| 686 |
|
---|
| 687 | /*
|
---|
| 688 | * We have to be a bit cautious here so we don't destroy the network or the
|
---|
| 689 | * semaphore before intnetR0BusyDec has signalled us.
|
---|
| 690 | */
|
---|
| 691 |
|
---|
| 692 | /* Reset the semaphore and flip the wakeup bit. */
|
---|
| 693 | RTSemEventWait(pNetwork->hEvtBusyIf, 0); /* clear it */
|
---|
| 694 | uint32_t cCurBusy = ASMAtomicReadU32(pcBusy);
|
---|
| 695 | do
|
---|
| 696 | {
|
---|
| 697 | if (cCurBusy == 0)
|
---|
| 698 | return;
|
---|
| 699 | AssertMsg(!(cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
|
---|
| 700 | AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
|
---|
| 701 | } while (!ASMAtomicCmpXchgExU32(pcBusy, cCurBusy | INTNET_BUSY_WAKEUP_MASK, cCurBusy, &cCurBusy));
|
---|
| 702 |
|
---|
| 703 | /* Wait for the count to reach zero. */
|
---|
| 704 | do
|
---|
| 705 | {
|
---|
| 706 | int rc2 = RTSemEventWait(pNetwork->hEvtBusyIf, 30000); NOREF(rc2);
|
---|
| 707 | //AssertMsg(RT_SUCCESS(rc2), ("rc=%Rrc *pcBusy=%#x (%#x)\n", rc2, ASMAtomicReadU32(pcBusy), cCurBusy ));
|
---|
| 708 | cCurBusy = ASMAtomicReadU32(pcBusy);
|
---|
| 709 | AssertMsg((cCurBusy & INTNET_BUSY_WAKEUP_MASK), ("%#x\n", cCurBusy));
|
---|
| 710 | AssertMsg((cCurBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cCurBusy));
|
---|
| 711 | } while ( cCurBusy != INTNET_BUSY_WAKEUP_MASK
|
---|
[31322] | 712 | || !ASMAtomicCmpXchgU32(pcBusy, 0, INTNET_BUSY_WAKEUP_MASK));
|
---|
[28430] | 713 | }
|
---|
| 714 |
|
---|
| 715 |
|
---|
| 716 | /**
|
---|
[28623] | 717 | * Decrements the busy counter and maybe wakes up any threads waiting for it to
|
---|
| 718 | * reach zero.
|
---|
[28430] | 719 | *
|
---|
[28623] | 720 | * @param pNetwork The network.
|
---|
| 721 | * @param pcBusy The busy counter.
|
---|
[28430] | 722 | */
|
---|
[28623] | 723 | DECLINLINE(void) intnetR0BusyDec(PINTNETNETWORK pNetwork, uint32_t volatile *pcBusy)
|
---|
[28430] | 724 | {
|
---|
[28623] | 725 | uint32_t cNewBusy = ASMAtomicDecU32(pcBusy);
|
---|
| 726 | if (RT_UNLIKELY( cNewBusy == INTNET_BUSY_WAKEUP_MASK
|
---|
| 727 | && pNetwork))
|
---|
| 728 | RTSemEventSignal(pNetwork->hEvtBusyIf);
|
---|
| 729 | AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
|
---|
| 730 | }
|
---|
[28430] | 731 |
|
---|
| 732 |
|
---|
[28623] | 733 | /**
|
---|
| 734 | * Increments the busy count of the specified interface.
|
---|
| 735 | *
|
---|
| 736 | * The caller must own the MAC address table spinlock.
|
---|
| 737 | *
|
---|
| 738 | * @param pIf The interface.
|
---|
| 739 | */
|
---|
| 740 | DECLINLINE(void) intnetR0BusyDecIf(PINTNETIF pIf)
|
---|
| 741 | {
|
---|
| 742 | intnetR0BusyDec(pIf->pNetwork, &pIf->cBusy);
|
---|
| 743 | }
|
---|
[28430] | 744 |
|
---|
| 745 |
|
---|
[28623] | 746 | /**
|
---|
| 747 | * Increments the busy count of the specified interface.
|
---|
| 748 | *
|
---|
| 749 | * The caller must own the MAC address table spinlock or an explicity reference.
|
---|
| 750 | *
|
---|
| 751 | * @param pTrunk The trunk.
|
---|
| 752 | */
|
---|
| 753 | DECLINLINE(void) intnetR0BusyDecTrunk(PINTNETTRUNKIF pTrunk)
|
---|
| 754 | {
|
---|
[52134] | 755 | if (pTrunk)
|
---|
| 756 | intnetR0BusyDec(pTrunk->pNetwork, &pTrunk->cBusy);
|
---|
[28623] | 757 | }
|
---|
[28430] | 758 |
|
---|
| 759 |
|
---|
[28623] | 760 | /**
|
---|
| 761 | * Increments the busy count of the specified interface.
|
---|
| 762 | *
|
---|
| 763 | * The caller must own the MAC address table spinlock or an explicity reference.
|
---|
| 764 | *
|
---|
| 765 | * @param pIf The interface.
|
---|
| 766 | */
|
---|
| 767 | DECLINLINE(void) intnetR0BusyIncIf(PINTNETIF pIf)
|
---|
| 768 | {
|
---|
| 769 | uint32_t cNewBusy = ASMAtomicIncU32(&pIf->cBusy);
|
---|
| 770 | AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
|
---|
| 771 | NOREF(cNewBusy);
|
---|
| 772 | }
|
---|
[28430] | 773 |
|
---|
| 774 |
|
---|
[28623] | 775 | /**
|
---|
| 776 | * Increments the busy count of the specified interface.
|
---|
| 777 | *
|
---|
| 778 | * The caller must own the MAC address table spinlock or an explicity reference.
|
---|
| 779 | *
|
---|
| 780 | * @param pTrunk The trunk.
|
---|
| 781 | */
|
---|
| 782 | DECLINLINE(void) intnetR0BusyIncTrunk(PINTNETTRUNKIF pTrunk)
|
---|
| 783 | {
|
---|
[52134] | 784 | if (!pTrunk) return;
|
---|
[28623] | 785 | uint32_t cNewBusy = ASMAtomicIncU32(&pTrunk->cBusy);
|
---|
| 786 | AssertMsg((cNewBusy & ~INTNET_BUSY_WAKEUP_MASK) < INTNET_MAX_IFS * 3, ("%#x\n", cNewBusy));
|
---|
| 787 | NOREF(cNewBusy);
|
---|
[28430] | 788 | }
|
---|
| 789 |
|
---|
| 790 |
|
---|
| 791 | /**
|
---|
[10819] | 792 | * Retain an interface.
|
---|
[10557] | 793 | *
|
---|
[10819] | 794 | * @returns VBox status code, can assume success in most situations.
|
---|
| 795 | * @param pIf The interface instance.
|
---|
| 796 | * @param pSession The current session.
|
---|
[10557] | 797 | */
|
---|
[10819] | 798 | DECLINLINE(int) intnetR0IfRetain(PINTNETIF pIf, PSUPDRVSESSION pSession)
|
---|
[10557] | 799 | {
|
---|
[60819] | 800 | Assert(pIf->hDestructorThread == NIL_RTNATIVETHREAD);
|
---|
[60525] | 801 |
|
---|
[15505] | 802 | int rc = SUPR0ObjAddRefEx(pIf->pvObj, pSession, true /* fNoBlocking */);
|
---|
[10819] | 803 | AssertRCReturn(rc, rc);
|
---|
[60525] | 804 |
|
---|
[10819] | 805 | return VINF_SUCCESS;
|
---|
[10557] | 806 | }
|
---|
[1] | 807 |
|
---|
[10557] | 808 |
|
---|
[1] | 809 | /**
|
---|
[10819] | 810 | * Release an interface previously retained by intnetR0IfRetain or
|
---|
| 811 | * by handle lookup/freeing.
|
---|
[1] | 812 | *
|
---|
[15842] | 813 | * @returns true if destroyed, false if not.
|
---|
[10819] | 814 | * @param pIf The interface instance.
|
---|
| 815 | * @param pSession The current session.
|
---|
[1] | 816 | */
|
---|
[15757] | 817 | DECLINLINE(bool) intnetR0IfRelease(PINTNETIF pIf, PSUPDRVSESSION pSession)
|
---|
[1] | 818 | {
|
---|
[60819] | 819 | Assert(pIf->hDestructorThread == NIL_RTNATIVETHREAD);
|
---|
[60525] | 820 |
|
---|
[10819] | 821 | int rc = SUPR0ObjRelease(pIf->pvObj, pSession);
|
---|
| 822 | AssertRC(rc);
|
---|
[60525] | 823 |
|
---|
[15842] | 824 | return rc == VINF_OBJECT_DESTROYED;
|
---|
[1] | 825 | }
|
---|
| 826 |
|
---|
| 827 |
|
---|
| 828 | /**
|
---|
[10819] | 829 | * RTHandleCreateEx callback that retains an object in the
|
---|
| 830 | * handle table before returning it.
|
---|
[1] | 831 | *
|
---|
[10819] | 832 | * (Avoids racing the freeing of the handle.)
|
---|
[1] | 833 | *
|
---|
[10819] | 834 | * @returns VBox status code.
|
---|
| 835 | * @param hHandleTable The handle table (ignored).
|
---|
| 836 | * @param pvObj The object (INTNETIF).
|
---|
| 837 | * @param pvCtx The context (SUPDRVSESSION).
|
---|
| 838 | * @param pvUser The user context (ignored).
|
---|
[1] | 839 | */
|
---|
[10819] | 840 | static DECLCALLBACK(int) intnetR0IfRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
|
---|
[1] | 841 | {
|
---|
[10819] | 842 | NOREF(pvUser);
|
---|
| 843 | NOREF(hHandleTable);
|
---|
[60525] | 844 |
|
---|
| 845 | PINTNETIF pIf = (PINTNETIF)pvObj;
|
---|
| 846 | RTNATIVETHREAD hDtorThrd;
|
---|
| 847 | ASMAtomicUoReadHandle(&pIf->hDestructorThread, &hDtorThrd);
|
---|
| 848 | if (hDtorThrd == NIL_RTNATIVETHREAD)
|
---|
[10819] | 849 | return intnetR0IfRetain(pIf, (PSUPDRVSESSION)pvCtx);
|
---|
[60525] | 850 |
|
---|
| 851 | /* Allow intnetR0IfDestruct to call RTHandleTableFreeWithCtx to free
|
---|
| 852 | the handle, but not even think about retaining a referenceas we don't
|
---|
| 853 | want to confuse SUPDrv and risk having the destructor called twice. */
|
---|
| 854 | if (hDtorThrd == RTThreadNativeSelf())
|
---|
| 855 | return VINF_SUCCESS;
|
---|
| 856 |
|
---|
| 857 | return VERR_SEM_DESTROYED;
|
---|
[1] | 858 | }
|
---|
| 859 |
|
---|
| 860 |
|
---|
[11055] | 861 |
|
---|
[28623] | 862 | /**
|
---|
| 863 | * Checks if the interface has a usable MAC address or not.
|
---|
| 864 | *
|
---|
| 865 | * @returns true if MacAddr is usable, false if not.
|
---|
| 866 | * @param pIf The interface.
|
---|
| 867 | */
|
---|
| 868 | DECL_FORCE_INLINE(bool) intnetR0IfHasMacAddr(PINTNETIF pIf)
|
---|
| 869 | {
|
---|
| 870 | return pIf->fMacSet || !(pIf->MacAddr.au8[0] & 1);
|
---|
| 871 | }
|
---|
[11055] | 872 |
|
---|
| 873 |
|
---|
[28623] | 874 | /**
|
---|
| 875 | * Locates the MAC address table entry for the given interface.
|
---|
| 876 | *
|
---|
| 877 | * The caller holds the MAC address table spinlock, obviously.
|
---|
| 878 | *
|
---|
| 879 | * @returns Pointer to the entry on if found, NULL if not.
|
---|
| 880 | * @param pNetwork The network.
|
---|
| 881 | * @param pIf The interface.
|
---|
| 882 | */
|
---|
| 883 | DECLINLINE(PINTNETMACTABENTRY) intnetR0NetworkFindMacAddrEntry(PINTNETNETWORK pNetwork, PINTNETIF pIf)
|
---|
| 884 | {
|
---|
| 885 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 886 | while (iIf-- > 0)
|
---|
| 887 | {
|
---|
| 888 | if (pNetwork->MacTab.paEntries[iIf].pIf == pIf)
|
---|
| 889 | return &pNetwork->MacTab.paEntries[iIf];
|
---|
| 890 | }
|
---|
| 891 | return NULL;
|
---|
| 892 | }
|
---|
[11055] | 893 |
|
---|
[28623] | 894 |
|
---|
[10733] | 895 | /**
|
---|
[45716] | 896 | * Checks if the IPv6 address is a good interface address.
|
---|
| 897 | * @returns true/false.
|
---|
| 898 | * @param addr The address, network endian.
|
---|
| 899 | */
|
---|
| 900 | DECLINLINE(bool) intnetR0IPv6AddrIsGood(RTNETADDRIPV6 addr)
|
---|
| 901 | {
|
---|
[45717] | 902 | return !( ( addr.QWords.qw0 == 0 && addr.QWords.qw1 == 0) /* :: */
|
---|
| 903 | || ( (addr.Words.w0 & RT_H2BE_U16(0xff00)) == RT_H2BE_U16(0xff00)) /* multicast */
|
---|
[45716] | 904 | || ( addr.Words.w0 == 0 && addr.Words.w1 == 0
|
---|
| 905 | && addr.Words.w2 == 0 && addr.Words.w3 == 0
|
---|
| 906 | && addr.Words.w4 == 0 && addr.Words.w5 == 0
|
---|
[45717] | 907 | && addr.Words.w6 == 0 && addr.Words.w7 == RT_H2BE_U16(0x0001))); /* ::1 */
|
---|
[45716] | 908 | }
|
---|
| 909 |
|
---|
| 910 |
|
---|
[63458] | 911 | #if 0 /* unused */
|
---|
[45716] | 912 | /**
|
---|
[11053] | 913 | * Checks if the IPv4 address is a broadcast address.
|
---|
| 914 | * @returns true/false.
|
---|
| 915 | * @param Addr The address, network endian.
|
---|
| 916 | */
|
---|
| 917 | DECLINLINE(bool) intnetR0IPv4AddrIsBroadcast(RTNETADDRIPV4 Addr)
|
---|
| 918 | {
|
---|
| 919 | /* Just check for 255.255.255.255 atm. */
|
---|
| 920 | return Addr.u == UINT32_MAX;
|
---|
| 921 | }
|
---|
[63478] | 922 | #endif /* unused */
|
---|
[11053] | 923 |
|
---|
| 924 |
|
---|
| 925 | /**
|
---|
| 926 | * Checks if the IPv4 address is a good interface address.
|
---|
| 927 | * @returns true/false.
|
---|
| 928 | * @param Addr The address, network endian.
|
---|
| 929 | */
|
---|
| 930 | DECLINLINE(bool) intnetR0IPv4AddrIsGood(RTNETADDRIPV4 Addr)
|
---|
| 931 | {
|
---|
| 932 | /* Usual suspects. */
|
---|
| 933 | if ( Addr.u == UINT32_MAX /* 255.255.255.255 - broadcast. */
|
---|
| 934 | || Addr.au8[0] == 0) /* Current network, can be used as source address. */
|
---|
| 935 | return false;
|
---|
| 936 |
|
---|
| 937 | /* Unusual suspects. */
|
---|
[11236] | 938 | if (RT_UNLIKELY( Addr.au8[0] == 127 /* Loopback */
|
---|
| 939 | || (Addr.au8[0] & 0xf0) == 224 /* Multicast */
|
---|
[11053] | 940 | ))
|
---|
| 941 | return false;
|
---|
| 942 | return true;
|
---|
| 943 | }
|
---|
| 944 |
|
---|
| 945 |
|
---|
| 946 | /**
|
---|
[10923] | 947 | * Gets the address size of a network layer type.
|
---|
| 948 | *
|
---|
| 949 | * @returns size in bytes.
|
---|
| 950 | * @param enmType The type.
|
---|
| 951 | */
|
---|
| 952 | DECLINLINE(uint8_t) intnetR0AddrSize(INTNETADDRTYPE enmType)
|
---|
| 953 | {
|
---|
| 954 | switch (enmType)
|
---|
| 955 | {
|
---|
| 956 | case kIntNetAddrType_IPv4: return 4;
|
---|
| 957 | case kIntNetAddrType_IPv6: return 16;
|
---|
| 958 | case kIntNetAddrType_IPX: return 4 + 6;
|
---|
| 959 | default: AssertFailedReturn(0);
|
---|
| 960 | }
|
---|
| 961 | }
|
---|
| 962 |
|
---|
| 963 |
|
---|
| 964 | /**
|
---|
| 965 | * Compares two address to see if they are equal, assuming naturally align structures.
|
---|
| 966 | *
|
---|
| 967 | * @returns true if equal, false if not.
|
---|
| 968 | * @param pAddr1 The first address.
|
---|
| 969 | * @param pAddr2 The second address.
|
---|
| 970 | * @param cbAddr The address size.
|
---|
| 971 | */
|
---|
[10961] | 972 | DECLINLINE(bool) intnetR0AddrUIsEqualEx(PCRTNETADDRU pAddr1, PCRTNETADDRU pAddr2, uint8_t const cbAddr)
|
---|
[10923] | 973 | {
|
---|
| 974 | switch (cbAddr)
|
---|
| 975 | {
|
---|
| 976 | case 4: /* IPv4 */
|
---|
| 977 | return pAddr1->au32[0] == pAddr2->au32[0];
|
---|
| 978 | case 16: /* IPv6 */
|
---|
| 979 | return pAddr1->au64[0] == pAddr2->au64[0]
|
---|
| 980 | && pAddr1->au64[1] == pAddr2->au64[1];
|
---|
| 981 | case 10: /* IPX */
|
---|
| 982 | return pAddr1->au64[0] == pAddr2->au64[0]
|
---|
| 983 | && pAddr1->au16[4] == pAddr2->au16[4];
|
---|
| 984 | default:
|
---|
| 985 | AssertFailedReturn(false);
|
---|
| 986 | }
|
---|
| 987 | }
|
---|
| 988 |
|
---|
| 989 |
|
---|
| 990 | /**
|
---|
| 991 | * Worker for intnetR0IfAddrCacheLookup that performs the lookup
|
---|
| 992 | * in the remaining cache entries after the caller has check the
|
---|
| 993 | * most likely ones.
|
---|
| 994 | *
|
---|
| 995 | * @returns -1 if not found, the index of the cache entry if found.
|
---|
| 996 | * @param pCache The cache.
|
---|
| 997 | * @param pAddr The address.
|
---|
| 998 | * @param cbAddr The address size (optimization).
|
---|
| 999 | */
|
---|
[10961] | 1000 | static int intnetR0IfAddrCacheLookupSlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
|
---|
[10923] | 1001 | {
|
---|
| 1002 | unsigned i = pCache->cEntries - 2;
|
---|
| 1003 | uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
|
---|
| 1004 | while (i >= 1)
|
---|
| 1005 | {
|
---|
[10961] | 1006 | if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr))
|
---|
[10923] | 1007 | return i;
|
---|
| 1008 | pbEntry -= pCache->cbEntry;
|
---|
| 1009 | i--;
|
---|
| 1010 | }
|
---|
| 1011 |
|
---|
| 1012 | return -1;
|
---|
| 1013 | }
|
---|
| 1014 |
|
---|
| 1015 | /**
|
---|
| 1016 | * Lookup an address in a cache without any expectations.
|
---|
| 1017 | *
|
---|
| 1018 | * @returns -1 if not found, the index of the cache entry if found.
|
---|
| 1019 | * @param pCache The cache.
|
---|
| 1020 | * @param pAddr The address.
|
---|
| 1021 | * @param cbAddr The address size (optimization).
|
---|
| 1022 | */
|
---|
[10961] | 1023 | DECLINLINE(int) intnetR0IfAddrCacheLookup(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
|
---|
[10923] | 1024 | {
|
---|
| 1025 | Assert(pCache->cbAddress == cbAddr);
|
---|
| 1026 |
|
---|
| 1027 | /*
|
---|
| 1028 | * The optimized case is when there is one cache entry and
|
---|
| 1029 | * it doesn't match.
|
---|
| 1030 | */
|
---|
| 1031 | unsigned i = pCache->cEntries;
|
---|
| 1032 | if ( i > 0
|
---|
[10961] | 1033 | && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr))
|
---|
[10923] | 1034 | return 0;
|
---|
| 1035 | if (i <= 1)
|
---|
| 1036 | return -1;
|
---|
| 1037 |
|
---|
| 1038 | /*
|
---|
| 1039 | * Check the last entry.
|
---|
| 1040 | */
|
---|
| 1041 | i--;
|
---|
[10961] | 1042 | if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr))
|
---|
[10923] | 1043 | return i;
|
---|
| 1044 | if (i <= 1)
|
---|
| 1045 | return -1;
|
---|
| 1046 |
|
---|
| 1047 | return intnetR0IfAddrCacheLookupSlow(pCache, pAddr, cbAddr);
|
---|
| 1048 | }
|
---|
| 1049 |
|
---|
[10961] | 1050 |
|
---|
[10923] | 1051 | /** Same as intnetR0IfAddrCacheLookup except we expect the address to be present already. */
|
---|
[10961] | 1052 | DECLINLINE(int) intnetR0IfAddrCacheLookupLikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
|
---|
[10923] | 1053 | {
|
---|
| 1054 | /** @todo implement this. */
|
---|
| 1055 | return intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
|
---|
| 1056 | }
|
---|
| 1057 |
|
---|
[63458] | 1058 | #if 0 /* unused */
|
---|
| 1059 |
|
---|
[10923] | 1060 | /**
|
---|
| 1061 | * Worker for intnetR0IfAddrCacheLookupUnlikely that performs
|
---|
| 1062 | * the lookup in the remaining cache entries after the caller
|
---|
| 1063 | * has check the most likely ones.
|
---|
| 1064 | *
|
---|
| 1065 | * The routine is expecting not to find the address.
|
---|
| 1066 | *
|
---|
| 1067 | * @returns -1 if not found, the index of the cache entry if found.
|
---|
| 1068 | * @param pCache The cache.
|
---|
| 1069 | * @param pAddr The address.
|
---|
| 1070 | * @param cbAddr The address size (optimization).
|
---|
| 1071 | */
|
---|
[10961] | 1072 | static int intnetR0IfAddrCacheInCacheUnlikelySlow(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
|
---|
[10923] | 1073 | {
|
---|
| 1074 | /*
|
---|
| 1075 | * Perform a full table lookup.
|
---|
| 1076 | */
|
---|
| 1077 | unsigned i = pCache->cEntries - 2;
|
---|
| 1078 | uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
|
---|
| 1079 | while (i >= 1)
|
---|
| 1080 | {
|
---|
[10961] | 1081 | if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
|
---|
[10923] | 1082 | return i;
|
---|
| 1083 | pbEntry -= pCache->cbEntry;
|
---|
| 1084 | i--;
|
---|
| 1085 | }
|
---|
| 1086 |
|
---|
| 1087 | return -1;
|
---|
| 1088 | }
|
---|
| 1089 |
|
---|
| 1090 |
|
---|
| 1091 | /**
|
---|
| 1092 | * Lookup an address in a cache expecting not to find it.
|
---|
| 1093 | *
|
---|
| 1094 | * @returns -1 if not found, the index of the cache entry if found.
|
---|
| 1095 | * @param pCache The cache.
|
---|
| 1096 | * @param pAddr The address.
|
---|
| 1097 | * @param cbAddr The address size (optimization).
|
---|
| 1098 | */
|
---|
[10961] | 1099 | DECLINLINE(int) intnetR0IfAddrCacheLookupUnlikely(PCINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr)
|
---|
[10923] | 1100 | {
|
---|
| 1101 | Assert(pCache->cbAddress == cbAddr);
|
---|
| 1102 |
|
---|
| 1103 | /*
|
---|
| 1104 | * The optimized case is when there is one cache entry and
|
---|
| 1105 | * it doesn't match.
|
---|
| 1106 | */
|
---|
| 1107 | unsigned i = pCache->cEntries;
|
---|
| 1108 | if (RT_UNLIKELY( i > 0
|
---|
[10961] | 1109 | && intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr)))
|
---|
[10923] | 1110 | return 0;
|
---|
| 1111 | if (RT_LIKELY(i <= 1))
|
---|
| 1112 | return -1;
|
---|
| 1113 |
|
---|
| 1114 | /*
|
---|
| 1115 | * Then check the last entry and return if there are just two cache entries.
|
---|
| 1116 | */
|
---|
| 1117 | i--;
|
---|
[10961] | 1118 | if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * i), pAddr, cbAddr)))
|
---|
[10923] | 1119 | return i;
|
---|
| 1120 | if (i <= 1)
|
---|
| 1121 | return -1;
|
---|
| 1122 |
|
---|
| 1123 | return intnetR0IfAddrCacheInCacheUnlikelySlow(pCache, pAddr, cbAddr);
|
---|
| 1124 | }
|
---|
| 1125 |
|
---|
[63458] | 1126 | #endif /* unused */
|
---|
[10923] | 1127 |
|
---|
[63458] | 1128 |
|
---|
[10923] | 1129 | /**
|
---|
| 1130 | * Deletes a specific cache entry.
|
---|
| 1131 | *
|
---|
| 1132 | * Worker for intnetR0NetworkAddrCacheDelete and intnetR0NetworkAddrCacheDeleteMinusIf.
|
---|
| 1133 | *
|
---|
| 1134 | * @param pIf The interface (for logging).
|
---|
| 1135 | * @param pCache The cache.
|
---|
| 1136 | * @param iEntry The entry to delete.
|
---|
[11069] | 1137 | * @param pszMsg Log message.
|
---|
[10923] | 1138 | */
|
---|
[11069] | 1139 | static void intnetR0IfAddrCacheDeleteIt(PINTNETIF pIf, PINTNETADDRCACHE pCache, int iEntry, const char *pszMsg)
|
---|
[10923] | 1140 | {
|
---|
[11073] | 1141 | AssertReturnVoid(iEntry < pCache->cEntries);
|
---|
[11123] | 1142 | AssertReturnVoid(iEntry >= 0);
|
---|
| 1143 | #ifdef LOG_ENABLED
|
---|
| 1144 | INTNETADDRTYPE enmAddrType = (INTNETADDRTYPE)(uintptr_t)(pCache - &pIf->aAddrCache[0]);
|
---|
| 1145 | PCRTNETADDRU pAddr = (PCRTNETADDRU)(pCache->pbEntries + iEntry * pCache->cbEntry);
|
---|
| 1146 | switch (enmAddrType)
|
---|
| 1147 | {
|
---|
| 1148 | case kIntNetAddrType_IPv4:
|
---|
[45716] | 1149 | Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv4 deleted #%d %RTnaipv4 %s\n",
|
---|
| 1150 | pIf->hIf, &pIf->MacAddr, iEntry, pAddr->IPv4, pszMsg));
|
---|
[11123] | 1151 | break;
|
---|
[45716] | 1152 | case kIntNetAddrType_IPv6:
|
---|
| 1153 | Log(("intnetR0IfAddrCacheDeleteIt: hIf=%#x MAC=%.6Rhxs IPv6 deleted #%d %RTnaipv6 %s\n",
|
---|
[56880] | 1154 | pIf->hIf, &pIf->MacAddr, iEntry, &pAddr->IPv6, pszMsg));
|
---|
[45716] | 1155 | break;
|
---|
[11123] | 1156 | default:
|
---|
| 1157 | Log(("intnetR0IfAddrCacheDeleteIt: hIf=%RX32 MAC=%.6Rhxs type=%d #%d %.*Rhxs %s\n",
|
---|
[28623] | 1158 | pIf->hIf, &pIf->MacAddr, enmAddrType, iEntry, pCache->cbAddress, pAddr, pszMsg));
|
---|
[11123] | 1159 | break;
|
---|
| 1160 | }
|
---|
[62628] | 1161 | #else
|
---|
| 1162 | RT_NOREF2(pIf, pszMsg);
|
---|
[11123] | 1163 | #endif
|
---|
| 1164 |
|
---|
[10923] | 1165 | pCache->cEntries--;
|
---|
| 1166 | if (iEntry < pCache->cEntries)
|
---|
| 1167 | memmove(pCache->pbEntries + iEntry * pCache->cbEntry,
|
---|
| 1168 | pCache->pbEntries + (iEntry + 1) * pCache->cbEntry,
|
---|
| 1169 | (pCache->cEntries - iEntry) * pCache->cbEntry);
|
---|
| 1170 | }
|
---|
| 1171 |
|
---|
| 1172 |
|
---|
| 1173 | /**
|
---|
| 1174 | * Deletes an address from the cache, assuming it isn't actually in the cache.
|
---|
| 1175 | *
|
---|
[28623] | 1176 | * May or may not own the spinlock when calling this.
|
---|
| 1177 | *
|
---|
[10923] | 1178 | * @param pIf The interface (for logging).
|
---|
| 1179 | * @param pCache The cache.
|
---|
| 1180 | * @param pAddr The address.
|
---|
| 1181 | * @param cbAddr The address size (optimization).
|
---|
| 1182 | */
|
---|
[11072] | 1183 | DECLINLINE(void) intnetR0IfAddrCacheDelete(PINTNETIF pIf, PINTNETADDRCACHE pCache, PCRTNETADDRU pAddr, uint8_t const cbAddr, const char *pszMsg)
|
---|
[10923] | 1184 | {
|
---|
| 1185 | int i = intnetR0IfAddrCacheLookup(pCache, pAddr, cbAddr);
|
---|
| 1186 | if (RT_UNLIKELY(i >= 0))
|
---|
[11072] | 1187 | intnetR0IfAddrCacheDeleteIt(pIf, pCache, i, pszMsg);
|
---|
[10923] | 1188 | }
|
---|
| 1189 |
|
---|
| 1190 |
|
---|
| 1191 | /**
|
---|
| 1192 | * Deletes the address from all the interface caches.
|
---|
| 1193 | *
|
---|
| 1194 | * This is used to remove stale entries that has been reassigned to
|
---|
| 1195 | * other machines on the network.
|
---|
| 1196 | *
|
---|
| 1197 | * @param pNetwork The network.
|
---|
| 1198 | * @param pAddr The address.
|
---|
| 1199 | * @param enmType The address type.
|
---|
| 1200 | * @param cbAddr The address size (optimization).
|
---|
[11069] | 1201 | * @param pszMsg Log message.
|
---|
[10923] | 1202 | */
|
---|
[56146] | 1203 | DECLINLINE(void) intnetR0NetworkAddrCacheDeleteLocked(PINTNETNETWORK pNetwork,
|
---|
| 1204 | PCRTNETADDRU pAddr, INTNETADDRTYPE enmType,
|
---|
| 1205 | uint8_t const cbAddr,
|
---|
| 1206 | const char *pszMsg)
|
---|
[10923] | 1207 | {
|
---|
[28623] | 1208 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 1209 | while (iIf--)
|
---|
[10923] | 1210 | {
|
---|
[28623] | 1211 | PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
[55652] | 1212 |
|
---|
[10923] | 1213 | int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
|
---|
| 1214 | if (RT_UNLIKELY(i >= 0))
|
---|
[11069] | 1215 | intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
|
---|
[10923] | 1216 | }
|
---|
[55652] | 1217 | }
|
---|
[28623] | 1218 |
|
---|
[55652] | 1219 |
|
---|
| 1220 | /**
|
---|
| 1221 | * Deletes the address from all the interface caches.
|
---|
| 1222 | *
|
---|
| 1223 | * This is used to remove stale entries that has been reassigned to
|
---|
| 1224 | * other machines on the network.
|
---|
| 1225 | *
|
---|
| 1226 | * @param pNetwork The network.
|
---|
| 1227 | * @param pAddr The address.
|
---|
| 1228 | * @param enmType The address type.
|
---|
| 1229 | * @param cbAddr The address size (optimization).
|
---|
| 1230 | * @param pszMsg Log message.
|
---|
| 1231 | */
|
---|
| 1232 | DECLINLINE(void) intnetR0NetworkAddrCacheDelete(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType,
|
---|
| 1233 | uint8_t const cbAddr, const char *pszMsg)
|
---|
| 1234 | {
|
---|
| 1235 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
| 1236 |
|
---|
[56146] | 1237 | intnetR0NetworkAddrCacheDeleteLocked(pNetwork, pAddr, enmType, cbAddr, pszMsg);
|
---|
[55652] | 1238 |
|
---|
[52618] | 1239 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[10923] | 1240 | }
|
---|
| 1241 |
|
---|
| 1242 |
|
---|
[63458] | 1243 | #if 0 /* unused */
|
---|
[10923] | 1244 | /**
|
---|
| 1245 | * Deletes the address from all the interface caches except the specified one.
|
---|
| 1246 | *
|
---|
| 1247 | * This is used to remove stale entries that has been reassigned to
|
---|
| 1248 | * other machines on the network.
|
---|
| 1249 | *
|
---|
| 1250 | * @param pNetwork The network.
|
---|
| 1251 | * @param pAddr The address.
|
---|
| 1252 | * @param enmType The address type.
|
---|
| 1253 | * @param cbAddr The address size (optimization).
|
---|
[11069] | 1254 | * @param pszMsg Log message.
|
---|
[10923] | 1255 | */
|
---|
[10961] | 1256 | DECLINLINE(void) intnetR0NetworkAddrCacheDeleteMinusIf(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCRTNETADDRU pAddr,
|
---|
[11069] | 1257 | INTNETADDRTYPE const enmType, uint8_t const cbAddr, const char *pszMsg)
|
---|
[10923] | 1258 | {
|
---|
[40806] | 1259 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1260 |
|
---|
| 1261 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 1262 | while (iIf--)
|
---|
| 1263 | {
|
---|
| 1264 | PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
[10923] | 1265 | if (pIf != pIfSender)
|
---|
| 1266 | {
|
---|
| 1267 | int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
|
---|
| 1268 | if (RT_UNLIKELY(i >= 0))
|
---|
[11069] | 1269 | intnetR0IfAddrCacheDeleteIt(pIf, &pIf->aAddrCache[enmType], i, pszMsg);
|
---|
[10923] | 1270 | }
|
---|
[28623] | 1271 | }
|
---|
| 1272 |
|
---|
[52618] | 1273 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[10923] | 1274 | }
|
---|
[63478] | 1275 | #endif /* unused */
|
---|
[10923] | 1276 |
|
---|
| 1277 |
|
---|
| 1278 | /**
|
---|
[28666] | 1279 | * Lookup an address on the network, returning the (first) interface having it
|
---|
| 1280 | * in its address cache.
|
---|
[11072] | 1281 | *
|
---|
[28623] | 1282 | * @returns Pointer to the interface on success, NULL if not found. The caller
|
---|
| 1283 | * must release the interface by calling intnetR0BusyDecIf.
|
---|
[11072] | 1284 | * @param pNetwork The network.
|
---|
| 1285 | * @param pAddr The address to lookup.
|
---|
| 1286 | * @param enmType The address type.
|
---|
| 1287 | * @param cbAddr The size of the address.
|
---|
| 1288 | */
|
---|
| 1289 | DECLINLINE(PINTNETIF) intnetR0NetworkAddrCacheLookupIf(PINTNETNETWORK pNetwork, PCRTNETADDRU pAddr, INTNETADDRTYPE const enmType, uint8_t const cbAddr)
|
---|
| 1290 | {
|
---|
[40806] | 1291 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1292 |
|
---|
| 1293 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 1294 | while (iIf--)
|
---|
[11072] | 1295 | {
|
---|
[28623] | 1296 | PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
[11072] | 1297 | int i = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmType], pAddr, cbAddr);
|
---|
| 1298 | if (i >= 0)
|
---|
[28623] | 1299 | {
|
---|
| 1300 | intnetR0BusyIncIf(pIf);
|
---|
[52618] | 1301 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[11072] | 1302 | return pIf;
|
---|
[28623] | 1303 | }
|
---|
[11072] | 1304 | }
|
---|
[28623] | 1305 |
|
---|
[52618] | 1306 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[11072] | 1307 | return NULL;
|
---|
| 1308 | }
|
---|
| 1309 |
|
---|
| 1310 |
|
---|
| 1311 | /**
|
---|
[55652] | 1312 | * Look up specified address in the network's blacklist.
|
---|
| 1313 | *
|
---|
[56316] | 1314 | * @param pNetwork The network.
|
---|
[55652] | 1315 | * @param enmType The address type.
|
---|
| 1316 | * @param pAddr The address.
|
---|
| 1317 | */
|
---|
| 1318 | static bool intnetR0NetworkBlacklistLookup(PINTNETNETWORK pNetwork,
|
---|
| 1319 | PCRTNETADDRU pAddr, INTNETADDRTYPE enmType)
|
---|
| 1320 | {
|
---|
| 1321 | PINTNETADDRCACHE pCache = &pNetwork->aAddrBlacklist[enmType];
|
---|
| 1322 |
|
---|
| 1323 | if (RT_UNLIKELY(pCache->cEntriesAlloc == 0))
|
---|
| 1324 | return false;
|
---|
| 1325 |
|
---|
| 1326 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1327 | Assert(cbAddr == intnetR0AddrSize(enmType));
|
---|
| 1328 |
|
---|
| 1329 | for (unsigned i = 0; i < pCache->cEntries; ++i)
|
---|
| 1330 | {
|
---|
| 1331 | uint8_t *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
|
---|
| 1332 | if (intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr))
|
---|
| 1333 | return true;
|
---|
| 1334 | }
|
---|
| 1335 |
|
---|
| 1336 | return false;
|
---|
| 1337 | }
|
---|
| 1338 |
|
---|
| 1339 |
|
---|
| 1340 | /**
|
---|
| 1341 | * Deletes specified address from network's blacklist.
|
---|
| 1342 | *
|
---|
[56316] | 1343 | * @param pNetwork The network.
|
---|
[55652] | 1344 | * @param enmType The address type.
|
---|
| 1345 | * @param pAddr The address.
|
---|
| 1346 | */
|
---|
| 1347 | static void intnetR0NetworkBlacklistDelete(PINTNETNETWORK pNetwork,
|
---|
| 1348 | PCRTNETADDRU pAddr, INTNETADDRTYPE enmType)
|
---|
| 1349 | {
|
---|
| 1350 | PINTNETADDRCACHE pCache = &pNetwork->aAddrBlacklist[enmType];
|
---|
| 1351 |
|
---|
| 1352 | if (RT_UNLIKELY(pCache->cEntriesAlloc == 0))
|
---|
| 1353 | return;
|
---|
| 1354 |
|
---|
| 1355 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1356 | Assert(cbAddr == intnetR0AddrSize(enmType));
|
---|
| 1357 |
|
---|
| 1358 | for (unsigned i = 0; i < pCache->cEntries; ++i)
|
---|
| 1359 | {
|
---|
| 1360 | uint8_t *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
|
---|
| 1361 | if (!intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr))
|
---|
| 1362 | continue;
|
---|
| 1363 |
|
---|
| 1364 | --pCache->cEntries;
|
---|
| 1365 | memmove(pCache->pbEntries + i * pCache->cbEntry,
|
---|
| 1366 | pCache->pbEntries + (i + 1) * pCache->cbEntry,
|
---|
| 1367 | (pCache->cEntries - i) * pCache->cbEntry);
|
---|
| 1368 | return;
|
---|
| 1369 | }
|
---|
| 1370 | }
|
---|
| 1371 |
|
---|
| 1372 |
|
---|
| 1373 | /**
|
---|
| 1374 | * Adds specified address from network's blacklist.
|
---|
| 1375 | *
|
---|
[56316] | 1376 | * @param pNetwork The network.
|
---|
[55652] | 1377 | * @param enmType The address type.
|
---|
| 1378 | * @param pAddr The address.
|
---|
| 1379 | */
|
---|
| 1380 | static void intnetR0NetworkBlacklistAdd(PINTNETNETWORK pNetwork,
|
---|
| 1381 | PCRTNETADDRU pAddr, INTNETADDRTYPE enmType)
|
---|
| 1382 | {
|
---|
| 1383 | PINTNETADDRCACHE pCache = &pNetwork->aAddrBlacklist[enmType];
|
---|
| 1384 |
|
---|
| 1385 | if (RT_UNLIKELY(pCache->cEntriesAlloc == 0))
|
---|
| 1386 | return;
|
---|
| 1387 |
|
---|
| 1388 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1389 | Assert(cbAddr == intnetR0AddrSize(enmType));
|
---|
| 1390 |
|
---|
| 1391 | /* lookup */
|
---|
| 1392 | for (unsigned i = 0; i < pCache->cEntries; ++i)
|
---|
| 1393 | {
|
---|
| 1394 | uint8_t *pbEntry = pCache->pbEntries + pCache->cbEntry * i;
|
---|
| 1395 | if (RT_UNLIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
|
---|
| 1396 | return; /* already exists */
|
---|
| 1397 | }
|
---|
| 1398 |
|
---|
| 1399 | if (pCache->cEntries >= pCache->cEntriesAlloc)
|
---|
| 1400 | {
|
---|
| 1401 | /* shift */
|
---|
[56316] | 1402 | memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry,
|
---|
[55652] | 1403 | pCache->cbEntry * (pCache->cEntries - 1));
|
---|
| 1404 | --pCache->cEntries;
|
---|
| 1405 | }
|
---|
| 1406 |
|
---|
| 1407 | Assert(pCache->cEntries < pCache->cEntriesAlloc);
|
---|
| 1408 |
|
---|
| 1409 | /* push */
|
---|
| 1410 | uint8_t *pbEntry = pCache->pbEntries + pCache->cEntries * pCache->cbEntry;
|
---|
| 1411 | memcpy(pbEntry, pAddr, cbAddr);
|
---|
| 1412 | memset(pbEntry + pCache->cbAddress, '\0', pCache->cbEntry - cbAddr);
|
---|
| 1413 | ++pCache->cEntries;
|
---|
| 1414 |
|
---|
| 1415 | Assert(pCache->cEntries <= pCache->cEntriesAlloc);
|
---|
| 1416 | }
|
---|
| 1417 |
|
---|
| 1418 |
|
---|
| 1419 | /**
|
---|
[28623] | 1420 | * Adds an address to the cache, the caller is responsible for making sure it's
|
---|
| 1421 | * not already in the cache.
|
---|
[10923] | 1422 | *
|
---|
[28623] | 1423 | * The caller must not
|
---|
| 1424 | *
|
---|
[10923] | 1425 | * @param pIf The interface (for logging).
|
---|
| 1426 | * @param pCache The address cache.
|
---|
| 1427 | * @param pAddr The address.
|
---|
[11069] | 1428 | * @param pszMsg log message.
|
---|
[10923] | 1429 | */
|
---|
[55652] | 1430 | static void intnetR0IfAddrCacheAddIt(PINTNETIF pIf, INTNETADDRTYPE enmAddrType, PCRTNETADDRU pAddr,
|
---|
| 1431 | const char *pszMsg)
|
---|
[10923] | 1432 | {
|
---|
[28623] | 1433 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
| 1434 | AssertReturnVoid(pNetwork);
|
---|
[55652] | 1435 |
|
---|
| 1436 | PINTNETADDRCACHE pCache = &pIf->aAddrCache[enmAddrType];
|
---|
| 1437 |
|
---|
[62437] | 1438 | #if defined(LOG_ENABLED) || defined(VBOX_STRICT)
|
---|
[55652] | 1439 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1440 | Assert(cbAddr == intnetR0AddrSize(enmAddrType));
|
---|
[62437] | 1441 | #endif
|
---|
[55652] | 1442 |
|
---|
[40806] | 1443 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1444 |
|
---|
[55652] | 1445 | bool fBlacklisted = intnetR0NetworkBlacklistLookup(pNetwork, pAddr, enmAddrType);
|
---|
| 1446 | if (fBlacklisted)
|
---|
| 1447 | {
|
---|
| 1448 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
| 1449 |
|
---|
| 1450 | #ifdef LOG_ENABLED
|
---|
| 1451 | switch (enmAddrType)
|
---|
| 1452 | {
|
---|
| 1453 | case kIntNetAddrType_IPv4:
|
---|
| 1454 | Log(("%s: spoofing attempt for %RTnaipv4\n",
|
---|
| 1455 | __FUNCTION__, pAddr->IPv4));
|
---|
| 1456 | break;
|
---|
| 1457 | case kIntNetAddrType_IPv6:
|
---|
| 1458 | Log(("%s: spoofing attempt for %RTnaipv6\n",
|
---|
| 1459 | __FUNCTION__, &pAddr->IPv6));
|
---|
| 1460 | break;
|
---|
[56316] | 1461 | default:
|
---|
[55652] | 1462 | Log(("%s: spoofing attempt for %.*Rhxs (type %d)\n",
|
---|
| 1463 | __FUNCTION__, cbAddr, pAddr, enmAddrType));
|
---|
| 1464 | break;
|
---|
| 1465 | }
|
---|
| 1466 | #endif
|
---|
| 1467 | return;
|
---|
| 1468 | }
|
---|
| 1469 |
|
---|
[29362] | 1470 | if (RT_UNLIKELY(!pCache->cEntriesAlloc))
|
---|
[10923] | 1471 | {
|
---|
[29362] | 1472 | /* This shouldn't happen*/
|
---|
[52618] | 1473 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[29362] | 1474 | return;
|
---|
[10923] | 1475 | }
|
---|
[29362] | 1476 |
|
---|
| 1477 | /* When the table is full, drop the older entry (FIFO). Do proper ageing? */
|
---|
| 1478 | if (pCache->cEntries >= pCache->cEntriesAlloc)
|
---|
[28623] | 1479 | {
|
---|
| 1480 | Log(("intnetR0IfAddrCacheAddIt: type=%d replacing %.*Rhxs\n",
|
---|
| 1481 | (int)(uintptr_t)(pCache - &pIf->aAddrCache[0]), pCache->cbAddress, pCache->pbEntries));
|
---|
| 1482 | memmove(pCache->pbEntries, pCache->pbEntries + pCache->cbEntry, pCache->cbEntry * (pCache->cEntries - 1));
|
---|
| 1483 | pCache->cEntries--;
|
---|
[29362] | 1484 | Assert(pCache->cEntries < pCache->cEntriesAlloc);
|
---|
[28623] | 1485 | }
|
---|
[10923] | 1486 |
|
---|
| 1487 | /*
|
---|
| 1488 | * Add the new entry to the end of the array.
|
---|
| 1489 | */
|
---|
| 1490 | uint8_t *pbEntry = pCache->pbEntries + pCache->cEntries * pCache->cbEntry;
|
---|
| 1491 | memcpy(pbEntry, pAddr, pCache->cbAddress);
|
---|
| 1492 | memset(pbEntry + pCache->cbAddress, '\0', pCache->cbEntry - pCache->cbAddress);
|
---|
[55652] | 1493 |
|
---|
[11123] | 1494 | #ifdef LOG_ENABLED
|
---|
| 1495 | switch (enmAddrType)
|
---|
| 1496 | {
|
---|
| 1497 | case kIntNetAddrType_IPv4:
|
---|
[45716] | 1498 | Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv4 added #%d %RTnaipv4 %s\n",
|
---|
| 1499 | pIf->hIf, &pIf->MacAddr, pCache->cEntries, pAddr->IPv4, pszMsg));
|
---|
[11123] | 1500 | break;
|
---|
[45716] | 1501 | case kIntNetAddrType_IPv6:
|
---|
[48947] | 1502 | Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs IPv6 added #%d %RTnaipv6 %s\n",
|
---|
[56880] | 1503 | pIf->hIf, &pIf->MacAddr, pCache->cEntries, &pAddr->IPv6, pszMsg));
|
---|
[45716] | 1504 | break;
|
---|
[11123] | 1505 | default:
|
---|
| 1506 | Log(("intnetR0IfAddrCacheAddIt: hIf=%#x MAC=%.6Rhxs type=%d added #%d %.*Rhxs %s\n",
|
---|
[28623] | 1507 | pIf->hIf, &pIf->MacAddr, enmAddrType, pCache->cEntries, pCache->cbAddress, pAddr, pszMsg));
|
---|
[11123] | 1508 | break;
|
---|
| 1509 | }
|
---|
[62628] | 1510 | #else
|
---|
| 1511 | RT_NOREF1(pszMsg);
|
---|
[11123] | 1512 | #endif
|
---|
[10923] | 1513 | pCache->cEntries++;
|
---|
| 1514 | Assert(pCache->cEntries <= pCache->cEntriesAlloc);
|
---|
[28623] | 1515 |
|
---|
[52618] | 1516 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[10923] | 1517 | }
|
---|
| 1518 |
|
---|
| 1519 |
|
---|
| 1520 | /**
|
---|
| 1521 | * A intnetR0IfAddrCacheAdd worker that performs the rest of the lookup.
|
---|
| 1522 | *
|
---|
| 1523 | * @param pIf The interface (for logging).
|
---|
| 1524 | * @param pCache The address cache.
|
---|
| 1525 | * @param pAddr The address.
|
---|
| 1526 | * @param cbAddr The size of the address (optimization).
|
---|
[11069] | 1527 | * @param pszMsg Log message.
|
---|
[10923] | 1528 | */
|
---|
[55652] | 1529 | static void intnetR0IfAddrCacheAddSlow(PINTNETIF pIf, INTNETADDRTYPE enmAddrType, PCRTNETADDRU pAddr,
|
---|
| 1530 | const char *pszMsg)
|
---|
[10923] | 1531 | {
|
---|
[55652] | 1532 | PINTNETADDRCACHE pCache = &pIf->aAddrCache[enmAddrType];
|
---|
| 1533 |
|
---|
| 1534 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1535 | Assert(cbAddr == intnetR0AddrSize(enmAddrType));
|
---|
| 1536 |
|
---|
[10923] | 1537 | /*
|
---|
| 1538 | * Check all but the first and last entries, the caller
|
---|
| 1539 | * has already checked those.
|
---|
| 1540 | */
|
---|
[11117] | 1541 | int i = pCache->cEntries - 2;
|
---|
[10923] | 1542 | uint8_t const *pbEntry = pCache->pbEntries + pCache->cbEntry;
|
---|
[11117] | 1543 | while (i >= 1)
|
---|
[10923] | 1544 | {
|
---|
[10961] | 1545 | if (RT_LIKELY(intnetR0AddrUIsEqualEx((PCRTNETADDRU)pbEntry, pAddr, cbAddr)))
|
---|
[10923] | 1546 | return;
|
---|
| 1547 | pbEntry += pCache->cbEntry;
|
---|
[11117] | 1548 | i--;
|
---|
[10923] | 1549 | }
|
---|
| 1550 |
|
---|
| 1551 | /*
|
---|
| 1552 | * Not found, add it.
|
---|
| 1553 | */
|
---|
[55652] | 1554 | intnetR0IfAddrCacheAddIt(pIf, enmAddrType, pAddr, pszMsg);
|
---|
[10923] | 1555 | }
|
---|
| 1556 |
|
---|
| 1557 |
|
---|
| 1558 | /**
|
---|
| 1559 | * Adds an address to the cache if it's not already there.
|
---|
| 1560 | *
|
---|
[28623] | 1561 | * Must not own any spinlocks when calling this function.
|
---|
| 1562 | *
|
---|
[10923] | 1563 | * @param pIf The interface (for logging).
|
---|
| 1564 | * @param pCache The address cache.
|
---|
| 1565 | * @param pAddr The address.
|
---|
| 1566 | * @param cbAddr The size of the address (optimization).
|
---|
[11069] | 1567 | * @param pszMsg Log message.
|
---|
[10923] | 1568 | */
|
---|
[55652] | 1569 | DECLINLINE(void) intnetR0IfAddrCacheAdd(PINTNETIF pIf, INTNETADDRTYPE enmAddrType, PCRTNETADDRU pAddr,
|
---|
| 1570 | const char *pszMsg)
|
---|
[10923] | 1571 | {
|
---|
[55652] | 1572 | PINTNETADDRCACHE pCache = &pIf->aAddrCache[enmAddrType];
|
---|
[10923] | 1573 |
|
---|
[55652] | 1574 | const uint8_t cbAddr = pCache->cbAddress;
|
---|
| 1575 | Assert(cbAddr == intnetR0AddrSize(enmAddrType));
|
---|
| 1576 |
|
---|
[10923] | 1577 | /*
|
---|
[11117] | 1578 | * The optimized case is when the address the first or last cache entry.
|
---|
[10923] | 1579 | */
|
---|
| 1580 | unsigned i = pCache->cEntries;
|
---|
| 1581 | if (RT_LIKELY( i > 0
|
---|
[11117] | 1582 | && ( intnetR0AddrUIsEqualEx((PCRTNETADDRU)pCache->pbEntries, pAddr, cbAddr)
|
---|
| 1583 | || (i > 1
|
---|
[56879] | 1584 | && intnetR0AddrUIsEqualEx((PCRTNETADDRU)(pCache->pbEntries + pCache->cbEntry * (i-1)), pAddr, cbAddr))) ))
|
---|
[10923] | 1585 | return;
|
---|
[55652] | 1586 |
|
---|
| 1587 | intnetR0IfAddrCacheAddSlow(pIf, enmAddrType, pAddr, pszMsg);
|
---|
[10923] | 1588 | }
|
---|
| 1589 |
|
---|
| 1590 |
|
---|
[28623] | 1591 | /**
|
---|
[29362] | 1592 | * Destroys the specified address cache.
|
---|
| 1593 | * @param pCache The address cache.
|
---|
| 1594 | */
|
---|
| 1595 | static void intnetR0IfAddrCacheDestroy(PINTNETADDRCACHE pCache)
|
---|
| 1596 | {
|
---|
| 1597 | void *pvFree = pCache->pbEntries;
|
---|
| 1598 | pCache->pbEntries = NULL;
|
---|
| 1599 | pCache->cEntries = 0;
|
---|
| 1600 | pCache->cEntriesAlloc = 0;
|
---|
| 1601 | RTMemFree(pvFree);
|
---|
| 1602 | }
|
---|
| 1603 |
|
---|
| 1604 |
|
---|
| 1605 | /**
|
---|
| 1606 | * Initialize the address cache for the specified address type.
|
---|
| 1607 | *
|
---|
| 1608 | * The cache storage is preallocated and fixed size so that we can handle
|
---|
| 1609 | * inserts from problematic contexts.
|
---|
| 1610 | *
|
---|
| 1611 | * @returns VINF_SUCCESS or VERR_NO_MEMORY.
|
---|
| 1612 | * @param pCache The cache to initialize.
|
---|
| 1613 | * @param enmAddrType The address type.
|
---|
| 1614 | * @param fEnabled Whether the address cache is enabled or not.
|
---|
| 1615 | */
|
---|
| 1616 | static int intnetR0IfAddrCacheInit(PINTNETADDRCACHE pCache, INTNETADDRTYPE enmAddrType, bool fEnabled)
|
---|
| 1617 | {
|
---|
| 1618 | pCache->cEntries = 0;
|
---|
| 1619 | pCache->cbAddress = intnetR0AddrSize(enmAddrType);
|
---|
| 1620 | pCache->cbEntry = RT_ALIGN(pCache->cbAddress, 4);
|
---|
| 1621 | if (fEnabled)
|
---|
| 1622 | {
|
---|
| 1623 | pCache->cEntriesAlloc = 32;
|
---|
| 1624 | pCache->pbEntries = (uint8_t *)RTMemAllocZ(pCache->cEntriesAlloc * pCache->cbEntry);
|
---|
| 1625 | if (!pCache->pbEntries)
|
---|
| 1626 | return VERR_NO_MEMORY;
|
---|
| 1627 | }
|
---|
| 1628 | else
|
---|
| 1629 | {
|
---|
| 1630 | pCache->cEntriesAlloc = 0;
|
---|
| 1631 | pCache->pbEntries = NULL;
|
---|
| 1632 | }
|
---|
| 1633 | return VINF_SUCCESS;
|
---|
| 1634 | }
|
---|
| 1635 |
|
---|
| 1636 |
|
---|
| 1637 | /**
|
---|
[28623] | 1638 | * Is it a multicast or broadcast MAC address?
|
---|
| 1639 | *
|
---|
| 1640 | * @returns true if multicast, false if not.
|
---|
| 1641 | * @param pMacAddr The address to inspect.
|
---|
| 1642 | */
|
---|
| 1643 | DECL_FORCE_INLINE(bool) intnetR0IsMacAddrMulticast(PCRTMAC pMacAddr)
|
---|
| 1644 | {
|
---|
| 1645 | return !!(pMacAddr->au8[0] & 0x01);
|
---|
| 1646 | }
|
---|
| 1647 |
|
---|
| 1648 |
|
---|
| 1649 | /**
|
---|
| 1650 | * Is it a dummy MAC address?
|
---|
| 1651 | *
|
---|
| 1652 | * We use dummy MAC addresses for interfaces which we don't know the MAC
|
---|
| 1653 | * address of because they haven't sent anything (learning) or explicitly set
|
---|
| 1654 | * it.
|
---|
| 1655 | *
|
---|
| 1656 | * @returns true if dummy, false if not.
|
---|
| 1657 | * @param pMacAddr The address to inspect.
|
---|
| 1658 | */
|
---|
| 1659 | DECL_FORCE_INLINE(bool) intnetR0IsMacAddrDummy(PCRTMAC pMacAddr)
|
---|
| 1660 | {
|
---|
| 1661 | /* The dummy address are broadcast addresses, don't bother check it all. */
|
---|
| 1662 | return pMacAddr->au16[0] == 0xffff;
|
---|
| 1663 | }
|
---|
| 1664 |
|
---|
| 1665 |
|
---|
| 1666 | /**
|
---|
| 1667 | * Compares two MAC addresses.
|
---|
| 1668 | *
|
---|
| 1669 | * @returns true if equal, false if not.
|
---|
| 1670 | * @param pDstAddr1 Address 1.
|
---|
| 1671 | * @param pDstAddr2 Address 2.
|
---|
| 1672 | */
|
---|
| 1673 | DECL_FORCE_INLINE(bool) intnetR0AreMacAddrsEqual(PCRTMAC pDstAddr1, PCRTMAC pDstAddr2)
|
---|
| 1674 | {
|
---|
| 1675 | return pDstAddr1->au16[2] == pDstAddr2->au16[2]
|
---|
| 1676 | && pDstAddr1->au16[1] == pDstAddr2->au16[1]
|
---|
| 1677 | && pDstAddr1->au16[0] == pDstAddr2->au16[0];
|
---|
| 1678 | }
|
---|
| 1679 |
|
---|
| 1680 |
|
---|
| 1681 | /**
|
---|
| 1682 | * Switch a unicast frame based on the network layer address (OSI level 3) and
|
---|
| 1683 | * return a destination table.
|
---|
| 1684 | *
|
---|
| 1685 | * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
|
---|
| 1686 | * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
|
---|
| 1687 | * @param pNetwork The network to switch on.
|
---|
| 1688 | * @param pDstMacAddr The destination MAC address.
|
---|
| 1689 | * @param enmL3AddrType The level-3 destination address type.
|
---|
| 1690 | * @param pL3Addr The level-3 destination address.
|
---|
| 1691 | * @param cbL3Addr The size of the level-3 destination address.
|
---|
| 1692 | * @param fSrc The frame source (INTNETTRUNKDIR_WIRE).
|
---|
| 1693 | * @param pDstTab The destination output table.
|
---|
| 1694 | */
|
---|
| 1695 | static INTNETSWDECISION intnetR0NetworkSwitchLevel3(PINTNETNETWORK pNetwork, PCRTMAC pDstMacAddr,
|
---|
| 1696 | INTNETADDRTYPE enmL3AddrType, PCRTNETADDRU pL3Addr, uint8_t cbL3Addr,
|
---|
| 1697 | uint32_t fSrc, PINTNETDSTTAB pDstTab)
|
---|
| 1698 | {
|
---|
| 1699 | Assert(fSrc == INTNETTRUNKDIR_WIRE);
|
---|
| 1700 |
|
---|
| 1701 | /*
|
---|
| 1702 | * Grab the spinlock first and do the switching.
|
---|
| 1703 | */
|
---|
| 1704 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
[40806] | 1705 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1706 |
|
---|
| 1707 | pDstTab->fTrunkDst = 0;
|
---|
| 1708 | pDstTab->pTrunk = 0;
|
---|
| 1709 | pDstTab->cIfs = 0;
|
---|
| 1710 |
|
---|
| 1711 | /* Find exactly matching or promiscuous interfaces. */
|
---|
| 1712 | uint32_t cExactHits = 0;
|
---|
| 1713 | uint32_t iIfMac = pTab->cEntries;
|
---|
| 1714 | while (iIfMac-- > 0)
|
---|
| 1715 | {
|
---|
| 1716 | if (pTab->paEntries[iIfMac].fActive)
|
---|
| 1717 | {
|
---|
| 1718 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
[28624] | 1719 | bool fExact = intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr) >= 0;
|
---|
[36075] | 1720 | if (fExact || pTab->paEntries[iIfMac].fPromiscuousSeeTrunk)
|
---|
[28623] | 1721 | {
|
---|
| 1722 | cExactHits += fExact;
|
---|
| 1723 |
|
---|
| 1724 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 1725 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 1726 | pDstTab->aIfs[iIfDst].fReplaceDstMac = fExact;
|
---|
[38937] | 1727 | intnetR0BusyIncIf(pIf);
|
---|
| 1728 |
|
---|
[38936] | 1729 | if (fExact)
|
---|
[38937] | 1730 | pDstMacAddr = &pIf->MacAddr; /* Avoids duplicates being sent to the host. */
|
---|
[28623] | 1731 | }
|
---|
| 1732 | }
|
---|
| 1733 | }
|
---|
| 1734 |
|
---|
[36089] | 1735 | /* Network only promicuous mode ifs should see related trunk traffic. */
|
---|
| 1736 | if ( cExactHits
|
---|
| 1737 | && fSrc
|
---|
| 1738 | && pNetwork->MacTab.cPromiscuousNoTrunkEntries)
|
---|
| 1739 | {
|
---|
| 1740 | iIfMac = pTab->cEntries;
|
---|
| 1741 | while (iIfMac-- > 0)
|
---|
| 1742 | {
|
---|
| 1743 | if ( pTab->paEntries[iIfMac].fActive
|
---|
| 1744 | && pTab->paEntries[iIfMac].fPromiscuousEff
|
---|
| 1745 | && !pTab->paEntries[iIfMac].fPromiscuousSeeTrunk)
|
---|
| 1746 | {
|
---|
| 1747 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
| 1748 | if (intnetR0IfAddrCacheLookup(&pIf->aAddrCache[enmL3AddrType], pL3Addr, cbL3Addr) < 0)
|
---|
| 1749 | {
|
---|
| 1750 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 1751 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 1752 | pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
|
---|
| 1753 | intnetR0BusyIncIf(pIf);
|
---|
| 1754 | }
|
---|
| 1755 | }
|
---|
| 1756 | }
|
---|
| 1757 | }
|
---|
| 1758 |
|
---|
[28623] | 1759 | /* Does it match the host, or is the host promiscuous? */
|
---|
| 1760 | if (pTab->fHostActive)
|
---|
| 1761 | {
|
---|
| 1762 | bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstMacAddr);
|
---|
| 1763 | if ( fExact
|
---|
| 1764 | || intnetR0IsMacAddrDummy(&pTab->HostMac)
|
---|
[36075] | 1765 | || pTab->fHostPromiscuousEff)
|
---|
[28623] | 1766 | {
|
---|
| 1767 | cExactHits += fExact;
|
---|
| 1768 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
|
---|
| 1769 | }
|
---|
| 1770 | }
|
---|
| 1771 |
|
---|
| 1772 | /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
|
---|
[36075] | 1773 | if (pTab->fWireActive && (!cExactHits || pTab->fWirePromiscuousEff))
|
---|
[28623] | 1774 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
|
---|
| 1775 | pDstTab->fTrunkDst &= ~fSrc;
|
---|
| 1776 | if (pDstTab->fTrunkDst)
|
---|
| 1777 | {
|
---|
| 1778 | PINTNETTRUNKIF pTrunk = pTab->pTrunk;
|
---|
| 1779 | pDstTab->pTrunk = pTrunk;
|
---|
| 1780 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 1781 | }
|
---|
| 1782 |
|
---|
[52618] | 1783 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1784 | return pDstTab->cIfs
|
---|
| 1785 | ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
|
---|
| 1786 | : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK);
|
---|
| 1787 | }
|
---|
| 1788 |
|
---|
| 1789 |
|
---|
| 1790 | /**
|
---|
[30557] | 1791 | * Pre-switch a unicast MAC address.
|
---|
| 1792 | *
|
---|
| 1793 | * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
|
---|
| 1794 | * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
|
---|
| 1795 | * @param pNetwork The network to switch on.
|
---|
| 1796 | * @param fSrc The frame source.
|
---|
| 1797 | * @param pSrcAddr The source address of the frame.
|
---|
| 1798 | * @param pDstAddr The destination address of the frame.
|
---|
| 1799 | */
|
---|
| 1800 | static INTNETSWDECISION intnetR0NetworkPreSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PCRTMAC pSrcAddr,
|
---|
| 1801 | PCRTMAC pDstAddr)
|
---|
| 1802 | {
|
---|
| 1803 | Assert(!intnetR0IsMacAddrMulticast(pDstAddr));
|
---|
[36075] | 1804 | Assert(fSrc);
|
---|
[30557] | 1805 |
|
---|
| 1806 | /*
|
---|
| 1807 | * Grab the spinlock first and do the switching.
|
---|
| 1808 | */
|
---|
| 1809 | INTNETSWDECISION enmSwDecision = INTNETSWDECISION_BROADCAST;
|
---|
| 1810 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
[40806] | 1811 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[30557] | 1812 |
|
---|
| 1813 | /* Iterate the internal network interfaces and look for matching source and
|
---|
| 1814 | destination addresses. */
|
---|
[39040] | 1815 | uint32_t iIfMac = pTab->cEntries;
|
---|
[30557] | 1816 | while (iIfMac-- > 0)
|
---|
| 1817 | {
|
---|
| 1818 | if (pTab->paEntries[iIfMac].fActive)
|
---|
| 1819 | {
|
---|
| 1820 | /* Unknown interface address? */
|
---|
| 1821 | if (intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr))
|
---|
| 1822 | break;
|
---|
| 1823 |
|
---|
| 1824 | /* Paranoia - this shouldn't happen, right? */
|
---|
| 1825 | if ( pSrcAddr
|
---|
| 1826 | && intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pSrcAddr))
|
---|
| 1827 | break;
|
---|
| 1828 |
|
---|
| 1829 | /* Exact match? */
|
---|
| 1830 | if (intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr))
|
---|
| 1831 | {
|
---|
[36075] | 1832 | enmSwDecision = pTab->fHostPromiscuousEff && fSrc == INTNETTRUNKDIR_WIRE
|
---|
[30557] | 1833 | ? INTNETSWDECISION_BROADCAST
|
---|
| 1834 | : INTNETSWDECISION_INTNET;
|
---|
| 1835 | break;
|
---|
| 1836 | }
|
---|
| 1837 | }
|
---|
| 1838 | }
|
---|
| 1839 |
|
---|
[52618] | 1840 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[30557] | 1841 | return enmSwDecision;
|
---|
| 1842 | }
|
---|
| 1843 |
|
---|
| 1844 |
|
---|
| 1845 | /**
|
---|
[28623] | 1846 | * Switch a unicast MAC address and return a destination table.
|
---|
| 1847 | *
|
---|
| 1848 | * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
|
---|
| 1849 | * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
|
---|
| 1850 | * @param pNetwork The network to switch on.
|
---|
| 1851 | * @param fSrc The frame source.
|
---|
| 1852 | * @param pIfSender The sender interface, NULL if trunk. Used to
|
---|
| 1853 | * prevent sending an echo to the sender.
|
---|
| 1854 | * @param pDstAddr The destination address of the frame.
|
---|
| 1855 | * @param pDstTab The destination output table.
|
---|
| 1856 | */
|
---|
| 1857 | static INTNETSWDECISION intnetR0NetworkSwitchUnicast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
|
---|
| 1858 | PCRTMAC pDstAddr, PINTNETDSTTAB pDstTab)
|
---|
| 1859 | {
|
---|
| 1860 | AssertPtr(pDstTab);
|
---|
| 1861 | Assert(!intnetR0IsMacAddrMulticast(pDstAddr));
|
---|
| 1862 |
|
---|
| 1863 | /*
|
---|
| 1864 | * Grab the spinlock first and do the switching.
|
---|
| 1865 | */
|
---|
[30557] | 1866 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
[40806] | 1867 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1868 |
|
---|
| 1869 | pDstTab->fTrunkDst = 0;
|
---|
| 1870 | pDstTab->pTrunk = 0;
|
---|
| 1871 | pDstTab->cIfs = 0;
|
---|
| 1872 |
|
---|
| 1873 | /* Find exactly matching or promiscuous interfaces. */
|
---|
| 1874 | uint32_t cExactHits = 0;
|
---|
| 1875 | uint32_t iIfMac = pTab->cEntries;
|
---|
| 1876 | while (iIfMac-- > 0)
|
---|
| 1877 | {
|
---|
| 1878 | if (pTab->paEntries[iIfMac].fActive)
|
---|
| 1879 | {
|
---|
| 1880 | bool fExact = intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr);
|
---|
| 1881 | if ( fExact
|
---|
| 1882 | || intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr)
|
---|
[36075] | 1883 | || ( pTab->paEntries[iIfMac].fPromiscuousSeeTrunk
|
---|
| 1884 | || (!fSrc && pTab->paEntries[iIfMac].fPromiscuousEff) )
|
---|
| 1885 | )
|
---|
[28623] | 1886 | {
|
---|
| 1887 | cExactHits += fExact;
|
---|
| 1888 |
|
---|
| 1889 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
| 1890 | if (RT_LIKELY(pIf != pIfSender)) /* paranoia */
|
---|
| 1891 | {
|
---|
| 1892 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 1893 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 1894 | pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
|
---|
| 1895 | intnetR0BusyIncIf(pIf);
|
---|
| 1896 | }
|
---|
| 1897 | }
|
---|
| 1898 | }
|
---|
| 1899 | }
|
---|
| 1900 |
|
---|
[36089] | 1901 | /* Network only promicuous mode ifs should see related trunk traffic. */
|
---|
| 1902 | if ( cExactHits
|
---|
| 1903 | && fSrc
|
---|
| 1904 | && pNetwork->MacTab.cPromiscuousNoTrunkEntries)
|
---|
| 1905 | {
|
---|
| 1906 | iIfMac = pTab->cEntries;
|
---|
| 1907 | while (iIfMac-- > 0)
|
---|
| 1908 | {
|
---|
| 1909 | if ( pTab->paEntries[iIfMac].fPromiscuousEff
|
---|
| 1910 | && !pTab->paEntries[iIfMac].fPromiscuousSeeTrunk
|
---|
| 1911 | && pTab->paEntries[iIfMac].fActive
|
---|
| 1912 | && !intnetR0AreMacAddrsEqual(&pTab->paEntries[iIfMac].MacAddr, pDstAddr)
|
---|
| 1913 | && !intnetR0IsMacAddrDummy(&pTab->paEntries[iIfMac].MacAddr) )
|
---|
| 1914 | {
|
---|
| 1915 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
| 1916 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 1917 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 1918 | pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
|
---|
| 1919 | intnetR0BusyIncIf(pIf);
|
---|
| 1920 | }
|
---|
| 1921 | }
|
---|
| 1922 | }
|
---|
| 1923 |
|
---|
[28623] | 1924 | /* Does it match the host, or is the host promiscuous? */
|
---|
| 1925 | if ( fSrc != INTNETTRUNKDIR_HOST
|
---|
| 1926 | && pTab->fHostActive)
|
---|
| 1927 | {
|
---|
| 1928 | bool fExact = intnetR0AreMacAddrsEqual(&pTab->HostMac, pDstAddr);
|
---|
| 1929 | if ( fExact
|
---|
| 1930 | || intnetR0IsMacAddrDummy(&pTab->HostMac)
|
---|
[36075] | 1931 | || pTab->fHostPromiscuousEff)
|
---|
[28623] | 1932 | {
|
---|
| 1933 | cExactHits += fExact;
|
---|
| 1934 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
|
---|
| 1935 | }
|
---|
| 1936 | }
|
---|
| 1937 |
|
---|
| 1938 | /* Hit the wire if there are no exact matches or if it's in promiscuous mode. */
|
---|
| 1939 | if ( fSrc != INTNETTRUNKDIR_WIRE
|
---|
| 1940 | && pTab->fWireActive
|
---|
[36075] | 1941 | && (!cExactHits || pTab->fWirePromiscuousEff)
|
---|
[28623] | 1942 | )
|
---|
| 1943 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
|
---|
| 1944 |
|
---|
| 1945 | /* Grab the trunk if we're sending to it. */
|
---|
| 1946 | if (pDstTab->fTrunkDst)
|
---|
| 1947 | {
|
---|
| 1948 | PINTNETTRUNKIF pTrunk = pTab->pTrunk;
|
---|
| 1949 | pDstTab->pTrunk = pTrunk;
|
---|
| 1950 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 1951 | }
|
---|
| 1952 |
|
---|
[52618] | 1953 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1954 | return pDstTab->cIfs
|
---|
| 1955 | ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST)
|
---|
| 1956 | : (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK);
|
---|
| 1957 | }
|
---|
| 1958 |
|
---|
| 1959 |
|
---|
| 1960 | /**
|
---|
| 1961 | * Create a destination table for a broadcast frame.
|
---|
| 1962 | *
|
---|
| 1963 | * @returns INTNETSWDECISION_BROADCAST.
|
---|
| 1964 | * @param pNetwork The network to switch on.
|
---|
| 1965 | * @param fSrc The frame source.
|
---|
| 1966 | * @param pIfSender The sender interface, NULL if trunk. Used to
|
---|
| 1967 | * prevent sending an echo to the sender.
|
---|
| 1968 | * @param pDstTab The destination output table.
|
---|
| 1969 | */
|
---|
| 1970 | static INTNETSWDECISION intnetR0NetworkSwitchBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETIF pIfSender,
|
---|
| 1971 | PINTNETDSTTAB pDstTab)
|
---|
| 1972 | {
|
---|
| 1973 | AssertPtr(pDstTab);
|
---|
| 1974 |
|
---|
| 1975 | /*
|
---|
| 1976 | * Grab the spinlock first and record all active interfaces.
|
---|
| 1977 | */
|
---|
| 1978 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
[40806] | 1979 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 1980 |
|
---|
| 1981 | pDstTab->fTrunkDst = 0;
|
---|
| 1982 | pDstTab->pTrunk = 0;
|
---|
| 1983 | pDstTab->cIfs = 0;
|
---|
| 1984 |
|
---|
| 1985 | /* Regular interfaces. */
|
---|
| 1986 | uint32_t iIfMac = pTab->cEntries;
|
---|
| 1987 | while (iIfMac-- > 0)
|
---|
| 1988 | {
|
---|
| 1989 | if (pTab->paEntries[iIfMac].fActive)
|
---|
| 1990 | {
|
---|
| 1991 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
| 1992 | if (pIf != pIfSender)
|
---|
| 1993 | {
|
---|
| 1994 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 1995 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 1996 | pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
|
---|
| 1997 | intnetR0BusyIncIf(pIf);
|
---|
| 1998 | }
|
---|
| 1999 | }
|
---|
| 2000 | }
|
---|
| 2001 |
|
---|
| 2002 | /* The trunk interface. */
|
---|
| 2003 | if (pTab->fHostActive)
|
---|
| 2004 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
|
---|
| 2005 | if (pTab->fWireActive)
|
---|
| 2006 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
|
---|
| 2007 | pDstTab->fTrunkDst &= ~fSrc;
|
---|
| 2008 | if (pDstTab->fTrunkDst)
|
---|
| 2009 | {
|
---|
| 2010 | PINTNETTRUNKIF pTrunk = pTab->pTrunk;
|
---|
| 2011 | pDstTab->pTrunk = pTrunk;
|
---|
| 2012 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 2013 | }
|
---|
| 2014 |
|
---|
[52618] | 2015 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2016 | return INTNETSWDECISION_BROADCAST;
|
---|
| 2017 | }
|
---|
| 2018 |
|
---|
| 2019 |
|
---|
| 2020 | /**
|
---|
| 2021 | * Create a destination table with the trunk and any promiscuous interfaces.
|
---|
| 2022 | *
|
---|
| 2023 | * This is only used in a fallback case of the level-3 switching, so we can
|
---|
| 2024 | * assume the wire as source and skip the sender interface filtering.
|
---|
| 2025 | *
|
---|
| 2026 | * @returns INTNETSWDECISION_DROP, INTNETSWDECISION_TRUNK,
|
---|
| 2027 | * INTNETSWDECISION_INTNET or INTNETSWDECISION_BROADCAST (misnomer).
|
---|
| 2028 | * @param pNetwork The network to switch on.
|
---|
| 2029 | * @param fSrc The frame source.
|
---|
| 2030 | * @param pDstTab The destination output table.
|
---|
| 2031 | */
|
---|
| 2032 | static INTNETSWDECISION intnetR0NetworkSwitchTrunkAndPromisc(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
|
---|
| 2033 | {
|
---|
| 2034 | Assert(fSrc == INTNETTRUNKDIR_WIRE);
|
---|
| 2035 |
|
---|
| 2036 | /*
|
---|
| 2037 | * Grab the spinlock first and do the switching.
|
---|
| 2038 | */
|
---|
| 2039 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
[40806] | 2040 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2041 |
|
---|
| 2042 | pDstTab->fTrunkDst = 0;
|
---|
| 2043 | pDstTab->pTrunk = 0;
|
---|
| 2044 | pDstTab->cIfs = 0;
|
---|
| 2045 |
|
---|
| 2046 | /* Find promiscuous interfaces. */
|
---|
| 2047 | uint32_t iIfMac = pTab->cEntries;
|
---|
| 2048 | while (iIfMac-- > 0)
|
---|
| 2049 | {
|
---|
| 2050 | if ( pTab->paEntries[iIfMac].fActive
|
---|
[36075] | 2051 | && ( pTab->paEntries[iIfMac].fPromiscuousSeeTrunk
|
---|
| 2052 | || (!fSrc && pTab->paEntries[iIfMac].fPromiscuousEff) )
|
---|
| 2053 | )
|
---|
[28623] | 2054 | {
|
---|
| 2055 | PINTNETIF pIf = pTab->paEntries[iIfMac].pIf; AssertPtr(pIf); Assert(pIf->pNetwork == pNetwork);
|
---|
| 2056 | uint32_t iIfDst = pDstTab->cIfs++;
|
---|
| 2057 | pDstTab->aIfs[iIfDst].pIf = pIf;
|
---|
| 2058 | pDstTab->aIfs[iIfDst].fReplaceDstMac = false;
|
---|
| 2059 | intnetR0BusyIncIf(pIf);
|
---|
| 2060 | }
|
---|
| 2061 | }
|
---|
| 2062 |
|
---|
| 2063 | /* The trunk interface. */
|
---|
| 2064 | if (pTab->fHostActive)
|
---|
| 2065 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
|
---|
| 2066 | if (pTab->fWireActive)
|
---|
| 2067 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
|
---|
| 2068 | pDstTab->fTrunkDst &= ~fSrc;
|
---|
| 2069 | if (pDstTab->fTrunkDst)
|
---|
| 2070 | {
|
---|
| 2071 | PINTNETTRUNKIF pTrunk = pTab->pTrunk;
|
---|
| 2072 | pDstTab->pTrunk = pTrunk;
|
---|
| 2073 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 2074 | }
|
---|
| 2075 |
|
---|
[52618] | 2076 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2077 | return !pDstTab->cIfs
|
---|
| 2078 | ? (!pDstTab->fTrunkDst ? INTNETSWDECISION_DROP : INTNETSWDECISION_TRUNK)
|
---|
| 2079 | : (!pDstTab->fTrunkDst ? INTNETSWDECISION_INTNET : INTNETSWDECISION_BROADCAST);
|
---|
| 2080 | }
|
---|
| 2081 |
|
---|
| 2082 |
|
---|
| 2083 | /**
|
---|
| 2084 | * Create a destination table for a trunk frame.
|
---|
| 2085 | *
|
---|
| 2086 | * @returns INTNETSWDECISION_BROADCAST.
|
---|
| 2087 | * @param pNetwork The network to switch on.
|
---|
| 2088 | * @param fSrc The frame source.
|
---|
| 2089 | * @param pDstTab The destination output table.
|
---|
| 2090 | */
|
---|
| 2091 | static INTNETSWDECISION intnetR0NetworkSwitchTrunk(PINTNETNETWORK pNetwork, uint32_t fSrc, PINTNETDSTTAB pDstTab)
|
---|
| 2092 | {
|
---|
| 2093 | AssertPtr(pDstTab);
|
---|
| 2094 |
|
---|
| 2095 | /*
|
---|
| 2096 | * Grab the spinlock first and record all active interfaces.
|
---|
| 2097 | */
|
---|
| 2098 | PINTNETMACTAB pTab= &pNetwork->MacTab;
|
---|
[40806] | 2099 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2100 |
|
---|
| 2101 | pDstTab->fTrunkDst = 0;
|
---|
| 2102 | pDstTab->pTrunk = 0;
|
---|
| 2103 | pDstTab->cIfs = 0;
|
---|
| 2104 |
|
---|
| 2105 | /* The trunk interface. */
|
---|
| 2106 | if (pTab->fHostActive)
|
---|
| 2107 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_HOST;
|
---|
| 2108 | if (pTab->fWireActive)
|
---|
| 2109 | pDstTab->fTrunkDst |= INTNETTRUNKDIR_WIRE;
|
---|
| 2110 | pDstTab->fTrunkDst &= ~fSrc;
|
---|
| 2111 | if (pDstTab->fTrunkDst)
|
---|
| 2112 | {
|
---|
| 2113 | PINTNETTRUNKIF pTrunk = pTab->pTrunk;
|
---|
| 2114 | pDstTab->pTrunk = pTrunk;
|
---|
| 2115 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 2116 | }
|
---|
| 2117 |
|
---|
[52618] | 2118 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2119 | return pDstTab->fTrunkDst ? INTNETSWDECISION_TRUNK : INTNETSWDECISION_DROP;
|
---|
| 2120 | }
|
---|
| 2121 |
|
---|
| 2122 |
|
---|
| 2123 | /**
|
---|
| 2124 | * Wrapper around RTMemAlloc for allocating a destination table.
|
---|
| 2125 | *
|
---|
| 2126 | * @returns VINF_SUCCESS or VERR_NO_MEMORY.
|
---|
| 2127 | * @param cEntries The size given as an entry count.
|
---|
| 2128 | * @param ppDstTab Where to store the pointer (always).
|
---|
| 2129 | */
|
---|
| 2130 | DECLINLINE(int) intnetR0AllocDstTab(uint32_t cEntries, PINTNETDSTTAB *ppDstTab)
|
---|
| 2131 | {
|
---|
| 2132 | PINTNETDSTTAB pDstTab;
|
---|
[73097] | 2133 | *ppDstTab = pDstTab = (PINTNETDSTTAB)RTMemAlloc(RT_UOFFSETOF_DYN(INTNETDSTTAB, aIfs[cEntries]));
|
---|
[28623] | 2134 | if (RT_UNLIKELY(!pDstTab))
|
---|
| 2135 | return VERR_NO_MEMORY;
|
---|
| 2136 | return VINF_SUCCESS;
|
---|
| 2137 | }
|
---|
| 2138 |
|
---|
| 2139 |
|
---|
| 2140 | /**
|
---|
| 2141 | * Ensures that there is space for another interface in the MAC address lookup
|
---|
| 2142 | * table as well as all the destination tables.
|
---|
| 2143 | *
|
---|
| 2144 | * The caller must own the create/open/destroy mutex.
|
---|
| 2145 | *
|
---|
| 2146 | * @returns VINF_SUCCESS, VERR_NO_MEMORY or VERR_OUT_OF_RANGE.
|
---|
| 2147 | * @param pNetwork The network to operate on.
|
---|
| 2148 | */
|
---|
| 2149 | static int intnetR0NetworkEnsureTabSpace(PINTNETNETWORK pNetwork)
|
---|
| 2150 | {
|
---|
| 2151 | /*
|
---|
| 2152 | * The cEntries and cEntriesAllocated members are only updated while
|
---|
| 2153 | * owning the big mutex, so we only need the spinlock when doing the
|
---|
| 2154 | * actual table replacing.
|
---|
| 2155 | */
|
---|
| 2156 | PINTNETMACTAB pTab = &pNetwork->MacTab;
|
---|
| 2157 | int rc = VINF_SUCCESS;
|
---|
| 2158 | AssertReturn(pTab->cEntries <= pTab->cEntriesAllocated, VERR_INTERNAL_ERROR_2);
|
---|
| 2159 | if (pTab->cEntries + 1 > pTab->cEntriesAllocated)
|
---|
| 2160 | {
|
---|
| 2161 | uint32_t const cAllocated = pTab->cEntriesAllocated + INTNET_GROW_DSTTAB_SIZE;
|
---|
| 2162 | if (cAllocated <= INTNET_MAX_IFS)
|
---|
| 2163 | {
|
---|
| 2164 | /*
|
---|
| 2165 | * Resize the destination tables first, this can be kind of tedious.
|
---|
| 2166 | */
|
---|
| 2167 | for (uint32_t i = 0; i < pTab->cEntries; i++)
|
---|
| 2168 | {
|
---|
| 2169 | PINTNETIF pIf = pTab->paEntries[i].pIf; AssertPtr(pIf);
|
---|
| 2170 | PINTNETDSTTAB pNew;
|
---|
| 2171 | rc = intnetR0AllocDstTab(cAllocated, &pNew);
|
---|
| 2172 | if (RT_FAILURE(rc))
|
---|
| 2173 | break;
|
---|
| 2174 |
|
---|
| 2175 | for (;;)
|
---|
| 2176 | {
|
---|
| 2177 | PINTNETDSTTAB pOld = pIf->pDstTab;
|
---|
| 2178 | if ( pOld
|
---|
[30111] | 2179 | && ASMAtomicCmpXchgPtr(&pIf->pDstTab, pNew, pOld))
|
---|
[28623] | 2180 | {
|
---|
| 2181 | RTMemFree(pOld);
|
---|
| 2182 | break;
|
---|
| 2183 | }
|
---|
| 2184 | intnetR0BusyWait(pNetwork, &pIf->cBusy);
|
---|
| 2185 | }
|
---|
| 2186 | }
|
---|
| 2187 |
|
---|
| 2188 | /*
|
---|
| 2189 | * The trunk.
|
---|
| 2190 | */
|
---|
| 2191 | if ( RT_SUCCESS(rc)
|
---|
| 2192 | && pNetwork->MacTab.pTrunk)
|
---|
| 2193 | {
|
---|
| 2194 | AssertCompileAdjacentMembers(INTNETTRUNKIF, apTaskDstTabs, apIntDstTabs);
|
---|
| 2195 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 2196 | PINTNETDSTTAB * const ppEndDstTab = &pTrunk->apIntDstTabs[pTrunk->cIntDstTabs];
|
---|
| 2197 | for (PINTNETDSTTAB *ppDstTab = &pTrunk->apTaskDstTabs[0];
|
---|
| 2198 | ppDstTab != ppEndDstTab && RT_SUCCESS(rc);
|
---|
| 2199 | ppDstTab++)
|
---|
| 2200 | {
|
---|
| 2201 | PINTNETDSTTAB pNew;
|
---|
| 2202 | rc = intnetR0AllocDstTab(cAllocated, &pNew);
|
---|
| 2203 | if (RT_FAILURE(rc))
|
---|
| 2204 | break;
|
---|
| 2205 |
|
---|
| 2206 | for (;;)
|
---|
| 2207 | {
|
---|
[40806] | 2208 | RTSpinlockAcquire(pTrunk->hDstTabSpinlock);
|
---|
[28623] | 2209 | void *pvOld = *ppDstTab;
|
---|
| 2210 | if (pvOld)
|
---|
| 2211 | *ppDstTab = pNew;
|
---|
[52618] | 2212 | RTSpinlockRelease(pTrunk->hDstTabSpinlock);
|
---|
[28623] | 2213 | if (pvOld)
|
---|
| 2214 | {
|
---|
| 2215 | RTMemFree(pvOld);
|
---|
| 2216 | break;
|
---|
| 2217 | }
|
---|
| 2218 | intnetR0BusyWait(pNetwork, &pTrunk->cBusy);
|
---|
| 2219 | }
|
---|
| 2220 | }
|
---|
| 2221 | }
|
---|
| 2222 |
|
---|
| 2223 | /*
|
---|
| 2224 | * The MAC Address table itself.
|
---|
| 2225 | */
|
---|
| 2226 | if (RT_SUCCESS(rc))
|
---|
| 2227 | {
|
---|
| 2228 | PINTNETMACTABENTRY paNew = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * cAllocated);
|
---|
| 2229 | if (paNew)
|
---|
| 2230 | {
|
---|
[40806] | 2231 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2232 |
|
---|
| 2233 | PINTNETMACTABENTRY paOld = pTab->paEntries;
|
---|
| 2234 | uint32_t i = pTab->cEntries;
|
---|
| 2235 | while (i-- > 0)
|
---|
| 2236 | {
|
---|
| 2237 | paNew[i] = paOld[i];
|
---|
| 2238 |
|
---|
| 2239 | paOld[i].fActive = false;
|
---|
| 2240 | paOld[i].pIf = NULL;
|
---|
| 2241 | }
|
---|
| 2242 |
|
---|
| 2243 | pTab->paEntries = paNew;
|
---|
| 2244 | pTab->cEntriesAllocated = cAllocated;
|
---|
| 2245 |
|
---|
[52618] | 2246 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2247 |
|
---|
| 2248 | RTMemFree(paOld);
|
---|
| 2249 | }
|
---|
| 2250 | else
|
---|
| 2251 | rc = VERR_NO_MEMORY;
|
---|
| 2252 | }
|
---|
| 2253 | }
|
---|
| 2254 | else
|
---|
| 2255 | rc = VERR_OUT_OF_RANGE;
|
---|
| 2256 | }
|
---|
| 2257 | return rc;
|
---|
| 2258 | }
|
---|
| 2259 |
|
---|
| 2260 |
|
---|
| 2261 |
|
---|
| 2262 |
|
---|
[11074] | 2263 | #ifdef INTNET_WITH_DHCP_SNOOPING
|
---|
| 2264 |
|
---|
[10923] | 2265 | /**
|
---|
[11055] | 2266 | * Snoops IP assignments and releases from the DHCPv4 traffic.
|
---|
[11053] | 2267 | *
|
---|
[11055] | 2268 | * The caller is responsible for making sure this traffic between the
|
---|
[11053] | 2269 | * BOOTPS and BOOTPC ports and validate the IP header. The UDP packet
|
---|
| 2270 | * need not be validated beyond the ports.
|
---|
| 2271 | *
|
---|
| 2272 | * @param pNetwork The network this frame was seen on.
|
---|
| 2273 | * @param pIpHdr Pointer to a valid IP header. This is for pseudo
|
---|
| 2274 | * header validation, so only the minimum header size
|
---|
| 2275 | * needs to be available and valid here.
|
---|
| 2276 | * @param pUdpHdr Pointer to the UDP header in the frame.
|
---|
| 2277 | * @param cbUdpPkt What's left of the frame when starting at the UDP header.
|
---|
[28025] | 2278 | * @param fGso Set if this is a GSO frame, clear if regular.
|
---|
[11053] | 2279 | */
|
---|
[11055] | 2280 | static void intnetR0NetworkSnoopDhcp(PINTNETNETWORK pNetwork, PCRTNETIPV4 pIpHdr, PCRTNETUDP pUdpHdr, uint32_t cbUdpPkt)
|
---|
[11053] | 2281 | {
|
---|
[11123] | 2282 | /*
|
---|
| 2283 | * Check if the DHCP message is valid and get the type.
|
---|
| 2284 | */
|
---|
[28025] | 2285 | if (!RTNetIPv4IsUDPValid(pIpHdr, pUdpHdr, pUdpHdr + 1, cbUdpPkt, true /*fCheckSum*/))
|
---|
[11123] | 2286 | {
|
---|
| 2287 | Log6(("Bad UDP packet\n"));
|
---|
| 2288 | return;
|
---|
| 2289 | }
|
---|
| 2290 | PCRTNETBOOTP pDhcp = (PCRTNETBOOTP)(pUdpHdr + 1);
|
---|
| 2291 | uint8_t MsgType;
|
---|
| 2292 | if (!RTNetIPv4IsDHCPValid(pUdpHdr, pDhcp, cbUdpPkt - sizeof(*pUdpHdr), &MsgType))
|
---|
| 2293 | {
|
---|
| 2294 | Log6(("Bad DHCP packet\n"));
|
---|
| 2295 | return;
|
---|
| 2296 | }
|
---|
| 2297 |
|
---|
| 2298 | #ifdef LOG_ENABLED
|
---|
| 2299 | /*
|
---|
| 2300 | * Log it.
|
---|
| 2301 | */
|
---|
| 2302 | const char *pszType = "unknown";
|
---|
| 2303 | switch (MsgType)
|
---|
| 2304 | {
|
---|
| 2305 | case RTNET_DHCP_MT_DISCOVER: pszType = "discover"; break;
|
---|
| 2306 | case RTNET_DHCP_MT_OFFER: pszType = "offer"; break;
|
---|
| 2307 | case RTNET_DHCP_MT_REQUEST: pszType = "request"; break;
|
---|
| 2308 | case RTNET_DHCP_MT_DECLINE: pszType = "decline"; break;
|
---|
[28025] | 2309 | case RTNET_DHCP_MT_ACK: pszType = "ack"; break;
|
---|
[11123] | 2310 | case RTNET_DHCP_MT_NAC: pszType = "nac"; break;
|
---|
| 2311 | case RTNET_DHCP_MT_RELEASE: pszType = "release"; break;
|
---|
| 2312 | case RTNET_DHCP_MT_INFORM: pszType = "inform"; break;
|
---|
| 2313 | }
|
---|
| 2314 | Log6(("DHCP msg: %d (%s) client %.6Rhxs ciaddr=%d.%d.%d.%d yiaddr=%d.%d.%d.%d\n", MsgType, pszType, &pDhcp->bp_chaddr,
|
---|
| 2315 | pDhcp->bp_ciaddr.au8[0], pDhcp->bp_ciaddr.au8[1], pDhcp->bp_ciaddr.au8[2], pDhcp->bp_ciaddr.au8[3],
|
---|
| 2316 | pDhcp->bp_yiaddr.au8[0], pDhcp->bp_yiaddr.au8[1], pDhcp->bp_yiaddr.au8[2], pDhcp->bp_yiaddr.au8[3]));
|
---|
| 2317 | #endif /* LOG_EANBLED */
|
---|
| 2318 |
|
---|
| 2319 | /*
|
---|
| 2320 | * Act upon the message.
|
---|
| 2321 | */
|
---|
| 2322 | switch (MsgType)
|
---|
| 2323 | {
|
---|
[14609] | 2324 | #if 0
|
---|
| 2325 | case RTNET_DHCP_MT_REQUEST:
|
---|
| 2326 | /** @todo Check for valid non-broadcast requests w/ IP for any of the MACs we
|
---|
| 2327 | * know, and add the IP to the cache. */
|
---|
| 2328 | break;
|
---|
| 2329 | #endif
|
---|
| 2330 |
|
---|
| 2331 |
|
---|
[11123] | 2332 | /*
|
---|
| 2333 | * Lookup the interface by its MAC address and insert the IPv4 address into the cache.
|
---|
| 2334 | * Delete the old client address first, just in case it changed in a renewal.
|
---|
| 2335 | */
|
---|
| 2336 | case RTNET_DHCP_MT_ACK:
|
---|
| 2337 | if (intnetR0IPv4AddrIsGood(pDhcp->bp_yiaddr))
|
---|
[28623] | 2338 | {
|
---|
| 2339 | PINTNETIF pMatchingIf = NULL;
|
---|
[40806] | 2340 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2341 |
|
---|
| 2342 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 2343 | while (iIf-- > 0)
|
---|
| 2344 | {
|
---|
| 2345 | PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
| 2346 | if ( intnetR0IfHasMacAddr(pCur)
|
---|
| 2347 | && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
|
---|
[11123] | 2348 | {
|
---|
| 2349 | intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
|
---|
| 2350 | (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_ACK");
|
---|
[28623] | 2351 | if (!pMatchingIf)
|
---|
| 2352 | {
|
---|
| 2353 | pMatchingIf = pCur;
|
---|
| 2354 | intnetR0BusyIncIf(pMatchingIf);
|
---|
| 2355 | }
|
---|
[11123] | 2356 | }
|
---|
[28623] | 2357 | }
|
---|
[11123] | 2358 |
|
---|
[52618] | 2359 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[11123] | 2360 |
|
---|
[28623] | 2361 | if (pMatchingIf)
|
---|
| 2362 | {
|
---|
[55652] | 2363 | intnetR0IfAddrCacheAdd(pMatchingIf, kIntNetAddrType_IPv4,
|
---|
| 2364 | (PCRTNETADDRU)&pDhcp->bp_yiaddr, "DHCP_MT_ACK");
|
---|
[28623] | 2365 | intnetR0BusyDecIf(pMatchingIf);
|
---|
| 2366 | }
|
---|
| 2367 | }
|
---|
| 2368 | return;
|
---|
| 2369 |
|
---|
| 2370 |
|
---|
[11123] | 2371 | /*
|
---|
| 2372 | * Lookup the interface by its MAC address and remove the IPv4 address(es) from the cache.
|
---|
| 2373 | */
|
---|
| 2374 | case RTNET_DHCP_MT_RELEASE:
|
---|
| 2375 | {
|
---|
[40806] | 2376 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 2377 |
|
---|
| 2378 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 2379 | while (iIf-- > 0)
|
---|
| 2380 | {
|
---|
| 2381 | PINTNETIF pCur = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
| 2382 | if ( intnetR0IfHasMacAddr(pCur)
|
---|
| 2383 | && !memcmp(&pCur->MacAddr, &pDhcp->bp_chaddr, sizeof(RTMAC)))
|
---|
[11123] | 2384 | {
|
---|
| 2385 | intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
|
---|
| 2386 | (PCRTNETADDRU)&pDhcp->bp_ciaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE");
|
---|
| 2387 | intnetR0IfAddrCacheDelete(pCur, &pCur->aAddrCache[kIntNetAddrType_IPv4],
|
---|
| 2388 | (PCRTNETADDRU)&pDhcp->bp_yiaddr, sizeof(RTNETADDRIPV4), "DHCP_MT_RELEASE");
|
---|
| 2389 | }
|
---|
[28623] | 2390 | }
|
---|
| 2391 |
|
---|
[52618] | 2392 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[11123] | 2393 | break;
|
---|
| 2394 | }
|
---|
| 2395 | }
|
---|
| 2396 |
|
---|
[11053] | 2397 | }
|
---|
| 2398 |
|
---|
| 2399 |
|
---|
[11123] | 2400 | /**
|
---|
| 2401 | * Worker for intnetR0TrunkIfSnoopAddr that takes care of what
|
---|
| 2402 | * is likely to be a DHCP message.
|
---|
| 2403 | *
|
---|
| 2404 | * The caller has already check that the UDP source and destination ports
|
---|
| 2405 | * are BOOTPS or BOOTPC.
|
---|
| 2406 | *
|
---|
| 2407 | * @param pNetwork The network this frame was seen on.
|
---|
| 2408 | * @param pSG The gather list for the frame.
|
---|
| 2409 | */
|
---|
[11055] | 2410 | static void intnetR0TrunkIfSnoopDhcp(PINTNETNETWORK pNetwork, PCINTNETSG pSG)
|
---|
| 2411 | {
|
---|
[11123] | 2412 | /*
|
---|
| 2413 | * Get a pointer to a linear copy of the full packet, using the
|
---|
| 2414 | * temporary buffer if necessary.
|
---|
| 2415 | */
|
---|
| 2416 | PCRTNETIPV4 pIpHdr = (PCRTNETIPV4)((PCRTNETETHERHDR)pSG->aSegs[0].pv + 1);
|
---|
[18459] | 2417 | uint32_t cbPacket = pSG->cbTotal - sizeof(RTNETETHERHDR);
|
---|
[11123] | 2418 | if (pSG->cSegsUsed > 1)
|
---|
| 2419 | {
|
---|
| 2420 | cbPacket = RT_MIN(cbPacket, INTNETNETWORK_TMP_SIZE);
|
---|
| 2421 | Log6(("intnetR0TrunkIfSnoopDhcp: Copying IPv4/UDP/DHCP pkt %u\n", cbPacket));
|
---|
| 2422 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), cbPacket, pNetwork->pbTmp))
|
---|
| 2423 | return;
|
---|
| 2424 | //pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
|
---|
| 2425 | pIpHdr = (PCRTNETIPV4)pNetwork->pbTmp;
|
---|
| 2426 | }
|
---|
| 2427 |
|
---|
| 2428 | /*
|
---|
| 2429 | * Validate the IP header and find the UDP packet.
|
---|
| 2430 | */
|
---|
[28025] | 2431 | if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, pSG->cbTotal - sizeof(RTNETETHERHDR), true /*fChecksum*/))
|
---|
[11123] | 2432 | {
|
---|
| 2433 | Log(("intnetR0TrunkIfSnoopDhcp: bad ip header\n"));
|
---|
| 2434 | return;
|
---|
| 2435 | }
|
---|
[18459] | 2436 | uint32_t cbIpHdr = pIpHdr->ip_hl * 4;
|
---|
[11123] | 2437 |
|
---|
| 2438 | /*
|
---|
| 2439 | * Hand it over to the common DHCP snooper.
|
---|
| 2440 | */
|
---|
| 2441 | intnetR0NetworkSnoopDhcp(pNetwork, pIpHdr, (PCRTNETUDP)((uintptr_t)pIpHdr + cbIpHdr), cbPacket - cbIpHdr);
|
---|
[11055] | 2442 | }
|
---|
| 2443 |
|
---|
[11074] | 2444 | #endif /* INTNET_WITH_DHCP_SNOOPING */
|
---|
[11061] | 2445 |
|
---|
[11074] | 2446 |
|
---|
[11061] | 2447 | /**
|
---|
[28623] | 2448 | * Snoops up source addresses from ARP requests and purge these from the address
|
---|
| 2449 | * caches.
|
---|
[11061] | 2450 | *
|
---|
| 2451 | * The purpose of this purging is to get rid of stale addresses.
|
---|
| 2452 | *
|
---|
[11123] | 2453 | * @param pNetwork The network this frame was seen on.
|
---|
[11061] | 2454 | * @param pSG The gather list for the frame.
|
---|
| 2455 | */
|
---|
[11055] | 2456 | static void intnetR0TrunkIfSnoopArp(PINTNETNETWORK pNetwork, PCINTNETSG pSG)
|
---|
| 2457 | {
|
---|
[11061] | 2458 | /*
|
---|
| 2459 | * Check the minimum size first.
|
---|
| 2460 | */
|
---|
[11073] | 2461 | if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4)))
|
---|
[11061] | 2462 | return;
|
---|
[11055] | 2463 |
|
---|
[11061] | 2464 | /*
|
---|
| 2465 | * Copy to temporary buffer if necessary.
|
---|
| 2466 | */
|
---|
[18459] | 2467 | uint32_t cbPacket = RT_MIN(pSG->cbTotal, sizeof(RTNETARPIPV4));
|
---|
[11073] | 2468 | PCRTNETARPIPV4 pArpIPv4 = (PCRTNETARPIPV4)((uintptr_t)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
|
---|
[11061] | 2469 | if ( pSG->cSegsUsed != 1
|
---|
| 2470 | && pSG->aSegs[0].cb < cbPacket)
|
---|
| 2471 | {
|
---|
[11073] | 2472 | if ( (pSG->fFlags & (INTNETSG_FLAGS_ARP_IPV4 | INTNETSG_FLAGS_PKT_CP_IN_TMP))
|
---|
| 2473 | != (INTNETSG_FLAGS_ARP_IPV4 | INTNETSG_FLAGS_PKT_CP_IN_TMP)
|
---|
| 2474 | && !intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), cbPacket, pNetwork->pbTmp))
|
---|
| 2475 | return;
|
---|
| 2476 | pArpIPv4 = (PCRTNETARPIPV4)pNetwork->pbTmp;
|
---|
[11061] | 2477 | }
|
---|
| 2478 |
|
---|
| 2479 | /*
|
---|
[11073] | 2480 | * Ignore packets which doesn't interest us or we perceive as malformed.
|
---|
[11061] | 2481 | */
|
---|
[11073] | 2482 | if (RT_UNLIKELY( pArpIPv4->Hdr.ar_hlen != sizeof(RTMAC)
|
---|
| 2483 | || pArpIPv4->Hdr.ar_plen != sizeof(RTNETADDRIPV4)
|
---|
| 2484 | || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
|
---|
| 2485 | || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
|
---|
[11061] | 2486 | return;
|
---|
[11073] | 2487 | uint16_t ar_oper = RT_H2BE_U16(pArpIPv4->Hdr.ar_oper);
|
---|
[11061] | 2488 | if (RT_UNLIKELY( ar_oper != RTNET_ARPOP_REQUEST
|
---|
[11073] | 2489 | && ar_oper != RTNET_ARPOP_REPLY))
|
---|
| 2490 | {
|
---|
| 2491 | Log6(("ts-ar: op=%#x\n", ar_oper));
|
---|
[11061] | 2492 | return;
|
---|
[11073] | 2493 | }
|
---|
[11061] | 2494 |
|
---|
| 2495 | /*
|
---|
[11073] | 2496 | * Delete the source address if it's OK.
|
---|
[11061] | 2497 | */
|
---|
[28623] | 2498 | if ( !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_sha)
|
---|
[11073] | 2499 | && ( pArpIPv4->ar_sha.au16[0]
|
---|
| 2500 | || pArpIPv4->ar_sha.au16[1]
|
---|
| 2501 | || pArpIPv4->ar_sha.au16[2])
|
---|
| 2502 | && intnetR0IPv4AddrIsGood(pArpIPv4->ar_spa))
|
---|
[11061] | 2503 | {
|
---|
[11073] | 2504 | Log6(("ts-ar: %d.%d.%d.%d / %.6Rhxs\n", pArpIPv4->ar_spa.au8[0], pArpIPv4->ar_spa.au8[1],
|
---|
| 2505 | pArpIPv4->ar_spa.au8[2], pArpIPv4->ar_spa.au8[3], &pArpIPv4->ar_sha));
|
---|
| 2506 | intnetR0NetworkAddrCacheDelete(pNetwork, (PCRTNETADDRU)&pArpIPv4->ar_spa,
|
---|
| 2507 | kIntNetAddrType_IPv4, sizeof(pArpIPv4->ar_spa), "tif/arp");
|
---|
[11061] | 2508 | }
|
---|
[11055] | 2509 | }
|
---|
| 2510 |
|
---|
| 2511 |
|
---|
[11074] | 2512 | #ifdef INTNET_WITH_DHCP_SNOOPING
|
---|
[11053] | 2513 | /**
|
---|
[33540] | 2514 | * Snoop up addresses from ARP and DHCP traffic from frames coming
|
---|
[11055] | 2515 | * over the trunk connection.
|
---|
| 2516 | *
|
---|
| 2517 | * The caller is responsible for do some basic filtering before calling
|
---|
| 2518 | * this function.
|
---|
| 2519 | * For IPv4 this means checking against the minimum DHCPv4 frame size.
|
---|
| 2520 | *
|
---|
| 2521 | * @param pNetwork The network.
|
---|
| 2522 | * @param pSG The SG list for the frame.
|
---|
| 2523 | * @param EtherType The Ethertype of the frame.
|
---|
| 2524 | */
|
---|
| 2525 | static void intnetR0TrunkIfSnoopAddr(PINTNETNETWORK pNetwork, PCINTNETSG pSG, uint16_t EtherType)
|
---|
| 2526 | {
|
---|
| 2527 | switch (EtherType)
|
---|
| 2528 | {
|
---|
| 2529 | case RTNET_ETHERTYPE_IPV4:
|
---|
| 2530 | {
|
---|
[11125] | 2531 | uint32_t cbIpHdr;
|
---|
| 2532 | uint8_t b;
|
---|
| 2533 |
|
---|
[11055] | 2534 | Assert(pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN);
|
---|
[11125] | 2535 | if (pSG->aSegs[0].cb >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN)
|
---|
| 2536 | {
|
---|
| 2537 | /* check if the protocol is UDP */
|
---|
| 2538 | PCRTNETIPV4 pIpHdr = (PCRTNETIPV4)((uint8_t const *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
|
---|
| 2539 | if (pIpHdr->ip_p != RTNETIPV4_PROT_UDP)
|
---|
| 2540 | return;
|
---|
[11055] | 2541 |
|
---|
[11125] | 2542 | /* get the TCP header length */
|
---|
| 2543 | cbIpHdr = pIpHdr->ip_hl * 4;
|
---|
| 2544 | }
|
---|
| 2545 | else
|
---|
| 2546 | {
|
---|
| 2547 | /* check if the protocol is UDP */
|
---|
[73097] | 2548 | if ( intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV4, ip_p))
|
---|
[11125] | 2549 | != RTNETIPV4_PROT_UDP)
|
---|
| 2550 | return;
|
---|
[11055] | 2551 |
|
---|
[11125] | 2552 | /* get the TCP header length */
|
---|
| 2553 | b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + 0); /* (IPv4 first byte, a bitfield) */
|
---|
| 2554 | cbIpHdr = (b & 0x0f) * 4;
|
---|
| 2555 | }
|
---|
[11055] | 2556 | if (cbIpHdr < RTNETIPV4_MIN_LEN)
|
---|
| 2557 | return;
|
---|
| 2558 |
|
---|
[11125] | 2559 | /* compare the ports. */
|
---|
| 2560 | if (pSG->aSegs[0].cb >= sizeof(RTNETETHERHDR) + cbIpHdr + RTNETUDP_MIN_LEN)
|
---|
| 2561 | {
|
---|
| 2562 | PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t const *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR) + cbIpHdr);
|
---|
| 2563 | if ( ( RT_BE2H_U16(pUdpHdr->uh_sport) != RTNETIPV4_PORT_BOOTPS
|
---|
| 2564 | && RT_BE2H_U16(pUdpHdr->uh_dport) != RTNETIPV4_PORT_BOOTPS)
|
---|
| 2565 | || ( RT_BE2H_U16(pUdpHdr->uh_dport) != RTNETIPV4_PORT_BOOTPC
|
---|
| 2566 | && RT_BE2H_U16(pUdpHdr->uh_sport) != RTNETIPV4_PORT_BOOTPC))
|
---|
| 2567 | return;
|
---|
| 2568 | }
|
---|
| 2569 | else
|
---|
| 2570 | {
|
---|
| 2571 | /* get the lower byte of the UDP source port number. */
|
---|
[73097] | 2572 | b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_UOFFSETOF(RTNETUDP, uh_sport) + 1);
|
---|
[11125] | 2573 | if ( b != RTNETIPV4_PORT_BOOTPS
|
---|
| 2574 | && b != RTNETIPV4_PORT_BOOTPC)
|
---|
| 2575 | return;
|
---|
| 2576 | uint8_t SrcPort = b;
|
---|
[73097] | 2577 | b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_UOFFSETOF(RTNETUDP, uh_sport));
|
---|
[11125] | 2578 | if (b)
|
---|
| 2579 | return;
|
---|
[11123] | 2580 |
|
---|
[11125] | 2581 | /* get the lower byte of the UDP destination port number. */
|
---|
[73097] | 2582 | b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_UOFFSETOF(RTNETUDP, uh_dport) + 1);
|
---|
[11125] | 2583 | if ( b != RTNETIPV4_PORT_BOOTPS
|
---|
| 2584 | && b != RTNETIPV4_PORT_BOOTPC)
|
---|
| 2585 | return;
|
---|
| 2586 | if (b == SrcPort)
|
---|
| 2587 | return;
|
---|
[73097] | 2588 | b = intnetR0SgReadByte(pSG, sizeof(RTNETETHERHDR) + cbIpHdr + RT_UOFFSETOF(RTNETUDP, uh_dport));
|
---|
[11125] | 2589 | if (b)
|
---|
| 2590 | return;
|
---|
| 2591 | }
|
---|
[11055] | 2592 | intnetR0TrunkIfSnoopDhcp(pNetwork, pSG);
|
---|
| 2593 | break;
|
---|
| 2594 | }
|
---|
| 2595 |
|
---|
| 2596 | case RTNET_ETHERTYPE_ARP:
|
---|
| 2597 | intnetR0TrunkIfSnoopArp(pNetwork, pSG);
|
---|
| 2598 | break;
|
---|
| 2599 | }
|
---|
| 2600 | }
|
---|
[11074] | 2601 | #endif /* INTNET_WITH_DHCP_SNOOPING */
|
---|
[11055] | 2602 |
|
---|
[45716] | 2603 | /**
|
---|
| 2604 | * Deals with an IPv6 packet.
|
---|
| 2605 | *
|
---|
| 2606 | * This will fish out the source IP address and add it to the cache.
|
---|
| 2607 | * Then it will look for DHCPRELEASE requests (?) and anything else
|
---|
| 2608 | * that we might find useful later.
|
---|
| 2609 | *
|
---|
| 2610 | * @param pIf The interface that's sending the frame.
|
---|
| 2611 | * @param pIpHdr Pointer to the IPv4 header in the frame.
|
---|
| 2612 | * @param cbPacket The size of the packet, or more correctly the
|
---|
| 2613 | * size of the frame without the ethernet header.
|
---|
| 2614 | * @param fGso Set if this is a GSO frame, clear if regular.
|
---|
| 2615 | */
|
---|
| 2616 | static void intnetR0IfSnoopIPv6SourceAddr(PINTNETIF pIf, PCRTNETIPV6 pIpHdr, uint32_t cbPacket, bool fGso)
|
---|
| 2617 | {
|
---|
[49480] | 2618 | NOREF(fGso);
|
---|
| 2619 |
|
---|
[45716] | 2620 | /*
|
---|
| 2621 | * Check the header size first to prevent access invalid data.
|
---|
| 2622 | */
|
---|
| 2623 | if (cbPacket < RTNETIPV6_MIN_LEN)
|
---|
| 2624 | return;
|
---|
[11055] | 2625 |
|
---|
[45716] | 2626 | /*
|
---|
| 2627 | * If the source address is good (not multicast) and
|
---|
| 2628 | * not already in the address cache of the sender, add it.
|
---|
| 2629 | */
|
---|
| 2630 | RTNETADDRU Addr;
|
---|
| 2631 | Addr.IPv6 = pIpHdr->ip6_src;
|
---|
| 2632 |
|
---|
| 2633 | if ( intnetR0IPv6AddrIsGood(Addr.IPv6) && (pIpHdr->ip6_hlim == 0xff)
|
---|
| 2634 | && intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv6], &Addr, sizeof(Addr.IPv6)) < 0)
|
---|
| 2635 | {
|
---|
[55652] | 2636 | intnetR0IfAddrCacheAdd(pIf, kIntNetAddrType_IPv6, &Addr, "if/ipv6");
|
---|
[45716] | 2637 | }
|
---|
| 2638 | }
|
---|
| 2639 |
|
---|
| 2640 |
|
---|
[11055] | 2641 | /**
|
---|
[10923] | 2642 | * Deals with an IPv4 packet.
|
---|
| 2643 | *
|
---|
| 2644 | * This will fish out the source IP address and add it to the cache.
|
---|
| 2645 | * Then it will look for DHCPRELEASE requests (?) and anything else
|
---|
[33540] | 2646 | * that we might find useful later.
|
---|
[10923] | 2647 | *
|
---|
| 2648 | * @param pIf The interface that's sending the frame.
|
---|
[11053] | 2649 | * @param pIpHdr Pointer to the IPv4 header in the frame.
|
---|
[10923] | 2650 | * @param cbPacket The size of the packet, or more correctly the
|
---|
| 2651 | * size of the frame without the ethernet header.
|
---|
[28025] | 2652 | * @param fGso Set if this is a GSO frame, clear if regular.
|
---|
[10923] | 2653 | */
|
---|
[28025] | 2654 | static void intnetR0IfSnoopIPv4SourceAddr(PINTNETIF pIf, PCRTNETIPV4 pIpHdr, uint32_t cbPacket, bool fGso)
|
---|
[10923] | 2655 | {
|
---|
| 2656 | /*
|
---|
[11053] | 2657 | * Check the header size first to prevent access invalid data.
|
---|
[10923] | 2658 | */
|
---|
[11053] | 2659 | if (cbPacket < RTNETIPV4_MIN_LEN)
|
---|
[10923] | 2660 | return;
|
---|
[11053] | 2661 | uint32_t cbHdr = (uint32_t)pIpHdr->ip_hl * 4;
|
---|
[11123] | 2662 | if ( cbHdr < RTNETIPV4_MIN_LEN
|
---|
[10923] | 2663 | || cbPacket < cbHdr)
|
---|
| 2664 | return;
|
---|
| 2665 |
|
---|
| 2666 | /*
|
---|
[11123] | 2667 | * If the source address is good (not broadcast or my network) and
|
---|
| 2668 | * not already in the address cache of the sender, add it. Validate
|
---|
| 2669 | * the IP header before adding it.
|
---|
[10923] | 2670 | */
|
---|
[11053] | 2671 | bool fValidatedIpHdr = false;
|
---|
[10961] | 2672 | RTNETADDRU Addr;
|
---|
[11053] | 2673 | Addr.IPv4 = pIpHdr->ip_src;
|
---|
| 2674 | if ( intnetR0IPv4AddrIsGood(Addr.IPv4)
|
---|
| 2675 | && intnetR0IfAddrCacheLookupLikely(&pIf->aAddrCache[kIntNetAddrType_IPv4], &Addr, sizeof(Addr.IPv4)) < 0)
|
---|
[10923] | 2676 | {
|
---|
[28025] | 2677 | if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, cbPacket, !fGso /*fChecksum*/))
|
---|
[11053] | 2678 | {
|
---|
| 2679 | Log(("intnetR0IfSnoopIPv4SourceAddr: bad ip header\n"));
|
---|
[10923] | 2680 | return;
|
---|
[11053] | 2681 | }
|
---|
[55652] | 2682 |
|
---|
| 2683 | intnetR0IfAddrCacheAddIt(pIf, kIntNetAddrType_IPv4, &Addr, "if/ipv4");
|
---|
[11053] | 2684 | fValidatedIpHdr = true;
|
---|
[10923] | 2685 | }
|
---|
| 2686 |
|
---|
[11074] | 2687 | #ifdef INTNET_WITH_DHCP_SNOOPING
|
---|
[10923] | 2688 | /*
|
---|
[11053] | 2689 | * Check for potential DHCP packets.
|
---|
[10923] | 2690 | */
|
---|
[11053] | 2691 | if ( pIpHdr->ip_p == RTNETIPV4_PROT_UDP /* DHCP is UDP. */
|
---|
[28025] | 2692 | && cbPacket >= cbHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN /* Min DHCP packet len. */
|
---|
| 2693 | && !fGso) /* GSO is not applicable to DHCP traffic. */
|
---|
[11053] | 2694 | {
|
---|
| 2695 | PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint8_t const *)pIpHdr + cbHdr);
|
---|
| 2696 | if ( ( RT_BE2H_U16(pUdpHdr->uh_dport) == RTNETIPV4_PORT_BOOTPS
|
---|
| 2697 | || RT_BE2H_U16(pUdpHdr->uh_sport) == RTNETIPV4_PORT_BOOTPS)
|
---|
| 2698 | && ( RT_BE2H_U16(pUdpHdr->uh_sport) == RTNETIPV4_PORT_BOOTPC
|
---|
| 2699 | || RT_BE2H_U16(pUdpHdr->uh_dport) == RTNETIPV4_PORT_BOOTPC))
|
---|
| 2700 | {
|
---|
| 2701 | if ( fValidatedIpHdr
|
---|
[28025] | 2702 | || RTNetIPv4IsHdrValid(pIpHdr, cbPacket, cbPacket, !fGso /*fChecksum*/))
|
---|
[11055] | 2703 | intnetR0NetworkSnoopDhcp(pIf->pNetwork, pIpHdr, pUdpHdr, cbPacket - cbHdr);
|
---|
[11053] | 2704 | else
|
---|
| 2705 | Log(("intnetR0IfSnoopIPv4SourceAddr: bad ip header (dhcp)\n"));
|
---|
| 2706 | }
|
---|
| 2707 | }
|
---|
[11074] | 2708 | #endif /* INTNET_WITH_DHCP_SNOOPING */
|
---|
[10923] | 2709 | }
|
---|
| 2710 |
|
---|
| 2711 |
|
---|
| 2712 | /**
|
---|
[11053] | 2713 | * Snoop up source addresses from an ARP request or reply.
|
---|
[10923] | 2714 | *
|
---|
| 2715 | * @param pIf The interface that's sending the frame.
|
---|
| 2716 | * @param pHdr The ARP header.
|
---|
[33540] | 2717 | * @param cbPacket The size of the packet (might be larger than the ARP
|
---|
[10923] | 2718 | * request 'cause of min ethernet frame size).
|
---|
[11072] | 2719 | * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we
|
---|
| 2720 | * don't have to repeat the frame parsing in intnetR0TrunkIfSend.
|
---|
[10923] | 2721 | */
|
---|
[11073] | 2722 | static void intnetR0IfSnoopArpAddr(PINTNETIF pIf, PCRTNETARPIPV4 pArpIPv4, uint32_t cbPacket, uint16_t *pfSgFlags)
|
---|
[10923] | 2723 | {
|
---|
| 2724 | /*
|
---|
[11073] | 2725 | * Ignore packets which doesn't interest us or we perceive as malformed.
|
---|
[10923] | 2726 | */
|
---|
[11073] | 2727 | if (RT_UNLIKELY(cbPacket < sizeof(RTNETARPIPV4)))
|
---|
[10923] | 2728 | return;
|
---|
[11073] | 2729 | if (RT_UNLIKELY( pArpIPv4->Hdr.ar_hlen != sizeof(RTMAC)
|
---|
| 2730 | || pArpIPv4->Hdr.ar_plen != sizeof(RTNETADDRIPV4)
|
---|
| 2731 | || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
|
---|
| 2732 | || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
|
---|
| 2733 | return;
|
---|
| 2734 | uint16_t ar_oper = RT_H2BE_U16(pArpIPv4->Hdr.ar_oper);
|
---|
[11053] | 2735 | if (RT_UNLIKELY( ar_oper != RTNET_ARPOP_REQUEST
|
---|
[11073] | 2736 | && ar_oper != RTNET_ARPOP_REPLY))
|
---|
| 2737 | {
|
---|
| 2738 | Log6(("ar_oper=%#x\n", ar_oper));
|
---|
[11053] | 2739 | return;
|
---|
[11073] | 2740 | }
|
---|
[10923] | 2741 |
|
---|
| 2742 | /*
|
---|
[11073] | 2743 | * Tag the SG as ARP IPv4 for later editing, then check for addresses
|
---|
| 2744 | * which can be removed or added to the address cache of the sender.
|
---|
[10923] | 2745 | */
|
---|
[11073] | 2746 | *pfSgFlags |= INTNETSG_FLAGS_ARP_IPV4;
|
---|
| 2747 |
|
---|
| 2748 | if ( ar_oper == RTNET_ARPOP_REPLY
|
---|
[28623] | 2749 | && !intnetR0IsMacAddrMulticast(&pArpIPv4->ar_tha)
|
---|
[11073] | 2750 | && ( pArpIPv4->ar_tha.au16[0]
|
---|
| 2751 | || pArpIPv4->ar_tha.au16[1]
|
---|
| 2752 | || pArpIPv4->ar_tha.au16[2])
|
---|
| 2753 | && intnetR0IPv4AddrIsGood(pArpIPv4->ar_tpa))
|
---|
| 2754 | intnetR0IfAddrCacheDelete(pIf, &pIf->aAddrCache[kIntNetAddrType_IPv4],
|
---|
| 2755 | (PCRTNETADDRU)&pArpIPv4->ar_tpa, sizeof(RTNETADDRIPV4), "if/arp");
|
---|
| 2756 |
|
---|
[28623] | 2757 | if ( !memcmp(&pArpIPv4->ar_sha, &pIf->MacAddr, sizeof(RTMAC))
|
---|
[11073] | 2758 | && intnetR0IPv4AddrIsGood(pArpIPv4->ar_spa))
|
---|
[55652] | 2759 | {
|
---|
| 2760 | intnetR0IfAddrCacheAdd(pIf, kIntNetAddrType_IPv4, (PCRTNETADDRU)&pArpIPv4->ar_spa, "if/arp");
|
---|
| 2761 | }
|
---|
[10923] | 2762 | }
|
---|
| 2763 |
|
---|
| 2764 |
|
---|
| 2765 |
|
---|
| 2766 | /**
|
---|
| 2767 | * Checks packets send by a normal interface for new network
|
---|
| 2768 | * layer addresses.
|
---|
| 2769 | *
|
---|
| 2770 | * @param pIf The interface that's sending the frame.
|
---|
| 2771 | * @param pbFrame The frame.
|
---|
| 2772 | * @param cbFrame The size of the frame.
|
---|
[28025] | 2773 | * @param fGso Set if this is a GSO frame, clear if regular.
|
---|
[11072] | 2774 | * @param pfSgFlags Pointer to the SG flags. This is used to tag the packet so we
|
---|
| 2775 | * don't have to repeat the frame parsing in intnetR0TrunkIfSend.
|
---|
[10923] | 2776 | */
|
---|
[28025] | 2777 | static void intnetR0IfSnoopAddr(PINTNETIF pIf, uint8_t const *pbFrame, uint32_t cbFrame, bool fGso, uint16_t *pfSgFlags)
|
---|
[10923] | 2778 | {
|
---|
| 2779 | /*
|
---|
| 2780 | * Fish out the ethertype and look for stuff we can handle.
|
---|
| 2781 | */
|
---|
[10961] | 2782 | if (cbFrame <= sizeof(RTNETETHERHDR))
|
---|
[10923] | 2783 | return;
|
---|
[10961] | 2784 | cbFrame -= sizeof(RTNETETHERHDR);
|
---|
[10923] | 2785 |
|
---|
[11053] | 2786 | uint16_t EtherType = RT_H2BE_U16(((PCRTNETETHERHDR)pbFrame)->EtherType);
|
---|
[11055] | 2787 | switch (EtherType)
|
---|
| 2788 | {
|
---|
| 2789 | case RTNET_ETHERTYPE_IPV4:
|
---|
[28025] | 2790 | intnetR0IfSnoopIPv4SourceAddr(pIf, (PCRTNETIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso);
|
---|
[11055] | 2791 | break;
|
---|
[45716] | 2792 |
|
---|
[11055] | 2793 | case RTNET_ETHERTYPE_IPV6:
|
---|
[45716] | 2794 | intnetR0IfSnoopIPv6SourceAddr(pIf, (PCRTNETIPV6)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, fGso);
|
---|
[11055] | 2795 | break;
|
---|
[45716] | 2796 |
|
---|
[10923] | 2797 | #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
|
---|
[11055] | 2798 | case RTNET_ETHERTYPE_IPX_1:
|
---|
| 2799 | case RTNET_ETHERTYPE_IPX_2:
|
---|
| 2800 | case RTNET_ETHERTYPE_IPX_3:
|
---|
[11073] | 2801 | intnetR0IfSnoopIpxSourceAddr(pIf, (PCINTNETIPX)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, pfSgFlags);
|
---|
[11055] | 2802 | break;
|
---|
[10923] | 2803 | #endif
|
---|
[11055] | 2804 | case RTNET_ETHERTYPE_ARP:
|
---|
[11073] | 2805 | intnetR0IfSnoopArpAddr(pIf, (PCRTNETARPIPV4)((PCRTNETETHERHDR)pbFrame + 1), cbFrame, pfSgFlags);
|
---|
[11055] | 2806 | break;
|
---|
| 2807 | }
|
---|
[10923] | 2808 | }
|
---|
| 2809 |
|
---|
| 2810 |
|
---|
[1] | 2811 | /**
|
---|
[26574] | 2812 | * Writes a frame packet to the ring buffer.
|
---|
[1] | 2813 | *
|
---|
| 2814 | * @returns VBox status code.
|
---|
[11069] | 2815 | * @param pBuf The buffer.
|
---|
| 2816 | * @param pRingBuf The ring buffer to read from.
|
---|
| 2817 | * @param pSG The gather list.
|
---|
| 2818 | * @param pNewDstMac Set the destination MAC address to the address if specified.
|
---|
[1] | 2819 | */
|
---|
[26574] | 2820 | static int intnetR0RingWriteFrame(PINTNETRINGBUF pRingBuf, PCINTNETSG pSG, PCRTMAC pNewDstMac)
|
---|
[1] | 2821 | {
|
---|
[26576] | 2822 | PINTNETHDR pHdr = NULL; /* shut up gcc*/
|
---|
| 2823 | void *pvDst = NULL; /* ditto */
|
---|
[28025] | 2824 | int rc;
|
---|
| 2825 | if (pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
|
---|
[28714] | 2826 | rc = IntNetRingAllocateFrame(pRingBuf, pSG->cbTotal, &pHdr, &pvDst);
|
---|
[28025] | 2827 | else
|
---|
[28714] | 2828 | rc = IntNetRingAllocateGsoFrame(pRingBuf, pSG->cbTotal, &pSG->GsoCtx, &pHdr, &pvDst);
|
---|
[26574] | 2829 | if (RT_SUCCESS(rc))
|
---|
[1] | 2830 | {
|
---|
[28714] | 2831 | IntNetSgRead(pSG, pvDst);
|
---|
[11069] | 2832 | if (pNewDstMac)
|
---|
[26574] | 2833 | ((PRTNETETHERHDR)pvDst)->DstMac = *pNewDstMac;
|
---|
[1] | 2834 |
|
---|
[28714] | 2835 | IntNetRingCommitFrame(pRingBuf, pHdr);
|
---|
[1] | 2836 | return VINF_SUCCESS;
|
---|
| 2837 | }
|
---|
[26574] | 2838 | return rc;
|
---|
[1] | 2839 | }
|
---|
| 2840 |
|
---|
| 2841 |
|
---|
[97341] | 2842 | /**
|
---|
[97338] | 2843 | * Notifies consumers of incoming data from @a pIf that data is available.
|
---|
[97339] | 2844 | */
|
---|
[97338] | 2845 | DECL_FORCE_INLINE(void) intnetR0IfNotifyRecv(PINTNETIF pIf)
|
---|
| 2846 | {
|
---|
| 2847 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
| 2848 | RTSemEventSignal(pIf->hRecvEvent);
|
---|
| 2849 | #else
|
---|
| 2850 | pIf->pfnRecvAvail(pIf->hIf, pIf->pvUserRecvAvail);
|
---|
| 2851 | #endif
|
---|
| 2852 | }
|
---|
| 2853 |
|
---|
| 2854 |
|
---|
[1] | 2855 | /**
|
---|
| 2856 | * Sends a frame to a specific interface.
|
---|
| 2857 | *
|
---|
[10740] | 2858 | * @param pIf The interface.
|
---|
| 2859 | * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
|
---|
| 2860 | * @param pSG The gather buffer which data is being sent to the interface.
|
---|
[11069] | 2861 | * @param pNewDstMac Set the destination MAC address to the address if specified.
|
---|
[1] | 2862 | */
|
---|
[11069] | 2863 | static void intnetR0IfSend(PINTNETIF pIf, PINTNETIF pIfSender, PINTNETSG pSG, PCRTMAC pNewDstMac)
|
---|
[1] | 2864 | {
|
---|
[28623] | 2865 | /*
|
---|
| 2866 | * Grab the receive/producer lock and copy over the frame.
|
---|
| 2867 | */
|
---|
[40806] | 2868 | RTSpinlockAcquire(pIf->hRecvInSpinlock);
|
---|
[26574] | 2869 | int rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
|
---|
[52618] | 2870 | RTSpinlockRelease(pIf->hRecvInSpinlock);
|
---|
[10533] | 2871 | if (RT_SUCCESS(rc))
|
---|
[1] | 2872 | {
|
---|
| 2873 | pIf->cYields = 0;
|
---|
[97338] | 2874 | intnetR0IfNotifyRecv(pIf);
|
---|
[1] | 2875 | return;
|
---|
| 2876 | }
|
---|
| 2877 |
|
---|
[10923] | 2878 | Log(("intnetR0IfSend: overflow cb=%d hIf=%RX32\n", pSG->cbTotal, pIf->hIf));
|
---|
[10763] | 2879 |
|
---|
[1] | 2880 | /*
|
---|
[10740] | 2881 | * Scheduling hack, for unicore machines primarily.
|
---|
| 2882 | */
|
---|
[10845] | 2883 | if ( pIf->fActive
|
---|
| 2884 | && pIf->cYields < 4 /* just twice */
|
---|
[28623] | 2885 | && pIfSender /* but not if it's from the trunk */
|
---|
| 2886 | && RTThreadPreemptIsEnabled(NIL_RTTHREAD)
|
---|
| 2887 | )
|
---|
[10740] | 2888 | {
|
---|
| 2889 | unsigned cYields = 2;
|
---|
| 2890 | while (--cYields > 0)
|
---|
[1] | 2891 | {
|
---|
[97338] | 2892 | intnetR0IfNotifyRecv(pIf);
|
---|
[1] | 2893 | RTThreadYield();
|
---|
[28623] | 2894 |
|
---|
[40806] | 2895 | RTSpinlockAcquire(pIf->hRecvInSpinlock);
|
---|
[26574] | 2896 | rc = intnetR0RingWriteFrame(&pIf->pIntBuf->Recv, pSG, pNewDstMac);
|
---|
[52618] | 2897 | RTSpinlockRelease(pIf->hRecvInSpinlock);
|
---|
[10533] | 2898 | if (RT_SUCCESS(rc))
|
---|
[1] | 2899 | {
|
---|
| 2900 | STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsOk);
|
---|
[97338] | 2901 | intnetR0IfNotifyRecv(pIf);
|
---|
[1] | 2902 | return;
|
---|
| 2903 | }
|
---|
| 2904 | pIf->cYields++;
|
---|
[10740] | 2905 | }
|
---|
[1] | 2906 | STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatYieldsNok);
|
---|
| 2907 | }
|
---|
| 2908 |
|
---|
| 2909 | /* ok, the frame is lost. */
|
---|
| 2910 | STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatLost);
|
---|
[97338] | 2911 | intnetR0IfNotifyRecv(pIf);
|
---|
[1] | 2912 | }
|
---|
| 2913 |
|
---|
| 2914 |
|
---|
| 2915 | /**
|
---|
[28025] | 2916 | * Fallback path that does the GSO segmenting before passing the frame on to the
|
---|
| 2917 | * trunk interface.
|
---|
| 2918 | *
|
---|
| 2919 | * The caller holds the trunk lock.
|
---|
| 2920 | *
|
---|
| 2921 | * @param pThis The trunk.
|
---|
[29662] | 2922 | * @param pIfSender The IF sending the frame.
|
---|
[28025] | 2923 | * @param pSG Pointer to the gather list.
|
---|
| 2924 | * @param fDst The destination flags.
|
---|
| 2925 | */
|
---|
[29662] | 2926 | static int intnetR0TrunkIfSendGsoFallback(PINTNETTRUNKIF pThis, PINTNETIF pIfSender, PINTNETSG pSG, uint32_t fDst)
|
---|
[28025] | 2927 | {
|
---|
| 2928 | /*
|
---|
[33540] | 2929 | * Since we're only using this for GSO frame coming from the internal
|
---|
[28025] | 2930 | * network interfaces and never the trunk, we can assume there is only
|
---|
| 2931 | * one segment. This simplifies the code quite a bit.
|
---|
| 2932 | */
|
---|
| 2933 | Assert(PDMNetGsoIsValid(&pSG->GsoCtx, sizeof(pSG->GsoCtx), pSG->cbTotal));
|
---|
| 2934 | AssertReturn(pSG->cSegsUsed == 1, VERR_INTERNAL_ERROR_4);
|
---|
| 2935 |
|
---|
| 2936 | union
|
---|
| 2937 | {
|
---|
[104355] | 2938 | uint8_t abBuf[sizeof(INTNETSG) + 2 * sizeof(INTNETSEG)];
|
---|
[28025] | 2939 | INTNETSG SG;
|
---|
| 2940 | } u;
|
---|
| 2941 |
|
---|
[46921] | 2942 | /** @todo We have to adjust MSS so it does not exceed the value configured for
|
---|
| 2943 | * the host's interface.
|
---|
[46904] | 2944 | */
|
---|
| 2945 |
|
---|
| 2946 | /*
|
---|
[28025] | 2947 | * Carve out the frame segments with the header and frame in different
|
---|
| 2948 | * scatter / gather segments.
|
---|
| 2949 | */
|
---|
| 2950 | uint32_t const cSegs = PDMNetGsoCalcSegmentCount(&pSG->GsoCtx, pSG->cbTotal);
|
---|
| 2951 | for (uint32_t iSeg = 0; iSeg < cSegs; iSeg++)
|
---|
| 2952 | {
|
---|
[38549] | 2953 | uint32_t cbSegPayload, cbSegHdrs;
|
---|
[28025] | 2954 | uint32_t offSegPayload = PDMNetGsoCarveSegment(&pSG->GsoCtx, (uint8_t *)pSG->aSegs[0].pv, pSG->cbTotal, iSeg, cSegs,
|
---|
[38549] | 2955 | pIfSender->abGsoHdrs, &cbSegHdrs, &cbSegPayload);
|
---|
[28025] | 2956 |
|
---|
[38549] | 2957 | IntNetSgInitTempSegs(&u.SG, cbSegHdrs + cbSegPayload, 2, 2);
|
---|
[28025] | 2958 | u.SG.aSegs[0].Phys = NIL_RTHCPHYS;
|
---|
[37909] | 2959 | u.SG.aSegs[0].pv = pIfSender->abGsoHdrs;
|
---|
[38549] | 2960 | u.SG.aSegs[0].cb = cbSegHdrs;
|
---|
[28025] | 2961 | u.SG.aSegs[1].Phys = NIL_RTHCPHYS;
|
---|
| 2962 | u.SG.aSegs[1].pv = (uint8_t *)pSG->aSegs[0].pv + offSegPayload;
|
---|
| 2963 | u.SG.aSegs[1].cb = (uint32_t)cbSegPayload;
|
---|
| 2964 |
|
---|
[29707] | 2965 | int rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, &u.SG, fDst);
|
---|
[28025] | 2966 | if (RT_FAILURE(rc))
|
---|
| 2967 | return rc;
|
---|
| 2968 | }
|
---|
| 2969 | return VINF_SUCCESS;
|
---|
| 2970 | }
|
---|
| 2971 |
|
---|
| 2972 |
|
---|
| 2973 | /**
|
---|
[28120] | 2974 | * Checks if any of the given trunk destinations can handle this kind of GSO SG.
|
---|
| 2975 | *
|
---|
| 2976 | * @returns true if it can, false if it cannot.
|
---|
| 2977 | * @param pThis The trunk.
|
---|
| 2978 | * @param pSG The scatter / gather buffer.
|
---|
[28623] | 2979 | * @param fDst The destination mask.
|
---|
[28120] | 2980 | */
|
---|
| 2981 | DECLINLINE(bool) intnetR0TrunkIfCanHandleGsoFrame(PINTNETTRUNKIF pThis, PINTNETSG pSG, uint32_t fDst)
|
---|
| 2982 | {
|
---|
| 2983 | uint8_t u8Type = pSG->GsoCtx.u8Type;
|
---|
| 2984 | AssertReturn(u8Type < 32, false); /* paranoia */
|
---|
| 2985 | uint32_t fMask = RT_BIT_32(u8Type);
|
---|
| 2986 |
|
---|
| 2987 | if (fDst == INTNETTRUNKDIR_HOST)
|
---|
[28430] | 2988 | return !!(pThis->fHostGsoCapabilites & fMask);
|
---|
[28120] | 2989 | if (fDst == INTNETTRUNKDIR_WIRE)
|
---|
[28430] | 2990 | return !!(pThis->fWireGsoCapabilites & fMask);
|
---|
[28156] | 2991 | Assert(fDst == (INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST));
|
---|
[28430] | 2992 | return !!(pThis->fHostGsoCapabilites & pThis->fWireGsoCapabilites & fMask);
|
---|
[28120] | 2993 | }
|
---|
| 2994 |
|
---|
| 2995 |
|
---|
| 2996 | /**
|
---|
[45716] | 2997 | * Calculates the checksum of a full ipv6 frame.
|
---|
| 2998 | *
|
---|
| 2999 | * @returns 16-bit hecksum value.
|
---|
| 3000 | * @param pIpHdr The IPv6 header (network endian (big)).
|
---|
| 3001 | * @param bProtocol The protocol number. This can be the same as the
|
---|
| 3002 | * ip6_nxt field, but doesn't need to be.
|
---|
| 3003 | * @param cbPkt The packet size (host endian of course). This can
|
---|
| 3004 | * be the same as the ip6_plen field, but as with @a
|
---|
| 3005 | * bProtocol it won't be when extension headers are
|
---|
| 3006 | * present. For UDP this will be uh_ulen converted to
|
---|
| 3007 | * host endian.
|
---|
| 3008 | */
|
---|
| 3009 | static uint16_t computeIPv6FullChecksum(PCRTNETIPV6 pIpHdr)
|
---|
| 3010 | {
|
---|
| 3011 | uint16_t const *data;
|
---|
| 3012 | int len = RT_BE2H_U16(pIpHdr->ip6_plen);
|
---|
| 3013 | uint32_t sum = RTNetIPv6PseudoChecksum(pIpHdr);
|
---|
| 3014 |
|
---|
| 3015 | /* add the payload */
|
---|
| 3016 | data = (uint16_t *) (pIpHdr + 1);
|
---|
| 3017 | while(len > 1)
|
---|
| 3018 | {
|
---|
| 3019 | sum += *(data);
|
---|
| 3020 | data++;
|
---|
| 3021 | len -= 2;
|
---|
| 3022 | }
|
---|
| 3023 |
|
---|
| 3024 | if(len > 0)
|
---|
| 3025 | sum += *((uint8_t *) data);
|
---|
| 3026 |
|
---|
| 3027 | while(sum >> 16)
|
---|
| 3028 | sum = (sum & 0xffff) + (sum >> 16);
|
---|
| 3029 |
|
---|
| 3030 | return (uint16_t) ~sum;
|
---|
| 3031 | }
|
---|
| 3032 |
|
---|
[52543] | 3033 |
|
---|
[45716] | 3034 | /**
|
---|
[52543] | 3035 | * Rewrite VM MAC address with shared host MAC address inside IPv6
|
---|
| 3036 | * Neighbor Discovery datagrams.
|
---|
| 3037 | */
|
---|
| 3038 | static void intnetR0TrunkSharedMacEditIPv6FromIntNet(PINTNETTRUNKIF pThis, PINTNETIF pIfSender,
|
---|
[53624] | 3039 | PRTNETETHERHDR pEthHdr, uint32_t cb)
|
---|
[52543] | 3040 | {
|
---|
| 3041 | if (RT_UNLIKELY(cb < sizeof(*pEthHdr)))
|
---|
| 3042 | return;
|
---|
| 3043 |
|
---|
| 3044 | /* have IPv6 header */
|
---|
| 3045 | PRTNETIPV6 pIPv6 = (PRTNETIPV6)(pEthHdr + 1);
|
---|
| 3046 | cb -= sizeof(*pEthHdr);
|
---|
| 3047 | if (RT_UNLIKELY(cb < sizeof(*pIPv6)))
|
---|
| 3048 | return;
|
---|
| 3049 |
|
---|
| 3050 | if ( pIPv6->ip6_nxt != RTNETIPV6_PROT_ICMPV6
|
---|
| 3051 | || pIPv6->ip6_hlim != 0xff)
|
---|
| 3052 | return;
|
---|
| 3053 |
|
---|
| 3054 | PRTNETICMPV6HDR pICMPv6 = (PRTNETICMPV6HDR)(pIPv6 + 1);
|
---|
| 3055 | cb -= sizeof(*pIPv6);
|
---|
| 3056 | if (RT_UNLIKELY(cb < sizeof(*pICMPv6)))
|
---|
| 3057 | return;
|
---|
| 3058 |
|
---|
[52544] | 3059 | uint32_t hdrlen = 0;
|
---|
[52543] | 3060 | uint8_t llaopt = RTNETIPV6_ICMP_ND_SLLA_OPT;
|
---|
| 3061 |
|
---|
| 3062 | uint8_t type = pICMPv6->icmp6_type;
|
---|
| 3063 | switch (type)
|
---|
| 3064 | {
|
---|
| 3065 | case RTNETIPV6_ICMP_TYPE_RS:
|
---|
[53624] | 3066 | hdrlen = 8;
|
---|
| 3067 | break;
|
---|
[52543] | 3068 |
|
---|
| 3069 | case RTNETIPV6_ICMP_TYPE_RA:
|
---|
[53624] | 3070 | hdrlen = 16;
|
---|
| 3071 | break;
|
---|
[52543] | 3072 |
|
---|
| 3073 | case RTNETIPV6_ICMP_TYPE_NS:
|
---|
[53624] | 3074 | hdrlen = 24;
|
---|
| 3075 | break;
|
---|
[52543] | 3076 |
|
---|
| 3077 | case RTNETIPV6_ICMP_TYPE_NA:
|
---|
[53624] | 3078 | hdrlen = 24;
|
---|
| 3079 | llaopt = RTNETIPV6_ICMP_ND_TLLA_OPT;
|
---|
| 3080 | break;
|
---|
[52543] | 3081 |
|
---|
| 3082 | default:
|
---|
[53624] | 3083 | return;
|
---|
[52543] | 3084 | }
|
---|
| 3085 |
|
---|
| 3086 | AssertReturnVoid(hdrlen > 0);
|
---|
| 3087 | if (RT_UNLIKELY(cb < hdrlen))
|
---|
| 3088 | return;
|
---|
| 3089 |
|
---|
| 3090 | if (RT_UNLIKELY(pICMPv6->icmp6_code != 0))
|
---|
[53624] | 3091 | return;
|
---|
[52543] | 3092 |
|
---|
| 3093 | PRTNETNDP_LLA_OPT pLLAOpt = NULL;
|
---|
| 3094 | char *pOpt = (char *)pICMPv6 + hdrlen;
|
---|
| 3095 | cb -= hdrlen;
|
---|
| 3096 |
|
---|
| 3097 | while (cb >= 8)
|
---|
| 3098 | {
|
---|
| 3099 | uint8_t opt = ((uint8_t *)pOpt)[0];
|
---|
[52544] | 3100 | uint32_t optlen = (uint32_t)((uint8_t *)pOpt)[1] * 8;
|
---|
[52543] | 3101 | if (RT_UNLIKELY(cb < optlen))
|
---|
| 3102 | return;
|
---|
| 3103 |
|
---|
| 3104 | if (opt == llaopt)
|
---|
| 3105 | {
|
---|
[53624] | 3106 | if (RT_UNLIKELY(optlen != 8))
|
---|
| 3107 | return;
|
---|
[52543] | 3108 | pLLAOpt = (PRTNETNDP_LLA_OPT)pOpt;
|
---|
| 3109 | break;
|
---|
| 3110 | }
|
---|
| 3111 |
|
---|
| 3112 | pOpt += optlen;
|
---|
| 3113 | cb -= optlen;
|
---|
| 3114 | }
|
---|
| 3115 |
|
---|
| 3116 | if (pLLAOpt == NULL)
|
---|
| 3117 | return;
|
---|
| 3118 |
|
---|
| 3119 | if (memcmp(&pLLAOpt->lla, &pIfSender->MacAddr, sizeof(RTMAC)) != 0)
|
---|
| 3120 | return;
|
---|
| 3121 |
|
---|
| 3122 | /* overwrite VM's MAC with host's MAC */
|
---|
| 3123 | pLLAOpt->lla = pThis->MacAddr;
|
---|
| 3124 |
|
---|
| 3125 | /* recompute the checksum */
|
---|
| 3126 | pICMPv6->icmp6_cksum = 0;
|
---|
| 3127 | pICMPv6->icmp6_cksum = computeIPv6FullChecksum(pIPv6);
|
---|
| 3128 | }
|
---|
| 3129 |
|
---|
| 3130 |
|
---|
| 3131 | /**
|
---|
[10733] | 3132 | * Sends a frame down the trunk.
|
---|
| 3133 | *
|
---|
| 3134 | * @param pThis The trunk.
|
---|
| 3135 | * @param pNetwork The network the frame is being sent to.
|
---|
[28623] | 3136 | * @param pIfSender The IF sending the frame. Used for MAC address
|
---|
| 3137 | * checks in shared MAC mode.
|
---|
[10733] | 3138 | * @param fDst The destination flags.
|
---|
| 3139 | * @param pSG Pointer to the gather list.
|
---|
| 3140 | */
|
---|
[11072] | 3141 | static void intnetR0TrunkIfSend(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork, PINTNETIF pIfSender,
|
---|
[28623] | 3142 | uint32_t fDst, PINTNETSG pSG)
|
---|
[10733] | 3143 | {
|
---|
[10734] | 3144 | /*
|
---|
| 3145 | * Quick sanity check.
|
---|
| 3146 | */
|
---|
| 3147 | AssertPtr(pThis);
|
---|
| 3148 | AssertPtr(pNetwork);
|
---|
[30587] | 3149 | AssertPtr(pIfSender);
|
---|
[10734] | 3150 | AssertPtr(pSG);
|
---|
| 3151 | Assert(fDst);
|
---|
| 3152 | AssertReturnVoid(pThis->pIfPort);
|
---|
| 3153 |
|
---|
| 3154 | /*
|
---|
[11073] | 3155 | * Edit the frame if we're sharing the MAC address with the host on the wire.
|
---|
[11072] | 3156 | *
|
---|
[11073] | 3157 | * If the frame is headed for both the host and the wire, we'll have to send
|
---|
| 3158 | * it to the host before making any modifications, and force the OS specific
|
---|
| 3159 | * backend to copy it. We do this by marking it as TEMP (which is always the
|
---|
| 3160 | * case right now).
|
---|
[11062] | 3161 | */
|
---|
| 3162 | if ( (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
| 3163 | && (fDst & INTNETTRUNKDIR_WIRE))
|
---|
[11072] | 3164 | {
|
---|
[28623] | 3165 | /*
|
---|
| 3166 | * Dispatch it to the host before making changes.
|
---|
| 3167 | */
|
---|
[11072] | 3168 | if (fDst & INTNETTRUNKDIR_HOST)
|
---|
| 3169 | {
|
---|
| 3170 | Assert(pSG->fFlags & INTNETSG_FLAGS_TEMP); /* make sure copy is forced */
|
---|
[28623] | 3171 | intnetR0TrunkIfSend(pThis, pNetwork, pIfSender, INTNETTRUNKDIR_HOST, pSG);
|
---|
[11072] | 3172 | fDst &= ~INTNETTRUNKDIR_HOST;
|
---|
| 3173 | }
|
---|
[11062] | 3174 |
|
---|
[28623] | 3175 | /*
|
---|
| 3176 | * Edit the source address so that it it's the same as the host.
|
---|
| 3177 | */
|
---|
[28706] | 3178 | /* ASSUME frame from IntNetR0IfSend! */
|
---|
[11072] | 3179 | AssertReturnVoid(pSG->cSegsUsed == 1);
|
---|
| 3180 | AssertReturnVoid(pSG->cbTotal >= sizeof(RTNETETHERHDR));
|
---|
| 3181 | AssertReturnVoid(pIfSender);
|
---|
| 3182 | PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pSG->aSegs[0].pv;
|
---|
| 3183 |
|
---|
[28623] | 3184 | pEthHdr->SrcMac = pThis->MacAddr;
|
---|
[11072] | 3185 |
|
---|
| 3186 | /*
|
---|
| 3187 | * Deal with tags from the snooping phase.
|
---|
| 3188 | */
|
---|
| 3189 | if (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4)
|
---|
| 3190 | {
|
---|
[11073] | 3191 | /*
|
---|
| 3192 | * APR IPv4: replace hardware (MAC) addresses because these end up
|
---|
[33540] | 3193 | * in ARP caches. So, if we don't the other machines will
|
---|
[11073] | 3194 | * send the packets to the MAC address of the guest
|
---|
| 3195 | * instead of the one of the host, which won't work on
|
---|
| 3196 | * wireless of course...
|
---|
| 3197 | */
|
---|
[11072] | 3198 | PRTNETARPIPV4 pArp = (PRTNETARPIPV4)(pEthHdr + 1);
|
---|
[28623] | 3199 | if (!memcmp(&pArp->ar_sha, &pIfSender->MacAddr, sizeof(RTMAC)))
|
---|
[11072] | 3200 | {
|
---|
[28623] | 3201 | Log6(("tw: ar_sha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_sha, &pThis->MacAddr));
|
---|
| 3202 | pArp->ar_sha = pThis->MacAddr;
|
---|
[11072] | 3203 | }
|
---|
[28623] | 3204 | if (!memcmp(&pArp->ar_tha, &pIfSender->MacAddr, sizeof(RTMAC))) /* just in case... */
|
---|
[11072] | 3205 | {
|
---|
[28623] | 3206 | Log6(("tw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArp->ar_tha, &pThis->MacAddr));
|
---|
| 3207 | pArp->ar_tha = pThis->MacAddr;
|
---|
[11072] | 3208 | }
|
---|
| 3209 | }
|
---|
[52543] | 3210 | else if (pEthHdr->EtherType == RT_H2N_U16_C(RTNET_ETHERTYPE_IPV6))
|
---|
[48947] | 3211 | {
|
---|
[52543] | 3212 | intnetR0TrunkSharedMacEditIPv6FromIntNet(pThis, pIfSender, pEthHdr, pSG->cbTotal);
|
---|
[45716] | 3213 | }
|
---|
[11072] | 3214 | }
|
---|
| 3215 |
|
---|
[11062] | 3216 | /*
|
---|
[52543] | 3217 | * Send the frame, handling the GSO fallback.
|
---|
| 3218 | *
|
---|
| 3219 | * Note! The trunk implementation will re-check that the trunk is active
|
---|
[28831] | 3220 | * before sending, so we don't have to duplicate that effort here.
|
---|
[10734] | 3221 | */
|
---|
[30587] | 3222 | STAM_REL_PROFILE_START(&pIfSender->pIntBuf->StatSend2, a);
|
---|
[10734] | 3223 | int rc;
|
---|
[28831] | 3224 | if ( pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID
|
---|
| 3225 | || intnetR0TrunkIfCanHandleGsoFrame(pThis, pSG, fDst) )
|
---|
[29707] | 3226 | rc = pThis->pIfPort->pfnXmit(pThis->pIfPort, pIfSender->pvIfData, pSG, fDst);
|
---|
[10734] | 3227 | else
|
---|
[29662] | 3228 | rc = intnetR0TrunkIfSendGsoFallback(pThis, pIfSender, pSG, fDst);
|
---|
[30587] | 3229 | STAM_REL_PROFILE_STOP(&pIfSender->pIntBuf->StatSend2, a);
|
---|
[10734] | 3230 |
|
---|
| 3231 | /** @todo failure statistics? */
|
---|
[28623] | 3232 | Log2(("intnetR0TrunkIfSend: %Rrc fDst=%d\n", rc, fDst)); NOREF(rc);
|
---|
[10733] | 3233 | }
|
---|
| 3234 |
|
---|
| 3235 |
|
---|
| 3236 | /**
|
---|
[52518] | 3237 | * Detect broadcasts packaged as unicast and convert them back to broadcast.
|
---|
[45716] | 3238 | *
|
---|
[52518] | 3239 | * WiFi routers try to use ethernet unicast instead of broadcast or
|
---|
| 3240 | * multicast when possible. Look inside the packet and fix up
|
---|
| 3241 | * ethernet destination to be proper broadcast or multicast if
|
---|
| 3242 | * necessary.
|
---|
| 3243 | *
|
---|
| 3244 | * @returns true broadcast (pEthHdr & pSG are modified), false if not.
|
---|
[45716] | 3245 | * @param pNetwork The network the frame is being sent to.
|
---|
[52518] | 3246 | * @param pSG Pointer to the gather list for the frame. The
|
---|
| 3247 | * ethernet destination address is modified when
|
---|
| 3248 | * returning true.
|
---|
| 3249 | * @param pEthHdr Pointer to the ethernet header. The ethernet
|
---|
| 3250 | * destination address is modified when returning true.
|
---|
[45716] | 3251 | */
|
---|
[52518] | 3252 | static bool intnetR0NetworkSharedMacDetectAndFixBroadcast(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
|
---|
[45716] | 3253 | {
|
---|
[49480] | 3254 | NOREF(pNetwork);
|
---|
| 3255 |
|
---|
[52518] | 3256 | switch (pEthHdr->EtherType)
|
---|
[45716] | 3257 | {
|
---|
[52518] | 3258 | case RT_H2N_U16_C(RTNET_ETHERTYPE_ARP):
|
---|
| 3259 | {
|
---|
| 3260 | uint16_t ar_oper;
|
---|
[73097] | 3261 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETARPHDR, ar_oper),
|
---|
[52518] | 3262 | sizeof(ar_oper), &ar_oper))
|
---|
| 3263 | return false;
|
---|
[45716] | 3264 |
|
---|
[52518] | 3265 | if (ar_oper == RT_H2N_U16_C(RTNET_ARPOP_REQUEST))
|
---|
| 3266 | {
|
---|
| 3267 | /* change to broadcast */
|
---|
| 3268 | pEthHdr->DstMac.au16[0] = 0xffff;
|
---|
| 3269 | pEthHdr->DstMac.au16[1] = 0xffff;
|
---|
| 3270 | pEthHdr->DstMac.au16[2] = 0xffff;
|
---|
| 3271 | }
|
---|
| 3272 | else
|
---|
| 3273 | return false;
|
---|
| 3274 | break;
|
---|
| 3275 | }
|
---|
| 3276 |
|
---|
| 3277 | case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV4):
|
---|
[45716] | 3278 | {
|
---|
[52518] | 3279 | RTNETADDRIPV4 ip_dst;
|
---|
[73097] | 3280 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV4, ip_dst),
|
---|
[52518] | 3281 | sizeof(ip_dst), &ip_dst))
|
---|
| 3282 | return false;
|
---|
| 3283 |
|
---|
| 3284 | if (ip_dst.u == 0xffffffff) /* 255.255.255.255? */
|
---|
| 3285 | {
|
---|
| 3286 | /* change to broadcast */
|
---|
| 3287 | pEthHdr->DstMac.au16[0] = 0xffff;
|
---|
| 3288 | pEthHdr->DstMac.au16[1] = 0xffff;
|
---|
| 3289 | pEthHdr->DstMac.au16[2] = 0xffff;
|
---|
| 3290 | }
|
---|
| 3291 | else if ((ip_dst.au8[0] & 0xf0) == 0xe0) /* IPv4 multicast? */
|
---|
| 3292 | {
|
---|
| 3293 | /* change to 01:00:5e:xx:xx:xx multicast ... */
|
---|
| 3294 | pEthHdr->DstMac.au8[0] = 0x01;
|
---|
| 3295 | pEthHdr->DstMac.au8[1] = 0x00;
|
---|
| 3296 | pEthHdr->DstMac.au8[2] = 0x5e;
|
---|
| 3297 | /* ... with lower 23 bits from the multicast IP address */
|
---|
| 3298 | pEthHdr->DstMac.au8[3] = ip_dst.au8[1] & 0x7f;
|
---|
| 3299 | pEthHdr->DstMac.au8[4] = ip_dst.au8[2];
|
---|
| 3300 | pEthHdr->DstMac.au8[5] = ip_dst.au8[3];
|
---|
| 3301 | }
|
---|
| 3302 | else
|
---|
| 3303 | return false;
|
---|
| 3304 | break;
|
---|
| 3305 | }
|
---|
| 3306 |
|
---|
| 3307 | case RT_H2N_U16_C(RTNET_ETHERTYPE_IPV6):
|
---|
[45716] | 3308 | {
|
---|
[52518] | 3309 | RTNETADDRIPV6 ip6_dst;
|
---|
[73097] | 3310 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV6, ip6_dst),
|
---|
[52518] | 3311 | sizeof(ip6_dst), &ip6_dst))
|
---|
| 3312 | return false;
|
---|
| 3313 |
|
---|
| 3314 | if (ip6_dst.au8[0] == 0xff) /* IPv6 multicast? */
|
---|
| 3315 | {
|
---|
| 3316 | pEthHdr->DstMac.au16[0] = 0x3333;
|
---|
| 3317 | pEthHdr->DstMac.au16[1] = ip6_dst.au16[6];
|
---|
| 3318 | pEthHdr->DstMac.au16[2] = ip6_dst.au16[7];
|
---|
| 3319 | }
|
---|
| 3320 | else
|
---|
| 3321 | return false;
|
---|
| 3322 | break;
|
---|
[45716] | 3323 | }
|
---|
[52518] | 3324 |
|
---|
| 3325 | default:
|
---|
| 3326 | return false;
|
---|
[45716] | 3327 | }
|
---|
| 3328 |
|
---|
[52518] | 3329 |
|
---|
| 3330 | /*
|
---|
| 3331 | * Update ethernet destination in the segment.
|
---|
| 3332 | */
|
---|
[73097] | 3333 | intnetR0SgWritePart(pSG, RT_UOFFSETOF(RTNETETHERHDR, DstMac), sizeof(pEthHdr->DstMac), &pEthHdr->DstMac);
|
---|
[52518] | 3334 |
|
---|
| 3335 | return true;
|
---|
[45716] | 3336 | }
|
---|
| 3337 |
|
---|
| 3338 |
|
---|
| 3339 | /**
|
---|
| 3340 | * Snoops a multicast ICMPv6 ND DAD from the wire via the trunk connection.
|
---|
| 3341 | *
|
---|
| 3342 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3343 | * @param pSG Pointer to the gather list for the frame.
|
---|
[48947] | 3344 | * @param pEthHdr Pointer to the ethernet header.
|
---|
[45716] | 3345 | */
|
---|
| 3346 | static void intnetR0NetworkSnoopNAFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
|
---|
| 3347 | {
|
---|
[49480] | 3348 | NOREF(pEthHdr);
|
---|
| 3349 |
|
---|
[45716] | 3350 | /*
|
---|
| 3351 | * Check the minimum size and get a linear copy of the thing to work on,
|
---|
| 3352 | * using the temporary buffer if necessary.
|
---|
| 3353 | */
|
---|
[48947] | 3354 | if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
|
---|
[45716] | 3355 | sizeof(RTNETNDP)))
|
---|
| 3356 | return;
|
---|
| 3357 | PRTNETIPV6 pIPv6 = (PRTNETIPV6)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
|
---|
| 3358 | if ( pSG->cSegsUsed != 1
|
---|
| 3359 | && pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETIPV6) +
|
---|
| 3360 | sizeof(RTNETNDP))
|
---|
| 3361 | {
|
---|
| 3362 | Log6(("fw: Copying IPv6 pkt %u\n", sizeof(RTNETIPV6)));
|
---|
| 3363 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETIPV6)
|
---|
| 3364 | + sizeof(RTNETNDP), pNetwork->pbTmp))
|
---|
| 3365 | return;
|
---|
| 3366 | pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
|
---|
| 3367 | pIPv6 = (PRTNETIPV6)pNetwork->pbTmp;
|
---|
| 3368 | }
|
---|
| 3369 |
|
---|
| 3370 | PCRTNETNDP pNd = (PCRTNETNDP) (pIPv6 + 1);
|
---|
| 3371 |
|
---|
| 3372 | /*
|
---|
| 3373 | * a multicast NS with :: as source address means a DAD packet.
|
---|
| 3374 | * if it comes from the wire and we have the DAD'd address in our cache,
|
---|
| 3375 | * flush the entry as the address is being acquired by someone else on
|
---|
| 3376 | * the network.
|
---|
| 3377 | */
|
---|
| 3378 | if ( pIPv6->ip6_hlim == 0xff
|
---|
| 3379 | && pIPv6->ip6_nxt == RTNETIPV6_PROT_ICMPV6
|
---|
[52543] | 3380 | && pNd->Hdr.icmp6_type == RTNETIPV6_ICMP_TYPE_NS
|
---|
| 3381 | && pNd->Hdr.icmp6_code == 0
|
---|
[45716] | 3382 | && pIPv6->ip6_src.QWords.qw0 == 0
|
---|
| 3383 | && pIPv6->ip6_src.QWords.qw1 == 0)
|
---|
| 3384 | {
|
---|
[48947] | 3385 |
|
---|
| 3386 | intnetR0NetworkAddrCacheDelete(pNetwork, (PCRTNETADDRU) &pNd->target_address,
|
---|
[45716] | 3387 | kIntNetAddrType_IPv6, sizeof(RTNETADDRIPV6), "tif/ip6");
|
---|
| 3388 | }
|
---|
| 3389 | }
|
---|
| 3390 | /**
|
---|
[11072] | 3391 | * Edits an ARP packet arriving from the wire via the trunk connection.
|
---|
| 3392 | *
|
---|
| 3393 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3394 | * @param pSG Pointer to the gather list for the frame.
|
---|
| 3395 | * The flags and data content may be updated.
|
---|
| 3396 | * @param pEthHdr Pointer to the ethernet header. This may also be
|
---|
| 3397 | * updated if it's a unicast...
|
---|
| 3398 | */
|
---|
| 3399 | static void intnetR0NetworkEditArpFromWire(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
|
---|
| 3400 | {
|
---|
| 3401 | /*
|
---|
[11073] | 3402 | * Check the minimum size and get a linear copy of the thing to work on,
|
---|
| 3403 | * using the temporary buffer if necessary.
|
---|
[11072] | 3404 | */
|
---|
[11073] | 3405 | if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4)))
|
---|
[11072] | 3406 | return;
|
---|
[11073] | 3407 | PRTNETARPIPV4 pArpIPv4 = (PRTNETARPIPV4)((uint8_t *)pSG->aSegs[0].pv + sizeof(RTNETETHERHDR));
|
---|
[11072] | 3408 | if ( pSG->cSegsUsed != 1
|
---|
[11073] | 3409 | && pSG->aSegs[0].cb < sizeof(RTNETETHERHDR) + sizeof(RTNETARPIPV4))
|
---|
[11072] | 3410 | {
|
---|
[11073] | 3411 | Log6(("fw: Copying ARP pkt %u\n", sizeof(RTNETARPIPV4)));
|
---|
| 3412 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), sizeof(RTNETARPIPV4), pNetwork->pbTmp))
|
---|
[11072] | 3413 | return;
|
---|
| 3414 | pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
|
---|
[11073] | 3415 | pArpIPv4 = (PRTNETARPIPV4)pNetwork->pbTmp;
|
---|
[11072] | 3416 | }
|
---|
| 3417 |
|
---|
| 3418 | /*
|
---|
[11073] | 3419 | * Ignore packets which doesn't interest us or we perceive as malformed.
|
---|
[11072] | 3420 | */
|
---|
[11073] | 3421 | if (RT_UNLIKELY( pArpIPv4->Hdr.ar_hlen != sizeof(RTMAC)
|
---|
| 3422 | || pArpIPv4->Hdr.ar_plen != sizeof(RTNETADDRIPV4)
|
---|
| 3423 | || pArpIPv4->Hdr.ar_htype != RT_H2BE_U16(RTNET_ARP_ETHER)
|
---|
| 3424 | || pArpIPv4->Hdr.ar_ptype != RT_H2BE_U16(RTNET_ETHERTYPE_IPV4)))
|
---|
[11072] | 3425 | return;
|
---|
[11073] | 3426 | uint16_t ar_oper = RT_H2BE_U16(pArpIPv4->Hdr.ar_oper);
|
---|
[11072] | 3427 | if (RT_UNLIKELY( ar_oper != RTNET_ARPOP_REQUEST
|
---|
[11073] | 3428 | && ar_oper != RTNET_ARPOP_REPLY))
|
---|
| 3429 | {
|
---|
| 3430 | Log6(("ar_oper=%#x\n", ar_oper));
|
---|
[11072] | 3431 | return;
|
---|
[11073] | 3432 | }
|
---|
[11072] | 3433 |
|
---|
[11073] | 3434 | /* Tag it as ARP IPv4. */
|
---|
| 3435 | pSG->fFlags |= INTNETSG_FLAGS_ARP_IPV4;
|
---|
| 3436 |
|
---|
[11072] | 3437 | /*
|
---|
[11073] | 3438 | * The thing we're interested in here is a reply to a query made by a guest
|
---|
| 3439 | * since we modified the MAC in the initial request the guest made.
|
---|
[11072] | 3440 | */
|
---|
[52134] | 3441 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
| 3442 | RTMAC MacAddrTrunk;
|
---|
| 3443 | if (pNetwork->MacTab.pTrunk)
|
---|
| 3444 | MacAddrTrunk = pNetwork->MacTab.pTrunk->MacAddr;
|
---|
| 3445 | else
|
---|
| 3446 | memset(&MacAddrTrunk, 0, sizeof(MacAddrTrunk));
|
---|
[52618] | 3447 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[11073] | 3448 | if ( ar_oper == RTNET_ARPOP_REPLY
|
---|
[52134] | 3449 | && !memcmp(&pArpIPv4->ar_tha, &MacAddrTrunk, sizeof(RTMAC)))
|
---|
[11072] | 3450 | {
|
---|
[11073] | 3451 | PINTNETIF pIf = intnetR0NetworkAddrCacheLookupIf(pNetwork, (PCRTNETADDRU)&pArpIPv4->ar_tpa,
|
---|
| 3452 | kIntNetAddrType_IPv4, sizeof(pArpIPv4->ar_tpa));
|
---|
| 3453 | if (pIf)
|
---|
[11072] | 3454 | {
|
---|
[28623] | 3455 | Log6(("fw: ar_tha %.6Rhxs -> %.6Rhxs\n", &pArpIPv4->ar_tha, &pIf->MacAddr));
|
---|
| 3456 | pArpIPv4->ar_tha = pIf->MacAddr;
|
---|
[52134] | 3457 | if (!memcmp(&pEthHdr->DstMac, &MacAddrTrunk, sizeof(RTMAC)))
|
---|
[11072] | 3458 | {
|
---|
[28623] | 3459 | Log6(("fw: DstMac %.6Rhxs -> %.6Rhxs\n", &pEthHdr->DstMac, &pIf->MacAddr));
|
---|
| 3460 | pEthHdr->DstMac = pIf->MacAddr;
|
---|
[11073] | 3461 | if ((void *)pEthHdr != pSG->aSegs[0].pv)
|
---|
[73097] | 3462 | intnetR0SgWritePart(pSG, RT_UOFFSETOF(RTNETETHERHDR, DstMac), sizeof(RTMAC), &pIf->MacAddr);
|
---|
[11073] | 3463 | }
|
---|
[28623] | 3464 | intnetR0BusyDecIf(pIf);
|
---|
[11072] | 3465 |
|
---|
[11073] | 3466 | /* Write back the packet if we've been making changes to a buffered copy. */
|
---|
| 3467 | if (pSG->fFlags & INTNETSG_FLAGS_PKT_CP_IN_TMP)
|
---|
| 3468 | intnetR0SgWritePart(pSG, sizeof(RTNETETHERHDR), sizeof(PRTNETARPIPV4), pArpIPv4);
|
---|
[11072] | 3469 | }
|
---|
| 3470 | }
|
---|
| 3471 | }
|
---|
| 3472 |
|
---|
| 3473 |
|
---|
| 3474 | /**
|
---|
[14695] | 3475 | * Detects and edits an DHCP packet arriving from the internal net.
|
---|
| 3476 | *
|
---|
| 3477 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3478 | * @param pSG Pointer to the gather list for the frame.
|
---|
| 3479 | * The flags and data content may be updated.
|
---|
| 3480 | * @param pEthHdr Pointer to the ethernet header. This may also be
|
---|
| 3481 | * updated if it's a unicast...
|
---|
| 3482 | */
|
---|
| 3483 | static void intnetR0NetworkEditDhcpFromIntNet(PINTNETNETWORK pNetwork, PINTNETSG pSG, PRTNETETHERHDR pEthHdr)
|
---|
| 3484 | {
|
---|
[39091] | 3485 | NOREF(pEthHdr);
|
---|
| 3486 |
|
---|
[14695] | 3487 | /*
|
---|
| 3488 | * Check the minimum size and get a linear copy of the thing to work on,
|
---|
| 3489 | * using the temporary buffer if necessary.
|
---|
| 3490 | */
|
---|
| 3491 | if (RT_UNLIKELY(pSG->cbTotal < sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN))
|
---|
| 3492 | return;
|
---|
| 3493 | /*
|
---|
| 3494 | * Get a pointer to a linear copy of the full packet, using the
|
---|
| 3495 | * temporary buffer if necessary.
|
---|
| 3496 | */
|
---|
| 3497 | PCRTNETIPV4 pIpHdr = (PCRTNETIPV4)((PCRTNETETHERHDR)pSG->aSegs[0].pv + 1);
|
---|
[18459] | 3498 | uint32_t cbPacket = pSG->cbTotal - sizeof(RTNETETHERHDR);
|
---|
[14695] | 3499 | if (pSG->cSegsUsed > 1)
|
---|
| 3500 | {
|
---|
| 3501 | cbPacket = RT_MIN(cbPacket, INTNETNETWORK_TMP_SIZE);
|
---|
| 3502 | Log6(("intnetR0NetworkEditDhcpFromIntNet: Copying IPv4/UDP/DHCP pkt %u\n", cbPacket));
|
---|
| 3503 | if (!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR), cbPacket, pNetwork->pbTmp))
|
---|
| 3504 | return;
|
---|
| 3505 | //pSG->fFlags |= INTNETSG_FLAGS_PKT_CP_IN_TMP;
|
---|
| 3506 | pIpHdr = (PCRTNETIPV4)pNetwork->pbTmp;
|
---|
| 3507 | }
|
---|
| 3508 |
|
---|
| 3509 | /*
|
---|
| 3510 | * Validate the IP header and find the UDP packet.
|
---|
| 3511 | */
|
---|
[28025] | 3512 | if (!RTNetIPv4IsHdrValid(pIpHdr, cbPacket, pSG->cbTotal - sizeof(RTNETETHERHDR), true /*fCheckSum*/))
|
---|
[14695] | 3513 | {
|
---|
| 3514 | Log6(("intnetR0NetworkEditDhcpFromIntNet: bad ip header\n"));
|
---|
| 3515 | return;
|
---|
| 3516 | }
|
---|
| 3517 | size_t cbIpHdr = pIpHdr->ip_hl * 4;
|
---|
| 3518 | if ( pIpHdr->ip_p != RTNETIPV4_PROT_UDP /* DHCP is UDP. */
|
---|
| 3519 | || cbPacket < cbIpHdr + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN) /* Min DHCP packet len */
|
---|
| 3520 | return;
|
---|
[15505] | 3521 |
|
---|
[14695] | 3522 | size_t cbUdpPkt = cbPacket - cbIpHdr;
|
---|
| 3523 | PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uintptr_t)pIpHdr + cbIpHdr);
|
---|
| 3524 | /* We are only interested in DHCP packets coming from client to server. */
|
---|
| 3525 | if ( RT_BE2H_U16(pUdpHdr->uh_dport) != RTNETIPV4_PORT_BOOTPS
|
---|
| 3526 | || RT_BE2H_U16(pUdpHdr->uh_sport) != RTNETIPV4_PORT_BOOTPC)
|
---|
| 3527 | return;
|
---|
| 3528 |
|
---|
| 3529 | /*
|
---|
| 3530 | * Check if the DHCP message is valid and get the type.
|
---|
| 3531 | */
|
---|
[28025] | 3532 | if (!RTNetIPv4IsUDPValid(pIpHdr, pUdpHdr, pUdpHdr + 1, cbUdpPkt, true /*fCheckSum*/))
|
---|
[14695] | 3533 | {
|
---|
| 3534 | Log6(("intnetR0NetworkEditDhcpFromIntNet: Bad UDP packet\n"));
|
---|
| 3535 | return;
|
---|
| 3536 | }
|
---|
| 3537 | PCRTNETBOOTP pDhcp = (PCRTNETBOOTP)(pUdpHdr + 1);
|
---|
[37979] | 3538 | uint8_t bMsgType;
|
---|
| 3539 | if (!RTNetIPv4IsDHCPValid(pUdpHdr, pDhcp, cbUdpPkt - sizeof(*pUdpHdr), &bMsgType))
|
---|
[14695] | 3540 | {
|
---|
| 3541 | Log6(("intnetR0NetworkEditDhcpFromIntNet: Bad DHCP packet\n"));
|
---|
| 3542 | return;
|
---|
| 3543 | }
|
---|
| 3544 |
|
---|
[37979] | 3545 | switch (bMsgType)
|
---|
[14695] | 3546 | {
|
---|
| 3547 | case RTNET_DHCP_MT_DISCOVER:
|
---|
| 3548 | case RTNET_DHCP_MT_REQUEST:
|
---|
[37979] | 3549 | /*
|
---|
| 3550 | * Must set the broadcast flag or we won't catch the respons.
|
---|
| 3551 | */
|
---|
[14695] | 3552 | if (!(pDhcp->bp_flags & RT_H2BE_U16_C(RTNET_DHCP_FLAG_BROADCAST)))
|
---|
| 3553 | {
|
---|
[37979] | 3554 | Log6(("intnetR0NetworkEditDhcpFromIntNet: Setting broadcast flag in DHCP %#x, previously %x\n",
|
---|
| 3555 | bMsgType, pDhcp->bp_flags));
|
---|
| 3556 |
|
---|
[14695] | 3557 | /* Patch flags */
|
---|
| 3558 | uint16_t uFlags = pDhcp->bp_flags | RT_H2BE_U16_C(RTNET_DHCP_FLAG_BROADCAST);
|
---|
[18459] | 3559 | intnetR0SgWritePart(pSG, (uintptr_t)&pDhcp->bp_flags - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR), sizeof(uFlags), &uFlags);
|
---|
[37979] | 3560 |
|
---|
[14695] | 3561 | /* Patch UDP checksum */
|
---|
[57846] | 3562 | if (pUdpHdr->uh_sum != 0)
|
---|
| 3563 | {
|
---|
| 3564 | uint32_t uChecksum = (uint32_t)~pUdpHdr->uh_sum + RT_H2BE_U16_C(RTNET_DHCP_FLAG_BROADCAST);
|
---|
| 3565 | while (uChecksum >> 16)
|
---|
| 3566 | uChecksum = (uChecksum >> 16) + (uChecksum & 0xFFFF);
|
---|
| 3567 | uChecksum = ~uChecksum;
|
---|
| 3568 | intnetR0SgWritePart(pSG,
|
---|
| 3569 | (uintptr_t)&pUdpHdr->uh_sum - (uintptr_t)pIpHdr + sizeof(RTNETETHERHDR),
|
---|
| 3570 | sizeof(pUdpHdr->uh_sum),
|
---|
| 3571 | &uChecksum);
|
---|
| 3572 | }
|
---|
[14695] | 3573 | }
|
---|
[37979] | 3574 |
|
---|
| 3575 | #ifdef RT_OS_DARWIN
|
---|
| 3576 | /*
|
---|
| 3577 | * Work around little endian checksum issue in mac os x 10.7.0 GM.
|
---|
| 3578 | */
|
---|
| 3579 | if ( pIpHdr->ip_tos
|
---|
| 3580 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_WORKAROUND_1))
|
---|
| 3581 | {
|
---|
| 3582 | /* Patch it. */
|
---|
| 3583 | uint8_t uTos = pIpHdr->ip_tos;
|
---|
| 3584 | uint8_t uZero = 0;
|
---|
| 3585 | intnetR0SgWritePart(pSG, sizeof(RTNETETHERHDR) + 1, sizeof(uZero), &uZero);
|
---|
| 3586 |
|
---|
| 3587 | /* Patch the IP header checksum. */
|
---|
| 3588 | uint32_t uChecksum = (uint32_t)~pIpHdr->ip_sum - (uTos << 8);
|
---|
| 3589 | while (uChecksum >> 16)
|
---|
| 3590 | uChecksum = (uChecksum >> 16) + (uChecksum & 0xFFFF);
|
---|
| 3591 | uChecksum = ~uChecksum;
|
---|
| 3592 |
|
---|
| 3593 | Log(("intnetR0NetworkEditDhcpFromIntNet: cleared ip_tos (was %#04x); ip_sum=%#06x -> %#06x\n",
|
---|
| 3594 | uTos, RT_BE2H_U16(pIpHdr->ip_sum), RT_BE2H_U16(uChecksum) ));
|
---|
[73097] | 3595 | intnetR0SgWritePart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV4, ip_sum),
|
---|
[37979] | 3596 | sizeof(pIpHdr->ip_sum), &uChecksum);
|
---|
| 3597 | }
|
---|
| 3598 | #endif
|
---|
[14695] | 3599 | break;
|
---|
| 3600 | }
|
---|
| 3601 | }
|
---|
| 3602 |
|
---|
| 3603 |
|
---|
| 3604 | /**
|
---|
[28623] | 3605 | * Checks if the callers context is okay for sending to the specified
|
---|
| 3606 | * destinations.
|
---|
[10733] | 3607 | *
|
---|
[28623] | 3608 | * @returns true if it's okay, false if it isn't.
|
---|
| 3609 | * @param pNetwork The network.
|
---|
[28699] | 3610 | * @param pIfSender The interface sending or NULL if it's the trunk.
|
---|
[28623] | 3611 | * @param pDstTab The destination table.
|
---|
| 3612 | */
|
---|
[28699] | 3613 | DECLINLINE(bool) intnetR0NetworkIsContextOk(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, PCINTNETDSTTAB pDstTab)
|
---|
[28623] | 3614 | {
|
---|
[39091] | 3615 | NOREF(pNetwork);
|
---|
| 3616 |
|
---|
[28699] | 3617 | /* Sending to the trunk is the problematic path. If the trunk is the
|
---|
| 3618 | sender we won't be sending to it, so no problem..
|
---|
| 3619 | Note! fTrunkDst may be set event if if the trunk is the sender. */
|
---|
| 3620 | if (!pIfSender)
|
---|
| 3621 | return true;
|
---|
| 3622 |
|
---|
| 3623 | uint32_t const fTrunkDst = pDstTab->fTrunkDst;
|
---|
[28623] | 3624 | if (!fTrunkDst)
|
---|
| 3625 | return true;
|
---|
| 3626 |
|
---|
| 3627 | /* ASSUMES: that the trunk won't change its report while we're checking. */
|
---|
| 3628 | PINTNETTRUNKIF pTrunk = pDstTab->pTrunk;
|
---|
[52134] | 3629 | if (pTrunk && (fTrunkDst & pTrunk->fNoPreemptDsts) == fTrunkDst)
|
---|
[28623] | 3630 | return true;
|
---|
| 3631 |
|
---|
[43387] | 3632 | /* ASSUMES: That a preemption test detects HM contexts. (Will work on
|
---|
[28623] | 3633 | non-preemptive systems as well.) */
|
---|
| 3634 | if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
|
---|
| 3635 | return true;
|
---|
| 3636 | return false;
|
---|
| 3637 | }
|
---|
| 3638 |
|
---|
| 3639 |
|
---|
| 3640 | /**
|
---|
| 3641 | * Checks if the callers context is okay for doing a broadcast given the
|
---|
| 3642 | * specified source.
|
---|
[10733] | 3643 | *
|
---|
[28623] | 3644 | * @returns true if it's okay, false if it isn't.
|
---|
| 3645 | * @param pNetwork The network.
|
---|
| 3646 | * @param fSrc The source of the packet. (0 (intnet),
|
---|
| 3647 | * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE).
|
---|
[10733] | 3648 | */
|
---|
[28623] | 3649 | DECLINLINE(bool) intnetR0NetworkIsContextOkForBroadcast(PINTNETNETWORK pNetwork, uint32_t fSrc)
|
---|
[10733] | 3650 | {
|
---|
[28699] | 3651 | /* Sending to the trunk is the problematic path. If the trunk is the
|
---|
| 3652 | sender we won't be sending to it, so no problem. */
|
---|
| 3653 | if (fSrc)
|
---|
[28623] | 3654 | return true;
|
---|
| 3655 |
|
---|
[43387] | 3656 | /* ASSUMES: That a preemption test detects HM contexts. (Will work on
|
---|
[28623] | 3657 | non-preemptive systems as well.) */
|
---|
| 3658 | if (RTThreadPreemptIsEnabled(NIL_RTTHREAD))
|
---|
| 3659 | return true;
|
---|
| 3660 |
|
---|
| 3661 | /* PARANOIA: Grab the spinlock to make sure the trunk structure cannot be
|
---|
| 3662 | freed while we're touching it. */
|
---|
[40806] | 3663 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 3664 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 3665 |
|
---|
| 3666 | bool fRc = !pTrunk
|
---|
[28722] | 3667 | || pTrunk->fNoPreemptDsts == (INTNETTRUNKDIR_HOST | INTNETTRUNKDIR_WIRE)
|
---|
| 3668 | || ( (!pNetwork->MacTab.fHostActive || (pTrunk->fNoPreemptDsts & INTNETTRUNKDIR_HOST) )
|
---|
| 3669 | && (!pNetwork->MacTab.fWireActive || (pTrunk->fNoPreemptDsts & INTNETTRUNKDIR_WIRE) ) );
|
---|
[28623] | 3670 |
|
---|
[52618] | 3671 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 3672 |
|
---|
| 3673 | return fRc;
|
---|
| 3674 | }
|
---|
| 3675 |
|
---|
| 3676 |
|
---|
| 3677 | /**
|
---|
| 3678 | * Check context, edit, snoop and switch a broadcast frame when sharing MAC
|
---|
| 3679 | * address on the wire.
|
---|
| 3680 | *
|
---|
| 3681 | * The caller must hold at least one interface on the network busy to prevent it
|
---|
| 3682 | * from destructing beath us.
|
---|
| 3683 | *
|
---|
| 3684 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3685 | * @param fSrc The source of the packet. (0 (intnet),
|
---|
| 3686 | * INTNETTRUNKDIR_HOST or INTNETTRUNKDIR_WIRE).
|
---|
| 3687 | * @param pIfSender The sender interface, NULL if trunk. Used to
|
---|
| 3688 | * prevent sending an echo to the sender.
|
---|
| 3689 | * @param pSG Pointer to the gather list.
|
---|
| 3690 | * @param pEthHdr Pointer to the ethernet header.
|
---|
| 3691 | * @param pDstTab The destination output table.
|
---|
| 3692 | */
|
---|
| 3693 | static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchBroadcast(PINTNETNETWORK pNetwork,
|
---|
| 3694 | uint32_t fSrc, PINTNETIF pIfSender,
|
---|
| 3695 | PINTNETSG pSG, PRTNETETHERHDR pEthHdr,
|
---|
| 3696 | PINTNETDSTTAB pDstTab)
|
---|
| 3697 | {
|
---|
[10733] | 3698 | /*
|
---|
[28623] | 3699 | * Before doing any work here, we need to figure out if we can handle it
|
---|
| 3700 | * in the current context. The restrictions are solely on the trunk.
|
---|
| 3701 | *
|
---|
| 3702 | * Note! Since at least one interface is busy, there won't be any changes
|
---|
| 3703 | * to the parameters here (unless the trunk changes its capability
|
---|
| 3704 | * report, which it shouldn't).
|
---|
| 3705 | */
|
---|
| 3706 | if (!intnetR0NetworkIsContextOkForBroadcast(pNetwork, fSrc))
|
---|
| 3707 | return INTNETSWDECISION_BAD_CONTEXT;
|
---|
| 3708 |
|
---|
| 3709 | /*
|
---|
[45716] | 3710 | * Check for ICMPv6 Neighbor Advertisements coming from the trunk.
|
---|
| 3711 | * If we see an advertisement for an IP in our cache, we can safely remove
|
---|
| 3712 | * it as the IP has probably moved.
|
---|
| 3713 | */
|
---|
| 3714 | if ( (fSrc & INTNETTRUNKDIR_WIRE)
|
---|
| 3715 | && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV6
|
---|
| 3716 | && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
|
---|
| 3717 | intnetR0NetworkSnoopNAFromWire(pNetwork, pSG, pEthHdr);
|
---|
| 3718 |
|
---|
| 3719 |
|
---|
| 3720 | /*
|
---|
[11072] | 3721 | * Check for ARP packets from the wire since we'll have to make
|
---|
| 3722 | * modification to them if we're sharing the MAC address with the host.
|
---|
| 3723 | */
|
---|
[28623] | 3724 | if ( (fSrc & INTNETTRUNKDIR_WIRE)
|
---|
| 3725 | && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_ARP
|
---|
| 3726 | && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
|
---|
[11072] | 3727 | intnetR0NetworkEditArpFromWire(pNetwork, pSG, pEthHdr);
|
---|
| 3728 |
|
---|
[28623] | 3729 | /*
|
---|
[14695] | 3730 | * Check for DHCP packets from the internal net since we'll have to set
|
---|
| 3731 | * broadcast flag in DHCP requests if we're sharing the MAC address with
|
---|
[28025] | 3732 | * the host. GSO is not applicable to DHCP traffic.
|
---|
[14695] | 3733 | */
|
---|
[28623] | 3734 | if ( !fSrc
|
---|
[28025] | 3735 | && RT_BE2H_U16(pEthHdr->EtherType) == RTNET_ETHERTYPE_IPV4
|
---|
| 3736 | && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
|
---|
[14695] | 3737 | intnetR0NetworkEditDhcpFromIntNet(pNetwork, pSG, pEthHdr);
|
---|
| 3738 |
|
---|
[11072] | 3739 | /*
|
---|
[33540] | 3740 | * Snoop address info from packet originating from the trunk connection.
|
---|
[11055] | 3741 | */
|
---|
[28623] | 3742 | if (fSrc)
|
---|
[11055] | 3743 | {
|
---|
[11074] | 3744 | #ifdef INTNET_WITH_DHCP_SNOOPING
|
---|
[11055] | 3745 | uint16_t EtherType = RT_BE2H_U16(pEthHdr->EtherType);
|
---|
| 3746 | if ( ( EtherType == RTNET_ETHERTYPE_IPV4 /* for DHCP */
|
---|
[28025] | 3747 | && pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
|
---|
| 3748 | && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID )
|
---|
[28623] | 3749 | || (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4) )
|
---|
[11055] | 3750 | intnetR0TrunkIfSnoopAddr(pNetwork, pSG, EtherType);
|
---|
[11074] | 3751 | #else
|
---|
[28623] | 3752 | if (pSG->fFlags & INTNETSG_FLAGS_ARP_IPV4)
|
---|
[11074] | 3753 | intnetR0TrunkIfSnoopArp(pNetwork, pSG);
|
---|
| 3754 | #endif
|
---|
[11055] | 3755 | }
|
---|
| 3756 |
|
---|
[28623] | 3757 | /*
|
---|
| 3758 | * Create the broadcast destination table.
|
---|
| 3759 | */
|
---|
| 3760 | return intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab);
|
---|
[10733] | 3761 | }
|
---|
| 3762 |
|
---|
| 3763 |
|
---|
| 3764 | /**
|
---|
[28623] | 3765 | * Check context, snoop and switch a unicast frame using the network layer
|
---|
| 3766 | * address of the link layer one (when sharing MAC address on the wire).
|
---|
[10733] | 3767 | *
|
---|
[29160] | 3768 | * This function is only used for frames coming from the wire (trunk).
|
---|
[10733] | 3769 | *
|
---|
| 3770 | * @returns true if it's addressed to someone on the network, otherwise false.
|
---|
| 3771 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3772 | * @param pSG Pointer to the gather list.
|
---|
| 3773 | * @param pEthHdr Pointer to the ethernet header.
|
---|
[28623] | 3774 | * @param pDstTab The destination output table.
|
---|
[10733] | 3775 | */
|
---|
[28623] | 3776 | static INTNETSWDECISION intnetR0NetworkSharedMacFixAndSwitchUnicast(PINTNETNETWORK pNetwork, PINTNETSG pSG,
|
---|
| 3777 | PRTNETETHERHDR pEthHdr, PINTNETDSTTAB pDstTab)
|
---|
[10733] | 3778 | {
|
---|
[11055] | 3779 | /*
|
---|
| 3780 | * Extract the network address from the packet.
|
---|
| 3781 | */
|
---|
| 3782 | RTNETADDRU Addr;
|
---|
| 3783 | INTNETADDRTYPE enmAddrType;
|
---|
| 3784 | uint8_t cbAddr;
|
---|
| 3785 | switch (RT_BE2H_U16(pEthHdr->EtherType))
|
---|
| 3786 | {
|
---|
| 3787 | case RTNET_ETHERTYPE_IPV4:
|
---|
[73097] | 3788 | if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV4, ip_dst), sizeof(Addr.IPv4), &Addr)))
|
---|
[11069] | 3789 | {
|
---|
| 3790 | Log(("intnetshareduni: failed to read ip_dst! cbTotal=%#x\n", pSG->cbTotal));
|
---|
[28623] | 3791 | return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
|
---|
[11069] | 3792 | }
|
---|
[11055] | 3793 | enmAddrType = kIntNetAddrType_IPv4;
|
---|
| 3794 | cbAddr = sizeof(Addr.IPv4);
|
---|
[11069] | 3795 | Log6(("intnetshareduni: IPv4 %d.%d.%d.%d\n", Addr.au8[0], Addr.au8[1], Addr.au8[2], Addr.au8[3]));
|
---|
[11055] | 3796 | break;
|
---|
| 3797 |
|
---|
[45716] | 3798 | case RTNET_ETHERTYPE_IPV6:
|
---|
[73097] | 3799 | if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_UOFFSETOF(RTNETIPV6, ip6_dst), sizeof(Addr.IPv6), &Addr)))
|
---|
[11069] | 3800 | {
|
---|
| 3801 | Log(("intnetshareduni: failed to read ip6_dst! cbTotal=%#x\n", pSG->cbTotal));
|
---|
[28623] | 3802 | return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
|
---|
[11069] | 3803 | }
|
---|
[11055] | 3804 | enmAddrType = kIntNetAddrType_IPv6;
|
---|
| 3805 | cbAddr = sizeof(Addr.IPv6);
|
---|
| 3806 | break;
|
---|
| 3807 | #if 0 /** @todo IntNet: implement IPX for wireless MAC sharing? */
|
---|
| 3808 | case RTNET_ETHERTYPE_IPX_1:
|
---|
| 3809 | case RTNET_ETHERTYPE_IPX_2:
|
---|
| 3810 | case RTNET_ETHERTYPE_IPX_3:
|
---|
[11069] | 3811 | if (RT_UNLIKELY(!intnetR0SgReadPart(pSG, sizeof(RTNETETHERHDR) + RT_OFFSETOF(RTNETIPX, ipx_dstnet), sizeof(Addr.IPX), &Addr)))
|
---|
| 3812 | {
|
---|
| 3813 | Log(("intnetshareduni: failed to read ipx_dstnet! cbTotal=%#x\n", pSG->cbTotal));
|
---|
[28623] | 3814 | return intnetR0NetworkSwitchTrunk(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
|
---|
[11069] | 3815 | }
|
---|
[11055] | 3816 | enmAddrType = kIntNetAddrType_IPX;
|
---|
| 3817 | cbAddr = sizeof(Addr.IPX);
|
---|
| 3818 | break;
|
---|
| 3819 | #endif
|
---|
| 3820 |
|
---|
| 3821 | /*
|
---|
[28025] | 3822 | * Treat ARP as broadcast (it shouldn't end up here normally,
|
---|
[11055] | 3823 | * so it goes last in the switch).
|
---|
| 3824 | */
|
---|
| 3825 | case RTNET_ETHERTYPE_ARP:
|
---|
[11069] | 3826 | Log6(("intnetshareduni: ARP\n"));
|
---|
[11073] | 3827 | /** @todo revisit this broadcasting of unicast ARP frames! */
|
---|
[29160] | 3828 | return intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, INTNETTRUNKDIR_WIRE, NULL, pSG, pEthHdr, pDstTab);
|
---|
[11055] | 3829 |
|
---|
| 3830 | /*
|
---|
[28623] | 3831 | * Unknown packets are sent to the trunk and any promiscuous interfaces.
|
---|
[11055] | 3832 | */
|
---|
| 3833 | default:
|
---|
| 3834 | {
|
---|
[11069] | 3835 | Log6(("intnetshareduni: unknown ethertype=%#x\n", RT_BE2H_U16(pEthHdr->EtherType)));
|
---|
[28623] | 3836 | return intnetR0NetworkSwitchTrunkAndPromisc(pNetwork, INTNETTRUNKDIR_WIRE, pDstTab);
|
---|
[11055] | 3837 | }
|
---|
| 3838 | }
|
---|
| 3839 |
|
---|
| 3840 | /*
|
---|
[28623] | 3841 | * Do level-3 switching.
|
---|
[11055] | 3842 | */
|
---|
[28623] | 3843 | INTNETSWDECISION enmSwDecision = intnetR0NetworkSwitchLevel3(pNetwork, &pEthHdr->DstMac,
|
---|
| 3844 | enmAddrType, &Addr, cbAddr,
|
---|
| 3845 | INTNETTRUNKDIR_WIRE, pDstTab);
|
---|
[11055] | 3846 |
|
---|
[11074] | 3847 | #ifdef INTNET_WITH_DHCP_SNOOPING
|
---|
[11055] | 3848 | /*
|
---|
[28025] | 3849 | * Perform DHCP snooping. GSO is not applicable to DHCP traffic
|
---|
[11055] | 3850 | */
|
---|
| 3851 | if ( enmAddrType == kIntNetAddrType_IPv4
|
---|
[28025] | 3852 | && pSG->cbTotal >= sizeof(RTNETETHERHDR) + RTNETIPV4_MIN_LEN + RTNETUDP_MIN_LEN + RTNETBOOTP_DHCP_MIN_LEN
|
---|
| 3853 | && pSG->GsoCtx.u8Type == PDMNETWORKGSOTYPE_INVALID)
|
---|
[11055] | 3854 | intnetR0TrunkIfSnoopAddr(pNetwork, pSG, RT_BE2H_U16(pEthHdr->EtherType));
|
---|
[11074] | 3855 | #endif /* INTNET_WITH_DHCP_SNOOPING */
|
---|
[11055] | 3856 |
|
---|
[28623] | 3857 | return enmSwDecision;
|
---|
[11055] | 3858 | }
|
---|
| 3859 |
|
---|
| 3860 |
|
---|
| 3861 | /**
|
---|
[28623] | 3862 | * Release all the interfaces in the destination table when we realize that
|
---|
| 3863 | * we're in a context where we cannot get the job done.
|
---|
[10733] | 3864 | *
|
---|
[28623] | 3865 | * @param pNetwork The network.
|
---|
| 3866 | * @param pDstTab The destination table.
|
---|
| 3867 | */
|
---|
| 3868 | static void intnetR0NetworkReleaseDstTab(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab)
|
---|
| 3869 | {
|
---|
| 3870 | /* The trunk interface. */
|
---|
| 3871 | if (pDstTab->fTrunkDst)
|
---|
| 3872 | {
|
---|
| 3873 | PINTNETTRUNKIF pTrunk = pDstTab->pTrunk;
|
---|
[52134] | 3874 | if (pTrunk)
|
---|
| 3875 | intnetR0BusyDec(pNetwork, &pTrunk->cBusy);
|
---|
[28623] | 3876 | pDstTab->pTrunk = NULL;
|
---|
| 3877 | pDstTab->fTrunkDst = 0;
|
---|
| 3878 | }
|
---|
| 3879 |
|
---|
| 3880 | /* Regular interfaces. */
|
---|
| 3881 | uint32_t iIf = pDstTab->cIfs;
|
---|
| 3882 | while (iIf-- > 0)
|
---|
| 3883 | {
|
---|
| 3884 | PINTNETIF pIf = pDstTab->aIfs[iIf].pIf;
|
---|
| 3885 | intnetR0BusyDecIf(pIf);
|
---|
| 3886 | pDstTab->aIfs[iIf].pIf = NULL;
|
---|
| 3887 | }
|
---|
| 3888 | pDstTab->cIfs = 0;
|
---|
| 3889 | }
|
---|
| 3890 |
|
---|
| 3891 |
|
---|
| 3892 | /**
|
---|
| 3893 | * Deliver the frame to the interfaces specified in the destination table.
|
---|
[10733] | 3894 | *
|
---|
[28623] | 3895 | * @param pNetwork The network.
|
---|
| 3896 | * @param pDstTab The destination table.
|
---|
| 3897 | * @param pSG The frame to send.
|
---|
[33540] | 3898 | * @param pIfSender The sender interface. NULL if it originated via
|
---|
[28623] | 3899 | * the trunk.
|
---|
[10733] | 3900 | */
|
---|
[28623] | 3901 | static void intnetR0NetworkDeliver(PINTNETNETWORK pNetwork, PINTNETDSTTAB pDstTab, PINTNETSG pSG, PINTNETIF pIfSender)
|
---|
[10733] | 3902 | {
|
---|
| 3903 | /*
|
---|
[30004] | 3904 | * Do the interfaces first before sending it to the wire and risk having to
|
---|
| 3905 | * modify it.
|
---|
| 3906 | */
|
---|
| 3907 | uint32_t iIf = pDstTab->cIfs;
|
---|
| 3908 | while (iIf-- > 0)
|
---|
| 3909 | {
|
---|
| 3910 | PINTNETIF pIf = pDstTab->aIfs[iIf].pIf;
|
---|
| 3911 | intnetR0IfSend(pIf, pIfSender, pSG,
|
---|
| 3912 | pDstTab->aIfs[iIf].fReplaceDstMac ? &pIf->MacAddr: NULL);
|
---|
| 3913 | intnetR0BusyDecIf(pIf);
|
---|
| 3914 | pDstTab->aIfs[iIf].pIf = NULL;
|
---|
| 3915 | }
|
---|
| 3916 | pDstTab->cIfs = 0;
|
---|
| 3917 |
|
---|
| 3918 | /*
|
---|
| 3919 | * Send to the trunk.
|
---|
[28623] | 3920 | *
|
---|
| 3921 | * Note! The switching functions will include the trunk even when the frame
|
---|
| 3922 | * source is the trunk. This is because we need it to figure out
|
---|
| 3923 | * whether the other half of the trunk should see the frame or not
|
---|
| 3924 | * and let the caller know.
|
---|
| 3925 | *
|
---|
| 3926 | * So, we'll ignore trunk sends here if the frame origin is
|
---|
| 3927 | * INTNETTRUNKSWPORT::pfnRecv.
|
---|
[10733] | 3928 | */
|
---|
[28623] | 3929 | if (pDstTab->fTrunkDst)
|
---|
[10733] | 3930 | {
|
---|
[28623] | 3931 | PINTNETTRUNKIF pTrunk = pDstTab->pTrunk;
|
---|
[52134] | 3932 | if (pTrunk)
|
---|
| 3933 | {
|
---|
| 3934 | if (pIfSender)
|
---|
| 3935 | intnetR0TrunkIfSend(pTrunk, pNetwork, pIfSender, pDstTab->fTrunkDst, pSG);
|
---|
| 3936 | intnetR0BusyDec(pNetwork, &pTrunk->cBusy);
|
---|
| 3937 | }
|
---|
[28623] | 3938 | pDstTab->pTrunk = NULL;
|
---|
| 3939 | pDstTab->fTrunkDst = 0;
|
---|
[10733] | 3940 | }
|
---|
| 3941 | }
|
---|
| 3942 |
|
---|
| 3943 |
|
---|
| 3944 | /**
|
---|
[1] | 3945 | * Sends a frame.
|
---|
| 3946 | *
|
---|
| 3947 | * This function will distribute the frame to the interfaces it is addressed to.
|
---|
| 3948 | * It will also update the MAC address of the sender.
|
---|
| 3949 | *
|
---|
| 3950 | * The caller must own the network mutex.
|
---|
| 3951 | *
|
---|
[28623] | 3952 | * @returns The switching decision.
|
---|
[10733] | 3953 | * @param pNetwork The network the frame is being sent to.
|
---|
| 3954 | * @param pIfSender The interface sending the frame. This is NULL if it's the trunk.
|
---|
| 3955 | * @param fSrc The source flags. This 0 if it's not from the trunk.
|
---|
| 3956 | * @param pSG Pointer to the gather list.
|
---|
[28623] | 3957 | * @param pDstTab The destination table to use.
|
---|
[1] | 3958 | */
|
---|
[28623] | 3959 | static INTNETSWDECISION intnetR0NetworkSend(PINTNETNETWORK pNetwork, PINTNETIF pIfSender, uint32_t fSrc,
|
---|
| 3960 | PINTNETSG pSG, PINTNETDSTTAB pDstTab)
|
---|
[1] | 3961 | {
|
---|
| 3962 | /*
|
---|
| 3963 | * Assert reality.
|
---|
| 3964 | */
|
---|
[10733] | 3965 | AssertPtr(pNetwork);
|
---|
| 3966 | AssertPtrNull(pIfSender);
|
---|
| 3967 | Assert(pIfSender ? fSrc == 0 : fSrc != 0);
|
---|
[10739] | 3968 | Assert(!pIfSender || pNetwork == pIfSender->pNetwork);
|
---|
[10733] | 3969 | AssertPtr(pSG);
|
---|
| 3970 | Assert(pSG->cSegsUsed >= 1);
|
---|
| 3971 | Assert(pSG->cSegsUsed <= pSG->cSegsAlloc);
|
---|
[10961] | 3972 | if (pSG->cbTotal < sizeof(RTNETETHERHDR))
|
---|
[28623] | 3973 | return INTNETSWDECISION_INVALID;
|
---|
[1] | 3974 |
|
---|
| 3975 | /*
|
---|
[10733] | 3976 | * Get the ethernet header (might theoretically involve multiple segments).
|
---|
| 3977 | */
|
---|
[10961] | 3978 | RTNETETHERHDR EthHdr;
|
---|
[11124] | 3979 | if (pSG->aSegs[0].cb >= sizeof(EthHdr))
|
---|
[10961] | 3980 | EthHdr = *(PCRTNETETHERHDR)pSG->aSegs[0].pv;
|
---|
[11124] | 3981 | else if (!intnetR0SgReadPart(pSG, 0, sizeof(EthHdr), &EthHdr))
|
---|
[28623] | 3982 | return INTNETSWDECISION_INVALID;
|
---|
[10978] | 3983 | if ( (EthHdr.DstMac.au8[0] == 0x08 && EthHdr.DstMac.au8[1] == 0x00 && EthHdr.DstMac.au8[2] == 0x27)
|
---|
| 3984 | || (EthHdr.SrcMac.au8[0] == 0x08 && EthHdr.SrcMac.au8[1] == 0x00 && EthHdr.SrcMac.au8[2] == 0x27)
|
---|
| 3985 | || (EthHdr.DstMac.au8[0] == 0x00 && EthHdr.DstMac.au8[1] == 0x16 && EthHdr.DstMac.au8[2] == 0xcb)
|
---|
| 3986 | || (EthHdr.SrcMac.au8[0] == 0x00 && EthHdr.SrcMac.au8[1] == 0x16 && EthHdr.SrcMac.au8[2] == 0xcb)
|
---|
| 3987 | || EthHdr.DstMac.au8[0] == 0xff
|
---|
| 3988 | || EthHdr.SrcMac.au8[0] == 0xff)
|
---|
[10763] | 3989 | Log2(("D=%.6Rhxs S=%.6Rhxs T=%04x f=%x z=%x\n",
|
---|
[10978] | 3990 | &EthHdr.DstMac, &EthHdr.SrcMac, RT_BE2H_U16(EthHdr.EtherType), fSrc, pSG->cbTotal));
|
---|
[10733] | 3991 |
|
---|
| 3992 | /*
|
---|
[28623] | 3993 | * Learn the MAC address of the sender. No re-learning as the interface
|
---|
| 3994 | * user will normally tell us the right MAC address.
|
---|
[29635] | 3995 | *
|
---|
| 3996 | * Note! We don't notify the trunk about these mainly because of the
|
---|
| 3997 | * problematic contexts we might be called in.
|
---|
[1] | 3998 | */
|
---|
[28623] | 3999 | if (RT_UNLIKELY( pIfSender
|
---|
| 4000 | && !pIfSender->fMacSet
|
---|
| 4001 | && memcmp(&EthHdr.SrcMac, &pIfSender->MacAddr, sizeof(pIfSender->MacAddr))
|
---|
| 4002 | && !intnetR0IsMacAddrMulticast(&EthHdr.SrcMac)
|
---|
| 4003 | ))
|
---|
[1] | 4004 | {
|
---|
[28623] | 4005 | Log2(("IF MAC: %.6Rhxs -> %.6Rhxs\n", &pIfSender->MacAddr, &EthHdr.SrcMac));
|
---|
[40806] | 4006 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 4007 |
|
---|
| 4008 | PINTNETMACTABENTRY pIfEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIfSender);
|
---|
| 4009 | if (pIfEntry)
|
---|
| 4010 | pIfEntry->MacAddr = EthHdr.SrcMac;
|
---|
| 4011 | pIfSender->MacAddr = EthHdr.SrcMac;
|
---|
| 4012 |
|
---|
[52618] | 4013 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[1] | 4014 | }
|
---|
| 4015 |
|
---|
[10733] | 4016 | /*
|
---|
[28623] | 4017 | * Deal with MAC address sharing as that may required editing of the
|
---|
| 4018 | * packets before we dispatch them anywhere.
|
---|
[10733] | 4019 | */
|
---|
[28623] | 4020 | INTNETSWDECISION enmSwDecision;
|
---|
| 4021 | if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
| 4022 | {
|
---|
| 4023 | if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac))
|
---|
| 4024 | enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
|
---|
| 4025 | else if (fSrc & INTNETTRUNKDIR_WIRE)
|
---|
[45716] | 4026 | {
|
---|
[52518] | 4027 | if (intnetR0NetworkSharedMacDetectAndFixBroadcast(pNetwork, pSG, &EthHdr))
|
---|
[45716] | 4028 | enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchBroadcast(pNetwork, fSrc, pIfSender, pSG, &EthHdr, pDstTab);
|
---|
| 4029 | else
|
---|
| 4030 | enmSwDecision = intnetR0NetworkSharedMacFixAndSwitchUnicast(pNetwork, pSG, &EthHdr, pDstTab);
|
---|
| 4031 | }
|
---|
[28623] | 4032 | else
|
---|
| 4033 | enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
|
---|
| 4034 | }
|
---|
| 4035 | else if (intnetR0IsMacAddrMulticast(&EthHdr.DstMac))
|
---|
| 4036 | enmSwDecision = intnetR0NetworkSwitchBroadcast(pNetwork, fSrc, pIfSender, pDstTab);
|
---|
[1] | 4037 | else
|
---|
[28623] | 4038 | enmSwDecision = intnetR0NetworkSwitchUnicast(pNetwork, fSrc, pIfSender, &EthHdr.DstMac, pDstTab);
|
---|
| 4039 |
|
---|
| 4040 | /*
|
---|
| 4041 | * Deliver to the destinations if we can.
|
---|
| 4042 | */
|
---|
| 4043 | if (enmSwDecision != INTNETSWDECISION_BAD_CONTEXT)
|
---|
| 4044 | {
|
---|
[28699] | 4045 | if (intnetR0NetworkIsContextOk(pNetwork, pIfSender, pDstTab))
|
---|
[28623] | 4046 | intnetR0NetworkDeliver(pNetwork, pDstTab, pSG, pIfSender);
|
---|
| 4047 | else
|
---|
| 4048 | {
|
---|
| 4049 | intnetR0NetworkReleaseDstTab(pNetwork, pDstTab);
|
---|
| 4050 | enmSwDecision = INTNETSWDECISION_BAD_CONTEXT;
|
---|
| 4051 | }
|
---|
| 4052 | }
|
---|
| 4053 |
|
---|
| 4054 | return enmSwDecision;
|
---|
[1] | 4055 | }
|
---|
| 4056 |
|
---|
| 4057 |
|
---|
| 4058 | /**
|
---|
| 4059 | * Sends one or more frames.
|
---|
| 4060 | *
|
---|
[28623] | 4061 | * The function will first the frame which is passed as the optional arguments
|
---|
| 4062 | * pvFrame and cbFrame. These are optional since it also possible to chain
|
---|
| 4063 | * together one or more frames in the send buffer which the function will
|
---|
| 4064 | * process after considering it's arguments.
|
---|
[1] | 4065 | *
|
---|
[28623] | 4066 | * The caller is responsible for making sure that there are no concurrent calls
|
---|
| 4067 | * to this method (with the same handle).
|
---|
| 4068 | *
|
---|
[1] | 4069 | * @returns VBox status code.
|
---|
| 4070 | * @param hIf The interface handle.
|
---|
[10806] | 4071 | * @param pSession The caller's session.
|
---|
[1] | 4072 | */
|
---|
[28706] | 4073 | INTNETR0DECL(int) IntNetR0IfSend(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession)
|
---|
[1] | 4074 | {
|
---|
[28706] | 4075 | Log5(("IntNetR0IfSend: hIf=%RX32\n", hIf));
|
---|
[1] | 4076 |
|
---|
| 4077 | /*
|
---|
[10733] | 4078 | * Validate input and translate the handle.
|
---|
[1] | 4079 | */
|
---|
[28706] | 4080 | PINTNET pIntNet = g_pIntNet;
|
---|
| 4081 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
| 4082 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4083 |
|
---|
[10819] | 4084 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
| 4085 | if (!pIf)
|
---|
| 4086 | return VERR_INVALID_HANDLE;
|
---|
[30587] | 4087 | STAM_REL_PROFILE_START(&pIf->pIntBuf->StatSend1, a);
|
---|
[1] | 4088 |
|
---|
[10733] | 4089 | /*
|
---|
[28623] | 4090 | * Make sure we've got a network.
|
---|
[10733] | 4091 | */
|
---|
[28623] | 4092 | int rc = VINF_SUCCESS;
|
---|
| 4093 | intnetR0BusyIncIf(pIf);
|
---|
[10733] | 4094 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
[28623] | 4095 | if (RT_LIKELY(pNetwork))
|
---|
[10819] | 4096 | {
|
---|
[28623] | 4097 | /*
|
---|
| 4098 | * Grab the destination table.
|
---|
| 4099 | */
|
---|
[30111] | 4100 | PINTNETDSTTAB pDstTab = ASMAtomicXchgPtrT(&pIf->pDstTab, NULL, PINTNETDSTTAB);
|
---|
[28623] | 4101 | if (RT_LIKELY(pDstTab))
|
---|
[10733] | 4102 | {
|
---|
[28623] | 4103 | /*
|
---|
| 4104 | * Process the send buffer.
|
---|
| 4105 | */
|
---|
| 4106 | INTNETSWDECISION enmSwDecision = INTNETSWDECISION_BROADCAST;
|
---|
[104159] | 4107 |
|
---|
| 4108 | /** @todo this will have to be changed if we're going to use async sending
|
---|
| 4109 | * with buffer sharing for some OS or service. Darwin copies everything so
|
---|
| 4110 | * I won't bother allocating and managing SGs right now. Sorry. */
|
---|
| 4111 | union
|
---|
| 4112 | {
|
---|
| 4113 | uint8_t abBuf[sizeof(INTNETSG) + sizeof(INTNETSEG)];
|
---|
| 4114 | INTNETSG SG;
|
---|
| 4115 | } u;
|
---|
| 4116 |
|
---|
[28623] | 4117 | PINTNETHDR pHdr;
|
---|
[28714] | 4118 | while ((pHdr = IntNetRingGetNextFrameToRead(&pIf->pIntBuf->Send)) != NULL)
|
---|
[28623] | 4119 | {
|
---|
[46904] | 4120 | uint8_t const u8Type = pHdr->u8Type;
|
---|
| 4121 | if (u8Type == INTNETHDR_TYPE_FRAME)
|
---|
[28623] | 4122 | {
|
---|
| 4123 | /* Send regular frame. */
|
---|
[28714] | 4124 | void *pvCurFrame = IntNetHdrGetFramePtr(pHdr, pIf->pIntBuf);
|
---|
[104159] | 4125 | IntNetSgInitTemp(&u.SG, pvCurFrame, pHdr->cbFrame);
|
---|
[28623] | 4126 | if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
[104159] | 4127 | intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, pHdr->cbFrame, false /*fGso*/, (uint16_t *)&u.SG.fFlags);
|
---|
| 4128 | enmSwDecision = intnetR0NetworkSend(pNetwork, pIf, 0 /*fSrc*/, &u.SG, pDstTab);
|
---|
[28623] | 4129 | }
|
---|
[46904] | 4130 | else if (u8Type == INTNETHDR_TYPE_GSO)
|
---|
[28623] | 4131 | {
|
---|
| 4132 | /* Send GSO frame if sane. */
|
---|
[28714] | 4133 | PPDMNETWORKGSO pGso = IntNetHdrGetGsoContext(pHdr, pIf->pIntBuf);
|
---|
[28623] | 4134 | uint32_t cbFrame = pHdr->cbFrame - sizeof(*pGso);
|
---|
| 4135 | if (RT_LIKELY(PDMNetGsoIsValid(pGso, pHdr->cbFrame, cbFrame)))
|
---|
| 4136 | {
|
---|
| 4137 | void *pvCurFrame = pGso + 1;
|
---|
[104159] | 4138 | IntNetSgInitTempGso(&u.SG, pvCurFrame, cbFrame, pGso);
|
---|
[28623] | 4139 | if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
[104159] | 4140 | intnetR0IfSnoopAddr(pIf, (uint8_t *)pvCurFrame, cbFrame, true /*fGso*/, (uint16_t *)&u.SG.fFlags);
|
---|
| 4141 | enmSwDecision = intnetR0NetworkSend(pNetwork, pIf, 0 /*fSrc*/, &u.SG, pDstTab);
|
---|
[28623] | 4142 | }
|
---|
| 4143 | else
|
---|
| 4144 | {
|
---|
| 4145 | STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
|
---|
| 4146 | enmSwDecision = INTNETSWDECISION_DROP;
|
---|
| 4147 | }
|
---|
| 4148 | }
|
---|
| 4149 | /* Unless it's a padding frame, we're getting babble from the producer. */
|
---|
| 4150 | else
|
---|
| 4151 | {
|
---|
[46904] | 4152 | if (u8Type != INTNETHDR_TYPE_PADDING)
|
---|
[28623] | 4153 | STAM_REL_COUNTER_INC(&pIf->pIntBuf->cStatBadFrames); /* ignore */
|
---|
| 4154 | enmSwDecision = INTNETSWDECISION_DROP;
|
---|
| 4155 | }
|
---|
| 4156 | if (enmSwDecision == INTNETSWDECISION_BAD_CONTEXT)
|
---|
| 4157 | {
|
---|
| 4158 | rc = VERR_TRY_AGAIN;
|
---|
| 4159 | break;
|
---|
| 4160 | }
|
---|
[10733] | 4161 |
|
---|
[28623] | 4162 | /* Skip to the next frame. */
|
---|
[28714] | 4163 | IntNetRingSkipFrame(&pIf->pIntBuf->Send);
|
---|
[28623] | 4164 | }
|
---|
[10733] | 4165 |
|
---|
[28623] | 4166 | /*
|
---|
| 4167 | * Put back the destination table.
|
---|
| 4168 | */
|
---|
| 4169 | Assert(!pIf->pDstTab);
|
---|
[30111] | 4170 | ASMAtomicWritePtr(&pIf->pDstTab, pDstTab);
|
---|
[28025] | 4171 | }
|
---|
[28623] | 4172 | else
|
---|
| 4173 | rc = VERR_INTERNAL_ERROR_4;
|
---|
[1] | 4174 | }
|
---|
[28623] | 4175 | else
|
---|
| 4176 | rc = VERR_INTERNAL_ERROR_3;
|
---|
[1] | 4177 |
|
---|
[10733] | 4178 | /*
|
---|
[28623] | 4179 | * Release the interface.
|
---|
[10733] | 4180 | */
|
---|
[28623] | 4181 | intnetR0BusyDecIf(pIf);
|
---|
[30587] | 4182 | STAM_REL_PROFILE_STOP(&pIf->pIntBuf->StatSend1, a);
|
---|
[10819] | 4183 | intnetR0IfRelease(pIf, pSession);
|
---|
[10733] | 4184 | return rc;
|
---|
[1] | 4185 | }
|
---|
| 4186 |
|
---|
| 4187 |
|
---|
| 4188 | /**
|
---|
[28706] | 4189 | * VMMR0 request wrapper for IntNetR0IfSend.
|
---|
[5283] | 4190 | *
|
---|
[28706] | 4191 | * @returns see IntNetR0IfSend.
|
---|
[10806] | 4192 | * @param pSession The caller's session.
|
---|
[5283] | 4193 | * @param pReq The request packet.
|
---|
| 4194 | */
|
---|
[28706] | 4195 | INTNETR0DECL(int) IntNetR0IfSendReq(PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq)
|
---|
[5283] | 4196 | {
|
---|
| 4197 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4198 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4199 | return IntNetR0IfSend(pReq->hIf, pSession);
|
---|
[5283] | 4200 | }
|
---|
| 4201 |
|
---|
| 4202 |
|
---|
| 4203 | /**
|
---|
[1] | 4204 | * Maps the default buffer into ring 3.
|
---|
| 4205 | *
|
---|
| 4206 | * @returns VBox status code.
|
---|
[10806] | 4207 | * @param hIf The interface handle.
|
---|
| 4208 | * @param pSession The caller's session.
|
---|
[28711] | 4209 | * @param ppRing3Buf Where to store the address of the ring-3 mapping
|
---|
| 4210 | * (optional).
|
---|
| 4211 | * @param ppRing0Buf Where to store the address of the ring-0 mapping
|
---|
| 4212 | * (optional).
|
---|
[1] | 4213 | */
|
---|
[28711] | 4214 | INTNETR0DECL(int) IntNetR0IfGetBufferPtrs(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession,
|
---|
| 4215 | R3PTRTYPE(PINTNETBUF) *ppRing3Buf, R0PTRTYPE(PINTNETBUF) *ppRing0Buf)
|
---|
[1] | 4216 | {
|
---|
[28711] | 4217 | LogFlow(("IntNetR0IfGetBufferPtrs: hIf=%RX32 ppRing3Buf=%p ppRing0Buf=%p\n", hIf, ppRing3Buf, ppRing0Buf));
|
---|
[1] | 4218 |
|
---|
| 4219 | /*
|
---|
| 4220 | * Validate input.
|
---|
| 4221 | */
|
---|
[28706] | 4222 | PINTNET pIntNet = g_pIntNet;
|
---|
| 4223 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
| 4224 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4225 |
|
---|
[28711] | 4226 | AssertPtrNullReturn(ppRing3Buf, VERR_INVALID_PARAMETER);
|
---|
| 4227 | AssertPtrNullReturn(ppRing0Buf, VERR_INVALID_PARAMETER);
|
---|
| 4228 | if (ppRing3Buf)
|
---|
| 4229 | *ppRing3Buf = 0;
|
---|
| 4230 | if (ppRing0Buf)
|
---|
| 4231 | *ppRing0Buf = 0;
|
---|
| 4232 |
|
---|
[10819] | 4233 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
[1] | 4234 | if (!pIf)
|
---|
| 4235 | return VERR_INVALID_HANDLE;
|
---|
| 4236 |
|
---|
| 4237 | /*
|
---|
| 4238 | * ASSUMES that only the process that created an interface can use it.
|
---|
| 4239 | * ASSUMES that we created the ring-3 mapping when selecting or
|
---|
| 4240 | * allocating the buffer.
|
---|
| 4241 | */
|
---|
[28623] | 4242 | int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
[10819] | 4243 | if (RT_SUCCESS(rc))
|
---|
| 4244 | {
|
---|
[28711] | 4245 | if (ppRing3Buf)
|
---|
| 4246 | *ppRing3Buf = pIf->pIntBufR3;
|
---|
| 4247 | if (ppRing0Buf)
|
---|
| 4248 | *ppRing0Buf = (R0PTRTYPE(PINTNETBUF))pIf->pIntBuf; /* tstIntNetR0 mess */
|
---|
[28623] | 4249 |
|
---|
| 4250 | rc = RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
[10819] | 4251 | }
|
---|
[1] | 4252 |
|
---|
[10819] | 4253 | intnetR0IfRelease(pIf, pSession);
|
---|
[28711] | 4254 | LogFlow(("IntNetR0IfGetBufferPtrs: returns %Rrc *ppRing3Buf=%p *ppRing0Buf=%p\n",
|
---|
[43976] | 4255 | rc, ppRing3Buf ? *ppRing3Buf : NIL_RTR3PTR, ppRing0Buf ? *ppRing0Buf : NIL_RTR0PTR));
|
---|
[1] | 4256 | return rc;
|
---|
| 4257 | }
|
---|
| 4258 |
|
---|
| 4259 |
|
---|
| 4260 | /**
|
---|
[28711] | 4261 | * VMMR0 request wrapper for IntNetR0IfGetBufferPtrs.
|
---|
[5283] | 4262 | *
|
---|
[28706] | 4263 | * @returns see IntNetR0IfGetRing3Buffer.
|
---|
[10806] | 4264 | * @param pSession The caller's session.
|
---|
[5283] | 4265 | * @param pReq The request packet.
|
---|
| 4266 | */
|
---|
[28711] | 4267 | INTNETR0DECL(int) IntNetR0IfGetBufferPtrsReq(PSUPDRVSESSION pSession, PINTNETIFGETBUFFERPTRSREQ pReq)
|
---|
[5283] | 4268 | {
|
---|
| 4269 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4270 | return VERR_INVALID_PARAMETER;
|
---|
[28711] | 4271 | return IntNetR0IfGetBufferPtrs(pReq->hIf, pSession, &pReq->pRing3Buf, &pReq->pRing0Buf);
|
---|
[5283] | 4272 | }
|
---|
| 4273 |
|
---|
| 4274 |
|
---|
[1] | 4275 | #if 0
|
---|
| 4276 | /**
|
---|
| 4277 | * Gets the physical addresses of the default interface buffer.
|
---|
| 4278 | *
|
---|
| 4279 | * @returns VBox status code.
|
---|
| 4280 | * @param hIF The interface handle.
|
---|
| 4281 | * @param paPages Where to store the addresses. (The reserved fields will be set to zero.)
|
---|
| 4282 | * @param cPages
|
---|
| 4283 | */
|
---|
[28706] | 4284 | INTNETR0DECL(int) IntNetR0IfGetPhysBuffer(INTNETIFHANDLE hIf, PSUPPAGE paPages, unsigned cPages)
|
---|
[1] | 4285 | {
|
---|
| 4286 | /*
|
---|
| 4287 | * Validate input.
|
---|
| 4288 | */
|
---|
[28706] | 4289 | PINTNET pIntNet = g_pIntNet;
|
---|
| 4290 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
| 4291 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4292 |
|
---|
[10819] | 4293 | AssertPtrReturn(paPages, VERR_INVALID_PARAMETER);
|
---|
| 4294 | AssertPtrReturn((uint8_t *)&paPages[cPages] - 1, VERR_INVALID_PARAMETER);
|
---|
| 4295 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
[1] | 4296 | if (!pIf)
|
---|
| 4297 | return VERR_INVALID_HANDLE;
|
---|
| 4298 |
|
---|
| 4299 | /*
|
---|
[10557] | 4300 | * Grab the lock and get the data.
|
---|
| 4301 | * ASSUMES that the handle isn't closed while we're here.
|
---|
[1] | 4302 | */
|
---|
| 4303 | int rc = RTSemFastMutexRequest(pIf->pNetwork->FastMutex);
|
---|
[10819] | 4304 | if (RT_SUCCESS(rc))
|
---|
| 4305 | {
|
---|
| 4306 | /** @todo make a SUPR0 api for obtaining the array. SUPR0/IPRT is keeping track of everything, there
|
---|
| 4307 | * is no need for any extra bookkeeping here.. */
|
---|
[1] | 4308 |
|
---|
[10819] | 4309 | rc = RTSemFastMutexRelease(pIf->pNetwork->FastMutex);
|
---|
| 4310 | }
|
---|
| 4311 | intnetR0IfRelease(pIf, pSession);
|
---|
[1] | 4312 | return VERR_NOT_IMPLEMENTED;
|
---|
| 4313 | }
|
---|
| 4314 | #endif
|
---|
| 4315 |
|
---|
| 4316 |
|
---|
| 4317 | /**
|
---|
| 4318 | * Sets the promiscuous mode property of an interface.
|
---|
| 4319 | *
|
---|
| 4320 | * @returns VBox status code.
|
---|
| 4321 | * @param hIf The interface handle.
|
---|
[10806] | 4322 | * @param pSession The caller's session.
|
---|
[1] | 4323 | * @param fPromiscuous Set if the interface should be in promiscuous mode, clear if not.
|
---|
| 4324 | */
|
---|
[28706] | 4325 | INTNETR0DECL(int) IntNetR0IfSetPromiscuousMode(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous)
|
---|
[1] | 4326 | {
|
---|
[28706] | 4327 | LogFlow(("IntNetR0IfSetPromiscuousMode: hIf=%RX32 fPromiscuous=%d\n", hIf, fPromiscuous));
|
---|
[1] | 4328 |
|
---|
| 4329 | /*
|
---|
[10557] | 4330 | * Validate & translate input.
|
---|
[1] | 4331 | */
|
---|
[28706] | 4332 | PINTNET pIntNet = g_pIntNet;
|
---|
| 4333 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
| 4334 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4335 |
|
---|
[10819] | 4336 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
[1] | 4337 | if (!pIf)
|
---|
| 4338 | {
|
---|
[28706] | 4339 | Log(("IntNetR0IfSetPromiscuousMode: returns VERR_INVALID_HANDLE\n"));
|
---|
[1] | 4340 | return VERR_INVALID_HANDLE;
|
---|
| 4341 | }
|
---|
[10557] | 4342 |
|
---|
| 4343 | /*
|
---|
[28623] | 4344 | * Get the network, take the address spinlock, and make the change.
|
---|
| 4345 | * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed.
|
---|
[10557] | 4346 | */
|
---|
[28623] | 4347 | int rc = VINF_SUCCESS;
|
---|
| 4348 | intnetR0BusyIncIf(pIf);
|
---|
[10711] | 4349 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
[10819] | 4350 | if (pNetwork)
|
---|
| 4351 | {
|
---|
[40806] | 4352 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 4353 |
|
---|
[36075] | 4354 | if (pIf->fPromiscuousReal != fPromiscuous)
|
---|
[10819] | 4355 | {
|
---|
[36075] | 4356 | const bool fPromiscuousEff = fPromiscuous
|
---|
| 4357 | && (pIf->fOpenFlags & INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW)
|
---|
| 4358 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS);
|
---|
[36089] | 4359 | Log(("IntNetR0IfSetPromiscuousMode: hIf=%RX32: Changed from %d -> %d (%d)\n",
|
---|
| 4360 | hIf, !fPromiscuous, !!fPromiscuous, fPromiscuousEff));
|
---|
[10557] | 4361 |
|
---|
[36075] | 4362 | pIf->fPromiscuousReal = fPromiscuous;
|
---|
| 4363 |
|
---|
[28623] | 4364 | PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
|
---|
| 4365 | if (RT_LIKELY(pEntry))
|
---|
[36075] | 4366 | {
|
---|
[36089] | 4367 | if (pEntry->fPromiscuousEff)
|
---|
| 4368 | {
|
---|
| 4369 | pNetwork->MacTab.cPromiscuousEntries--;
|
---|
| 4370 | if (!pEntry->fPromiscuousSeeTrunk)
|
---|
| 4371 | pNetwork->MacTab.cPromiscuousNoTrunkEntries--;
|
---|
| 4372 | Assert(pNetwork->MacTab.cPromiscuousEntries < pNetwork->MacTab.cEntries);
|
---|
| 4373 | Assert(pNetwork->MacTab.cPromiscuousNoTrunkEntries < pNetwork->MacTab.cEntries);
|
---|
| 4374 | }
|
---|
| 4375 |
|
---|
[36075] | 4376 | pEntry->fPromiscuousEff = fPromiscuousEff;
|
---|
| 4377 | pEntry->fPromiscuousSeeTrunk = fPromiscuousEff
|
---|
| 4378 | && (pIf->fOpenFlags & INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK);
|
---|
[36089] | 4379 |
|
---|
| 4380 | if (pEntry->fPromiscuousEff)
|
---|
| 4381 | {
|
---|
| 4382 | pNetwork->MacTab.cPromiscuousEntries++;
|
---|
| 4383 | if (!pEntry->fPromiscuousSeeTrunk)
|
---|
| 4384 | pNetwork->MacTab.cPromiscuousNoTrunkEntries++;
|
---|
| 4385 | }
|
---|
| 4386 | Assert(pNetwork->MacTab.cPromiscuousEntries <= pNetwork->MacTab.cEntries);
|
---|
| 4387 | Assert(pNetwork->MacTab.cPromiscuousNoTrunkEntries <= pNetwork->MacTab.cEntries);
|
---|
[36075] | 4388 | }
|
---|
[10819] | 4389 | }
|
---|
[28623] | 4390 |
|
---|
[52618] | 4391 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[1] | 4392 | }
|
---|
[10819] | 4393 | else
|
---|
| 4394 | rc = VERR_WRONG_ORDER;
|
---|
[10557] | 4395 |
|
---|
[28623] | 4396 | intnetR0BusyDecIf(pIf);
|
---|
[10819] | 4397 | intnetR0IfRelease(pIf, pSession);
|
---|
| 4398 | return rc;
|
---|
[1] | 4399 | }
|
---|
| 4400 |
|
---|
| 4401 |
|
---|
| 4402 | /**
|
---|
[28706] | 4403 | * VMMR0 request wrapper for IntNetR0IfSetPromiscuousMode.
|
---|
[5283] | 4404 | *
|
---|
[28706] | 4405 | * @returns see IntNetR0IfSetPromiscuousMode.
|
---|
[10806] | 4406 | * @param pSession The caller's session.
|
---|
[5283] | 4407 | * @param pReq The request packet.
|
---|
| 4408 | */
|
---|
[28706] | 4409 | INTNETR0DECL(int) IntNetR0IfSetPromiscuousModeReq(PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq)
|
---|
[5283] | 4410 | {
|
---|
| 4411 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4412 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4413 | return IntNetR0IfSetPromiscuousMode(pReq->hIf, pSession, pReq->fPromiscuous);
|
---|
[5283] | 4414 | }
|
---|
| 4415 |
|
---|
| 4416 |
|
---|
| 4417 | /**
|
---|
[10843] | 4418 | * Sets the MAC address of an interface.
|
---|
| 4419 | *
|
---|
| 4420 | * @returns VBox status code.
|
---|
| 4421 | * @param hIf The interface handle.
|
---|
| 4422 | * @param pSession The caller's session.
|
---|
| 4423 | * @param pMAC The new MAC address.
|
---|
| 4424 | */
|
---|
[28706] | 4425 | INTNETR0DECL(int) IntNetR0IfSetMacAddress(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac)
|
---|
[10843] | 4426 | {
|
---|
[28706] | 4427 | LogFlow(("IntNetR0IfSetMacAddress: hIf=%RX32 pMac=%p:{%.6Rhxs}\n", hIf, pMac, pMac));
|
---|
[10843] | 4428 |
|
---|
| 4429 | /*
|
---|
| 4430 | * Validate & translate input.
|
---|
| 4431 | */
|
---|
[28706] | 4432 | PINTNET pIntNet = g_pIntNet;
|
---|
[10843] | 4433 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
[28706] | 4434 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4435 |
|
---|
[10843] | 4436 | AssertPtrReturn(pMac, VERR_INVALID_PARAMETER);
|
---|
| 4437 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
| 4438 | if (!pIf)
|
---|
| 4439 | {
|
---|
[28706] | 4440 | Log(("IntNetR0IfSetMacAddress: returns VERR_INVALID_HANDLE\n"));
|
---|
[10843] | 4441 | return VERR_INVALID_HANDLE;
|
---|
| 4442 | }
|
---|
| 4443 |
|
---|
| 4444 | /*
|
---|
[28623] | 4445 | * Get the network, take the address spinlock, and make the change.
|
---|
| 4446 | * Paranoia^2: Mark ourselves busy to prevent anything from being destroyed.
|
---|
[10843] | 4447 | */
|
---|
[28623] | 4448 | int rc = VINF_SUCCESS;
|
---|
| 4449 | intnetR0BusyIncIf(pIf);
|
---|
[10843] | 4450 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
| 4451 | if (pNetwork)
|
---|
| 4452 | {
|
---|
[29635] | 4453 | PINTNETTRUNKIF pTrunk = NULL;
|
---|
| 4454 |
|
---|
[40806] | 4455 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 4456 |
|
---|
| 4457 | if (memcmp(&pIf->MacAddr, pMac, sizeof(pIf->MacAddr)))
|
---|
[10843] | 4458 | {
|
---|
[28706] | 4459 | Log(("IntNetR0IfSetMacAddress: hIf=%RX32: Changed from %.6Rhxs -> %.6Rhxs\n",
|
---|
[28623] | 4460 | hIf, &pIf->MacAddr, pMac));
|
---|
[10843] | 4461 |
|
---|
[29635] | 4462 | /* Update the two copies. */
|
---|
[28623] | 4463 | PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
|
---|
| 4464 | if (RT_LIKELY(pEntry))
|
---|
| 4465 | pEntry->MacAddr = *pMac;
|
---|
| 4466 | pIf->MacAddr = *pMac;
|
---|
| 4467 | pIf->fMacSet = true;
|
---|
[29635] | 4468 |
|
---|
| 4469 | /* Grab a busy reference to the trunk so we release the lock before notifying it. */
|
---|
| 4470 | pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 4471 | if (pTrunk)
|
---|
| 4472 | intnetR0BusyIncTrunk(pTrunk);
|
---|
[10843] | 4473 | }
|
---|
[28623] | 4474 |
|
---|
[52618] | 4475 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[29635] | 4476 |
|
---|
| 4477 | if (pTrunk)
|
---|
[29491] | 4478 | {
|
---|
| 4479 | Log(("IntNetR0IfSetMacAddress: pfnNotifyMacAddress hIf=%RX32\n", hIf));
|
---|
[29635] | 4480 | PINTNETTRUNKIFPORT pIfPort = pTrunk->pIfPort;
|
---|
| 4481 | if (pIfPort)
|
---|
[29662] | 4482 | pIfPort->pfnNotifyMacAddress(pIfPort, pIf->pvIfData, pMac);
|
---|
[29635] | 4483 | intnetR0BusyDecTrunk(pTrunk);
|
---|
[29491] | 4484 | }
|
---|
[10843] | 4485 | }
|
---|
| 4486 | else
|
---|
| 4487 | rc = VERR_WRONG_ORDER;
|
---|
| 4488 |
|
---|
[28623] | 4489 | intnetR0BusyDecIf(pIf);
|
---|
[10843] | 4490 | intnetR0IfRelease(pIf, pSession);
|
---|
| 4491 | return rc;
|
---|
| 4492 | }
|
---|
| 4493 |
|
---|
| 4494 |
|
---|
| 4495 | /**
|
---|
[28706] | 4496 | * VMMR0 request wrapper for IntNetR0IfSetMacAddress.
|
---|
[10843] | 4497 | *
|
---|
[28706] | 4498 | * @returns see IntNetR0IfSetMacAddress.
|
---|
[10843] | 4499 | * @param pSession The caller's session.
|
---|
| 4500 | * @param pReq The request packet.
|
---|
| 4501 | */
|
---|
[28706] | 4502 | INTNETR0DECL(int) IntNetR0IfSetMacAddressReq(PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq)
|
---|
[10843] | 4503 | {
|
---|
| 4504 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4505 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4506 | return IntNetR0IfSetMacAddress(pReq->hIf, pSession, &pReq->Mac);
|
---|
[10843] | 4507 | }
|
---|
| 4508 |
|
---|
| 4509 |
|
---|
| 4510 | /**
|
---|
[28623] | 4511 | * Worker for intnetR0IfSetActive and intnetR0IfDestruct.
|
---|
[10711] | 4512 | *
|
---|
| 4513 | * This function will update the active interface count on the network and
|
---|
[31323] | 4514 | * activate or deactivate the trunk connection if necessary.
|
---|
[10711] | 4515 | *
|
---|
[31323] | 4516 | * The call must own the giant lock (we cannot take it here).
|
---|
| 4517 | *
|
---|
[10711] | 4518 | * @returns VBox status code.
|
---|
| 4519 | * @param pNetwork The network.
|
---|
| 4520 | * @param fIf The interface.
|
---|
| 4521 | * @param fActive What to do.
|
---|
| 4522 | */
|
---|
| 4523 | static int intnetR0NetworkSetIfActive(PINTNETNETWORK pNetwork, PINTNETIF pIf, bool fActive)
|
---|
| 4524 | {
|
---|
[33540] | 4525 | /* quick sanity check */
|
---|
[10711] | 4526 | AssertPtr(pNetwork);
|
---|
| 4527 | AssertPtr(pIf);
|
---|
| 4528 |
|
---|
| 4529 | /*
|
---|
[28831] | 4530 | * The address spinlock of the network protects the variables, while the
|
---|
| 4531 | * big lock protects the calling of pfnSetState. Grab both lock at once
|
---|
[33540] | 4532 | * to save us the extra hassle.
|
---|
[10711] | 4533 | */
|
---|
[28831] | 4534 | PINTNETTRUNKIF pTrunk = NULL;
|
---|
[40806] | 4535 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 4536 |
|
---|
| 4537 | /*
|
---|
| 4538 | * Do the update.
|
---|
| 4539 | */
|
---|
| 4540 | if (pIf->fActive != fActive)
|
---|
[10711] | 4541 | {
|
---|
[28623] | 4542 | PINTNETMACTABENTRY pEntry = intnetR0NetworkFindMacAddrEntry(pNetwork, pIf); Assert(pEntry);
|
---|
| 4543 | if (RT_LIKELY(pEntry))
|
---|
[10711] | 4544 | {
|
---|
[28623] | 4545 | pEntry->fActive = fActive;
|
---|
| 4546 | pIf->fActive = fActive;
|
---|
[10711] | 4547 |
|
---|
[28623] | 4548 | if (fActive)
|
---|
[10711] | 4549 | {
|
---|
[28623] | 4550 | pNetwork->cActiveIFs++;
|
---|
[28831] | 4551 | if (pNetwork->cActiveIFs == 1)
|
---|
| 4552 | {
|
---|
| 4553 | pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 4554 | if (pTrunk)
|
---|
| 4555 | {
|
---|
[36075] | 4556 | pNetwork->MacTab.fHostActive = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED);
|
---|
| 4557 | pNetwork->MacTab.fWireActive = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED);
|
---|
[28831] | 4558 | }
|
---|
| 4559 | }
|
---|
[10711] | 4560 | }
|
---|
[28623] | 4561 | else
|
---|
| 4562 | {
|
---|
| 4563 | pNetwork->cActiveIFs--;
|
---|
[28831] | 4564 | if (pNetwork->cActiveIFs == 0)
|
---|
| 4565 | {
|
---|
| 4566 | pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 4567 | pNetwork->MacTab.fHostActive = false;
|
---|
| 4568 | pNetwork->MacTab.fWireActive = false;
|
---|
| 4569 | }
|
---|
[28623] | 4570 | }
|
---|
[10711] | 4571 | }
|
---|
| 4572 | }
|
---|
| 4573 |
|
---|
[52618] | 4574 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[10711] | 4575 |
|
---|
| 4576 | /*
|
---|
[28623] | 4577 | * Tell the trunk if necessary.
|
---|
[31323] | 4578 | * The wait for !busy is for the Solaris streams trunk driver (mostly).
|
---|
[10711] | 4579 | */
|
---|
[28831] | 4580 | if (pTrunk && pTrunk->pIfPort)
|
---|
[31001] | 4581 | {
|
---|
| 4582 | if (!fActive)
|
---|
| 4583 | intnetR0BusyWait(pNetwork, &pTrunk->cBusy);
|
---|
| 4584 |
|
---|
[28831] | 4585 | pTrunk->pIfPort->pfnSetState(pTrunk->pIfPort, fActive ? INTNETTRUNKIFSTATE_ACTIVE : INTNETTRUNKIFSTATE_INACTIVE);
|
---|
[31001] | 4586 | }
|
---|
[28623] | 4587 |
|
---|
| 4588 | return VINF_SUCCESS;
|
---|
[10711] | 4589 | }
|
---|
| 4590 |
|
---|
| 4591 |
|
---|
| 4592 | /**
|
---|
[10843] | 4593 | * Sets the active property of an interface.
|
---|
| 4594 | *
|
---|
| 4595 | * @returns VBox status code.
|
---|
| 4596 | * @param hIf The interface handle.
|
---|
| 4597 | * @param pSession The caller's session.
|
---|
| 4598 | * @param fActive The new state.
|
---|
| 4599 | */
|
---|
[28706] | 4600 | INTNETR0DECL(int) IntNetR0IfSetActive(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive)
|
---|
[10843] | 4601 | {
|
---|
[28706] | 4602 | LogFlow(("IntNetR0IfSetActive: hIf=%RX32 fActive=%RTbool\n", hIf, fActive));
|
---|
[10843] | 4603 |
|
---|
| 4604 | /*
|
---|
| 4605 | * Validate & translate input.
|
---|
| 4606 | */
|
---|
[28706] | 4607 | PINTNET pIntNet = g_pIntNet;
|
---|
[10843] | 4608 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
[28706] | 4609 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4610 |
|
---|
[10843] | 4611 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
| 4612 | if (!pIf)
|
---|
| 4613 | {
|
---|
[28706] | 4614 | Log(("IntNetR0IfSetActive: returns VERR_INVALID_HANDLE\n"));
|
---|
[10843] | 4615 | return VERR_INVALID_HANDLE;
|
---|
| 4616 | }
|
---|
| 4617 |
|
---|
| 4618 | /*
|
---|
[28623] | 4619 | * Hand it to the network since it might involve the trunk and things are
|
---|
| 4620 | * tricky there wrt to locking order.
|
---|
| 4621 | *
|
---|
[31323] | 4622 | * 1. We take the giant lock here. This makes sure nobody is re-enabling
|
---|
| 4623 | * the network while we're pausing it and vice versa. This also enables
|
---|
| 4624 | * us to wait for the network to become idle before telling the trunk.
|
---|
| 4625 | * (Important on Solaris.)
|
---|
| 4626 | *
|
---|
| 4627 | * 2. For paranoid reasons, we grab a busy reference to the calling
|
---|
| 4628 | * interface. This is totally unnecessary but should hurt (when done
|
---|
| 4629 | * after grabbing the giant lock).
|
---|
[10843] | 4630 | */
|
---|
[31323] | 4631 | int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
| 4632 | if (RT_SUCCESS(rc))
|
---|
| 4633 | {
|
---|
| 4634 | intnetR0BusyIncIf(pIf);
|
---|
[28623] | 4635 |
|
---|
[31323] | 4636 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
| 4637 | if (pNetwork)
|
---|
| 4638 | rc = intnetR0NetworkSetIfActive(pNetwork, pIf, fActive);
|
---|
| 4639 | else
|
---|
| 4640 | rc = VERR_WRONG_ORDER;
|
---|
[10843] | 4641 |
|
---|
[31323] | 4642 | intnetR0BusyDecIf(pIf);
|
---|
| 4643 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
| 4644 | }
|
---|
| 4645 |
|
---|
[10843] | 4646 | intnetR0IfRelease(pIf, pSession);
|
---|
[31323] | 4647 | LogFlow(("IntNetR0IfSetActive: returns %Rrc\n", rc));
|
---|
[10843] | 4648 | return rc;
|
---|
| 4649 | }
|
---|
| 4650 |
|
---|
| 4651 |
|
---|
| 4652 | /**
|
---|
[28706] | 4653 | * VMMR0 request wrapper for IntNetR0IfSetActive.
|
---|
[10843] | 4654 | *
|
---|
[28706] | 4655 | * @returns see IntNetR0IfSetActive.
|
---|
[10843] | 4656 | * @param pIntNet The internal networking instance.
|
---|
| 4657 | * @param pSession The caller's session.
|
---|
| 4658 | * @param pReq The request packet.
|
---|
| 4659 | */
|
---|
[28706] | 4660 | INTNETR0DECL(int) IntNetR0IfSetActiveReq(PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq)
|
---|
[10843] | 4661 | {
|
---|
| 4662 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4663 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4664 | return IntNetR0IfSetActive(pReq->hIf, pSession, pReq->fActive);
|
---|
[10843] | 4665 | }
|
---|
| 4666 |
|
---|
| 4667 |
|
---|
| 4668 | /**
|
---|
[1] | 4669 | * Wait for the interface to get signaled.
|
---|
| 4670 | * The interface will be signaled when is put into the receive buffer.
|
---|
| 4671 | *
|
---|
| 4672 | * @returns VBox status code.
|
---|
[10806] | 4673 | * @param hIf The interface handle.
|
---|
| 4674 | * @param pSession The caller's session.
|
---|
| 4675 | * @param cMillies Number of milliseconds to wait. RT_INDEFINITE_WAIT should be
|
---|
| 4676 | * used if indefinite wait is desired.
|
---|
[1] | 4677 | */
|
---|
[28706] | 4678 | INTNETR0DECL(int) IntNetR0IfWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies)
|
---|
[1] | 4679 | {
|
---|
[28706] | 4680 | Log4(("IntNetR0IfWait: hIf=%RX32 cMillies=%u\n", hIf, cMillies));
|
---|
[1] | 4681 |
|
---|
| 4682 | /*
|
---|
| 4683 | * Get and validate essential handles.
|
---|
| 4684 | */
|
---|
[28706] | 4685 | PINTNET pIntNet = g_pIntNet;
|
---|
[10819] | 4686 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
[28706] | 4687 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4688 |
|
---|
[10819] | 4689 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
[1] | 4690 | if (!pIf)
|
---|
| 4691 | {
|
---|
[28706] | 4692 | Log(("IntNetR0IfWait: returns VERR_INVALID_HANDLE\n"));
|
---|
[1] | 4693 | return VERR_INVALID_HANDLE;
|
---|
| 4694 | }
|
---|
[29669] | 4695 |
|
---|
[97338] | 4696 | #if defined(VBOX_WITH_INTNET_SERVICE_IN_R3) && defined(IN_RING3)
|
---|
| 4697 | AssertReleaseFailed(); /* Should never be called. */
|
---|
[97339] | 4698 | RT_NOREF(cMillies);
|
---|
[97338] | 4699 | return VERR_NOT_SUPPORTED;
|
---|
| 4700 | #else
|
---|
| 4701 | const RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
|
---|
[60525] | 4702 | const bool fNoMoreWaits = ASMAtomicUoReadBool(&pIf->fNoMoreWaits);
|
---|
| 4703 | RTNATIVETHREAD hDtorThrd;
|
---|
| 4704 | ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd);
|
---|
| 4705 | if (hDtorThrd != NIL_RTNATIVETHREAD)
|
---|
[1] | 4706 | {
|
---|
[60525] | 4707 | /* See IntNetR0IfAbortWait for an explanation of hDestructorThread. */
|
---|
[28706] | 4708 | Log(("IntNetR0IfWait: returns VERR_SEM_DESTROYED\n"));
|
---|
[1] | 4709 | return VERR_SEM_DESTROYED;
|
---|
| 4710 | }
|
---|
| 4711 |
|
---|
[60525] | 4712 | /* Check whether further waits have been barred by IntNetR0IfAbortWait. */
|
---|
| 4713 | int rc;
|
---|
| 4714 | if ( !fNoMoreWaits
|
---|
| 4715 | && hRecvEvent != NIL_RTSEMEVENT)
|
---|
| 4716 | {
|
---|
| 4717 | /*
|
---|
| 4718 | * It is tempting to check if there is data to be read here,
|
---|
| 4719 | * but the problem with such an approach is that it will cause
|
---|
| 4720 | * one unnecessary supervisor->user->supervisor trip. There is
|
---|
| 4721 | * already a slight risk for such, so no need to increase it.
|
---|
| 4722 | */
|
---|
[1] | 4723 |
|
---|
[60525] | 4724 | /*
|
---|
| 4725 | * Increment the number of waiters before starting the wait.
|
---|
| 4726 | * Upon wakeup we must assert reality, checking that we're not
|
---|
| 4727 | * already destroyed or in the process of being destroyed. This
|
---|
| 4728 | * code must be aligned with the waiting code in intnetR0IfDestruct.
|
---|
| 4729 | */
|
---|
| 4730 | ASMAtomicIncU32(&pIf->cSleepers);
|
---|
| 4731 | rc = RTSemEventWaitNoResume(hRecvEvent, cMillies);
|
---|
| 4732 | if (pIf->hRecvEvent == hRecvEvent)
|
---|
[10819] | 4733 | {
|
---|
[60525] | 4734 | ASMAtomicDecU32(&pIf->cSleepers);
|
---|
| 4735 | ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd);
|
---|
| 4736 | if (hDtorThrd == NIL_RTNATIVETHREAD)
|
---|
| 4737 | {
|
---|
| 4738 | if (intnetR0IfRelease(pIf, pSession))
|
---|
| 4739 | rc = VERR_SEM_DESTROYED;
|
---|
| 4740 | }
|
---|
| 4741 | else
|
---|
[10819] | 4742 | rc = VERR_SEM_DESTROYED;
|
---|
| 4743 | }
|
---|
| 4744 | else
|
---|
[1] | 4745 | rc = VERR_SEM_DESTROYED;
|
---|
| 4746 | }
|
---|
| 4747 | else
|
---|
[60525] | 4748 | {
|
---|
[1] | 4749 | rc = VERR_SEM_DESTROYED;
|
---|
[60525] | 4750 | intnetR0IfRelease(pIf, pSession);
|
---|
| 4751 | }
|
---|
| 4752 |
|
---|
[28706] | 4753 | Log4(("IntNetR0IfWait: returns %Rrc\n", rc));
|
---|
[1] | 4754 | return rc;
|
---|
[97338] | 4755 | #endif
|
---|
[1] | 4756 | }
|
---|
| 4757 |
|
---|
| 4758 |
|
---|
| 4759 | /**
|
---|
[28706] | 4760 | * VMMR0 request wrapper for IntNetR0IfWait.
|
---|
[5283] | 4761 | *
|
---|
[28706] | 4762 | * @returns see IntNetR0IfWait.
|
---|
[10806] | 4763 | * @param pSession The caller's session.
|
---|
[5283] | 4764 | * @param pReq The request packet.
|
---|
| 4765 | */
|
---|
[28706] | 4766 | INTNETR0DECL(int) IntNetR0IfWaitReq(PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq)
|
---|
[5283] | 4767 | {
|
---|
| 4768 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4769 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4770 | return IntNetR0IfWait(pReq->hIf, pSession, pReq->cMillies);
|
---|
[5283] | 4771 | }
|
---|
| 4772 |
|
---|
| 4773 |
|
---|
| 4774 | /**
|
---|
[29669] | 4775 | * Wake up any threads waiting on the interface.
|
---|
| 4776 | *
|
---|
| 4777 | * @returns VBox status code.
|
---|
| 4778 | * @param hIf The interface handle.
|
---|
| 4779 | * @param pSession The caller's session.
|
---|
| 4780 | * @param fNoMoreWaits When set, no more waits are permitted.
|
---|
| 4781 | */
|
---|
| 4782 | INTNETR0DECL(int) IntNetR0IfAbortWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fNoMoreWaits)
|
---|
| 4783 | {
|
---|
| 4784 | Log4(("IntNetR0IfAbortWait: hIf=%RX32 fNoMoreWaits=%RTbool\n", hIf, fNoMoreWaits));
|
---|
| 4785 |
|
---|
| 4786 | /*
|
---|
| 4787 | * Get and validate essential handles.
|
---|
| 4788 | */
|
---|
| 4789 | PINTNET pIntNet = g_pIntNet;
|
---|
| 4790 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
| 4791 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4792 |
|
---|
| 4793 | PINTNETIF pIf = (PINTNETIF)RTHandleTableLookupWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
| 4794 | if (!pIf)
|
---|
| 4795 | {
|
---|
| 4796 | Log(("IntNetR0IfAbortWait: returns VERR_INVALID_HANDLE\n"));
|
---|
| 4797 | return VERR_INVALID_HANDLE;
|
---|
| 4798 | }
|
---|
| 4799 |
|
---|
[97338] | 4800 | #if defined(VBOX_WITH_INTNET_SERVICE_IN_R3) && defined(IN_RING3)
|
---|
| 4801 | AssertReleaseFailed();
|
---|
[97339] | 4802 | RT_NOREF(fNoMoreWaits);
|
---|
[97338] | 4803 | return VERR_NOT_SUPPORTED;
|
---|
| 4804 | #else
|
---|
[60525] | 4805 | const RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
|
---|
| 4806 | RTNATIVETHREAD hDtorThrd;
|
---|
| 4807 | ASMAtomicReadHandle(&pIf->hDestructorThread, &hDtorThrd);
|
---|
| 4808 | if (hDtorThrd != NIL_RTNATIVETHREAD)
|
---|
[29669] | 4809 | {
|
---|
[60525] | 4810 | /* This can only happen if we for some reason race SUPDRVSESSION cleanup,
|
---|
| 4811 | i.e. the object count is set to zero without yet having removed it from
|
---|
| 4812 | the object table, so we got a spurious "reference". We must drop that
|
---|
| 4813 | reference and let the destructor get on with its work. (Not entirely sure
|
---|
| 4814 | if this is practically possible on any of the platforms, i.e. whether it's
|
---|
| 4815 | we can actually close a SUPDrv handle/descriptor with active threads still
|
---|
| 4816 | in NtDeviceIoControlFile/ioctl, but better safe than sorry.) */
|
---|
[29669] | 4817 | Log(("IntNetR0IfAbortWait: returns VERR_SEM_DESTROYED\n"));
|
---|
| 4818 | return VERR_SEM_DESTROYED;
|
---|
| 4819 | }
|
---|
| 4820 |
|
---|
[60525] | 4821 | /* a bit of paranoia */
|
---|
| 4822 | int rc = VINF_SUCCESS;
|
---|
| 4823 | if (hRecvEvent != NIL_RTSEMEVENT)
|
---|
| 4824 | {
|
---|
| 4825 | /*
|
---|
| 4826 | * Set fNoMoreWaits if requested to do so and then wake up all the sleeping
|
---|
| 4827 | * threads (usually just one). We leave the semaphore in the signalled
|
---|
| 4828 | * state so the next caller will return immediately.
|
---|
| 4829 | */
|
---|
| 4830 | if (fNoMoreWaits)
|
---|
| 4831 | ASMAtomicWriteBool(&pIf->fNoMoreWaits, true);
|
---|
[29669] | 4832 |
|
---|
[60525] | 4833 | uint32_t cSleepers = ASMAtomicReadU32(&pIf->cSleepers) + 1;
|
---|
| 4834 | while (cSleepers-- > 0)
|
---|
| 4835 | {
|
---|
| 4836 | int rc2 = RTSemEventSignal(pIf->hRecvEvent);
|
---|
| 4837 | AssertRC(rc2);
|
---|
| 4838 | }
|
---|
[29669] | 4839 | }
|
---|
[60525] | 4840 | else
|
---|
| 4841 | rc = VERR_SEM_DESTROYED;
|
---|
[29669] | 4842 |
|
---|
[60525] | 4843 | intnetR0IfRelease(pIf, pSession);
|
---|
| 4844 |
|
---|
[29669] | 4845 | Log4(("IntNetR0IfWait: returns %Rrc\n", VINF_SUCCESS));
|
---|
| 4846 | return VINF_SUCCESS;
|
---|
[97338] | 4847 | #endif
|
---|
[29669] | 4848 | }
|
---|
| 4849 |
|
---|
| 4850 |
|
---|
| 4851 | /**
|
---|
| 4852 | * VMMR0 request wrapper for IntNetR0IfAbortWait.
|
---|
| 4853 | *
|
---|
| 4854 | * @returns see IntNetR0IfWait.
|
---|
| 4855 | * @param pSession The caller's session.
|
---|
| 4856 | * @param pReq The request packet.
|
---|
| 4857 | */
|
---|
| 4858 | INTNETR0DECL(int) IntNetR0IfAbortWaitReq(PSUPDRVSESSION pSession, PINTNETIFABORTWAITREQ pReq)
|
---|
| 4859 | {
|
---|
| 4860 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4861 | return VERR_INVALID_PARAMETER;
|
---|
| 4862 | return IntNetR0IfAbortWait(pReq->hIf, pSession, pReq->fNoMoreWaits);
|
---|
| 4863 | }
|
---|
| 4864 |
|
---|
| 4865 |
|
---|
| 4866 | /**
|
---|
[1] | 4867 | * Close an interface.
|
---|
| 4868 | *
|
---|
| 4869 | * @returns VBox status code.
|
---|
| 4870 | * @param pIntNet The instance handle.
|
---|
| 4871 | * @param hIf The interface handle.
|
---|
[10806] | 4872 | * @param pSession The caller's session.
|
---|
[1] | 4873 | */
|
---|
[28706] | 4874 | INTNETR0DECL(int) IntNetR0IfClose(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession)
|
---|
[1] | 4875 | {
|
---|
[28706] | 4876 | LogFlow(("IntNetR0IfClose: hIf=%RX32\n", hIf));
|
---|
[1] | 4877 |
|
---|
| 4878 | /*
|
---|
[10819] | 4879 | * Validate and free the handle.
|
---|
[1] | 4880 | */
|
---|
[28706] | 4881 | PINTNET pIntNet = g_pIntNet;
|
---|
[10451] | 4882 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
[28706] | 4883 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
| 4884 |
|
---|
[10819] | 4885 | PINTNETIF pIf = (PINTNETIF)RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pSession);
|
---|
[1] | 4886 | if (!pIf)
|
---|
| 4887 | return VERR_INVALID_HANDLE;
|
---|
[10819] | 4888 |
|
---|
[29635] | 4889 | /* Mark the handle as freed so intnetR0IfDestruct won't free it again. */
|
---|
[10557] | 4890 | ASMAtomicWriteU32(&pIf->hIf, INTNET_HANDLE_INVALID);
|
---|
[1] | 4891 |
|
---|
[97338] | 4892 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[10557] | 4893 | /*
|
---|
[29635] | 4894 | * Signal the event semaphore to wake up any threads in IntNetR0IfWait
|
---|
| 4895 | * and give them a moment to get out and release the interface.
|
---|
[10557] | 4896 | */
|
---|
[28623] | 4897 | uint32_t i = pIf->cSleepers;
|
---|
| 4898 | while (i-- > 0)
|
---|
| 4899 | {
|
---|
| 4900 | RTSemEventSignal(pIf->hRecvEvent);
|
---|
| 4901 | RTThreadYield();
|
---|
| 4902 | }
|
---|
| 4903 | RTSemEventSignal(pIf->hRecvEvent);
|
---|
[97338] | 4904 | #endif
|
---|
[10819] | 4905 |
|
---|
[29635] | 4906 | /*
|
---|
| 4907 | * Release the references to the interface object (handle + free lookup).
|
---|
| 4908 | */
|
---|
[15842] | 4909 | void *pvObj = pIf->pvObj;
|
---|
[10819] | 4910 | intnetR0IfRelease(pIf, pSession); /* (RTHandleTableFreeWithCtx) */
|
---|
| 4911 |
|
---|
[15842] | 4912 | int rc = SUPR0ObjRelease(pvObj, pSession);
|
---|
[28706] | 4913 | LogFlow(("IntNetR0IfClose: returns %Rrc\n", rc));
|
---|
[1] | 4914 | return rc;
|
---|
| 4915 | }
|
---|
| 4916 |
|
---|
| 4917 |
|
---|
| 4918 | /**
|
---|
[28706] | 4919 | * VMMR0 request wrapper for IntNetR0IfCloseReq.
|
---|
[5283] | 4920 | *
|
---|
[28706] | 4921 | * @returns see IntNetR0IfClose.
|
---|
[10806] | 4922 | * @param pSession The caller's session.
|
---|
[5283] | 4923 | * @param pReq The request packet.
|
---|
| 4924 | */
|
---|
[28706] | 4925 | INTNETR0DECL(int) IntNetR0IfCloseReq(PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq)
|
---|
[5283] | 4926 | {
|
---|
| 4927 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 4928 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 4929 | return IntNetR0IfClose(pReq->hIf, pSession);
|
---|
[5283] | 4930 | }
|
---|
| 4931 |
|
---|
| 4932 |
|
---|
| 4933 | /**
|
---|
[1] | 4934 | * Interface destructor callback.
|
---|
| 4935 | * This is called for reference counted objectes when the count reaches 0.
|
---|
| 4936 | *
|
---|
| 4937 | * @param pvObj The object pointer.
|
---|
| 4938 | * @param pvUser1 Pointer to the interface.
|
---|
| 4939 | * @param pvUser2 Pointer to the INTNET instance data.
|
---|
| 4940 | */
|
---|
[10711] | 4941 | static DECLCALLBACK(void) intnetR0IfDestruct(void *pvObj, void *pvUser1, void *pvUser2)
|
---|
[1] | 4942 | {
|
---|
[28488] | 4943 | PINTNETIF pIf = (PINTNETIF)pvUser1;
|
---|
[1] | 4944 | PINTNET pIntNet = (PINTNET)pvUser2;
|
---|
[10923] | 4945 | Log(("intnetR0IfDestruct: pvObj=%p pIf=%p pIntNet=%p hIf=%RX32\n", pvObj, pIf, pIntNet, pIf->hIf));
|
---|
[62628] | 4946 | RT_NOREF1(pvObj);
|
---|
[1] | 4947 |
|
---|
| 4948 | /*
|
---|
[60525] | 4949 | * For paranoid reasons we must now mark the interface as destroyed.
|
---|
| 4950 | * This is so that any waiting threads can take evasive action (kind
|
---|
| 4951 | * of theoretical case), and we can reject everyone else referencing
|
---|
| 4952 | * the object via the handle table before we get around to removing it.
|
---|
| 4953 | */
|
---|
| 4954 | ASMAtomicWriteHandle(&pIf->hDestructorThread, RTThreadNativeSelf());
|
---|
| 4955 |
|
---|
| 4956 | /*
|
---|
[28488] | 4957 | * We grab the INTNET create/open/destroy semaphore to make sure nobody is
|
---|
[60525] | 4958 | * adding or removing interfaces while we're in here.
|
---|
[1] | 4959 | */
|
---|
[28488] | 4960 | RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
[10819] | 4961 |
|
---|
| 4962 | /*
|
---|
| 4963 | * Delete the interface handle so the object no longer can be used.
|
---|
| 4964 | * (Can happen if the client didn't close its session.)
|
---|
| 4965 | */
|
---|
[10557] | 4966 | INTNETIFHANDLE hIf = ASMAtomicXchgU32(&pIf->hIf, INTNET_HANDLE_INVALID);
|
---|
| 4967 | if (hIf != INTNET_HANDLE_INVALID)
|
---|
[10819] | 4968 | {
|
---|
[11133] | 4969 | void *pvObj2 = RTHandleTableFreeWithCtx(pIntNet->hHtIfs, hIf, pIf->pSession); NOREF(pvObj2);
|
---|
[10923] | 4970 | AssertMsg(pvObj2 == pIf, ("%p, %p, hIf=%RX32 pSession=%p\n", pvObj2, pIf, hIf, pIf->pSession));
|
---|
[10819] | 4971 | }
|
---|
[1] | 4972 |
|
---|
[15842] | 4973 | /*
|
---|
[28623] | 4974 | * If we've got a network deactivate and detach ourselves from it. Because
|
---|
| 4975 | * of cleanup order we might have been orphaned by the network destructor.
|
---|
[1] | 4976 | */
|
---|
[29635] | 4977 | PINTNETNETWORK pNetwork = pIf->pNetwork;
|
---|
[10548] | 4978 | if (pNetwork)
|
---|
[1] | 4979 | {
|
---|
[28623] | 4980 | /* set inactive. */
|
---|
| 4981 | intnetR0NetworkSetIfActive(pNetwork, pIf, false /*fActive*/);
|
---|
[10711] | 4982 |
|
---|
[28623] | 4983 | /* remove ourselves from the switch table. */
|
---|
[40806] | 4984 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 4985 |
|
---|
| 4986 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 4987 | while (iIf-- > 0)
|
---|
| 4988 | if (pNetwork->MacTab.paEntries[iIf].pIf == pIf)
|
---|
[9180] | 4989 | {
|
---|
[36089] | 4990 | if (pNetwork->MacTab.paEntries[iIf].fPromiscuousEff)
|
---|
| 4991 | {
|
---|
| 4992 | pNetwork->MacTab.cPromiscuousEntries--;
|
---|
| 4993 | if (!pNetwork->MacTab.paEntries[iIf].fPromiscuousSeeTrunk)
|
---|
| 4994 | pNetwork->MacTab.cPromiscuousNoTrunkEntries--;
|
---|
| 4995 | }
|
---|
| 4996 | Assert(pNetwork->MacTab.cPromiscuousEntries < pNetwork->MacTab.cEntries);
|
---|
| 4997 | Assert(pNetwork->MacTab.cPromiscuousNoTrunkEntries < pNetwork->MacTab.cEntries);
|
---|
| 4998 |
|
---|
[28623] | 4999 | if (iIf + 1 < pNetwork->MacTab.cEntries)
|
---|
| 5000 | memmove(&pNetwork->MacTab.paEntries[iIf],
|
---|
| 5001 | &pNetwork->MacTab.paEntries[iIf + 1],
|
---|
| 5002 | (pNetwork->MacTab.cEntries - iIf - 1) * sizeof(pNetwork->MacTab.paEntries[0]));
|
---|
| 5003 | pNetwork->MacTab.cEntries--;
|
---|
| 5004 | break;
|
---|
[9180] | 5005 | }
|
---|
[10547] | 5006 |
|
---|
[36075] | 5007 | /* recalc the min flags. */
|
---|
| 5008 | if (pIf->fOpenFlags & INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES)
|
---|
| 5009 | {
|
---|
| 5010 | uint32_t fMinFlags = 0;
|
---|
| 5011 | iIf = pNetwork->MacTab.cEntries;
|
---|
| 5012 | while (iIf-- > 0)
|
---|
| 5013 | {
|
---|
| 5014 | PINTNETIF pIf2 = pNetwork->MacTab.paEntries[iIf].pIf;
|
---|
| 5015 | if ( pIf2 /* paranoia */
|
---|
| 5016 | && (pIf2->fOpenFlags & INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES))
|
---|
| 5017 | fMinFlags |= pIf2->fOpenFlags & INTNET_OPEN_FLAGS_STRICT_MASK;
|
---|
| 5018 | }
|
---|
| 5019 | pNetwork->fMinFlags = fMinFlags;
|
---|
| 5020 | }
|
---|
[36089] | 5021 |
|
---|
[29635] | 5022 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 5023 |
|
---|
[52618] | 5024 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 5025 |
|
---|
[29662] | 5026 | /* Notify the trunk about the interface being destroyed. */
|
---|
| 5027 | if (pTrunk && pTrunk->pIfPort)
|
---|
| 5028 | pTrunk->pIfPort->pfnDisconnectInterface(pTrunk->pIfPort, pIf->pvIfData);
|
---|
[29635] | 5029 |
|
---|
[28623] | 5030 | /* Wait for the interface to quiesce while we still can. */
|
---|
| 5031 | intnetR0BusyWait(pNetwork, &pIf->cBusy);
|
---|
| 5032 |
|
---|
[28488] | 5033 | /* Release our reference to the network. */
|
---|
[40806] | 5034 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 5035 | pIf->pNetwork = NULL;
|
---|
[52618] | 5036 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 5037 |
|
---|
[10548] | 5038 | SUPR0ObjRelease(pNetwork->pvObj, pIf->pSession);
|
---|
[1] | 5039 | }
|
---|
| 5040 |
|
---|
[28488] | 5041 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
| 5042 |
|
---|
[97338] | 5043 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[1] | 5044 | /*
|
---|
[60525] | 5045 | * Wakeup anyone waiting on this interface. (Kind of unlikely, but perhaps
|
---|
| 5046 | * not quite impossible.)
|
---|
[1] | 5047 | *
|
---|
| 5048 | * We *must* make sure they have woken up properly and realized
|
---|
| 5049 | * that the interface is no longer valid.
|
---|
| 5050 | */
|
---|
[28623] | 5051 | if (pIf->hRecvEvent != NIL_RTSEMEVENT)
|
---|
[1] | 5052 | {
|
---|
[28623] | 5053 | RTSEMEVENT hRecvEvent = pIf->hRecvEvent;
|
---|
| 5054 | unsigned cMaxWait = 0x1000;
|
---|
[1] | 5055 | while (pIf->cSleepers && cMaxWait-- > 0)
|
---|
| 5056 | {
|
---|
[28623] | 5057 | RTSemEventSignal(hRecvEvent);
|
---|
[1] | 5058 | RTThreadYield();
|
---|
| 5059 | }
|
---|
| 5060 | if (pIf->cSleepers)
|
---|
| 5061 | {
|
---|
| 5062 | RTThreadSleep(1);
|
---|
| 5063 |
|
---|
| 5064 | cMaxWait = pIf->cSleepers;
|
---|
| 5065 | while (pIf->cSleepers && cMaxWait-- > 0)
|
---|
| 5066 | {
|
---|
[28623] | 5067 | RTSemEventSignal(hRecvEvent);
|
---|
[1] | 5068 | RTThreadSleep(10);
|
---|
| 5069 | }
|
---|
| 5070 | }
|
---|
[10819] | 5071 |
|
---|
[28623] | 5072 | RTSemEventDestroy(hRecvEvent);
|
---|
| 5073 | pIf->hRecvEvent = NIL_RTSEMEVENT;
|
---|
[1] | 5074 | }
|
---|
[97338] | 5075 | #endif
|
---|
[1] | 5076 |
|
---|
| 5077 | /*
|
---|
| 5078 | * Unmap user buffer.
|
---|
| 5079 | */
|
---|
| 5080 | if (pIf->pIntBuf != pIf->pIntBufDefault)
|
---|
| 5081 | {
|
---|
| 5082 | /** @todo user buffer */
|
---|
| 5083 | }
|
---|
| 5084 |
|
---|
| 5085 | /*
|
---|
| 5086 | * Unmap and Free the default buffer.
|
---|
| 5087 | */
|
---|
| 5088 | if (pIf->pIntBufDefault)
|
---|
| 5089 | {
|
---|
[1482] | 5090 | SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
|
---|
[28438] | 5091 | pIf->pIntBufDefault = NULL;
|
---|
| 5092 | pIf->pIntBufDefaultR3 = 0;
|
---|
| 5093 | pIf->pIntBuf = NULL;
|
---|
| 5094 | pIf->pIntBufR3 = 0;
|
---|
[1] | 5095 | }
|
---|
| 5096 |
|
---|
| 5097 | /*
|
---|
[28623] | 5098 | * Free remaining resources
|
---|
[1] | 5099 | */
|
---|
[28623] | 5100 | RTSpinlockDestroy(pIf->hRecvInSpinlock);
|
---|
| 5101 | pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
|
---|
| 5102 |
|
---|
| 5103 | RTMemFree(pIf->pDstTab);
|
---|
| 5104 | pIf->pDstTab = NULL;
|
---|
| 5105 |
|
---|
[29362] | 5106 | for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End; i++)
|
---|
| 5107 | intnetR0IfAddrCacheDestroy(&pIf->aAddrCache[i]);
|
---|
[28623] | 5108 |
|
---|
[29491] | 5109 | pIf->pvObj = NULL;
|
---|
[15842] | 5110 | RTMemFree(pIf);
|
---|
[1] | 5111 | }
|
---|
| 5112 |
|
---|
| 5113 |
|
---|
[74484] | 5114 | /* Forward declaration of trunk reconnection thread function. */
|
---|
| 5115 | static DECLCALLBACK(int) intnetR0TrunkReconnectThread(RTTHREAD hThread, void *pvUser);
|
---|
| 5116 |
|
---|
[1] | 5117 | /**
|
---|
| 5118 | * Creates a new network interface.
|
---|
| 5119 | *
|
---|
[28488] | 5120 | * The call must have opened the network for the new interface and is
|
---|
| 5121 | * responsible for closing it on failure. On success it must leave the network
|
---|
| 5122 | * opened so the interface destructor can close it.
|
---|
[1] | 5123 | *
|
---|
| 5124 | * @returns VBox status code.
|
---|
[97338] | 5125 | * @param pNetwork The network, referenced. The reference is consumed
|
---|
| 5126 | * on success.
|
---|
| 5127 | * @param pSession The session handle.
|
---|
| 5128 | * @param cbSend The size of the send buffer.
|
---|
| 5129 | * @param cbRecv The size of the receive buffer.
|
---|
| 5130 | * @param fFlags The open network flags.
|
---|
| 5131 | * @param pfnRecvAvail The receive available callback to call instead of
|
---|
| 5132 | * signalling the semaphore (R3 service only).
|
---|
| 5133 | * @param pvUser The opaque user data to pass to the callback.
|
---|
| 5134 | * @param phIf Where to store the interface handle.
|
---|
[1] | 5135 | */
|
---|
[97338] | 5136 | static int intnetR0NetworkCreateIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession, unsigned cbSend, unsigned cbRecv,
|
---|
| 5137 | uint32_t fFlags, PFNINTNETIFRECVAVAIL pfnRecvAvail, void *pvUser, PINTNETIFHANDLE phIf)
|
---|
[1] | 5138 | {
|
---|
[36075] | 5139 | LogFlow(("intnetR0NetworkCreateIf: pNetwork=%p pSession=%p cbSend=%u cbRecv=%u fFlags=%#x phIf=%p\n",
|
---|
| 5140 | pNetwork, pSession, cbSend, cbRecv, fFlags, phIf));
|
---|
[1] | 5141 |
|
---|
| 5142 | /*
|
---|
| 5143 | * Assert input.
|
---|
| 5144 | */
|
---|
[10451] | 5145 | AssertPtr(pNetwork);
|
---|
| 5146 | AssertPtr(phIf);
|
---|
[97338] | 5147 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
| 5148 | Assert(pfnRecvAvail == NULL);
|
---|
| 5149 | Assert(pvUser == NULL);
|
---|
| 5150 | RT_NOREF(pfnRecvAvail, pvUser);
|
---|
| 5151 | #endif
|
---|
[1] | 5152 |
|
---|
| 5153 | /*
|
---|
[36075] | 5154 | * Adjust the flags with defaults for the interface policies.
|
---|
| 5155 | * Note: Main restricts promiscuous mode per interface.
|
---|
| 5156 | */
|
---|
| 5157 | uint32_t const fDefFlags = INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW
|
---|
| 5158 | | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK;
|
---|
| 5159 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkIfFlags); i++)
|
---|
| 5160 | if (!(fFlags & g_afIntNetOpenNetworkIfFlags[i].fPair))
|
---|
| 5161 | fFlags |= g_afIntNetOpenNetworkIfFlags[i].fPair & fDefFlags;
|
---|
| 5162 |
|
---|
| 5163 | /*
|
---|
[28623] | 5164 | * Make sure that all destination tables as well as the have space of
|
---|
[1] | 5165 | */
|
---|
[28623] | 5166 | int rc = intnetR0NetworkEnsureTabSpace(pNetwork);
|
---|
| 5167 | if (RT_FAILURE(rc))
|
---|
| 5168 | return rc;
|
---|
| 5169 |
|
---|
| 5170 | /*
|
---|
[33540] | 5171 | * Allocate the interface and initialize it.
|
---|
[28623] | 5172 | */
|
---|
[1] | 5173 | PINTNETIF pIf = (PINTNETIF)RTMemAllocZ(sizeof(*pIf));
|
---|
| 5174 | if (!pIf)
|
---|
| 5175 | return VERR_NO_MEMORY;
|
---|
[28623] | 5176 |
|
---|
| 5177 | memset(&pIf->MacAddr, 0xff, sizeof(pIf->MacAddr)); /* broadcast */
|
---|
| 5178 | //pIf->fMacSet = false;
|
---|
[36075] | 5179 | //pIf->fPromiscuousReal = false;
|
---|
[28623] | 5180 | //pIf->fActive = false;
|
---|
[60525] | 5181 | //pIf->fNoMoreWaits = false;
|
---|
[36075] | 5182 | pIf->fOpenFlags = fFlags;
|
---|
[28623] | 5183 | //pIf->cYields = 0;
|
---|
| 5184 | //pIf->pIntBuf = 0;
|
---|
| 5185 | //pIf->pIntBufR3 = NIL_RTR3PTR;
|
---|
| 5186 | //pIf->pIntBufDefault = 0;
|
---|
[10711] | 5187 | //pIf->pIntBufDefaultR3 = NIL_RTR3PTR;
|
---|
[97338] | 5188 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[28623] | 5189 | pIf->hRecvEvent = NIL_RTSEMEVENT;
|
---|
[97338] | 5190 | #else
|
---|
| 5191 | pIf->pfnRecvAvail = pfnRecvAvail;
|
---|
| 5192 | pIf->pvUserRecvAvail = pvUser;
|
---|
| 5193 | #endif
|
---|
[28623] | 5194 | //pIf->cSleepers = 0;
|
---|
| 5195 | pIf->hIf = INTNET_HANDLE_INVALID;
|
---|
[60525] | 5196 | pIf->hDestructorThread = NIL_RTNATIVETHREAD;
|
---|
[28623] | 5197 | pIf->pNetwork = pNetwork;
|
---|
| 5198 | pIf->pSession = pSession;
|
---|
| 5199 | //pIf->pvObj = NULL;
|
---|
[29362] | 5200 | //pIf->aAddrCache = {0};
|
---|
[28623] | 5201 | pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
|
---|
| 5202 | pIf->cBusy = 0;
|
---|
| 5203 | //pIf->pDstTab = NULL;
|
---|
[29662] | 5204 | //pIf->pvIfData = NULL;
|
---|
[28623] | 5205 |
|
---|
[29362] | 5206 | for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End && RT_SUCCESS(rc); i++)
|
---|
| 5207 | rc = intnetR0IfAddrCacheInit(&pIf->aAddrCache[i], (INTNETADDRTYPE)i,
|
---|
| 5208 | !!(pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE));
|
---|
[10533] | 5209 | if (RT_SUCCESS(rc))
|
---|
[29362] | 5210 | rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, (PINTNETDSTTAB *)&pIf->pDstTab);
|
---|
[97338] | 5211 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[29362] | 5212 | if (RT_SUCCESS(rc))
|
---|
[28623] | 5213 | rc = RTSemEventCreate((PRTSEMEVENT)&pIf->hRecvEvent);
|
---|
[97338] | 5214 | #endif
|
---|
[28623] | 5215 | if (RT_SUCCESS(rc))
|
---|
[40806] | 5216 | rc = RTSpinlockCreate(&pIf->hRecvInSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "hRecvInSpinlock");
|
---|
[28623] | 5217 | if (RT_SUCCESS(rc))
|
---|
[1] | 5218 | {
|
---|
| 5219 | /*
|
---|
| 5220 | * Create the default buffer.
|
---|
| 5221 | */
|
---|
[10745] | 5222 | /** @todo adjust with minimums and apply defaults here. */
|
---|
[26574] | 5223 | cbRecv = RT_ALIGN(RT_MAX(cbRecv, sizeof(INTNETHDR) * 4), INTNETRINGBUF_ALIGNMENT);
|
---|
| 5224 | cbSend = RT_ALIGN(RT_MAX(cbSend, sizeof(INTNETHDR) * 4), INTNETRINGBUF_ALIGNMENT);
|
---|
| 5225 | const unsigned cbBuf = RT_ALIGN(sizeof(*pIf->pIntBuf), INTNETRINGBUF_ALIGNMENT) + cbRecv + cbSend;
|
---|
[1481] | 5226 | rc = SUPR0MemAlloc(pIf->pSession, cbBuf, (PRTR0PTR)&pIf->pIntBufDefault, (PRTR3PTR)&pIf->pIntBufDefaultR3);
|
---|
[10533] | 5227 | if (RT_SUCCESS(rc))
|
---|
[1] | 5228 | {
|
---|
[103025] | 5229 | RT_BZERO(pIf->pIntBufDefault, cbBuf); /** @todo I thought I specified these buggers as clearing the memory... */
|
---|
[10748] | 5230 |
|
---|
[28488] | 5231 | pIf->pIntBuf = pIf->pIntBufDefault;
|
---|
[1] | 5232 | pIf->pIntBufR3 = pIf->pIntBufDefaultR3;
|
---|
[28714] | 5233 | IntNetBufInit(pIf->pIntBuf, cbBuf, cbRecv, cbSend);
|
---|
[1] | 5234 |
|
---|
| 5235 | /*
|
---|
[28623] | 5236 | * Register the interface with the session and create a handle for it.
|
---|
[1] | 5237 | */
|
---|
[28623] | 5238 | pIf->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE,
|
---|
| 5239 | intnetR0IfDestruct, pIf, pNetwork->pIntNet);
|
---|
| 5240 | if (pIf->pvObj)
|
---|
[1] | 5241 | {
|
---|
[28623] | 5242 | rc = RTHandleTableAllocWithCtx(pNetwork->pIntNet->hHtIfs, pIf, pSession, (uint32_t *)&pIf->hIf);
|
---|
[28488] | 5243 | if (RT_SUCCESS(rc))
|
---|
[1] | 5244 | {
|
---|
[28623] | 5245 | /*
|
---|
| 5246 | * Finally add the interface to the network, consuming the
|
---|
| 5247 | * network reference of the caller.
|
---|
| 5248 | */
|
---|
[40806] | 5249 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28488] | 5250 |
|
---|
[28623] | 5251 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 5252 | Assert(iIf + 1 <= pNetwork->MacTab.cEntriesAllocated);
|
---|
[1] | 5253 |
|
---|
[36075] | 5254 | pNetwork->MacTab.paEntries[iIf].MacAddr = pIf->MacAddr;
|
---|
| 5255 | pNetwork->MacTab.paEntries[iIf].fActive = false;
|
---|
| 5256 | pNetwork->MacTab.paEntries[iIf].fPromiscuousEff = false;
|
---|
| 5257 | pNetwork->MacTab.paEntries[iIf].fPromiscuousSeeTrunk = false;
|
---|
| 5258 | pNetwork->MacTab.paEntries[iIf].pIf = pIf;
|
---|
[28623] | 5259 |
|
---|
| 5260 | pNetwork->MacTab.cEntries = iIf + 1;
|
---|
| 5261 | pIf->pNetwork = pNetwork;
|
---|
| 5262 |
|
---|
[29635] | 5263 | /*
|
---|
[33540] | 5264 | * Grab a busy reference (paranoia) to the trunk before releasing
|
---|
[29635] | 5265 | * the spinlock and then notify it about the new interface.
|
---|
| 5266 | */
|
---|
[29491] | 5267 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
[29635] | 5268 | if (pTrunk)
|
---|
| 5269 | intnetR0BusyIncTrunk(pTrunk);
|
---|
| 5270 |
|
---|
[52618] | 5271 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[29635] | 5272 |
|
---|
| 5273 | if (pTrunk)
|
---|
[29491] | 5274 | {
|
---|
| 5275 | Log(("intnetR0NetworkCreateIf: pfnConnectInterface hIf=%RX32\n", pIf->hIf));
|
---|
[29635] | 5276 | if (pTrunk->pIfPort)
|
---|
[29662] | 5277 | rc = pTrunk->pIfPort->pfnConnectInterface(pTrunk->pIfPort, pIf, &pIf->pvIfData);
|
---|
[29635] | 5278 | intnetR0BusyDecTrunk(pTrunk);
|
---|
[29491] | 5279 | }
|
---|
[29635] | 5280 | if (RT_SUCCESS(rc))
|
---|
| 5281 | {
|
---|
| 5282 | /*
|
---|
| 5283 | * We're good!
|
---|
| 5284 | */
|
---|
| 5285 | *phIf = pIf->hIf;
|
---|
| 5286 | Log(("intnetR0NetworkCreateIf: returns VINF_SUCCESS *phIf=%RX32 cbSend=%u cbRecv=%u cbBuf=%u\n",
|
---|
| 5287 | *phIf, pIf->pIntBufDefault->cbSend, pIf->pIntBufDefault->cbRecv, pIf->pIntBufDefault->cbBuf));
|
---|
| 5288 | return VINF_SUCCESS;
|
---|
| 5289 | }
|
---|
[1] | 5290 | }
|
---|
[10711] | 5291 |
|
---|
[54868] | 5292 | SUPR0ObjAddRef(pNetwork->pvObj, pSession);
|
---|
[28623] | 5293 | SUPR0ObjRelease(pIf->pvObj, pSession);
|
---|
| 5294 | LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
|
---|
| 5295 | return rc;
|
---|
[1] | 5296 | }
|
---|
[10711] | 5297 |
|
---|
[28623] | 5298 | /* clean up */
|
---|
[1482] | 5299 | SUPR0MemFree(pIf->pSession, (RTHCUINTPTR)pIf->pIntBufDefault);
|
---|
[1] | 5300 | pIf->pIntBufDefault = NULL;
|
---|
| 5301 | pIf->pIntBuf = NULL;
|
---|
| 5302 | }
|
---|
[28623] | 5303 | }
|
---|
[1] | 5304 |
|
---|
[28623] | 5305 | RTSpinlockDestroy(pIf->hRecvInSpinlock);
|
---|
| 5306 | pIf->hRecvInSpinlock = NIL_RTSPINLOCK;
|
---|
[97338] | 5307 | #if !defined(VBOX_WITH_INTNET_SERVICE_IN_R3) || !defined(IN_RING3)
|
---|
[28623] | 5308 | RTSemEventDestroy(pIf->hRecvEvent);
|
---|
| 5309 | pIf->hRecvEvent = NIL_RTSEMEVENT;
|
---|
[97338] | 5310 | #else
|
---|
| 5311 | pIf->pfnRecvAvail = NULL;
|
---|
| 5312 | pIf->pvUserRecvAvail = NULL;
|
---|
| 5313 | #endif
|
---|
[28623] | 5314 | RTMemFree(pIf->pDstTab);
|
---|
[29362] | 5315 | for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End; i++)
|
---|
| 5316 | intnetR0IfAddrCacheDestroy(&pIf->aAddrCache[i]);
|
---|
[1] | 5317 | RTMemFree(pIf);
|
---|
[10711] | 5318 | LogFlow(("intnetR0NetworkCreateIf: returns %Rrc\n", rc));
|
---|
[1] | 5319 | return rc;
|
---|
| 5320 | }
|
---|
| 5321 |
|
---|
| 5322 |
|
---|
[62956] | 5323 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnSetSGPhys} */
|
---|
[25336] | 5324 | static DECLCALLBACK(bool) intnetR0TrunkIfPortSetSGPhys(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)
|
---|
[10663] | 5325 | {
|
---|
[10681] | 5326 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
[10663] | 5327 | AssertMsgFailed(("Not implemented because it wasn't required on Darwin\n"));
|
---|
[10681] | 5328 | return ASMAtomicXchgBool(&pThis->fPhysSG, fEnable);
|
---|
[10663] | 5329 | }
|
---|
| 5330 |
|
---|
| 5331 |
|
---|
[62956] | 5332 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnReportMacAddress} */
|
---|
[28666] | 5333 | static DECLCALLBACK(void) intnetR0TrunkIfPortReportMacAddress(PINTNETTRUNKSWPORT pSwitchPort, PCRTMAC pMacAddr)
|
---|
| 5334 | {
|
---|
| 5335 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5336 |
|
---|
| 5337 | /*
|
---|
| 5338 | * Get the network instance and grab the address spinlock before making
|
---|
| 5339 | * any changes.
|
---|
| 5340 | */
|
---|
| 5341 | intnetR0BusyIncTrunk(pThis);
|
---|
| 5342 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
| 5343 | if (pNetwork)
|
---|
| 5344 | {
|
---|
[40806] | 5345 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28666] | 5346 |
|
---|
| 5347 | pNetwork->MacTab.HostMac = *pMacAddr;
|
---|
| 5348 | pThis->MacAddr = *pMacAddr;
|
---|
| 5349 |
|
---|
[52618] | 5350 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28666] | 5351 | }
|
---|
| 5352 | else
|
---|
| 5353 | pThis->MacAddr = *pMacAddr;
|
---|
| 5354 | intnetR0BusyDecTrunk(pThis);
|
---|
| 5355 | }
|
---|
| 5356 |
|
---|
| 5357 |
|
---|
[62956] | 5358 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnReportPromiscuousMode} */
|
---|
[28666] | 5359 | static DECLCALLBACK(void) intnetR0TrunkIfPortReportPromiscuousMode(PINTNETTRUNKSWPORT pSwitchPort, bool fPromiscuous)
|
---|
| 5360 | {
|
---|
| 5361 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5362 |
|
---|
| 5363 | /*
|
---|
| 5364 | * Get the network instance and grab the address spinlock before making
|
---|
| 5365 | * any changes.
|
---|
| 5366 | */
|
---|
| 5367 | intnetR0BusyIncTrunk(pThis);
|
---|
| 5368 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
| 5369 | if (pNetwork)
|
---|
| 5370 | {
|
---|
[40806] | 5371 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28666] | 5372 |
|
---|
[36075] | 5373 | pNetwork->MacTab.fHostPromiscuousReal = fPromiscuous
|
---|
| 5374 | || (pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE);
|
---|
| 5375 | pNetwork->MacTab.fHostPromiscuousEff = pNetwork->MacTab.fHostPromiscuousReal
|
---|
| 5376 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST);
|
---|
[28666] | 5377 |
|
---|
[52618] | 5378 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28666] | 5379 | }
|
---|
| 5380 | intnetR0BusyDecTrunk(pThis);
|
---|
| 5381 | }
|
---|
| 5382 |
|
---|
| 5383 |
|
---|
[62956] | 5384 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnReportGsoCapabilities} */
|
---|
[28120] | 5385 | static DECLCALLBACK(void) intnetR0TrunkIfPortReportGsoCapabilities(PINTNETTRUNKSWPORT pSwitchPort,
|
---|
[28723] | 5386 | uint32_t fGsoCapabilities, uint32_t fDst)
|
---|
[28120] | 5387 | {
|
---|
| 5388 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5389 |
|
---|
| 5390 | for (unsigned iBit = PDMNETWORKGSOTYPE_END; iBit < 32; iBit++)
|
---|
| 5391 | Assert(!(fGsoCapabilities & RT_BIT_32(iBit)));
|
---|
[28156] | 5392 | Assert(!(fDst & ~INTNETTRUNKDIR_VALID_MASK));
|
---|
[28120] | 5393 | Assert(fDst);
|
---|
| 5394 |
|
---|
| 5395 | if (fDst & INTNETTRUNKDIR_HOST)
|
---|
[28430] | 5396 | pThis->fHostGsoCapabilites = fGsoCapabilities;
|
---|
[28120] | 5397 |
|
---|
| 5398 | if (fDst & INTNETTRUNKDIR_WIRE)
|
---|
[28430] | 5399 | pThis->fWireGsoCapabilites = fGsoCapabilities;
|
---|
[28120] | 5400 | }
|
---|
| 5401 |
|
---|
| 5402 |
|
---|
[62956] | 5403 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnReportNoPreemptDsts} */
|
---|
[28723] | 5404 | static DECLCALLBACK(void) intnetR0TrunkIfPortReportNoPreemptDsts(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fNoPreemptDsts)
|
---|
| 5405 | {
|
---|
| 5406 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5407 | Assert(!(fNoPreemptDsts & ~INTNETTRUNKDIR_VALID_MASK));
|
---|
| 5408 |
|
---|
| 5409 | pThis->fNoPreemptDsts = fNoPreemptDsts;
|
---|
| 5410 | }
|
---|
| 5411 |
|
---|
| 5412 |
|
---|
[62956] | 5413 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnDisconnect} */
|
---|
[52394] | 5414 | static DECLCALLBACK(void) intnetR0TrunkIfPortDisconnect(PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT pIfPort,
|
---|
| 5415 | PFNINTNETTRUNKIFPORTRELEASEBUSY pfnReleaseBusy)
|
---|
[52134] | 5416 | {
|
---|
| 5417 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
[52393] | 5418 |
|
---|
[52134] | 5419 | /*
|
---|
[52393] | 5420 | * The caller has marked the trunk instance busy on his side before making
|
---|
| 5421 | * the call (see method docs) to let us safely grab the network and internal
|
---|
| 5422 | * network instance pointers without racing the network destruction code
|
---|
| 5423 | * (intnetR0TrunkIfDestroy (called by intnetR0TrunkIfDestroy) will wait for
|
---|
| 5424 | * the interface to stop being busy before setting pNetwork to NULL and
|
---|
| 5425 | * freeing up the resources).
|
---|
[52134] | 5426 | */
|
---|
| 5427 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
| 5428 | if (pNetwork)
|
---|
| 5429 | {
|
---|
| 5430 | PINTNET pIntNet = pNetwork->pIntNet;
|
---|
| 5431 | Assert(pNetwork->pIntNet);
|
---|
[52393] | 5432 |
|
---|
[52134] | 5433 | /*
|
---|
[52393] | 5434 | * We must decrease the callers busy count here to prevent deadlocking
|
---|
| 5435 | * when requesting the big mutex ownership. This will of course
|
---|
| 5436 | * unblock anyone stuck in intnetR0TrunkIfDestroy doing pfnWaitForIdle
|
---|
| 5437 | * (the other deadlock party), so we have to revalidate the network
|
---|
| 5438 | * pointer after taking ownership of the big mutex.
|
---|
[52134] | 5439 | */
|
---|
[65698] | 5440 | if (pfnReleaseBusy)
|
---|
| 5441 | pfnReleaseBusy(pIfPort);
|
---|
[52393] | 5442 |
|
---|
[52134] | 5443 | RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
[52393] | 5444 |
|
---|
[52134] | 5445 | if (intnetR0NetworkIsValid(pIntNet, pNetwork))
|
---|
| 5446 | {
|
---|
[52393] | 5447 | Assert(pNetwork->MacTab.pTrunk == pThis); /* Must be valid as long as tehre are no concurrent calls to this method. */
|
---|
[52394] | 5448 | Assert(pThis->pIfPort == pIfPort); /* Ditto */
|
---|
[52393] | 5449 |
|
---|
| 5450 | /*
|
---|
| 5451 | * Disconnect the trunk and destroy it, similar to what is done int
|
---|
| 5452 | * intnetR0NetworkDestruct.
|
---|
| 5453 | */
|
---|
[52394] | 5454 | pIfPort->pfnSetState(pIfPort, INTNETTRUNKIFSTATE_DISCONNECTING);
|
---|
[52134] | 5455 |
|
---|
| 5456 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
| 5457 | pNetwork->MacTab.pTrunk = NULL;
|
---|
[52618] | 5458 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[52134] | 5459 |
|
---|
[74484] | 5460 | /*
|
---|
| 5461 | * Create a system thread that will attempt to re-connect this trunk periodically
|
---|
| 5462 | * hoping that the corresponding filter module reappears in the system. The thread
|
---|
| 5463 | * will go away if it succeeds in re-connecting the trunk or if it is signalled.
|
---|
| 5464 | */
|
---|
| 5465 | int rc = RTThreadCreate(&pNetwork->hTrunkReconnectThread, intnetR0TrunkReconnectThread, pNetwork,
|
---|
| 5466 | 0, RTTHREADTYPE_INFREQUENT_POLLER, RTTHREADFLAGS_WAITABLE, "TRNKRECON");
|
---|
| 5467 | AssertRC(rc);
|
---|
| 5468 |
|
---|
[52134] | 5469 | intnetR0TrunkIfDestroy(pThis, pNetwork);
|
---|
| 5470 | }
|
---|
| 5471 |
|
---|
[52393] | 5472 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
[52134] | 5473 | }
|
---|
[52394] | 5474 | /*
|
---|
| 5475 | * We must always release the busy reference.
|
---|
| 5476 | */
|
---|
[65698] | 5477 | else if (pfnReleaseBusy)
|
---|
[52394] | 5478 | pfnReleaseBusy(pIfPort);
|
---|
[52134] | 5479 | }
|
---|
| 5480 |
|
---|
| 5481 |
|
---|
[62956] | 5482 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnPreRecv} */
|
---|
[28208] | 5483 | static DECLCALLBACK(INTNETSWDECISION) intnetR0TrunkIfPortPreRecv(PINTNETTRUNKSWPORT pSwitchPort,
|
---|
| 5484 | void const *pvSrc, size_t cbSrc, uint32_t fSrc)
|
---|
| 5485 | {
|
---|
| 5486 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5487 |
|
---|
| 5488 | /* assert some sanity */
|
---|
| 5489 | AssertPtr(pvSrc);
|
---|
[30557] | 5490 | AssertReturn(cbSrc >= 6, INTNETSWDECISION_BROADCAST);
|
---|
[28208] | 5491 | Assert(fSrc);
|
---|
| 5492 |
|
---|
[30557] | 5493 | /*
|
---|
| 5494 | * Mark the trunk as busy, make sure we've got a network and that there are
|
---|
| 5495 | * some active interfaces around.
|
---|
| 5496 | */
|
---|
| 5497 | INTNETSWDECISION enmSwDecision = INTNETSWDECISION_TRUNK;
|
---|
| 5498 | intnetR0BusyIncTrunk(pThis);
|
---|
| 5499 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
| 5500 | if (RT_LIKELY( pNetwork
|
---|
| 5501 | && pNetwork->cActiveIFs > 0 ))
|
---|
| 5502 | {
|
---|
| 5503 | /*
|
---|
| 5504 | * Lazy bird! No pre-switching of multicast and shared-MAC-on-wire.
|
---|
| 5505 | */
|
---|
| 5506 | PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pvSrc;
|
---|
| 5507 | if (intnetR0IsMacAddrMulticast(&pEthHdr->DstMac))
|
---|
| 5508 | enmSwDecision = INTNETSWDECISION_BROADCAST;
|
---|
[54132] | 5509 | else if ( fSrc == INTNETTRUNKDIR_WIRE
|
---|
| 5510 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE))
|
---|
[30557] | 5511 | enmSwDecision = INTNETSWDECISION_BROADCAST;
|
---|
| 5512 | else
|
---|
| 5513 | enmSwDecision = intnetR0NetworkPreSwitchUnicast(pNetwork,
|
---|
| 5514 | fSrc,
|
---|
| 5515 | cbSrc >= 12 ? &pEthHdr->SrcMac : NULL,
|
---|
| 5516 | &pEthHdr->DstMac);
|
---|
| 5517 | }
|
---|
[28208] | 5518 |
|
---|
[30557] | 5519 | intnetR0BusyDecTrunk(pThis);
|
---|
| 5520 | return enmSwDecision;
|
---|
[28208] | 5521 | }
|
---|
| 5522 |
|
---|
| 5523 |
|
---|
[62956] | 5524 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnRecv} */
|
---|
[29662] | 5525 | static DECLCALLBACK(bool) intnetR0TrunkIfPortRecv(PINTNETTRUNKSWPORT pSwitchPort, void *pvIf, PINTNETSG pSG, uint32_t fSrc)
|
---|
[10663] | 5526 | {
|
---|
[10681] | 5527 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5528 |
|
---|
| 5529 | /* assert some sanity */
|
---|
| 5530 | AssertPtr(pSG);
|
---|
| 5531 | Assert(fSrc);
|
---|
[29662] | 5532 | NOREF(pvIf); /* later */
|
---|
[10681] | 5533 |
|
---|
| 5534 | /*
|
---|
[28623] | 5535 | * Mark the trunk as busy, make sure we've got a network and that there are
|
---|
| 5536 | * some active interfaces around.
|
---|
[10681] | 5537 | */
|
---|
[28623] | 5538 | bool fRc = false /* don't drop it */;
|
---|
| 5539 | intnetR0BusyIncTrunk(pThis);
|
---|
| 5540 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
| 5541 | if (RT_LIKELY( pNetwork
|
---|
| 5542 | && pNetwork->cActiveIFs > 0 ))
|
---|
| 5543 | {
|
---|
| 5544 | /*
|
---|
| 5545 | * Grab or allocate a destination table.
|
---|
| 5546 | */
|
---|
| 5547 | bool const fIntCtx = RTThreadPreemptIsEnabled(NIL_RTTHREAD) || RTThreadIsInInterrupt(NIL_RTTHREAD);
|
---|
| 5548 | unsigned iDstTab = 0;
|
---|
| 5549 | PINTNETDSTTAB pDstTab = NULL;
|
---|
[40806] | 5550 | RTSpinlockAcquire(pThis->hDstTabSpinlock);
|
---|
[28623] | 5551 | if (fIntCtx)
|
---|
| 5552 | {
|
---|
| 5553 | /* Interrupt or restricted context. */
|
---|
| 5554 | iDstTab = RTMpCpuIdToSetIndex(RTMpCpuId());
|
---|
| 5555 | iDstTab %= pThis->cIntDstTabs;
|
---|
| 5556 | pDstTab = pThis->apIntDstTabs[iDstTab];
|
---|
| 5557 | if (RT_LIKELY(pDstTab))
|
---|
| 5558 | pThis->apIntDstTabs[iDstTab] = NULL;
|
---|
| 5559 | else
|
---|
| 5560 | {
|
---|
| 5561 | iDstTab = pThis->cIntDstTabs;
|
---|
| 5562 | while (iDstTab-- > 0)
|
---|
| 5563 | {
|
---|
| 5564 | pDstTab = pThis->apIntDstTabs[iDstTab];
|
---|
| 5565 | if (pDstTab)
|
---|
| 5566 | {
|
---|
| 5567 | pThis->apIntDstTabs[iDstTab] = NULL;
|
---|
| 5568 | break;
|
---|
| 5569 | }
|
---|
| 5570 | }
|
---|
| 5571 | }
|
---|
[52618] | 5572 | RTSpinlockRelease(pThis->hDstTabSpinlock);
|
---|
[28623] | 5573 | Assert(!pDstTab || iDstTab < pThis->cIntDstTabs);
|
---|
| 5574 | }
|
---|
| 5575 | else
|
---|
| 5576 | {
|
---|
| 5577 | /* Task context, fallback is to allocate a table. */
|
---|
| 5578 | AssertCompile(RT_ELEMENTS(pThis->apTaskDstTabs) == 2); /* for loop rollout */
|
---|
| 5579 | pDstTab = pThis->apIntDstTabs[iDstTab = 0];
|
---|
| 5580 | if (!pDstTab)
|
---|
| 5581 | pDstTab = pThis->apIntDstTabs[iDstTab = 1];
|
---|
| 5582 | if (pDstTab)
|
---|
| 5583 | {
|
---|
| 5584 | pThis->apIntDstTabs[iDstTab] = NULL;
|
---|
[52618] | 5585 | RTSpinlockRelease(pThis->hDstTabSpinlock);
|
---|
[28623] | 5586 | Assert(iDstTab < RT_ELEMENTS(pThis->apTaskDstTabs));
|
---|
| 5587 | }
|
---|
| 5588 | else
|
---|
| 5589 | {
|
---|
[52618] | 5590 | RTSpinlockRelease(pThis->hDstTabSpinlock);
|
---|
[28623] | 5591 | intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pDstTab);
|
---|
| 5592 | iDstTab = 65535;
|
---|
| 5593 | }
|
---|
| 5594 | }
|
---|
| 5595 | if (RT_LIKELY(pDstTab))
|
---|
| 5596 | {
|
---|
| 5597 | /*
|
---|
| 5598 | * Finally, get down to business of sending the frame.
|
---|
| 5599 | */
|
---|
| 5600 | INTNETSWDECISION enmSwDecision = intnetR0NetworkSend(pNetwork, NULL, fSrc, pSG, pDstTab);
|
---|
[28699] | 5601 | AssertMsg(enmSwDecision != INTNETSWDECISION_BAD_CONTEXT, ("fSrc=%#x fTrunkDst=%#x hdr=%.14Rhxs\n", fSrc, pDstTab->fTrunkDst, pSG->aSegs[0].pv));
|
---|
[28623] | 5602 | if (enmSwDecision == INTNETSWDECISION_INTNET)
|
---|
| 5603 | fRc = true; /* drop it */
|
---|
[10681] | 5604 |
|
---|
[28623] | 5605 | /*
|
---|
| 5606 | * Free the destination table.
|
---|
| 5607 | */
|
---|
| 5608 | if (iDstTab == 65535)
|
---|
| 5609 | RTMemFree(pDstTab);
|
---|
| 5610 | else
|
---|
| 5611 | {
|
---|
[40806] | 5612 | RTSpinlockAcquire(pThis->hDstTabSpinlock);
|
---|
[28623] | 5613 | if (fIntCtx && !pThis->apIntDstTabs[iDstTab])
|
---|
| 5614 | pThis->apIntDstTabs[iDstTab] = pDstTab;
|
---|
| 5615 | else if (!fIntCtx && !pThis->apTaskDstTabs[iDstTab])
|
---|
| 5616 | pThis->apTaskDstTabs[iDstTab] = pDstTab;
|
---|
| 5617 | else
|
---|
| 5618 | {
|
---|
| 5619 | /* this shouldn't happen! */
|
---|
| 5620 | PINTNETDSTTAB *papDstTabs = fIntCtx ? &pThis->apIntDstTabs[0] : &pThis->apTaskDstTabs[0];
|
---|
| 5621 | iDstTab = fIntCtx ? pThis->cIntDstTabs : RT_ELEMENTS(pThis->apTaskDstTabs);
|
---|
| 5622 | while (iDstTab-- > 0)
|
---|
| 5623 | if (!papDstTabs[iDstTab])
|
---|
| 5624 | {
|
---|
| 5625 | papDstTabs[iDstTab] = pDstTab;
|
---|
| 5626 | break;
|
---|
| 5627 | }
|
---|
| 5628 | }
|
---|
[52618] | 5629 | RTSpinlockRelease(pThis->hDstTabSpinlock);
|
---|
[28623] | 5630 | Assert(iDstTab < RT_MAX(RT_ELEMENTS(pThis->apTaskDstTabs), pThis->cIntDstTabs));
|
---|
| 5631 | }
|
---|
| 5632 | }
|
---|
| 5633 | }
|
---|
[10681] | 5634 |
|
---|
[28623] | 5635 | intnetR0BusyDecTrunk(pThis);
|
---|
[10733] | 5636 | return fRc;
|
---|
[10663] | 5637 | }
|
---|
| 5638 |
|
---|
| 5639 |
|
---|
[62956] | 5640 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnSGRetain} */
|
---|
[25336] | 5641 | static DECLCALLBACK(void) intnetR0TrunkIfPortSGRetain(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
|
---|
[10663] | 5642 | {
|
---|
[10681] | 5643 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5644 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
[10663] | 5645 |
|
---|
[10681] | 5646 | /* assert some sanity */
|
---|
| 5647 | AssertPtrReturnVoid(pNetwork);
|
---|
[28623] | 5648 | AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT);
|
---|
[10681] | 5649 | AssertPtr(pSG);
|
---|
[28025] | 5650 | Assert(pSG->cUsers > 0 && pSG->cUsers < 256);
|
---|
[10681] | 5651 |
|
---|
| 5652 | /* do it. */
|
---|
| 5653 | ++pSG->cUsers;
|
---|
[10663] | 5654 | }
|
---|
| 5655 |
|
---|
| 5656 |
|
---|
[62956] | 5657 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnSGRelease} */
|
---|
[25336] | 5658 | static DECLCALLBACK(void) intnetR0TrunkIfPortSGRelease(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)
|
---|
[10663] | 5659 | {
|
---|
[10681] | 5660 | PINTNETTRUNKIF pThis = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5661 | PINTNETNETWORK pNetwork = pThis->pNetwork;
|
---|
[10663] | 5662 |
|
---|
[10681] | 5663 | /* assert some sanity */
|
---|
| 5664 | AssertPtrReturnVoid(pNetwork);
|
---|
[28623] | 5665 | AssertReturnVoid(pNetwork->hEvtBusyIf != NIL_RTSEMEVENT);
|
---|
[10681] | 5666 | AssertPtr(pSG);
|
---|
| 5667 | Assert(pSG->cUsers > 0);
|
---|
| 5668 |
|
---|
| 5669 | /*
|
---|
| 5670 | * Free it?
|
---|
| 5671 | */
|
---|
| 5672 | if (!--pSG->cUsers)
|
---|
| 5673 | {
|
---|
| 5674 | /** @todo later */
|
---|
| 5675 | }
|
---|
[10663] | 5676 | }
|
---|
| 5677 |
|
---|
| 5678 |
|
---|
[62956] | 5679 | /** @interface_method_impl{INTNETTRUNKSWPORT,pfnNotifyHostAddress} */
|
---|
[55652] | 5680 | static DECLCALLBACK(void) intnetR0NetworkNotifyHostAddress(PINTNETTRUNKSWPORT pSwitchPort,
|
---|
| 5681 | bool fAdded,
|
---|
| 5682 | INTNETADDRTYPE enmType, const void *pvAddr)
|
---|
| 5683 | {
|
---|
| 5684 | PINTNETTRUNKIF pTrunkIf = INTNET_SWITCHPORT_2_TRUNKIF(pSwitchPort);
|
---|
| 5685 | PINTNETNETWORK pNetwork = pTrunkIf->pNetwork;
|
---|
| 5686 | PCRTNETADDRU pAddr = (PCRTNETADDRU)pvAddr;
|
---|
| 5687 | uint8_t cbAddr;
|
---|
| 5688 |
|
---|
| 5689 | if (enmType == kIntNetAddrType_IPv4)
|
---|
| 5690 | {
|
---|
| 5691 | Log(("%s: %s %RTnaipv4\n",
|
---|
| 5692 | __FUNCTION__, (fAdded ? "add" : "del"),
|
---|
| 5693 | pAddr->IPv4));
|
---|
| 5694 | cbAddr = 4;
|
---|
| 5695 | }
|
---|
| 5696 | else if (enmType == kIntNetAddrType_IPv6)
|
---|
| 5697 | {
|
---|
| 5698 | Log(("%s: %s %RTnaipv6\n",
|
---|
| 5699 | __FUNCTION__, (fAdded ? "add" : "del"),
|
---|
| 5700 | pAddr));
|
---|
| 5701 | cbAddr = 16;
|
---|
| 5702 | }
|
---|
| 5703 | else
|
---|
| 5704 | {
|
---|
| 5705 | Log(("%s: unexpected address type %d\n", __FUNCTION__, enmType));
|
---|
| 5706 | return;
|
---|
| 5707 | }
|
---|
| 5708 |
|
---|
| 5709 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
| 5710 | if (fAdded) /* one of host interfaces got a new address */
|
---|
| 5711 | {
|
---|
| 5712 | /* blacklist it to prevent spoofing by guests */
|
---|
| 5713 | intnetR0NetworkBlacklistAdd(pNetwork, pAddr, enmType);
|
---|
| 5714 |
|
---|
| 5715 | /* kick out any guest that uses it */
|
---|
[56146] | 5716 | intnetR0NetworkAddrCacheDeleteLocked(pNetwork, pAddr, enmType, cbAddr, "tif/host");
|
---|
[55652] | 5717 | }
|
---|
| 5718 | else /* address deleted from one of host interfaces */
|
---|
| 5719 | {
|
---|
| 5720 | /* stop blacklisting it, guests may use it now */
|
---|
| 5721 | intnetR0NetworkBlacklistDelete(pNetwork, pAddr, enmType);
|
---|
| 5722 | }
|
---|
| 5723 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
| 5724 | }
|
---|
| 5725 |
|
---|
| 5726 |
|
---|
[1] | 5727 | /**
|
---|
[10681] | 5728 | * Shutdown the trunk interface.
|
---|
| 5729 | *
|
---|
| 5730 | * @param pThis The trunk.
|
---|
| 5731 | * @param pNetworks The network.
|
---|
| 5732 | *
|
---|
[28831] | 5733 | * @remarks The caller must hold the global lock.
|
---|
[10681] | 5734 | */
|
---|
[10711] | 5735 | static void intnetR0TrunkIfDestroy(PINTNETTRUNKIF pThis, PINTNETNETWORK pNetwork)
|
---|
[10681] | 5736 | {
|
---|
| 5737 | /* assert sanity */
|
---|
| 5738 | if (!pThis)
|
---|
| 5739 | return;
|
---|
| 5740 | AssertPtr(pThis);
|
---|
| 5741 | Assert(pThis->pNetwork == pNetwork);
|
---|
| 5742 | AssertPtrNull(pThis->pIfPort);
|
---|
| 5743 |
|
---|
| 5744 | /*
|
---|
| 5745 | * The interface has already been deactivated, we just to wait for
|
---|
| 5746 | * it to become idle before we can disconnect and release it.
|
---|
| 5747 | */
|
---|
| 5748 | PINTNETTRUNKIFPORT pIfPort = pThis->pIfPort;
|
---|
| 5749 | if (pIfPort)
|
---|
| 5750 | {
|
---|
| 5751 | /* unset it */
|
---|
| 5752 | pThis->pIfPort = NULL;
|
---|
| 5753 |
|
---|
[52393] | 5754 | /* wait in portions so we can complain every now an then. */
|
---|
[10681] | 5755 | uint64_t StartTS = RTTimeSystemNanoTS();
|
---|
| 5756 | int rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
|
---|
| 5757 | if (RT_FAILURE(rc))
|
---|
| 5758 | {
|
---|
[33595] | 5759 | LogRel(("intnet: '%s' didn't become idle in %RU64 ns (%Rrc).\n",
|
---|
[10681] | 5760 | pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
|
---|
| 5761 | Assert(rc == VERR_TIMEOUT);
|
---|
| 5762 | while ( RT_FAILURE(rc)
|
---|
| 5763 | && RTTimeSystemNanoTS() - StartTS < UINT64_C(30000000000)) /* 30 sec */
|
---|
| 5764 | rc = pIfPort->pfnWaitForIdle(pIfPort, 10*1000);
|
---|
| 5765 | if (rc == VERR_TIMEOUT)
|
---|
| 5766 | {
|
---|
[33595] | 5767 | LogRel(("intnet: '%s' didn't become idle in %RU64 ns (%Rrc).\n",
|
---|
[10681] | 5768 | pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
|
---|
| 5769 | while ( rc == VERR_TIMEOUT
|
---|
| 5770 | && RTTimeSystemNanoTS() - StartTS < UINT64_C(360000000000)) /* 360 sec */
|
---|
| 5771 | rc = pIfPort->pfnWaitForIdle(pIfPort, 30*1000);
|
---|
| 5772 | if (RT_FAILURE(rc))
|
---|
| 5773 | {
|
---|
[33595] | 5774 | LogRel(("intnet: '%s' didn't become idle in %RU64 ns (%Rrc), giving up.\n",
|
---|
[10681] | 5775 | pNetwork->szName, RTTimeSystemNanoTS() - StartTS, rc));
|
---|
| 5776 | AssertRC(rc);
|
---|
| 5777 | }
|
---|
| 5778 | }
|
---|
| 5779 | }
|
---|
| 5780 |
|
---|
| 5781 | /* disconnect & release it. */
|
---|
| 5782 | pIfPort->pfnDisconnectAndRelease(pIfPort);
|
---|
| 5783 | }
|
---|
| 5784 |
|
---|
| 5785 | /*
|
---|
| 5786 | * Free up the resources.
|
---|
| 5787 | */
|
---|
[52393] | 5788 | pThis->pNetwork = NULL; /* Must not be cleared while busy, see intnetR0TrunkIfPortDisconnect. */
|
---|
[28623] | 5789 | RTSpinlockDestroy(pThis->hDstTabSpinlock);
|
---|
| 5790 | for (unsigned i = 0; i < RT_ELEMENTS(pThis->apTaskDstTabs); i++)
|
---|
| 5791 | {
|
---|
| 5792 | Assert(pThis->apTaskDstTabs[i]);
|
---|
| 5793 | RTMemFree(pThis->apTaskDstTabs[i]);
|
---|
| 5794 | pThis->apTaskDstTabs[i] = NULL;
|
---|
| 5795 | }
|
---|
| 5796 | for (unsigned i = 0; i < pThis->cIntDstTabs; i++)
|
---|
| 5797 | {
|
---|
| 5798 | Assert(pThis->apIntDstTabs[i]);
|
---|
| 5799 | RTMemFree(pThis->apIntDstTabs[i]);
|
---|
| 5800 | pThis->apIntDstTabs[i] = NULL;
|
---|
| 5801 | }
|
---|
[10681] | 5802 | RTMemFree(pThis);
|
---|
| 5803 | }
|
---|
| 5804 |
|
---|
| 5805 |
|
---|
| 5806 | /**
|
---|
[10557] | 5807 | * Creates the trunk connection (if any).
|
---|
| 5808 | *
|
---|
| 5809 | * @returns VBox status code.
|
---|
| 5810 | *
|
---|
| 5811 | * @param pNetwork The newly created network.
|
---|
| 5812 | * @param pSession The session handle.
|
---|
| 5813 | */
|
---|
[10711] | 5814 | static int intnetR0NetworkCreateTrunkIf(PINTNETNETWORK pNetwork, PSUPDRVSESSION pSession)
|
---|
[10557] | 5815 | {
|
---|
[10559] | 5816 | const char *pszName;
|
---|
[10557] | 5817 | switch (pNetwork->enmTrunkType)
|
---|
| 5818 | {
|
---|
| 5819 | /*
|
---|
| 5820 | * The 'None' case, simple.
|
---|
| 5821 | */
|
---|
| 5822 | case kIntNetTrunkType_None:
|
---|
| 5823 | case kIntNetTrunkType_WhateverNone:
|
---|
[44824] | 5824 | #ifdef VBOX_WITH_NAT_SERVICE
|
---|
[48947] | 5825 | /*
|
---|
[45356] | 5826 | * Well, here we don't want load anything special,
|
---|
[48947] | 5827 | * just communicate between processes via internal network.
|
---|
[45356] | 5828 | */
|
---|
| 5829 | case kIntNetTrunkType_SrvNat:
|
---|
[44824] | 5830 | #endif
|
---|
[10557] | 5831 | return VINF_SUCCESS;
|
---|
[10663] | 5832 |
|
---|
| 5833 | /* Can't happen, but makes GCC happy. */
|
---|
[10557] | 5834 | default:
|
---|
| 5835 | return VERR_NOT_IMPLEMENTED;
|
---|
| 5836 |
|
---|
[10663] | 5837 | /*
|
---|
| 5838 | * Translate enum to component factory name.
|
---|
| 5839 | */
|
---|
[10557] | 5840 | case kIntNetTrunkType_NetFlt:
|
---|
[10559] | 5841 | pszName = "VBoxNetFlt";
|
---|
[10557] | 5842 | break;
|
---|
[16750] | 5843 | case kIntNetTrunkType_NetAdp:
|
---|
[17256] | 5844 | #if defined(RT_OS_DARWIN) && !defined(VBOXNETADP_DO_NOT_USE_NETFLT)
|
---|
| 5845 | pszName = "VBoxNetFlt";
|
---|
| 5846 | #else /* VBOXNETADP_DO_NOT_USE_NETFLT */
|
---|
[16750] | 5847 | pszName = "VBoxNetAdp";
|
---|
[17256] | 5848 | #endif /* VBOXNETADP_DO_NOT_USE_NETFLT */
|
---|
[10557] | 5849 | break;
|
---|
[48947] | 5850 | #ifndef VBOX_WITH_NAT_SERVICE
|
---|
[45356] | 5851 | case kIntNetTrunkType_SrvNat:
|
---|
| 5852 | pszName = "VBoxSrvNat";
|
---|
[10557] | 5853 | break;
|
---|
[44824] | 5854 | #endif
|
---|
[10557] | 5855 | }
|
---|
| 5856 |
|
---|
| 5857 | /*
|
---|
[28623] | 5858 | * Allocate the trunk interface and associated destination tables.
|
---|
| 5859 | *
|
---|
| 5860 | * We take a very optimistic view on the parallelism of the host
|
---|
| 5861 | * network stack and NIC driver. So, we allocate one table for each
|
---|
| 5862 | * possible CPU to deal with interrupt time requests and one for task
|
---|
| 5863 | * time calls.
|
---|
[10557] | 5864 | */
|
---|
[28623] | 5865 | RTCPUID cCpus = RTMpGetCount(); Assert(cCpus > 0);
|
---|
[73097] | 5866 | PINTNETTRUNKIF pTrunk = (PINTNETTRUNKIF)RTMemAllocZ(RT_UOFFSETOF_DYN(INTNETTRUNKIF, apIntDstTabs[cCpus]));
|
---|
[28623] | 5867 | if (!pTrunk)
|
---|
[10559] | 5868 | return VERR_NO_MEMORY;
|
---|
[28623] | 5869 |
|
---|
| 5870 | Assert(pNetwork->MacTab.cEntriesAllocated > 0);
|
---|
| 5871 | int rc = VINF_SUCCESS;
|
---|
| 5872 | pTrunk->cIntDstTabs = cCpus;
|
---|
| 5873 | for (unsigned i = 0; i < cCpus && RT_SUCCESS(rc); i++)
|
---|
| 5874 | rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apIntDstTabs[i]);
|
---|
| 5875 | for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs) && RT_SUCCESS(rc); i++)
|
---|
| 5876 | rc = intnetR0AllocDstTab(pNetwork->MacTab.cEntriesAllocated, &pTrunk->apTaskDstTabs[i]);
|
---|
| 5877 |
|
---|
[10559] | 5878 | if (RT_SUCCESS(rc))
|
---|
| 5879 | {
|
---|
[28623] | 5880 | pTrunk->SwitchPort.u32Version = INTNETTRUNKSWPORT_VERSION;
|
---|
| 5881 | pTrunk->SwitchPort.pfnPreRecv = intnetR0TrunkIfPortPreRecv;
|
---|
| 5882 | pTrunk->SwitchPort.pfnRecv = intnetR0TrunkIfPortRecv;
|
---|
| 5883 | pTrunk->SwitchPort.pfnSGRetain = intnetR0TrunkIfPortSGRetain;
|
---|
| 5884 | pTrunk->SwitchPort.pfnSGRelease = intnetR0TrunkIfPortSGRelease;
|
---|
| 5885 | pTrunk->SwitchPort.pfnSetSGPhys = intnetR0TrunkIfPortSetSGPhys;
|
---|
[28666] | 5886 | pTrunk->SwitchPort.pfnReportMacAddress = intnetR0TrunkIfPortReportMacAddress;
|
---|
| 5887 | pTrunk->SwitchPort.pfnReportPromiscuousMode = intnetR0TrunkIfPortReportPromiscuousMode;
|
---|
[28623] | 5888 | pTrunk->SwitchPort.pfnReportGsoCapabilities = intnetR0TrunkIfPortReportGsoCapabilities;
|
---|
[28723] | 5889 | pTrunk->SwitchPort.pfnReportNoPreemptDsts = intnetR0TrunkIfPortReportNoPreemptDsts;
|
---|
[55652] | 5890 | if (pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
| 5891 | pTrunk->SwitchPort.pfnNotifyHostAddress = intnetR0NetworkNotifyHostAddress;
|
---|
[52134] | 5892 | pTrunk->SwitchPort.pfnDisconnect = intnetR0TrunkIfPortDisconnect;
|
---|
[28623] | 5893 | pTrunk->SwitchPort.u32VersionEnd = INTNETTRUNKSWPORT_VERSION;
|
---|
| 5894 | //pTrunk->pIfPort = NULL;
|
---|
| 5895 | pTrunk->pNetwork = pNetwork;
|
---|
| 5896 | pTrunk->MacAddr.au8[0] = 0xff;
|
---|
| 5897 | pTrunk->MacAddr.au8[1] = 0xff;
|
---|
| 5898 | pTrunk->MacAddr.au8[2] = 0xff;
|
---|
| 5899 | pTrunk->MacAddr.au8[3] = 0xff;
|
---|
| 5900 | pTrunk->MacAddr.au8[4] = 0xff;
|
---|
| 5901 | pTrunk->MacAddr.au8[5] = 0xff;
|
---|
| 5902 | //pTrunk->fPhysSG = false;
|
---|
[28722] | 5903 | //pTrunk->fUnused = false;
|
---|
[28623] | 5904 | //pTrunk->cBusy = 0;
|
---|
[28722] | 5905 | //pTrunk->fNoPreemptDsts = 0;
|
---|
[28623] | 5906 | //pTrunk->fWireGsoCapabilites = 0;
|
---|
| 5907 | //pTrunk->fHostGsoCapabilites = 0;
|
---|
| 5908 | //pTrunk->abGsoHdrs = {0};
|
---|
| 5909 | pTrunk->hDstTabSpinlock = NIL_RTSPINLOCK;
|
---|
| 5910 | //pTrunk->apTaskDstTabs = above;
|
---|
| 5911 | //pTrunk->cIntDstTabs = above;
|
---|
| 5912 | //pTrunk->apIntDstTabs = above;
|
---|
| 5913 |
|
---|
[10559] | 5914 | /*
|
---|
[28831] | 5915 | * Create the lock (we've NIL'ed the members above to simplify cleanup).
|
---|
[10559] | 5916 | */
|
---|
[40806] | 5917 | rc = RTSpinlockCreate(&pTrunk->hDstTabSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "hDstTabSpinlock");
|
---|
[10559] | 5918 | if (RT_SUCCESS(rc))
|
---|
| 5919 | {
|
---|
[28666] | 5920 | /*
|
---|
| 5921 | * There are a couple of bits in MacTab as well pertaining to the
|
---|
| 5922 | * trunk. We have to set this before it's reported.
|
---|
| 5923 | *
|
---|
| 5924 | * Note! We don't need to lock the MacTab here - creation time.
|
---|
| 5925 | */
|
---|
[36075] | 5926 | pNetwork->MacTab.pTrunk = pTrunk;
|
---|
| 5927 | pNetwork->MacTab.HostMac = pTrunk->MacAddr;
|
---|
| 5928 | pNetwork->MacTab.fHostPromiscuousReal = false;
|
---|
| 5929 | pNetwork->MacTab.fHostPromiscuousEff = (pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE)
|
---|
| 5930 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST);
|
---|
| 5931 | pNetwork->MacTab.fHostActive = false;
|
---|
[36077] | 5932 | pNetwork->MacTab.fWirePromiscuousReal = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE);
|
---|
[36075] | 5933 | pNetwork->MacTab.fWirePromiscuousEff = pNetwork->MacTab.fWirePromiscuousReal
|
---|
| 5934 | && (pNetwork->fFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE);
|
---|
| 5935 | pNetwork->MacTab.fWireActive = false;
|
---|
[28666] | 5936 |
|
---|
[28623] | 5937 | #ifdef IN_RING0 /* (testcase is ring-3) */
|
---|
| 5938 | /*
|
---|
| 5939 | * Query the factory we want, then use it create and connect the trunk.
|
---|
| 5940 | */
|
---|
| 5941 | PINTNETTRUNKFACTORY pTrunkFactory = NULL;
|
---|
| 5942 | rc = SUPR0ComponentQueryFactory(pSession, pszName, INTNETTRUNKFACTORY_UUID_STR, (void **)&pTrunkFactory);
|
---|
[10559] | 5943 | if (RT_SUCCESS(rc))
|
---|
| 5944 | {
|
---|
[28666] | 5945 | rc = pTrunkFactory->pfnCreateAndConnect(pTrunkFactory,
|
---|
| 5946 | pNetwork->szTrunk,
|
---|
| 5947 | &pTrunk->SwitchPort,
|
---|
[28623] | 5948 | pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE
|
---|
[28666] | 5949 | ? INTNETTRUNKFACTORY_FLAG_NO_PROMISC
|
---|
| 5950 | : 0,
|
---|
[28623] | 5951 | &pTrunk->pIfPort);
|
---|
| 5952 | pTrunkFactory->pfnRelease(pTrunkFactory);
|
---|
| 5953 | if (RT_SUCCESS(rc))
|
---|
| 5954 | {
|
---|
| 5955 | Assert(pTrunk->pIfPort);
|
---|
| 5956 |
|
---|
| 5957 | Log(("intnetR0NetworkCreateTrunkIf: VINF_SUCCESS - pszName=%s szTrunk=%s%s Network=%s\n",
|
---|
| 5958 | pszName, pNetwork->szTrunk, pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE ? " shared-mac" : "", pNetwork->szName));
|
---|
| 5959 | return VINF_SUCCESS;
|
---|
| 5960 | }
|
---|
[10559] | 5961 | }
|
---|
[28623] | 5962 | #else /* IN_RING3 */
|
---|
[39091] | 5963 | NOREF(pSession);
|
---|
[28623] | 5964 | rc = VERR_NOT_SUPPORTED;
|
---|
| 5965 | #endif /* IN_RING3 */
|
---|
[28666] | 5966 |
|
---|
| 5967 | pNetwork->MacTab.pTrunk = NULL;
|
---|
[10559] | 5968 | }
|
---|
[28623] | 5969 |
|
---|
| 5970 | /* bail out and clean up. */
|
---|
| 5971 | RTSpinlockDestroy(pTrunk->hDstTabSpinlock);
|
---|
[10559] | 5972 | }
|
---|
[28623] | 5973 |
|
---|
| 5974 | for (unsigned i = 0; i < RT_ELEMENTS(pTrunk->apTaskDstTabs); i++)
|
---|
| 5975 | RTMemFree(pTrunk->apTaskDstTabs[i]);
|
---|
| 5976 | for (unsigned i = 0; i < pTrunk->cIntDstTabs; i++)
|
---|
| 5977 | RTMemFree(pTrunk->apIntDstTabs[i]);
|
---|
| 5978 | RTMemFree(pTrunk);
|
---|
| 5979 |
|
---|
[10711] | 5980 | LogFlow(("intnetR0NetworkCreateTrunkIf: %Rrc - pszName=%s szTrunk=%s Network=%s\n",
|
---|
[10559] | 5981 | rc, pszName, pNetwork->szTrunk, pNetwork->szName));
|
---|
| 5982 | return rc;
|
---|
[10557] | 5983 | }
|
---|
| 5984 |
|
---|
| 5985 |
|
---|
[74484] | 5986 | /**
|
---|
| 5987 | * Trunk reconnection thread function. It runs until signalled by another thread or by itself (upon
|
---|
| 5988 | * successful trunk re-connection).
|
---|
[74506] | 5989 | *
|
---|
[74484] | 5990 | * Note that this function erases pNetwork->hTrunkReconnectThread right before it terminates!
|
---|
| 5991 | */
|
---|
| 5992 | static DECLCALLBACK(int) intnetR0TrunkReconnectThread(RTTHREAD hThread, void *pvUser)
|
---|
| 5993 | {
|
---|
| 5994 | RT_NOREF1(hThread);
|
---|
| 5995 | PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser;
|
---|
| 5996 | PINTNET pIntNet = pNetwork->pIntNet;
|
---|
| 5997 | Assert(pNetwork->pIntNet);
|
---|
[10663] | 5998 |
|
---|
[74484] | 5999 | /*
|
---|
| 6000 | * We attempt to reconnect the trunk every 5 seconds until somebody signals us.
|
---|
| 6001 | */
|
---|
| 6002 | while (!pNetwork->fTerminateReconnectThread && RTThreadUserWait(hThread, 5 * RT_MS_1SEC) == VERR_TIMEOUT)
|
---|
| 6003 | {
|
---|
| 6004 | /*
|
---|
| 6005 | * Make sure nobody else is modifying networks.
|
---|
| 6006 | * It is essential we give up on waiting for the big mutex much earlier than intnetR0NetworkDestruct
|
---|
| 6007 | * gives up on waiting for us to terminate! This is why we wait for 1 second while network destruction
|
---|
| 6008 | * code waits for 5 seconds. Otherwise the network may be already gone by the time we get the mutex.
|
---|
| 6009 | */
|
---|
| 6010 | if (RT_FAILURE(RTSemMutexRequestNoResume(pIntNet->hMtxCreateOpenDestroy, RT_MS_1SEC)))
|
---|
| 6011 | continue;
|
---|
| 6012 | #if 0
|
---|
| 6013 | /*
|
---|
| 6014 | * This thread should be long gone by the time the network has been destroyed, but if we are
|
---|
| 6015 | * really paranoid we should include the following code.
|
---|
| 6016 | */
|
---|
| 6017 | /*
|
---|
| 6018 | * The network could have been destroyed while we were waiting on the big mutex, let us verify
|
---|
| 6019 | * it is still valid by going over the list of existing networks.
|
---|
| 6020 | */
|
---|
| 6021 | PINTNETNETWORK pExistingNetwork = pIntNet->pNetworks;
|
---|
| 6022 | for (; pExistingNetwork; pExistingNetwork = pExistingNetwork->pNext)
|
---|
| 6023 | if (pExistingNetwork == pNetwork)
|
---|
| 6024 | break;
|
---|
| 6025 | /* We need the network to exist and to have at least one interface. */
|
---|
| 6026 | if (pExistingNetwork && pNetwork->MacTab.cEntries)
|
---|
| 6027 | #else
|
---|
| 6028 | /* We need the network to have at least one interface. */
|
---|
| 6029 | if (pNetwork->MacTab.cEntries)
|
---|
| 6030 | #endif
|
---|
| 6031 | {
|
---|
| 6032 | PINTNETIF pAnyIf = pNetwork->MacTab.paEntries[0].pIf;
|
---|
| 6033 | PSUPDRVSESSION pAnySession = pAnyIf ? pAnyIf->pSession : NULL;
|
---|
| 6034 | if (pAnySession)
|
---|
| 6035 | {
|
---|
| 6036 | /* Attempt to re-connect trunk and if successful, terminate thread. */
|
---|
| 6037 | if (RT_SUCCESS(intnetR0NetworkCreateTrunkIf(pNetwork, pAnySession)))
|
---|
| 6038 | {
|
---|
| 6039 | /* The network has active interfaces, we need to activate the trunk. */
|
---|
| 6040 | if (pNetwork->cActiveIFs)
|
---|
| 6041 | {
|
---|
| 6042 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 6043 | /* The intnetR0NetworkCreateTrunkIf call resets fHostActive and fWireActive. */
|
---|
| 6044 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
| 6045 | pNetwork->MacTab.fHostActive = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED);
|
---|
| 6046 | pNetwork->MacTab.fWireActive = RT_BOOL(pNetwork->fFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED);
|
---|
| 6047 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
| 6048 | pTrunk->pIfPort->pfnSetState(pTrunk->pIfPort, INTNETTRUNKIFSTATE_ACTIVE);
|
---|
| 6049 | }
|
---|
| 6050 | pNetwork->fTerminateReconnectThread = true;
|
---|
| 6051 | RTThreadUserSignal(hThread); /* Signal ourselves, so we break the loop after releasing the mutex */
|
---|
| 6052 | }
|
---|
| 6053 | }
|
---|
| 6054 | }
|
---|
| 6055 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
| 6056 | }
|
---|
| 6057 |
|
---|
| 6058 | /*
|
---|
| 6059 | * Destroy our handle in INTNETNETWORK so everyone knows we are gone.
|
---|
| 6060 | * Note that this is the only place where this handle gets wiped out.
|
---|
| 6061 | */
|
---|
| 6062 | pNetwork->hTrunkReconnectThread = NIL_RTTHREAD;
|
---|
| 6063 |
|
---|
| 6064 | return VINF_SUCCESS;
|
---|
| 6065 | }
|
---|
| 6066 |
|
---|
| 6067 |
|
---|
| 6068 |
|
---|
[10557] | 6069 | /**
|
---|
[1] | 6070 | * Object destructor callback.
|
---|
| 6071 | * This is called for reference counted objectes when the count reaches 0.
|
---|
| 6072 | *
|
---|
| 6073 | * @param pvObj The object pointer.
|
---|
| 6074 | * @param pvUser1 Pointer to the network.
|
---|
| 6075 | * @param pvUser2 Pointer to the INTNET instance data.
|
---|
| 6076 | */
|
---|
[10711] | 6077 | static DECLCALLBACK(void) intnetR0NetworkDestruct(void *pvObj, void *pvUser1, void *pvUser2)
|
---|
[1] | 6078 | {
|
---|
| 6079 | PINTNETNETWORK pNetwork = (PINTNETNETWORK)pvUser1;
|
---|
[28623] | 6080 | PINTNET pIntNet = (PINTNET)pvUser2;
|
---|
[10763] | 6081 | Log(("intnetR0NetworkDestruct: pvObj=%p pNetwork=%p pIntNet=%p %s\n", pvObj, pNetwork, pIntNet, pNetwork->szName));
|
---|
[1] | 6082 | Assert(pNetwork->pIntNet == pIntNet);
|
---|
[62628] | 6083 | RT_NOREF1(pvObj);
|
---|
[1] | 6084 |
|
---|
[28623] | 6085 | /* Take the big create/open/destroy sem. */
|
---|
[28488] | 6086 | RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
[10557] | 6087 |
|
---|
[10681] | 6088 | /*
|
---|
[28831] | 6089 | * Tell the trunk, if present, that we're about to disconnect it and wish
|
---|
| 6090 | * no further calls from it.
|
---|
[10681] | 6091 | */
|
---|
[28831] | 6092 | PINTNETTRUNKIF pTrunk = pNetwork->MacTab.pTrunk;
|
---|
| 6093 | if (pTrunk)
|
---|
| 6094 | pTrunk->pIfPort->pfnSetState(pTrunk->pIfPort, INTNETTRUNKIFSTATE_DISCONNECTING);
|
---|
[10557] | 6095 |
|
---|
[1] | 6096 | /*
|
---|
[28623] | 6097 | * Deactivate and orphan any remaining interfaces and wait for them to idle.
|
---|
| 6098 | *
|
---|
| 6099 | * Note! Normally there are no more interfaces at this point, however, when
|
---|
| 6100 | * supdrvCloseSession / supdrvCleanupSession release the objects the
|
---|
| 6101 | * order is undefined. So, it's quite possible that the network will
|
---|
| 6102 | * be dereference and destroyed before the interfaces.
|
---|
| 6103 | */
|
---|
[40806] | 6104 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6105 |
|
---|
| 6106 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 6107 | while (iIf-- > 0)
|
---|
| 6108 | {
|
---|
| 6109 | pNetwork->MacTab.paEntries[iIf].fActive = false;
|
---|
| 6110 | pNetwork->MacTab.paEntries[iIf].pIf->fActive = false;
|
---|
| 6111 | }
|
---|
| 6112 |
|
---|
| 6113 | pNetwork->MacTab.fHostActive = false;
|
---|
| 6114 | pNetwork->MacTab.fWireActive = false;
|
---|
| 6115 |
|
---|
[52618] | 6116 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6117 |
|
---|
| 6118 | /* Wait for all the interfaces to quiesce. (Interfaces cannot be
|
---|
| 6119 | removed / added since we're holding the big lock.) */
|
---|
[28831] | 6120 | if (pTrunk)
|
---|
| 6121 | intnetR0BusyWait(pNetwork, &pTrunk->cBusy);
|
---|
[74484] | 6122 | else if (pNetwork->hTrunkReconnectThread != NIL_RTTHREAD)
|
---|
| 6123 | {
|
---|
| 6124 | /*
|
---|
| 6125 | * There is no trunk and we have the trunk reconnection thread running.
|
---|
| 6126 | * Signal the thread and wait for it to terminate.
|
---|
| 6127 | */
|
---|
| 6128 | pNetwork->fTerminateReconnectThread = true;
|
---|
| 6129 | RTThreadUserSignal(pNetwork->hTrunkReconnectThread);
|
---|
| 6130 | /*
|
---|
| 6131 | * The tread cannot be re-connecting the trunk at the moment since we hold the big
|
---|
| 6132 | * mutex, thus 5 second wait is definitely enough. Note that the wait time must
|
---|
| 6133 | * exceed the time the reconnection thread waits on acquiring the big mutex, otherwise
|
---|
| 6134 | * we will give up waiting for thread termination prematurely. Unfortunately it seems
|
---|
| 6135 | * we have no way to terminate the thread if it failed to stop gracefully.
|
---|
[74496] | 6136 | *
|
---|
[74484] | 6137 | * Note that it is ok if the thread has already wiped out hTrunkReconnectThread by now,
|
---|
| 6138 | * this means we no longer need to wait for it.
|
---|
| 6139 | */
|
---|
| 6140 | RTThreadWait(pNetwork->hTrunkReconnectThread, 5 * RT_MS_1SEC, NULL);
|
---|
| 6141 | }
|
---|
[28623] | 6142 |
|
---|
| 6143 | iIf = pNetwork->MacTab.cEntries;
|
---|
| 6144 | while (iIf-- > 0)
|
---|
| 6145 | intnetR0BusyWait(pNetwork, &pNetwork->MacTab.paEntries[iIf].pIf->cBusy);
|
---|
| 6146 |
|
---|
[29635] | 6147 | /* Orphan the interfaces (not trunk). Don't bother with calling
|
---|
| 6148 | pfnDisconnectInterface here since the networking is going away. */
|
---|
[40806] | 6149 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6150 | while ((iIf = pNetwork->MacTab.cEntries) > 0)
|
---|
| 6151 | {
|
---|
| 6152 | PINTNETIF pIf = pNetwork->MacTab.paEntries[iIf - 1].pIf;
|
---|
[40806] | 6153 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6154 |
|
---|
| 6155 | intnetR0BusyWait(pNetwork, &pIf->cBusy);
|
---|
| 6156 |
|
---|
[40806] | 6157 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6158 | if ( iIf == pNetwork->MacTab.cEntries /* paranoia */
|
---|
| 6159 | && pIf->cBusy)
|
---|
| 6160 | {
|
---|
| 6161 | pIf->pNetwork = NULL;
|
---|
| 6162 | pNetwork->MacTab.cEntries--;
|
---|
| 6163 | }
|
---|
| 6164 | }
|
---|
| 6165 |
|
---|
| 6166 | /*
|
---|
[28831] | 6167 | * Zap the trunk pointer while we still own the spinlock, destroy the
|
---|
| 6168 | * trunk after we've left it. Note that this might take a while...
|
---|
[28623] | 6169 | */
|
---|
| 6170 | pNetwork->MacTab.pTrunk = NULL;
|
---|
| 6171 |
|
---|
[52618] | 6172 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[28623] | 6173 |
|
---|
| 6174 | if (pTrunk)
|
---|
| 6175 | intnetR0TrunkIfDestroy(pTrunk, pNetwork);
|
---|
| 6176 |
|
---|
| 6177 | /*
|
---|
[10557] | 6178 | * Unlink the network.
|
---|
| 6179 | * Note that it needn't be in the list if we failed during creation.
|
---|
[1] | 6180 | */
|
---|
| 6181 | PINTNETNETWORK pPrev = pIntNet->pNetworks;
|
---|
| 6182 | if (pPrev == pNetwork)
|
---|
| 6183 | pIntNet->pNetworks = pNetwork->pNext;
|
---|
| 6184 | else
|
---|
| 6185 | {
|
---|
| 6186 | for (; pPrev; pPrev = pPrev->pNext)
|
---|
| 6187 | if (pPrev->pNext == pNetwork)
|
---|
| 6188 | {
|
---|
| 6189 | pPrev->pNext = pNetwork->pNext;
|
---|
| 6190 | break;
|
---|
| 6191 | }
|
---|
| 6192 | }
|
---|
| 6193 | pNetwork->pNext = NULL;
|
---|
| 6194 | pNetwork->pvObj = NULL;
|
---|
| 6195 |
|
---|
| 6196 | /*
|
---|
| 6197 | * Free resources.
|
---|
| 6198 | */
|
---|
[28623] | 6199 | RTSemEventDestroy(pNetwork->hEvtBusyIf);
|
---|
| 6200 | pNetwork->hEvtBusyIf = NIL_RTSEMEVENT;
|
---|
| 6201 | RTSpinlockDestroy(pNetwork->hAddrSpinlock);
|
---|
| 6202 | pNetwork->hAddrSpinlock = NIL_RTSPINLOCK;
|
---|
| 6203 | RTMemFree(pNetwork->MacTab.paEntries);
|
---|
| 6204 | pNetwork->MacTab.paEntries = NULL;
|
---|
[55842] | 6205 | for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End; i++)
|
---|
| 6206 | intnetR0IfAddrCacheDestroy(&pNetwork->aAddrBlacklist[i]);
|
---|
[1] | 6207 | RTMemFree(pNetwork);
|
---|
[10557] | 6208 |
|
---|
[28623] | 6209 | /* Release the create/destroy sem. */
|
---|
[28488] | 6210 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
[1] | 6211 | }
|
---|
| 6212 |
|
---|
| 6213 |
|
---|
| 6214 | /**
|
---|
[36075] | 6215 | * Checks if the open network flags are compatible.
|
---|
| 6216 | *
|
---|
| 6217 | * @returns VBox status code.
|
---|
| 6218 | * @param pNetwork The network.
|
---|
| 6219 | * @param fFlags The open network flags.
|
---|
| 6220 | */
|
---|
| 6221 | static int intnetR0CheckOpenNetworkFlags(PINTNETNETWORK pNetwork, uint32_t fFlags)
|
---|
| 6222 | {
|
---|
| 6223 | uint32_t const fNetFlags = pNetwork->fFlags;
|
---|
| 6224 |
|
---|
| 6225 | if ( (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
| 6226 | ^ (fNetFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE))
|
---|
| 6227 | return VERR_INTNET_INCOMPATIBLE_FLAGS;
|
---|
| 6228 |
|
---|
| 6229 | if (fFlags & INTNET_OPEN_FLAGS_REQUIRE_EXACT)
|
---|
| 6230 | {
|
---|
| 6231 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6232 | if ( (fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair)
|
---|
| 6233 | && (fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair)
|
---|
| 6234 | != (fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fPair) )
|
---|
| 6235 | return VERR_INTNET_INCOMPATIBLE_FLAGS;
|
---|
| 6236 | }
|
---|
| 6237 |
|
---|
| 6238 | if (fFlags & INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES)
|
---|
| 6239 | {
|
---|
| 6240 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6241 | if ( (fFlags & g_afIntNetOpenNetworkNetFlags[i].fRestrictive)
|
---|
| 6242 | && !(fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fRestrictive)
|
---|
| 6243 | && (fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fFixed) )
|
---|
| 6244 | return VERR_INTNET_INCOMPATIBLE_FLAGS;
|
---|
| 6245 | }
|
---|
| 6246 |
|
---|
| 6247 | return VINF_SUCCESS;
|
---|
| 6248 | }
|
---|
| 6249 |
|
---|
| 6250 |
|
---|
| 6251 | /**
|
---|
| 6252 | * Adapts flag changes on network opening.
|
---|
| 6253 | *
|
---|
| 6254 | * @returns VBox status code.
|
---|
| 6255 | * @param pNetwork The network.
|
---|
| 6256 | * @param fFlags The open network flags.
|
---|
| 6257 | */
|
---|
| 6258 | static int intnetR0AdaptOpenNetworkFlags(PINTNETNETWORK pNetwork, uint32_t fFlags)
|
---|
| 6259 | {
|
---|
| 6260 | /*
|
---|
| 6261 | * Upgrade the minimum policy flags.
|
---|
| 6262 | */
|
---|
| 6263 | uint32_t fNetMinFlags = pNetwork->fMinFlags;
|
---|
| 6264 | Assert(!(fNetMinFlags & INTNET_OPEN_FLAGS_RELAXED_MASK));
|
---|
| 6265 | if (fFlags & INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES)
|
---|
| 6266 | {
|
---|
| 6267 | fNetMinFlags |= fFlags & INTNET_OPEN_FLAGS_STRICT_MASK;
|
---|
| 6268 | if (fNetMinFlags != pNetwork->fMinFlags)
|
---|
| 6269 | {
|
---|
| 6270 | LogRel(("INTNET: %s - min flags changed %#x -> %#x\n", pNetwork->szName, pNetwork->fMinFlags, fNetMinFlags));
|
---|
| 6271 | pNetwork->fMinFlags = fNetMinFlags;
|
---|
| 6272 | }
|
---|
| 6273 | }
|
---|
| 6274 |
|
---|
| 6275 | /*
|
---|
| 6276 | * Calculate the new network flags.
|
---|
| 6277 | * (Depends on fNetMinFlags being recalculated first.)
|
---|
| 6278 | */
|
---|
| 6279 | uint32_t fNetFlags = pNetwork->fFlags;
|
---|
| 6280 |
|
---|
| 6281 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6282 | {
|
---|
| 6283 | Assert(fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fPair);
|
---|
| 6284 | Assert(!(fNetMinFlags & g_afIntNetOpenNetworkNetFlags[i].fRelaxed));
|
---|
| 6285 |
|
---|
| 6286 | if (!(fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair))
|
---|
| 6287 | continue;
|
---|
| 6288 | if (fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fFixed)
|
---|
| 6289 | continue;
|
---|
| 6290 |
|
---|
| 6291 | if ( (fNetMinFlags & g_afIntNetOpenNetworkNetFlags[i].fRestrictive)
|
---|
| 6292 | || (fFlags & g_afIntNetOpenNetworkNetFlags[i].fRestrictive) )
|
---|
| 6293 | {
|
---|
| 6294 | fNetFlags &= ~g_afIntNetOpenNetworkNetFlags[i].fPair;
|
---|
| 6295 | fNetFlags |= g_afIntNetOpenNetworkNetFlags[i].fRestrictive;
|
---|
| 6296 | }
|
---|
| 6297 | else if (!(fFlags & INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES))
|
---|
| 6298 | {
|
---|
| 6299 | fNetFlags &= ~g_afIntNetOpenNetworkNetFlags[i].fPair;
|
---|
| 6300 | fNetFlags |= g_afIntNetOpenNetworkNetFlags[i].fRelaxed;
|
---|
| 6301 | }
|
---|
| 6302 | }
|
---|
| 6303 |
|
---|
| 6304 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6305 | {
|
---|
| 6306 | Assert(fNetFlags & g_afIntNetOpenNetworkNetFlags[i].fPair);
|
---|
| 6307 | fNetFlags |= fFlags & g_afIntNetOpenNetworkNetFlags[i].fFixed;
|
---|
| 6308 | }
|
---|
| 6309 |
|
---|
| 6310 | /*
|
---|
| 6311 | * Apply the flags if they changed.
|
---|
| 6312 | */
|
---|
| 6313 | uint32_t const fOldNetFlags = pNetwork->fFlags;
|
---|
| 6314 | if (fOldNetFlags != fNetFlags)
|
---|
| 6315 | {
|
---|
| 6316 | LogRel(("INTNET: %s - flags changed %#x -> %#x\n", pNetwork->szName, fOldNetFlags, fNetFlags));
|
---|
| 6317 |
|
---|
[40806] | 6318 | RTSpinlockAcquire(pNetwork->hAddrSpinlock);
|
---|
[36075] | 6319 |
|
---|
| 6320 | pNetwork->fFlags = fNetFlags;
|
---|
| 6321 |
|
---|
| 6322 | /* Recalculate some derived switcher variables. */
|
---|
| 6323 | bool fActiveTrunk = pNetwork->MacTab.pTrunk
|
---|
| 6324 | && pNetwork->cActiveIFs > 0;
|
---|
| 6325 | pNetwork->MacTab.fHostActive = fActiveTrunk
|
---|
| 6326 | && (fNetFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED);
|
---|
| 6327 | pNetwork->MacTab.fHostPromiscuousEff = ( pNetwork->MacTab.fHostPromiscuousReal
|
---|
| 6328 | || (fNetFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE))
|
---|
| 6329 | && (fNetFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST);
|
---|
| 6330 |
|
---|
| 6331 | pNetwork->MacTab.fWireActive = fActiveTrunk
|
---|
| 6332 | && (fNetFlags & INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED);
|
---|
[36077] | 6333 | pNetwork->MacTab.fWirePromiscuousReal= RT_BOOL(fNetFlags & INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE);
|
---|
[36075] | 6334 | pNetwork->MacTab.fWirePromiscuousEff = pNetwork->MacTab.fWirePromiscuousReal
|
---|
| 6335 | && (fNetFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE);
|
---|
| 6336 |
|
---|
| 6337 | if ((fOldNetFlags ^ fNetFlags) & INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS)
|
---|
| 6338 | {
|
---|
[36089] | 6339 | pNetwork->MacTab.cPromiscuousEntries = 0;
|
---|
| 6340 | pNetwork->MacTab.cPromiscuousNoTrunkEntries = 0;
|
---|
| 6341 |
|
---|
[36075] | 6342 | uint32_t iIf = pNetwork->MacTab.cEntries;
|
---|
| 6343 | while (iIf-- > 0)
|
---|
| 6344 | {
|
---|
| 6345 | PINTNETMACTABENTRY pEntry = &pNetwork->MacTab.paEntries[iIf];
|
---|
| 6346 | PINTNETIF pIf2 = pEntry->pIf;
|
---|
| 6347 | if ( pIf2 /* paranoia */
|
---|
| 6348 | && pIf2->fPromiscuousReal)
|
---|
| 6349 | {
|
---|
| 6350 | bool fPromiscuousEff = (fNetFlags & INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS)
|
---|
| 6351 | && (pIf2->fOpenFlags & INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW);
|
---|
| 6352 | pEntry->fPromiscuousEff = fPromiscuousEff;
|
---|
| 6353 | pEntry->fPromiscuousSeeTrunk = fPromiscuousEff
|
---|
| 6354 | && (pIf2->fOpenFlags & INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK);
|
---|
[36089] | 6355 |
|
---|
| 6356 | if (pEntry->fPromiscuousEff)
|
---|
| 6357 | {
|
---|
| 6358 | pNetwork->MacTab.cPromiscuousEntries++;
|
---|
| 6359 | if (!pEntry->fPromiscuousSeeTrunk)
|
---|
| 6360 | pNetwork->MacTab.cPromiscuousNoTrunkEntries++;
|
---|
| 6361 | }
|
---|
[36075] | 6362 | }
|
---|
| 6363 | }
|
---|
| 6364 | }
|
---|
| 6365 |
|
---|
[52618] | 6366 | RTSpinlockRelease(pNetwork->hAddrSpinlock);
|
---|
[36075] | 6367 | }
|
---|
| 6368 |
|
---|
| 6369 | return VINF_SUCCESS;
|
---|
| 6370 | }
|
---|
| 6371 |
|
---|
| 6372 |
|
---|
| 6373 | /**
|
---|
[1] | 6374 | * Opens an existing network.
|
---|
| 6375 | *
|
---|
[28488] | 6376 | * The call must own the INTNET::hMtxCreateOpenDestroy.
|
---|
| 6377 | *
|
---|
[1] | 6378 | * @returns VBox status code.
|
---|
[10530] | 6379 | * @param pIntNet The instance data.
|
---|
| 6380 | * @param pSession The current session.
|
---|
| 6381 | * @param pszNetwork The network name. This has a valid length.
|
---|
| 6382 | * @param enmTrunkType The trunk type.
|
---|
[33540] | 6383 | * @param pszTrunk The trunk name. Its meaning is specific to the type.
|
---|
[10530] | 6384 | * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
|
---|
| 6385 | * @param ppNetwork Where to store the pointer to the network on success.
|
---|
[1] | 6386 | */
|
---|
[10711] | 6387 | static int intnetR0OpenNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
|
---|
| 6388 | const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
|
---|
[1] | 6389 | {
|
---|
[10711] | 6390 | LogFlow(("intnetR0OpenNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
|
---|
[10530] | 6391 | pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
|
---|
[1] | 6392 |
|
---|
[10530] | 6393 | /* just pro forma validation, the caller is internal. */
|
---|
[10451] | 6394 | AssertPtr(pIntNet);
|
---|
| 6395 | AssertPtr(pSession);
|
---|
| 6396 | AssertPtr(pszNetwork);
|
---|
[10530] | 6397 | Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
|
---|
| 6398 | AssertPtr(pszTrunk);
|
---|
[36075] | 6399 | Assert(!(fFlags & ~INTNET_OPEN_FLAGS_MASK));
|
---|
[10451] | 6400 | AssertPtr(ppNetwork);
|
---|
[1] | 6401 | *ppNetwork = NULL;
|
---|
| 6402 |
|
---|
| 6403 | /*
|
---|
| 6404 | * Search networks by name.
|
---|
| 6405 | */
|
---|
| 6406 | PINTNETNETWORK pCur;
|
---|
[17184] | 6407 | uint8_t cchName = (uint8_t)strlen(pszNetwork);
|
---|
[1] | 6408 | Assert(cchName && cchName < sizeof(pCur->szName)); /* caller ensures this */
|
---|
| 6409 |
|
---|
| 6410 | pCur = pIntNet->pNetworks;
|
---|
| 6411 | while (pCur)
|
---|
| 6412 | {
|
---|
| 6413 | if ( pCur->cchName == cchName
|
---|
| 6414 | && !memcmp(pCur->szName, pszNetwork, cchName))
|
---|
| 6415 | {
|
---|
| 6416 | /*
|
---|
[10530] | 6417 | * Found the network, now check that we have the same ideas
|
---|
| 6418 | * about the trunk setup and security.
|
---|
[1] | 6419 | */
|
---|
[10530] | 6420 | int rc;
|
---|
[44824] | 6421 | if ( enmTrunkType == kIntNetTrunkType_WhateverNone
|
---|
| 6422 | #ifdef VBOX_WITH_NAT_SERVICE
|
---|
[63562] | 6423 | || enmTrunkType == kIntNetTrunkType_SrvNat /** @todo what does it mean */
|
---|
[44824] | 6424 | #endif
|
---|
| 6425 | || ( pCur->enmTrunkType == enmTrunkType
|
---|
[45356] | 6426 | && !strcmp(pCur->szTrunk, pszTrunk)))
|
---|
[1] | 6427 | {
|
---|
[36075] | 6428 | rc = intnetR0CheckOpenNetworkFlags(pCur, fFlags);
|
---|
| 6429 | if (RT_SUCCESS(rc))
|
---|
[1] | 6430 | {
|
---|
[10530] | 6431 | /*
|
---|
[10557] | 6432 | * Increment the reference and check that the session
|
---|
| 6433 | * can access this network.
|
---|
[10530] | 6434 | */
|
---|
| 6435 | rc = SUPR0ObjAddRef(pCur->pvObj, pSession);
|
---|
[10533] | 6436 | if (RT_SUCCESS(rc))
|
---|
[10530] | 6437 | {
|
---|
[36075] | 6438 | if (pCur->fFlags & INTNET_OPEN_FLAGS_ACCESS_RESTRICTED)
|
---|
[10530] | 6439 | rc = SUPR0ObjVerifyAccess(pCur->pvObj, pSession, pCur->szName);
|
---|
[10533] | 6440 | if (RT_SUCCESS(rc))
|
---|
[10530] | 6441 | *ppNetwork = pCur;
|
---|
| 6442 | else
|
---|
| 6443 | SUPR0ObjRelease(pCur->pvObj, pSession);
|
---|
| 6444 | }
|
---|
[10557] | 6445 | else if (rc == VERR_WRONG_ORDER)
|
---|
| 6446 | rc = VERR_NOT_FOUND; /* destruction race, pretend the other isn't there. */
|
---|
[1] | 6447 | }
|
---|
| 6448 | }
|
---|
[10530] | 6449 | else
|
---|
[33410] | 6450 | {
|
---|
[10530] | 6451 | rc = VERR_INTNET_INCOMPATIBLE_TRUNK;
|
---|
[33443] | 6452 | LogRel(("intnetR0OpenNetwork failed. rc=%Rrc pCur->szTrunk=%s pszTrunk=%s pCur->enmTrunkType=%d enmTrunkType=%d\n",
|
---|
[33410] | 6453 | rc, pCur->szTrunk, pszTrunk, pCur->enmTrunkType, enmTrunkType));
|
---|
| 6454 | }
|
---|
[10530] | 6455 |
|
---|
[10711] | 6456 | LogFlow(("intnetR0OpenNetwork: returns %Rrc *ppNetwork=%p\n", rc, *ppNetwork));
|
---|
[1] | 6457 | return rc;
|
---|
| 6458 | }
|
---|
[28488] | 6459 |
|
---|
[1] | 6460 | pCur = pCur->pNext;
|
---|
| 6461 | }
|
---|
| 6462 |
|
---|
[10711] | 6463 | LogFlow(("intnetR0OpenNetwork: returns VERR_NOT_FOUND\n"));
|
---|
[10530] | 6464 | return VERR_NOT_FOUND;
|
---|
[1] | 6465 | }
|
---|
| 6466 |
|
---|
| 6467 |
|
---|
| 6468 | /**
|
---|
| 6469 | * Creates a new network.
|
---|
| 6470 | *
|
---|
[28488] | 6471 | * The call must own the INTNET::hMtxCreateOpenDestroy and has already attempted
|
---|
[10557] | 6472 | * opening the network and found it to be non-existing.
|
---|
[1] | 6473 | *
|
---|
| 6474 | * @returns VBox status code.
|
---|
[1606] | 6475 | * @param pIntNet The instance data.
|
---|
[10530] | 6476 | * @param pSession The session handle.
|
---|
[1606] | 6477 | * @param pszNetwork The name of the network. This must be at least one character long and no longer
|
---|
| 6478 | * than the INTNETNETWORK::szName.
|
---|
[10530] | 6479 | * @param enmTrunkType The trunk type.
|
---|
[33540] | 6480 | * @param pszTrunk The trunk name. Its meaning is specific to the type.
|
---|
[10530] | 6481 | * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
|
---|
[28488] | 6482 | * @param ppNetwork Where to store the network. In the case of failure
|
---|
| 6483 | * whatever is returned here should be dereferenced
|
---|
| 6484 | * outside the INTNET::hMtxCreateOpenDestroy.
|
---|
[1] | 6485 | */
|
---|
[10711] | 6486 | static int intnetR0CreateNetwork(PINTNET pIntNet, PSUPDRVSESSION pSession, const char *pszNetwork, INTNETTRUNKTYPE enmTrunkType,
|
---|
| 6487 | const char *pszTrunk, uint32_t fFlags, PINTNETNETWORK *ppNetwork)
|
---|
[1] | 6488 | {
|
---|
[10711] | 6489 | LogFlow(("intnetR0CreateNetwork: pIntNet=%p pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x ppNetwork=%p\n",
|
---|
[10530] | 6490 | pIntNet, pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, ppNetwork));
|
---|
[1] | 6491 |
|
---|
[10530] | 6492 | /* just pro forma validation, the caller is internal. */
|
---|
[10451] | 6493 | AssertPtr(pIntNet);
|
---|
| 6494 | AssertPtr(pSession);
|
---|
| 6495 | AssertPtr(pszNetwork);
|
---|
[10530] | 6496 | Assert(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End);
|
---|
| 6497 | AssertPtr(pszTrunk);
|
---|
[10733] | 6498 | Assert(!(fFlags & ~INTNET_OPEN_FLAGS_MASK));
|
---|
[10451] | 6499 | AssertPtr(ppNetwork);
|
---|
[36075] | 6500 |
|
---|
[1] | 6501 | *ppNetwork = NULL;
|
---|
| 6502 |
|
---|
| 6503 | /*
|
---|
[36075] | 6504 | * Adjust the flags with defaults for the network policies.
|
---|
| 6505 | * Note: Main restricts promiscuous mode on the per interface level.
|
---|
| 6506 | */
|
---|
| 6507 | fFlags &= ~( INTNET_OPEN_FLAGS_IF_FIXED
|
---|
| 6508 | | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW
|
---|
| 6509 | | INTNET_OPEN_FLAGS_IF_PROMISC_DENY
|
---|
| 6510 | | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK
|
---|
| 6511 | | INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK
|
---|
| 6512 | | INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES
|
---|
| 6513 | | INTNET_OPEN_FLAGS_REQUIRE_EXACT);
|
---|
[38628] | 6514 | uint32_t fDefFlags = INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS
|
---|
| 6515 | | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST
|
---|
| 6516 | | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE
|
---|
| 6517 | | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED
|
---|
| 6518 | | INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE
|
---|
| 6519 | | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED
|
---|
| 6520 | | INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE;
|
---|
| 6521 | if ( enmTrunkType == kIntNetTrunkType_WhateverNone
|
---|
[44824] | 6522 | #ifdef VBOX_WITH_NAT_SERVICE
|
---|
[45356] | 6523 | || enmTrunkType == kIntNetTrunkType_SrvNat /* simialar security */
|
---|
[44824] | 6524 | #endif
|
---|
[38628] | 6525 | || enmTrunkType == kIntNetTrunkType_None)
|
---|
| 6526 | fDefFlags |= INTNET_OPEN_FLAGS_ACCESS_RESTRICTED;
|
---|
| 6527 | else
|
---|
| 6528 | fDefFlags |= INTNET_OPEN_FLAGS_ACCESS_PUBLIC;
|
---|
[36075] | 6529 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6530 | if (!(fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair))
|
---|
| 6531 | fFlags |= g_afIntNetOpenNetworkNetFlags[i].fPair & fDefFlags;
|
---|
| 6532 |
|
---|
| 6533 | /*
|
---|
[1] | 6534 | * Allocate and initialize.
|
---|
| 6535 | */
|
---|
[11057] | 6536 | size_t cb = sizeof(INTNETNETWORK);
|
---|
| 6537 | if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
| 6538 | cb += INTNETNETWORK_TMP_SIZE + 64;
|
---|
[28623] | 6539 | PINTNETNETWORK pNetwork = (PINTNETNETWORK)RTMemAllocZ(cb);
|
---|
| 6540 | if (!pNetwork)
|
---|
[1] | 6541 | return VERR_NO_MEMORY;
|
---|
[36075] | 6542 | //pNetwork->pNext = NULL;
|
---|
| 6543 | //pNetwork->pIfs = NULL;
|
---|
[74484] | 6544 | //pNetwork->fTerminateReconnectThread = false;
|
---|
| 6545 | pNetwork->hTrunkReconnectThread = NIL_RTTHREAD;
|
---|
[36075] | 6546 | pNetwork->hAddrSpinlock = NIL_RTSPINLOCK;
|
---|
| 6547 | pNetwork->MacTab.cEntries = 0;
|
---|
| 6548 | pNetwork->MacTab.cEntriesAllocated = INTNET_GROW_DSTTAB_SIZE;
|
---|
[36089] | 6549 | //pNetwork->MacTab.cPromiscuousEntries = 0;
|
---|
| 6550 | //pNetwork->MacTab.cPromiscuousNoTrunkEntries = 0;
|
---|
[36075] | 6551 | pNetwork->MacTab.paEntries = NULL;
|
---|
| 6552 | pNetwork->MacTab.fHostPromiscuousReal = false;
|
---|
| 6553 | pNetwork->MacTab.fHostPromiscuousEff = false;
|
---|
| 6554 | pNetwork->MacTab.fHostActive = false;
|
---|
| 6555 | pNetwork->MacTab.fWirePromiscuousReal = false;
|
---|
| 6556 | pNetwork->MacTab.fWirePromiscuousEff = false;
|
---|
| 6557 | pNetwork->MacTab.fWireActive = false;
|
---|
| 6558 | pNetwork->MacTab.pTrunk = NULL;
|
---|
| 6559 | pNetwork->hEvtBusyIf = NIL_RTSEMEVENT;
|
---|
| 6560 | pNetwork->pIntNet = pIntNet;
|
---|
| 6561 | //pNetwork->pvObj = NULL;
|
---|
[28623] | 6562 | if (fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE)
|
---|
[36075] | 6563 | pNetwork->pbTmp = RT_ALIGN_PT(pNetwork + 1, 64, uint8_t *);
|
---|
[28623] | 6564 | //else
|
---|
[36075] | 6565 | // pNetwork->pbTmp = NULL;
|
---|
| 6566 | pNetwork->fFlags = fFlags;
|
---|
| 6567 | //pNetwork->fMinFlags = 0;
|
---|
| 6568 | //pNetwork->cActiveIFs = 0;
|
---|
| 6569 | size_t cchName = strlen(pszNetwork);
|
---|
| 6570 | pNetwork->cchName = (uint8_t)cchName;
|
---|
[28623] | 6571 | Assert(cchName && cchName < sizeof(pNetwork->szName)); /* caller's responsibility. */
|
---|
| 6572 | memcpy(pNetwork->szName, pszNetwork, cchName); /* '\0' at courtesy of alloc. */
|
---|
[36075] | 6573 | pNetwork->enmTrunkType = enmTrunkType;
|
---|
[28623] | 6574 | Assert(strlen(pszTrunk) < sizeof(pNetwork->szTrunk)); /* caller's responsibility. */
|
---|
| 6575 | strcpy(pNetwork->szTrunk, pszTrunk);
|
---|
| 6576 |
|
---|
| 6577 | /*
|
---|
| 6578 | * Create the semaphore, spinlock and allocate the interface table.
|
---|
| 6579 | */
|
---|
| 6580 | int rc = RTSemEventCreate(&pNetwork->hEvtBusyIf);
|
---|
[10533] | 6581 | if (RT_SUCCESS(rc))
|
---|
[40806] | 6582 | rc = RTSpinlockCreate(&pNetwork->hAddrSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "hAddrSpinlock");
|
---|
[28623] | 6583 | if (RT_SUCCESS(rc))
|
---|
[1] | 6584 | {
|
---|
[28623] | 6585 | pNetwork->MacTab.paEntries = (PINTNETMACTABENTRY)RTMemAlloc(sizeof(INTNETMACTABENTRY) * pNetwork->MacTab.cEntriesAllocated);
|
---|
| 6586 | if (!pNetwork->MacTab.paEntries)
|
---|
| 6587 | rc = VERR_NO_MEMORY;
|
---|
| 6588 | }
|
---|
| 6589 | if (RT_SUCCESS(rc))
|
---|
| 6590 | {
|
---|
[55652] | 6591 | for (int i = kIntNetAddrType_Invalid + 1; i < kIntNetAddrType_End && RT_SUCCESS(rc); i++)
|
---|
| 6592 | rc = intnetR0IfAddrCacheInit(&pNetwork->aAddrBlacklist[i], (INTNETADDRTYPE)i,
|
---|
| 6593 | !!(pNetwork->fFlags & INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE));
|
---|
| 6594 | }
|
---|
| 6595 | if (RT_SUCCESS(rc))
|
---|
| 6596 | {
|
---|
[1] | 6597 | /*
|
---|
[10557] | 6598 | * Register the object in the current session and link it into the network list.
|
---|
[1] | 6599 | */
|
---|
[28623] | 6600 | pNetwork->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_INTERNAL_NETWORK, intnetR0NetworkDestruct, pNetwork, pIntNet);
|
---|
| 6601 | if (pNetwork->pvObj)
|
---|
[1] | 6602 | {
|
---|
[28623] | 6603 | pNetwork->pNext = pIntNet->pNetworks;
|
---|
| 6604 | pIntNet->pNetworks = pNetwork;
|
---|
[1] | 6605 |
|
---|
[10557] | 6606 | /*
|
---|
[28488] | 6607 | * Check if the current session is actually allowed to create and
|
---|
| 6608 | * open the network. It is possible to implement network name
|
---|
| 6609 | * based policies and these must be checked now. SUPR0ObjRegister
|
---|
| 6610 | * does no such checks.
|
---|
[10557] | 6611 | */
|
---|
[28623] | 6612 | rc = SUPR0ObjVerifyAccess(pNetwork->pvObj, pSession, pNetwork->szName);
|
---|
[10530] | 6613 | if (RT_SUCCESS(rc))
|
---|
[1] | 6614 | {
|
---|
[10530] | 6615 | /*
|
---|
[10557] | 6616 | * Connect the trunk.
|
---|
[10530] | 6617 | */
|
---|
[28623] | 6618 | rc = intnetR0NetworkCreateTrunkIf(pNetwork, pSession);
|
---|
[10533] | 6619 | if (RT_SUCCESS(rc))
|
---|
[10530] | 6620 | {
|
---|
[28623] | 6621 | *ppNetwork = pNetwork;
|
---|
| 6622 | LogFlow(("intnetR0CreateNetwork: returns VINF_SUCCESS *ppNetwork=%p\n", pNetwork));
|
---|
[10530] | 6623 | return VINF_SUCCESS;
|
---|
| 6624 | }
|
---|
[1] | 6625 | }
|
---|
| 6626 |
|
---|
[28623] | 6627 | SUPR0ObjRelease(pNetwork->pvObj, pSession);
|
---|
[10711] | 6628 | LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
|
---|
[1] | 6629 | return rc;
|
---|
| 6630 | }
|
---|
[28623] | 6631 |
|
---|
| 6632 | /* cleanup */
|
---|
[1] | 6633 | rc = VERR_NO_MEMORY;
|
---|
[28623] | 6634 | }
|
---|
[1] | 6635 |
|
---|
[28623] | 6636 | RTSemEventDestroy(pNetwork->hEvtBusyIf);
|
---|
| 6637 | pNetwork->hEvtBusyIf = NIL_RTSEMEVENT;
|
---|
| 6638 | RTSpinlockDestroy(pNetwork->hAddrSpinlock);
|
---|
| 6639 | pNetwork->hAddrSpinlock = NIL_RTSPINLOCK;
|
---|
| 6640 | RTMemFree(pNetwork->MacTab.paEntries);
|
---|
| 6641 | pNetwork->MacTab.paEntries = NULL;
|
---|
| 6642 | RTMemFree(pNetwork);
|
---|
| 6643 |
|
---|
[10711] | 6644 | LogFlow(("intnetR0CreateNetwork: returns %Rrc\n", rc));
|
---|
[1] | 6645 | return rc;
|
---|
| 6646 | }
|
---|
| 6647 |
|
---|
| 6648 |
|
---|
| 6649 | /**
|
---|
[10076] | 6650 | * Opens a network interface and connects it to the specified network.
|
---|
[1] | 6651 | *
|
---|
| 6652 | * @returns VBox status code.
|
---|
[1606] | 6653 | * @param pSession The session handle.
|
---|
| 6654 | * @param pszNetwork The network name.
|
---|
[10451] | 6655 | * @param enmTrunkType The trunk type.
|
---|
[33540] | 6656 | * @param pszTrunk The trunk name. Its meaning is specific to the type.
|
---|
[10451] | 6657 | * @param fFlags Flags, see INTNET_OPEN_FLAGS_*.
|
---|
[97338] | 6658 | * @param fRestrictAccess Whether new participants should be subjected to
|
---|
| 6659 | * access check or not.
|
---|
[1606] | 6660 | * @param cbSend The send buffer size.
|
---|
| 6661 | * @param cbRecv The receive buffer size.
|
---|
[97339] | 6662 | * @param pfnRecvAvail The receive available callback to call instead of
|
---|
[97338] | 6663 | * signalling the semaphore (R3 service only).
|
---|
| 6664 | * @param pvUser The opaque user data to pass to the callback.
|
---|
[1606] | 6665 | * @param phIf Where to store the handle to the network interface.
|
---|
[1] | 6666 | */
|
---|
[28706] | 6667 | INTNETR0DECL(int) IntNetR0Open(PSUPDRVSESSION pSession, const char *pszNetwork,
|
---|
[10451] | 6668 | INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
|
---|
[97339] | 6669 | uint32_t cbSend, uint32_t cbRecv, PFNINTNETIFRECVAVAIL pfnRecvAvail, void *pvUser,
|
---|
[97338] | 6670 | PINTNETIFHANDLE phIf)
|
---|
[1] | 6671 | {
|
---|
[28706] | 6672 | LogFlow(("IntNetR0Open: pSession=%p pszNetwork=%p:{%s} enmTrunkType=%d pszTrunk=%p:{%s} fFlags=%#x cbSend=%u cbRecv=%u phIf=%p\n",
|
---|
| 6673 | pSession, pszNetwork, pszNetwork, enmTrunkType, pszTrunk, pszTrunk, fFlags, cbSend, cbRecv, phIf));
|
---|
[1] | 6674 |
|
---|
| 6675 | /*
|
---|
| 6676 | * Validate input.
|
---|
| 6677 | */
|
---|
[28706] | 6678 | PINTNET pIntNet = g_pIntNet;
|
---|
[10451] | 6679 | AssertPtrReturn(pIntNet, VERR_INVALID_PARAMETER);
|
---|
[28706] | 6680 | AssertReturn(pIntNet->u32Magic, VERR_INVALID_MAGIC);
|
---|
[10451] | 6681 |
|
---|
| 6682 | AssertPtrReturn(pszNetwork, VERR_INVALID_PARAMETER);
|
---|
[30320] | 6683 | const char *pszNetworkEnd = RTStrEnd(pszNetwork, INTNET_MAX_NETWORK_NAME);
|
---|
[1] | 6684 | AssertReturn(pszNetworkEnd, VERR_INVALID_PARAMETER);
|
---|
| 6685 | size_t cchNetwork = pszNetworkEnd - pszNetwork;
|
---|
| 6686 | AssertReturn(cchNetwork, VERR_INVALID_PARAMETER);
|
---|
| 6687 |
|
---|
[10451] | 6688 | if (pszTrunk)
|
---|
| 6689 | {
|
---|
| 6690 | AssertPtrReturn(pszTrunk, VERR_INVALID_PARAMETER);
|
---|
[30320] | 6691 | const char *pszTrunkEnd = RTStrEnd(pszTrunk, INTNET_MAX_TRUNK_NAME);
|
---|
[10451] | 6692 | AssertReturn(pszTrunkEnd, VERR_INVALID_PARAMETER);
|
---|
| 6693 | }
|
---|
[10530] | 6694 | else
|
---|
| 6695 | pszTrunk = "";
|
---|
| 6696 |
|
---|
[10451] | 6697 | AssertMsgReturn(enmTrunkType > kIntNetTrunkType_Invalid && enmTrunkType < kIntNetTrunkType_End,
|
---|
| 6698 | ("%d\n", enmTrunkType), VERR_INVALID_PARAMETER);
|
---|
| 6699 | switch (enmTrunkType)
|
---|
| 6700 | {
|
---|
| 6701 | case kIntNetTrunkType_None:
|
---|
| 6702 | case kIntNetTrunkType_WhateverNone:
|
---|
[44824] | 6703 | #ifdef VBOX_WITH_NAT_SERVICE
|
---|
[45356] | 6704 | case kIntNetTrunkType_SrvNat:
|
---|
[44824] | 6705 | #endif
|
---|
[26574] | 6706 | if (*pszTrunk)
|
---|
| 6707 | return VERR_INVALID_PARAMETER;
|
---|
[10451] | 6708 | break;
|
---|
| 6709 |
|
---|
| 6710 | case kIntNetTrunkType_NetFlt:
|
---|
[16856] | 6711 | case kIntNetTrunkType_NetAdp:
|
---|
[26574] | 6712 | if (!*pszTrunk)
|
---|
| 6713 | return VERR_INVALID_PARAMETER;
|
---|
[10451] | 6714 | break;
|
---|
| 6715 |
|
---|
| 6716 | default:
|
---|
| 6717 | return VERR_NOT_IMPLEMENTED;
|
---|
| 6718 | }
|
---|
| 6719 |
|
---|
[10733] | 6720 | AssertMsgReturn(!(fFlags & ~INTNET_OPEN_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
|
---|
[36075] | 6721 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkNetFlags); i++)
|
---|
| 6722 | AssertMsgReturn((fFlags & g_afIntNetOpenNetworkNetFlags[i].fPair) != g_afIntNetOpenNetworkNetFlags[i].fPair,
|
---|
| 6723 | ("%#x (%#x)\n", fFlags, g_afIntNetOpenNetworkNetFlags[i].fPair), VERR_INVALID_PARAMETER);
|
---|
| 6724 | for (uint32_t i = 0; i < RT_ELEMENTS(g_afIntNetOpenNetworkIfFlags); i++)
|
---|
| 6725 | AssertMsgReturn((fFlags & g_afIntNetOpenNetworkIfFlags[i].fPair) != g_afIntNetOpenNetworkIfFlags[i].fPair,
|
---|
| 6726 | ("%#x (%#x)\n", fFlags, g_afIntNetOpenNetworkIfFlags[i].fPair), VERR_INVALID_PARAMETER);
|
---|
[10451] | 6727 | AssertPtrReturn(phIf, VERR_INVALID_PARAMETER);
|
---|
| 6728 |
|
---|
[1] | 6729 | /*
|
---|
[28488] | 6730 | * Acquire the mutex to serialize open/create/close.
|
---|
[1] | 6731 | */
|
---|
[28488] | 6732 | int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
[10533] | 6733 | if (RT_FAILURE(rc))
|
---|
[1] | 6734 | return rc;
|
---|
| 6735 |
|
---|
| 6736 | /*
|
---|
[26574] | 6737 | * Try open / create the network and create an interface on it for the
|
---|
| 6738 | * caller to use.
|
---|
[1] | 6739 | */
|
---|
[10557] | 6740 | PINTNETNETWORK pNetwork = NULL;
|
---|
[10711] | 6741 | rc = intnetR0OpenNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
|
---|
[28488] | 6742 | if (RT_SUCCESS(rc))
|
---|
[1] | 6743 | {
|
---|
[97338] | 6744 | rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, fFlags, pfnRecvAvail, pvUser, phIf);
|
---|
[10557] | 6745 | if (RT_SUCCESS(rc))
|
---|
[36075] | 6746 | {
|
---|
| 6747 | intnetR0AdaptOpenNetworkFlags(pNetwork, fFlags);
|
---|
[28488] | 6748 | rc = VINF_ALREADY_INITIALIZED;
|
---|
[36075] | 6749 | }
|
---|
[28623] | 6750 | else
|
---|
| 6751 | SUPR0ObjRelease(pNetwork->pvObj, pSession);
|
---|
[28488] | 6752 | }
|
---|
| 6753 | else if (rc == VERR_NOT_FOUND)
|
---|
| 6754 | {
|
---|
| 6755 | rc = intnetR0CreateNetwork(pIntNet, pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, &pNetwork);
|
---|
| 6756 | if (RT_SUCCESS(rc))
|
---|
[17966] | 6757 | {
|
---|
[97338] | 6758 | rc = intnetR0NetworkCreateIf(pNetwork, pSession, cbSend, cbRecv, fFlags, pfnRecvAvail, pvUser, phIf);
|
---|
[28623] | 6759 | if (RT_FAILURE(rc))
|
---|
| 6760 | SUPR0ObjRelease(pNetwork->pvObj, pSession);
|
---|
[17966] | 6761 | }
|
---|
[1] | 6762 | }
|
---|
| 6763 |
|
---|
[28488] | 6764 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
[28706] | 6765 | LogFlow(("IntNetR0Open: return %Rrc *phIf=%RX32\n", rc, *phIf));
|
---|
[1] | 6766 | return rc;
|
---|
| 6767 | }
|
---|
| 6768 |
|
---|
| 6769 |
|
---|
| 6770 | /**
|
---|
[28871] | 6771 | * VMMR0 request wrapper for IntNetR0Open.
|
---|
[5283] | 6772 | *
|
---|
| 6773 | * @returns see GMMR0MapUnmapChunk.
|
---|
[10806] | 6774 | * @param pSession The caller's session.
|
---|
[5283] | 6775 | * @param pReq The request packet.
|
---|
| 6776 | */
|
---|
[28706] | 6777 | INTNETR0DECL(int) IntNetR0OpenReq(PSUPDRVSESSION pSession, PINTNETOPENREQ pReq)
|
---|
[5283] | 6778 | {
|
---|
| 6779 | if (RT_UNLIKELY(pReq->Hdr.cbReq != sizeof(*pReq)))
|
---|
| 6780 | return VERR_INVALID_PARAMETER;
|
---|
[28706] | 6781 | return IntNetR0Open(pSession, &pReq->szNetwork[0], pReq->enmTrunkType, pReq->szTrunk,
|
---|
[97338] | 6782 | pReq->fFlags, pReq->cbSend, pReq->cbRecv, NULL /*pfnRecvAvail*/, NULL /*pvUser*/, &pReq->hIf);
|
---|
[5283] | 6783 | }
|
---|
| 6784 |
|
---|
| 6785 |
|
---|
[97338] | 6786 | #if defined(VBOX_WITH_INTNET_SERVICE_IN_R3) && defined(IN_RING3)
|
---|
| 6787 | INTNETR3DECL(int) IntNetR3Open(PSUPDRVSESSION pSession, const char *pszNetwork,
|
---|
| 6788 | INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags,
|
---|
[97341] | 6789 | uint32_t cbSend, uint32_t cbRecv, PFNINTNETIFRECVAVAIL pfnRecvAvail, void *pvUser,
|
---|
[97338] | 6790 | PINTNETIFHANDLE phIf)
|
---|
| 6791 | {
|
---|
| 6792 | return IntNetR0Open(pSession, pszNetwork, enmTrunkType, pszTrunk, fFlags, cbSend, cbRecv, pfnRecvAvail, pvUser, phIf);
|
---|
| 6793 | }
|
---|
| 6794 | #endif
|
---|
| 6795 |
|
---|
| 6796 |
|
---|
[5283] | 6797 | /**
|
---|
[28706] | 6798 | * Count the internal networks.
|
---|
[1] | 6799 | *
|
---|
[28706] | 6800 | * This is mainly for providing the testcase with some introspection to validate
|
---|
| 6801 | * behavior when closing interfaces.
|
---|
| 6802 | *
|
---|
| 6803 | * @returns The number of networks.
|
---|
[1] | 6804 | */
|
---|
[28706] | 6805 | INTNETR0DECL(uint32_t) IntNetR0GetNetworkCount(void)
|
---|
[1] | 6806 | {
|
---|
[28706] | 6807 | /*
|
---|
| 6808 | * Grab the instance.
|
---|
| 6809 | */
|
---|
| 6810 | PINTNET pIntNet = g_pIntNet;
|
---|
| 6811 | if (!pIntNet)
|
---|
| 6812 | return 0;
|
---|
| 6813 | AssertPtrReturn(pIntNet, 0);
|
---|
| 6814 | AssertReturn(pIntNet->u32Magic == INTNET_MAGIC, 0);
|
---|
[1] | 6815 |
|
---|
| 6816 | /*
|
---|
[28706] | 6817 | * Grab the mutex and count the networks.
|
---|
[1] | 6818 | */
|
---|
[28706] | 6819 | int rc = RTSemMutexRequest(pIntNet->hMtxCreateOpenDestroy, RT_INDEFINITE_WAIT);
|
---|
| 6820 | if (RT_FAILURE(rc))
|
---|
| 6821 | return 0;
|
---|
| 6822 |
|
---|
| 6823 | uint32_t cNetworks = 0;
|
---|
| 6824 | for (PINTNETNETWORK pCur = pIntNet->pNetworks; pCur; pCur = pCur->pNext)
|
---|
| 6825 | cNetworks++;
|
---|
| 6826 |
|
---|
| 6827 | RTSemMutexRelease(pIntNet->hMtxCreateOpenDestroy);
|
---|
| 6828 |
|
---|
| 6829 | return cNetworks;
|
---|
| 6830 | }
|
---|
| 6831 |
|
---|
| 6832 |
|
---|
| 6833 |
|
---|
| 6834 | /**
|
---|
| 6835 | * Destroys an instance of the Ring-0 internal networking service.
|
---|
| 6836 | */
|
---|
| 6837 | INTNETR0DECL(void) IntNetR0Term(void)
|
---|
| 6838 | {
|
---|
| 6839 | LogFlow(("IntNetR0Term:\n"));
|
---|
| 6840 |
|
---|
| 6841 | /*
|
---|
| 6842 | * Zap the global pointer and validate it.
|
---|
| 6843 | */
|
---|
| 6844 | PINTNET pIntNet = g_pIntNet;
|
---|
| 6845 | g_pIntNet = NULL;
|
---|
[1] | 6846 | if (!pIntNet)
|
---|
| 6847 | return;
|
---|
[10557] | 6848 | AssertPtrReturnVoid(pIntNet);
|
---|
[28706] | 6849 | AssertReturnVoid(pIntNet->u32Magic == INTNET_MAGIC);
|
---|
[1] | 6850 |
|
---|
| 6851 | /*
|
---|
| 6852 | * There is not supposed to be any networks hanging around at this time.
|
---|
| 6853 | */
|
---|
[28706] | 6854 | AssertReturnVoid(ASMAtomicCmpXchgU32(&pIntNet->u32Magic, ~INTNET_MAGIC, INTNET_MAGIC));
|
---|
[1] | 6855 | Assert(pIntNet->pNetworks == NULL);
|
---|
[74484] | 6856 | /*
|
---|
| 6857 | * @todo Do we really need to be paranoid enough to go over the list of networks here,
|
---|
| 6858 | * trying to terminate trunk re-connection threads here?
|
---|
[74496] | 6859 | */
|
---|
[28488] | 6860 | if (pIntNet->hMtxCreateOpenDestroy != NIL_RTSEMMUTEX)
|
---|
[1] | 6861 | {
|
---|
[28488] | 6862 | RTSemMutexDestroy(pIntNet->hMtxCreateOpenDestroy);
|
---|
| 6863 | pIntNet->hMtxCreateOpenDestroy = NIL_RTSEMMUTEX;
|
---|
[1] | 6864 | }
|
---|
[10819] | 6865 | if (pIntNet->hHtIfs != NIL_RTHANDLETABLE)
|
---|
[1] | 6866 | {
|
---|
[10819] | 6867 | /** @todo does it make sense to have a deleter here? */
|
---|
| 6868 | RTHandleTableDestroy(pIntNet->hHtIfs, NULL, NULL);
|
---|
| 6869 | pIntNet->hHtIfs = NIL_RTHANDLETABLE;
|
---|
[1] | 6870 | }
|
---|
| 6871 |
|
---|
| 6872 | RTMemFree(pIntNet);
|
---|
| 6873 | }
|
---|
| 6874 |
|
---|
| 6875 |
|
---|
| 6876 | /**
|
---|
[33540] | 6877 | * Initializes the internal network ring-0 service.
|
---|
[1] | 6878 | *
|
---|
| 6879 | * @returns VBox status code.
|
---|
| 6880 | */
|
---|
[28706] | 6881 | INTNETR0DECL(int) IntNetR0Init(void)
|
---|
[1] | 6882 | {
|
---|
[28706] | 6883 | LogFlow(("IntNetR0Init:\n"));
|
---|
[1] | 6884 | int rc = VERR_NO_MEMORY;
|
---|
| 6885 | PINTNET pIntNet = (PINTNET)RTMemAllocZ(sizeof(*pIntNet));
|
---|
| 6886 | if (pIntNet)
|
---|
| 6887 | {
|
---|
[26574] | 6888 | //pIntNet->pNetworks = NULL;
|
---|
[1] | 6889 |
|
---|
[28488] | 6890 | rc = RTSemMutexCreate(&pIntNet->hMtxCreateOpenDestroy);
|
---|
[10533] | 6891 | if (RT_SUCCESS(rc))
|
---|
[1] | 6892 | {
|
---|
[10819] | 6893 | rc = RTHandleTableCreateEx(&pIntNet->hHtIfs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
|
---|
| 6894 | UINT32_C(0x8ffe0000), 4096, intnetR0IfRetainHandle, NULL);
|
---|
[10533] | 6895 | if (RT_SUCCESS(rc))
|
---|
[1] | 6896 | {
|
---|
[28706] | 6897 | pIntNet->u32Magic = INTNET_MAGIC;
|
---|
| 6898 | g_pIntNet = pIntNet;
|
---|
| 6899 | LogFlow(("IntNetR0Init: returns VINF_SUCCESS pIntNet=%p\n", pIntNet));
|
---|
[1] | 6900 | return VINF_SUCCESS;
|
---|
| 6901 | }
|
---|
[10819] | 6902 |
|
---|
[28488] | 6903 | RTSemMutexDestroy(pIntNet->hMtxCreateOpenDestroy);
|
---|
[1] | 6904 | }
|
---|
| 6905 | RTMemFree(pIntNet);
|
---|
| 6906 | }
|
---|
[28706] | 6907 | LogFlow(("IntNetR0Init: returns %Rrc\n", rc));
|
---|
[1] | 6908 | return rc;
|
---|
| 6909 | }
|
---|
| 6910 |
|
---|