Commit 966e5159 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by David S. Miller

[TUN]: tun using alloc_netdev.

parent 822e5c2d
...@@ -122,12 +122,6 @@ int tun_net_init(struct net_device *dev) ...@@ -122,12 +122,6 @@ int tun_net_init(struct net_device *dev)
DBG(KERN_INFO "%s: tun_net_init\n", tun->name); DBG(KERN_INFO "%s: tun_net_init\n", tun->name);
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;
switch (tun->flags & TUN_TYPE_MASK) { switch (tun->flags & TUN_TYPE_MASK) {
case TUN_TUN_DEV: case TUN_TUN_DEV:
/* Point-to-Point TUN Device */ /* Point-to-Point TUN Device */
...@@ -199,14 +193,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, ...@@ -199,14 +193,14 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
skb_reserve(skb, 2); skb_reserve(skb, 2);
memcpy_fromiovec(skb_put(skb, len), iv, len); memcpy_fromiovec(skb_put(skb, len), iv, len);
skb->dev = &tun->dev; skb->dev = tun->dev;
switch (tun->flags & TUN_TYPE_MASK) { switch (tun->flags & TUN_TYPE_MASK) {
case TUN_TUN_DEV: case TUN_TUN_DEV:
skb->mac.raw = skb->data; skb->mac.raw = skb->data;
skb->protocol = pi.proto; skb->protocol = pi.proto;
break; break;
case TUN_TAP_DEV: case TUN_TAP_DEV:
skb->protocol = eth_type_trans(skb, &tun->dev); skb->protocol = eth_type_trans(skb, tun->dev);
break; break;
}; };
...@@ -325,7 +319,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv, ...@@ -325,7 +319,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
schedule(); schedule();
continue; continue;
} }
netif_start_queue(&tun->dev); netif_start_queue(tun->dev);
ret = tun_put_user(tun, skb, (struct iovec *) iv, len); ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
...@@ -347,6 +341,24 @@ static ssize_t tun_chr_read(struct file * file, char * buf, ...@@ -347,6 +341,24 @@ static ssize_t tun_chr_read(struct file * file, char * buf,
return tun_chr_readv(file, &iv, 1, pos); return tun_chr_readv(file, &iv, 1, pos);
} }
static void tun_setup(struct net_device *dev)
{
struct tun_struct *tun = dev->priv;
skb_queue_head_init(&tun->readq);
init_waitqueue_head(&tun->read_wait);
tun->owner = -1;
dev->init = tun_net_init;
tun->name = dev->name;
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;
dev->destructor = (void (*)(struct net_device *))kfree;
}
static int tun_set_iff(struct file *file, struct ifreq *ifr) static int tun_set_iff(struct file *file, struct ifreq *ifr)
{ {
struct tun_struct *tun; struct tun_struct *tun;
...@@ -367,30 +379,18 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) ...@@ -367,30 +379,18 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
return -EPERM; return -EPERM;
} else { } else {
char *name; char *name;
unsigned long flags = 0;
/* Allocate new device */
if (!(tun = kmalloc(sizeof(struct tun_struct), GFP_KERNEL)) )
return -ENOMEM;
memset(tun, 0, sizeof(struct tun_struct));
skb_queue_head_init(&tun->readq);
init_waitqueue_head(&tun->read_wait);
tun->owner = -1;
tun->dev.init = tun_net_init;
tun->dev.priv = tun;
SET_MODULE_OWNER(&tun->dev);
err = -EINVAL; err = -EINVAL;
/* Set dev type */ /* Set dev type */
if (ifr->ifr_flags & IFF_TUN) { if (ifr->ifr_flags & IFF_TUN) {
/* TUN device */ /* TUN device */
tun->flags |= TUN_TUN_DEV; flags |= TUN_TUN_DEV;
name = "tun%d"; name = "tun%d";
} else if (ifr->ifr_flags & IFF_TAP) { } else if (ifr->ifr_flags & IFF_TAP) {
/* TAP device */ /* TAP device */
tun->flags |= TUN_TAP_DEV; flags |= TUN_TAP_DEV;
name = "tap%d"; name = "tap%d";
} else } else
goto failed; goto failed;
...@@ -398,12 +398,27 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) ...@@ -398,12 +398,27 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
if (*ifr->ifr_name) if (*ifr->ifr_name)
name = ifr->ifr_name; name = ifr->ifr_name;
if ((err = dev_alloc_name(&tun->dev, name)) < 0) dev = alloc_netdev(sizeof(struct tun_struct), name,
goto failed; tun_setup);
if ((err = register_netdevice(&tun->dev))) if (!dev)
return -ENOMEM;
tun = dev->priv;
tun->flags = flags;
if (strchr(dev->name, '%')) {
err = dev_alloc_name(dev, dev->name);
if (err < 0) {
kfree(dev);
goto failed;
}
}
if ((err = register_netdevice(tun->dev))) {
kfree(dev);
goto failed; goto failed;
}
tun->name = tun->dev.name;
} }
DBG(KERN_INFO "%s: tun_set_iff\n", tun->name); DBG(KERN_INFO "%s: tun_set_iff\n", tun->name);
...@@ -419,9 +434,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr) ...@@ -419,9 +434,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
strcpy(ifr->ifr_name, tun->name); strcpy(ifr->ifr_name, tun->name);
return 0; return 0;
failed:
failed:
kfree(tun);
return err; return err;
} }
...@@ -548,10 +561,8 @@ static int tun_chr_close(struct inode *inode, struct file *file) ...@@ -548,10 +561,8 @@ static int tun_chr_close(struct inode *inode, struct file *file)
/* Drop read queue */ /* Drop read queue */
skb_queue_purge(&tun->readq); skb_queue_purge(&tun->readq);
if (!(tun->flags & TUN_PERSIST)) { if (!(tun->flags & TUN_PERSIST))
dev_close(&tun->dev); unregister_netdevice(tun->dev);
unregister_netdevice(&tun->dev);
}
rtnl_unlock(); rtnl_unlock();
...@@ -574,11 +585,10 @@ static struct file_operations tun_fops = { ...@@ -574,11 +585,10 @@ static struct file_operations tun_fops = {
.fasync = tun_chr_fasync .fasync = tun_chr_fasync
}; };
static struct miscdevice tun_miscdev= static struct miscdevice tun_miscdev = {
{ .minor = TUN_MINOR,
TUN_MINOR, .name = "net/tun",
"net/tun", .fops = &tun_fops
&tun_fops
}; };
int __init tun_init(void) int __init tun_init(void)
......
...@@ -40,7 +40,7 @@ struct tun_struct { ...@@ -40,7 +40,7 @@ struct tun_struct {
wait_queue_head_t read_wait; wait_queue_head_t read_wait;
struct sk_buff_head readq; struct sk_buff_head readq;
struct net_device dev; struct net_device *dev;
struct net_device_stats stats; struct net_device_stats stats;
struct fasync_struct *fasync; struct fasync_struct *fasync;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment