Setting tag linux-2.6-22-50
[linux-2.6.git] / linux-2.6-526-tun-tap.patch
1 diff -Nurb linux-2.6.22-525/drivers/net/Makefile linux-2.6.22-526/drivers/net/Makefile
2 --- linux-2.6.22-525/drivers/net/Makefile       2008-07-13 23:58:01.000000000 -0400
3 +++ linux-2.6.22-526/drivers/net/Makefile       2008-07-13 23:58:45.000000000 -0400
4 @@ -1,7 +1,7 @@
5  #
6  # Makefile for the Linux network (ethercard) device drivers.
7  #
8 -
9 +obj-m += vnet_tun.o
10  obj-$(CONFIG_E1000) += e1000/
11  obj-$(CONFIG_E1000E) += e1000e/
12  obj-$(CONFIG_IBM_EMAC) += ibm_emac/
13 diff -Nurb linux-2.6.22-525/drivers/net/vnet_tun.c linux-2.6.22-526/drivers/net/vnet_tun.c
14 --- linux-2.6.22-525/drivers/net/vnet_tun.c     1969-12-31 19:00:00.000000000 -0500
15 +++ linux-2.6.22-526/drivers/net/vnet_tun.c     2008-07-14 16:22:57.000000000 -0400
16 @@ -0,0 +1,725 @@
17 +/*
18 + *  TUN - Universal TUN/TAP device driver.
19 + *  Copyright (C) 1999-2002 Maxim Krasnyansky <maxk@qualcomm.com>
20 + *  Modifications for PlanetLab by
21 + *  Mark Huang <mlhuang@cs.princeton.edu>
22 + *  Copyright (C) 2005 The Trustees of Princeton University
23 + *  Ported to PlanetLab 4.2 by Sapan Bhatia <sapanb@cs.princeton.edu>
24 + *
25 + *  Modifications for PlanetLab by
26 + *  Mark Huang <mlhuang@cs.princeton.edu>
27 + *  Copyright (C) 2005 The Trustees of Princeton University
28 + *
29 + *  This program is free software; you can redistribute it and/or modify
30 + *  it under the terms of the GNU General Public License as published by
31 + *  the Free Software Foundation; either version 2 of the License, or
32 + *  (at your option) any later version.
33 + *
34 + *  This program is distributed in the hope that it will be useful,
35 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
36 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 + *  GNU General Public License for more details.
38 + *
39 + *  $Id: vnet_tun.c,v 1.10 2007/03/07 21:25:26 mef Exp $
40 + */
41 +
42 +/*
43 + *  Daniel Podlejski <underley@underley.eu.org>
44 + *    Modifications for 2.3.99-pre5 kernel.
45 + */
46 +
47 +#define TUN_VER "1.5"
48 +
49 +int vnet_verbose=1;
50 +
51 +#define dbg(format, args...) do { if (vnet_verbose >= 2) { printk(format, ## args); } } while (0)
52 +#define err(format, args...) do { if (vnet_verbose >= 1) { printk(format, ## args); } } while (0)
53 +
54 +#include <linux/version.h>
55 +#include <linux/module.h>
56 +#include <linux/errno.h>
57 +#include <linux/kernel.h>
58 +#include <linux/major.h>
59 +#include <linux/slab.h>
60 +#include <linux/poll.h>
61 +#include <linux/fcntl.h>
62 +#include <linux/init.h>
63 +#include <linux/random.h>
64 +#include <linux/skbuff.h>
65 +#include <linux/netdevice.h>
66 +#include <linux/etherdevice.h>
67 +#include <linux/miscdevice.h>
68 +#include <linux/rtnetlink.h>
69 +#include <linux/if.h>
70 +#include <linux/if_arp.h>
71 +#include <linux/if_ether.h>
72 +#include <linux/if_tun.h>
73 +#include <net/sock.h>
74 +
75 +#include <asm/system.h>
76 +#include <asm/uaccess.h>
77 +
78 +/*
79 + * PlanetLab TAP device
80 + *
81 + * A single, persistent tap0 to /dev/net/tun tunnel. Packets sent out
82 + * the tap0 device, via either IP or raw sockets, are queued to both
83 + * the sending slice's /dev/net/tun queue, and the root queue. Only
84 + * one reader of each queue is allowed at a time. Any type of packet
85 + * may be written to /dev/net/tun and received via packet socket(s)
86 + * bound to tap0. However, only locally destined IP packets will be
87 + * injected into the stack, and such packets are subject to the same
88 + * connection tracking and ownership assignment that all inbound IP
89 + * packets are subject to.
90 + */
91 +
92 +struct net_device tun_netdev;
93 +static struct net_device_stats tun_stats;
94 +
95 +int print_once=1;
96 +
97 +static inline xid_t
98 +get_sk_xid(struct sock *sk)
99 +{
100 +       if (sk) {
101 +               return (int) sk->sk_nid >= 0 ? sk->sk_nid : 0;
102 +       } 
103 +       else {
104 +               if (in_interrupt() && print_once) {
105 +                       print_once=0;
106 +                       printk(KERN_EMERG "vnet_tun: get-sk_xid called in interrupt context! Stephen: Don't Panic.\n");
107 +               }
108 +               return current->xid;
109 +       }
110 +}
111 +
112 +#define set_sk_xid(sk,xid) sk->sk_nid=xid
113 +#define set_skb_xid(skb,xid) skb->skb_tag=xid
114 +#define get_skb_xid(skb) skb->skb_tag
115 +
116 +/* Extended fields */
117 +struct tun_pi_ext {
118 +       unsigned long mark;
119 +       long timestamp_sec;
120 +       long timestamp_usec;
121 +};
122 +#define TUN_PKT_EXT    0x0002
123 +       
124 +#include <net/ip.h>
125 +
126 +/* UID hash function stolen from kernel/user.c */
127 +#define XIDHASH_BITS           8
128 +#define XIDHASH_SZ             (1 << XIDHASH_BITS)
129 +#define XIDHASH_MASK           (XIDHASH_SZ - 1)
130 +#define __xidhashfn(xid)       (((xid >> XIDHASH_BITS) + xid) & XIDHASH_MASK)
131 +
132 +static struct list_head tun_dev_hash[XIDHASH_SZ];
133 +static rwlock_t tun_dev_hash_lock = RW_LOCK_UNLOCKED;
134 +
135 +static inline xid_t
136 +get_file_xid(struct file *file)
137 +{
138 +               return file->f_xid;
139 +}
140 +
141 +static inline void
142 +set_file_xid(struct file *file, xid_t xid)
143 +{
144 +               file->f_xid = xid;
145 +}
146 +
147 +static struct tun_struct *tun_get_by_xid(xid_t xid)
148 +{
149 +       struct tun_struct *tun;
150 +
151 +       read_lock_bh(&tun_dev_hash_lock);
152 +
153 +       list_for_each_entry(tun, &tun_dev_hash[__xidhashfn(xid)], list) {
154 +               if (tun->owner == xid) {
155 +                       read_unlock_bh(&tun_dev_hash_lock);
156 +                       return tun;
157 +               }
158 +       }
159 +
160 +       read_unlock_bh(&tun_dev_hash_lock);
161 +
162 +       return NULL;
163 +}
164 +
165 +/* Network device part of the driver */
166 +
167 +static void tun_xmit(struct sk_buff *skb, struct tun_struct *tun)
168 +{
169 +       /* Drop packet if interface is not attached */
170 +       if (!tun || !tun->attached)
171 +               goto drop;
172 +
173 +       dbg("%s:%d: tun_xmit %d\n", tun->dev->name, tun->owner, skb->len);
174 +
175 +       /* Queue packet */
176 +       if (skb_queue_len(&tun->readq) >= tun->dev->tx_queue_len)
177 +               goto drop;
178 +
179 +       skb = skb_clone(skb, GFP_ATOMIC);
180 +       if (!skb)
181 +               goto drop;
182 +
183 +       skb_queue_tail(&tun->readq, skb);
184 +
185 +       /* Notify and wake up reader process */
186 +       if (tun->flags & TUN_FASYNC)
187 +               kill_fasync(&tun->fasync, SIGIO, POLL_IN);
188 +       wake_up_interruptible(&tun->read_wait);
189 +
190 + drop:
191 +       if (tun)
192 +               tun->stats.tx_dropped++;
193 +       tun_stats.tx_dropped++;
194 +}
195 +
196 +/* Net device start xmit */
197 +static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
198 +{
199 +       xid_t xid, skb_xid; 
200 +       struct tun_struct *tun;
201 +       skb_xid=get_skb_xid(skb);
202 +       if (skb_xid<1) 
203 +               xid=get_sk_xid(skb->sk);
204 +       else
205 +               xid=skb_xid;
206 +
207 +       tun = tun_get_by_xid(xid);
208 +       /* Mark packet */
209 +       set_skb_xid(skb, xid);
210 +
211 +       tun_xmit(skb, tun);
212 +
213 +       /* Copy root on packets that the slice is not listening for */
214 +       if ((!tun || !tun->attached) && xid) {
215 +               tun = tun_get_by_xid(0);
216 +               tun_xmit(skb, tun);
217 +       }
218 +
219 +       kfree_skb(skb);
220 +       return 0;
221 +}
222 +
223 +static void tun_net_mclist(struct net_device *dev)
224 +{
225 +       /* Nothing to do for multicast filters. 
226 +        * We always accept all frames. */
227 +       return;
228 +}
229 +
230 +static struct net_device_stats *tun_net_stats(struct net_device *dev)
231 +{
232 +       struct tun_struct *tun = tun_get_by_xid(current->xid);
233 +       return tun ? &tun->stats : &tun_stats;
234 +}
235 +
236 +/* Character device part */
237 +
238 +/* Poll */
239 +static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
240 +{  
241 +       struct tun_struct *tun = file->private_data;
242 +       unsigned int mask = POLLOUT | POLLWRNORM;
243 +
244 +       if (!tun)
245 +               return -EBADFD;
246 +
247 +       dbg("%s:%d: tun_chr_poll\n", tun->dev->name, tun->owner);
248 +
249 +       poll_wait(file, &tun->read_wait, wait);
250
251 +       if (skb_queue_len(&tun->readq))
252 +               mask |= POLLIN | POLLRDNORM;
253 +
254 +       return mask;
255 +}
256 +
257 +/* Get packet from user space buffer */
258 +static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, size_t count)
259 +{
260 +       struct tun_pi pi = { 0, __constant_htons(ETH_P_IP) };
261 +       struct tun_pi_ext pi_ext;
262 +       struct sk_buff *skb;
263 +       size_t len = count;
264 +
265 +       if (!(tun->flags & TUN_NO_PI)) {
266 +               if ((len -= sizeof(pi)) < 0)
267 +                       return -EINVAL;
268 +
269 +               if(memcpy_fromiovec((void *)&pi, iv, sizeof(pi)))
270 +                       return -EFAULT;
271 +
272 +               if (pi.flags & TUN_PKT_EXT) {
273 +                       if ((len -= sizeof(pi_ext)) < 0)
274 +                               return -EINVAL;
275 +
276 +                       if (memcpy_fromiovec((void *)&pi_ext, iv, sizeof(pi_ext)))
277 +                               return -EFAULT;
278 +               }
279 +       }
280
281 +       if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
282 +               tun->stats.rx_dropped++;
283 +               tun_stats.rx_dropped++;
284 +               return -ENOMEM;
285 +       }
286 +
287 +       skb_reserve(skb, 2);
288 +       if (memcpy_fromiovec(skb_put(skb, len), iv, len))
289 +               return -EFAULT;
290 +
291 +       skb->dev = tun->dev;
292 +       switch (tun->flags & TUN_TYPE_MASK) {
293 +       case TUN_TUN_DEV:
294 +               skb_reset_mac_header(skb);
295 +               skb->protocol = pi.proto;
296 +               break;
297 +       case TUN_TAP_DEV:
298 +               skb->protocol = eth_type_trans(skb, tun->dev);
299 +               break;
300 +       };
301 +
302 +       if (tun->flags & TUN_NOCHECKSUM)
303 +               skb->ip_summed = CHECKSUM_UNNECESSARY;
304 +
305 +       /* Mark packet */
306 +       set_skb_xid(skb, tun->owner);
307 +
308 +       netif_rx_ni(skb);
309 +   
310 +       tun->stats.rx_packets++;
311 +       tun->stats.rx_bytes += len;
312 +       tun_stats.rx_packets++;
313 +       tun_stats.rx_bytes += len;
314 +
315 +       return count;
316 +} 
317 +
318 +static inline size_t iov_total(const struct iovec *iv, unsigned long count)
319 +{
320 +       unsigned long i;
321 +       size_t len;
322 +
323 +       for (i = 0, len = 0; i < count; i++) 
324 +               len += iv[i].iov_len;
325 +
326 +       return len;
327 +}
328 +
329 +/* Writev - Obsolete in 2.6.22, but let's keep this aroudn just in case */
330 +static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv, 
331 +                             unsigned long count, loff_t *pos)
332 +{
333 +       struct tun_struct *tun = file->private_data;
334 +
335 +       if (!tun)
336 +               return -EBADFD;
337 +
338 +       dbg("%s:%d: tun_chr_write %ld\n", tun->dev->name, tun->owner, count);
339 +
340 +       return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
341 +}
342 +
343 +/* Write */
344 +static ssize_t tun_chr_write(struct file * file, const char __user * buf, 
345 +                            size_t count, loff_t *pos)
346 +{
347 +       struct iovec iv = { (void __user *) buf, count };
348 +       return tun_chr_writev(file, &iv, 1, pos);
349 +}
350 +
351 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
352 +
353 +static inline void skb_get_timestamp(const struct sk_buff *skb, struct timeval *stamp)
354 +{
355 +       stamp->tv_sec = skb->stamp.tv_sec;
356 +       stamp->tv_usec = skb->stamp.tv_usec;
357 +}
358 +
359 +static inline void skb_set_timestamp(struct sk_buff *skb, const struct timeval *stamp)
360 +{
361 +       skb->stamp.tv_sec = stamp->tv_sec;
362 +       skb->stamp.tv_usec = stamp->tv_usec;
363 +}
364 +
365 +static void __net_timestamp(struct sk_buff *skb)
366 +{
367 +       struct timeval tv;
368 +
369 +       do_gettimeofday(&tv);
370 +       skb_set_timestamp(skb, &tv);
371 +}
372 +
373 +#endif
374 +
375 +/* Put packet to the user space buffer */
376 +static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
377 +                                      struct sk_buff *skb,
378 +                                      struct iovec *iv, int len)
379 +{
380 +       struct tun_pi pi;
381 +       struct tun_pi_ext pi_ext;
382 +       struct timeval stamp;
383 +       ssize_t total = 0;
384 +
385 +       if (!(tun->flags & TUN_NO_PI)) {
386 +               struct iovec iv1 = { iv->iov_base, iv->iov_len };
387 +
388 +               if ((len -= sizeof(pi)) < 0)
389 +                       return -EINVAL;
390 +
391 +               if (memcpy_fromiovec((void *)&pi, &iv1, sizeof(pi)))
392 +                       return -EFAULT;
393 +
394 +               if (pi.flags & TUN_PKT_EXT) {
395 +                       if ((len -= sizeof(pi_ext)) < 0)
396 +                               return -EINVAL;
397 +
398 +                       /* We might not have a timestamp, get one */
399 +                       skb_get_timestamp(skb, &stamp);
400 +                       if (stamp.tv_sec == 0) {
401 +                               __net_timestamp(skb);
402 +                               skb_get_timestamp(skb, &stamp);
403 +                       }
404 +
405 +                       pi.flags = TUN_PKT_EXT;
406 +                       pi.proto = skb->protocol;
407 +                       pi_ext.timestamp_sec = stamp.tv_sec;
408 +                       pi_ext.timestamp_usec = stamp.tv_usec;
409 +                       pi_ext.mark = skb->skb_tag;
410 +               } else {
411 +                       pi.flags = 0;
412 +                       pi.proto = skb->protocol;
413 +               }
414 +
415 +               if (len < skb->len) {
416 +                       /* Packet will be striped */
417 +                       pi.flags |= TUN_PKT_STRIP;
418 +               }
419
420 +               if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
421 +                       return -EFAULT;
422 +               total += sizeof(pi);
423 +
424 +               if (pi.flags & TUN_PKT_EXT) {
425 +                       if (memcpy_toiovec(iv, (void *) &pi_ext, sizeof(pi_ext)))
426 +                               return -EFAULT;
427 +                       total += sizeof(pi_ext);
428 +               }
429 +       }       
430 +
431 +       len = min_t(int, skb->len, len);
432 +
433 +       skb_copy_datagram_iovec(skb, 0, iv, len);
434 +       total += len;
435 +
436 +       tun->stats.tx_packets++;
437 +       tun->stats.tx_bytes += len;
438 +       tun_stats.tx_packets++;
439 +       tun_stats.tx_bytes += len;
440 +
441 +       return total;
442 +}
443 +
444 +/* Readv - Obsolete in 2.6.22, but let's keep this aroudn just in case */
445 +static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
446 +                           unsigned long count, loff_t *pos)
447 +{
448 +       struct tun_struct *tun = file->private_data;
449 +       DECLARE_WAITQUEUE(wait, current);
450 +       struct sk_buff *skb;
451 +       ssize_t len, ret = 0;
452 +
453 +       if (!tun)
454 +               return -EBADFD;
455 +
456 +       dbg("%s:%d: tun_chr_read\n", tun->dev->name, tun->owner);
457 +
458 +       len = iov_total(iv, count);
459 +       if (len < 0)
460 +               return -EINVAL;
461 +
462 +       add_wait_queue(&tun->read_wait, &wait);
463 +       while (len) {
464 +               current->state = TASK_INTERRUPTIBLE;
465 +
466 +               /* Read frames from the queue */
467 +               if (!(skb=skb_dequeue(&tun->readq))) {
468 +                       if (file->f_flags & O_NONBLOCK) {
469 +                               ret = -EAGAIN;
470 +                               break;
471 +                       }
472 +                       if (signal_pending(current)) {
473 +                               ret = -ERESTARTSYS;
474 +                               break;
475 +                       }
476 +
477 +                       /* Nothing to read, let's sleep */
478 +                       schedule();
479 +                       continue;
480 +               }
481 +
482 +               ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
483 +
484 +               kfree_skb(skb);
485 +               break;
486 +       }
487 +
488 +       current->state = TASK_RUNNING;
489 +       remove_wait_queue(&tun->read_wait, &wait);
490 +
491 +       return ret;
492 +}
493 +
494 +/* Read */
495 +static ssize_t tun_chr_read(struct file * file, char __user * buf, 
496 +                           size_t count, loff_t *pos)
497 +{
498 +       struct iovec iv = { buf, count };
499 +       return tun_chr_readv(file, &iv, 1, pos);
500 +}
501 +
502 +static int tun_set_iff(struct file *file, struct ifreq *ifr)
503 +{
504 +       struct tun_struct *tun;
505 +
506 +       tun = tun_get_by_xid(get_file_xid(file));
507 +       if (tun) {
508 +               if (tun->attached)
509 +                       return -EBUSY;
510 +
511 +               /* Check permissions */
512 +               if (tun->owner != -1 &&
513 +                   get_file_xid(file) != tun->owner && !capable(CAP_NET_ADMIN))
514 +                       return -EPERM;
515 +       }
516 +       else {
517 +               /* Create a new queue */
518 +               tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL);
519 +               if (!tun)
520 +                       return -ENOMEM;
521 +               memset(tun, 0, sizeof(struct tun_struct));
522 +
523 +               tun->dev = &tun_netdev;
524 +
525 +               skb_queue_head_init(&tun->readq);
526 +               init_waitqueue_head(&tun->read_wait);
527 +
528 +               tun->owner = get_file_xid(file);
529 +
530 +               write_lock_bh(&tun_dev_hash_lock);
531 +               list_add(&tun->list, &tun_dev_hash[__xidhashfn(get_file_xid(file))]);
532 +               write_unlock_bh(&tun_dev_hash_lock);
533 +       }
534 +
535 +       dbg("%s:%d: tun_set_iff\n", tun->dev->name, tun->owner);
536 +
537 +       tun->flags = TUN_TAP_DEV;
538 +
539 +       if (ifr->ifr_flags & IFF_NO_PI)
540 +               tun->flags |= TUN_NO_PI;
541 +
542 +       file->private_data = tun;
543 +       tun->attached = 1;
544 +
545 +       strcpy(ifr->ifr_name, tun->dev->name);
546 +       return 0;
547 +}
548 +
549 +static int tun_chr_ioctl(struct inode *inode, struct file *file, 
550 +                        unsigned int cmd, unsigned long arg)
551 +{
552 +       struct tun_struct *tun = file->private_data;
553 +
554 +       if (cmd == TUNSETIFF && !tun) {
555 +               struct ifreq ifr;
556 +               int err;
557 +
558 +               if (copy_from_user(&ifr, (void __user *)arg, sizeof(ifr)))
559 +                       return -EFAULT;
560 +               ifr.ifr_name[IFNAMSIZ-1] = '\0';
561 +
562 +               err = tun_set_iff(file, &ifr);
563 +
564 +               if (err)
565 +                       return err;
566 +
567 +               if (copy_to_user((void __user *)arg, &ifr, sizeof(ifr)))
568 +                       return -EFAULT;
569 +               return 0;
570 +       }
571 +
572 +       if (!tun)
573 +               return -EBADFD;
574 +
575 +       dbg("%s:%d: tun_chr_ioctl cmd %d\n", tun->dev->name, tun->owner, cmd);
576 +
577 +       switch (cmd) {
578 +       case TUNSETNOCSUM:
579 +               /* Disable/Enable checksum */
580 +               if (arg)
581 +                       tun->flags |= TUN_NOCHECKSUM;
582 +               else
583 +                       tun->flags &= ~TUN_NOCHECKSUM;
584 +
585 +               dbg("%s:%d: checksum %s\n",
586 +                   tun->dev->name, tun->owner, arg ? "disabled" : "enabled");
587 +               break;
588 +
589 +       case TUNSETPERSIST:
590 +       case TUNSETOWNER:
591 +       case TUNSETDEBUG:
592 +               /* Not applicable */
593 +               break;
594 +
595 +       default:
596 +               return -EINVAL;
597 +       };
598 +
599 +       return 0;
600 +}
601 +
602 +static int tun_chr_fasync(int fd, struct file *file, int on)
603 +{
604 +       struct tun_struct *tun = file->private_data;
605 +       int ret;
606 +
607 +       if (!tun)
608 +               return -EBADFD;
609 +
610 +       dbg("%s:%d: tun_chr_fasync %d\n", tun->dev->name, tun->owner, on);
611 +
612 +       if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
613 +               return ret; 
614
615 +       if (on) {
616 +               ret = f_setown(file, current->pid, 0);
617 +               if (ret)
618 +                       return ret;
619 +               tun->flags |= TUN_FASYNC;
620 +       } else 
621 +               tun->flags &= ~TUN_FASYNC;
622 +
623 +       return 0;
624 +}
625 +
626 +static int tun_chr_open(struct inode *inode, struct file * file)
627 +{
628 +       dbg("tunX: tun_chr_open\n");
629 +       file->private_data = NULL;
630 +       return 0;
631 +}
632 +
633 +static int tun_chr_close(struct inode *inode, struct file *file)
634 +{
635 +       struct tun_struct *tun = file->private_data;
636 +
637 +       if (!tun)
638 +               return 0;
639 +
640 +       dbg("%s:%d: tun_chr_close\n", tun->dev->name, tun->owner);
641 +
642 +       tun_chr_fasync(-1, file, 0);
643 +
644 +       /* Detach from net device */
645 +       file->private_data = NULL;
646 +       tun->attached = 0;
647 +
648 +       /* Drop read queue */
649 +       skb_queue_purge(&tun->readq);
650 +
651 +       return 0;
652 +}
653 +
654 +static struct file_operations tun_fops = {
655 +       .owner  = THIS_MODULE,  
656 +       .llseek = no_llseek,
657 +       .read   = tun_chr_read,
658 +       //.readv        = tun_chr_readv,
659 +       .write  = tun_chr_write,
660 +       //.writev = tun_chr_writev,
661 +       .poll   = tun_chr_poll,
662 +       .ioctl  = tun_chr_ioctl,
663 +       .open   = tun_chr_open,
664 +       .release = tun_chr_close,
665 +       .fasync = tun_chr_fasync                
666 +};
667 +
668 +static struct miscdevice tun_miscdev = {
669 +       .minor = TUN_MINOR,
670 +       .name = "tun",
671 +       .fops = &tun_fops,
672 +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
673 +       .devfs_name = "net/tun",
674 +#endif
675 +};
676 +
677 +int __init tun_init(void)
678 +{
679 +       int ret = 0;
680 +       struct net_device *dev = &tun_netdev;
681 +       int i;
682 +
683 +       /* Initialize hash table */
684 +       for (i = 0; i < XIDHASH_SZ; i++)
685 +               INIT_LIST_HEAD(&tun_dev_hash[i]);
686 +
687 +       ret = misc_register(&tun_miscdev);
688 +       if (ret) {
689 +               err("tun: Can't register misc device %d\n", TUN_MINOR);
690 +               return ret;
691 +       }
692 +
693 +       memset(dev, 0, sizeof(struct net_device));
694 +
695 +       /* Ethernet TAP Device */
696 +       dev->set_multicast_list = tun_net_mclist;
697 +
698 +       /* Generate random Ethernet address.  */
699 +       *(u16 *)dev->dev_addr = htons(0x00FF);
700 +       get_random_bytes(dev->dev_addr + sizeof(u16), 4);
701 +
702 +       ether_setup(dev);
703 +
704 +       dev->flags |= IFF_NOARP | IFF_POINTOPOINT;
705 +       dev->flags &= ~IFF_MULTICAST;
706 +
707 +       SET_MODULE_OWNER(dev);
708 +       dev->hard_start_xmit = tun_net_xmit;
709 +       dev->get_stats = tun_net_stats;
710 +
711 +       strcpy(dev->name, "tap0");
712 +
713 +       ret = register_netdev(dev);
714 +       if (ret < 0)
715 +               misc_deregister(&tun_miscdev);
716 +
717 +       return ret;
718 +}
719 +
720 +void __exit tun_cleanup(void)
721 +{
722 +       struct tun_struct *tun, *nxt;
723 +       int i;
724 +
725 +       misc_deregister(&tun_miscdev);  
726 +
727 +       write_lock_bh(&tun_dev_hash_lock);
728 +       for (i = 0; i < XIDHASH_SZ; i++) {
729 +               list_for_each_entry_safe(tun, nxt, &tun_dev_hash[i], list) {
730 +                       skb_queue_purge(&tun->readq);
731 +                       kfree(tun);
732 +               }
733 +       }
734 +       write_unlock_bh(&tun_dev_hash_lock);
735 +
736 +       unregister_netdev(&tun_netdev);
737 +}
738 +
739 +module_init(tun_init);
740 +module_cleanup(tun_cleanup);
741 +MODULE_LICENSE("GPL");