VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetFlt/darwin/VBoxNetAdapter-darwin.cpp@ 16805

Last change on this file since 16805 was 16741, checked in by vboxsync, 16 years ago

#2957: Cleanup of minor glitches.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: VBoxNetAdapter-darwin.cpp 16741 2009-02-13 15:08:22Z vboxsync $ */
2/** @file
3 * VBoxNetAdapter - Virtual Network Adapter Driver (Host), Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2008 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25
26#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
27#include <VBox/log.h>
28#include <VBox/err.h>
29#include <iprt/assert.h>
30#include <iprt/semaphore.h>
31#include <iprt/uuid.h>
32
33#include <sys/systm.h>
34__BEGIN_DECLS /* Buggy 10.4 headers, fixed in 10.5. */
35#include <sys/kpi_mbuf.h>
36__END_DECLS
37
38#include <net/ethernet.h>
39#include <net/if_ether.h>
40#include <net/if_types.h>
41#include <sys/socket.h>
42#include <net/if.h>
43#include <net/if_dl.h>
44#include <sys/errno.h>
45#include <sys/param.h>
46
47#define VBOXNETADA_MAX_INSTANCES 8
48#define VBOXNETADA_MAX_FAMILIES 4
49#define VBOXNETADA_NAME "vboxnet"
50#define VBOXNETADA_MTU 1500
51#define VBOXNETADA_DETACH_TIMEOUT 500
52
53#define VBOXNETADA_FROM_IFACE(iface) ((PVBOXNETADA) ifnet_softc(iface))
54
55/**
56 * Void NETADAs mark vacant slots in NETADA array. Valid NETADAs are busy slots.
57 * As soon as slot is being modified its state changes to transitional.
58 * NETADAs in transitional state must only be accessed by the thread that
59 * put it to this state.
60 */
61enum VBoxNetAdaState
62{
63 VBOXNETADA_ST_VOID,
64 VBOXNETADA_ST_TRANSITIONAL,
65 VBOXNETADA_ST_VALID
66};
67typedef enum VBoxNetAdaState VBOXNETADASTATE;
68
69struct VBoxNetAda
70{
71 /** Mutex protecting access to enmState. */
72 RTSEMFASTMUTEX hStateMtx;
73 /** Denotes availability of this NETADA. */
74 VBOXNETADASTATE enmState;
75 /** Corresponds to the digit at the end of NETADA name. */
76 uint8_t uUnit;
77 /** Event to signal detachment of interface. */
78 RTSEMEVENT hEvtDetached;
79 /** Pointer to Darwin interface structure. */
80 ifnet_t pIface;
81 /* todo: MAC address? */
82 /** Protocol families attached to this NETADA. */
83 protocol_family_t aAttachedFamilies[VBOXNETADA_MAX_FAMILIES];
84};
85typedef struct VBoxNetAda VBOXNETADA;
86typedef VBOXNETADA *PVBOXNETADA;
87
88VBOXNETADA g_aAdapters[VBOXNETADA_MAX_INSTANCES];
89
90DECLINLINE(bool) vboxNetAdaIsValid(PVBOXNETADA pAda)
91{
92 return pAda->enmState == VBOXNETADA_ST_VALID;
93}
94
95DECLINLINE(bool) vboxNetAdaIsVoid(PVBOXNETADA pAda)
96{
97 return pAda->enmState == VBOXNETADA_ST_VOID;
98}
99
100static void vboxNetAdaComposeMACAddress(PVBOXNETADA pAda, PCRTMAC pCustomMac, struct sockaddr_dl *pMac)
101{
102 pMac->sdl_len = sizeof(*pMac);
103 pMac->sdl_family = AF_LINK;
104 pMac->sdl_alen = ETHER_ADDR_LEN;
105 pMac->sdl_nlen = 0;
106 pMac->sdl_slen = 0;
107 if (pMac)
108 memcpy(LLADDR(pMac), pCustomMac->au8, ETHER_ADDR_LEN);
109 else
110 {
111 memcpy(LLADDR(pMac), "\0vbox0", pMac->sdl_alen);
112 LLADDR(pMac)[ETHER_ADDR_LEN - 1] += pAda->uUnit;
113 }
114}
115
116static void vboxNetAdaComposeUUID(PVBOXNETADA pAda, PRTUUID pUuid)
117{
118 /* Generate UUID from name and MAC address. */
119 RTUuidClear(pUuid);
120 memcpy(pUuid->au8, "vboxnet", 7);
121 pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
122 pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
123 pUuid->Gen.u8ClockSeqLow = pAda->uUnit;
124 memcpy(pUuid->Gen.au8Node, "\0vbox0", sizeof(pUuid->Gen.au8Node));
125 pUuid->Gen.au8Node[sizeof(pUuid->Gen.au8Node) - 1] += pAda->uUnit;
126}
127
128
129static errno_t vboxNetAdaOutput(ifnet_t pIface, mbuf_t pMBuf)
130{
131 mbuf_freem_list(pMBuf);
132 return 0;
133}
134
135static void vboxNetAdaAttachFamily(PVBOXNETADA pAda, protocol_family_t Family)
136{
137 u_int32_t i;
138 for (i = 0; i < VBOXNETADA_MAX_FAMILIES; i++)
139 if (pAda->aAttachedFamilies[i] == 0)
140 {
141 pAda->aAttachedFamilies[i] = Family;
142 break;
143 }
144}
145
146static void vboxNetAdaDetachFamily(PVBOXNETADA pAda, protocol_family_t Family)
147{
148 u_int32_t i;
149 for (i = 0; i < VBOXNETADA_MAX_FAMILIES; i++)
150 if (pAda->aAttachedFamilies[i] == Family)
151 pAda->aAttachedFamilies[i] = 0;
152}
153
154static errno_t vboxNetAdaAddProto(ifnet_t pIface, protocol_family_t Family, const struct ifnet_demux_desc *pDemuxDesc, u_int32_t nDesc)
155{
156 PVBOXNETADA pAda = VBOXNETADA_FROM_IFACE(pIface);
157 Assert(pAda);
158 vboxNetAdaAttachFamily(pAda, Family);
159 LogFlow(("vboxNetAdaAddProto: Family=%d.\n", Family));
160 return ether_add_proto(pIface, Family, pDemuxDesc, nDesc);
161}
162
163static errno_t vboxNetAdaDelProto(ifnet_t pIface, protocol_family_t Family)
164{
165 PVBOXNETADA pAda = VBOXNETADA_FROM_IFACE(pIface);
166 Assert(pAda);
167 LogFlow(("vboxNetAdaDelProto: Family=%d.\n", Family));
168 vboxNetAdaDetachFamily(pAda, Family);
169 return ether_del_proto(pIface, Family);
170}
171
172static void vboxNetAdaDetach(ifnet_t pIface)
173{
174 PVBOXNETADA pAda = VBOXNETADA_FROM_IFACE(pIface);
175 Assert(pAda);
176 Log2(("vboxNetAdaDetach: Signaling detach to vboxNetAdaUnregisterDevice.\n"));
177 /* Let vboxNetAdaUnregisterDevice know that the interface has been detached. */
178 RTSemEventSignal(pAda->hEvtDetached);
179}
180
181
182static int vboxNetAdaRegisterDevice(PVBOXNETADA pAda, const struct sockaddr_dl *pMACAddress)
183{
184 struct ifnet_init_params Params;
185 RTUUID uuid;
186
187 vboxNetAdaComposeUUID(pAda, &uuid);
188 Params.uniqueid = uuid.au8;
189 Params.uniqueid_len = sizeof(uuid);
190 Params.name = VBOXNETADA_NAME;
191 Params.unit = pAda->uUnit;
192 Params.family = IFNET_FAMILY_ETHERNET;
193 Params.type = IFT_ETHER;
194 Params.output = vboxNetAdaOutput;
195 Params.demux = ether_demux;
196 Params.add_proto = vboxNetAdaAddProto;
197 Params.del_proto = vboxNetAdaDelProto;
198 Params.check_multi = ether_check_multi;
199 Params.framer = ether_frameout;
200 Params.softc = pAda;
201 Params.ioctl = ether_ioctl;
202 Params.set_bpf_tap = NULL;
203 Params.detach = vboxNetAdaDetach;
204 Params.event = NULL;
205 Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
206 Params.broadcast_len = ETHER_ADDR_LEN;
207
208 errno_t err = ifnet_allocate(&Params, &pAda->pIface);
209 if (!err)
210 {
211 err = ifnet_attach(pAda->pIface, pMACAddress);
212 if (!err)
213 {
214 err = ifnet_set_flags(pAda->pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
215 if (!err)
216 {
217 ifnet_set_mtu(pAda->pIface, VBOXNETADA_MTU);
218 return VINF_SUCCESS;
219 }
220 else
221 Log(("vboxNetAdaRegisterDevice: Failed to set flags (err=%d).\n", err));
222 ifnet_detach(pAda->pIface);
223 }
224 else
225 Log(("vboxNetAdaRegisterDevice: Failed to attach to interface (err=%d).\n", err));
226 ifnet_release(pAda->pIface);
227 }
228 else
229 Log(("vboxNetAdaRegisterDevice: Failed to allocate interface (err=%d).\n", err));
230
231 return RTErrConvertFromErrno(err);
232}
233
234static int vboxNetAdaUnregisterDevice(PVBOXNETADA pAda)
235{
236 u_int32_t i;
237 /* Bring down the interface */
238 int rc = VINF_SUCCESS;
239 errno_t err = ifnet_set_flags(pAda->pIface, 0, IFF_UP | IFF_RUNNING);
240 if (err)
241 Log(("vboxNetAdaUnregisterDevice: Failed to bring down interface "
242 "(err=%d).\n", err));
243 /* Detach all protocols. */
244 for (i = 0; i < VBOXNETADA_MAX_FAMILIES; i++)
245 if (pAda->aAttachedFamilies[i])
246 ifnet_detach_protocol(pAda->pIface, pAda->aAttachedFamilies[i]);
247 err = ifnet_detach(pAda->pIface);
248 if (err)
249 Log(("vboxNetAdaUnregisterDevice: Failed to detach interface "
250 "(err=%d).\n", err));
251 Log2(("vboxNetAdaUnregisterDevice: Waiting for 'detached' event...\n"));
252 /* Wait until we get a signal from detach callback. */
253 rc = RTSemEventWait(pAda->hEvtDetached, VBOXNETADA_DETACH_TIMEOUT);
254 if (rc == VERR_TIMEOUT)
255 LogRel(("VBoxNETADA: Failed to detach interface %s%d\n.",
256 VBOXNETADA_NAME, pAda->uUnit));
257 err = ifnet_release(pAda->pIface);
258 if (err)
259 Log(("vboxNetAdaUnregisterDevice: Failed to release interface (err=%d).\n", err));
260
261 return rc;
262}
263
264int vboxNetAdaCreate (PVBOXNETADA *ppAda, PCRTMAC pMac)
265{
266 int rc;
267 unsigned i;
268
269 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
270 {
271 PVBOXNETADA pAda = &g_aAdapters[i];
272 RTSemFastMutexRequest(pAda->hStateMtx);
273 if (vboxNetAdaIsVoid(pAda))
274 {
275 pAda->enmState = VBOXNETADA_ST_TRANSITIONAL;
276 RTSemFastMutexRelease(pAda->hStateMtx);
277 /* Found an empty slot -- use it. */
278 struct sockaddr_dl mac;
279 Assert(pAda->hEvtDetached == NIL_RTSEMEVENT);
280 rc = RTSemEventCreate(&pAda->hEvtDetached);
281 if (RT_FAILURE(rc))
282 return rc;
283 pAda->uUnit = i;
284 vboxNetAdaComposeMACAddress(pAda, pMac, &mac);
285 rc = vboxNetAdaRegisterDevice(pAda, &mac);
286 *ppAda = pAda;
287 RTSemFastMutexRequest(pAda->hStateMtx);
288 pAda->enmState = VBOXNETADA_ST_VALID;
289 RTSemFastMutexRelease(pAda->hStateMtx);
290 return rc;
291 }
292 RTSemFastMutexRelease(pAda->hStateMtx);
293 }
294
295 /* All slots in adapter array are busy. */
296 return VERR_OUT_OF_RESOURCES;
297}
298
299int vboxNetAdaDestroy (PVBOXNETADA pAda)
300{
301 int rc;
302
303 RTSemFastMutexRequest(pAda->hStateMtx);
304 if (!vboxNetAdaIsValid(pAda))
305 {
306 RTSemFastMutexRelease(pAda->hStateMtx);
307 return VERR_INVALID_PARAMETER;
308 }
309 pAda->enmState = VBOXNETADA_ST_TRANSITIONAL;
310 RTSemFastMutexRelease(pAda->hStateMtx);
311
312 rc = vboxNetAdaUnregisterDevice(pAda);
313 if (RT_FAILURE(rc))
314 Log(("vboxNetAdaDestroy: Failed to unregister device (rc=%Rrc).\n", rc));
315
316 RTSemEventDestroy(pAda->hEvtDetached);
317 pAda->hEvtDetached = NIL_RTSEMEVENT;
318
319 RTSemFastMutexRequest(pAda->hStateMtx);
320 pAda->enmState = VBOXNETADA_ST_VOID;
321 RTSemFastMutexRelease(pAda->hStateMtx);
322
323 return rc;
324}
325
326int vboxNetAdaModuleStart(void)
327{
328 memset(&g_aAdapters, 0, sizeof(g_aAdapters));
329 for (unsigned i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
330 {
331 int rc = RTSemFastMutexCreate(&g_aAdapters[i].hStateMtx);
332 if (RT_FAILURE(rc))
333 {
334 Log(("vboxNetAdaModuleStart: Failed to create fast mutex (rc=%Rrc).\n", rc));
335 return rc;
336 }
337 }
338
339 return VINF_SUCCESS;
340}
341
342int vboxNetAdaModuleStop(void)
343{
344 int rc;
345 unsigned i;
346
347 for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
348 {
349 vboxNetAdaDestroy(&g_aAdapters[i]);
350 rc = RTSemFastMutexDestroy(g_aAdapters[i].hStateMtx);
351 if (RT_FAILURE(rc))
352 Log(("vboxNetAdaModuleStop: Failed to destroy fast mutex (rc=%Rrc).\n", rc));
353 }
354
355 return VINF_SUCCESS;
356}
357
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