tun.c 20.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
/*
 *  TUN - Universal TUN/TAP device driver.
3
 *  Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com>
Linus Torvalds's avatar
Linus Torvalds committed
4 5 6 7 8 9 10 11 12 13 14
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
15
 *  $Id: tun.c,v 1.15 2002/03/01 02:44:24 maxk Exp $
Linus Torvalds's avatar
Linus Torvalds committed
16 17 18
 */

/*
19 20
 *  Changes:
 *
21 22 23
 *  Mark Smith <markzzzsmith@yahoo.com.au>
 *   Use random_ether_addr() for tap MAC address.
 *
24 25 26 27 28 29
 *  Harald Roelle <harald.roelle@ifi.lmu.de>  2004/04/20
 *    Fixes in packet dropping, queue length setting and queue wakeup.
 *    Increased default tx queue length.
 *    Added ethtool API.
 *    Minor cleanups
 *
Linus Torvalds's avatar
Linus Torvalds committed
30 31 32 33
 *  Daniel Podlejski <underley@underley.eu.org>
 *    Modifications for 2.3.99-pre5 kernel.
 */

34 35 36 37
#define DRV_NAME	"tun"
#define DRV_VERSION	"1.6"
#define DRV_DESCRIPTION	"Universal TUN/TAP device driver"
#define DRV_COPYRIGHT	"(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>"
Linus Torvalds's avatar
Linus Torvalds committed
38

Linus Torvalds's avatar
Linus Torvalds committed
39
#include <linux/config.h>
Linus Torvalds's avatar
Linus Torvalds committed
40 41 42 43
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
Linus Torvalds's avatar
Linus Torvalds committed
44
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
45 46 47 48 49 50 51
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/miscdevice.h>
52
#include <linux/ethtool.h>
Linus Torvalds's avatar
Linus Torvalds committed
53 54 55 56 57
#include <linux/rtnetlink.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
58
#include <linux/crc32.h>
Linus Torvalds's avatar
Linus Torvalds committed
59 60 61 62 63

#include <asm/system.h>
#include <asm/uaccess.h>

#ifdef TUN_DEBUG
Linus Torvalds's avatar
Linus Torvalds committed
64
static int debug;
Linus Torvalds's avatar
Linus Torvalds committed
65 66 67 68
#endif

/* Network device part of the driver */

69
static LIST_HEAD(tun_dev_list);
70
static struct ethtool_ops tun_ethtool_ops;
71

Linus Torvalds's avatar
Linus Torvalds committed
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/* Net device open. */
static int tun_net_open(struct net_device *dev)
{
	netif_start_queue(dev);
	return 0;
}

/* Net device close. */
static int tun_net_close(struct net_device *dev)
{
	netif_stop_queue(dev);
	return 0;
}

/* Net device start xmit */
static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
89
	struct tun_struct *tun = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
90

91
	DBG(KERN_INFO "%s: tun_net_xmit %d\n", tun->dev->name, skb->len);
Linus Torvalds's avatar
Linus Torvalds committed
92

Linus Torvalds's avatar
Linus Torvalds committed
93 94 95 96
	/* Drop packet if interface is not attached */
	if (!tun->attached)
		goto drop;

97 98 99 100 101
	/* Packet dropping */
	if (skb_queue_len(&tun->readq) >= dev->tx_queue_len) {
		if (!(tun->flags & TUN_ONE_QUEUE)) {
			/* Normal queueing mode. */
			/* Packet scheduler handles dropping of further packets. */
Linus Torvalds's avatar
Linus Torvalds committed
102
			netif_stop_queue(dev);
103 104 105 106 107 108 109

			/* We won't see all dropped packets individually, so overrun
			 * error is more appropriate. */
			tun->stats.tx_fifo_errors++;
		} else {
			/* Single queue mode.
			 * Driver handles dropping of all packets itself. */
Linus Torvalds's avatar
Linus Torvalds committed
110
			goto drop;
111
		}
Linus Torvalds's avatar
Linus Torvalds committed
112
	}
113 114

	/* Queue packet */
Linus Torvalds's avatar
Linus Torvalds committed
115
	skb_queue_tail(&tun->readq, skb);
Linus Torvalds's avatar
Linus Torvalds committed
116

Linus Torvalds's avatar
Linus Torvalds committed
117
	/* Notify and wake up reader process */
Linus Torvalds's avatar
Linus Torvalds committed
118 119 120
	if (tun->flags & TUN_FASYNC)
		kill_fasync(&tun->fasync, SIGIO, POLL_IN);
	wake_up_interruptible(&tun->read_wait);
Linus Torvalds's avatar
Linus Torvalds committed
121
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
122

Linus Torvalds's avatar
Linus Torvalds committed
123 124 125
drop:
	tun->stats.tx_dropped++;
	kfree_skb(skb);
Linus Torvalds's avatar
Linus Torvalds committed
126 127 128
	return 0;
}

129 130 131
/** Add the specified Ethernet address to this multicast filter. */
static void
add_multi(u32* filter, const u8* addr)
Linus Torvalds's avatar
Linus Torvalds committed
132
{
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
	int bit_nr = ether_crc(ETH_ALEN, addr) >> 26;
	filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
}

/** Remove the specified Ethernet addres from this multicast filter. */
static void
del_multi(u32* filter, const u8* addr)
{
	int bit_nr = ether_crc(ETH_ALEN, addr) >> 26;
	filter[bit_nr >> 5] &= ~(1 << (bit_nr & 31));
}

/** Update the list of multicast groups to which the network device belongs.
 * This list is used to filter packets being sent from the character device to
 * the network device. */
static void
tun_net_mclist(struct net_device *dev)
{
	struct tun_struct *tun = netdev_priv(dev);
	const struct dev_mc_list *mclist;
	int i;
	DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n",
			dev->name, dev->mc_count);
	memset(tun->chr_filter, 0, sizeof tun->chr_filter);
	for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL;
			i++, mclist = mclist->next) {
		add_multi(tun->net_filter, mclist->dmi_addr);
		DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n",
				dev->name,
				mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2],
				mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]);
	}
Linus Torvalds's avatar
Linus Torvalds committed
165 166 167 168
}

static struct net_device_stats *tun_net_stats(struct net_device *dev)
{
169
	struct tun_struct *tun = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
170 171 172 173
	return &tun->stats;
}

/* Initialize net device. */
174
static void tun_net_init(struct net_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
175
{
176
	struct tun_struct *tun = netdev_priv(dev);
Linus Torvalds's avatar
Linus Torvalds committed
177 178 179 180 181 182 183 184
   
	switch (tun->flags & TUN_TYPE_MASK) {
	case TUN_TUN_DEV:
		/* Point-to-Point TUN Device */
		dev->hard_header_len = 0;
		dev->addr_len = 0;
		dev->mtu = 1500;

185 186
		/* Zero header length */
		dev->type = ARPHRD_NONE; 
Linus Torvalds's avatar
Linus Torvalds committed
187
		dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
188
		dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
Linus Torvalds's avatar
Linus Torvalds committed
189 190 191 192 193 194 195
		break;

	case TUN_TAP_DEV:
		/* Ethernet TAP Device */
		dev->set_multicast_list = tun_net_mclist;

		ether_setup(dev);
196
		random_ether_addr(dev->dev_addr);
197
		dev->tx_queue_len = TUN_READQ_SIZE;  /* We prefer our own queue length */
Linus Torvalds's avatar
Linus Torvalds committed
198
		break;
199
	}
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203 204 205 206
}

/* Character device part */

/* Poll */
static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
{  
207
	struct tun_struct *tun = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210 211
	unsigned int mask = POLLOUT | POLLWRNORM;

	if (!tun)
		return -EBADFD;
Linus Torvalds's avatar
Linus Torvalds committed
212

213
	DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
214 215 216

	poll_wait(file, &tun->read_wait, wait);
 
Linus Torvalds's avatar
Linus Torvalds committed
217 218
	if (skb_queue_len(&tun->readq))
		mask |= POLLIN | POLLRDNORM;
Linus Torvalds's avatar
Linus Torvalds committed
219

Linus Torvalds's avatar
Linus Torvalds committed
220
	return mask;
Linus Torvalds's avatar
Linus Torvalds committed
221 222
}

223
/* Get packet from user space buffer */
224
static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count)
Linus Torvalds's avatar
Linus Torvalds committed
225 226 227
{
	struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
	struct sk_buff *skb;
228
	size_t len = count;
Linus Torvalds's avatar
Linus Torvalds committed
229 230

	if (!(tun->flags & TUN_NO_PI)) {
231
		if ((len -= sizeof(pi)) > len)
Linus Torvalds's avatar
Linus Torvalds committed
232 233
			return -EINVAL;

234 235
		if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
236 237
	}
 
238
	if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
Linus Torvalds's avatar
Linus Torvalds committed
239 240 241 242 243
		tun->stats.rx_dropped++;
		return -ENOMEM;
	}

	skb_reserve(skb, 2);
244 245
	if (memcpy_fromiovec(skb_put(skb, len), iv, len))
		return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
246

247
	skb->dev = tun->dev;
Linus Torvalds's avatar
Linus Torvalds committed
248 249 250 251 252 253
	switch (tun->flags & TUN_TYPE_MASK) {
	case TUN_TUN_DEV:
		skb->mac.raw = skb->data;
		skb->protocol = pi.proto;
		break;
	case TUN_TAP_DEV:
254
		skb->protocol = eth_type_trans(skb, tun->dev);
Linus Torvalds's avatar
Linus Torvalds committed
255 256 257 258 259 260
		break;
	};

	if (tun->flags & TUN_NOCHECKSUM)
		skb->ip_summed = CHECKSUM_UNNECESSARY;
 
Linus Torvalds's avatar
Linus Torvalds committed
261
	netif_rx_ni(skb);
Linus Torvalds's avatar
Linus Torvalds committed
262 263
   
	tun->stats.rx_packets++;
264
	tun->stats.rx_bytes += len;
Linus Torvalds's avatar
Linus Torvalds committed
265

266
	return count;
Linus Torvalds's avatar
Linus Torvalds committed
267 268
} 

269 270 271 272 273 274 275 276 277 278 279
static inline size_t iov_total(const struct iovec *iv, unsigned long count)
{
	unsigned long i;
	size_t len;

	for (i = 0, len = 0; i < count; i++) 
		len += iv[i].iov_len;

	return len;
}

280
/* Writev */
281
static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, 
282 283
			      unsigned long count, loff_t *pos)
{
284
	struct tun_struct *tun = file->private_data;
285 286 287 288

	if (!tun)
		return -EBADFD;

289
	DBG(KERN_INFO "%s: tun_chr_write %ld\n", tun->dev->name, count);
290

291
	return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
292 293 294
}

/* Write */
295
static ssize_t tun_chr_write(struct file * file, const char __user * buf, 
296 297
			     size_t count, loff_t *pos)
{
298
	struct iovec iv = { (void __user *) buf, count };
299
	return tun_chr_writev(file, &iv, 1, pos);
Linus Torvalds's avatar
Linus Torvalds committed
300 301
}

302
/* Put packet to the user space buffer */
Linus Torvalds's avatar
Linus Torvalds committed
303 304
static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
				       struct sk_buff *skb,
305
				       struct iovec *iv, int len)
Linus Torvalds's avatar
Linus Torvalds committed
306 307
{
	struct tun_pi pi = { 0, skb->protocol };
308
	ssize_t total = 0;
Linus Torvalds's avatar
Linus Torvalds committed
309 310 311 312 313 314 315 316 317 318

	if (!(tun->flags & TUN_NO_PI)) {
		if ((len -= sizeof(pi)) < 0)
			return -EINVAL;

		if (len < skb->len) {
			/* Packet will be striped */
			pi.flags |= TUN_PKT_STRIP;
		}
 
319 320
		if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
321 322 323
		total += sizeof(pi);
	}       

324
	len = min_t(int, skb->len, len);
325 326

	skb_copy_datagram_iovec(skb, 0, iv, len);
Linus Torvalds's avatar
Linus Torvalds committed
327 328 329 330 331 332 333 334
	total += len;

	tun->stats.tx_packets++;
	tun->stats.tx_bytes += len;

	return total;
}

335 336 337
/* Readv */
static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
			    unsigned long count, loff_t *pos)
Linus Torvalds's avatar
Linus Torvalds committed
338
{
339
	struct tun_struct *tun = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
340 341
	DECLARE_WAITQUEUE(wait, current);
	struct sk_buff *skb;
342
	ssize_t len, ret = 0;
Linus Torvalds's avatar
Linus Torvalds committed
343

Linus Torvalds's avatar
Linus Torvalds committed
344 345 346
	if (!tun)
		return -EBADFD;

347
	DBG(KERN_INFO "%s: tun_chr_read\n", tun->dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
348

349
	len = iov_total(iv, count);
350 351
	if (len < 0)
		return -EINVAL;
352

Linus Torvalds's avatar
Linus Torvalds committed
353
	add_wait_queue(&tun->read_wait, &wait);
354
	while (len) {
355 356 357 358
		const u8 ones[ ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
		u8 addr[ ETH_ALEN];
		int bit_nr;

Linus Torvalds's avatar
Linus Torvalds committed
359 360
		current->state = TASK_INTERRUPTIBLE;

Linus Torvalds's avatar
Linus Torvalds committed
361 362
		/* Read frames from the queue */
		if (!(skb=skb_dequeue(&tun->readq))) {
Linus Torvalds's avatar
Linus Torvalds committed
363 364 365 366 367 368 369 370 371 372 373 374 375
			if (file->f_flags & O_NONBLOCK) {
				ret = -EAGAIN;
				break;
			}
			if (signal_pending(current)) {
				ret = -ERESTARTSYS;
				break;
			}

			/* Nothing to read, let's sleep */
			schedule();
			continue;
		}
376
		netif_wake_queue(tun->dev);
Linus Torvalds's avatar
Linus Torvalds committed
377

378 379 380 381 382 383 384 385 386
		/** Decide whether to accept this packet. This code is designed to
		 * behave identically to an Ethernet interface. Accept the packet if
		 * - we are promiscuous.
		 * - the packet is addressed to us.
		 * - the packet is broadcast.
		 * - the packet is multicast and
		 *   - we are multicast promiscous.
		 *   - we belong to the multicast group.
		 */
387 388
		memcpy(addr, skb->data,
		       min_t(size_t, sizeof addr, skb->len));
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
		bit_nr = ether_crc(sizeof addr, addr) >> 26;
		if ((tun->if_flags & IFF_PROMISC) ||
				memcmp(addr, tun->dev_addr, sizeof addr) == 0 ||
				memcmp(addr, ones, sizeof addr) == 0 ||
				(((addr[0] == 1 && addr[1] == 0 && addr[2] == 0x5e) ||
				  (addr[0] == 0x33 && addr[1] == 0x33)) &&
				 ((tun->if_flags & IFF_ALLMULTI) ||
				  (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) {
			DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n",
					tun->dev->name, addr[0], addr[1], addr[2],
					addr[3], addr[4], addr[5]);
			ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
			kfree_skb(skb);
			break;
		} else {
			DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n",
					tun->dev->name, addr[0], addr[1], addr[2],
					addr[3], addr[4], addr[5]);
			kfree_skb(skb);
			continue;
		}
Linus Torvalds's avatar
Linus Torvalds committed
410 411 412 413 414 415 416 417
	}

	current->state = TASK_RUNNING;
	remove_wait_queue(&tun->read_wait, &wait);

	return ret;
}

418
/* Read */
419
static ssize_t tun_chr_read(struct file * file, char __user * buf, 
420 421 422 423 424 425
			    size_t count, loff_t *pos)
{
	struct iovec iv = { buf, count };
	return tun_chr_readv(file, &iv, 1, pos);
}

426 427
static void tun_setup(struct net_device *dev)
{
428
	struct tun_struct *tun = netdev_priv(dev);
429 430 431 432 433

	skb_queue_head_init(&tun->readq);
	init_waitqueue_head(&tun->read_wait);

	tun->owner = -1;
434

435 436 437 438 439
	SET_MODULE_OWNER(dev);
	dev->open = tun_net_open;
	dev->hard_start_xmit = tun_net_xmit;
	dev->stop = tun_net_close;
	dev->get_stats = tun_net_stats;
440
	dev->ethtool_ops = &tun_ethtool_ops;
441
	dev->destructor = free_netdev;
442 443
}

444 445 446 447 448 449 450 451 452 453 454 455 456
static struct tun_struct *tun_get_by_name(const char *name)
{
	struct tun_struct *tun;

	ASSERT_RTNL();
	list_for_each_entry(tun, &tun_dev_list, list) {
		if (!strncmp(tun->dev->name, name, IFNAMSIZ))
		    return tun;
	}

	return NULL;
}

Linus Torvalds's avatar
Linus Torvalds committed
457
static int tun_set_iff(struct file *file, struct ifreq *ifr)
Linus Torvalds's avatar
Linus Torvalds committed
458
{
Linus Torvalds's avatar
Linus Torvalds committed
459
	struct tun_struct *tun;
460
	struct net_device *dev;
Linus Torvalds's avatar
Linus Torvalds committed
461 462
	int err;

463 464 465
	tun = tun_get_by_name(ifr->ifr_name);
	if (tun) {
		if (tun->attached)
Linus Torvalds's avatar
Linus Torvalds committed
466 467 468
			return -EBUSY;

		/* Check permissions */
469 470 471 472 473 474 475
		if (tun->owner != -1 &&
		    current->euid != tun->owner && !capable(CAP_NET_ADMIN))
			return -EPERM;
	} 
	else if (__dev_get_by_name(ifr->ifr_name)) 
		return -EINVAL;
	else {
Linus Torvalds's avatar
Linus Torvalds committed
476
		char *name;
477
		unsigned long flags = 0;
Linus Torvalds's avatar
Linus Torvalds committed
478 479 480 481 482 483

		err = -EINVAL;

		/* Set dev type */
		if (ifr->ifr_flags & IFF_TUN) {
			/* TUN device */
484
			flags |= TUN_TUN_DEV;
Linus Torvalds's avatar
Linus Torvalds committed
485 486 487
			name = "tun%d";
		} else if (ifr->ifr_flags & IFF_TAP) {
			/* TAP device */
488
			flags |= TUN_TAP_DEV;
Linus Torvalds's avatar
Linus Torvalds committed
489 490 491
			name = "tap%d";
		} else 
			goto failed;
Linus Torvalds's avatar
Linus Torvalds committed
492
   
Linus Torvalds's avatar
Linus Torvalds committed
493 494 495
		if (*ifr->ifr_name)
			name = ifr->ifr_name;

496 497 498 499 500
		dev = alloc_netdev(sizeof(struct tun_struct), name,
				   tun_setup);
		if (!dev)
			return -ENOMEM;

501
		tun = netdev_priv(dev);
502
		tun->dev = dev;
503
		tun->flags = flags;
504 505 506 507 508 509
		/* Be promiscuous by default to maintain previous behaviour. */
		tun->if_flags = IFF_PROMISC;
		/* Generate random Ethernet address. */
		*(u16 *)tun->dev_addr = htons(0x00FF);
		get_random_bytes(tun->dev_addr + sizeof(u16), 4);
		memset(tun->chr_filter, 0, sizeof tun->chr_filter);
510

511 512
		tun_net_init(dev);

513 514
		if (strchr(dev->name, '%')) {
			err = dev_alloc_name(dev, dev->name);
515 516
			if (err < 0)
				goto err_free_dev;
517 518
		}

519 520 521
		err = register_netdevice(tun->dev);
		if (err < 0)
			goto err_free_dev;
Linus Torvalds's avatar
Linus Torvalds committed
522
	
523
		list_add(&tun->list, &tun_dev_list);
Linus Torvalds's avatar
Linus Torvalds committed
524 525
	}

526
	DBG(KERN_INFO "%s: tun_set_iff\n", tun->dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
527

Linus Torvalds's avatar
Linus Torvalds committed
528 529
	if (ifr->ifr_flags & IFF_NO_PI)
		tun->flags |= TUN_NO_PI;
Linus Torvalds's avatar
Linus Torvalds committed
530

Linus Torvalds's avatar
Linus Torvalds committed
531 532 533 534 535
	if (ifr->ifr_flags & IFF_ONE_QUEUE)
		tun->flags |= TUN_ONE_QUEUE;

	file->private_data = tun;
	tun->attached = 1;
Linus Torvalds's avatar
Linus Torvalds committed
536

537
	strcpy(ifr->ifr_name, tun->dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
538
	return 0;
539 540 541

 err_free_dev:
	free_netdev(dev);
542
 failed:
Linus Torvalds's avatar
Linus Torvalds committed
543
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
544 545 546 547 548
}

static int tun_chr_ioctl(struct inode *inode, struct file *file, 
			 unsigned int cmd, unsigned long arg)
{
549
	struct tun_struct *tun = file->private_data;
550 551 552 553 554 555
	void __user* argp = (void __user*)arg;
	struct ifreq ifr;

	if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
		if (copy_from_user(&ifr, argp, sizeof ifr))
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
556

Linus Torvalds's avatar
Linus Torvalds committed
557 558
	if (cmd == TUNSETIFF && !tun) {
		int err;
Linus Torvalds's avatar
Linus Torvalds committed
559

Linus Torvalds's avatar
Linus Torvalds committed
560
		ifr.ifr_name[IFNAMSIZ-1] = '\0';
Linus Torvalds's avatar
Linus Torvalds committed
561

562
		rtnl_lock();
Linus Torvalds's avatar
Linus Torvalds committed
563 564 565 566 567 568
		err = tun_set_iff(file, &ifr);
		rtnl_unlock();

		if (err)
			return err;

569
		if (copy_to_user(argp, &ifr, sizeof(ifr)))
570
			return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
571 572 573 574 575 576
		return 0;
	}

	if (!tun)
		return -EBADFD;

577
	DBG(KERN_INFO "%s: tun_chr_ioctl cmd %d\n", tun->dev->name, cmd);
Linus Torvalds's avatar
Linus Torvalds committed
578 579

	switch (cmd) {
Linus Torvalds's avatar
Linus Torvalds committed
580
	case TUNSETNOCSUM:
Linus Torvalds's avatar
Linus Torvalds committed
581
		/* Disable/Enable checksum */
Linus Torvalds's avatar
Linus Torvalds committed
582 583 584 585 586 587
		if (arg)
			tun->flags |= TUN_NOCHECKSUM;
		else
			tun->flags &= ~TUN_NOCHECKSUM;

		DBG(KERN_INFO "%s: checksum %s\n",
588
		    tun->dev->name, arg ? "disabled" : "enabled");
Linus Torvalds's avatar
Linus Torvalds committed
589 590
		break;

Linus Torvalds's avatar
Linus Torvalds committed
591 592 593 594 595 596 597 598
	case TUNSETPERSIST:
		/* Disable/Enable persist mode */
		if (arg)
			tun->flags |= TUN_PERSIST;
		else
			tun->flags &= ~TUN_PERSIST;

		DBG(KERN_INFO "%s: persist %s\n",
599
		    tun->dev->name, arg ? "disabled" : "enabled");
Linus Torvalds's avatar
Linus Torvalds committed
600 601 602 603 604 605
		break;

	case TUNSETOWNER:
		/* Set owner of the device */
		tun->owner = (uid_t) arg;

606
		DBG(KERN_INFO "%s: owner set to %d\n", tun->dev->name, tun->owner);
Linus Torvalds's avatar
Linus Torvalds committed
607 608
		break;

Linus Torvalds's avatar
Linus Torvalds committed
609 610 611 612 613 614
#ifdef TUN_DEBUG
	case TUNSETDEBUG:
		tun->debug = arg;
		break;
#endif

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
	case SIOCGIFFLAGS:
		ifr.ifr_flags = tun->if_flags;
		if (copy_to_user( argp, &ifr, sizeof ifr))
			return -EFAULT;
		return 0;

	case SIOCSIFFLAGS:
		/** Set the character device's interface flags. Currently only
		 * IFF_PROMISC and IFF_ALLMULTI are used. */
		tun->if_flags = ifr.ifr_flags;
		DBG(KERN_INFO "%s: interface flags 0x%lx\n",
				tun->dev->name, tun->if_flags);
		return 0;

	case SIOCGIFHWADDR:
		memcpy(ifr.ifr_hwaddr.sa_data, tun->dev_addr,
				min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
		if (copy_to_user( argp, &ifr, sizeof ifr))
			return -EFAULT;
		return 0;

	case SIOCSIFHWADDR:
		/** Set the character device's hardware address. This is used when
		 * filtering packets being sent from the network device to the character
		 * device. */
		memcpy(tun->dev_addr, ifr.ifr_hwaddr.sa_data,
				min(sizeof ifr.ifr_hwaddr.sa_data, sizeof tun->dev_addr));
		DBG(KERN_DEBUG "%s: set hardware address: %x:%x:%x:%x:%x:%x\n",
				tun->dev->name,
				tun->dev_addr[0], tun->dev_addr[1], tun->dev_addr[2],
				tun->dev_addr[3], tun->dev_addr[4], tun->dev_addr[5]);
		return 0;

	case SIOCADDMULTI:
		/** Add the specified group to the character device's multicast filter
		 * list. */
		add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
		DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n",
				tun->dev->name,
				(u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
				(u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
				(u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
		return 0;

	case SIOCDELMULTI:
		/** Remove the specified group from the character device's multicast
		 * filter list. */
		del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
		DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n",
				tun->dev->name,
				(u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
				(u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
				(u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
670 671 672 673 674 675 676 677 678
	default:
		return -EINVAL;
	};

	return 0;
}

static int tun_chr_fasync(int fd, struct file *file, int on)
{
679
	struct tun_struct *tun = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
680 681
	int ret;

Linus Torvalds's avatar
Linus Torvalds committed
682 683 684
	if (!tun)
		return -EBADFD;

685
	DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on);
Linus Torvalds's avatar
Linus Torvalds committed
686 687 688 689

	if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
		return ret; 
 
Linus Torvalds's avatar
Linus Torvalds committed
690
	if (on) {
691 692 693
		ret = f_setown(file, current->pid, 0);
		if (ret)
			return ret;
Linus Torvalds's avatar
Linus Torvalds committed
694
		tun->flags |= TUN_FASYNC;
Linus Torvalds's avatar
Linus Torvalds committed
695
	} else 
Linus Torvalds's avatar
Linus Torvalds committed
696 697 698 699 700 701 702 703
		tun->flags &= ~TUN_FASYNC;

	return 0;
}

static int tun_chr_open(struct inode *inode, struct file * file)
{
	DBG1(KERN_INFO "tunX: tun_chr_open\n");
Linus Torvalds's avatar
Linus Torvalds committed
704
	file->private_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
705 706 707 708 709
	return 0;
}

static int tun_chr_close(struct inode *inode, struct file *file)
{
710
	struct tun_struct *tun = file->private_data;
Linus Torvalds's avatar
Linus Torvalds committed
711

Linus Torvalds's avatar
Linus Torvalds committed
712 713
	if (!tun)
		return 0;
Linus Torvalds's avatar
Linus Torvalds committed
714

715
	DBG(KERN_INFO "%s: tun_chr_close\n", tun->dev->name);
Linus Torvalds's avatar
Linus Torvalds committed
716

Linus Torvalds's avatar
Linus Torvalds committed
717
	tun_chr_fasync(-1, file, 0);
Linus Torvalds's avatar
Linus Torvalds committed
718

719
	rtnl_lock();
Linus Torvalds's avatar
Linus Torvalds committed
720

Linus Torvalds's avatar
Linus Torvalds committed
721
	/* Detach from net device */
Linus Torvalds's avatar
Linus Torvalds committed
722
	file->private_data = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
723 724 725 726 727
	tun->attached = 0;

	/* Drop read queue */
	skb_queue_purge(&tun->readq);

728 729
	if (!(tun->flags & TUN_PERSIST)) {
		list_del(&tun->list);
730
		unregister_netdevice(tun->dev);
731
	}
Linus Torvalds's avatar
Linus Torvalds committed
732

Linus Torvalds's avatar
Linus Torvalds committed
733
	rtnl_unlock();
734

Linus Torvalds's avatar
Linus Torvalds committed
735 736 737 738
	return 0;
}

static struct file_operations tun_fops = {
739 740 741 742 743 744 745 746 747 748 749
	.owner	= THIS_MODULE,	
	.llseek = no_llseek,
	.read	= tun_chr_read,
	.readv	= tun_chr_readv,
	.write	= tun_chr_write,
	.writev = tun_chr_writev,
	.poll	= tun_chr_poll,
	.ioctl	= tun_chr_ioctl,
	.open	= tun_chr_open,
	.release = tun_chr_close,
	.fasync = tun_chr_fasync		
Linus Torvalds's avatar
Linus Torvalds committed
750 751
};

752 753
static struct miscdevice tun_miscdev = {
	.minor = TUN_MINOR,
Stephen Hemminger's avatar
Stephen Hemminger committed
754 755 756
	.name = "tun",
	.fops = &tun_fops,
	.devfs_name = "net/tun",
Linus Torvalds's avatar
Linus Torvalds committed
757 758
};

759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843
/* ethtool interface */

static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	cmd->supported		= 0;
	cmd->advertising	= 0;
	cmd->speed		= SPEED_10;
	cmd->duplex		= DUPLEX_FULL;
	cmd->port		= PORT_TP;
	cmd->phy_address	= 0;
	cmd->transceiver	= XCVR_INTERNAL;
	cmd->autoneg		= AUTONEG_DISABLE;
	cmd->maxtxpkt		= 0;
	cmd->maxrxpkt		= 0;
	return 0;
}

static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
	struct tun_struct *tun = netdev_priv(dev);

	strcpy(info->driver, DRV_NAME);
	strcpy(info->version, DRV_VERSION);
	strcpy(info->fw_version, "N/A");

	switch (tun->flags & TUN_TYPE_MASK) {
	case TUN_TUN_DEV:
		strcpy(info->bus_info, "tun");
		break;
	case TUN_TAP_DEV:
		strcpy(info->bus_info, "tap");
		break;
	}
}

static u32 tun_get_msglevel(struct net_device *dev)
{
#ifdef TUN_DEBUG
	struct tun_struct *tun = netdev_priv(dev);
	return tun->debug;
#else
	return -EOPNOTSUPP;
#endif
}

static void tun_set_msglevel(struct net_device *dev, u32 value)
{
#ifdef TUN_DEBUG
	struct tun_struct *tun = netdev_priv(dev);
	tun->debug = value;
#endif
}

static u32 tun_get_link(struct net_device *dev)
{
	struct tun_struct *tun = netdev_priv(dev);
	return tun->attached;
}

static u32 tun_get_rx_csum(struct net_device *dev)
{
	struct tun_struct *tun = netdev_priv(dev);
	return (tun->flags & TUN_NOCHECKSUM) == 0;
}

static int tun_set_rx_csum(struct net_device *dev, u32 data)
{
	struct tun_struct *tun = netdev_priv(dev);
	if (data)
		tun->flags &= ~TUN_NOCHECKSUM;
	else
		tun->flags |= TUN_NOCHECKSUM;
	return 0;
}

static struct ethtool_ops tun_ethtool_ops = {
	.get_settings	= tun_get_settings,
	.get_drvinfo	= tun_get_drvinfo,
	.get_msglevel	= tun_get_msglevel,
	.set_msglevel	= tun_set_msglevel,
	.get_link	= tun_get_link,
	.get_rx_csum	= tun_get_rx_csum,
	.set_rx_csum	= tun_set_rx_csum
};

Linus Torvalds's avatar
Linus Torvalds committed
844 845
int __init tun_init(void)
{
846 847
	int ret = 0;

848 849
	printk(KERN_INFO "tun: %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
	printk(KERN_INFO "tun: %s\n", DRV_COPYRIGHT);
Linus Torvalds's avatar
Linus Torvalds committed
850

851 852
	ret = misc_register(&tun_miscdev);
	if (ret)
Linus Torvalds's avatar
Linus Torvalds committed
853
		printk(KERN_ERR "tun: Can't register misc device %d\n", TUN_MINOR);
854
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
855 856 857 858
}

void tun_cleanup(void)
{
859
	struct tun_struct *tun, *nxt;
860

Linus Torvalds's avatar
Linus Torvalds committed
861
	misc_deregister(&tun_miscdev);  
862 863

	rtnl_lock();
864 865 866
	list_for_each_entry_safe(tun, nxt, &tun_dev_list, list) {
		DBG(KERN_INFO "%s cleaned up\n", tun->dev->name);
		unregister_netdevice(tun->dev);
867 868 869
	}
	rtnl_unlock();
	
Linus Torvalds's avatar
Linus Torvalds committed
870 871 872 873
}

module_init(tun_init);
module_exit(tun_cleanup);
874 875
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR(DRV_COPYRIGHT);
Linus Torvalds's avatar
Linus Torvalds committed
876
MODULE_LICENSE("GPL");
877
MODULE_ALIAS_MISCDEV(TUN_MINOR);