diff options
| author | David S. Miller <davem@kernel.bkbits.net> | 2003-08-19 06:13:58 -0700 |
|---|---|---|
| committer | David S. Miller <davem@kernel.bkbits.net> | 2003-08-19 06:13:58 -0700 |
| commit | 9bff215af2cae2932448a110bd3ec5e7db3f43aa (patch) | |
| tree | 42c9e0413b469f4e2b33615406b13cb4263479c6 /net | |
| parent | 76e8b3a47a22076c9ca8fa741d9765d30be309ab (diff) | |
| parent | fbc1cf5cfa15c6ee7772bc8cd127f218155e3614 (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.c | 137 | ||||
| -rw-r--r-- | net/8021q/vlan.c | 2 | ||||
| -rw-r--r-- | net/Kconfig | 1 | ||||
| -rw-r--r-- | net/atm/br2684.c | 222 | ||||
| -rw-r--r-- | net/atm/clip.c | 2 | ||||
| -rw-r--r-- | net/atm/common.c | 3 | ||||
| -rw-r--r-- | net/atm/lec.c | 2 | ||||
| -rw-r--r-- | net/atm/pppoatm.c | 8 | ||||
| -rw-r--r-- | net/bridge/br_device.c | 18 | ||||
| -rw-r--r-- | net/core/dev.c | 34 | ||||
| -rw-r--r-- | net/core/neighbour.c | 28 | ||||
| -rw-r--r-- | net/core/net-sysfs.c | 15 | ||||
| -rw-r--r-- | net/ipv4/arp.c | 21 | ||||
| -rw-r--r-- | net/ipv4/ip_gre.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ipip.c | 2 | ||||
| -rw-r--r-- | net/ipv4/ipmr.c | 2 | ||||
| -rw-r--r-- | net/ipv6/ndisc.c | 21 | ||||
| -rw-r--r-- | net/ipv6/sit.c | 2 | ||||
| -rw-r--r-- | net/irda/ircomm/ircomm_tty.c | 8 | ||||
| -rw-r--r-- | net/irda/irda_device.c | 13 | ||||
| -rw-r--r-- | net/irda/irlan/irlan_client.c | 7 | ||||
| -rw-r--r-- | net/irda/irlan/irlan_common.c | 274 | ||||
| -rw-r--r-- | net/irda/irlan/irlan_eth.c | 12 | ||||
| -rw-r--r-- | net/irda/irlan/irlan_filter.c | 47 | ||||
| -rw-r--r-- | net/irda/irproc.c | 8 | ||||
| -rw-r--r-- | net/netrom/nr_dev.c | 2 | ||||
| -rw-r--r-- | net/netsyms.c | 1 | ||||
| -rw-r--r-- | net/rose/af_rose.c | 2 | ||||
| -rw-r--r-- | net/sched/sch_teql.c | 2 | ||||
| -rw-r--r-- | net/wanrouter/wanmain.c | 2 |
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; } |
