Commit b56ea1b8 authored by Stephen Hemminger's avatar Stephen Hemminger

[NET]: ethertap fixes.

includes these changes from viro
* switched ethertap to dynamic allocation
* ethertap: embedded ->priv
* ethertap: fixed resource leaks on failure exits
and from me
* get it out of the static device list completely.
* add dependency on NETLINK_DEV
* not really obsolete yet
* configurable number of interfaces
parent 967a2af0
...@@ -132,8 +132,8 @@ config TUN ...@@ -132,8 +132,8 @@ config TUN
If you don't know what to use this for, you don't need it. If you don't know what to use this for, you don't need it.
config ETHERTAP config ETHERTAP
tristate "Ethertap network tap (OBSOLETE)" tristate "Ethertap network tap"
depends on NETDEVICES && EXPERIMENTAL depends on NETDEVICES && EXPERIMENTAL && NETLINK_DEV
---help--- ---help---
If you say Y here (and have said Y to "Kernel/User network link If you say Y here (and have said Y to "Kernel/User network link
driver", above) and create a character special file /dev/tap0 with driver", above) and create a character special file /dev/tap0 with
......
...@@ -89,7 +89,6 @@ extern int apne_probe(struct net_device *); ...@@ -89,7 +89,6 @@ extern int apne_probe(struct net_device *);
extern int bionet_probe(struct net_device *); extern int bionet_probe(struct net_device *);
extern int pamsnet_probe(struct net_device *); extern int pamsnet_probe(struct net_device *);
extern int cs89x0_probe(struct net_device *dev); extern int cs89x0_probe(struct net_device *dev);
extern int ethertap_probe(struct net_device *dev);
extern int hplance_probe(struct net_device *dev); extern int hplance_probe(struct net_device *dev);
extern int bagetlance_probe(struct net_device *); extern int bagetlance_probe(struct net_device *);
extern int mvme147lance_probe(struct net_device *dev); extern int mvme147lance_probe(struct net_device *dev);
...@@ -387,17 +386,6 @@ static int __init ethif_probe(struct net_device *dev) ...@@ -387,17 +386,6 @@ static int __init ethif_probe(struct net_device *dev)
return -ENODEV; return -ENODEV;
} }
#ifdef CONFIG_ETHERTAP
static struct net_device tap0_dev = {
.name = "tap0",
.base_addr = NETLINK_TAPBASE,
.next = NEXT_DEV,
.init = ethertap_probe,
};
#undef NEXT_DEV
#define NEXT_DEV (&tap0_dev)
#endif
#ifdef CONFIG_SDLA #ifdef CONFIG_SDLA
extern int sdla_init(struct net_device *); extern int sdla_init(struct net_device *);
static struct net_device sdla0_dev = { static struct net_device sdla0_dev = {
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
* Index to functions. * Index to functions.
*/ */
int ethertap_probe(struct net_device *dev);
static int ethertap_open(struct net_device *dev); static int ethertap_open(struct net_device *dev);
static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev); static int ethertap_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int ethertap_close(struct net_device *dev); static int ethertap_close(struct net_device *dev);
...@@ -45,7 +44,11 @@ static void set_multicast_list(struct net_device *dev); ...@@ -45,7 +44,11 @@ static void set_multicast_list(struct net_device *dev);
static int ethertap_debug; static int ethertap_debug;
static struct net_device *tap_map[32]; /* Returns the tap device for a given netlink */ static int max_taps = 1;
MODULE_PARM(max_taps, "i");
MODULE_PARM_DESC(max_taps,"Max number of ethernet tap devices");
static struct net_device **tap_map; /* Returns the tap device for a given netlink */
/* /*
* Board-specific info in dev->priv. * Board-specific info in dev->priv.
...@@ -64,24 +67,28 @@ struct net_local ...@@ -64,24 +67,28 @@ struct net_local
* To call this a probe is a bit misleading, however for real * To call this a probe is a bit misleading, however for real
* hardware it would have to check what was present. * hardware it would have to check what was present.
*/ */
static int __init ethertap_probe(int unit)
int __init ethertap_probe(struct net_device *dev)
{ {
struct net_device *dev;
int err = -ENOMEM;
dev = alloc_netdev(sizeof(struct net_local), "tap%d",
ether_setup);
if (!dev)
goto out;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
sprintf(dev->name, "tap%d", unit);
dev->base_addr = unit + NETLINK_TAPBASE;
netdev_boot_setup_check(dev);
memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6); memcpy(dev->dev_addr, "\xFE\xFD\x00\x00\x00\x00", 6);
if (dev->mem_start & 0xf) if (dev->mem_start & 0xf)
ethertap_debug = dev->mem_start & 0x7; ethertap_debug = dev->mem_start & 0x7;
/*
* Initialize the device structure.
*/
dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
if (dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct net_local));
/* /*
* The tap specific entries in the device structure. * The tap specific entries in the device structure.
*/ */
...@@ -94,17 +101,19 @@ int __init ethertap_probe(struct net_device *dev) ...@@ -94,17 +101,19 @@ int __init ethertap_probe(struct net_device *dev)
dev->set_multicast_list = set_multicast_list; dev->set_multicast_list = set_multicast_list;
#endif #endif
/*
* Setup the generic properties
*/
ether_setup(dev);
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
dev->flags|=IFF_NOARP; dev->flags|=IFF_NOARP;
tap_map[dev->base_addr]=dev;
err = register_netdev(dev);
if (err)
goto out1;
tap_map[unit]=dev;
return 0; return 0;
out1:
kfree(dev);
out:
return err;
} }
/* /*
...@@ -116,11 +125,12 @@ static int ethertap_open(struct net_device *dev) ...@@ -116,11 +125,12 @@ static int ethertap_open(struct net_device *dev)
struct net_local *lp = (struct net_local*)dev->priv; struct net_local *lp = (struct net_local*)dev->priv;
if (ethertap_debug > 2) if (ethertap_debug > 2)
printk("%s: Doing ethertap_open()...", dev->name); printk(KERN_DEBUG "%s: Doing ethertap_open()...", dev->name);
lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx); lp->nl = netlink_kernel_create(dev->base_addr, ethertap_rx);
if (lp->nl == NULL) if (lp->nl == NULL)
return -ENOBUFS; return -ENOBUFS;
netif_start_queue(dev); netif_start_queue(dev);
return 0; return 0;
} }
...@@ -302,7 +312,7 @@ static void ethertap_rx(struct sock *sk, int len) ...@@ -302,7 +312,7 @@ static void ethertap_rx(struct sock *sk, int len)
} }
if (ethertap_debug > 3) if (ethertap_debug > 3)
printk("%s: ethertap_rx()\n", dev->name); printk(KERN_DEBUG "%s: ethertap_rx()\n", dev->name);
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
ethertap_rx_skb(skb, dev); ethertap_rx_skb(skb, dev);
...@@ -314,7 +324,7 @@ static int ethertap_close(struct net_device *dev) ...@@ -314,7 +324,7 @@ static int ethertap_close(struct net_device *dev)
struct sock *sk = lp->nl; struct sock *sk = lp->nl;
if (ethertap_debug > 2) if (ethertap_debug > 2)
printk("%s: Shutting down.\n", dev->name); printk(KERN_DEBUG "%s: Shutting down.\n", dev->name);
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -332,45 +342,49 @@ static struct net_device_stats *ethertap_get_stats(struct net_device *dev) ...@@ -332,45 +342,49 @@ static struct net_device_stats *ethertap_get_stats(struct net_device *dev)
return &lp->stats; return &lp->stats;
} }
#ifdef MODULE
static int unit;
MODULE_PARM(unit,"i");
MODULE_PARM_DESC(unit,"Ethertap device number");
static struct net_device dev_ethertap = int __init ethertap_init(void)
{ {
.name = " ", int i, err = 0;
.init = ethertap_probe
};
int init_module(void) /* netlink can only hande 16 entries unless modified */
{ if (max_taps > MAX_LINKS - NETLINK_TAPBASE)
dev_ethertap.base_addr=unit+NETLINK_TAPBASE; return -E2BIG;
sprintf(dev_ethertap.name,"tap%d",unit);
if (dev_get(dev_ethertap.name)) tap_map = kmalloc(sizeof(struct net_device *)*max_taps, GFP_KERNEL);
{ if (!tap_map)
printk(KERN_INFO "%s already loaded.\n", dev_ethertap.name); return -ENOMEM;
return -EBUSY;
for (i = 0; i < max_taps; i++) {
err = ethertap_probe(i);
if (err) {
while (--i > 0) {
unregister_netdev(tap_map[i]);
free_netdev(tap_map[i]);
} }
if (register_netdev(&dev_ethertap) != 0) break;
return -EIO; }
return 0; }
if (err)
kfree(tap_map);
return err;
} }
module_init(ethertap_init);
void cleanup_module(void) void __exit ethertap_cleanup(void)
{ {
tap_map[dev_ethertap.base_addr]=NULL; int i;
unregister_netdev(&dev_ethertap);
for (i = 0; i < max_taps; i++) {
/* struct net_device *dev = tap_map[i];
* Free up the private structure. if (dev) {
*/ tap_map[i] = NULL;
unregister_netdev(dev);
kfree(dev_ethertap.priv); free_netdev(dev);
dev_ethertap.priv = NULL; /* gets re-allocated by ethertap_probe */ }
}
kfree(tap_map);
} }
module_exit(ethertap_cleanup);
#endif /* MODULE */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
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