%PDF- %PDF-
| Direktori : /proc/self/root/usr/share/virtualbox/src/vboxhost/vboxnetadp/ |
| Current File : //proc/self/root/usr/share/virtualbox/src/vboxhost/vboxnetadp/VBoxNetAdp.c |
/* $Id: VBoxNetAdp.c 155244 2023-01-17 14:15:46Z bird $ */
/** @file
* VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
*/
/*
* Copyright (C) 2008-2023 Oracle and/or its affiliates.
*
* This file is part of VirtualBox base platform packages, as
* available from https://www.virtualbox.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, in version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses>.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
* in the VirtualBox distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*
* SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
*/
/** @page pg_netadp VBoxNetAdp - Network Adapter
*
* This is a kernel module that creates a virtual interface that can be attached
* to an internal network.
*
* In the big picture we're one of the three trunk interface on the internal
* network, the one named "TAP Interface": @image html Networking_Overview.gif
*
*/
/*********************************************************************************************************************************
* Header Files *
*********************************************************************************************************************************/
#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
#include "VBoxNetAdpInternal.h"
#include <VBox/log.h>
#include <VBox/err.h>
#include <iprt/string.h>
VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
static uint8_t g_aUnits[VBOXNETADP_MAX_UNITS/8];
DECLINLINE(int) vboxNetAdpGetUnitByName(const char *pcszName)
{
uint32_t iUnit = RTStrToUInt32(pcszName + sizeof(VBOXNETADP_NAME) - 1);
bool fOld;
if (iUnit >= VBOXNETADP_MAX_UNITS)
return -1;
fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
return fOld ? -1 : (int)iUnit;
}
DECLINLINE(int) vboxNetAdpGetNextAvailableUnit(void)
{
bool fOld;
int iUnit;
/* There is absolutely no chance that all units are taken */
do {
iUnit = ASMBitFirstClear(g_aUnits, VBOXNETADP_MAX_UNITS);
if (iUnit < 0)
break;
fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
} while (fOld);
return iUnit;
}
DECLINLINE(void) vboxNetAdpReleaseUnit(int iUnit)
{
bool fSet = ASMAtomicBitTestAndClear(g_aUnits, iUnit);
NOREF(fSet);
Assert(fSet);
}
/**
* Generate a suitable MAC address.
*
* @param pThis The instance.
* @param pMac Where to return the MAC address.
*/
DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
{
/* Use a locally administered version of the OUI we use for the guest NICs. */
pMac->au8[0] = 0x08 | 2;
pMac->au8[1] = 0x00;
pMac->au8[2] = 0x27;
pMac->au8[3] = 0; /* pThis->iUnit >> 16; */
pMac->au8[4] = 0; /* pThis->iUnit >> 8; */
pMac->au8[5] = pThis->iUnit;
}
int vboxNetAdpCreate(PVBOXNETADP *ppNew, const char *pcszName)
{
int rc;
unsigned i;
for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
{
PVBOXNETADP pThis = &g_aAdapters[i];
if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
{
RTMAC Mac;
/* Found an empty slot -- use it. */
Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
if (pcszName)
{
Log(("vboxNetAdpCreate: using name: %s\n", pcszName));
pThis->iUnit = vboxNetAdpGetUnitByName(pcszName);
strncpy(pThis->szName, pcszName, sizeof(pThis->szName) - 1);
pThis->szName[sizeof(pThis->szName) - 1] = '\0';
}
else
{
pThis->iUnit = vboxNetAdpGetNextAvailableUnit();
pThis->szName[0] = '\0';
}
if (pThis->iUnit < 0)
rc = VERR_INVALID_PARAMETER;
else
{
vboxNetAdpComposeMACAddress(pThis, &Mac);
rc = vboxNetAdpOsCreate(pThis, &Mac);
Log(("vboxNetAdpCreate: pThis=%p pThis->iUnit=%d, pThis->szName=%s\n",
pThis, pThis->iUnit, pThis->szName));
}
if (RT_SUCCESS(rc))
{
*ppNew = pThis;
ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
Log2(("VBoxNetAdpCreate: Created %s\n", g_aAdapters[i].szName));
}
else
{
ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
}
for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
Log2(("VBoxNetAdpCreate: Scanning entry: state=%d unit=%d name=%s\n",
g_aAdapters[i].enmState, g_aAdapters[i].iUnit, g_aAdapters[i].szName));
return rc;
}
}
Log(("vboxNetAdpCreate: no empty slots!\n"));
/* All slots in adapter array are busy. */
return VERR_OUT_OF_RESOURCES;
}
int vboxNetAdpDestroy(PVBOXNETADP pThis)
{
int rc = VINF_SUCCESS;
if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
return VERR_INTNET_FLT_IF_BUSY;
Assert(pThis->iUnit >= 0 && pThis->iUnit < VBOXNETADP_MAX_UNITS);
vboxNetAdpOsDestroy(pThis);
vboxNetAdpReleaseUnit(pThis->iUnit);
pThis->iUnit = -1;
pThis->szName[0] = '\0';
ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
return rc;
}
int vboxNetAdpInit(void)
{
unsigned i;
/*
* Init common members and call OS-specific init.
*/
memset(g_aUnits, 0, sizeof(g_aUnits));
memset(g_aAdapters, 0, sizeof(g_aAdapters));
LogFlow(("vboxnetadp: max host-only interfaces supported: %d (%d bytes)\n",
VBOXNETADP_MAX_INSTANCES, sizeof(g_aAdapters)));
for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
{
g_aAdapters[i].enmState = kVBoxNetAdpState_Invalid;
g_aAdapters[i].iUnit = -1;
vboxNetAdpOsInit(&g_aAdapters[i]);
}
return VINF_SUCCESS;
}
/**
* Finds an adapter by its name.
*
* @returns Pointer to the instance by the given name. NULL if not found.
* @param pszName The name of the instance.
*/
PVBOXNETADP vboxNetAdpFindByName(const char *pszName)
{
unsigned i;
for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
{
PVBOXNETADP pThis = &g_aAdapters[i];
Log2(("VBoxNetAdp: Scanning entry: state=%d name=%s\n", pThis->enmState, pThis->szName));
if ( strcmp(pThis->szName, pszName) == 0
&& ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
return pThis;
}
return NULL;
}
void vboxNetAdpShutdown(void)
{
unsigned i;
/* Remove virtual adapters */
for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
vboxNetAdpDestroy(&g_aAdapters[i]);
}