diff options
Diffstat (limited to 'net/atm')
| -rw-r--r-- | net/atm/atm_misc.c | 4 | ||||
| -rw-r--r-- | net/atm/atm_sysfs.c | 51 | ||||
| -rw-r--r-- | net/atm/br2684.c | 134 | ||||
| -rw-r--r-- | net/atm/clip.c | 217 | ||||
| -rw-r--r-- | net/atm/common.c | 57 | ||||
| -rw-r--r-- | net/atm/common.h | 1 | ||||
| -rw-r--r-- | net/atm/ioctl.c | 8 | ||||
| -rw-r--r-- | net/atm/lec.c | 249 | ||||
| -rw-r--r-- | net/atm/lec.h | 9 | ||||
| -rw-r--r-- | net/atm/mpc.c | 23 | ||||
| -rw-r--r-- | net/atm/mpoa_proc.c | 2 | ||||
| -rw-r--r-- | net/atm/pppoatm.c | 170 | ||||
| -rw-r--r-- | net/atm/proc.c | 10 | ||||
| -rw-r--r-- | net/atm/pvc.c | 2 | ||||
| -rw-r--r-- | net/atm/raw.c | 2 | ||||
| -rw-r--r-- | net/atm/resources.c | 9 | ||||
| -rw-r--r-- | net/atm/resources.h | 2 | ||||
| -rw-r--r-- | net/atm/signaling.c | 7 | ||||
| -rw-r--r-- | net/atm/svc.c | 11 | 
19 files changed, 490 insertions, 478 deletions
diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index fc63526d869..876fbe83e2e 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -9,7 +9,7 @@  #include <linux/sonet.h>  #include <linux/bitops.h>  #include <linux/errno.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  int atm_charge(struct atm_vcc *vcc, int truesize)  { @@ -26,7 +26,7 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size,  				 gfp_t gfp_flags)  {  	struct sock *sk = sk_atm(vcc); -	int guess = atm_guess_pdu2truesize(pdu_size); +	int guess = SKB_TRUESIZE(pdu_size);  	atm_force_charge(vcc, guess);  	if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index 799c631f0fe..350bf62b2ae 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -14,67 +14,67 @@ static ssize_t show_type(struct device *cdev,  			 struct device_attribute *attr, char *buf)  {  	struct atm_dev *adev = to_atm_dev(cdev); -	return sprintf(buf, "%s\n", adev->type); + +	return scnprintf(buf, PAGE_SIZE, "%s\n", adev->type);  }  static ssize_t show_address(struct device *cdev,  			    struct device_attribute *attr, char *buf)  { -	char *pos = buf;  	struct atm_dev *adev = to_atm_dev(cdev); -	int i; - -	for (i = 0; i < (ESI_LEN - 1); i++) -		pos += sprintf(pos, "%02x:", adev->esi[i]); -	pos += sprintf(pos, "%02x\n", adev->esi[i]); -	return pos - buf; +	return scnprintf(buf, PAGE_SIZE, "%pM\n", adev->esi);  }  static ssize_t show_atmaddress(struct device *cdev,  			       struct device_attribute *attr, char *buf)  {  	unsigned long flags; -	char *pos = buf;  	struct atm_dev *adev = to_atm_dev(cdev);  	struct atm_dev_addr *aaddr;  	int bin[] = { 1, 2, 10, 6, 1 }, *fmt = bin; -	int i, j; +	int i, j, count = 0;  	spin_lock_irqsave(&adev->lock, flags);  	list_for_each_entry(aaddr, &adev->local, entry) {  		for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {  			if (j == *fmt) { -				pos += sprintf(pos, "."); +				count += scnprintf(buf + count, +						   PAGE_SIZE - count, ".");  				++fmt;  				j = 0;  			} -			pos += sprintf(pos, "%02x", -				       aaddr->addr.sas_addr.prv[i]); +			count += scnprintf(buf + count, +					   PAGE_SIZE - count, "%02x", +					   aaddr->addr.sas_addr.prv[i]);  		} -		pos += sprintf(pos, "\n"); +		count += scnprintf(buf + count, PAGE_SIZE - count, "\n");  	}  	spin_unlock_irqrestore(&adev->lock, flags); -	return pos - buf; +	return count; +} + +static ssize_t show_atmindex(struct device *cdev, +			     struct device_attribute *attr, char *buf) +{ +	struct atm_dev *adev = to_atm_dev(cdev); + +	return scnprintf(buf, PAGE_SIZE, "%d\n", adev->number);  }  static ssize_t show_carrier(struct device *cdev,  			    struct device_attribute *attr, char *buf)  { -	char *pos = buf;  	struct atm_dev *adev = to_atm_dev(cdev); -	pos += sprintf(pos, "%d\n", -		       adev->signal == ATM_PHY_SIG_LOST ? 0 : 1); - -	return pos - buf; +	return scnprintf(buf, PAGE_SIZE, "%d\n", +			 adev->signal == ATM_PHY_SIG_LOST ? 0 : 1);  }  static ssize_t show_link_rate(struct device *cdev,  			      struct device_attribute *attr, char *buf)  { -	char *pos = buf;  	struct atm_dev *adev = to_atm_dev(cdev);  	int link_rate; @@ -92,13 +92,12 @@ static ssize_t show_link_rate(struct device *cdev,  	default:  		link_rate = adev->link_rate * 8 * 53;  	} -	pos += sprintf(pos, "%d\n", link_rate); - -	return pos - buf; +	return scnprintf(buf, PAGE_SIZE, "%d\n", link_rate);  }  static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);  static DEVICE_ATTR(atmaddress, S_IRUGO, show_atmaddress, NULL); +static DEVICE_ATTR(atmindex, S_IRUGO, show_atmindex, NULL);  static DEVICE_ATTR(carrier, S_IRUGO, show_carrier, NULL);  static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);  static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL); @@ -106,6 +105,7 @@ static DEVICE_ATTR(link_rate, S_IRUGO, show_link_rate, NULL);  static struct device_attribute *atm_attrs[] = {  	&dev_attr_atmaddress,  	&dev_attr_address, +	&dev_attr_atmindex,  	&dev_attr_carrier,  	&dev_attr_type,  	&dev_attr_link_rate, @@ -143,12 +143,13 @@ static struct class atm_class = {  	.dev_uevent		= atm_uevent,  }; -int atm_register_sysfs(struct atm_dev *adev) +int atm_register_sysfs(struct atm_dev *adev, struct device *parent)  {  	struct device *cdev = &adev->class_dev;  	int i, j, err;  	cdev->class = &atm_class; +	cdev->parent = parent;  	dev_set_drvdata(cdev, adev);  	dev_set_name(cdev, "%s%d", adev->type, adev->number); diff --git a/net/atm/br2684.c b/net/atm/br2684.c index fce2eae8d47..403e71fa88f 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -53,6 +53,7 @@ static const unsigned char ethertype_ipv4[] = { ETHERTYPE_IPV4 };  static const unsigned char ethertype_ipv6[] = { ETHERTYPE_IPV6 };  static const unsigned char llc_oui_pid_pad[] =  			{ LLC, SNAP_BRIDGED, PID_ETHERNET, PAD_BRIDGED }; +static const unsigned char pad[] = { PAD_BRIDGED };  static const unsigned char llc_oui_ipv4[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV4 };  static const unsigned char llc_oui_ipv6[] = { LLC, SNAP_ROUTED, ETHERTYPE_IPV6 }; @@ -67,12 +68,15 @@ struct br2684_vcc {  	/* 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); +	void (*old_release_cb)(struct atm_vcc *vcc); +	struct module *old_owner;  	enum br2684_encaps encaps;  	struct list_head brvccs;  #ifdef CONFIG_ATM_BR2684_IPFILTER  	struct br2684_filter filter;  #endif /* CONFIG_ATM_BR2684_IPFILTER */ -	unsigned copies_needed, copies_failed; +	unsigned int copies_needed, copies_failed; +	atomic_t qspace;  };  struct br2684_dev { @@ -180,18 +184,15 @@ static struct notifier_block atm_dev_notifier = {  static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)  {  	struct br2684_vcc *brvcc = BR2684_VCC(vcc); -	struct net_device *net_dev = skb->dev; -	pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev); +	pr_debug("(vcc %p ; net_dev %p )\n", vcc, brvcc->device);  	brvcc->old_pop(vcc, skb); -	if (!net_dev) -		return; - -	if (atm_may_send(vcc, 0)) -		netif_wake_queue(net_dev); - +	/* If the queue space just went up from zero, wake */ +	if (atomic_inc_return(&brvcc->qspace) == 1) +		netif_wake_queue(brvcc->device);  } +  /*   * Send a packet out a particular vcc.  Not to useful right now, but paves   * the way for multiple vcc's per itf.  Returns true if we can send, @@ -202,7 +203,10 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,  {  	struct br2684_dev *brdev = BRPRIV(dev);  	struct atm_vcc *atmvcc; -	int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2; +	int minheadroom = (brvcc->encaps == e_llc) ? +		((brdev->payload == p_bridged) ? +			sizeof(llc_oui_pid_pad) : sizeof(llc_oui_ipv4)) : +		((brdev->payload == p_bridged) ? BR2684_PAD_LEN : 0);  	if (skb_headroom(skb) < minheadroom) {  		struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom); @@ -242,8 +246,6 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,  		if (brdev->payload == p_bridged) {  			skb_push(skb, 2);  			memset(skb->data, 0, 2); -		} else { /* p_routed */ -			skb_pull(skb, ETH_HLEN);  		}  	}  	skb_debug(skb); @@ -254,16 +256,30 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,  	ATM_SKB(skb)->atm_options = atmvcc->atm_options;  	dev->stats.tx_packets++;  	dev->stats.tx_bytes += skb->len; -	atmvcc->send(atmvcc, skb); -	if (!atm_may_send(atmvcc, 0)) { +	if (atomic_dec_return(&brvcc->qspace) < 1) { +		/* No more please! */  		netif_stop_queue(brvcc->device); -		/*check for race with br2684_pop*/ -		if (atm_may_send(atmvcc, 0)) -			netif_start_queue(brvcc->device); +		/* We might have raced with br2684_pop() */ +		if (unlikely(atomic_read(&brvcc->qspace) > 0)) +			netif_wake_queue(brvcc->device);  	} -	return 1; +	/* If this fails immediately, the skb will be freed and br2684_pop() +	   will wake the queue if appropriate. Just return an error so that +	   the stats are updated correctly */ +	return !atmvcc->send(atmvcc, skb); +} + +static void br2684_release_cb(struct atm_vcc *atmvcc) +{ +	struct br2684_vcc *brvcc = BR2684_VCC(atmvcc); + +	if (atomic_read(&brvcc->qspace) > 0) +		netif_wake_queue(brvcc->device); + +	if (brvcc->old_release_cb) +		brvcc->old_release_cb(atmvcc);  }  static inline struct br2684_vcc *pick_outgoing_vcc(const struct sk_buff *skb, @@ -277,6 +293,8 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,  {  	struct br2684_dev *brdev = BRPRIV(dev);  	struct br2684_vcc *brvcc; +	struct atm_vcc *atmvcc; +	netdev_tx_t ret = NETDEV_TX_OK;  	pr_debug("skb_dst(skb)=%p\n", skb_dst(skb));  	read_lock(&devs_lock); @@ -287,9 +305,26 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,  		dev->stats.tx_carrier_errors++;  		/* netif_stop_queue(dev); */  		dev_kfree_skb(skb); -		read_unlock(&devs_lock); -		return NETDEV_TX_OK; +		goto out_devs; +	} +	atmvcc = brvcc->atmvcc; + +	bh_lock_sock(sk_atm(atmvcc)); + +	if (test_bit(ATM_VF_RELEASED, &atmvcc->flags) || +	    test_bit(ATM_VF_CLOSE, &atmvcc->flags) || +	    !test_bit(ATM_VF_READY, &atmvcc->flags)) { +		dev->stats.tx_dropped++; +		dev_kfree_skb(skb); +		goto out; +	} + +	if (sock_owned_by_user(sk_atm(atmvcc))) { +		netif_stop_queue(brvcc->device); +		ret = NETDEV_TX_BUSY; +		goto out;  	} +  	if (!br2684_xmit_vcc(skb, dev, brvcc)) {  		/*  		 * We should probably use netif_*_queue() here, but that @@ -301,8 +336,11 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,  		dev->stats.tx_errors++;  		dev->stats.tx_fifo_errors++;  	} + out: +	bh_unlock_sock(sk_atm(atmvcc)); + out_devs:  	read_unlock(&devs_lock); -	return NETDEV_TX_OK; +	return ret;  }  /* @@ -375,9 +413,10 @@ static void br2684_close_vcc(struct br2684_vcc *brvcc)  	list_del(&brvcc->brvccs);  	write_unlock_irq(&devs_lock);  	brvcc->atmvcc->user_back = NULL;	/* what about vcc->recvq ??? */ +	brvcc->atmvcc->release_cb = brvcc->old_release_cb;  	brvcc->old_push(brvcc->atmvcc, NULL);	/* pass on the bad news */ +	module_put(brvcc->old_owner);  	kfree(brvcc); -	module_put(THIS_MODULE);  }  /* when AAL5 PDU comes in: */ @@ -452,7 +491,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)  			skb->pkt_type = PACKET_HOST;  		} else { /* p_bridged */  			/* first 2 chars should be 0 */ -			if (*((u16 *) (skb->data)) != 0) +			if (memcmp(skb->data, pad, BR2684_PAD_LEN) != 0)  				goto error;  			skb_pull(skb, BR2684_PAD_LEN);  			skb->protocol = eth_type_trans(skb, net_dev); @@ -491,25 +530,28 @@ free_skb:   */  static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)  { -	struct sk_buff_head queue; -	int err;  	struct br2684_vcc *brvcc; -	struct sk_buff *skb, *tmp; -	struct sk_buff_head *rq;  	struct br2684_dev *brdev;  	struct net_device *net_dev;  	struct atm_backend_br2684 be; -	unsigned long flags; +	int err;  	if (copy_from_user(&be, arg, sizeof be))  		return -EFAULT;  	brvcc = kzalloc(sizeof(struct br2684_vcc), GFP_KERNEL);  	if (!brvcc)  		return -ENOMEM; +	/* +	 * Allow two packets in the ATM queue. One actually being sent, and one +	 * for the ATM 'TX done' handler to send. It shouldn't take long to get +	 * the next one from the netdev queue, when we need it. More than that +	 * would be bufferbloat. +	 */ +	atomic_set(&brvcc->qspace, 2);  	write_lock_irq(&devs_lock);  	net_dev = br2684_find_dev(&be.ifspec);  	if (net_dev == NULL) { -		pr_err("tried to attach to non-existant device\n"); +		pr_err("tried to attach to non-existent device\n");  		err = -ENXIO;  		goto error;  	} @@ -548,25 +590,13 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)  	brvcc->encaps = (enum br2684_encaps)be.encaps;  	brvcc->old_push = atmvcc->push;  	brvcc->old_pop = atmvcc->pop; +	brvcc->old_release_cb = atmvcc->release_cb; +	brvcc->old_owner = atmvcc->owner;  	barrier();  	atmvcc->push = br2684_push;  	atmvcc->pop = br2684_pop; - -	__skb_queue_head_init(&queue); -	rq = &sk_atm(atmvcc)->sk_receive_queue; - -	spin_lock_irqsave(&rq->lock, flags); -	skb_queue_splice_init(rq, &queue); -	spin_unlock_irqrestore(&rq->lock, flags); - -	skb_queue_walk_safe(&queue, skb, tmp) { -		struct net_device *dev = skb->dev; - -		dev->stats.rx_bytes -= skb->len; -		dev->stats.rx_packets--; - -		br2684_push(atmvcc, skb); -	} +	atmvcc->release_cb = br2684_release_cb; +	atmvcc->owner = THIS_MODULE;  	/* initialize netdev carrier state */  	if (atmvcc->dev->signal == ATM_PHY_SIG_LOST) @@ -575,6 +605,10 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)  		netif_carrier_on(net_dev);  	__module_get(THIS_MODULE); + +	/* re-process everything received between connection setup and +	   backend setup */ +	vcc_process_recv_queue(atmvcc);  	return 0;  error: @@ -601,6 +635,7 @@ static void br2684_setup(struct net_device *netdev)  	struct br2684_dev *brdev = BRPRIV(netdev);  	ether_setup(netdev); +	netdev->hard_header_len += sizeof(llc_oui_pid_pad); /* worst case */  	brdev->net_dev = netdev;  	netdev->netdev_ops = &br2684_netdev_ops; @@ -613,7 +648,7 @@ static void br2684_setup_routed(struct net_device *netdev)  	struct br2684_dev *brdev = BRPRIV(netdev);  	brdev->net_dev = netdev; -	netdev->hard_header_len = 0; +	netdev->hard_header_len = sizeof(llc_oui_ipv4); /* worst case */  	netdev->netdev_ops = &br2684_netdev_ops_routed;  	netdev->addr_len = 0;  	netdev->mtu = 1500; @@ -700,10 +735,13 @@ static int br2684_ioctl(struct socket *sock, unsigned int cmd,  			return -ENOIOCTLCMD;  		if (!capable(CAP_NET_ADMIN))  			return -EPERM; -		if (cmd == ATM_SETBACKEND) +		if (cmd == ATM_SETBACKEND) { +			if (sock->state != SS_CONNECTED) +				return -EINVAL;  			return br2684_regvcc(atmvcc, argp); -		else +		} else {  			return br2684_create(argp); +		}  #ifdef CONFIG_ATM_BR2684_IPFILTER  	case BR2684_SETFILT:  		if (atmvcc->push != br2684_push) diff --git a/net/atm/clip.c b/net/atm/clip.c index d257da50fcf..ba291ce4bdf 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -33,11 +33,11 @@  #include <linux/slab.h>  #include <net/route.h> /* for struct rtable and routing */  #include <net/icmp.h> /* icmp_send */ +#include <net/arp.h>  #include <linux/param.h> /* for HZ */  #include <linux/uaccess.h>  #include <asm/byteorder.h> /* for htons etc. */ -#include <asm/system.h> /* save/restore_flags */ -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "common.h"  #include "resources.h" @@ -45,8 +45,8 @@  static struct net_device *clip_devs;  static struct atm_vcc *atmarpd; -static struct neigh_table clip_tbl;  static struct timer_list idle_timer; +static const struct neigh_ops clip_neigh_ops;  static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)  { @@ -68,7 +68,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)  	sk = sk_atm(atmarpd);  	skb_queue_tail(&sk->sk_receive_queue, skb); -	sk->sk_data_ready(sk, skb->len); +	sk->sk_data_ready(sk);  	return 0;  } @@ -119,9 +119,11 @@ out:  /* The neighbour entry n->lock is held. */  static int neigh_check_cb(struct neighbour *n)  { -	struct atmarp_entry *entry = NEIGH2ENTRY(n); +	struct atmarp_entry *entry = neighbour_priv(n);  	struct clip_vcc *cv; +	if (n->ops != &clip_neigh_ops) +		return 0;  	for (cv = entry->vccs; cv; cv = cv->next) {  		unsigned long exp = cv->last_use + cv->idle_timeout; @@ -153,10 +155,10 @@ static int neigh_check_cb(struct neighbour *n)  static void idle_timer_check(unsigned long dummy)  { -	write_lock(&clip_tbl.lock); -	__neigh_for_each_release(&clip_tbl, neigh_check_cb); +	write_lock(&arp_tbl.lock); +	__neigh_for_each_release(&arp_tbl, neigh_check_cb);  	mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ); -	write_unlock(&clip_tbl.lock); +	write_unlock(&arp_tbl.lock);  }  static int clip_arp_rcv(struct sk_buff *skb) @@ -189,6 +191,13 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)  	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);  	pr_debug("\n"); + +	if (!clip_devs) { +		atm_return(vcc, skb->truesize); +		kfree_skb(skb); +		return; +	} +  	if (!skb) {  		pr_debug("removing VCC %p\n", clip_vcc);  		if (clip_vcc->entry) @@ -255,8 +264,10 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)  static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)  { +	__be32 *ip = (__be32 *) neigh->primary_key; +  	pr_debug("(neigh %p, skb %p)\n", neigh, skb); -	to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip); +	to_atmarpd(act_need, PRIV(neigh->dev)->number, *ip);  }  static void clip_neigh_error(struct neighbour *neigh, struct sk_buff *skb) @@ -271,80 +282,30 @@ static const struct neigh_ops clip_neigh_ops = {  	.family =		AF_INET,  	.solicit =		clip_neigh_solicit,  	.error_report =		clip_neigh_error, -	.output =		dev_queue_xmit, -	.connected_output =	dev_queue_xmit, -	.hh_output =		dev_queue_xmit, -	.queue_xmit =		dev_queue_xmit, +	.output =		neigh_direct_output, +	.connected_output =	neigh_direct_output,  };  static int clip_constructor(struct neighbour *neigh)  { -	struct atmarp_entry *entry = NEIGH2ENTRY(neigh); -	struct net_device *dev = neigh->dev; -	struct in_device *in_dev; -	struct neigh_parms *parms; +	struct atmarp_entry *entry = neighbour_priv(neigh); -	pr_debug("(neigh %p, entry %p)\n", neigh, entry); -	neigh->type = inet_addr_type(&init_net, entry->ip); -	if (neigh->type != RTN_UNICAST) +	if (neigh->tbl->family != AF_INET)  		return -EINVAL; -	rcu_read_lock(); -	in_dev = __in_dev_get_rcu(dev); -	if (!in_dev) { -		rcu_read_unlock(); +	if (neigh->type != RTN_UNICAST)  		return -EINVAL; -	} - -	parms = in_dev->arp_parms; -	__neigh_parms_put(neigh->parms); -	neigh->parms = neigh_parms_clone(parms); -	rcu_read_unlock(); +	neigh->nud_state = NUD_NONE;  	neigh->ops = &clip_neigh_ops; -	neigh->output = neigh->nud_state & NUD_VALID ? -	    neigh->ops->connected_output : neigh->ops->output; +	neigh->output = neigh->ops->output;  	entry->neigh = neigh;  	entry->vccs = NULL;  	entry->expires = jiffies - 1; +  	return 0;  } -static u32 clip_hash(const void *pkey, const struct net_device *dev, __u32 rnd) -{ -	return jhash_2words(*(u32 *) pkey, dev->ifindex, rnd); -} - -static struct neigh_table clip_tbl = { -	.family 	= AF_INET, -	.entry_size 	= sizeof(struct neighbour)+sizeof(struct atmarp_entry), -	.key_len 	= 4, -	.hash 		= clip_hash, -	.constructor 	= clip_constructor, -	.id 		= "clip_arp_cache", - -	/* parameters are copied from ARP ... */ -	.parms = { -		.tbl 			= &clip_tbl, -		.base_reachable_time 	= 30 * HZ, -		.retrans_time 		= 1 * HZ, -		.gc_staletime 		= 60 * HZ, -		.reachable_time 	= 30 * HZ, -		.delay_probe_time 	= 5 * HZ, -		.queue_len 		= 3, -		.ucast_probes 		= 3, -		.mcast_probes 		= 3, -		.anycast_delay 		= 1 * HZ, -		.proxy_delay 		= (8 * HZ) / 10, -		.proxy_qlen 		= 64, -		.locktime 		= 1 * HZ, -	}, -	.gc_interval 	= 30 * HZ, -	.gc_thresh1 	= 128, -	.gc_thresh2 	= 512, -	.gc_thresh3 	= 1024, -}; -  /* @@@ copy bh locking from arp.c -- need to bh-enable atm code before */  /* @@ -364,38 +325,40 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,  				   struct net_device *dev)  {  	struct clip_priv *clip_priv = PRIV(dev); +	struct dst_entry *dst = skb_dst(skb);  	struct atmarp_entry *entry; +	struct neighbour *n;  	struct atm_vcc *vcc; +	struct rtable *rt; +	__be32 *daddr;  	int old;  	unsigned long flags;  	pr_debug("(skb %p)\n", skb); -	if (!skb_dst(skb)) { +	if (!dst) {  		pr_err("skb_dst(skb) == NULL\n");  		dev_kfree_skb(skb);  		dev->stats.tx_dropped++;  		return NETDEV_TX_OK;  	} -	if (!skb_dst(skb)->neighbour) { -#if 0 -		skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1); -		if (!skb_dst(skb)->neighbour) { -			dev_kfree_skb(skb);	/* lost that one */ -			dev->stats.tx_dropped++; -			return 0; -		} -#endif +	rt = (struct rtable *) dst; +	if (rt->rt_gateway) +		daddr = &rt->rt_gateway; +	else +		daddr = &ip_hdr(skb)->daddr; +	n = dst_neigh_lookup(dst, daddr); +	if (!n) {  		pr_err("NO NEIGHBOUR !\n");  		dev_kfree_skb(skb);  		dev->stats.tx_dropped++;  		return NETDEV_TX_OK;  	} -	entry = NEIGH2ENTRY(skb_dst(skb)->neighbour); +	entry = neighbour_priv(n);  	if (!entry->vccs) {  		if (time_after(jiffies, entry->expires)) {  			/* should be resolved */  			entry->expires = jiffies + ATMARP_RETRY_DELAY * HZ; -			to_atmarpd(act_need, PRIV(dev)->number, entry->ip); +			to_atmarpd(act_need, PRIV(dev)->number, *((__be32 *)n->primary_key));  		}  		if (entry->neigh->arp_queue.qlen < ATMARP_MAX_UNRES_PACKETS)  			skb_queue_tail(&entry->neigh->arp_queue, skb); @@ -403,11 +366,11 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,  			dev_kfree_skb(skb);  			dev->stats.tx_dropped++;  		} -		return NETDEV_TX_OK; +		goto out_release_neigh;  	}  	pr_debug("neigh %p, vccs %p\n", entry, entry->vccs);  	ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; -	pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc); +	pr_debug("using neighbour %p, vcc %p\n", n, vcc);  	if (entry->vccs->encap) {  		void *here; @@ -422,14 +385,14 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,  	old = xchg(&entry->vccs->xoff, 1);	/* assume XOFF ... */  	if (old) {  		pr_warning("XOFF->XOFF transition\n"); -		return NETDEV_TX_OK; +		goto out_release_neigh;  	}  	dev->stats.tx_packets++;  	dev->stats.tx_bytes += skb->len;  	vcc->send(vcc, skb);  	if (atm_may_send(vcc, 0)) {  		entry->vccs->xoff = 0; -		return NETDEV_TX_OK; +		goto out_release_neigh;  	}  	spin_lock_irqsave(&clip_priv->xoff_lock, flags);  	netif_stop_queue(dev);	/* XOFF -> throttle immediately */ @@ -441,15 +404,14 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,  	   of the brief netif_stop_queue. If this isn't true or if it  	   changes, use netif_wake_queue instead. */  	spin_unlock_irqrestore(&clip_priv->xoff_lock, flags); +out_release_neigh: +	neigh_release(n);  	return NETDEV_TX_OK;  }  static int clip_mkip(struct atm_vcc *vcc, int timeout)  { -	struct sk_buff_head *rq, queue;  	struct clip_vcc *clip_vcc; -	struct sk_buff *skb, *tmp; -	unsigned long flags;  	if (!vcc->push)  		return -EBADFD; @@ -470,29 +432,9 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)  	vcc->push = clip_push;  	vcc->pop = clip_pop; -	__skb_queue_head_init(&queue); -	rq = &sk_atm(vcc)->sk_receive_queue; - -	spin_lock_irqsave(&rq->lock, flags); -	skb_queue_splice_init(rq, &queue); -	spin_unlock_irqrestore(&rq->lock, flags); -  	/* re-process everything received between connection setup and MKIP */ -	skb_queue_walk_safe(&queue, skb, tmp) { -		if (!clip_devs) { -			atm_return(vcc, skb->truesize); -			kfree_skb(skb); -		} else { -			struct net_device *dev = skb->dev; -			unsigned int len = skb->len; - -			skb_get(skb); -			clip_push(vcc, skb); -			dev->stats.rx_packets--; -			dev->stats.rx_bytes -= len; -			kfree_skb(skb); -		} -	} +	vcc_process_recv_queue(vcc); +  	return 0;  } @@ -502,8 +444,6 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)  	struct atmarp_entry *entry;  	int error;  	struct clip_vcc *clip_vcc; -	struct flowi fl = { .fl4_dst = ip, -			    .fl4_tos = 1 };  	struct rtable *rt;  	if (vcc->push != clip_push) { @@ -520,14 +460,14 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)  		unlink_clip_vcc(clip_vcc);  		return 0;  	} -	error = ip_route_output_key(&init_net, &rt, &fl); -	if (error) -		return error; -	neigh = __neigh_lookup(&clip_tbl, &ip, rt->dst.dev, 1); +	rt = ip_route_output(&init_net, ip, 0, 1, 0); +	if (IS_ERR(rt)) +		return PTR_ERR(rt); +	neigh = __neigh_lookup(&arp_tbl, &ip, rt->dst.dev, 1);  	ip_rt_put(rt);  	if (!neigh)  		return -ENOMEM; -	entry = NEIGH2ENTRY(neigh); +	entry = neighbour_priv(neigh);  	if (entry != clip_vcc->entry) {  		if (!clip_vcc->entry)  			pr_debug("add\n"); @@ -544,13 +484,15 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)  }  static const struct net_device_ops clip_netdev_ops = { -	.ndo_start_xmit = clip_start_xmit, +	.ndo_start_xmit		= clip_start_xmit, +	.ndo_neigh_construct	= clip_constructor,  };  static void clip_setup(struct net_device *dev)  {  	dev->netdev_ops = &clip_netdev_ops;  	dev->type = ARPHRD_ATM; +	dev->neigh_priv_len = sizeof(struct atmarp_entry);  	dev->hard_header_len = RFC1483LLC_LEN;  	dev->mtu = RFC1626_MTU;  	dev->tx_queue_len = 100;	/* "normal" queue (packets) */ @@ -597,17 +539,15 @@ static int clip_create(int number)  }  static int clip_device_event(struct notifier_block *this, unsigned long event, -			     void *arg) +			     void *ptr)  { -	struct net_device *dev = arg; +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);  	if (!net_eq(dev_net(dev), &init_net))  		return NOTIFY_DONE; -	if (event == NETDEV_UNREGISTER) { -		neigh_ifdown(&clip_tbl, dev); +	if (event == NETDEV_UNREGISTER)  		return NOTIFY_DONE; -	}  	/* ignore non-CLIP devices */  	if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops) @@ -635,6 +575,7 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event,  			   void *ifa)  {  	struct in_device *in_dev; +	struct netdev_notifier_info info;  	in_dev = ((struct in_ifaddr *)ifa)->ifa_dev;  	/* @@ -643,7 +584,8 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event,  	 */  	if (event != NETDEV_UP)  		return NOTIFY_DONE; -	return clip_device_event(this, NETDEV_CHANGE, in_dev->dev); +	netdev_notifier_info_init(&info, in_dev->dev); +	return clip_device_event(this, NETDEV_CHANGE, &info);  }  static struct notifier_block clip_dev_notifier = { @@ -787,9 +729,10 @@ static void svc_addr(struct seq_file *seq, struct sockaddr_atmsvc *addr)  /* This means the neighbour entry has no attached VCC objects. */  #define SEQ_NO_VCC_TOKEN	((void *) 2) -static void atmarp_info(struct seq_file *seq, struct net_device *dev, +static void atmarp_info(struct seq_file *seq, struct neighbour *n,  			struct atmarp_entry *entry, struct clip_vcc *clip_vcc)  { +	struct net_device *dev = n->dev;  	unsigned long exp;  	char buf[17];  	int svc, llc, off; @@ -809,8 +752,7 @@ static void atmarp_info(struct seq_file *seq, struct net_device *dev,  	seq_printf(seq, "%-6s%-4s%-4s%5ld ",  		   dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp); -	off = scnprintf(buf, sizeof(buf) - 1, "%pI4", -			&entry->ip); +	off = scnprintf(buf, sizeof(buf) - 1, "%pI4", n->primary_key);  	while (off < 16)  		buf[off++] = ' ';  	buf[off] = '\0'; @@ -881,14 +823,17 @@ static void *clip_seq_sub_iter(struct neigh_seq_state *_state,  {  	struct clip_seq_state *state = (struct clip_seq_state *)_state; -	return clip_seq_vcc_walk(state, NEIGH2ENTRY(n), pos); +	if (n->dev->type != ARPHRD_ATM) +		return NULL; + +	return clip_seq_vcc_walk(state, neighbour_priv(n), pos);  }  static void *clip_seq_start(struct seq_file *seq, loff_t * pos)  {  	struct clip_seq_state *state = seq->private;  	state->ns.neigh_sub_iter = clip_seq_sub_iter; -	return neigh_seq_start(seq, pos, &clip_tbl, NEIGH_SEQ_NEIGH_ONLY); +	return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_NEIGH_ONLY);  }  static int clip_seq_show(struct seq_file *seq, void *v) @@ -900,10 +845,10 @@ static int clip_seq_show(struct seq_file *seq, void *v)  		seq_puts(seq, atm_arp_banner);  	} else {  		struct clip_seq_state *state = seq->private; -		struct neighbour *n = v;  		struct clip_vcc *vcc = state->vcc; +		struct neighbour *n = v; -		atmarp_info(seq, n->dev, NEIGH2ENTRY(n), vcc); +		atmarp_info(seq, n, neighbour_priv(n), vcc);  	}  	return 0;  } @@ -934,9 +879,6 @@ static void atm_clip_exit_noproc(void);  static int __init atm_clip_init(void)  { -	neigh_table_init_no_netlink(&clip_tbl); - -	clip_tbl_hook = &clip_tbl;  	register_atm_ioctl(&clip_ioctl_ops);  	register_netdevice_notifier(&clip_dev_notifier);  	register_inetaddr_notifier(&clip_inet_notifier); @@ -973,12 +915,6 @@ static void atm_clip_exit_noproc(void)  	 */  	del_timer_sync(&idle_timer); -	/* Next, purge the table, so that the device -	 * unregister loop below does not hang due to -	 * device references remaining in the table. -	 */ -	neigh_ifdown(&clip_tbl, NULL); -  	dev = clip_devs;  	while (dev) {  		next = PRIV(dev)->next; @@ -986,11 +922,6 @@ static void atm_clip_exit_noproc(void)  		free_netdev(dev);  		dev = next;  	} - -	/* Now it is safe to fully shutdown whole table. */ -	neigh_table_clear(&clip_tbl); - -	clip_tbl_hook = NULL;  }  static void __exit atm_clip_exit(void) diff --git a/net/atm/common.c b/net/atm/common.c index 1b9c52a02cd..7b491006eaf 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -23,7 +23,7 @@  #include <linux/uaccess.h>  #include <linux/poll.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "resources.h"		/* atm_find_dev */  #include "common.h"		/* prototypes */ @@ -126,10 +126,19 @@ static void vcc_write_space(struct sock *sk)  	rcu_read_unlock();  } +static void vcc_release_cb(struct sock *sk) +{ +	struct atm_vcc *vcc = atm_sk(sk); + +	if (vcc->release_cb) +		vcc->release_cb(vcc); +} +  static struct proto vcc_proto = {  	.name	  = "VCC",  	.owner	  = THIS_MODULE,  	.obj_size = sizeof(struct atm_vcc), +	.release_cb = vcc_release_cb,  };  int vcc_create(struct net *net, struct socket *sock, int protocol, int family) @@ -156,7 +165,9 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)  	atomic_set(&sk->sk_rmem_alloc, 0);  	vcc->push = NULL;  	vcc->pop = NULL; +	vcc->owner = NULL;  	vcc->push_oam = NULL; +	vcc->release_cb = NULL;  	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */  	vcc->atm_options = vcc->aal_options = 0;  	sk->sk_destruct = vcc_sock_destruct; @@ -175,6 +186,7 @@ static void vcc_destroy_socket(struct sock *sk)  			vcc->dev->ops->close(vcc);  		if (vcc->push)  			vcc->push(vcc, NULL); /* atmarpd has no push */ +		module_put(vcc->owner);  		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {  			atm_return(vcc, skb->truesize); @@ -214,6 +226,26 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)  }  EXPORT_SYMBOL(vcc_release_async); +void vcc_process_recv_queue(struct atm_vcc *vcc) +{ +	struct sk_buff_head queue, *rq; +	struct sk_buff *skb, *tmp; +	unsigned long flags; + +	__skb_queue_head_init(&queue); +	rq = &sk_atm(vcc)->sk_receive_queue; + +	spin_lock_irqsave(&rq->lock, flags); +	skb_queue_splice_init(rq, &queue); +	spin_unlock_irqrestore(&rq->lock, flags); + +	skb_queue_walk_safe(&queue, skb, tmp) { +		__skb_unlink(skb, &queue); +		vcc->push(vcc, skb); +	} +} +EXPORT_SYMBOL(vcc_process_recv_queue); +  void atm_dev_signal_change(struct atm_dev *dev, char signal)  {  	pr_debug("%s signal=%d dev=%p number=%d dev->signal=%d\n", @@ -238,11 +270,11 @@ void atm_dev_release_vccs(struct atm_dev *dev)  	write_lock_irq(&vcc_sklist_lock);  	for (i = 0; i < VCC_HTABLE_SIZE; i++) {  		struct hlist_head *head = &vcc_hash[i]; -		struct hlist_node *node, *tmp; +		struct hlist_node *tmp;  		struct sock *s;  		struct atm_vcc *vcc; -		sk_for_each_safe(s, node, tmp, head) { +		sk_for_each_safe(s, tmp, head) {  			vcc = atm_sk(s);  			if (vcc->dev == dev) {  				vcc_release_async(vcc, -EPIPE); @@ -252,6 +284,7 @@ void atm_dev_release_vccs(struct atm_dev *dev)  	}  	write_unlock_irq(&vcc_sklist_lock);  } +EXPORT_SYMBOL(atm_dev_release_vccs);  static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)  { @@ -284,11 +317,10 @@ static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)  static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)  {  	struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)]; -	struct hlist_node *node;  	struct sock *s;  	struct atm_vcc *walk; -	sk_for_each(s, node, head) { +	sk_for_each(s, head) {  		walk = atm_sk(s);  		if (walk->dev != vcc->dev)  			continue; @@ -501,8 +533,11 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,  	if (sock->state != SS_CONNECTED)  		return -ENOTCONN; -	if (flags & ~MSG_DONTWAIT)		/* only handle MSG_DONTWAIT */ + +	/* only handle MSG_DONTWAIT and MSG_PEEK */ +	if (flags & ~(MSG_DONTWAIT | MSG_PEEK))  		return -EOPNOTSUPP; +  	vcc = ATM_SD(sock);  	if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||  	    test_bit(ATM_VF_CLOSE, &vcc->flags) || @@ -523,8 +558,13 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,  	if (error)  		return error;  	sock_recv_ts_and_drops(msg, sk, skb); -	pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize); -	atm_return(vcc, skb->truesize); + +	if (!(flags & MSG_PEEK)) { +		pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), +			 skb->truesize); +		atm_return(vcc, skb->truesize); +	} +  	skb_free_datagram(sk, skb);  	return copied;  } @@ -783,6 +823,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,  		if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))  			return -ENOTCONN; +		memset(&pvc, 0, sizeof(pvc));  		pvc.sap_family = AF_ATMPVC;  		pvc.sap_addr.itf = vcc->dev->number;  		pvc.sap_addr.vpi = vcc->vpi; diff --git a/net/atm/common.h b/net/atm/common.h index f48a76b6cdf..cc3c2dae4d7 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -24,6 +24,7 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,  		   char __user *optval, unsigned int optlen);  int vcc_getsockopt(struct socket *sock, int level, int optname,  		   char __user *optval, int __user *optlen); +void vcc_process_recv_queue(struct atm_vcc *vcc);  int atmpvc_init(void);  void atmpvc_exit(void); diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 62dc8bfe6fe..bbd3b639992 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -97,9 +97,8 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,  			error = sock_get_timestampns(sk, argp);  		goto done;  	case ATM_SETSC: -		if (net_ratelimit()) -			pr_warning("ATM_SETSC is obsolete; used by %s:%d\n", -				   current->comm, task_pid_nr(current)); +		net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n", +				     current->comm, task_pid_nr(current));  		error = 0;  		goto done;  	case ATMSIGD_CTRL: @@ -123,8 +122,7 @@ static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,  		   work for 32-bit userspace. TBH I don't really want  		   to think about it at all. dwmw2. */  		if (compat) { -			if (net_ratelimit()) -				pr_warning("32-bit task cannot be atmsigd\n"); +			net_warn_ratelimited("32-bit task cannot be atmsigd\n");  			error = -EINVAL;  			goto done;  		} diff --git a/net/atm/lec.c b/net/atm/lec.c index 179e04bc99d..4c5b8ba0f84 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -26,11 +26,6 @@  #include <linux/spinlock.h>  #include <linux/seq_file.h> -/* TokenRing if needed */ -#ifdef CONFIG_TR -#include <linux/trdevice.h> -#endif -  /* And atm device */  #include <linux/atmdev.h>  #include <linux/atmlec.h> @@ -129,7 +124,6 @@ static struct net_device *dev_lec[MAX_LEC_ITF];  #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)  static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)  { -	struct ethhdr *eth;  	char *buff;  	struct lec_priv *priv; @@ -138,7 +132,6 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)  	 * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit  	 * as the Config BPDU has  	 */ -	eth = (struct ethhdr *)skb->data;  	buff = skb->data + skb->dev->hard_header_len;  	if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {  		struct sock *sk; @@ -159,56 +152,12 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)  		atm_force_charge(priv->lecd, skb2->truesize);  		sk = sk_atm(priv->lecd);  		skb_queue_tail(&sk->sk_receive_queue, skb2); -		sk->sk_data_ready(sk, skb2->len); +		sk->sk_data_ready(sk);  	}  }  #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */  /* - * Modelled after tr_type_trans - * All multicast and ARE or STE frames go to BUS. - * Non source routed frames go by destination address. - * Last hop source routed frames go by destination address. - * Not last hop source routed frames go by _next_ route descriptor. - * Returns pointer to destination MAC address or fills in rdesc - * and returns NULL. - */ -#ifdef CONFIG_TR -static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) -{ -	struct trh_hdr *trh; -	unsigned int riflen, num_rdsc; - -	trh = (struct trh_hdr *)packet; -	if (trh->daddr[0] & (uint8_t) 0x80) -		return bus_mac;	/* multicast */ - -	if (trh->saddr[0] & TR_RII) { -		riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8; -		if ((ntohs(trh->rcf) >> 13) != 0) -			return bus_mac;	/* ARE or STE */ -	} else -		return trh->daddr;	/* not source routed */ - -	if (riflen < 6) -		return trh->daddr;	/* last hop, source routed */ - -	/* riflen is 6 or more, packet has more than one route descriptor */ -	num_rdsc = (riflen / 2) - 1; -	memset(rdesc, 0, ETH_ALEN); -	/* offset 4 comes from LAN destination field in LE control frames */ -	if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT)) -		memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(__be16)); -	else { -		memcpy(&rdesc[4], &trh->rseg[1], sizeof(__be16)); -		rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0)); -	} - -	return NULL; -} -#endif /* CONFIG_TR */ - -/*   * Open/initialize the netdevice. This is called (in the current kernel)   * sometime after booting when the 'ifconfig' program is run.   * @@ -259,9 +208,6 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,  	struct lec_arp_table *entry;  	unsigned char *dst;  	int min_frame_size; -#ifdef CONFIG_TR -	unsigned char rdesc[ETH_ALEN];	/* Token Ring route descriptor */ -#endif  	int is_rdesc;  	pr_debug("called\n"); @@ -285,31 +231,19 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,  	if (skb_headroom(skb) < 2) {  		pr_debug("reallocating skb\n");  		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); -		kfree_skb(skb); -		if (skb2 == NULL) +		if (unlikely(!skb2)) { +			kfree_skb(skb);  			return NETDEV_TX_OK; +		} +		consume_skb(skb);  		skb = skb2;  	}  	skb_push(skb, 2); -	/* Put le header to place, works for TokenRing too */ +	/* Put le header to place */  	lec_h = (struct lecdatahdr_8023 *)skb->data;  	lec_h->le_header = htons(priv->lecid); -#ifdef CONFIG_TR -	/* -	 * Ugly. Use this to realign Token Ring packets for -	 * e.g. PCA-200E driver. -	 */ -	if (priv->is_trdev) { -		skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN); -		kfree_skb(skb); -		if (skb2 == NULL) -			return NETDEV_TX_OK; -		skb = skb2; -	} -#endif -  #if DUMP_PACKETS >= 2  #define MAX_DUMP_SKB 99  #elif DUMP_PACKETS >= 1 @@ -323,12 +257,7 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,  #endif /* DUMP_PACKETS >= 1 */  	/* Minimum ethernet-frame size */ -#ifdef CONFIG_TR -	if (priv->is_trdev) -		min_frame_size = LEC_MINIMUM_8025_SIZE; -	else -#endif -		min_frame_size = LEC_MINIMUM_8023_SIZE; +	min_frame_size = LEC_MINIMUM_8023_SIZE;  	if (skb->len < min_frame_size) {  		if ((skb->len + skb_tailroom(skb)) < min_frame_size) {  			skb2 = skb_copy_expand(skb, 0, @@ -347,15 +276,6 @@ static netdev_tx_t lec_start_xmit(struct sk_buff *skb,  	/* Send to right vcc */  	is_rdesc = 0;  	dst = lec_h->h_dest; -#ifdef CONFIG_TR -	if (priv->is_trdev) { -		dst = get_tr_dst(skb->data + 2, rdesc); -		if (dst == NULL) { -			dst = rdesc; -			is_rdesc = 1; -		} -	} -#endif  	entry = NULL;  	vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);  	pr_debug("%s:vcc:%p vcc_flags:%lx, entry:%p\n", @@ -527,7 +447,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)  			atm_force_charge(priv->lecd, skb2->truesize);  			sk = sk_atm(priv->lecd);  			skb_queue_tail(&sk->sk_receive_queue, skb2); -			sk->sk_data_ready(sk, skb2->len); +			sk->sk_data_ready(sk);  		}  	}  #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ @@ -601,7 +521,7 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,  	if (data != NULL)  		mesg->sizeoftlvs = data->len;  	if (mac_addr) -		memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN); +		ether_addr_copy(mesg->content.normal.mac_addr, mac_addr);  	else  		mesg->content.normal.targetless_le_arp = 1;  	if (atm_addr) @@ -610,13 +530,13 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,  	atm_force_charge(priv->lecd, skb->truesize);  	sk = sk_atm(priv->lecd);  	skb_queue_tail(&sk->sk_receive_queue, skb); -	sk->sk_data_ready(sk, skb->len); +	sk->sk_data_ready(sk);  	if (data != NULL) {  		pr_debug("about to send %d bytes of data\n", data->len);  		atm_force_charge(priv->lecd, data->truesize);  		skb_queue_tail(&sk->sk_receive_queue, data); -		sk->sk_data_ready(sk, skb->len); +		sk->sk_data_ready(sk);  	}  	return 0; @@ -645,7 +565,7 @@ static const struct net_device_ops lec_netdev_ops = {  	.ndo_start_xmit		= lec_start_xmit,  	.ndo_change_mtu		= lec_change_mtu,  	.ndo_tx_timeout		= lec_tx_timeout, -	.ndo_set_multicast_list	= lec_set_multicast_list, +	.ndo_set_rx_mode	= lec_set_multicast_list,  };  static const unsigned char lec_ctrl_magic[] = { @@ -696,7 +616,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)  		pr_debug("%s: To daemon\n", dev->name);  		skb_queue_tail(&sk->sk_receive_queue, skb); -		sk->sk_data_ready(sk, skb->len); +		sk->sk_data_ready(sk);  	} else {		/* Data frame, queue to protocol handlers */  		struct lec_arp_table *entry;  		unsigned char *src, *dst; @@ -712,12 +632,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)  			dev_kfree_skb(skb);  			return;  		} -#ifdef CONFIG_TR -		if (priv->is_trdev) -			dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest; -		else -#endif -			dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest; +		dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;  		/*  		 * If this is a Data Direct VCC, and the VCC does not match @@ -725,16 +640,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)  		 */  		spin_lock_irqsave(&priv->lec_arp_lock, flags);  		if (lec_is_data_direct(vcc)) { -#ifdef CONFIG_TR -			if (priv->is_trdev) -				src = -				    ((struct lecdatahdr_8025 *)skb->data)-> -				    h_source; -			else -#endif -				src = -				    ((struct lecdatahdr_8023 *)skb->data)-> -				    h_source; +			src = ((struct lecdatahdr_8023 *)skb->data)->h_source;  			entry = lec_arp_find(priv, src);  			if (entry && entry->vcc != vcc) {  				lec_arp_remove(priv, entry); @@ -752,12 +658,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)  		if (!hlist_empty(&priv->lec_arp_empty_ones))  			lec_arp_check_empties(priv, vcc, skb);  		skb_pull(skb, 2);	/* skip lec_id */ -#ifdef CONFIG_TR -		if (priv->is_trdev) -			skb->protocol = tr_type_trans(skb, dev); -		else -#endif -			skb->protocol = eth_type_trans(skb, dev); +		skb->protocol = eth_type_trans(skb, dev);  		dev->stats.rx_packets++;  		dev->stats.rx_bytes += skb->len;  		memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data)); @@ -829,27 +730,13 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)  		i = 0;  	else  		i = arg; -#ifdef CONFIG_TR  	if (arg >= MAX_LEC_ITF)  		return -EINVAL; -#else				/* Reserve the top NUM_TR_DEVS for TR */ -	if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS)) -		return -EINVAL; -#endif  	if (!dev_lec[i]) { -		int is_trdev, size; - -		is_trdev = 0; -		if (i >= (MAX_LEC_ITF - NUM_TR_DEVS)) -			is_trdev = 1; +		int size;  		size = sizeof(struct lec_priv); -#ifdef CONFIG_TR -		if (is_trdev) -			dev_lec[i] = alloc_trdev(size); -		else -#endif -			dev_lec[i] = alloc_etherdev(size); +		dev_lec[i] = alloc_etherdev(size);  		if (!dev_lec[i])  			return -ENOMEM;  		dev_lec[i]->netdev_ops = &lec_netdev_ops; @@ -860,7 +747,6 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)  		}  		priv = netdev_priv(dev_lec[i]); -		priv->is_trdev = is_trdev;  	} else {  		priv = netdev_priv(dev_lec[i]);  		if (priv->lecd) @@ -956,7 +842,9 @@ static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,  		--*l;  	} -	hlist_for_each_entry_from(tmp, e, next) { +	tmp = container_of(e, struct lec_arp_table, next); + +	hlist_for_each_entry_from(tmp, next) {  		if (--*l < 0)  			break;  	} @@ -1173,14 +1061,13 @@ static int __init lane_module_init(void)  #endif  	register_atm_ioctl(&lane_ioctl_ops); -	pr_info("lec.c: " __DATE__ " " __TIME__ " initialized\n"); +	pr_info("lec.c: initialized\n");  	return 0;  }  static void __exit lane_module_cleanup(void)  {  	int i; -	struct lec_priv *priv;  	remove_proc_entry("lec", atm_proc_root); @@ -1188,7 +1075,6 @@ static void __exit lane_module_cleanup(void)  	for (i = 0; i < MAX_LEC_ITF; i++) {  		if (dev_lec[i] != NULL) { -			priv = netdev_priv(dev_lec[i]);  			unregister_netdev(dev_lec[i]);  			free_netdev(dev_lec[i]);  			dev_lec[i] = NULL; @@ -1259,7 +1145,7 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst,  	struct sk_buff *skb;  	struct lec_priv *priv = netdev_priv(dev); -	if (compare_ether_addr(lan_dst, dev->dev_addr)) +	if (!ether_addr_equal(lan_dst, dev->dev_addr))  		return 0;	/* not our mac address */  	kfree(priv->tlvs);	/* NULL if there was no previous association */ @@ -1339,7 +1225,7 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr,  #include <linux/types.h>  #include <linux/timer.h>  #include <linux/param.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <linux/inetdevice.h>  #include <net/route.h> @@ -1423,7 +1309,6 @@ lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)  static int  lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)  { -	struct hlist_node *node;  	struct lec_arp_table *entry;  	int i, remove_vcc = 1; @@ -1442,7 +1327,7 @@ lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)  		 * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT  		 */  		for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -			hlist_for_each_entry(entry, node, +			hlist_for_each_entry(entry,  					     &priv->lec_arp_tables[i], next) {  				if (memcmp(to_remove->atm_addr,  					   entry->atm_addr, ATM_ESA_LEN) == 0) { @@ -1480,14 +1365,13 @@ static const char *get_status_string(unsigned char st)  static void dump_arp_table(struct lec_priv *priv)  { -	struct hlist_node *node;  	struct lec_arp_table *rulla;  	char buf[256];  	int i, j, offset;  	pr_info("Dump %p:\n", priv);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry(rulla, node, +		hlist_for_each_entry(rulla,  				     &priv->lec_arp_tables[i], next) {  			offset = 0;  			offset += sprintf(buf, "%d: %p\n", i, rulla); @@ -1519,7 +1403,7 @@ static void dump_arp_table(struct lec_priv *priv)  	if (!hlist_empty(&priv->lec_no_forward))  		pr_info("No forward\n"); -	hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) { +	hlist_for_each_entry(rulla, &priv->lec_no_forward, next) {  		offset = 0;  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);  		offset += sprintf(buf + offset, " Atm:"); @@ -1544,7 +1428,7 @@ static void dump_arp_table(struct lec_priv *priv)  	if (!hlist_empty(&priv->lec_arp_empty_ones))  		pr_info("Empty ones\n"); -	hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) { +	hlist_for_each_entry(rulla, &priv->lec_arp_empty_ones, next) {  		offset = 0;  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);  		offset += sprintf(buf + offset, " Atm:"); @@ -1569,7 +1453,7 @@ static void dump_arp_table(struct lec_priv *priv)  	if (!hlist_empty(&priv->mcast_fwds))  		pr_info("Multicast Forward VCCs\n"); -	hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) { +	hlist_for_each_entry(rulla, &priv->mcast_fwds, next) {  		offset = 0;  		offset += sprintf(buf + offset, "Mac: %pM", rulla->mac_addr);  		offset += sprintf(buf + offset, " Atm:"); @@ -1603,11 +1487,11 @@ static void dump_arp_table(struct lec_priv *priv)  static void lec_arp_destroy(struct lec_priv *priv)  {  	unsigned long flags; -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry;  	int i; -	cancel_rearming_delayed_work(&priv->lec_arp_work); +	cancel_delayed_work_sync(&priv->lec_arp_work);  	/*  	 * Remove all entries @@ -1615,7 +1499,7 @@ static void lec_arp_destroy(struct lec_priv *priv)  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry_safe(entry, node, next, +		hlist_for_each_entry_safe(entry, next,  					  &priv->lec_arp_tables[i], next) {  			lec_arp_remove(priv, entry);  			lec_arp_put(entry); @@ -1623,7 +1507,7 @@ static void lec_arp_destroy(struct lec_priv *priv)  		INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);  	} -	hlist_for_each_entry_safe(entry, node, next, +	hlist_for_each_entry_safe(entry, next,  				  &priv->lec_arp_empty_ones, next) {  		del_timer_sync(&entry->timer);  		lec_arp_clear_vccs(entry); @@ -1632,7 +1516,7 @@ static void lec_arp_destroy(struct lec_priv *priv)  	}  	INIT_HLIST_HEAD(&priv->lec_arp_empty_ones); -	hlist_for_each_entry_safe(entry, node, next, +	hlist_for_each_entry_safe(entry, next,  				  &priv->lec_no_forward, next) {  		del_timer_sync(&entry->timer);  		lec_arp_clear_vccs(entry); @@ -1641,7 +1525,7 @@ static void lec_arp_destroy(struct lec_priv *priv)  	}  	INIT_HLIST_HEAD(&priv->lec_no_forward); -	hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) { +	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {  		/* No timer, LANEv2 7.1.20 and 2.3.5.3 */  		lec_arp_clear_vccs(entry);  		hlist_del(&entry->next); @@ -1658,15 +1542,14 @@ static void lec_arp_destroy(struct lec_priv *priv)  static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,  					  const unsigned char *mac_addr)  { -	struct hlist_node *node;  	struct hlist_head *head;  	struct lec_arp_table *entry;  	pr_debug("%pM\n", mac_addr);  	head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])]; -	hlist_for_each_entry(entry, node, head, next) { -		if (!compare_ether_addr(mac_addr, entry->mac_addr)) +	hlist_for_each_entry(entry, head, next) { +		if (ether_addr_equal(mac_addr, entry->mac_addr))  			return entry;  	}  	return NULL; @@ -1682,7 +1565,7 @@ static struct lec_arp_table *make_entry(struct lec_priv *priv,  		pr_info("LEC: Arp entry kmalloc failed\n");  		return NULL;  	} -	memcpy(to_return->mac_addr, mac_addr, ETH_ALEN); +	ether_addr_copy(to_return->mac_addr, mac_addr);  	INIT_HLIST_NODE(&to_return->next);  	setup_timer(&to_return->timer, lec_arp_expire_arp,  			(unsigned long)to_return); @@ -1720,7 +1603,7 @@ static void lec_arp_expire_vcc(unsigned long data)  {  	unsigned long flags;  	struct lec_arp_table *to_remove = (struct lec_arp_table *)data; -	struct lec_priv *priv = (struct lec_priv *)to_remove->priv; +	struct lec_priv *priv = to_remove->priv;  	del_timer(&to_remove->timer); @@ -1802,7 +1685,7 @@ static void lec_arp_check_expire(struct work_struct *work)  	unsigned long flags;  	struct lec_priv *priv =  		container_of(work, struct lec_priv, lec_arp_work.work); -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry;  	unsigned long now;  	int i; @@ -1812,7 +1695,7 @@ static void lec_arp_check_expire(struct work_struct *work)  restart:  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry_safe(entry, node, next, +		hlist_for_each_entry_safe(entry, next,  					  &priv->lec_arp_tables[i], next) {  			if (__lec_arp_check_expire(entry, now, priv)) {  				struct sk_buff *skb; @@ -1853,7 +1736,7 @@ static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,  		case 1:  			return priv->mcast_vcc;  		case 2:	/* LANE2 wants arp for multicast addresses */ -			if (!compare_ether_addr(mac_to_find, bus_mac)) +			if (ether_addr_equal(mac_to_find, bus_mac))  				return priv->mcast_vcc;  			break;  		default: @@ -1939,14 +1822,14 @@ lec_addr_delete(struct lec_priv *priv, const unsigned char *atm_addr,  		unsigned long permanent)  {  	unsigned long flags; -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry;  	int i;  	pr_debug("\n");  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry_safe(entry, node, next, +		hlist_for_each_entry_safe(entry, next,  					  &priv->lec_arp_tables[i], next) {  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) &&  			    (permanent || @@ -1971,7 +1854,7 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,  	       unsigned int targetless_le_arp)  {  	unsigned long flags; -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry, *tmp;  	int i; @@ -1986,7 +1869,7 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,  				 * we have no entry in the cache. 7.1.30  				 */  	if (!hlist_empty(&priv->lec_arp_empty_ones)) { -		hlist_for_each_entry_safe(entry, node, next, +		hlist_for_each_entry_safe(entry, next,  					  &priv->lec_arp_empty_ones, next) {  			if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {  				hlist_del(&entry->next); @@ -2004,7 +1887,8 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,  					entry = tmp;  				} else {  					entry->status = ESI_FORWARD_DIRECT; -					memcpy(entry->mac_addr, mac_addr, ETH_ALEN); +					ether_addr_copy(entry->mac_addr, +							mac_addr);  					entry->last_used = jiffies;  					lec_arp_add(priv, entry);  				} @@ -2031,7 +1915,7 @@ lec_arp_update(struct lec_priv *priv, const unsigned char *mac_addr,  	memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);  	del_timer(&entry->timer);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry(tmp, node, +		hlist_for_each_entry(tmp,  				     &priv->lec_arp_tables[i], next) {  			if (entry != tmp &&  			    !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) { @@ -2072,7 +1956,6 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,  	      void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))  {  	unsigned long flags; -	struct hlist_node *node;  	struct lec_arp_table *entry;  	int i, found_entry = 0; @@ -2142,7 +2025,7 @@ lec_vcc_added(struct lec_priv *priv, const struct atmlec_ioc *ioc_data,  		 ioc_data->atm_addr[16], ioc_data->atm_addr[17],  		 ioc_data->atm_addr[18], ioc_data->atm_addr[19]);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry(entry, node, +		hlist_for_each_entry(entry,  				     &priv->lec_arp_tables[i], next) {  			if (memcmp  			    (ioc_data->atm_addr, entry->atm_addr, @@ -2219,7 +2102,6 @@ out:  static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)  {  	unsigned long flags; -	struct hlist_node *node;  	struct lec_arp_table *entry;  	int i; @@ -2227,7 +2109,7 @@ static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)  restart:  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry(entry, node, +		hlist_for_each_entry(entry,  				     &priv->lec_arp_tables[i], next) {  			if (entry->flush_tran_id == tran_id &&  			    entry->status == ESI_FLUSH_PENDING) { @@ -2256,13 +2138,12 @@ lec_set_flush_tran_id(struct lec_priv *priv,  		      const unsigned char *atm_addr, unsigned long tran_id)  {  	unsigned long flags; -	struct hlist_node *node;  	struct lec_arp_table *entry;  	int i;  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) -		hlist_for_each_entry(entry, node, +		hlist_for_each_entry(entry,  				     &priv->lec_arp_tables[i], next) {  			if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {  				entry->flush_tran_id = tran_id; @@ -2314,7 +2195,7 @@ out:  static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)  {  	unsigned long flags; -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry;  	int i; @@ -2324,7 +2205,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)  	spin_lock_irqsave(&priv->lec_arp_lock, flags);  	for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) { -		hlist_for_each_entry_safe(entry, node, next, +		hlist_for_each_entry_safe(entry, next,  					  &priv->lec_arp_tables[i], next) {  			if (vcc == entry->vcc) {  				lec_arp_remove(priv, entry); @@ -2335,7 +2216,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)  		}  	} -	hlist_for_each_entry_safe(entry, node, next, +	hlist_for_each_entry_safe(entry, next,  				  &priv->lec_arp_empty_ones, next) {  		if (entry->vcc == vcc) {  			lec_arp_clear_vccs(entry); @@ -2345,7 +2226,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)  		}  	} -	hlist_for_each_entry_safe(entry, node, next, +	hlist_for_each_entry_safe(entry, next,  				  &priv->lec_no_forward, next) {  		if (entry->recv_vcc == vcc) {  			lec_arp_clear_vccs(entry); @@ -2355,7 +2236,7 @@ static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)  		}  	} -	hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) { +	hlist_for_each_entry_safe(entry, next, &priv->mcast_fwds, next) {  		if (entry->recv_vcc == vcc) {  			lec_arp_clear_vccs(entry);  			/* No timer, LANEv2 7.1.20 and 2.3.5.3 */ @@ -2373,25 +2254,17 @@ lec_arp_check_empties(struct lec_priv *priv,  		      struct atm_vcc *vcc, struct sk_buff *skb)  {  	unsigned long flags; -	struct hlist_node *node, *next; +	struct hlist_node *next;  	struct lec_arp_table *entry, *tmp;  	struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data; -	unsigned char *src; -#ifdef CONFIG_TR -	struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data; - -	if (priv->is_trdev) -		src = tr_hdr->h_source; -	else -#endif -		src = hdr->h_source; +	unsigned char *src = hdr->h_source;  	spin_lock_irqsave(&priv->lec_arp_lock, flags); -	hlist_for_each_entry_safe(entry, node, next, +	hlist_for_each_entry_safe(entry, next,  				  &priv->lec_arp_empty_ones, next) {  		if (vcc == entry->vcc) {  			del_timer(&entry->timer); -			memcpy(entry->mac_addr, src, ETH_ALEN); +			ether_addr_copy(entry->mac_addr, src);  			entry->status = ESI_FORWARD_DIRECT;  			entry->last_used = jiffies;  			/* We might have got an entry */ diff --git a/net/atm/lec.h b/net/atm/lec.h index 9d14d196cc1..4149db1b788 100644 --- a/net/atm/lec.h +++ b/net/atm/lec.h @@ -35,7 +35,7 @@ struct lecdatahdr_8025 {   * Operations that LANE2 capable device can do. Two first functions   * are used to make the device do things. See spec 3.1.3 and 3.1.4.   * - * The third function is intented for the MPOA component sitting on + * The third function is intended for the MPOA component sitting on   * top of the LANE device. The MPOA component assigns it's own function   * to (*associate_indicator)() and the LANE device will use that   * function to tell about TLVs it sees floating through. @@ -55,11 +55,11 @@ struct lane2_ops {   * frames.   *   * 1. Dix Ethernet EtherType frames encoded by placing EtherType - *    field in h_type field. Data follows immediatelly after header. + *    field in h_type field. Data follows immediately after header.   * 2. LLC Data frames whose total length, including LLC field and data,   *    but not padding required to meet the minimum data frame length, - *    is less than 1536(0x0600) MUST be encoded by placing that length - *    in the h_type field. The LLC field follows header immediatelly. + *    is less than ETH_P_802_3_MIN MUST be encoded by placing that length + *    in the h_type field. The LLC field follows header immediately.   * 3. LLC data frames longer than this maximum MUST be encoded by placing   *    the value 0 in the h_type field.   * @@ -142,7 +142,6 @@ struct lec_priv {  	int itfnum;				/* e.g. 2 for lec2, 5 for lec5 */  	struct lane2_ops *lane2_ops;		/* can be NULL for LANE v1 */  	int is_proxy;				/* bridge between ATM and Ethernet */ -	int is_trdev;				/* Device type, 0 = Ethernet, 1 = TokenRing */  };  struct lec_vcc_priv { diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 74bcc662c3d..e8e0e7a8a23 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -64,8 +64,6 @@  	do { if (0) printk(KERN_CONT format, ##args); } while (0)  #endif -#define MPOA_TAG_LEN 4 -  /* mpc_daemon -> kernel */  static void MPOA_trigger_rcvd(struct k_message *msg, struct mpoa_client *mpc);  static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc); @@ -480,7 +478,7 @@ static const uint8_t *copy_macs(struct mpoa_client *mpc,  			return NULL;  		}  	} -	memcpy(mpc->mps_macs, router_mac, ETH_ALEN); +	ether_addr_copy(mpc->mps_macs, router_mac);  	tlvs += 20; if (device_type == MPS_AND_MPC) tlvs += 20;  	if (mps_macs > 0)  		memcpy(mpc->mps_macs, tlvs, mps_macs*ETH_ALEN); @@ -594,8 +592,7 @@ static netdev_tx_t mpc_send_packet(struct sk_buff *skb,  		goto non_ip;  	while (i < mpc->number_of_mps_macs) { -		if (!compare_ether_addr(eth->h_dest, -					(mpc->mps_macs + i*ETH_ALEN))) +		if (ether_addr_equal(eth->h_dest, mpc->mps_macs + i * ETH_ALEN))  			if (send_via_shortcut(skb, mpc) == 0) /* try shortcut */  				return NETDEV_TX_OK;  		i++; @@ -709,7 +706,7 @@ static void mpc_push(struct atm_vcc *vcc, struct sk_buff *skb)  		dprintk("(%s) control packet arrived\n", dev->name);  		/* Pass control packets to daemon */  		skb_queue_tail(&sk->sk_receive_queue, skb); -		sk->sk_data_ready(sk, skb->len); +		sk->sk_data_ready(sk);  		return;  	} @@ -995,20 +992,18 @@ int msg_to_mpoad(struct k_message *mesg, struct mpoa_client *mpc)  	sk = sk_atm(mpc->mpoad_vcc);  	skb_queue_tail(&sk->sk_receive_queue, skb); -	sk->sk_data_ready(sk, skb->len); +	sk->sk_data_ready(sk);  	return 0;  }  static int mpoa_event_listener(struct notifier_block *mpoa_notifier, -			       unsigned long event, void *dev_ptr) +			       unsigned long event, void *ptr)  { -	struct net_device *dev; +	struct net_device *dev = netdev_notifier_info_to_dev(ptr);  	struct mpoa_client *mpc;  	struct lec_priv *priv; -	dev = (struct net_device *)dev_ptr; -  	if (!net_eq(dev_net(dev), &init_net))  		return NOTIFY_DONE; @@ -1278,7 +1273,7 @@ static void purge_egress_shortcut(struct atm_vcc *vcc, eg_cache_entry *entry)  	sk = sk_atm(vcc);  	skb_queue_tail(&sk->sk_receive_queue, skb); -	sk->sk_data_ready(sk, skb->len); +	sk->sk_data_ready(sk);  	dprintk("exiting\n");  } @@ -1484,7 +1479,7 @@ static __init int atm_mpoa_init(void)  	if (mpc_proc_init() != 0)  		pr_info("failed to initialize /proc/mpoa\n"); -	pr_info("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); +	pr_info("mpc.c: initialized\n");  	return 0;  } @@ -1497,7 +1492,7 @@ static void __exit atm_mpoa_cleanup(void)  	mpc_proc_clean(); -	del_timer(&mpc_timer); +	del_timer_sync(&mpc_timer);  	unregister_netdevice_notifier(&mpoa_notifier);  	deregister_atm_ioctl(&atm_ioctl_ops); diff --git a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c index 53e50029227..5bdd300db0f 100644 --- a/net/atm/mpoa_proc.c +++ b/net/atm/mpoa_proc.c @@ -207,7 +207,7 @@ static ssize_t proc_mpc_write(struct file *file, const char __user *buff,  			      size_t nbytes, loff_t *ppos)  {  	char *page, *p; -	unsigned len; +	unsigned int len;  	if (nbytes == 0)  		return 0; diff --git a/net/atm/pppoatm.c b/net/atm/pppoatm.c index e9aced0ec56..c4e09846d1d 100644 --- a/net/atm/pppoatm.c +++ b/net/atm/pppoatm.c @@ -37,13 +37,14 @@  #include <linux/module.h>  #include <linux/init.h> +#include <linux/interrupt.h>  #include <linux/skbuff.h>  #include <linux/slab.h>  #include <linux/atm.h>  #include <linux/atmdev.h>  #include <linux/capability.h>  #include <linux/ppp_defs.h> -#include <linux/if_ppp.h> +#include <linux/ppp-ioctl.h>  #include <linux/ppp_channel.h>  #include <linux/atmppp.h> @@ -59,14 +60,29 @@ struct pppoatm_vcc {  	struct atm_vcc	*atmvcc;	/* VCC descriptor */  	void (*old_push)(struct atm_vcc *, struct sk_buff *);  	void (*old_pop)(struct atm_vcc *, struct sk_buff *); +	void (*old_release_cb)(struct atm_vcc *); +	struct module *old_owner;  					/* keep old push/pop for detaching */  	enum pppoatm_encaps encaps; +	atomic_t inflight; +	unsigned long blocked;  	int flags;			/* SC_COMP_PROT - compress protocol */  	struct ppp_channel chan;	/* interface to generic ppp layer */  	struct tasklet_struct wakeup_tasklet;  };  /* + * We want to allow two packets in the queue. The one that's currently in + * flight, and *one* queued up ready for the ATM device to send immediately + * from its TX done IRQ. We want to be able to use atomic_inc_not_zero(), so + * inflight == -2 represents an empty queue, -1 one packet, and zero means + * there are two packets in the queue. + */ +#define NONE_INFLIGHT -2 + +#define BLOCKED 0 + +/*   * Header used for LLC Encapsulated PPP (4 bytes) followed by the LCP protocol   * ID (0xC021) used in autodetection   */ @@ -93,6 +109,24 @@ static void pppoatm_wakeup_sender(unsigned long arg)  	ppp_output_wakeup((struct ppp_channel *) arg);  } +static void pppoatm_release_cb(struct atm_vcc *atmvcc) +{ +	struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); + +	/* +	 * As in pppoatm_pop(), it's safe to clear the BLOCKED bit here because +	 * the wakeup *can't* race with pppoatm_send(). They both hold the PPP +	 * channel's ->downl lock. And the potential race with *setting* it, +	 * which leads to the double-check dance in pppoatm_may_send(), doesn't +	 * exist here. In the sock_owned_by_user() case in pppoatm_send(), we +	 * set the BLOCKED bit while the socket is still locked. We know that +	 * ->release_cb() can't be called until that's done. +	 */ +	if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) +		tasklet_schedule(&pvcc->wakeup_tasklet); +	if (pvcc->old_release_cb) +		pvcc->old_release_cb(atmvcc); +}  /*   * This gets called every time the ATM card has finished sending our   * skb.  The ->old_pop will take care up normal atm flow control, @@ -101,16 +135,30 @@ static void pppoatm_wakeup_sender(unsigned long arg)  static void pppoatm_pop(struct atm_vcc *atmvcc, struct sk_buff *skb)  {  	struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); +  	pvcc->old_pop(atmvcc, skb); +	atomic_dec(&pvcc->inflight); +  	/* -	 * We don't really always want to do this since it's -	 * really inefficient - it would be much better if we could -	 * test if we had actually throttled the generic layer. -	 * Unfortunately then there would be a nasty SMP race where -	 * we could clear that flag just as we refuse another packet. -	 * For now we do the safe thing. +	 * We always used to run the wakeup tasklet unconditionally here, for +	 * fear of race conditions where we clear the BLOCKED flag just as we +	 * refuse another packet in pppoatm_send(). This was quite inefficient. +	 * +	 * In fact it's OK. The PPP core will only ever call pppoatm_send() +	 * while holding the channel->downl lock. And ppp_output_wakeup() as +	 * called by the tasklet will *also* grab that lock. So even if another +	 * CPU is in pppoatm_send() right now, the tasklet isn't going to race +	 * with it. The wakeup *will* happen after the other CPU is safely out +	 * of pppoatm_send() again. +	 * +	 * So if the CPU in pppoatm_send() has already set the BLOCKED bit and +	 * it about to return, that's fine. We trigger a wakeup which will +	 * happen later. And if the CPU in pppoatm_send() *hasn't* set the +	 * BLOCKED bit yet, that's fine too because of the double check in +	 * pppoatm_may_send() which is commented there.  	 */ -	tasklet_schedule(&pvcc->wakeup_tasklet); +	if (test_and_clear_bit(BLOCKED, &pvcc->blocked)) +		tasklet_schedule(&pvcc->wakeup_tasklet);  }  /* @@ -123,12 +171,11 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)  	pvcc = atmvcc_to_pvcc(atmvcc);  	atmvcc->push = pvcc->old_push;  	atmvcc->pop = pvcc->old_pop; +	atmvcc->release_cb = pvcc->old_release_cb;  	tasklet_kill(&pvcc->wakeup_tasklet);  	ppp_unregister_channel(&pvcc->chan);  	atmvcc->user_back = NULL;  	kfree(pvcc); -	/* Gee, I hope we have the big kernel lock here... */ -	module_put(THIS_MODULE);  }  /* Called when an AAL5 PDU comes in */ @@ -137,9 +184,13 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)  	struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);  	pr_debug("\n");  	if (skb == NULL) {			/* VCC was closed */ +		struct module *module; +  		pr_debug("removing ATMPPP VCC %p\n", pvcc); +		module = pvcc->old_owner;  		pppoatm_unassign_vcc(atmvcc);  		atmvcc->push(atmvcc, NULL);	/* Pass along bad news */ +		module_put(module);  		return;  	}  	atm_return(atmvcc, skb->truesize); @@ -183,6 +234,51 @@ error:  	ppp_input_error(&pvcc->chan, 0);  } +static int pppoatm_may_send(struct pppoatm_vcc *pvcc, int size) +{ +	/* +	 * It's not clear that we need to bother with using atm_may_send() +	 * to check we don't exceed sk->sk_sndbuf. If userspace sets a +	 * value of sk_sndbuf which is lower than the MTU, we're going to +	 * block for ever. But the code always did that before we introduced +	 * the packet count limit, so... +	 */ +	if (atm_may_send(pvcc->atmvcc, size) && +	    atomic_inc_not_zero_hint(&pvcc->inflight, NONE_INFLIGHT)) +		return 1; + +	/* +	 * We use test_and_set_bit() rather than set_bit() here because +	 * we need to ensure there's a memory barrier after it. The bit +	 * *must* be set before we do the atomic_inc() on pvcc->inflight. +	 * There's no smp_mb__after_set_bit(), so it's this or abuse +	 * smp_mb__after_atomic(). +	 */ +	test_and_set_bit(BLOCKED, &pvcc->blocked); + +	/* +	 * We may have raced with pppoatm_pop(). If it ran for the +	 * last packet in the queue, *just* before we set the BLOCKED +	 * bit, then it might never run again and the channel could +	 * remain permanently blocked. Cope with that race by checking +	 * *again*. If it did run in that window, we'll have space on +	 * the queue now and can return success. It's harmless to leave +	 * the BLOCKED flag set, since it's only used as a trigger to +	 * run the wakeup tasklet. Another wakeup will never hurt. +	 * If pppoatm_pop() is running but hasn't got as far as making +	 * space on the queue yet, then it hasn't checked the BLOCKED +	 * flag yet either, so we're safe in that case too. It'll issue +	 * an "immediate" wakeup... where "immediate" actually involves +	 * taking the PPP channel's ->downl lock, which is held by the +	 * code path that calls pppoatm_send(), and is thus going to +	 * wait for us to finish. +	 */ +	if (atm_may_send(pvcc->atmvcc, size) && +	    atomic_inc_not_zero(&pvcc->inflight)) +		return 1; + +	return 0; +}  /*   * Called by the ppp_generic.c to send a packet - returns true if packet   * was accepted.  If we return false, then it's our job to call @@ -196,33 +292,59 @@ error:  static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)  {  	struct pppoatm_vcc *pvcc = chan_to_pvcc(chan); +	struct atm_vcc *vcc; +	int ret; +  	ATM_SKB(skb)->vcc = pvcc->atmvcc;  	pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);  	if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))  		(void) skb_pull(skb, 1); + +	vcc = ATM_SKB(skb)->vcc; +	bh_lock_sock(sk_atm(vcc)); +	if (sock_owned_by_user(sk_atm(vcc))) { +		/* +		 * Needs to happen (and be flushed, hence test_and_) before we unlock +		 * the socket. It needs to be seen by the time our ->release_cb gets +		 * called. +		 */ +		test_and_set_bit(BLOCKED, &pvcc->blocked); +		goto nospace; +	} +	if (test_bit(ATM_VF_RELEASED, &vcc->flags) || +	    test_bit(ATM_VF_CLOSE, &vcc->flags) || +	    !test_bit(ATM_VF_READY, &vcc->flags)) { +		bh_unlock_sock(sk_atm(vcc)); +		kfree_skb(skb); +		return DROP_PACKET; +	} +  	switch (pvcc->encaps) {		/* LLC encapsulation needed */  	case e_llc:  		if (skb_headroom(skb) < LLC_LEN) {  			struct sk_buff *n;  			n = skb_realloc_headroom(skb, LLC_LEN);  			if (n != NULL && -			    !atm_may_send(pvcc->atmvcc, n->truesize)) { +			    !pppoatm_may_send(pvcc, n->truesize)) {  				kfree_skb(n);  				goto nospace;  			} -			kfree_skb(skb); +			consume_skb(skb);  			skb = n; -			if (skb == NULL) +			if (skb == NULL) { +				bh_unlock_sock(sk_atm(vcc));  				return DROP_PACKET; -		} else if (!atm_may_send(pvcc->atmvcc, skb->truesize)) +			} +		} else if (!pppoatm_may_send(pvcc, skb->truesize))  			goto nospace;  		memcpy(skb_push(skb, LLC_LEN), pppllc, LLC_LEN);  		break;  	case e_vc: -		if (!atm_may_send(pvcc->atmvcc, skb->truesize)) +		if (!pppoatm_may_send(pvcc, skb->truesize))  			goto nospace;  		break;  	case e_autodetect: +		bh_unlock_sock(sk_atm(vcc));  		pr_debug("Trying to send without setting encaps!\n");  		kfree_skb(skb);  		return 1; @@ -232,9 +354,12 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)  	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;  	pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",  		 skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev); -	return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb) +	ret = ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)  	    ? DROP_PACKET : 1; +	bh_unlock_sock(sk_atm(vcc)); +	return ret;  nospace: +	bh_unlock_sock(sk_atm(vcc));  	/*  	 * We don't have space to send this SKB now, but we might have  	 * already applied SC_COMP_PROT compression, so may need to undo @@ -284,8 +409,13 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)  	if (pvcc == NULL)  		return -ENOMEM;  	pvcc->atmvcc = atmvcc; + +	/* Maximum is zero, so that we can use atomic_inc_not_zero() */ +	atomic_set(&pvcc->inflight, NONE_INFLIGHT);  	pvcc->old_push = atmvcc->push;  	pvcc->old_pop = atmvcc->pop; +	pvcc->old_owner = atmvcc->owner; +	pvcc->old_release_cb = atmvcc->release_cb;  	pvcc->encaps = (enum pppoatm_encaps) be.encaps;  	pvcc->chan.private = pvcc;  	pvcc->chan.ops = &pppoatm_ops; @@ -301,7 +431,13 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)  	atmvcc->user_back = pvcc;  	atmvcc->push = pppoatm_push;  	atmvcc->pop = pppoatm_pop; +	atmvcc->release_cb = pppoatm_release_cb;  	__module_get(THIS_MODULE); +	atmvcc->owner = THIS_MODULE; + +	/* re-process everything received between connection setup and +	   backend setup */ +	vcc_process_recv_queue(atmvcc);  	return 0;  } @@ -326,6 +462,8 @@ static int pppoatm_ioctl(struct socket *sock, unsigned int cmd,  			return -ENOIOCTLCMD;  		if (!capable(CAP_NET_ADMIN))  			return -EPERM; +		if (sock->state != SS_CONNECTED) +			return -EINVAL;  		return pppoatm_assign_vcc(atmvcc, argp);  		}  	case PPPIOCGCHAN: diff --git a/net/atm/proc.c b/net/atm/proc.c index f85da0779e5..bbb6461a4b7 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -27,7 +27,7 @@  #include <net/atmclip.h>  #include <linux/uaccess.h>  #include <linux/param.h> /* for HZ */ -#include <asm/atomic.h> +#include <linux/atomic.h>  #include "resources.h"  #include "common.h" /* atm_proc_init prototype */  #include "signaling.h" /* to get sigd - ugly too */ @@ -191,7 +191,7 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)  {  	struct sock *sk = sk_atm(vcc); -	seq_printf(seq, "%p ", vcc); +	seq_printf(seq, "%pK ", vcc);  	if (!vcc->dev)  		seq_printf(seq, "Unassigned    ");  	else @@ -218,7 +218,7 @@ static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)  {  	if (!vcc->dev)  		seq_printf(seq, sizeof(void *) == 4 ? -			   "N/A@%p%10s" : "N/A@%p%2s", vcc, ""); +			   "N/A@%pK%10s" : "N/A@%pK%2s", vcc, "");  	else  		seq_printf(seq, "%3d %3d %5d         ",  			   vcc->dev->number, vcc->vpi, vcc->vci); @@ -385,7 +385,7 @@ static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,  	page = get_zeroed_page(GFP_KERNEL);  	if (!page)  		return -ENOMEM; -	dev = PDE(file->f_path.dentry->d_inode)->data; +	dev = PDE_DATA(file_inode(file));  	if (!dev->ops->proc_read)  		length = -EINVAL;  	else { @@ -460,7 +460,7 @@ static void atm_proc_dirs_remove(void)  		if (e->dirent)  			remove_proc_entry(e->name, atm_proc_root);  	} -	proc_net_remove(&init_net, "atm"); +	remove_proc_entry("atm", init_net.proc_net);  }  int __init atm_proc_init(void) diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 437ee70c5e6..ae032402140 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -11,6 +11,7 @@  #include <linux/init.h>  #include <linux/skbuff.h>  #include <linux/bitops.h> +#include <linux/export.h>  #include <net/sock.h>		/* for sock_no_* */  #include "resources.h"		/* devs and vccs */ @@ -94,6 +95,7 @@ static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,  		return -ENOTCONN;  	*sockaddr_len = sizeof(struct sockaddr_atmpvc);  	addr = (struct sockaddr_atmpvc *)sockaddr; +	memset(addr, 0, sizeof(*addr));  	addr->sap_family = AF_ATMPVC;  	addr->sap_addr.itf = vcc->dev->number;  	addr->sap_addr.vpi = vcc->vpi; diff --git a/net/atm/raw.c b/net/atm/raw.c index b4f7b9ff3c7..2e17e97a7a8 100644 --- a/net/atm/raw.c +++ b/net/atm/raw.c @@ -25,7 +25,7 @@ static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb)  		struct sock *sk = sk_atm(vcc);  		skb_queue_tail(&sk->sk_receive_queue, skb); -		sk->sk_data_ready(sk, skb->len); +		sk->sk_data_ready(sk);  	}  } diff --git a/net/atm/resources.c b/net/atm/resources.c index d29e5826151..0447d5d0b63 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -74,8 +74,9 @@ struct atm_dev *atm_dev_lookup(int number)  }  EXPORT_SYMBOL(atm_dev_lookup); -struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops, -				 int number, unsigned long *flags) +struct atm_dev *atm_dev_register(const char *type, struct device *parent, +				 const struct atmdev_ops *ops, int number, +				 unsigned long *flags)  {  	struct atm_dev *dev, *inuse; @@ -115,7 +116,7 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,  		goto out_fail;  	} -	if (atm_register_sysfs(dev) < 0) { +	if (atm_register_sysfs(dev, parent) < 0) {  		pr_err("atm_register_sysfs failed for dev %s\n", type);  		atm_proc_dev_deregister(dev);  		goto out_fail; @@ -431,7 +432,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)  			size = dev->ops->ioctl(dev, cmd, buf);  		}  		if (size < 0) { -			error = (size == -ENOIOCTLCMD ? -EINVAL : size); +			error = (size == -ENOIOCTLCMD ? -ENOTTY : size);  			goto done;  		}  	} diff --git a/net/atm/resources.h b/net/atm/resources.h index 126fb1840df..521431e3050 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -42,6 +42,6 @@ static inline void atm_proc_dev_deregister(struct atm_dev *dev)  #endif /* CONFIG_PROC_FS */ -int atm_register_sysfs(struct atm_dev *adev); +int atm_register_sysfs(struct atm_dev *adev, struct device *parent);  void atm_unregister_sysfs(struct atm_dev *adev);  #endif diff --git a/net/atm/signaling.c b/net/atm/signaling.c index 509c8ac02b6..523bce72f69 100644 --- a/net/atm/signaling.c +++ b/net/atm/signaling.c @@ -51,7 +51,7 @@ static void sigd_put_skb(struct sk_buff *skb)  #endif  	atm_force_charge(sigd, skb->truesize);  	skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb); -	sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len); +	sk_atm(sigd)->sk_data_ready(sk_atm(sigd));  }  static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg) @@ -166,7 +166,7 @@ void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type,  {  	struct sk_buff *skb;  	struct atmsvc_msg *msg; -	static unsigned session = 0; +	static unsigned int session = 0;  	pr_debug("%d (0x%p)\n", (int)type, vcc);  	while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL))) @@ -217,7 +217,6 @@ static void purge_vcc(struct atm_vcc *vcc)  static void sigd_close(struct atm_vcc *vcc)  { -	struct hlist_node *node;  	struct sock *s;  	int i; @@ -231,7 +230,7 @@ static void sigd_close(struct atm_vcc *vcc)  	for (i = 0; i < VCC_HTABLE_SIZE; ++i) {  		struct hlist_head *head = &vcc_hash[i]; -		sk_for_each(s, node, head) { +		sk_for_each(s, head) {  			vcc = atm_sk(s);  			purge_vcc(vcc); diff --git a/net/atm/svc.c b/net/atm/svc.c index 754ee4791d9..d8e5d0c2ebb 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -20,6 +20,7 @@  #include <linux/bitops.h>  #include <net/sock.h>		/* for sock_no_* */  #include <linux/uaccess.h> +#include <linux/export.h>  #include "resources.h"  #include "common.h"		/* common for PVCs and SVCs */ @@ -262,17 +263,11 @@ static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,  			goto out;  		}  	} -/* - * Not supported yet - * - * #ifndef CONFIG_SINGLE_SIGITF - */ +  	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);  	vcc->qos.txtp.pcr = 0;  	vcc->qos.txtp.min_pcr = 0; -/* - * #endif - */ +  	error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);  	if (!error)  		sock->state = SS_CONNECTED;  | 
