diff options
| author | Tony Luck <tony.luck@intel.com> | 2005-05-17 15:53:14 -0700 | 
|---|---|---|
| committer | Tony Luck <tony.luck@intel.com> | 2005-05-17 15:53:14 -0700 | 
| commit | 325a479c4c110db278ef3361460a48c4093252cc (patch) | |
| tree | bcfbf4d0647d9442045639a5c19da59d55190e81 /net | |
| parent | ebcc80c1b6629a445f7471cc1ddb48faf8a84e70 (diff) | |
| parent | 7f9eaedf894dbaa08c157832e9a6c9c03ffed1ed (diff) | |
Merge with temp tree to get David's gdb inferior calls patch
Diffstat (limited to 'net')
47 files changed, 496 insertions, 309 deletions
| diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index c32d27af0a3f..7b214cffc956 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -23,7 +23,7 @@  #include <linux/errno.h>	/* return codes */  #include <linux/kernel.h>  #include <linux/slab.h>		/* kmalloc(), kfree() */ -#include <linux/mm.h>		/* verify_area(), etc. */ +#include <linux/mm.h>  #include <linux/string.h>	/* inline mem*, str* functions */  #include <linux/init.h>		/* __initfunc et al. */  #include <asm/byteorder.h>	/* htons(), etc. */ diff --git a/net/atm/common.c b/net/atm/common.c index 6d16be334ea0..e93e838069e8 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -12,7 +12,7 @@  #include <linux/socket.h>	/* SOL_SOCKET */  #include <linux/errno.h>	/* error codes */  #include <linux/capability.h> -#include <linux/mm.h>		/* verify_area */ +#include <linux/mm.h>  #include <linux/sched.h>  #include <linux/time.h>		/* struct timeval */  #include <linux/skbuff.h> @@ -540,7 +540,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,  		error = -EMSGSIZE;  		goto out;  	} -	/* verify_area is done by net/socket.c */ +  	eff = (size+3) & ~3; /* align to word boundary */  	prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);  	error = 0; diff --git a/net/core/datagram.c b/net/core/datagram.c index d1bfd279cc1a..fcee054b6f75 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -115,10 +115,10 @@ out_noerr:  /**   *	skb_recv_datagram - Receive a datagram skbuff - *	@sk - socket - *	@flags - MSG_ flags - *	@noblock - blocking operation? - *	@err - error code returned + *	@sk: socket + *	@flags: MSG_ flags + *	@noblock: blocking operation? + *	@err: error code returned   *   *	Get a datagram skbuff, understands the peeking, nonblocking wakeups   *	and possible races. This replaces identical code in packet, raw and @@ -201,10 +201,10 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)  /**   *	skb_copy_datagram_iovec - Copy a datagram to an iovec. - *	@skb - buffer to copy - *	@offset - offset in the buffer to start copying from - *	@iovec - io vector to copy to - *	@len - amount of data to copy from buffer to iovec + *	@skb: buffer to copy + *	@offset: offset in the buffer to start copying from + *	@to: io vector to copy to + *	@len: amount of data to copy from buffer to iovec   *   *	Note: the iovec is modified during the copy.   */ @@ -377,9 +377,9 @@ fault:  /**   *	skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. - *	@skb - skbuff - *	@hlen - hardware length - *	@iovec - io vector + *	@skb: skbuff + *	@hlen: hardware length + *	@iov: io vector   *    *	Caller _must_ check that skb will fit to this iovec.   * @@ -425,9 +425,9 @@ fault:  /**   * 	datagram_poll - generic datagram poll - *	@file - file struct - *	@sock - socket - *	@wait - poll table + *	@file: file struct + *	@sock: socket + *	@wait: poll table   *   *	Datagram poll: Again totally generic. This also handles   *	sequenced packet sockets providing the socket receive queue diff --git a/net/core/dev.c b/net/core/dev.c index 7bd4cd4502c4..f5f005846fe1 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3091,7 +3091,7 @@ void free_netdev(struct net_device *dev)  void synchronize_net(void)   {  	might_sleep(); -	synchronize_kernel(); +	synchronize_rcu();  }  /** diff --git a/net/core/iovec.c b/net/core/iovec.c index d57ace949ab8..65e4b56fbc77 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -33,7 +33,7 @@   *	Verify iovec. The caller must ensure that the iovec is big enough   *	to hold the message iovec.   * - *	Save time not doing verify_area. copy_*_user will make this work + *	Save time not doing access_ok. copy_*_user will make this work   *	in any case.   */ diff --git a/net/core/link_watch.c b/net/core/link_watch.c index 4859b7446c6f..d43d1201275c 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -16,6 +16,7 @@  #include <linux/netdevice.h>  #include <linux/if.h>  #include <net/sock.h> +#include <net/pkt_sched.h>  #include <linux/rtnetlink.h>  #include <linux/jiffies.h>  #include <linux/spinlock.h> @@ -74,6 +75,12 @@ void linkwatch_run_queue(void)  		clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);  		if (dev->flags & IFF_UP) { +			if (netif_carrier_ok(dev)) { +				WARN_ON(dev->qdisc_sleeping == &noop_qdisc); +				dev_activate(dev); +			} else +				dev_deactivate(dev); +  			netdev_state_change(dev);  		} diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0a2f67bbef2e..43bdc521e20d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1953,7 +1953,7 @@ static int neigh_stat_seq_show(struct seq_file *seq, void *v)  	struct neigh_statistics *st = v;  	if (v == SEQ_START_TOKEN) { -		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); +		seq_printf(seq, "entries  allocs destroys hash_grows  lookups hits  res_failed  rcv_probes_mcast rcv_probes_ucast  periodic_gc_runs forced_gc_runs\n");  		return 0;  	} diff --git a/net/core/netfilter.c b/net/core/netfilter.c index e51cfa46950c..22a8f127c4aa 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -217,21 +217,10 @@ void nf_debug_ip_local_deliver(struct sk_buff *skb)  	 * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING.  */  	if (!skb->dev) {  		printk("ip_local_deliver: skb->dev is NULL.\n"); -	} -	else if (strcmp(skb->dev->name, "lo") == 0) { -		if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) -				      | (1 << NF_IP_POST_ROUTING) -				      | (1 << NF_IP_PRE_ROUTING) -				      | (1 << NF_IP_LOCAL_IN))) { -			printk("ip_local_deliver: bad loopback skb: "); -			debug_print_hooks_ip(skb->nf_debug); -			nf_dump_skb(PF_INET, skb); -		} -	} -	else { +	} else {  		if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING)  				      | (1<<NF_IP_LOCAL_IN))) { -			printk("ip_local_deliver: bad non-lo skb: "); +			printk("ip_local_deliver: bad skb: ");  			debug_print_hooks_ip(skb->nf_debug);  			nf_dump_skb(PF_INET, skb);  		} @@ -247,8 +236,6 @@ void nf_debug_ip_loopback_xmit(struct sk_buff *newskb)  		debug_print_hooks_ip(newskb->nf_debug);  		nf_dump_skb(PF_INET, newskb);  	} -	/* Clear to avoid confusing input check */ -	newskb->nf_debug = 0;  }  void nf_debug_ip_finish_output2(struct sk_buff *skb) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index d8c198e42f90..00caf4b318b2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -86,30 +86,33 @@ struct sock *rtnl;  struct rtnetlink_link * rtnetlink_links[NPROTO]; -static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] = +static const int rtm_min[RTM_NR_FAMILIES] =  { -	NLMSG_LENGTH(sizeof(struct ifinfomsg)), -	NLMSG_LENGTH(sizeof(struct ifaddrmsg)), -	NLMSG_LENGTH(sizeof(struct rtmsg)), -	NLMSG_LENGTH(sizeof(struct ndmsg)), -	NLMSG_LENGTH(sizeof(struct rtmsg)), -	NLMSG_LENGTH(sizeof(struct tcmsg)), -	NLMSG_LENGTH(sizeof(struct tcmsg)), -	NLMSG_LENGTH(sizeof(struct tcmsg)), -	NLMSG_LENGTH(sizeof(struct tcamsg)) +	[RTM_FAM(RTM_NEWLINK)]      = NLMSG_LENGTH(sizeof(struct ifinfomsg)), +	[RTM_FAM(RTM_NEWADDR)]      = NLMSG_LENGTH(sizeof(struct ifaddrmsg)), +	[RTM_FAM(RTM_NEWROUTE)]     = NLMSG_LENGTH(sizeof(struct rtmsg)), +	[RTM_FAM(RTM_NEWNEIGH)]     = NLMSG_LENGTH(sizeof(struct ndmsg)), +	[RTM_FAM(RTM_NEWRULE)]      = NLMSG_LENGTH(sizeof(struct rtmsg)), +	[RTM_FAM(RTM_NEWQDISC)]     = NLMSG_LENGTH(sizeof(struct tcmsg)), +	[RTM_FAM(RTM_NEWTCLASS)]    = NLMSG_LENGTH(sizeof(struct tcmsg)), +	[RTM_FAM(RTM_NEWTFILTER)]   = NLMSG_LENGTH(sizeof(struct tcmsg)), +	[RTM_FAM(RTM_NEWACTION)]    = NLMSG_LENGTH(sizeof(struct tcamsg)), +	[RTM_FAM(RTM_NEWPREFIX)]    = NLMSG_LENGTH(sizeof(struct rtgenmsg)), +	[RTM_FAM(RTM_GETMULTICAST)] = NLMSG_LENGTH(sizeof(struct rtgenmsg)), +	[RTM_FAM(RTM_GETANYCAST)]   = NLMSG_LENGTH(sizeof(struct rtgenmsg)),  }; -static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] = +static const int rta_max[RTM_NR_FAMILIES] =  { -	IFLA_MAX, -	IFA_MAX, -	RTA_MAX, -	NDA_MAX, -	RTA_MAX, -	TCA_MAX, -	TCA_MAX, -	TCA_MAX, -	TCAA_MAX +	[RTM_FAM(RTM_NEWLINK)]      = IFLA_MAX, +	[RTM_FAM(RTM_NEWADDR)]      = IFA_MAX, +	[RTM_FAM(RTM_NEWROUTE)]     = RTA_MAX, +	[RTM_FAM(RTM_NEWNEIGH)]     = NDA_MAX, +	[RTM_FAM(RTM_NEWRULE)]      = RTA_MAX, +	[RTM_FAM(RTM_NEWQDISC)]     = TCA_MAX, +	[RTM_FAM(RTM_NEWTCLASS)]    = TCA_MAX, +	[RTM_FAM(RTM_NEWTFILTER)]   = TCA_MAX, +	[RTM_FAM(RTM_NEWACTION)]    = TCAA_MAX,  };  void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data) @@ -606,27 +609,33 @@ static inline int rtnetlink_rcv_skb(struct sk_buff *skb)  /*   *  rtnetlink input queue processing routine: - *	- try to acquire shared lock. If it is failed, defer processing. + *	- process as much as there was in the queue upon entry.   *	- feed skbs to rtnetlink_rcv_skb, until it refuse a message, - *	  that will occur, when a dump started and/or acquisition of - *	  exclusive lock failed. + *	  that will occur, when a dump started.   */  static void rtnetlink_rcv(struct sock *sk, int len)  { +	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); +  	do {  		struct sk_buff *skb; -		if (rtnl_shlock_nowait()) -			return; +		rtnl_lock(); + +		if (qlen > skb_queue_len(&sk->sk_receive_queue)) +			qlen = skb_queue_len(&sk->sk_receive_queue); -		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { +		for (; qlen; qlen--) { +			skb = skb_dequeue(&sk->sk_receive_queue);  			if (rtnetlink_rcv_skb(skb)) {  				if (skb->len)  					skb_queue_head(&sk->sk_receive_queue,  						       skb); -				else +				else {  					kfree_skb(skb); +					qlen--; +				}  				break;  			}  			kfree_skb(skb); @@ -635,10 +644,10 @@ static void rtnetlink_rcv(struct sock *sk, int len)  		up(&rtnl_sem);  		netdev_run_todo(); -	} while (rtnl && rtnl->sk_receive_queue.qlen); +	} while (qlen);  } -static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = +static struct rtnetlink_link link_rtnetlink_table[RTM_NR_MSGTYPES] =  {  	[RTM_GETLINK  - RTM_BASE] = { .dumpit = rtnetlink_dump_ifinfo },  	[RTM_SETLINK  - RTM_BASE] = { .doit   = do_setlink	      }, diff --git a/net/core/sock.c b/net/core/sock.c index 5c2f72fa1013..98171ddd7e7d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -616,10 +616,10 @@ lenout:  /**   *	sk_alloc - All socket objects are allocated here - *	@family - protocol family - *	@priority - for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) - *	@prot - struct proto associated with this new sock instance - *	@zero_it - if we should zero the newly allocated sock + *	@family: protocol family + *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) + *	@prot: struct proto associated with this new sock instance + *	@zero_it: if we should zero the newly allocated sock   */  struct sock *sk_alloc(int family, int priority, struct proto *prot, int zero_it)  { @@ -970,8 +970,8 @@ static void __release_sock(struct sock *sk)  /**   * sk_wait_data - wait for data to arrive at sk_receive_queue - * sk - sock to wait on - * timeo - for how long + * @sk:    sock to wait on + * @timeo: for how long   *   * Now socket state including sk->sk_err is changed only under lock,   * hence we may omit checks after joining wait queue. diff --git a/net/core/stream.c b/net/core/stream.c index 1e27a57b5a97..ac9edfdf8742 100644 --- a/net/core/stream.c +++ b/net/core/stream.c @@ -21,7 +21,7 @@  /**   * sk_stream_write_space - stream socket write_space callback. - * sk - socket + * @sk: socket   *   * FIXME: write proper description   */ @@ -43,8 +43,8 @@ EXPORT_SYMBOL(sk_stream_write_space);  /**   * sk_stream_wait_connect - Wait for a socket to get into the connected state - * @sk - sock to wait on - * @timeo_p - for how long to wait + * @sk: sock to wait on + * @timeo_p: for how long to wait   *   * Must be called with the socket locked.   */ @@ -79,7 +79,7 @@ EXPORT_SYMBOL(sk_stream_wait_connect);  /**   * sk_stream_closing - Return 1 if we still have things to send in our buffers. - * @sk - socket to verify + * @sk: socket to verify   */  static inline int sk_stream_closing(struct sock *sk)  { @@ -107,8 +107,8 @@ EXPORT_SYMBOL(sk_stream_wait_close);  /**   * sk_stream_wait_memory - Wait for more memory for a socket - * @sk - socket to wait for memory - * @timeo_p - for how long + * @sk: socket to wait for memory + * @timeo_p: for how long   */  int sk_stream_wait_memory(struct sock *sk, long *timeo_p)  { diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index c2a0346f423b..e6e23eb14428 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -1411,21 +1411,22 @@ static struct file_operations dn_dev_seq_fops = {  #endif /* CONFIG_PROC_FS */ -static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =  +static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =  { -	 [4] = { .doit   = dn_dev_rtm_newaddr,	}, -	 [5] = { .doit   = dn_dev_rtm_deladdr,	}, -	 [6] = { .dumpit = dn_dev_dump_ifaddr,	}, - +	[RTM_NEWADDR  - RTM_BASE] = { .doit	= dn_dev_rtm_newaddr,	}, +	[RTM_DELADDR  - RTM_BASE] = { .doit	= dn_dev_rtm_deladdr,	}, +	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= dn_dev_dump_ifaddr,	},  #ifdef CONFIG_DECNET_ROUTER -	 [8] = { .doit   = dn_fib_rtm_newroute,	}, -	 [9] = { .doit   = dn_fib_rtm_delroute,	}, -	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_fib_dump, }, -	[16] = { .doit   = dn_fib_rtm_newrule, }, -	[17] = { .doit   = dn_fib_rtm_delrule, }, -	[18] = { .dumpit = dn_fib_dump_rules,  }, +	[RTM_NEWROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_newroute,	}, +	[RTM_DELROUTE - RTM_BASE] = { .doit	= dn_fib_rtm_delroute,	}, +	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute, +				      .dumpit	= dn_fib_dump,		}, +	[RTM_NEWRULE  - RTM_BASE] = { .doit	= dn_fib_rtm_newrule,	}, +	[RTM_DELRULE  - RTM_BASE] = { .doit	= dn_fib_rtm_delrule,	}, +	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= dn_fib_dump_rules,	},  #else -	[10] = { .doit   = dn_cache_getroute, .dumpit = dn_cache_dump, }, +	[RTM_GETROUTE - RTM_BASE] = { .doit	= dn_cache_getroute, +				      .dumpit	= dn_cache_dump,	  #endif  }; diff --git a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c index f86a6259fd12..284a9998e53d 100644 --- a/net/decnet/netfilter/dn_rtmsg.c +++ b/net/decnet/netfilter/dn_rtmsg.c @@ -119,8 +119,9 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)  static void dnrmg_receive_user_sk(struct sock *sk, int len)  {  	struct sk_buff *skb; +	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); -	while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { +	for (; qlen && (skb = skb_dequeue(&sk->sk_receive_queue)); qlen--) {  		dnrmg_receive_user_skb(skb);  		kfree_skb(skb);  	} diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index eea7ef010776..abbc6d5c183e 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1107,17 +1107,18 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa)  	}  } -static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = { -	 [4] = { .doit	 = inet_rtm_newaddr,  }, -	 [5] = { .doit	 = inet_rtm_deladdr,  }, -	 [6] = { .dumpit = inet_dump_ifaddr,  }, -	 [8] = { .doit	 = inet_rtm_newroute, }, -	 [9] = { .doit	 = inet_rtm_delroute, }, -	[10] = { .doit	 = inet_rtm_getroute, .dumpit = inet_dump_fib, }, +static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = { +	[RTM_NEWADDR  - RTM_BASE] = { .doit	= inet_rtm_newaddr,	}, +	[RTM_DELADDR  - RTM_BASE] = { .doit	= inet_rtm_deladdr,	}, +	[RTM_GETADDR  - RTM_BASE] = { .dumpit	= inet_dump_ifaddr,	}, +	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet_rtm_newroute,	}, +	[RTM_DELROUTE - RTM_BASE] = { .doit	= inet_rtm_delroute,	}, +	[RTM_GETROUTE - RTM_BASE] = { .doit	= inet_rtm_getroute, +				      .dumpit	= inet_dump_fib,	},  #ifdef CONFIG_IP_MULTIPLE_TABLES -	[16] = { .doit	 = inet_rtm_newrule, }, -	[17] = { .doit	 = inet_rtm_delrule, }, -	[18] = { .dumpit = inet_dump_rules,  }, +	[RTM_NEWRULE  - RTM_BASE] = { .doit	= inet_rtm_newrule,	}, +	[RTM_DELRULE  - RTM_BASE] = { .doit	= inet_rtm_delrule,	}, +	[RTM_GETRULE  - RTM_BASE] = { .dumpit	= inet_dump_rules,	},  #endif  }; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 38f69532a029..24fe3e00b42b 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -111,6 +111,7 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)  #ifdef CONFIG_NETFILTER_DEBUG  	nf_debug_ip_loopback_xmit(newskb);  #endif +	nf_reset(newskb);  	netif_rx(newskb);  	return 0;  } diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 2b87c1974be6..721ddbf522b4 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c @@ -819,6 +819,7 @@ static int tcp_error(struct sk_buff *skb,  	 */  	/* FIXME: Source route IP option packets --RR */  	if (hooknum == NF_IP_PRE_ROUTING +	    && skb->ip_summed != CHECKSUM_UNNECESSARY  	    && csum_tcpudp_magic(iph->saddr, iph->daddr, tcplen, IPPROTO_TCP,  			         skb->ip_summed == CHECKSUM_HW ? skb->csum  			      	 : skb_checksum(skb, iph->ihl*4, tcplen, 0))) { diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 9e40dffc204f..e5746b674413 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -546,20 +546,18 @@ ipq_rcv_skb(struct sk_buff *skb)  static void  ipq_rcv_sk(struct sock *sk, int len)  { -	do { -		struct sk_buff *skb; +	struct sk_buff *skb; +	unsigned int qlen; -		if (down_trylock(&ipqnl_sem)) -			return; +	down(&ipqnl_sem); -		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { -			ipq_rcv_skb(skb); -			kfree_skb(skb); -		} +	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { +		skb = skb_dequeue(&sk->sk_receive_queue); +		ipq_rcv_skb(skb); +		kfree_skb(skb); +	} -		up(&ipqnl_sem); - -	} while (ipqnl && ipqnl->sk_receive_queue.qlen); +	up(&ipqnl_sem);  }  static int diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 01b4a3c814d3..47449ba83eb9 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -103,13 +103,15 @@ static struct nf_hook_ops ipt_ops[] = {  	  .hook = ipt_hook,   	  .pf = PF_INET,   	  .hooknum = NF_IP_PRE_ROUTING,  -	  .priority = NF_IP_PRI_RAW +	  .priority = NF_IP_PRI_RAW, +	  .owner = THIS_MODULE,  	},  	{  	  .hook = ipt_hook,   	  .pf = PF_INET,   	  .hooknum = NF_IP_LOCAL_OUT,  -	  .priority = NF_IP_PRI_RAW +	  .priority = NF_IP_PRI_RAW, +	  .owner = THIS_MODULE,  	},  }; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index bb90a0c3a91e..199311746932 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -397,7 +397,7 @@ static int rt_cpu_seq_show(struct seq_file *seq, void *v)  	struct rt_cache_stat *st = v;  	if (v == SEQ_START_TOKEN) { -		seq_printf(seq, "entries  in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); +		seq_printf(seq, "entries  in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src  out_hit out_slow_tot out_slow_mc  gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n");  		return 0;  	} @@ -2843,7 +2843,7 @@ ctl_table ipv4_route_table[] = {  		.procname	= "flush",  		.data		= &flush_delay,  		.maxlen		= sizeof(int), -		.mode		= 0644, +		.mode		= 0200,  		.proc_handler	= &ipv4_sysctl_rtcache_flush,  		.strategy	= &ipv4_sysctl_rtcache_flush_strategy,  	}, diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 313c1408da33..8faa8948f75c 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -777,8 +777,9 @@ static inline void tcpdiag_rcv_skb(struct sk_buff *skb)  static void tcpdiag_rcv(struct sock *sk, int len)  {  	struct sk_buff *skb; +	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); -	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { +	while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) {  		tcpdiag_rcv_skb(skb);  		kfree_skb(skb);  	} diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3ac6659869c4..dad98e4a5043 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -222,10 +222,13 @@ static int tcp_v4_get_port(struct sock *sk, unsigned short snum)  		int rover;  		spin_lock(&tcp_portalloc_lock); -		rover = tcp_port_rover; +		if (tcp_port_rover < low) +			rover = low; +		else +			rover = tcp_port_rover;  		do {  			rover++; -			if (rover < low || rover > high) +			if (rover > high)  				rover = low;  			head = &tcp_bhash[tcp_bhashfn(rover)];  			spin_lock(&head->lock); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 7fe2afd2e669..b2b60f3e9cdd 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -8,7 +8,10 @@   * 	   */ +#include <asm/bug.h> +#include <linux/compiler.h>  #include <linux/config.h> +#include <linux/inetdevice.h>  #include <net/xfrm.h>  #include <net/ip.h> @@ -152,6 +155,8 @@ __xfrm4_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int  		x->u.rt.rt_dst = rt0->rt_dst;  		x->u.rt.rt_gateway = rt->rt_gateway;  		x->u.rt.rt_spec_dst = rt0->rt_spec_dst; +		x->u.rt.idev = rt0->idev; +		in_dev_hold(rt0->idev);  		header_len -= x->u.dst.xfrm->props.header_len;  		trailer_len -= x->u.dst.xfrm->props.trailer_len;  	} @@ -243,11 +248,48 @@ static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)  	path->ops->update_pmtu(path, mtu);  } +static void xfrm4_dst_destroy(struct dst_entry *dst) +{ +	struct xfrm_dst *xdst = (struct xfrm_dst *)dst; + +	if (likely(xdst->u.rt.idev)) +		in_dev_put(xdst->u.rt.idev); +	xfrm_dst_destroy(xdst); +} + +static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, +			     int unregister) +{ +	struct xfrm_dst *xdst; + +	if (!unregister) +		return; + +	xdst = (struct xfrm_dst *)dst; +	if (xdst->u.rt.idev->dev == dev) { +		struct in_device *loopback_idev = in_dev_get(&loopback_dev); +		BUG_ON(!loopback_idev); + +		do { +			in_dev_put(xdst->u.rt.idev); +			xdst->u.rt.idev = loopback_idev; +			in_dev_hold(loopback_idev); +			xdst = (struct xfrm_dst *)xdst->u.dst.child; +		} while (xdst->u.dst.xfrm); + +		__in_dev_put(loopback_idev); +	} + +	xfrm_dst_ifdown(dst, dev); +} +  static struct dst_ops xfrm4_dst_ops = {  	.family =		AF_INET,  	.protocol =		__constant_htons(ETH_P_IP),  	.gc =			xfrm4_garbage_collect,  	.update_pmtu =		xfrm4_update_pmtu, +	.destroy =		xfrm4_dst_destroy, +	.ifdown =		xfrm4_dst_ifdown,  	.gc_thresh =		1024,  	.entry_size =		sizeof(struct xfrm_dst),  }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7196ac2f2d16..7744a2592693 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3076,7 +3076,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,  	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_PREFIX, GFP_ATOMIC);  } -static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = { +static struct rtnetlink_link inet6_rtnetlink_table[RTM_NR_MSGTYPES] = {  	[RTM_GETLINK - RTM_BASE] = { .dumpit	= inet6_dump_ifinfo, },  	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },  	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, }, diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index c54830b89593..750943e2d34e 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -549,20 +549,18 @@ ipq_rcv_skb(struct sk_buff *skb)  static void  ipq_rcv_sk(struct sock *sk, int len)  { -	do { -		struct sk_buff *skb; +	struct sk_buff *skb; +	unsigned int qlen; -		if (down_trylock(&ipqnl_sem)) -			return; +	down(&ipqnl_sem); -		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { -			ipq_rcv_skb(skb); -			kfree_skb(skb); -		} +	for (qlen = skb_queue_len(&sk->sk_receive_queue); qlen; qlen--) { +		skb = skb_dequeue(&sk->sk_receive_queue); +		ipq_rcv_skb(skb); +		kfree_skb(skb); +	} -		up(&ipqnl_sem); - -	} while (ipqnl && ipqnl->sk_receive_queue.qlen); +	up(&ipqnl_sem);  }  static int diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 1352c1d9bf4d..617645bc5ed6 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -455,11 +455,11 @@ csum_copy_err:  static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,  				     struct raw6_sock *rp)  { -	struct inet_sock *inet = inet_sk(sk);  	struct sk_buff *skb;  	int err = 0;  	int offset;  	int len; +	int total_len;  	u32 tmp_csum;  	u16 csum; @@ -470,7 +470,8 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,  		goto out;  	offset = rp->offset; -	if (offset >= inet->cork.length - 1) { +	total_len = inet_sk(sk)->cork.length - (skb->nh.raw - skb->data); +	if (offset >= total_len - 1) {  		err = -EINVAL;  		ip6_flush_pending_frames(sk);  		goto out; @@ -514,7 +515,7 @@ static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl,  	tmp_csum = csum_ipv6_magic(&fl->fl6_src,  				   &fl->fl6_dst, -				   inet->cork.length, fl->proto, tmp_csum); +				   total_len, fl->proto, tmp_csum);  	if (tmp_csum == 0)  		tmp_csum = -1; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 183802902c02..3bf8a0254f81 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2005,7 +2005,7 @@ ctl_table ipv6_route_table[] = {  		.procname	=	"flush",           	.data		=	&flush_delay,  		.maxlen		=	sizeof(int), -		.mode		=	0644, +		.mode		=	0200,           	.proc_handler	=	&ipv6_sysctl_rtcache_flush  	},  	{ diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 4760c85e19db..0f69e800a0ad 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -139,9 +139,12 @@ static int tcp_v6_get_port(struct sock *sk, unsigned short snum)  		int rover;  		spin_lock(&tcp_portalloc_lock); -		rover = tcp_port_rover; +		if (tcp_port_rover < low) +			rover = low; +		else +			rover = tcp_port_rover;  		do {	rover++; -			if ((rover < low) || (rover > high)) +			if (rover > high)  				rover = low;  			head = &tcp_bhash[tcp_bhashfn(rover)];  			spin_lock(&head->lock); diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8a4f37de4d2d..4429b1a1fe5f 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -11,7 +11,11 @@   *    */ +#include <asm/bug.h> +#include <linux/compiler.h>  #include <linux/config.h> +#include <linux/netdevice.h> +#include <net/addrconf.h>  #include <net/xfrm.h>  #include <net/ip.h>  #include <net/ipv6.h> @@ -166,6 +170,8 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int  		memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway));   		x->u.rt6.rt6i_dst      = rt0->rt6i_dst;  		x->u.rt6.rt6i_src      = rt0->rt6i_src;	 +		x->u.rt6.rt6i_idev     = rt0->rt6i_idev; +		in6_dev_hold(rt0->rt6i_idev);  		header_len -= x->u.dst.xfrm->props.header_len;  		trailer_len -= x->u.dst.xfrm->props.trailer_len;  	} @@ -251,11 +257,48 @@ static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu)  	path->ops->update_pmtu(path, mtu);  } +static void xfrm6_dst_destroy(struct dst_entry *dst) +{ +	struct xfrm_dst *xdst = (struct xfrm_dst *)dst; + +	if (likely(xdst->u.rt6.rt6i_idev)) +		in6_dev_put(xdst->u.rt6.rt6i_idev); +	xfrm_dst_destroy(xdst); +} + +static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, +			     int unregister) +{ +	struct xfrm_dst *xdst; + +	if (!unregister) +		return; + +	xdst = (struct xfrm_dst *)dst; +	if (xdst->u.rt6.rt6i_idev->dev == dev) { +		struct inet6_dev *loopback_idev = in6_dev_get(&loopback_dev); +		BUG_ON(!loopback_idev); + +		do { +			in6_dev_put(xdst->u.rt6.rt6i_idev); +			xdst->u.rt6.rt6i_idev = loopback_idev; +			in6_dev_hold(loopback_idev); +			xdst = (struct xfrm_dst *)xdst->u.dst.child; +		} while (xdst->u.dst.xfrm); + +		__in6_dev_put(loopback_idev); +	} + +	xfrm_dst_ifdown(dst, dev); +} +  static struct dst_ops xfrm6_dst_ops = {  	.family =		AF_INET6,  	.protocol =		__constant_htons(ETH_P_IPV6),  	.gc =			xfrm6_garbage_collect,  	.update_pmtu =		xfrm6_update_pmtu, +	.destroy =		xfrm6_dst_destroy, +	.ifdown =		xfrm6_dst_ifdown,  	.gc_thresh =		1024,  	.entry_size =		sizeof(struct xfrm_dst),  }; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 29a5fd231eac..4ee392066148 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -373,7 +373,6 @@ static int netlink_release(struct socket *sock)  		nlk->cb->done(nlk->cb);  		netlink_destroy_callback(nlk->cb);  		nlk->cb = NULL; -		__sock_put(sk);  	}  	spin_unlock(&nlk->cb_lock); @@ -1099,7 +1098,6 @@ static int netlink_dump(struct sock *sk)  	spin_unlock(&nlk->cb_lock);  	netlink_destroy_callback(cb); -	__sock_put(sk);  	return 0;  } @@ -1138,7 +1136,6 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb,  		return -EBUSY;  	}  	nlk->cb = cb; -	sock_hold(sk);  	spin_unlock(&nlk->cb_lock);  	netlink_dump(sk); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 9c118baed9dc..b0941186f867 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -185,7 +185,7 @@ config NET_SCH_GRED  	depends on NET_SCHED  	help  	  Say Y here if you want to use the Generic Random Early Detection -	  (RED) packet scheduling algorithm for some of your network devices +	  (GRED) packet scheduling algorithm for some of your network devices  	  (see the top of <file:net/sched/sch_red.c> for details and  	  references about the algorithm). diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 5e6cc371b39e..cafcb084098d 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -171,10 +171,10 @@ repeat:  				skb->tc_verd = SET_TC_OK2MUNGE(skb->tc_verd);  				skb->tc_verd = CLR_TC_MUNGED(skb->tc_verd);  			} -			if (ret != TC_ACT_PIPE) -				goto exec_done;  			if (ret == TC_ACT_REPEAT)  				goto repeat;	/* we need a ttl - JHS */ +			if (ret != TC_ACT_PIPE) +				goto exec_done;  		}  		act = a->next;  	} diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 4323a74eea30..07977f8f2679 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1289,6 +1289,7 @@ static int __init pktsched_init(void)  subsys_initcall(pktsched_init); +EXPORT_SYMBOL(qdisc_lookup);  EXPORT_SYMBOL(qdisc_get_rtab);  EXPORT_SYMBOL(qdisc_put_rtab);  EXPORT_SYMBOL(register_qdisc); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 8c01e023f02e..87e48a4e1051 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -179,6 +179,7 @@ requeue:  		netif_schedule(dev);  		return 1;  	} +	BUG_ON((int) q->q.qlen < 0);  	return q->q.qlen;  } @@ -539,6 +540,10 @@ void dev_activate(struct net_device *dev)  		write_unlock_bh(&qdisc_tree_lock);  	} +	if (!netif_carrier_ok(dev)) +		/* Delay activation until next carrier-on event */ +		return; +  	spin_lock_bh(&dev->queue_lock);  	rcu_assign_pointer(dev->qdisc, dev->qdisc_sleeping);  	if (dev->qdisc != &noqueue_qdisc) { diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index a85935e7d53d..558cc087e602 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -717,6 +717,10 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch)  	if (q->direct_queue.qlen < q->direct_qlen) {  	    __skb_queue_tail(&q->direct_queue, skb);  	    q->direct_pkts++; +	} else { +	    kfree_skb(skb); +	    sch->qstats.drops++; +	    return NET_XMIT_DROP;  	}  #ifdef CONFIG_NET_CLS_ACT      } else if (!cl) { diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 31c29deb139d..e0c9fbe73b15 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -138,38 +138,77 @@ static long tabledist(unsigned long mu, long sigma,  }  /* Put skb in the private delayed queue. */ -static int delay_skb(struct Qdisc *sch, struct sk_buff *skb) +static int netem_delay(struct Qdisc *sch, struct sk_buff *skb)  {  	struct netem_sched_data *q = qdisc_priv(sch); -	struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb;  	psched_tdiff_t td;  	psched_time_t now;  	PSCHED_GET_TIME(now);  	td = tabledist(q->latency, q->jitter, &q->delay_cor, q->delay_dist); -	PSCHED_TADD2(now, td, cb->time_to_send);  	/* Always queue at tail to keep packets in order */  	if (likely(q->delayed.qlen < q->limit)) { +		struct netem_skb_cb *cb = (struct netem_skb_cb *)skb->cb; +	 +		PSCHED_TADD2(now, td, cb->time_to_send); + +		pr_debug("netem_delay: skb=%p now=%llu tosend=%llu\n", skb,  +			 now, cb->time_to_send); +	  		__skb_queue_tail(&q->delayed, skb); -		if (!timer_pending(&q->timer)) { -			q->timer.expires = jiffies + PSCHED_US2JIFFIE(td); -			add_timer(&q->timer); -		}  		return NET_XMIT_SUCCESS;  	} +	pr_debug("netem_delay: queue over limit %d\n", q->limit); +	sch->qstats.overlimits++;  	kfree_skb(skb);  	return NET_XMIT_DROP;  } +/* + *  Move a packet that is ready to send from the delay holding + *  list to the underlying qdisc. + */ +static int netem_run(struct Qdisc *sch) +{ +	struct netem_sched_data *q = qdisc_priv(sch); +	struct sk_buff *skb; +	psched_time_t now; + +	PSCHED_GET_TIME(now); + +	skb = skb_peek(&q->delayed); +	if (skb) { +		const struct netem_skb_cb *cb +			= (const struct netem_skb_cb *)skb->cb; +		long delay  +			= PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); +		pr_debug("netem_run: skb=%p delay=%ld\n", skb, delay); + +		/* if more time remaining? */ +		if (delay > 0) { +			mod_timer(&q->timer, jiffies + delay); +			return 1; +		} + +		__skb_unlink(skb, &q->delayed); +		 +		if (q->qdisc->enqueue(skb, q->qdisc)) { +			sch->q.qlen--; +			sch->qstats.drops++; +		}  +	} + +	return 0; +} +  static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)  {  	struct netem_sched_data *q = qdisc_priv(sch); -	struct sk_buff *skb2;  	int ret; -	pr_debug("netem_enqueue skb=%p @%lu\n", skb, jiffies); +	pr_debug("netem_enqueue skb=%p\n", skb);  	/* Random packet drop 0 => none, ~0 => all */  	if (q->loss && q->loss >= get_crandom(&q->loss_cor)) { @@ -180,11 +219,21 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)  	}  	/* Random duplication */ -	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor) -	    && (skb2 = skb_clone(skb, GFP_ATOMIC)) != NULL) { -		pr_debug("netem_enqueue: dup %p\n", skb2); +	if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor)) { +		struct sk_buff *skb2; + +		skb2 = skb_clone(skb, GFP_ATOMIC); +		if (skb2 && netem_delay(sch, skb2) == NET_XMIT_SUCCESS) { +			struct Qdisc *qp; + +			/* Since one packet can generate two packets in the +			 * queue, the parent's qlen accounting gets confused, +			 * so fix it. +			 */ +			qp = qdisc_lookup(sch->dev, TC_H_MAJ(sch->parent)); +			if (qp) +				qp->q.qlen++; -		if (delay_skb(sch, skb2)) {  			sch->q.qlen++;  			sch->bstats.bytes += skb2->len;  			sch->bstats.packets++; @@ -202,7 +251,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)  		ret = q->qdisc->enqueue(skb, q->qdisc);  	} else {  		q->counter = 0; -		ret = delay_skb(sch, skb); +		ret = netem_delay(sch, skb); +		netem_run(sch);  	}  	if (likely(ret == NET_XMIT_SUCCESS)) { @@ -212,6 +262,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)  	} else  		sch->qstats.drops++; +	pr_debug("netem: enqueue ret %d\n", ret);  	return ret;  } @@ -241,56 +292,35 @@ static unsigned int netem_drop(struct Qdisc* sch)  	return len;  } -/* Dequeue packet. - *  Move all packets that are ready to send from the delay holding - *  list to the underlying qdisc, then just call dequeue - */  static struct sk_buff *netem_dequeue(struct Qdisc *sch)  {  	struct netem_sched_data *q = qdisc_priv(sch);  	struct sk_buff *skb; +	int pending; + +	pending = netem_run(sch);  	skb = q->qdisc->dequeue(q->qdisc); -	if (skb)  +	if (skb) { +		pr_debug("netem_dequeue: return skb=%p\n", skb);  		sch->q.qlen--; +		sch->flags &= ~TCQ_F_THROTTLED; +	} +	else if (pending) { +		pr_debug("netem_dequeue: throttling\n"); +		sch->flags |= TCQ_F_THROTTLED; +	}  +  	return skb;  }  static void netem_watchdog(unsigned long arg)  {  	struct Qdisc *sch = (struct Qdisc *)arg; -	struct netem_sched_data *q = qdisc_priv(sch); -	struct net_device *dev = sch->dev; -	struct sk_buff *skb; -	psched_time_t now; - -	pr_debug("netem_watchdog: fired @%lu\n", jiffies); - -	spin_lock_bh(&dev->queue_lock); -	PSCHED_GET_TIME(now); - -	while ((skb = skb_peek(&q->delayed)) != NULL) { -		const struct netem_skb_cb *cb -			= (const struct netem_skb_cb *)skb->cb; -		long delay  -			= PSCHED_US2JIFFIE(PSCHED_TDIFF(cb->time_to_send, now)); -		pr_debug("netem_watchdog: skb %p@%lu %ld\n", -			 skb, jiffies, delay); -		/* if more time remaining? */ -		if (delay > 0) { -			mod_timer(&q->timer, jiffies + delay); -			break; -		} -		__skb_unlink(skb, &q->delayed); - -		if (q->qdisc->enqueue(skb, q->qdisc)) { -			sch->q.qlen--; -			sch->qstats.drops++; -		} -	} -	qdisc_run(dev); -	spin_unlock_bh(&dev->queue_lock); +	pr_debug("netem_watchdog qlen=%d\n", sch->q.qlen); +	sch->flags &= ~TCQ_F_THROTTLED; +	netif_schedule(sch->dev);  }  static void netem_reset(struct Qdisc *sch) @@ -301,6 +331,7 @@ static void netem_reset(struct Qdisc *sch)  	skb_queue_purge(&q->delayed);  	sch->q.qlen = 0; +	sch->flags &= ~TCQ_F_THROTTLED;  	del_timer_sync(&q->timer);  } diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 544b75077dbd..334f61773e6d 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -125,6 +125,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,  		sp->autoclose * HZ;  	/* Use SCTP specific send buffer space queues.  */ +	ep->sndbuf_policy = sctp_sndbuf_policy;  	sk->sk_write_space = sctp_write_space;  	sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index e42c74e3ec1e..c9d9ea064734 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -496,9 +496,7 @@ static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port)  /* Is this a wildcard address? */  static int sctp_v6_is_any(const union sctp_addr *addr)  { -	int type; -	type = ipv6_addr_type((struct in6_addr *)&addr->v6.sin6_addr); -	return IPV6_ADDR_ANY == type; +	return ipv6_addr_any(&addr->v6.sin6_addr);  }  /* Should this be available for binding?   */ diff --git a/net/sctp/output.c b/net/sctp/output.c index 9013f64f5219..84b5b370b09d 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -313,12 +313,12 @@ int sctp_packet_transmit(struct sctp_packet *packet)  	sk = chunk->skb->sk;  	/* Allocate the new skb.  */ -	nskb = dev_alloc_skb(packet->size); +	nskb = alloc_skb(packet->size + LL_MAX_HEADER, GFP_ATOMIC);  	if (!nskb)  		goto nomem;  	/* Make sure the outbound skb has enough header room reserved. */ -	skb_reserve(nskb, packet->overhead); +	skb_reserve(nskb, packet->overhead + LL_MAX_HEADER);  	/* Set the owning socket so that we know where to get the  	 * destination IP address. diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index b9813cf3d91c..2e1f9c3556f5 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1043,6 +1043,9 @@ SCTP_STATIC __init int sctp_init(void)  	sctp_max_retrans_path		= 5;  	sctp_max_retrans_init		= 8; +	/* Sendbuffer growth	    - do per-socket accounting */ +	sctp_sndbuf_policy		= 0; +  	/* HB.interval              - 30 seconds */  	sctp_hb_interval		= 30 * HZ; @@ -1159,8 +1162,6 @@ SCTP_STATIC __init int sctp_init(void)  	status = 0;  out:  	return status; -err_add_protocol: -	proto_unregister(&sctp_prot);  err_ctl_sock_init:  	sctp_v6_exit();  err_v6_init: @@ -1188,6 +1189,8 @@ err_bucket_cachep:  	inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);  	inet_unregister_protosw(&sctp_seqpacket_protosw);  	inet_unregister_protosw(&sctp_stream_protosw); +err_add_protocol: +	proto_unregister(&sctp_prot);  	goto out;  } diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 1db12cc18cf7..33ac8bf47b0e 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -710,7 +710,9 @@ struct sctp_chunk *sctp_make_shutdown_complete(  	struct sctp_chunk *retval;  	__u8 flags = 0; -	/* Maybe set the T-bit if we have no association. */ +	/* Set the T-bit if we have no association (vtag will be +	 * reflected) +	 */  	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T;  	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_COMPLETE, flags, 0); @@ -732,7 +734,7 @@ struct sctp_chunk *sctp_make_shutdown_complete(  }  /* Create an ABORT.  Note that we set the T bit if we have no - * association. + * association, except when responding to an INIT (sctpimpguide 2.41).   */  struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,  			      const struct sctp_chunk *chunk, @@ -741,8 +743,16 @@ struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,  	struct sctp_chunk *retval;  	__u8 flags = 0; -	/* Maybe set the T-bit if we have no association.  */ -	flags |= asoc ? 0 : SCTP_CHUNK_FLAG_T; +	/* Set the T-bit if we have no association and 'chunk' is not +	 * an INIT (vtag will be reflected). +	 */ +	if (!asoc) { +		if (chunk && chunk->chunk_hdr && +		    chunk->chunk_hdr->type == SCTP_CID_INIT) +			flags = 0; +		else +			flags = SCTP_CHUNK_FLAG_T; +	}  	retval = sctp_make_chunk(asoc, SCTP_CID_ABORT, flags, hint); @@ -2744,7 +2754,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,  	hint = (nstreams + 1) * sizeof(__u32); -	/* Maybe set the T-bit if we have no association.  */  	retval = sctp_make_chunk(asoc, SCTP_CID_FWD_TSN, 0, hint);  	if (!retval) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 278c56a2d076..8e01b8f09ac2 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -126,15 +126,18 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk,   * should stop the T2-shutdown timer and remove all knowledge of the   * association (and thus the association enters the CLOSED state).   * - * Verification Tag: 8.5.1(C) + * Verification Tag: 8.5.1(C), sctpimpguide 2.41.   * C) Rules for packet carrying SHUTDOWN COMPLETE:   * ... - * - The receiver of a SHUTDOWN COMPLETE shall accept the packet if the - *   Verification Tag field of the packet matches its own tag OR it is - *   set to its peer's tag and the T bit is set in the Chunk Flags. - *   Otherwise, the receiver MUST silently discard the packet and take - *   no further action. An endpoint MUST ignore the SHUTDOWN COMPLETE if - *   it is not in the SHUTDOWN-ACK-SENT state. + * - The receiver of a SHUTDOWN COMPLETE shall accept the packet + *   if the Verification Tag field of the packet matches its own tag and + *   the T bit is not set + *   OR + *   it is set to its peer's tag and the T bit is set in the Chunk + *   Flags. + *   Otherwise, the receiver MUST silently discard the packet + *   and take no further action.  An endpoint MUST ignore the + *   SHUTDOWN COMPLETE if it is not in the SHUTDOWN-ACK-SENT state.   *   * Inputs   * (endpoint, asoc, chunk) @@ -2858,16 +2861,16 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,  /*   * Generate an ABORT in response to a packet.   * - * Section: 8.4 Handle "Out of the blue" Packets + * Section: 8.4 Handle "Out of the blue" Packets, sctpimpguide 2.41   * - * 8) The receiver should respond to the sender of the OOTB packet - *    with an ABORT.  When sending the ABORT, the receiver of the - *    OOTB packet MUST fill in the Verification Tag field of the - *    outbound packet with the value found in the Verification Tag - *    field of the OOTB packet and set the T-bit in the Chunk Flags - *    to indicate that no TCB was found.  After sending this ABORT, - *    the receiver of the OOTB packet shall discard the OOTB packet - *    and take no further action. + * 8) The receiver should respond to the sender of the OOTB packet with + *    an ABORT.  When sending the ABORT, the receiver of the OOTB packet + *    MUST fill in the Verification Tag field of the outbound packet + *    with the value found in the Verification Tag field of the OOTB + *    packet and set the T-bit in the Chunk Flags to indicate that the + *    Verification Tag is reflected.  After sending this ABORT, the + *    receiver of the OOTB packet shall discard the OOTB packet and take + *    no further action.   *   * Verification Tag:   * @@ -2895,6 +2898,10 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,  			return SCTP_DISPOSITION_NOMEM;  		} +		/* Reflect vtag if T-Bit is set */ +		if (sctp_test_T_bit(abort)) +			packet->vtag = ntohl(chunk->sctp_hdr->vtag); +  		/* Set the skb to the belonging sock for accounting.  */  		abort->skb->sk = ep->base.sk; @@ -3026,22 +3033,24 @@ nomem:  }  /* - * RFC 2960, 8.4 - Handle "Out of the blue" Packets + * RFC 2960, 8.4 - Handle "Out of the blue" Packets, sctpimpguide 2.41. + *   * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should   *    respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE.   *    When sending the SHUTDOWN COMPLETE, the receiver of the OOTB   *    packet must fill in the Verification Tag field of the outbound   *    packet with the Verification Tag received in the SHUTDOWN ACK and - *    set the T-bit in the Chunk Flags to indicate that no TCB was - *    found. Otherwise, + *    set the T-bit in the Chunk Flags to indicate that the Verification + *    Tag is reflected.   *   * 8) The receiver should respond to the sender of the OOTB packet with   *    an ABORT.  When sending the ABORT, the receiver of the OOTB packet   *    MUST fill in the Verification Tag field of the outbound packet   *    with the value found in the Verification Tag field of the OOTB - *    packet and set the T-bit in the Chunk Flags to indicate that no - *    TCB was found.  After sending this ABORT, the receiver of the OOTB - *    packet shall discard the OOTB packet and take no further action. + *    packet and set the T-bit in the Chunk Flags to indicate that the + *    Verification Tag is reflected.  After sending this ABORT, the + *    receiver of the OOTB packet shall discard the OOTB packet and take + *    no further action.   */  sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,  				const struct sctp_association *asoc, @@ -3090,13 +3099,15 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,  /*   * Handle an "Out of the blue" SHUTDOWN ACK.   * - * Section: 8.4 5) + * Section: 8.4 5, sctpimpguide 2.41. + *   * 5) If the packet contains a SHUTDOWN ACK chunk, the receiver should - *   respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. - *   When sending the SHUTDOWN COMPLETE, the receiver of the OOTB packet - *   must fill in the Verification Tag field of the outbound packet with - *   the Verification Tag received in the SHUTDOWN ACK and set the - *   T-bit in the Chunk Flags to indicate that no TCB was found. + *    respond to the sender of the OOTB packet with a SHUTDOWN COMPLETE. + *    When sending the SHUTDOWN COMPLETE, the receiver of the OOTB + *    packet must fill in the Verification Tag field of the outbound + *    packet with the Verification Tag received in the SHUTDOWN ACK and + *    set the T-bit in the Chunk Flags to indicate that the Verification + *    Tag is reflected.   *   * Inputs   * (endpoint, asoc, type, arg, commands) @@ -3128,6 +3139,10 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,  			return SCTP_DISPOSITION_NOMEM;  		} +		/* Reflect vtag if T-Bit is set */ +		if (sctp_test_T_bit(shut)) +			packet->vtag = ntohl(chunk->sctp_hdr->vtag); +  		/* Set the skb to the belonging sock for accounting.  */  		shut->skb->sk = ep->base.sk; @@ -3591,7 +3606,6 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,   *   * 2) If the OOTB packet contains an ABORT chunk, the receiver MUST   *    silently discard the OOTB packet and take no further action. - *    Otherwise,   *   * Verification Tag: No verification necessary   * @@ -4961,6 +4975,11 @@ static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,  			sctp_ootb_pkt_free(packet);  			return NULL;  		} + +		/* Reflect vtag if T-Bit is set */ +		if (sctp_test_T_bit(abort)) +			packet->vtag = ntohl(chunk->sctp_hdr->vtag); +  		/* Add specified error causes, i.e., payload, to the  		 * end of the chunk.  		 */ diff --git a/net/sctp/socket.c b/net/sctp/socket.c index e8c210182571..0b338eca6dc0 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -115,9 +115,17 @@ static inline int sctp_wspace(struct sctp_association *asoc)  	struct sock *sk = asoc->base.sk;  	int amt = 0; -	amt = sk->sk_sndbuf - asoc->sndbuf_used; +	if (asoc->ep->sndbuf_policy) { +		/* make sure that no association uses more than sk_sndbuf */ +		amt = sk->sk_sndbuf - asoc->sndbuf_used; +	} else { +		/* do socket level accounting */ +		amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); +	} +  	if (amt < 0)  		amt = 0; +  	return amt;  } @@ -138,12 +146,21 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)  	/* The sndbuf space is tracked per association.  */  	sctp_association_hold(asoc); +	skb_set_owner_w(chunk->skb, sk); +  	chunk->skb->destructor = sctp_wfree;  	/* Save the chunk pointer in skb for sctp_wfree to use later.  */  	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk; -	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); -	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); +	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk) + +				sizeof(struct sk_buff) + +				sizeof(struct sctp_chunk); + +	sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk) + +				sizeof(struct sk_buff) + +				sizeof(struct sctp_chunk); + +	atomic_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);  }  /* Verify that this is a valid address. */ @@ -3473,7 +3490,7 @@ static int sctp_getsockopt_associnfo(struct sock *sk, int len,  		return -EINVAL;  	/* Values correspoinding to the specific association */ -	if (assocparams.sasoc_assoc_id != 0) { +	if (asoc) {  		assocparams.sasoc_asocmaxrxt = asoc->max_retrans;  		assocparams.sasoc_peer_rwnd = asoc->peer.rwnd;  		assocparams.sasoc_local_rwnd = asoc->a_rwnd; @@ -4422,8 +4439,17 @@ static void sctp_wfree(struct sk_buff *skb)  	chunk = *((struct sctp_chunk **)(skb->cb));  	asoc = chunk->asoc;  	sk = asoc->base.sk; -	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); -	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); +	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk) + +				sizeof(struct sk_buff) + +				sizeof(struct sctp_chunk); + +	sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk) + +				sizeof(struct sk_buff) + +				sizeof(struct sctp_chunk); + +	atomic_sub(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc); + +	sock_wfree(skb);  	__sctp_write_space(asoc);  	sctp_association_put(asoc); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 89fa20c73a5c..7fc31849312b 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -110,6 +110,14 @@ static ctl_table sctp_table[] = {  		.proc_handler	= &proc_dointvec  	},  	{ +		.ctl_name	= NET_SCTP_SNDBUF_POLICY, +		.procname	= "sndbuf_policy", +		.data		= &sctp_sndbuf_policy, +		.maxlen		= sizeof(int), +		.mode		= 0644, +		.proc_handler	= &proc_dointvec +	}, +	{  		.ctl_name	= NET_SCTP_PATH_MAX_RETRANS,  		.procname	= "path_max_retrans",  		.data		= &sctp_max_retrans_path, diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c index 4484931018eb..67b9f035ba86 100644 --- a/net/sunrpc/xdr.c +++ b/net/sunrpc/xdr.c @@ -46,9 +46,9 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)  /**   * xdr_encode_opaque_fixed - Encode fixed length opaque data - * @p - pointer to current position in XDR buffer. - * @ptr - pointer to data to encode (or NULL) - * @nbytes - size of data. + * @p: pointer to current position in XDR buffer. + * @ptr: pointer to data to encode (or NULL) + * @nbytes: size of data.   *   * Copy the array of data of length nbytes at ptr to the XDR buffer   * at position p, then align to the next 32-bit boundary by padding @@ -76,9 +76,9 @@ EXPORT_SYMBOL(xdr_encode_opaque_fixed);  /**   * xdr_encode_opaque - Encode variable length opaque data - * @p - pointer to current position in XDR buffer. - * @ptr - pointer to data to encode (or NULL) - * @nbytes - size of data. + * @p: pointer to current position in XDR buffer. + * @ptr: pointer to data to encode (or NULL) + * @nbytes: size of data.   *   * Returns the updated current XDR buffer position   */ diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 956c17f6c548..d6844ac226f5 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -48,8 +48,8 @@  #include <linux/kernel.h>  #include <linux/init.h>  #include <linux/module.h>	/* support for loadable modules */ -#include <linux/slab.h>	/* kmalloc(), kfree() */ -#include <linux/mm.h>		/* verify_area(), etc. */ +#include <linux/slab.h>		/* kmalloc(), kfree() */ +#include <linux/mm.h>  #include <linux/string.h>	/* inline mem*, str* functions */  #include <asm/byteorder.h>	/* htons(), etc. */ diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 80828078733d..55ed979db144 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1028,30 +1028,15 @@ static int stale_bundle(struct dst_entry *dst)  	return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC);  } -static void xfrm_dst_destroy(struct dst_entry *dst) +void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)  { -	struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - -	dst_release(xdst->route); - -	if (!dst->xfrm) -		return; -	xfrm_state_put(dst->xfrm); -	dst->xfrm = NULL; -} - -static void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev, -			    int unregister) -{ -	if (!unregister) -		return; -  	while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {  		dst->dev = &loopback_dev;  		dev_hold(&loopback_dev);  		dev_put(dev);  	}  } +EXPORT_SYMBOL(xfrm_dst_ifdown);  static void xfrm_link_failure(struct sk_buff *skb)  { @@ -1262,10 +1247,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)  			dst_ops->kmem_cachep = xfrm_dst_cache;  		if (likely(dst_ops->check == NULL))  			dst_ops->check = xfrm_dst_check; -		if (likely(dst_ops->destroy == NULL)) -			dst_ops->destroy = xfrm_dst_destroy; -		if (likely(dst_ops->ifdown == NULL)) -			dst_ops->ifdown = xfrm_dst_ifdown;  		if (likely(dst_ops->negative_advice == NULL))  			dst_ops->negative_advice = xfrm_negative_advice;  		if (likely(dst_ops->link_failure == NULL)) @@ -1297,8 +1278,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)  			xfrm_policy_afinfo[afinfo->family] = NULL;  			dst_ops->kmem_cachep = NULL;  			dst_ops->check = NULL; -			dst_ops->destroy = NULL; -			dst_ops->ifdown = NULL;  			dst_ops->negative_advice = NULL;  			dst_ops->link_failure = NULL;  			dst_ops->get_mss = NULL; diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 63661b0fd736..5ddda2c98af9 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -855,47 +855,44 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **x  	return 0;  } -static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = { -	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* NEW SA */ -	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* DEL SA */ -	NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)),	/* GET SA */ -	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* NEW POLICY */ -	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* DEL POLICY */ -	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)),  /* GET POLICY */ -	NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)),	/* ALLOC SPI */ -	NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)),	/* ACQUIRE */ -	NLMSG_LENGTH(sizeof(struct xfrm_user_expire)),	/* EXPIRE */ -	NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* UPD POLICY */ -	NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)),	/* UPD SA */ -	NLMSG_LENGTH(sizeof(struct xfrm_user_polexpire)), /* POLEXPIRE */ -	NLMSG_LENGTH(sizeof(struct xfrm_usersa_flush)),	/* FLUSH SA */ -	NLMSG_LENGTH(0),				/* FLUSH POLICY */ +#define XMSGSIZE(type) NLMSG_LENGTH(sizeof(struct type)) + +static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { +	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), +	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), +	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), +	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), +	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), +	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), +	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), +	[XFRM_MSG_ACQUIRE     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), +	[XFRM_MSG_EXPIRE      - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), +	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), +	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), +	[XFRM_MSG_POLEXPIRE   - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), +	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), +	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = NLMSG_LENGTH(0),  }; +#undef XMSGSIZE +  static struct xfrm_link {  	int (*doit)(struct sk_buff *, struct nlmsghdr *, void **);  	int (*dump)(struct sk_buff *, struct netlink_callback *); -} xfrm_dispatch[] = { -	{	.doit	=	xfrm_add_sa, 		}, -	{	.doit	=	xfrm_del_sa, 		}, -	{ -		.doit	=	xfrm_get_sa, -		.dump	=	xfrm_dump_sa, -	}, -	{	.doit	=	xfrm_add_policy 	}, -	{	.doit	=	xfrm_get_policy 	}, -	{ -		.doit	=	xfrm_get_policy, -		.dump	=	xfrm_dump_policy, -	}, -	{	.doit	=	xfrm_alloc_userspi	}, -	{}, -	{}, -	{	.doit	=	xfrm_add_policy 	}, -	{	.doit	=	xfrm_add_sa, 		}, -	{}, -	{	.doit	=	xfrm_flush_sa		}, -	{	.doit	=	xfrm_flush_policy	}, +} xfrm_dispatch[XFRM_NR_MSGTYPES] = { +	[XFRM_MSG_NEWSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        }, +	[XFRM_MSG_DELSA       - XFRM_MSG_BASE] = { .doit = xfrm_del_sa        }, +	[XFRM_MSG_GETSA       - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, +						   .dump = xfrm_dump_sa       }, +	[XFRM_MSG_NEWPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    }, +	[XFRM_MSG_DELPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy    }, +	[XFRM_MSG_GETPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, +						   .dump = xfrm_dump_policy   }, +	[XFRM_MSG_ALLOCSPI    - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, +	[XFRM_MSG_UPDPOLICY   - XFRM_MSG_BASE] = { .doit = xfrm_add_policy    }, +	[XFRM_MSG_UPDSA       - XFRM_MSG_BASE] = { .doit = xfrm_add_sa        }, +	[XFRM_MSG_FLUSHSA     - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa      }, +	[XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy  },  };  static int xfrm_done(struct netlink_callback *cb) @@ -931,7 +928,9 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *err  		return -1;  	} -	if ((type == 2 || type == 5) && (nlh->nlmsg_flags & NLM_F_DUMP)) { +	if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || +	     type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && +	    (nlh->nlmsg_flags & NLM_F_DUMP)) {  		u32 rlen;  		if (link->dump == NULL) @@ -1009,18 +1008,26 @@ static int xfrm_user_rcv_skb(struct sk_buff *skb)  static void xfrm_netlink_rcv(struct sock *sk, int len)  { +	unsigned int qlen = skb_queue_len(&sk->sk_receive_queue); +  	do {  		struct sk_buff *skb;  		down(&xfrm_cfg_sem); -		while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { +		if (qlen > skb_queue_len(&sk->sk_receive_queue)) +			qlen = skb_queue_len(&sk->sk_receive_queue); + +		for (; qlen; qlen--) { +			skb = skb_dequeue(&sk->sk_receive_queue);  			if (xfrm_user_rcv_skb(skb)) {  				if (skb->len)  					skb_queue_head(&sk->sk_receive_queue,  						       skb); -				else +				else {  					kfree_skb(skb); +					qlen--; +				}  				break;  			}  			kfree_skb(skb); @@ -1028,7 +1035,7 @@ static void xfrm_netlink_rcv(struct sock *sk, int len)  		up(&xfrm_cfg_sem); -	} while (xfrm_nl && xfrm_nl->sk_receive_queue.qlen); +	} while (qlen);  }  static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) | 
