summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@kernel.bkbits.net>2003-08-19 06:13:58 -0700
committerDavid S. Miller <davem@kernel.bkbits.net>2003-08-19 06:13:58 -0700
commit9bff215af2cae2932448a110bd3ec5e7db3f43aa (patch)
tree42c9e0413b469f4e2b33615406b13cb4263479c6 /net
parent76e8b3a47a22076c9ca8fa741d9765d30be309ab (diff)
parentfbc1cf5cfa15c6ee7772bc8cd127f218155e3614 (diff)
Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5
into kernel.bkbits.net:/home/davem/net-2.5
Diffstat (limited to 'net')
-rw-r--r--net/802/tr.c137
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/Kconfig1
-rw-r--r--net/atm/br2684.c222
-rw-r--r--net/atm/clip.c2
-rw-r--r--net/atm/common.c3
-rw-r--r--net/atm/lec.c2
-rw-r--r--net/atm/pppoatm.c8
-rw-r--r--net/bridge/br_device.c18
-rw-r--r--net/core/dev.c34
-rw-r--r--net/core/neighbour.c28
-rw-r--r--net/core/net-sysfs.c15
-rw-r--r--net/ipv4/arp.c21
-rw-r--r--net/ipv4/ip_gre.c2
-rw-r--r--net/ipv4/ipip.c2
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv6/ndisc.c21
-rw-r--r--net/ipv6/sit.c2
-rw-r--r--net/irda/ircomm/ircomm_tty.c8
-rw-r--r--net/irda/irda_device.c13
-rw-r--r--net/irda/irlan/irlan_client.c7
-rw-r--r--net/irda/irlan/irlan_common.c274
-rw-r--r--net/irda/irlan/irlan_eth.c12
-rw-r--r--net/irda/irlan/irlan_filter.c47
-rw-r--r--net/irda/irproc.c8
-rw-r--r--net/netrom/nr_dev.c2
-rw-r--r--net/netsyms.c1
-rw-r--r--net/rose/af_rose.c2
-rw-r--r--net/sched/sch_teql.c2
-rw-r--r--net/wanrouter/wanmain.c2
30 files changed, 519 insertions, 381 deletions
diff --git a/net/802/tr.c b/net/802/tr.c
index 6e029d3932fe..1eb39e9e2e57 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -33,6 +33,7 @@
#include <linux/timer.h>
#include <linux/net.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <net/arp.h>
@@ -456,84 +457,108 @@ static void rif_check_expire(unsigned long dummy)
* routing.
*/
-#ifndef CONFIG_PROC_FS
-static int rif_get_info(char *buffer,char **start, off_t offset, int length) { return 0;}
-#else
-static int rif_get_info(char *buffer,char **start, off_t offset, int length)
+#ifdef CONFIG_PROC_FS
+/* Magic token to indicate first entry (header line) */
+#define RIF_PROC_START ((void *)1)
+
+static struct rif_cache_s *rif_get_idx(loff_t pos)
+{
+ int i;
+ struct rif_cache_s *entry;
+ loff_t off = 0;
+
+ for(i=0;i < RIF_TABLE_SIZE;i++)
+ for(entry=rif_table[i];entry;entry=entry->next) {
+ if (off == pos)
+ return entry;
+ ++off;
+ }
+
+ return NULL;
+}
+
+static void *rif_seq_start(struct seq_file *seq, loff_t *pos)
{
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size,i,j,rcf_len,segment,brdgnmb;
- unsigned long now=jiffies;
unsigned long flags;
- rif_cache entry;
+ spin_lock_irqsave(&rif_lock, flags);
+ seq->private = (void *) flags;
+
+ return *pos ? rif_get_idx(*pos - 1) : RIF_PROC_START;
+}
+
+static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ return rif_get_idx(*pos++);
+}
- size=sprintf(buffer,
+static void rif_seq_stop(struct seq_file *seq, void *v)
+{
+ unsigned long flags = (unsigned long) seq->private;
+ spin_lock_irqsave(&rif_lock, flags);
+}
+
+static int rif_seq_show(struct seq_file *seq, void *v)
+{
+ int j, rcf_len, segment, brdgnmb;
+ rif_cache entry = v;
+
+ if (v == RIF_PROC_START)
+ seq_puts(seq,
"if TR address TTL rcf routing segments\n");
- pos+=size;
- len+=size;
+ else {
+ struct net_device *dev = dev_get_by_index(entry->iface);
- spin_lock_irqsave(&rif_lock,flags);
- for(i=0;i < RIF_TABLE_SIZE;i++)
- {
- for(entry=rif_table[i];entry;entry=entry->next) {
- struct net_device *dev = __dev_get_by_index(entry->iface);
+ seq_printf(seq, "%s %02X:%02X:%02X:%02X:%02X:%02X %7li ",
+ dev?dev->name:"?",
+ entry->addr[0],entry->addr[1],entry->addr[2],
+ entry->addr[3],entry->addr[4],entry->addr[5],
+ sysctl_tr_rif_timeout-(jiffies-entry->last_used));
- size=sprintf(buffer+len,"%s %02X:%02X:%02X:%02X:%02X:%02X %7li ",
- dev?dev->name:"?",entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
- sysctl_tr_rif_timeout-(now-entry->last_used));
- len+=size;
- pos=begin+len;
if (entry->local_ring)
- size=sprintf(buffer+len,"local\n");
+ seq_puts(seq, "local\n");
else {
- size=sprintf(buffer+len,"%04X", ntohs(entry->rcf));
+
+ seq_printf(seq, "%04X", ntohs(entry->rcf));
rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2;
if (rcf_len)
rcf_len >>= 1;
for(j = 1; j < rcf_len; j++) {
if(j==1) {
segment=ntohs(entry->rseg[j-1])>>4;
- len+=size;
- pos=begin+len;
- size=sprintf(buffer+len," %03X",segment);
+ seq_printf(seq," %03X",segment);
};
segment=ntohs(entry->rseg[j])>>4;
brdgnmb=ntohs(entry->rseg[j-1])&0x00f;
- len+=size;
- pos=begin+len;
- size=sprintf(buffer+len,"-%01X-%03X",brdgnmb,segment);
+ seq_printf(seq,"-%01X-%03X",brdgnmb,segment);
}
- len+=size;
- pos=begin+len;
- size=sprintf(buffer+len,"\n");
+ seq_putc(seq, '\n');
}
- len+=size;
- pos=begin+len;
-
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
}
- if(pos>offset+length)
- break;
- }
- spin_unlock_irqrestore(&rif_lock,flags);
+ return 0;
+}
+
+
+static struct seq_operations rif_seq_ops = {
+ .start = rif_seq_start,
+ .next = rif_seq_next,
+ .stop = rif_seq_stop,
+ .show = rif_seq_show,
+};
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
- if (len<0)
- len=0;
- return len;
+static int rif_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &rif_seq_ops);
}
+
+static struct file_operations rif_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = rif_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
#endif
/*
@@ -549,7 +574,7 @@ static int __init rif_init(void)
rif_timer.function = rif_check_expire;
add_timer(&rif_timer);
- proc_net_create("tr_rif",0,rif_get_info);
+ proc_net_fops_create("tr_rif", S_IRUGO, &rif_seq_fops);
return 0;
}
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index f4dd67ca3118..03f7077524f5 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -358,7 +358,7 @@ static void vlan_setup(struct net_device *new_dev)
new_dev->stop = vlan_dev_stop;
new_dev->set_mac_address = vlan_dev_set_mac_address;
new_dev->set_multicast_list = vlan_dev_set_multicast_list;
- new_dev->destructor = (void (*)(struct net_device *)) kfree;
+ new_dev->destructor = free_netdev;
}
/* Attach a VLAN device to a mac address (ie Ethernet Card).
diff --git a/net/Kconfig b/net/Kconfig
index e2aa43ed5c15..7aab60e25d25 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -662,6 +662,7 @@ menu "Network testing"
config NET_PKTGEN
tristate "Packet Generator (USE WITH CAUTION)"
+ depends on PROC_FS
---help---
This module will inject preconfigured packets, at a configurable
rate, out of a given interface. It is used for network interface
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 6c7f4fa24552..fa25cbdd9a80 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -66,7 +66,7 @@ enum br2684_encaps {
struct br2684_vcc {
struct atm_vcc *atmvcc;
- struct br2684_dev *brdev;
+ struct net_device *device;
/* keep old push,pop functions for chaining */
void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
/* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */
@@ -81,7 +81,7 @@ struct br2684_vcc {
};
struct br2684_dev {
- struct net_device net_dev;
+ struct net_device *net_dev;
struct list_head br2684_devs;
int number;
struct list_head brvccs; /* one device <=> one vcc (before xmas) */
@@ -102,13 +102,12 @@ static LIST_HEAD(br2684_devs);
static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
{
- return (struct br2684_dev *) ((char *) (net_dev) -
- (unsigned long) (&((struct br2684_dev *) 0)->net_dev));
+ return (struct br2684_dev *) net_dev->priv;
}
-static inline struct br2684_dev *list_entry_brdev(const struct list_head *le)
+static inline struct net_device *list_entry_brdev(const struct list_head *le)
{
- return list_entry(le, struct br2684_dev, br2684_devs);
+ return list_entry(le, struct br2684_dev, br2684_devs)->net_dev;
}
static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
@@ -122,24 +121,23 @@ static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
}
/* Caller should hold read_lock(&devs_lock) */
-static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s)
+static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
{
struct list_head *lh;
- struct br2684_dev *brdev;
+ struct net_device *net_dev;
switch (s->method) {
case BR2684_FIND_BYNUM:
list_for_each(lh, &br2684_devs) {
- brdev = list_entry_brdev(lh);
- if (brdev->number == s->spec.devnum)
- return brdev;
+ net_dev = list_entry_brdev(lh);
+ if (BRPRIV(net_dev)->number == s->spec.devnum)
+ return net_dev;
}
break;
case BR2684_FIND_BYIFNAME:
list_for_each(lh, &br2684_devs) {
- brdev = list_entry_brdev(lh);
- if (!strncmp(brdev->net_dev.name, s->spec.ifname,
- sizeof brdev->net_dev.name))
- return brdev;
+ net_dev = list_entry_brdev(lh);
+ if (!strncmp(net_dev->name, s->spec.ifname, IFNAMSIZ))
+ return net_dev;
}
break;
}
@@ -357,7 +355,7 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
*/
struct br2684_dev *brdev;
read_lock(&devs_lock);
- brdev = br2684_find_dev(&fs.ifspec);
+ brdev = BRPRIV(br2684_find_dev(&fs.ifspec));
if (brdev == NULL || list_empty(&brdev->brvccs) ||
brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */
brvcc = NULL;
@@ -393,33 +391,35 @@ packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
static void br2684_close_vcc(struct br2684_vcc *brvcc)
{
- DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev);
+ DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->device);
write_lock_irq(&devs_lock);
list_del(&brvcc->brvccs);
write_unlock_irq(&devs_lock);
brvcc->atmvcc->user_back = NULL; /* what about vcc->recvq ??? */
brvcc->old_push(brvcc->atmvcc, NULL); /* pass on the bad news */
kfree(brvcc);
- MOD_DEC_USE_COUNT;
+ module_put(THIS_MODULE);
}
/* when AAL5 PDU comes in: */
static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
{
struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
- struct br2684_dev *brdev = brvcc->brdev;
+ struct net_device *net_dev = brvcc->device;
+ struct br2684_dev *brdev = BRPRIV(net_dev);
int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
DPRINTK("br2684_push\n");
- if (skb == NULL) { /* skb==NULL means VCC is being destroyed */
+ if (unlikely(skb == NULL)) {
+ /* skb==NULL means VCC is being destroyed */
br2684_close_vcc(brvcc);
if (list_empty(&brdev->brvccs)) {
read_lock(&devs_lock);
list_del(&brdev->br2684_devs);
read_unlock(&devs_lock);
- unregister_netdev(&brdev->net_dev);
- kfree(brdev);
+ unregister_netdev(net_dev);
+ free_netdev(net_dev);
}
return;
}
@@ -460,24 +460,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
#ifdef CONFIG_BR2684_FAST_TRANS
skb->protocol = ((u16 *) skb->data)[-1];
#else /* some protocols might require this: */
- skb->protocol = br_type_trans(skb, &brdev->net_dev);
+ skb->protocol = br_type_trans(skb, net_dev);
#endif /* CONFIG_BR2684_FAST_TRANS */
#else
skb_pull(skb, plen - ETH_HLEN);
- skb->protocol = eth_type_trans(skb, &brdev->net_dev);
+ skb->protocol = eth_type_trans(skb, net_dev);
#endif /* FASTER_VERSION */
#ifdef CONFIG_ATM_BR2684_IPFILTER
- if (packet_fails_filter(skb->protocol, brvcc, skb)) {
+ if (unlikely(packet_fails_filter(skb->protocol, brvcc, skb))) {
brdev->stats.rx_dropped++;
dev_kfree_skb(skb);
return;
}
#endif /* CONFIG_ATM_BR2684_IPFILTER */
- skb->dev = &brdev->net_dev;
+ skb->dev = net_dev;
ATM_SKB(skb)->vcc = atmvcc; /* needed ? */
DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol));
skb_debug(skb);
- if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
+ if (unlikely(!(net_dev->flags & IFF_UP))) {
+ /* sigh, interface is down */
brdev->stats.rx_dropped++;
dev_kfree_skb(skb);
return;
@@ -498,26 +499,30 @@ Note: we do not have explicit unassign, but look at _push()
struct sk_buff_head copy;
struct sk_buff *skb;
struct br2684_dev *brdev;
+ struct net_device *net_dev;
struct atm_backend_br2684 be;
- MOD_INC_USE_COUNT;
- if (copy_from_user(&be, (void *) arg, sizeof be)) {
- MOD_DEC_USE_COUNT;
+ if (copy_from_user(&be, (void *) arg, sizeof be))
return -EFAULT;
- }
+ brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
+ if (!brvcc)
+ return -ENOMEM;
+ memset(brvcc, 0, sizeof(struct br2684_vcc));
write_lock_irq(&devs_lock);
- brdev = br2684_find_dev(&be.ifspec);
- if (brdev == NULL) {
+ net_dev = br2684_find_dev(&be.ifspec);
+ if (net_dev == NULL) {
printk(KERN_ERR
"br2684: tried to attach to non-existant device\n");
err = -ENXIO;
goto error;
}
+ brdev = BRPRIV(net_dev);
if (atmvcc->push == NULL) {
err = -EBADFD;
goto error;
}
- if (!list_empty(&brdev->brvccs)) { /* Only 1 VCC/dev right now */
+ if (!list_empty(&brdev->brvccs)) {
+ /* Only 1 VCC/dev right now */
err = -EEXIST;
goto error;
}
@@ -528,25 +533,18 @@ Note: we do not have explicit unassign, but look at _push()
err = -EINVAL;
goto error;
}
- brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
- if (!brvcc) {
- err = -ENOMEM;
- goto error;
- }
- memset(brvcc, 0, sizeof(struct br2684_vcc));
DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps,
brvcc);
if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
unsigned char *esi = atmvcc->dev->esi;
if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
- memcpy(brdev->net_dev.dev_addr, esi,
- brdev->net_dev.addr_len);
+ memcpy(net_dev->dev_addr, esi, net_dev->addr_len);
else
- brdev->net_dev.dev_addr[2] = 1;
+ net_dev->dev_addr[2] = 1;
}
list_add(&brvcc->brvccs, &brdev->brvccs);
write_unlock_irq(&devs_lock);
- brvcc->brdev = brdev;
+ brvcc->device = net_dev;
brvcc->atmvcc = atmvcc;
atmvcc->user_back = brvcc;
brvcc->encaps = (enum br2684_encaps) be.encaps;
@@ -560,80 +558,74 @@ Note: we do not have explicit unassign, but look at _push()
BRPRIV(skb->dev)->stats.rx_packets--;
br2684_push(atmvcc, skb);
}
+ (void) try_module_get(THIS_MODULE);
return 0;
error:
write_unlock_irq(&devs_lock);
- MOD_DEC_USE_COUNT;
+ kfree(brvcc);
return err;
}
+static void br2684_setup(struct net_device *netdev)
+{
+ struct br2684_dev *brdev = BRPRIV(netdev);
+
+ ether_setup(netdev);
+ brdev->net_dev = netdev;
+
+#ifdef FASTER_VERSION
+ my_eth_header = netdev->hard_header;
+ netdev->hard_header = br2684_header;
+ my_eth_header_cache = netdev->hard_header_cache;
+ netdev->hard_header_cache = br2684_header_cache;
+ netdev->hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */
+#endif
+ my_eth_mac_addr = netdev->set_mac_address;
+ netdev->set_mac_address = br2684_mac_addr;
+ netdev->hard_start_xmit = br2684_start_xmit;
+ netdev->get_stats = br2684_get_stats;
+
+ INIT_LIST_HEAD(&brdev->brvccs);
+}
+
static int br2684_create(unsigned long arg)
{
int err;
+ struct net_device *netdev;
struct br2684_dev *brdev;
struct atm_newif_br2684 ni;
DPRINTK("br2684_create\n");
- /*
- * We track module use by vcc's NOT the devices they're on. We're
- * protected here against module death by the kernel_lock, but if
- * we need to sleep we should make sure that the module doesn't
- * disappear under us.
- */
- MOD_INC_USE_COUNT;
+
if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
- MOD_DEC_USE_COUNT;
return -EFAULT;
}
if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
- MOD_DEC_USE_COUNT;
return -EINVAL;
}
- if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) {
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
- memset(brdev, 0, sizeof(struct br2684_dev));
- INIT_LIST_HEAD(&brdev->brvccs);
- write_lock_irq(&devs_lock);
- brdev->number = list_empty(&br2684_devs) ? 1 :
- list_entry_brdev(br2684_devs.prev)->number + 1;
- list_add_tail(&brdev->br2684_devs, &br2684_devs);
- write_unlock_irq(&devs_lock);
+ netdev = alloc_netdev(sizeof(struct br2684_dev),
+ ni.ifname[0] ? ni.ifname : "nas%d",
+ br2684_setup);
+ if (!netdev)
+ return -ENOMEM;
- if (ni.ifname[0] != '\0') {
- memcpy(brdev->net_dev.name, ni.ifname,
- sizeof(brdev->net_dev.name));
- brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0';
- } else
- sprintf(brdev->net_dev.name, "nas%d", brdev->number);
- DPRINTK("registered netdev %s\n", brdev->net_dev.name);
- ether_setup(&brdev->net_dev);
- brdev->mac_was_set = 0;
-#ifdef FASTER_VERSION
- my_eth_header = brdev->net_dev.hard_header;
- brdev->net_dev.hard_header = br2684_header;
- my_eth_header_cache = brdev->net_dev.hard_header_cache;
- brdev->net_dev.hard_header_cache = br2684_header_cache;
- brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN; /* 10 + 14 */
-#endif
- my_eth_mac_addr = brdev->net_dev.set_mac_address;
- brdev->net_dev.set_mac_address = br2684_mac_addr;
- brdev->net_dev.hard_start_xmit = br2684_start_xmit;
- brdev->net_dev.get_stats = br2684_get_stats;
+ brdev = BRPRIV(netdev);
+ DPRINTK("registered netdev %s\n", netdev->name);
/* open, stop, do_ioctl ? */
- err = register_netdev(&brdev->net_dev);
- MOD_DEC_USE_COUNT;
+ err = register_netdev(netdev);
if (err < 0) {
printk(KERN_ERR "br2684_create: register_netdev failed\n");
- write_lock_irq(&devs_lock);
- list_del(&brdev->br2684_devs);
- write_unlock_irq(&devs_lock);
- kfree(brdev);
+ free_netdev(netdev);
return err;
}
+
+ write_lock_irq(&devs_lock);
+ brdev->number = list_empty(&br2684_devs) ? 1 :
+ BRPRIV(list_entry_brdev(br2684_devs.prev))->number + 1;
+ list_add_tail(&brdev->br2684_devs, &br2684_devs);
+ write_unlock_irq(&devs_lock);
return 0;
}
@@ -649,9 +641,7 @@ static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
case ATM_SETBACKEND:
case ATM_NEWBACKENDIF: {
atm_backend_t b;
- MOD_INC_USE_COUNT;
err = get_user(b, (atm_backend_t *) arg);
- MOD_DEC_USE_COUNT;
if (err)
return -EFAULT;
if (b != ATM_BACKEND_BR2684)
@@ -669,9 +659,7 @@ static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
return -ENOIOCTLCMD;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- MOD_INC_USE_COUNT;
err = br2684_setfilt(atmvcc, arg);
- MOD_DEC_USE_COUNT;
return err;
#endif /* CONFIG_ATM_BR2684_IPFILTER */
}
@@ -682,20 +670,22 @@ static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
static int br2684_proc_engine(loff_t pos, char *buf)
{
struct list_head *lhd, *lhc;
+ struct net_device *net_dev;
struct br2684_dev *brdev;
struct br2684_vcc *brvcc;
list_for_each(lhd, &br2684_devs) {
- brdev = list_entry_brdev(lhd);
+ net_dev = list_entry_brdev(lhd);
+ brdev = BRPRIV(net_dev);
if (pos-- == 0)
return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
- "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
+ "%02X:%02X:%02X:%02X (%s)\n", net_dev->name,
brdev->number,
- brdev->net_dev.dev_addr[0],
- brdev->net_dev.dev_addr[1],
- brdev->net_dev.dev_addr[2],
- brdev->net_dev.dev_addr[3],
- brdev->net_dev.dev_addr[4],
- brdev->net_dev.dev_addr[5],
+ net_dev->dev_addr[0],
+ net_dev->dev_addr[1],
+ net_dev->dev_addr[2],
+ net_dev->dev_addr[3],
+ net_dev->dev_addr[4],
+ net_dev->dev_addr[5],
brdev->mac_was_set ? "set" : "auto");
list_for_each(lhc, &brdev->brvccs) {
brvcc = list_entry_brvcc(lhc);
@@ -766,15 +756,13 @@ static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
}
static struct file_operations br2684_proc_operations = {
- read: br2684_proc_read,
+ .owner = THIS_MODULE,
+ .read = br2684_proc_read,
};
extern struct proc_dir_entry *atm_proc_root; /* from proc.c */
-/* the following avoids some spurious warnings from the compiler */
-#define UNUSED __attribute__((unused))
-
-static int __init UNUSED br2684_init(void)
+static int __init br2684_init(void)
{
struct proc_dir_entry *p;
if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
@@ -784,16 +772,26 @@ static int __init UNUSED br2684_init(void)
return 0;
}
-static void __exit UNUSED br2684_exit(void)
+static void __exit br2684_exit(void)
{
+ struct net_device *net_dev;
struct br2684_dev *brdev;
+ struct br2684_vcc *brvcc;
br2684_ioctl_set(NULL);
+
remove_proc_entry("br2684", atm_proc_root);
+
while (!list_empty(&br2684_devs)) {
- brdev = list_entry_brdev(br2684_devs.next);
- unregister_netdev(&brdev->net_dev);
+ net_dev = list_entry_brdev(br2684_devs.next);
+ brdev = BRPRIV(net_dev);
+ while (!list_empty(&brdev->brvccs)) {
+ brvcc = list_entry_brvcc(brdev->brvccs.next);
+ br2684_close_vcc(brvcc);
+ }
+
list_del(&brdev->br2684_devs);
- kfree(brdev);
+ unregister_netdev(net_dev);
+ free_netdev(net_dev);
}
}
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 3eac40cd88ee..74a58eee32fd 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -786,7 +786,7 @@ static void __exit atm_clip_exit(void)
while (dev) {
next = PRIV(dev)->next;
unregister_netdev(dev);
- kfree(dev);
+ free_netdev(dev);
dev = next;
}
if (start_timer == 0) del_timer(&idle_timer);
diff --git a/net/atm/common.c b/net/atm/common.c
index 63b649bb7800..91f2c8fbe9e0 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -545,9 +545,6 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
if (error)
return error;
sock_recv_timestamp(msg, sk, skb);
- if (vcc->dev->ops->feedback)
- vcc->dev->ops->feedback(vcc, skb, (unsigned long) skb->data,
- (unsigned long) msg->msg_iov->iov_base, copied);
DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->rmem_alloc), skb->truesize);
atm_return(vcc, skb->truesize);
skb_free_datagram(sk, skb);
diff --git a/net/atm/lec.c b/net/atm/lec.c
index 67228a48527d..a3058de18f90 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -864,7 +864,7 @@ static void __exit lane_module_cleanup(void)
if (dev_lec[i] != NULL) {
priv = (struct lec_priv *)dev_lec[i]->priv;
unregister_netdev(dev_lec[i]);
- kfree(dev_lec[i]);
+ free_netdev(dev_lec[i]);
dev_lec[i] = NULL;
}
}
diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c
index b462ded246e2..cca22da87ae6 100644
--- a/net/atm/pppoatm.c
+++ b/net/atm/pppoatm.c
@@ -132,7 +132,7 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
atmvcc->user_back = NULL;
kfree(pvcc);
/* Gee, I hope we have the big kernel lock here... */
- MOD_DEC_USE_COUNT;
+ module_put(THIS_MODULE);
}
/* Called when an AAL5 PDU comes in */
@@ -286,12 +286,9 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, unsigned long arg)
if (be.encaps != PPPOATM_ENCAPS_AUTODETECT &&
be.encaps != PPPOATM_ENCAPS_VC && be.encaps != PPPOATM_ENCAPS_LLC)
return -EINVAL;
- MOD_INC_USE_COUNT;
pvcc = kmalloc(sizeof(*pvcc), GFP_KERNEL);
- if (pvcc == NULL) {
- MOD_DEC_USE_COUNT;
+ if (pvcc == NULL)
return -ENOMEM;
- }
memset(pvcc, 0, sizeof(*pvcc));
pvcc->atmvcc = atmvcc;
pvcc->old_push = atmvcc->push;
@@ -310,6 +307,7 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, unsigned long arg)
atmvcc->user_back = pvcc;
atmvcc->push = pppoatm_push;
atmvcc->pop = pppoatm_pop;
+ (void) try_module_get(THIS_MODULE);
return 0;
}
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 36d02b08989d..e208f0a42763 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -110,22 +110,6 @@ static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
return -1;
}
-/* convert later to direct kfree */
-static void br_dev_free(struct net_device *dev)
-{
- struct net_bridge *br = dev->priv;
-
- WARN_ON(!list_empty(&br->port_list));
- WARN_ON(!list_empty(&br->age_list));
-
- BUG_ON(timer_pending(&br->hello_timer));
- BUG_ON(timer_pending(&br->tcn_timer));
- BUG_ON(timer_pending(&br->topology_change_timer));
- BUG_ON(timer_pending(&br->gc_timer));
-
- kfree(dev);
-}
-
void br_dev_setup(struct net_device *dev)
{
memset(dev->dev_addr, 0, ETH_ALEN);
@@ -137,7 +121,7 @@ void br_dev_setup(struct net_device *dev)
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_free;
+ dev->destructor = free_netdev;
SET_MODULE_OWNER(dev);
dev->stop = br_dev_stop;
dev->accept_fastpath = br_dev_accept_fastpath;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6b184e9a90ea..c24e705172a4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1836,8 +1836,7 @@ static int dev_ifconf(char *arg)
* This is invoked by the /proc filesystem handler to display a device
* in detail.
*/
-static __inline__ struct net_device *dev_get_idx(struct seq_file *seq,
- loff_t pos)
+static __inline__ struct net_device *dev_get_idx(loff_t pos)
{
struct net_device *dev;
loff_t i;
@@ -1850,7 +1849,7 @@ static __inline__ struct net_device *dev_get_idx(struct seq_file *seq,
void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&dev_base_lock);
- return *pos ? dev_get_idx(seq, *pos - 1) : (void *)1;
+ return *pos ? dev_get_idx(*pos - 1) : (void *)1;
}
void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
@@ -2643,7 +2642,7 @@ int register_netdevice(struct net_device *dev)
ASSERT_RTNL();
/* When net_device's are persistent, this will be fatal. */
- WARN_ON(dev->reg_state != NETREG_UNINITIALIZED);
+ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
spin_lock_init(&dev->queue_lock);
spin_lock_init(&dev->xmit_lock);
@@ -2788,6 +2787,8 @@ static void netdev_wait_allrefs(struct net_device *dev)
* unregister_netdevice(y2);
* ...
* rtnl_unlock();
+ * free_netdev(y1);
+ * free_netdev(y2);
*
* We are invoked by rtnl_unlock() after it drops the semaphore.
* This allows us to deal with problems:
@@ -2827,7 +2828,7 @@ void netdev_run_todo(void)
break;
case NETREG_UNREGISTERING:
- class_device_unregister(&dev->class_dev);
+ class_device_del(&dev->class_dev);
dev->reg_state = NETREG_UNREGISTERED;
netdev_wait_allrefs(dev);
@@ -2856,6 +2857,29 @@ void netdev_run_todo(void)
up(&net_todo_run_mutex);
}
+/**
+ * free_netdev - free network device
+ * @dev: device
+ *
+ * This function does the last stage of destroying an allocated device
+ * interface. The reference to the device object is released.
+ * If this is the last reference then it will be freed.
+ */
+void free_netdev(struct net_device *dev)
+{
+ /* Compatiablity with error handling in drivers */
+ if (dev->reg_state == NETREG_UNINITIALIZED) {
+ kfree(dev);
+ return;
+ }
+
+ BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
+ dev->reg_state = NETREG_RELEASED;
+
+ /* will free via class release */
+ class_device_put(&dev->class_dev);
+}
+
/* Synchronize with packet receive processing. */
void synchronize_net(void)
{
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 001fdb40e6de..f87894a7dc93 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -50,6 +50,7 @@ static void neigh_timer_handler(unsigned long arg);
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
@@ -168,6 +169,33 @@ static void pneigh_queue_purge(struct sk_buff_head *list)
}
}
+void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
+{
+ int i;
+
+ write_lock_bh(&tbl->lock);
+
+ for (i=0; i <= NEIGH_HASHMASK; i++) {
+ struct neighbour *n, **np;
+
+ np = &tbl->hash_buckets[i];
+ while ((n = *np) != NULL) {
+ if (dev && n->dev != dev) {
+ np = &n->next;
+ continue;
+ }
+ *np = n->next;
+ write_lock_bh(&n->lock);
+ n->dead = 1;
+ neigh_del_timer(n);
+ write_unlock_bh(&n->lock);
+ neigh_release(n);
+ }
+ }
+
+ write_unlock_bh(&tbl->lock);
+}
+
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
{
int i;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 3e3c7c524f2f..3ff9e58a06c8 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -361,8 +361,23 @@ static int netdev_hotplug(struct class_device *cd, char **envp,
}
#endif
+/*
+ * netdev_release -- destroy and free a dead device.
+ * Called when last reference to class_device kobject is gone.
+ */
+static void netdev_release(struct class_device *cd)
+{
+ struct net_device *dev
+ = container_of(cd, struct net_device, class_dev);
+
+ BUG_ON(dev->reg_state != NETREG_RELEASED);
+
+ kfree(dev);
+}
+
static struct class net_class = {
.name = "net",
+ .release = netdev_release,
#ifdef CONFIG_HOTPLUG
.hotplug = netdev_hotplug,
#endif
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 1324b4e97d83..4fd817944e99 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1071,6 +1071,26 @@ out:
return err;
}
+static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&arp_tbl, dev);
+ rt_cache_flush(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block arp_netdev_notifier = {
+ .notifier_call = arp_netdev_event,
+};
+
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
@@ -1103,6 +1123,7 @@ void __init arp_init(void)
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4");
#endif
+ register_netdevice_notifier(&arp_netdev_notifier);
}
#ifdef CONFIG_PROC_FS
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index c793f48b8df3..90ace8969820 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1128,7 +1128,7 @@ static void ipgre_tunnel_setup(struct net_device *dev)
{
SET_MODULE_OWNER(dev);
dev->uninit = ipgre_tunnel_uninit;
- dev->destructor = (void (*)(struct net_device *))kfree;
+ dev->destructor = free_netdev;
dev->hard_start_xmit = ipgre_tunnel_xmit;
dev->get_stats = ipgre_tunnel_get_stats;
dev->do_ioctl = ipgre_tunnel_ioctl;
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 19eab54dceb8..d272c9dc1099 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -246,7 +246,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c
nt = dev->priv;
SET_MODULE_OWNER(dev);
dev->init = ipip_tunnel_init;
- dev->destructor = (void (*)(struct net_device *))kfree;
+ dev->destructor = free_netdev;
nt->parms = *parms;
if (register_netdevice(dev) < 0) {
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 689ae198d82c..3f671efed9e6 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -193,7 +193,7 @@ static void reg_vif_setup(struct net_device *dev)
dev->flags = IFF_NOARP;
dev->hard_start_xmit = reg_vif_xmit;
dev->get_stats = reg_vif_get_stats;
- dev->destructor = (void (*)(struct net_device *)) kfree;
+ dev->destructor = free_netdev;
}
static struct net_device *ipmr_reg_vif(void)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3728805d5d60..ef434507c04a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1447,6 +1447,26 @@ int ndisc_rcv(struct sk_buff *skb)
return 0;
}
+static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ switch (event) {
+ case NETDEV_CHANGEADDR:
+ neigh_changeaddr(&nd_tbl, dev);
+ fib6_run_gc(0);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block ndisc_netdev_notifier = {
+ .notifier_call = ndisc_netdev_event,
+};
+
int __init ndisc_init(struct net_proto_family *ops)
{
struct ipv6_pinfo *np;
@@ -1480,6 +1500,7 @@ int __init ndisc_init(struct net_proto_family *ops)
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
+ register_netdevice_notifier(&ndisc_netdev_notifier);
return 0;
}
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 6d58029d1fe5..8576eda7d5f4 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -722,7 +722,7 @@ static void ipip6_tunnel_setup(struct net_device *dev)
{
SET_MODULE_OWNER(dev);
dev->uninit = ipip6_tunnel_uninit;
- dev->destructor = (void (*)(struct net_device *))kfree;
+ dev->destructor = free_netdev;
dev->hard_start_xmit = ipip6_tunnel_xmit;
dev->get_stats = ipip6_tunnel_get_stats;
dev->do_ioctl = ipip6_tunnel_ioctl;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 56095cbe1490..82c090f08df5 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -117,6 +117,7 @@ int __init ircomm_tty_init(void)
return -ENOMEM;
}
+ driver->owner = THIS_MODULE;
driver->driver_name = "ircomm";
driver->name = "ircomm";
driver->devfs_name = "ircomm";
@@ -363,10 +364,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
- MOD_INC_USE_COUNT;
line = tty->index;
if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) {
- MOD_DEC_USE_COUNT;
return -ENODEV;
}
@@ -377,7 +376,6 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
self = kmalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL);
if (self == NULL) {
ERROR("%s(), kmalloc failed!\n", __FUNCTION__);
- MOD_DEC_USE_COUNT;
return -ENOMEM;
}
memset(self, 0, sizeof(struct ircomm_tty_cb));
@@ -503,7 +501,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
spin_lock_irqsave(&self->spinlock, flags);
if (tty_hung_up_p(filp)) {
- MOD_DEC_USE_COUNT;
spin_unlock_irqrestore(&self->spinlock, flags);
IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ );
@@ -530,7 +527,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
self->open_count = 0;
}
if (self->open_count) {
- MOD_DEC_USE_COUNT;
spin_unlock_irqrestore(&self->spinlock, flags);
IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ );
@@ -572,8 +568,6 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&self->close_wait);
-
- MOD_DEC_USE_COUNT;
}
/*
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 5f3f6feaad66..187356ed0c10 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -83,12 +83,6 @@ static const char *task_state[] = {
static void irda_task_timer_expired(void *data);
-#ifdef CONFIG_PROC_FS
-int irda_device_proc_read(char *buf, char **start, off_t offset, int len,
- int unused);
-
-#endif /* CONFIG_PROC_FS */
-
int __init irda_device_init( void)
{
dongles = hashbin_new(HB_LOCK);
@@ -372,11 +366,6 @@ static void irda_task_timer_expired(void *data)
irda_task_kick(task);
}
-static void irda_device_destructor(struct net_device *dev)
-{
- kfree(dev);
-}
-
/*
* Function irda_device_setup (dev)
*
@@ -388,7 +377,7 @@ void irda_device_setup(struct net_device *dev)
dev->hard_header_len = 0;
dev->addr_len = 0;
- dev->destructor = irda_device_destructor;
+ dev->destructor = free_netdev;
dev->type = ARPHRD_IRDA;
dev->tx_queue_len = 8; /* Window size + 1 s-frame */
diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c
index e142dbb0172e..573907187208 100644
--- a/net/irda/irlan/irlan_client.c
+++ b/net/irda/irlan/irlan_client.c
@@ -154,7 +154,6 @@ void irlan_client_discovery_indication(discinfo_t *discovery,
IRDA_DEBUG(1, "%s()\n", __FUNCTION__ );
- ASSERT(irlan != NULL, return;);
ASSERT(discovery != NULL, return;);
/*
@@ -170,7 +169,8 @@ void irlan_client_discovery_indication(discinfo_t *discovery,
daddr = discovery->daddr;
/* Find instance */
- self = (struct irlan_cb *) hashbin_get_first(irlan);
+ rcu_read_lock();
+ self = irlan_get_any();
if (self) {
ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -179,6 +179,7 @@ void irlan_client_discovery_indication(discinfo_t *discovery,
irlan_client_wakeup(self, saddr, daddr);
}
+ rcu_read_unlock();
}
/*
@@ -511,7 +512,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param,
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4],
bytes[5]);
for (i = 0; i < 6; i++)
- self->dev.dev_addr[i] = bytes[i];
+ self->dev->dev_addr[i] = bytes[i];
}
}
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index e9b7a7dd9176..b53d2b68de5d 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -31,8 +31,10 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
#include <asm/system.h>
#include <asm/bitops.h>
@@ -63,7 +65,8 @@
/*
* Master structure
*/
-hashbin_t *irlan = NULL;
+static LIST_HEAD(irlans);
+
static void *ckey;
static void *skey;
@@ -72,20 +75,6 @@ static int eth; /* Use "eth" or "irlan" name for devices */
static int access = ACCESS_PEER; /* PEER, DIRECT or HOSTED */
#ifdef CONFIG_PROC_FS
-static char *irlan_state[] = {
- "IRLAN_IDLE",
- "IRLAN_QUERY",
- "IRLAN_CONN",
- "IRLAN_INFO",
- "IRLAN_MEDIA",
- "IRLAN_OPEN",
- "IRLAN_WAIT",
- "IRLAN_ARB",
- "IRLAN_DATA",
- "IRLAN_CLOSE",
- "IRLAN_SYNC"
-};
-
static char *irlan_access[] = {
"UNKNOWN",
"DIRECT",
@@ -98,6 +87,20 @@ static char *irlan_media[] = {
"802.3",
"802.5"
};
+
+extern struct proc_dir_entry *proc_irda;
+
+static int irlan_seq_open(struct inode *inode, struct file *file);
+
+static struct file_operations irlan_fops = {
+ .owner = THIS_MODULE,
+ .open = irlan_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+extern struct proc_dir_entry *proc_irda;
#endif /* CONFIG_PROC_FS */
static void __irlan_close(struct irlan_cb *self);
@@ -106,12 +109,6 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type,
__u8 *value_array, __u16 value_len);
void irlan_close_tsaps(struct irlan_cb *self);
-#ifdef CONFIG_PROC_FS
-static int irlan_proc_read(char *buf, char **start, off_t offset, int len);
-
-extern struct proc_dir_entry *proc_irda;
-#endif /* CONFIG_PROC_FS */
-
/*
* Function irlan_init (void)
*
@@ -124,14 +121,17 @@ int __init irlan_init(void)
__u16 hints;
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
- /* Allocate master structure */
- irlan = hashbin_new(HB_LOCK); /* protect from /proc */
- if (irlan == NULL) {
- printk(KERN_WARNING "IrLAN: Can't allocate hashbin!\n");
- return -ENOMEM;
- }
+
#ifdef CONFIG_PROC_FS
- create_proc_info_entry("irlan", 0, proc_irda, irlan_proc_read);
+ { struct proc_dir_entry *proc;
+ proc = create_proc_entry("irlan", 0, proc_irda);
+ if (!proc) {
+ printk(KERN_ERR "irlan_init: can't create /proc entry!\n");
+ return -ENODEV;
+ }
+
+ proc->proc_fops = &irlan_fops;
+ }
#endif /* CONFIG_PROC_FS */
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
@@ -158,6 +158,8 @@ int __init irlan_init(void)
void __exit irlan_cleanup(void)
{
+ struct irlan_cb *self, *next;
+
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
irlmp_unregister_client(ckey);
@@ -166,37 +168,13 @@ void __exit irlan_cleanup(void)
#ifdef CONFIG_PROC_FS
remove_proc_entry("irlan", proc_irda);
#endif /* CONFIG_PROC_FS */
- /*
- * Delete hashbin and close all irlan client instances in it
- */
- hashbin_delete(irlan, (FREE_FUNC) __irlan_close);
-}
-
-/*
- * Function irlan_register_netdev (self)
- *
- * Registers the network device to be used. We should don't register until
- * we have been binded to a particular provider or client.
- */
-int irlan_register_netdev(struct irlan_cb *self)
-{
- int i=0;
-
- IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
- /* Check if we should call the device eth<x> or irlan<x> */
- if (!eth) {
- /* Get the first free irlan<x> name */
- do {
- sprintf(self->dev.name, "%s%d", "irlan", i++);
- } while (dev_get(self->dev.name));
+ /* Cleanup any leftover network devices */
+ rtnl_lock();
+ list_for_each_entry_safe(self, next, &irlans, dev_list) {
+ __irlan_close(self);
}
-
- if (register_netdev(&self->dev) != 0) {
- IRDA_DEBUG(2, "%s(), register_netdev() failed!\n", __FUNCTION__ );
- return -1;
- }
- return 0;
+ rtnl_unlock();
}
/*
@@ -207,31 +185,25 @@ int irlan_register_netdev(struct irlan_cb *self)
*/
struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
{
+ struct net_device *dev;
struct irlan_cb *self;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
- ASSERT(irlan != NULL, return NULL;);
- /*
- * Initialize the irlan structure.
- */
- self = kmalloc(sizeof(struct irlan_cb), GFP_ATOMIC);
- if (self == NULL)
+ /* Create network device with irlan */
+ dev = alloc_netdev(sizeof(*self),
+ eth ? "eth%d" : "irlan%d",
+ irlan_eth_setup);
+ if (!dev)
return NULL;
-
- memset(self, 0, sizeof(struct irlan_cb));
+
+ self = dev->priv;
+ self->dev = dev;
/*
* Initialize local device structure
*/
self->magic = IRLAN_MAGIC;
-
- sprintf(self->dev.name, "%s", "unknown");
-
- self->dev.priv = (void *) self;
- self->dev.next = NULL;
- self->dev.init = irlan_eth_init;
-
self->saddr = saddr;
self->daddr = daddr;
@@ -242,15 +214,22 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
init_timer(&self->watchdog_timer);
init_timer(&self->client.kick_timer);
init_waitqueue_head(&self->open_wait);
-
- hashbin_insert(irlan, (irda_queue_t *) self, daddr, NULL);
skb_queue_head_init(&self->client.txq);
irlan_next_client_state(self, IRLAN_IDLE);
irlan_next_provider_state(self, IRLAN_IDLE);
- irlan_register_netdev(self);
+ if (register_netdev(dev)) {
+ IRDA_DEBUG(2, "%s(), register_netdev() failed!\n",
+ __FUNCTION__ );
+ self = NULL;
+ kfree(dev);
+ } else {
+ rtnl_lock();
+ list_add_rcu(&self->dev_list, &irlans);
+ rtnl_unlock();
+ }
return self;
}
@@ -258,8 +237,8 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr)
* Function __irlan_close (self)
*
* This function closes and deallocates the IrLAN client instances. Be
- * aware that other functions which calles client_close() must call
- * hashbin_remove() first!!!
+ * aware that other functions which calls client_close() must
+ * remove self from irlans list first.
*/
static void __irlan_close(struct irlan_cb *self)
{
@@ -267,6 +246,7 @@ static void __irlan_close(struct irlan_cb *self)
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
+ ASSERT_RTNL();
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -283,10 +263,19 @@ static void __irlan_close(struct irlan_cb *self)
while ((skb = skb_dequeue(&self->client.txq)))
dev_kfree_skb(skb);
- unregister_netdev(&self->dev);
-
- self->magic = 0;
- kfree(self);
+ /* Unregister and free self via destructor */
+ unregister_netdevice(self->dev);
+}
+
+/* Find any instance of irlan, used for client discovery wakeup */
+struct irlan_cb *irlan_get_any(void)
+{
+ struct irlan_cb *self;
+
+ list_for_each_entry_rcu(self, &irlans, dev_list) {
+ return self;
+ }
+ return NULL;
}
/*
@@ -337,7 +326,7 @@ void irlan_connect_indication(void *instance, void *sap, struct qos_info *qos,
irlan_open_unicast_addr(self);
}
/* Ready to transfer Ethernet frames (at last) */
- netif_start_queue(&self->dev); /* Clear reason */
+ netif_start_queue(self->dev); /* Clear reason */
}
void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
@@ -371,7 +360,7 @@ void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
irlan_set_multicast_filter(self, TRUE);
/* Ready to transfer Ethernet frames */
- netif_start_queue(&self->dev);
+ netif_start_queue(self->dev);
self->disconnect_reason = 0; /* Clear reason */
#ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP
irlan_eth_send_gratuitous_arp(&self->dev);
@@ -1079,59 +1068,104 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
}
#ifdef CONFIG_PROC_FS
+#define IRLAN_PROC_START_TOKEN ((void *)1)
+
/*
- * Function irlan_client_proc_read (buf, start, offset, len, unused)
- *
- * Give some info to the /proc file system
+ * Start of reading /proc entries.
+ * Return entry at pos,
+ * or start_token to indicate print header line
+ * or NULL if end of file
*/
-static int irlan_proc_read(char *buf, char **start, off_t offset, int len)
+static void *irlan_seq_start(struct seq_file *seq, loff_t *pos)
{
- struct irlan_cb *self;
- unsigned long flags;
- ASSERT(irlan != NULL, return 0;);
-
- len = 0;
-
- spin_lock_irqsave(&irlan->hb_spinlock, flags);
+ int i = 1;
+ struct irlan_cb *self;
- len += sprintf(buf+len, "IrLAN instances:\n");
-
- self = (struct irlan_cb *) hashbin_get_first(irlan);
- while (self != NULL) {
- ASSERT(self->magic == IRLAN_MAGIC, break;);
+ rcu_read_lock();
+ if (*pos == 0)
+ return IRLAN_PROC_START_TOKEN;
+
+ list_for_each_entry(self, &irlans, dev_list) {
+ if (*pos == i)
+ return self;
+ ++i;
+ }
+ return NULL;
+}
+
+/* Return entry after v, and increment pos */
+static void *irlan_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct list_head *nxt;
+
+ ++*pos;
+ if (v == IRLAN_PROC_START_TOKEN)
+ nxt = irlans.next;
+ else
+ nxt = ((struct irlan_cb *)v)->dev_list.next;
+
+ return (nxt == &irlans) ? NULL
+ : list_entry(nxt, struct irlan_cb, dev_list);
+}
+
+/* End of reading /proc file */
+static void irlan_seq_stop(struct seq_file *seq, void *v)
+{
+ rcu_read_unlock();
+}
+
+
+/*
+ * Show one entry in /proc file.
+ */
+static int irlan_seq_show(struct seq_file *seq, void *v)
+{
+ if (v == IRLAN_PROC_START_TOKEN)
+ seq_puts(seq, "IrLAN instances:\n");
+ else {
+ struct irlan_cb *self = v;
- len += sprintf(buf+len, "ifname: %s,\n",
- self->dev.name);
- len += sprintf(buf+len, "client state: %s, ",
+ ASSERT(self != NULL, return -1;);
+ ASSERT(self->magic == IRLAN_MAGIC, return -1;);
+
+ seq_printf(seq,"ifname: %s,\n",
+ self->dev->name);
+ seq_printf(seq,"client state: %s, ",
irlan_state[ self->client.state]);
- len += sprintf(buf+len, "provider state: %s,\n",
+ seq_printf(seq,"provider state: %s,\n",
irlan_state[ self->provider.state]);
- len += sprintf(buf+len, "saddr: %#08x, ",
+ seq_printf(seq,"saddr: %#08x, ",
self->saddr);
- len += sprintf(buf+len, "daddr: %#08x\n",
+ seq_printf(seq,"daddr: %#08x\n",
self->daddr);
- len += sprintf(buf+len, "version: %d.%d,\n",
+ seq_printf(seq,"version: %d.%d,\n",
self->version[1], self->version[0]);
- len += sprintf(buf+len, "access type: %s\n",
+ seq_printf(seq,"access type: %s\n",
irlan_access[self->client.access_type]);
- len += sprintf(buf+len, "media: %s\n",
+ seq_printf(seq,"media: %s\n",
irlan_media[self->media]);
- len += sprintf(buf+len, "local filter:\n");
- len += sprintf(buf+len, "remote filter: ");
- len += irlan_print_filter(self->client.filter_type,
- buf+len);
-
- len += sprintf(buf+len, "tx busy: %s\n",
- netif_queue_stopped(&self->dev) ? "TRUE" : "FALSE");
+ seq_printf(seq,"local filter:\n");
+ seq_printf(seq,"remote filter: ");
+ irlan_print_filter(seq, self->client.filter_type);
+ seq_printf(seq,"tx busy: %s\n",
+ netif_queue_stopped(self->dev) ? "TRUE" : "FALSE");
- len += sprintf(buf+len, "\n");
+ seq_putc(seq,'\n');
+ }
+ return 0;
+}
- self = (struct irlan_cb *) hashbin_get_next(irlan);
- }
- spin_unlock_irqrestore(&irlan->hb_spinlock, flags);
+static struct seq_operations irlan_seq_ops = {
+ .start = irlan_seq_start,
+ .next = irlan_seq_next,
+ .stop = irlan_seq_stop,
+ .show = irlan_seq_show,
+};
- return len;
+static int irlan_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &irlan_seq_ops);
}
#endif
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 6ba413f5e82b..6a9c33f6ff31 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -47,14 +47,12 @@
* The network device initialization function.
*
*/
-int irlan_eth_init(struct net_device *dev)
+void irlan_eth_setup(struct net_device *dev)
{
struct irlan_cb *self;
IRDA_DEBUG(2, "%s()\n", __FUNCTION__ );
- ASSERT(dev != NULL, return -1;);
-
self = (struct irlan_cb *) dev->priv;
dev->open = irlan_eth_open;
@@ -62,6 +60,8 @@ int irlan_eth_init(struct net_device *dev)
dev->hard_start_xmit = irlan_eth_xmit;
dev->get_stats = irlan_eth_get_stats;
dev->set_multicast_list = irlan_eth_set_multicast_list;
+ dev->destructor = (void (*)(struct net_device *)) kfree;
+
SET_MODULE_OWNER(dev);
ether_setup(dev);
@@ -85,8 +85,6 @@ int irlan_eth_init(struct net_device *dev)
get_random_bytes(dev->dev_addr+4, 1);
get_random_bytes(dev->dev_addr+5, 1);
}
-
- return 0;
}
/*
@@ -237,7 +235,7 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb)
* might have been previously set by the low level IrDA network
* device driver
*/
- skb->dev = &self->dev;
+ skb->dev = self->dev;
skb->protocol=eth_type_trans(skb, skb->dev); /* Remove eth header */
self->stats.rx_packets++;
@@ -264,7 +262,7 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
ASSERT(self != NULL, return;);
ASSERT(self->magic == IRLAN_MAGIC, return;);
- dev = &self->dev;
+ dev = self->dev;
ASSERT(dev != NULL, return;);
diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c
index 66f4a842cc6c..87e4601231f6 100644
--- a/net/irda/irlan/irlan_filter.c
+++ b/net/irda/irlan/irlan_filter.c
@@ -24,6 +24,7 @@
#include <linux/skbuff.h>
#include <linux/random.h>
+#include <linux/seq_file.h>
#include <net/irda/irlan_common.h>
@@ -216,26 +217,30 @@ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value)
* Print status of filter. Used by /proc file system
*
*/
-int irlan_print_filter(int filter_type, char *buf)
+#ifdef CONFIG_PROC_FS
+#define MASK2STR(m,s) { .mask = m, .str = s }
+
+void irlan_print_filter(struct seq_file *seq, int filter_type)
{
- int len = 0;
-
- if (filter_type & IRLAN_DIRECTED)
- len += sprintf(buf+len, "%s", "DIRECTED ");
- if (filter_type & IRLAN_FUNCTIONAL)
- len += sprintf(buf+len, "%s", "FUNCTIONAL ");
- if (filter_type & IRLAN_GROUP)
- len += sprintf(buf+len, "%s", "GROUP ");
- if (filter_type & IRLAN_MAC_FRAME)
- len += sprintf(buf+len, "%s", "MAC_FRAME ");
- if (filter_type & IRLAN_MULTICAST)
- len += sprintf(buf+len, "%s", "MULTICAST ");
- if (filter_type & IRLAN_BROADCAST)
- len += sprintf(buf+len, "%s", "BROADCAST ");
- if (filter_type & IRLAN_IPX_SOCKET)
- len += sprintf(buf+len, "%s", "IPX_SOCKET");
-
- len += sprintf(buf+len, "\n");
-
- return len;
+ static struct {
+ int mask;
+ const char *str;
+ } filter_mask2str[] = {
+ MASK2STR(IRLAN_DIRECTED, "DIRECTED"),
+ MASK2STR(IRLAN_FUNCTIONAL, "FUNCTIONAL"),
+ MASK2STR(IRLAN_GROUP, "GROUP"),
+ MASK2STR(IRLAN_MAC_FRAME, "MAC_FRAME"),
+ MASK2STR(IRLAN_MULTICAST, "MULTICAST"),
+ MASK2STR(IRLAN_BROADCAST, "BROADCAST"),
+ MASK2STR(IRLAN_IPX_SOCKET, "IPX_SOCKET"),
+ MASK2STR(0, NULL)
+ }, *p;
+
+ for (p = filter_mask2str; p->str; p++) {
+ if (filter_type & p->mask)
+ seq_printf(seq, "%s ", p->str);
+ }
+ seq_putc(seq, '\n');
}
+#undef MASK2STR
+#endif
diff --git a/net/irda/irproc.c b/net/irda/irproc.c
index aef346111238..6373aba599b1 100644
--- a/net/irda/irproc.c
+++ b/net/irda/irproc.c
@@ -62,14 +62,18 @@ static struct irda_entry dir[] = {
void __init irda_proc_register(void)
{
int i;
+ struct proc_dir_entry *d;
proc_irda = proc_mkdir("net/irda", NULL);
if (proc_irda == NULL)
return;
proc_irda->owner = THIS_MODULE;
- for (i=0; i<ARRAY_SIZE(dir); i++)
- create_proc_info_entry(dir[i].name,0,proc_irda,dir[i].fn);
+ for (i=0; i<ARRAY_SIZE(dir); i++) {
+ d = create_proc_info_entry(dir[i].name,0,proc_irda,dir[i].fn);
+ if (d)
+ d->owner = THIS_MODULE;
+ }
}
/*
diff --git a/net/netrom/nr_dev.c b/net/netrom/nr_dev.c
index 1d126a109a9a..a86becaacc2a 100644
--- a/net/netrom/nr_dev.c
+++ b/net/netrom/nr_dev.c
@@ -204,7 +204,7 @@ void nr_setup(struct net_device *dev)
dev->hard_start_xmit = nr_xmit;
dev->open = nr_open;
dev->stop = nr_close;
- dev->destructor = (void (*)(struct net_device *))kfree;
+ dev->destructor = free_netdev;
dev->hard_header = nr_header;
dev->hard_header_len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
diff --git a/net/netsyms.c b/net/netsyms.c
index a1b61a2af1c9..660fe34f9e68 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -480,6 +480,7 @@ EXPORT_SYMBOL(call_netdevice_notifiers);
EXPORT_SYMBOL(loopback_dev);
EXPORT_SYMBOL(register_netdevice);
EXPORT_SYMBOL(unregister_netdevice);
+EXPORT_SYMBOL(free_netdev);
EXPORT_SYMBOL(synchronize_net);
EXPORT_SYMBOL(netdev_state_change);
EXPORT_SYMBOL(netdev_boot_setup_check);
diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c
index d540328896ab..59ef64968f0d 100644
--- a/net/rose/af_rose.c
+++ b/net/rose/af_rose.c
@@ -1580,7 +1580,7 @@ static void __exit rose_exit(void)
if (dev) {
unregister_netdev(dev);
- kfree(dev);
+ free_netdev(dev);
}
}
diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
index 5e54ef181e6d..0606b0eb140a 100644
--- a/net/sched/sch_teql.c
+++ b/net/sched/sch_teql.c
@@ -498,7 +498,7 @@ static void __exit teql_exit(void)
unregister_qdisc(&master->qops);
unregister_netdev(master->dev);
- kfree(master->dev);
+ free_netdev(master->dev);
}
spin_unlock(&master_dev_lock);
}
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 34091a2f8a3f..2d8659709f36 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -908,7 +908,7 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name)
unregister_netdev(dev);
- kfree(dev);
+ free_netdev(dev);
return 0;
}