VirtualBox

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

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

VBoxNetAdp: ioctl cleanup.

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