VirtualBox

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

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

vboxnetadp: cosmetics

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