VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c@ 41199

Last change on this file since 41199 was 41199, checked in by vboxsync, 12 years ago

VBoxNetAdp/freebsd: Fix crash during destruction

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.6 KB
Line 
1/* $Id: VBoxNetAdp-freebsd.c 41199 2012-05-08 08:25:20Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), FreeBSD Specific Code.
4 */
5
6/*-
7 * Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <sys/param.h>
35#undef PVM
36#include <sys/types.h>
37#include <sys/module.h>
38#include <sys/systm.h>
39#include <sys/errno.h>
40#include <sys/kernel.h>
41#include <sys/fcntl.h>
42#include <sys/conf.h>
43#include <sys/uio.h>
44#include <sys/socket.h>
45#include <sys/sockio.h>
46
47#include <net/if.h>
48#include <net/if_var.h>
49#include <net/route.h>
50#include <net/if_dl.h>
51#include <net/if_types.h>
52#include <net/ethernet.h>
53#include <net/bpf.h>
54
55#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
56#include <VBox/version.h>
57#include <VBox/err.h>
58#include <VBox/log.h>
59#include <iprt/initterm.h>
60#include <iprt/string.h>
61#include <iprt/spinlock.h>
62#include <iprt/process.h>
63#include <iprt/assert.h>
64#include <iprt/uuid.h>
65#include <iprt/alloc.h>
66#include <iprt/err.h>
67
68#define VBOXNETADP_OS_SPECFIC 1
69#include "../VBoxNetAdpInternal.h"
70
71#if defined(__FreeBSD_version) && __FreeBSD_version >= 800500
72# include <sys/jail.h>
73# include <net/vnet.h>
74
75# define VBOXCURVNET_SET(arg) CURVNET_SET_QUIET(arg)
76# define VBOXCURVNET_SET_FROM_UCRED() VBOXCURVNET_SET(CRED_TO_VNET(curthread->td_ucred))
77# define VBOXCURVNET_RESTORE() CURVNET_RESTORE()
78
79#else /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
80
81# define VBOXCURVNET_SET(arg)
82# define VBOXCURVNET_SET_FROM_UCRED()
83# define VBOXCURVNET_RESTORE()
84
85#endif /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
86
87static int VBoxNetAdpFreeBSDCtrlioctl(struct cdev *, u_long, caddr_t, int flags,
88 struct thread *);
89static struct cdevsw vboxnetadp_cdevsw =
90{
91 .d_version = D_VERSION,
92 .d_ioctl = VBoxNetAdpFreeBSDCtrlioctl,
93 .d_read = (d_read_t *)nullop,
94 .d_write = (d_write_t *)nullop,
95 .d_name = VBOXNETADP_CTL_DEV_NAME,
96};
97
98static struct cdev *VBoxNetAdpFreeBSDcdev;
99
100static int VBoxNetAdpFreeBSDModuleEvent(struct module *, int, void *);
101static moduledata_t g_VBoxNetAdpFreeBSDModule = {
102 "vboxnetadp",
103 VBoxNetAdpFreeBSDModuleEvent,
104 NULL
105};
106
107/** Declare the module as a pseudo device. */
108DECLARE_MODULE(vboxnetadp, g_VBoxNetAdpFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
109MODULE_VERSION(vboxnetadp, 1);
110MODULE_DEPEND(vboxnetadp, vboxdrv, 1, 1, 1);
111MODULE_DEPEND(vboxnetadp, vboxnetflt, 1, 1, 1);
112
113/**
114 * Module event handler
115 */
116static int
117VBoxNetAdpFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
118{
119 int rc = 0;
120
121 Log(("VBoxNetAdpFreeBSDModuleEvent\n"));
122
123 switch (enmEventType)
124 {
125 case MOD_LOAD:
126 rc = RTR0Init(0);
127 if (RT_FAILURE(rc))
128 {
129 Log(("RTR0Init failed %d\n", rc));
130 return RTErrConvertToErrno(rc);
131 }
132 rc = vboxNetAdpInit();
133 if (RT_FAILURE(rc))
134 {
135 RTR0Term();
136 Log(("vboxNetAdpInit failed %d\n", rc));
137 return RTErrConvertToErrno(rc);
138 }
139 /* Create dev node */
140 VBoxNetAdpFreeBSDcdev = make_dev(&vboxnetadp_cdevsw, 0,
141 UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
142
143 break;
144
145 case MOD_UNLOAD:
146 vboxNetAdpShutdown();
147 destroy_dev(VBoxNetAdpFreeBSDcdev);
148 RTR0Term();
149 break;
150 case MOD_SHUTDOWN:
151 case MOD_QUIESCE:
152 default:
153 return EOPNOTSUPP;
154 }
155
156 if (RT_SUCCESS(rc))
157 return 0;
158 return RTErrConvertToErrno(rc);
159}
160
161/**
162 * Device I/O Control entry point.
163 */
164static int
165VBoxNetAdpFreeBSDCtrlioctl(struct cdev *dev, u_long iCmd, caddr_t data, int flags, struct thread *td)
166{
167 PVBOXNETADP pAdp;
168 PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)data;
169 struct ifnet *ifp;
170 int rc;
171
172 switch (iCmd)
173 {
174 case VBOXNETADP_CTL_ADD:
175 if ( !(iCmd & IOC_INOUT) /* paranoia*/
176 || IOCPARM_LEN(iCmd) < sizeof(*pReq))
177 return EINVAL;
178
179 rc = vboxNetAdpCreate(&pAdp,
180 pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(IOCPARM_LEN(iCmd), sizeof(pReq->szName))) ?
181 pReq->szName : NULL);
182 if (RT_FAILURE(rc))
183 return EINVAL;
184
185 strncpy(pReq->szName, pAdp->szName, sizeof(pReq->szName) - 1);
186 pReq->szName[sizeof(pReq->szName) - 1] = '\0';
187 break;
188
189 case VBOXNETADP_CTL_REMOVE:
190 if (!RTStrEnd(pReq->szName, RT_MIN(sizeof(pReq->szName), IOCPARM_LEN(iCmd))))
191 return EINVAL;
192
193 pAdp = vboxNetAdpFindByName(pReq->szName);
194 if (!pAdp)
195 return EINVAL;
196
197 rc = vboxNetAdpDestroy(pAdp);
198 if (RT_FAILURE(rc))
199 return EINVAL;
200
201 break;
202
203 default:
204 return EINVAL;
205 }
206 return 0;
207}
208
209/**
210 * Initialize device, just set the running flag.
211 */
212static void VBoxNetAdpFreeBSDNetinit(void *priv)
213{
214 PVBOXNETADP pThis = priv;
215 struct ifnet *ifp = pThis->u.s.ifp;
216
217 ifp->if_drv_flags |= IFF_DRV_RUNNING;
218}
219
220/**
221 * Transmit packets.
222 * netflt has already done everything for us so we just hand the
223 * packets to BPF and increment the packet stats.
224 */
225static void VBoxNetAdpFreeBSDNetstart(struct ifnet *ifp)
226{
227 PVBOXNETADP pThis = ifp->if_softc;
228 struct mbuf *m;
229
230 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
231 return;
232
233 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
234 while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
235 {
236 ifp->if_opackets++;
237 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
238 BPF_MTAP(ifp, m);
239 m_freem(m);
240 }
241 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
242}
243
244/**
245 * Interface ioctl handling
246 */
247static int VBoxNetAdpFreeBSDNetioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
248{
249 switch (cmd)
250 {
251 case SIOCSIFFLAGS:
252 if (ifp->if_flags & IFF_UP)
253 {
254 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
255 ifp->if_init(ifp->if_softc);
256 }
257 else
258 {
259 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
260 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
261 }
262 break;
263 default:
264 return ether_ioctl(ifp, cmd, data);
265 }
266 return 0;
267}
268
269int vboxNetAdpOsInit(PVBOXNETADP pThis)
270{
271 pThis->u.s.ifp = NULL;
272 return VINF_SUCCESS;;
273}
274
275int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMac)
276{
277 struct ifnet *ifp;
278
279 VBOXCURVNET_SET_FROM_UCRED();
280 ifp = if_alloc(IFT_ETHER);
281 if (ifp == NULL)
282 return VERR_NO_MEMORY;
283
284 if_initname(ifp, VBOXNETADP_NAME, pThis->iUnit);
285 ifp->if_softc = pThis;
286 ifp->if_mtu = ETHERMTU;
287 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
288 ifp->if_ioctl = VBoxNetAdpFreeBSDNetioctl;
289 ifp->if_start = VBoxNetAdpFreeBSDNetstart;
290 ifp->if_init = VBoxNetAdpFreeBSDNetinit;
291 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
292 ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
293 IFQ_SET_READY(&ifp->if_snd);
294 ether_ifattach(ifp, (void *)pMac);
295 ifp->if_baudrate = 0;
296
297 strncpy(pThis->szName, ifp->if_xname, VBOXNETADP_MAX_NAME_LEN);
298 pThis->u.s.ifp = ifp;
299 VBOXCURVNET_RESTORE();
300 return 0;
301}
302
303void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
304{
305 struct ifnet *ifp;
306
307 ifp = pThis->u.s.ifp;
308 VBOXCURVNET_SET(ifp->if_vnet);
309 ether_ifdetach(ifp);
310 if_free(ifp);
311 VBOXCURVNET_RESTORE();
312}
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