VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.7 KB
Line 
1/* $Id: VBoxNetAdp.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/** @page pg_netadp VBoxNetAdp - Network Adapter
38 *
39 * This is a kernel module that creates a virtual interface that can be attached
40 * to an internal network.
41 *
42 * In the big picture we're one of the three trunk interface on the internal
43 * network, the one named "TAP Interface": @image html Networking_Overview.gif
44 *
45 */
46
47
48/*********************************************************************************************************************************
49* Header Files *
50*********************************************************************************************************************************/
51#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
52#include "VBoxNetAdpInternal.h"
53
54#include <VBox/log.h>
55#include <VBox/err.h>
56#include <iprt/string.h>
57
58
59VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
60static uint8_t g_aUnits[VBOXNETADP_MAX_UNITS/8];
61
62
63DECLINLINE(int) vboxNetAdpGetUnitByName(const char *pcszName)
64{
65 uint32_t iUnit = RTStrToUInt32(pcszName + sizeof(VBOXNETADP_NAME) - 1);
66 bool fOld;
67
68 if (iUnit >= VBOXNETADP_MAX_UNITS)
69 return -1;
70
71 fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
72 return fOld ? -1 : (int)iUnit;
73}
74
75DECLINLINE(int) vboxNetAdpGetNextAvailableUnit(void)
76{
77 bool fOld;
78 int iUnit;
79 /* There is absolutely no chance that all units are taken */
80 do {
81 iUnit = ASMBitFirstClear(g_aUnits, VBOXNETADP_MAX_UNITS);
82 if (iUnit < 0)
83 break;
84 fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
85 } while (fOld);
86
87 return iUnit;
88}
89
90DECLINLINE(void) vboxNetAdpReleaseUnit(int iUnit)
91{
92 bool fSet = ASMAtomicBitTestAndClear(g_aUnits, iUnit);
93 NOREF(fSet);
94 Assert(fSet);
95}
96
97/**
98 * Generate a suitable MAC address.
99 *
100 * @param pThis The instance.
101 * @param pMac Where to return the MAC address.
102 */
103DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
104{
105 /* Use a locally administered version of the OUI we use for the guest NICs. */
106 pMac->au8[0] = 0x08 | 2;
107 pMac->au8[1] = 0x00;
108 pMac->au8[2] = 0x27;
109
110 pMac->au8[3] = 0; /* pThis->iUnit >> 16; */
111 pMac->au8[4] = 0; /* pThis->iUnit >> 8; */
112 pMac->au8[5] = pThis->iUnit;
113}
114
115int vboxNetAdpCreate(PVBOXNETADP *ppNew, const char *pcszName)
116{
117 int rc;
118 unsigned i;
119 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
120 {
121 PVBOXNETADP pThis = &g_aAdapters[i];
122
123 if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
124 {
125 RTMAC Mac;
126 /* Found an empty slot -- use it. */
127 Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
128 if (pcszName)
129 {
130 Log(("vboxNetAdpCreate: using name: %s\n", pcszName));
131 pThis->iUnit = vboxNetAdpGetUnitByName(pcszName);
132 strncpy(pThis->szName, pcszName, sizeof(pThis->szName) - 1);
133 pThis->szName[sizeof(pThis->szName) - 1] = '\0';
134 }
135 else
136 {
137 pThis->iUnit = vboxNetAdpGetNextAvailableUnit();
138 pThis->szName[0] = '\0';
139 }
140 if (pThis->iUnit < 0)
141 rc = VERR_INVALID_PARAMETER;
142 else
143 {
144 vboxNetAdpComposeMACAddress(pThis, &Mac);
145 rc = vboxNetAdpOsCreate(pThis, &Mac);
146 Log(("vboxNetAdpCreate: pThis=%p pThis->iUnit=%d, pThis->szName=%s\n",
147 pThis, pThis->iUnit, pThis->szName));
148 }
149 if (RT_SUCCESS(rc))
150 {
151 *ppNew = pThis;
152 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
153 Log2(("VBoxNetAdpCreate: Created %s\n", g_aAdapters[i].szName));
154 }
155 else
156 {
157 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
158 Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
159 }
160 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
161 Log2(("VBoxNetAdpCreate: Scanning entry: state=%d unit=%d name=%s\n",
162 g_aAdapters[i].enmState, g_aAdapters[i].iUnit, g_aAdapters[i].szName));
163 return rc;
164 }
165 }
166 Log(("vboxNetAdpCreate: no empty slots!\n"));
167
168 /* All slots in adapter array are busy. */
169 return VERR_OUT_OF_RESOURCES;
170}
171
172int vboxNetAdpDestroy(PVBOXNETADP pThis)
173{
174 int rc = VINF_SUCCESS;
175
176 if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
177 return VERR_INTNET_FLT_IF_BUSY;
178
179 Assert(pThis->iUnit >= 0 && pThis->iUnit < VBOXNETADP_MAX_UNITS);
180 vboxNetAdpOsDestroy(pThis);
181 vboxNetAdpReleaseUnit(pThis->iUnit);
182 pThis->iUnit = -1;
183 pThis->szName[0] = '\0';
184
185 ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
186
187 return rc;
188}
189
190int vboxNetAdpInit(void)
191{
192 unsigned i;
193 /*
194 * Init common members and call OS-specific init.
195 */
196 memset(g_aUnits, 0, sizeof(g_aUnits));
197 memset(g_aAdapters, 0, sizeof(g_aAdapters));
198 LogFlow(("vboxnetadp: max host-only interfaces supported: %d (%d bytes)\n",
199 VBOXNETADP_MAX_INSTANCES, sizeof(g_aAdapters)));
200 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
201 {
202 g_aAdapters[i].enmState = kVBoxNetAdpState_Invalid;
203 g_aAdapters[i].iUnit = -1;
204 vboxNetAdpOsInit(&g_aAdapters[i]);
205 }
206
207 return VINF_SUCCESS;
208}
209
210/**
211 * Finds an adapter by its name.
212 *
213 * @returns Pointer to the instance by the given name. NULL if not found.
214 * @param pszName The name of the instance.
215 */
216PVBOXNETADP vboxNetAdpFindByName(const char *pszName)
217{
218 unsigned i;
219
220 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
221 {
222 PVBOXNETADP pThis = &g_aAdapters[i];
223 Log2(("VBoxNetAdp: Scanning entry: state=%d name=%s\n", pThis->enmState, pThis->szName));
224 if ( strcmp(pThis->szName, pszName) == 0
225 && ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
226 return pThis;
227 }
228 return NULL;
229}
230
231void vboxNetAdpShutdown(void)
232{
233 unsigned i;
234
235 /* Remove virtual adapters */
236 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
237 vboxNetAdpDestroy(&g_aAdapters[i]);
238}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette