#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/if_bridge.h>
+#include <linux/module.h>
#include <asm/uaccess.h>
#include "br_private.h"
netif_start_queue(dev);
br = dev->priv;
- read_lock(&br->lock);
+ write_lock(&br->lock);
br_stp_enable_bridge(br);
- read_unlock(&br->lock);
+ write_unlock(&br->lock);
return 0;
}
struct net_bridge *br;
br = dev->priv;
- read_lock(&br->lock);
+ write_lock(&br->lock);
br_stp_disable_bridge(br);
- read_unlock(&br->lock);
+ write_unlock(&br->lock);
netif_stop_queue(dev);
return -1;
}
+static void br_dev_destruct(struct net_device *dev)
+{
+ kfree(dev->priv);
+}
+
void br_dev_setup(struct net_device *dev)
{
memset(dev->dev_addr, 0, ETH_ALEN);
dev->hard_start_xmit = br_dev_xmit;
dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list;
+ dev->destructor = br_dev_destruct;
+ dev->owner = THIS_MODULE;
dev->stop = br_dev_stop;
dev->accept_fastpath = br_dev_accept_fastpath;
dev->tx_queue_len = 0;
#include <linux/if_arp.h>
#include <linux/if_bridge.h>
#include <linux/inetdevice.h>
+#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/brlock.h>
+#include <net/sock.h>
#include <asm/uaccess.h>
#include "br_private.h"
-static struct net_bridge *bridge_list;
-static spinlock_t bridge_lock = SPIN_LOCK_UNLOCKED;
-
static int br_initial_port_cost(struct net_device *dev)
{
if (!strncmp(dev->name, "lec", 3))
return 0;
}
-/* called with bridge_lock */
-static struct net_bridge **__find_br(char *name)
-{
- struct net_bridge **b;
- struct net_bridge *br;
-
- b = &bridge_list;
- while ((br = *b) != NULL) {
- if (!strncmp(br->dev.name, name, IFNAMSIZ))
- return b;
-
- b = &(br->next);
- }
-
- return NULL;
-}
-
static void del_ifs(struct net_bridge *br)
{
br_write_lock_bh(BR_NETPROTO_LOCK);
br_write_unlock_bh(BR_NETPROTO_LOCK);
}
-static struct net_bridge *new_nb(char *name)
+static struct net_bridge *new_nb(const char *name)
{
struct net_bridge *br;
struct net_device *dev;
strncpy(dev->name, name, IFNAMSIZ);
dev->priv = br;
+ dev->priv_flags = IFF_EBRIDGE;
ether_setup(dev);
br_dev_setup(dev);
return p;
}
-int br_add_bridge(char *name)
+int br_add_bridge(const char *name)
{
struct net_bridge *br;
+ int ret;
- if ((br = new_nb(name)) == NULL)
+ if ((br = new_nb(name)) == NULL)
return -ENOMEM;
- if (__dev_get_by_name(name) != NULL) {
+ ret = register_netdev(&br->dev);
+ if (ret)
kfree(br);
- return -EEXIST;
- }
-
- spin_lock(&bridge_lock);
- br->next = bridge_list;
- bridge_list = br;
- spin_unlock(&bridge_lock);
-
- br_inc_use_count();
- register_netdev(&br->dev);
-
- return 0;
+ return ret;
}
-int br_del_bridge(char *name)
+int br_del_bridge(const char *name)
{
- struct net_bridge **b;
- struct net_bridge *br;
+ struct net_device *dev;
+ int ret = 0;
- spin_lock(&bridge_lock);
- if ((b = __find_br(name)) == NULL) {
- spin_unlock(&bridge_lock);
- return -ENXIO;
- }
+ dev = dev_get_by_name(name);
+ if (dev == NULL)
+ return -ENXIO; /* Could not find device */
- br = *b;
- if (br->dev.flags & IFF_UP) {
- spin_unlock(&bridge_lock);
- return -EBUSY;
+ if (!(dev->priv_flags & IFF_EBRIDGE)) {
+ /* Attempt to delete non bridge device! */
+ ret = -EPERM;
}
- *b = br->next;
- spin_unlock(&bridge_lock);
-
- del_ifs(br);
+ else if (dev->flags & IFF_UP) {
+ /* Not shutdown yet. */
+ ret = -EBUSY;
+ }
- unregister_netdev(&br->dev);
- kfree(br);
- br_dec_use_count();
+ else {
+ del_ifs((struct net_bridge *) dev->priv);
+
+ unregister_netdev(dev);
+ }
- return 0;
+ dev_put(dev);
+ return ret;
}
int br_add_if(struct net_bridge *br, struct net_device *dev)
int br_get_bridge_ifindices(int *indices, int num)
{
- struct net_bridge *br;
- int i;
-
- spin_lock(&bridge_lock);
- br = bridge_list;
- for (i=0;i<num;i++) {
- if (br == NULL)
- break;
+ struct net_device *dev;
+ int i = 0;
- indices[i] = br->dev.ifindex;
- br = br->next;
+ rtnl_shlock();
+ for (dev = dev_base; dev && i < num; dev = dev->next) {
+ if (dev->priv_flags & IFF_EBRIDGE)
+ indices[i++] = dev->ifindex;
}
- spin_unlock(&bridge_lock);
+ rtnl_shunlock();
return i;
}
-/* called under ioctl_lock */
void br_get_port_ifindices(struct net_bridge *br, int *ifindices)
{
struct net_bridge_port *p;
}
read_unlock(&br->lock);
}
+
+
+void __exit br_cleanup_bridges(void)
+{
+ struct net_device *dev, *nxt;
+
+ rtnl_lock();
+ for (dev = dev_base; dev; dev = nxt) {
+ nxt = dev->next;
+ if ((dev->priv_flags & IFF_EBRIDGE)
+ && dev->owner == THIS_MODULE) {
+ pr_debug("cleanup %s\n", dev->name);
+
+ del_ifs((struct net_bridge *) dev->priv);
+
+ unregister_netdevice(dev);
+ }
+ }
+ rtnl_unlock();
+
+}
struct net_bridge
{
- struct net_bridge *next;
rwlock_t lock;
struct net_bridge_port *port_list;
struct net_device dev;
extern struct notifier_block br_device_notifier;
extern unsigned char bridge_ula[6];
-/* br.c */
-extern void br_dec_use_count(void);
-extern void br_inc_use_count(void);
-
/* br_device.c */
extern void br_dev_setup(struct net_device *dev);
extern int br_dev_xmit(struct sk_buff *skb, struct net_device *dev);
int clone);
/* br_if.c */
-extern int br_add_bridge(char *name);
-extern int br_del_bridge(char *name);
+extern int br_add_bridge(const char *name);
+extern int br_del_bridge(const char *name);
+extern void br_cleanup_bridges(void);
extern int br_add_if(struct net_bridge *br,
struct net_device *dev);
extern int br_del_if(struct net_bridge *br,
extern int br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */
-extern void br_call_ioctl_atomic(void (*fn)(void));
extern int br_ioctl(struct net_bridge *br,
unsigned int cmd,
unsigned long arg0,