VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c@ 26977

Last change on this file since 26977 was 25465, checked in by vboxsync, 15 years ago

SUPDrv,++: Made SUPDrv.c platform agnostic and renamed SUPDrvAgnostic.c to SUPDrvSem.c. dprintf and dprintf2 are no more (Log/Log2), while OSDBGPRINT simply calls SUPR0Printf.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: VBoxNetAdp-linux.c 25465 2009-12-17 14:49:34Z vboxsync $ */
2/** @file
3 * VBoxNetAdp - Virtual Network Adapter Driver (Host), Linux Specific Code.
4 */
5
6/*
7 * Copyright (C) 2009 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#include "the-linux-kernel.h"
26#include "version-generated.h"
27#include <linux/netdevice.h>
28#include <linux/etherdevice.h>
29#include <linux/miscdevice.h>
30
31#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
32#include <VBox/log.h>
33#include <VBox/err.h>
34#include <iprt/process.h>
35#include <iprt/initterm.h>
36#include <iprt/mem.h>
37
38/*
39#include <iprt/assert.h>
40#include <iprt/semaphore.h>
41#include <iprt/spinlock.h>
42#include <iprt/string.h>
43#include <iprt/uuid.h>
44#include <iprt/alloca.h>
45*/
46
47#define VBOXNETADP_OS_SPECFIC 1
48#include "../VBoxNetAdpInternal.h"
49
50/*******************************************************************************
51* Defined Constants And Macros *
52*******************************************************************************/
53#define VBOXNETADP_LINUX_NAME "vboxnet%d"
54#define VBOXNETADP_CTL_DEV_NAME "vboxnetctl"
55
56#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
57
58/*******************************************************************************
59* Internal Functions *
60*******************************************************************************/
61static int VBoxNetAdpLinuxInit(void);
62static void VBoxNetAdpLinuxUnload(void);
63
64static int VBoxNetAdpLinuxOpen(struct inode *pInode, struct file *pFilp);
65static int VBoxNetAdpLinuxClose(struct inode *pInode, struct file *pFilp);
66static int VBoxNetAdpLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
67
68/*******************************************************************************
69* Global Variables *
70*******************************************************************************/
71module_init(VBoxNetAdpLinuxInit);
72module_exit(VBoxNetAdpLinuxUnload);
73
74MODULE_AUTHOR("Sun Microsystems, Inc.");
75MODULE_DESCRIPTION("VirtualBox Network Adapter Driver");
76MODULE_LICENSE("GPL");
77#ifdef MODULE_VERSION
78MODULE_VERSION(VBOX_VERSION_STRING " (" RT_XSTR(INTNETTRUNKIFPORT_VERSION) ")");
79#endif
80
81/**
82 * The (common) global data.
83 */
84static struct file_operations gFileOpsVBoxNetAdp =
85{
86 owner: THIS_MODULE,
87 open: VBoxNetAdpLinuxOpen,
88 release: VBoxNetAdpLinuxClose,
89 ioctl: VBoxNetAdpLinuxIOCtl,
90};
91
92/** The miscdevice structure. */
93static struct miscdevice g_CtlDev =
94{
95 minor: MISC_DYNAMIC_MINOR,
96 name: VBOXNETADP_CTL_DEV_NAME,
97 fops: &gFileOpsVBoxNetAdp,
98# if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
99 devfs_name: VBOXNETADP_CTL_DEV_NAME
100# endif
101};
102
103struct VBoxNetAdpPriv
104{
105 struct net_device_stats Stats;
106};
107
108typedef struct VBoxNetAdpPriv VBOXNETADPPRIV;
109typedef VBOXNETADPPRIV *PVBOXNETADPPRIV;
110
111static int vboxNetAdpLinuxOpen(struct net_device *pNetDev)
112{
113 netif_start_queue(pNetDev);
114 printk("vboxNetAdpOpen returns 0\n");
115 return 0;
116}
117
118static int vboxNetAdpLinuxStop(struct net_device *pNetDev)
119{
120 netif_stop_queue(pNetDev);
121 return 0;
122}
123
124static int vboxNetAdpLinuxXmit(struct sk_buff *pSkb, struct net_device *pNetDev)
125{
126 PVBOXNETADPPRIV pPriv = netdev_priv(pNetDev);
127
128 /* Update the stats. */
129 pPriv->Stats.tx_packets++;
130 pPriv->Stats.tx_bytes += pSkb->len;
131 /* Update transmission time stamp. */
132 pNetDev->trans_start = jiffies;
133 /* Nothing else to do, just free the sk_buff. */
134 dev_kfree_skb(pSkb);
135 return 0;
136}
137
138struct net_device_stats *vboxNetAdpLinuxGetStats(struct net_device *pNetDev)
139{
140 PVBOXNETADPPRIV pPriv = netdev_priv(pNetDev);
141 return &pPriv->Stats;
142}
143
144#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
145static const struct net_device_ops vboxNetAdpNetdevOps = {
146 .ndo_open = vboxNetAdpLinuxOpen,
147 .ndo_stop = vboxNetAdpLinuxStop,
148 .ndo_start_xmit = vboxNetAdpLinuxXmit,
149 .ndo_get_stats = vboxNetAdpLinuxGetStats
150};
151#endif
152
153static void vboxNetAdpNetDevInit(struct net_device *pNetDev)
154{
155 PVBOXNETADPPRIV pPriv;
156
157 ether_setup(pNetDev);
158#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
159 pNetDev->netdev_ops = &vboxNetAdpNetdevOps;
160#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) */
161 pNetDev->open = vboxNetAdpLinuxOpen;
162 pNetDev->stop = vboxNetAdpLinuxStop;
163 pNetDev->hard_start_xmit = vboxNetAdpLinuxXmit;
164 pNetDev->get_stats = vboxNetAdpLinuxGetStats;
165#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) */
166
167 pPriv = netdev_priv(pNetDev);
168 memset(pPriv, 0, sizeof(*pPriv));
169}
170
171
172int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
173{
174 int rc = VINF_SUCCESS;
175 struct net_device *pNetDev;
176
177 /* No need for private data. */
178 pNetDev = alloc_netdev(sizeof(VBOXNETADPPRIV), VBOXNETADP_LINUX_NAME, vboxNetAdpNetDevInit);
179 if (pNetDev)
180 {
181 int err;
182
183 memcpy(pNetDev->dev_addr, pMACAddress, ETH_ALEN);
184 Log2(("vboxNetAdpOsCreate: pNetDev->dev_addr = %.6Rhxd\n", pNetDev->dev_addr));
185 err = register_netdev(pNetDev);
186 if (!err)
187 {
188 strncpy(pThis->szName, pNetDev->name, VBOXNETADP_MAX_NAME_LEN);
189 pThis->u.s.pNetDev = pNetDev;
190 Log2(("vboxNetAdpOsCreate: pThis=%p pThis->szName = %p\n", pThis, pThis->szName));
191 return VINF_SUCCESS;
192 }
193 free_netdev(pNetDev);
194 rc = RTErrConvertFromErrno(err);
195 }
196 return rc;
197}
198
199void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
200{
201 struct net_device *pNetDev = pThis->u.s.pNetDev;
202 AssertPtr(pThis->u.s.pNetDev);
203
204 pThis->u.s.pNetDev = NULL;
205 unregister_netdev(pNetDev);
206 free_netdev(pNetDev);
207}
208
209/**
210 * Device open. Called on open /dev/vboxnetctl
211 *
212 * @param pInode Pointer to inode info structure.
213 * @param pFilp Associated file pointer.
214 */
215static int VBoxNetAdpLinuxOpen(struct inode *pInode, struct file *pFilp)
216{
217 Log(("VBoxNetAdpLinuxOpen: pid=%d/%d %s\n", RTProcSelf(), current->pid, current->comm));
218
219 /*
220 * Only root is allowed to access the device, enforce it!
221 */
222 if (!capable(CAP_SYS_ADMIN))
223 {
224 Log(("VBoxNetAdpLinuxOpen: admin privileges required!\n"));
225 return -EPERM;
226 }
227
228 return 0;
229}
230
231
232/**
233 * Close device.
234 *
235 * @param pInode Pointer to inode info structure.
236 * @param pFilp Associated file pointer.
237 */
238static int VBoxNetAdpLinuxClose(struct inode *pInode, struct file *pFilp)
239{
240 Log(("VBoxNetAdpLinuxClose: pid=%d/%d %s\n",
241 RTProcSelf(), current->pid, current->comm));
242 pFilp->private_data = NULL;
243 return 0;
244}
245
246/**
247 * Device I/O Control entry point.
248 *
249 * @param pFilp Associated file pointer.
250 * @param uCmd The function specified to ioctl().
251 * @param ulArg The argument specified to ioctl().
252 */
253static int VBoxNetAdpLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
254{
255 VBOXNETADPREQ Req;
256 PVBOXNETADP pAdp;
257 int rc;
258
259 Log(("VBoxNetAdpLinuxIOCtl: param len %#x; uCmd=%#x; add=%#x\n", _IOC_SIZE(uCmd), uCmd, VBOXNETADP_CTL_ADD));
260 if (RT_UNLIKELY(_IOC_SIZE(uCmd) != sizeof(Req))) /* paraonia */
261 {
262 Log(("VBoxNetAdpLinuxIOCtl: bad ioctl sizeof(Req)=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", sizeof(Req), _IOC_SIZE(uCmd), uCmd));
263 return -EINVAL;
264 }
265
266 switch (uCmd)
267 {
268 case VBOXNETADP_CTL_ADD:
269 Log(("VBoxNetAdpLinuxIOCtl: _IOC_DIR(uCmd)=%#x; IOC_OUT=%#x\n", _IOC_DIR(uCmd), IOC_OUT));
270 rc = vboxNetAdpCreate(&pAdp);
271 if (RT_FAILURE(rc))
272 {
273 Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpCreate -> %Rrc\n", rc));
274 return -EINVAL;
275 }
276
277 Assert(strlen(pAdp->szName) < sizeof(Req.szName));
278 strncpy(Req.szName, pAdp->szName, sizeof(Req.szName) - 1);
279 Req.szName[sizeof(Req.szName) - 1] = '\0';
280
281 if (RT_UNLIKELY(copy_to_user((void *)ulArg, &Req, sizeof(Req))))
282 {
283 /* this is really bad! */
284 /** @todo remove the adapter again? */
285 printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: copy_to_user(%#lx,,%#zx); uCmd=%#x!\n", ulArg, sizeof(Req), uCmd);
286 return -EFAULT;
287 }
288 Log(("VBoxNetAdpLinuxIOCtl: Successfully added '%s'\n", Req.szName));
289 break;
290
291 case VBOXNETADP_CTL_REMOVE:
292 if (RT_UNLIKELY(copy_from_user(&Req, (void *)ulArg, sizeof(Req))))
293 {
294 Log(("VBoxNetAdpLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
295 return -EFAULT;
296 }
297 Log(("VBoxNetAdpLinuxIOCtl: Remove %s\n", Req.szName));
298
299 pAdp = vboxNetAdpFindByName(Req.szName);
300 if (!pAdp)
301 {
302 Log(("VBoxNetAdpLinuxIOCtl: '%s' not found\n", Req.szName));
303 return -EINVAL;
304 }
305
306 rc = vboxNetAdpDestroy(pAdp);
307 if (RT_FAILURE(rc))
308 {
309 Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpDestroy('%s') -> %Rrc\n", Req.szName, rc));
310 return -EINVAL;
311 }
312 Log(("VBoxNetAdpLinuxIOCtl: Successfully removed '%s'\n", Req.szName));
313 break;
314
315 default:
316 printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: unknown command %x.\n", uCmd);
317 return -EINVAL;
318 }
319
320 return 0;
321}
322
323int vboxNetAdpOsInit(PVBOXNETADP pThis)
324{
325 /*
326 * Init linux-specific members.
327 */
328 pThis->u.s.pNetDev = NULL;
329
330 return VINF_SUCCESS;
331}
332
333
334
335/**
336 * Initialize module.
337 *
338 * @returns appropriate status code.
339 */
340static int __init VBoxNetAdpLinuxInit(void)
341{
342 int rc;
343 /*
344 * Initialize IPRT.
345 */
346 rc = RTR0Init(0);
347 if (RT_SUCCESS(rc))
348 {
349 Log(("VBoxNetAdpLinuxInit\n"));
350
351 rc = vboxNetAdpInit();
352 if (RT_SUCCESS(rc))
353 {
354 rc = misc_register(&g_CtlDev);
355 if (rc)
356 {
357 printk(KERN_ERR "VBoxNetAdp: Can't register " VBOXNETADP_CTL_DEV_NAME " device! rc=%d\n", rc);
358 return rc;
359 }
360 LogRel(("VBoxNetAdp: Successfully started.\n"));
361 return 0;
362 }
363 else
364 LogRel(("VBoxNetAdp: failed to register vboxnet0 device (rc=%d)\n", rc));
365 }
366 else
367 LogRel(("VBoxNetFlt: failed to initialize IPRT (rc=%d)\n", rc));
368
369 return -RTErrConvertToErrno(rc);
370}
371
372
373/**
374 * Unload the module.
375 *
376 * @todo We have to prevent this if we're busy!
377 */
378static void __exit VBoxNetAdpLinuxUnload(void)
379{
380 int rc;
381 Log(("VBoxNetFltLinuxUnload\n"));
382
383 /*
384 * Undo the work done during start (in reverse order).
385 */
386
387 vboxNetAdpShutdown();
388 /* Remove control device */
389 rc = misc_deregister(&g_CtlDev);
390 if (rc < 0)
391 {
392 printk(KERN_ERR "misc_deregister failed with rc=%x\n", rc);
393 }
394
395 RTR0Term();
396
397 Log(("VBoxNetFltLinuxUnload - done\n"));
398}
399
Note: See TracBrowser for help on using the repository browser.

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