VirtualBox

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

Last change on this file since 20904 was 20802, checked in by vboxsync, 15 years ago

gcc warnings

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