diff options
Diffstat (limited to 'net/rxrpc')
| -rw-r--r-- | net/rxrpc/Kconfig | 2 | ||||
| -rw-r--r-- | net/rxrpc/Makefile | 5 | ||||
| -rw-r--r-- | net/rxrpc/af_rxrpc.c | 32 | ||||
| -rw-r--r-- | net/rxrpc/ar-ack.c | 102 | ||||
| -rw-r--r-- | net/rxrpc/ar-call.c | 213 | ||||
| -rw-r--r-- | net/rxrpc/ar-connection.c | 12 | ||||
| -rw-r--r-- | net/rxrpc/ar-connevent.c | 3 | ||||
| -rw-r--r-- | net/rxrpc/ar-error.c | 10 | ||||
| -rw-r--r-- | net/rxrpc/ar-input.c | 199 | ||||
| -rw-r--r-- | net/rxrpc/ar-internal.h | 206 | ||||
| -rw-r--r-- | net/rxrpc/ar-key.c | 107 | ||||
| -rw-r--r-- | net/rxrpc/ar-output.c | 26 | ||||
| -rw-r--r-- | net/rxrpc/ar-peer.c | 34 | ||||
| -rw-r--r-- | net/rxrpc/ar-recvmsg.c | 30 | ||||
| -rw-r--r-- | net/rxrpc/ar-skbuff.c | 7 | ||||
| -rw-r--r-- | net/rxrpc/ar-transport.c | 13 | ||||
| -rw-r--r-- | net/rxrpc/rxkad.c | 6 | ||||
| -rw-r--r-- | net/rxrpc/sysctl.c | 146 | 
18 files changed, 777 insertions, 376 deletions
diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig index 0d3103c4f11..23dcef12b98 100644 --- a/net/rxrpc/Kconfig +++ b/net/rxrpc/Kconfig @@ -4,7 +4,7 @@  config AF_RXRPC  	tristate "RxRPC session sockets" -	depends on INET && EXPERIMENTAL +	depends on INET  	select CRYPTO  	select KEYS  	help diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile index d1c3429b69e..ec126f91276 100644 --- a/net/rxrpc/Makefile +++ b/net/rxrpc/Makefile @@ -20,9 +20,8 @@ af-rxrpc-y := \  	ar-skbuff.o \  	ar-transport.o -ifeq ($(CONFIG_PROC_FS),y) -af-rxrpc-y += ar-proc.o -endif +af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o +af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o  obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 0b9bb2085ce..7b167048963 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -10,6 +10,7 @@   */  #include <linux/module.h> +#include <linux/kernel.h>  #include <linux/net.h>  #include <linux/slab.h>  #include <linux/skbuff.h> @@ -26,7 +27,7 @@ MODULE_AUTHOR("Red Hat, Inc.");  MODULE_LICENSE("GPL");  MODULE_ALIAS_NETPROTO(PF_RXRPC); -unsigned rxrpc_debug; // = RXRPC_DEBUG_KPROTO; +unsigned int rxrpc_debug; // = RXRPC_DEBUG_KPROTO;  module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);  MODULE_PARM_DESC(debug, "RxRPC debugging mask"); @@ -513,7 +514,7 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,  			    char __user *optval, unsigned int optlen)  {  	struct rxrpc_sock *rx = rxrpc_sk(sock->sk); -	unsigned min_sec_level; +	unsigned int min_sec_level;  	int ret;  	_enter(",%d,%d,,%d", level, optname, optlen); @@ -555,13 +556,13 @@ static int rxrpc_setsockopt(struct socket *sock, int level, int optname,  		case RXRPC_MIN_SECURITY_LEVEL:  			ret = -EINVAL; -			if (optlen != sizeof(unsigned)) +			if (optlen != sizeof(unsigned int))  				goto error;  			ret = -EISCONN;  			if (rx->sk.sk_state != RXRPC_UNCONNECTED)  				goto error;  			ret = get_user(min_sec_level, -				       (unsigned __user *) optval); +				       (unsigned int __user *) optval);  			if (ret < 0)  				goto error;  			ret = -EINVAL; @@ -792,10 +793,9 @@ static const struct net_proto_family rxrpc_family_ops = {   */  static int __init af_rxrpc_init(void)  { -	struct sk_buff *dummy_skb;  	int ret = -1; -	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof(dummy_skb->cb)); +	BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > FIELD_SIZEOF(struct sk_buff, cb));  	rxrpc_epoch = htonl(get_seconds()); @@ -808,7 +808,7 @@ static int __init af_rxrpc_init(void)  		goto error_call_jar;  	} -	rxrpc_workqueue = create_workqueue("krxrpcd"); +	rxrpc_workqueue = alloc_workqueue("krxrpcd", 0, 1);  	if (!rxrpc_workqueue) {  		printk(KERN_NOTICE "RxRPC: Failed to allocate work queue\n");  		goto error_work_queue; @@ -838,12 +838,21 @@ static int __init af_rxrpc_init(void)  		goto error_key_type_s;  	} +	ret = rxrpc_sysctl_init(); +	if (ret < 0) { +		printk(KERN_CRIT "RxRPC: Cannot register sysctls\n"); +		goto error_sysctls; +	} +  #ifdef CONFIG_PROC_FS -	proc_net_fops_create(&init_net, "rxrpc_calls", 0, &rxrpc_call_seq_fops); -	proc_net_fops_create(&init_net, "rxrpc_conns", 0, &rxrpc_connection_seq_fops); +	proc_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops); +	proc_create("rxrpc_conns", 0, init_net.proc_net, +		    &rxrpc_connection_seq_fops);  #endif  	return 0; +error_sysctls: +	unregister_key_type(&key_type_rxrpc_s);  error_key_type_s:  	unregister_key_type(&key_type_rxrpc);  error_key_type: @@ -864,6 +873,7 @@ error_call_jar:  static void __exit af_rxrpc_exit(void)  {  	_enter(""); +	rxrpc_sysctl_exit();  	unregister_key_type(&key_type_rxrpc_s);  	unregister_key_type(&key_type_rxrpc);  	sock_unregister(PF_RXRPC); @@ -878,8 +888,8 @@ static void __exit af_rxrpc_exit(void)  	_debug("flush scheduled work");  	flush_workqueue(rxrpc_workqueue); -	proc_net_remove(&init_net, "rxrpc_conns"); -	proc_net_remove(&init_net, "rxrpc_calls"); +	remove_proc_entry("rxrpc_conns", init_net.proc_net); +	remove_proc_entry("rxrpc_calls", init_net.proc_net);  	destroy_workqueue(rxrpc_workqueue);  	kmem_cache_destroy(rxrpc_call_jar);  	_leave(""); diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index b6ffe4e1b84..c6be17a959a 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -19,12 +19,61 @@  #include <net/af_rxrpc.h>  #include "ar-internal.h" -static unsigned rxrpc_ack_defer = 1; +/* + * How long to wait before scheduling ACK generation after seeing a + * packet with RXRPC_REQUEST_ACK set (in jiffies). + */ +unsigned rxrpc_requested_ack_delay = 1; -static const char *const rxrpc_acks[] = { -	"---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", "IDL", -	"-?-" -}; +/* + * How long to wait before scheduling an ACK with subtype DELAY (in jiffies). + * + * We use this when we've received new data packets.  If those packets aren't + * all consumed within this time we will send a DELAY ACK if an ACK was not + * requested to let the sender know it doesn't need to resend. + */ +unsigned rxrpc_soft_ack_delay = 1 * HZ; + +/* + * How long to wait before scheduling an ACK with subtype IDLE (in jiffies). + * + * We use this when we've consumed some previously soft-ACK'd packets when + * further packets aren't immediately received to decide when to send an IDLE + * ACK let the other end know that it can free up its Tx buffer space. + */ +unsigned rxrpc_idle_ack_delay = 0.5 * HZ; + +/* + * Receive window size in packets.  This indicates the maximum number of + * unconsumed received packets we're willing to retain in memory.  Once this + * limit is hit, we should generate an EXCEEDS_WINDOW ACK and discard further + * packets. + */ +unsigned rxrpc_rx_window_size = 32; + +/* + * Maximum Rx MTU size.  This indicates to the sender the size of jumbo packet + * made by gluing normal packets together that we're willing to handle. + */ +unsigned rxrpc_rx_mtu = 5692; + +/* + * The maximum number of fragments in a received jumbo packet that we tell the + * sender that we're willing to handle. + */ +unsigned rxrpc_rx_jumbo_max = 4; + +static const char *rxrpc_acks(u8 reason) +{ +	static const char *const str[] = { +		"---", "REQ", "DUP", "OOS", "WIN", "MEM", "PNG", "PNR", "DLY", +		"IDL", "-?-" +	}; + +	if (reason >= ARRAY_SIZE(str)) +		reason = ARRAY_SIZE(str) - 1; +	return str[reason]; +}  static const s8 rxrpc_ack_priority[] = {  	[0]				= 0, @@ -50,7 +99,7 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,  	ASSERTCMP(prior, >, 0);  	_enter("{%d},%s,%%%x,%u", -	       call->debug_id, rxrpc_acks[ack_reason], ntohl(serial), +	       call->debug_id, rxrpc_acks(ack_reason), ntohl(serial),  	       immediate);  	if (prior < rxrpc_ack_priority[call->ackr_reason]) { @@ -75,24 +124,23 @@ void __rxrpc_propose_ACK(struct rxrpc_call *call, u8 ack_reason,  	switch (ack_reason) {  	case RXRPC_ACK_DELAY:  		_debug("run delay timer"); -		call->ack_timer.expires = jiffies + rxrpc_ack_timeout * HZ; -		add_timer(&call->ack_timer); -		return; +		expiry = rxrpc_soft_ack_delay; +		goto run_timer;  	case RXRPC_ACK_IDLE:  		if (!immediate) {  			_debug("run defer timer"); -			expiry = 1; +			expiry = rxrpc_idle_ack_delay;  			goto run_timer;  		}  		goto cancel_timer;  	case RXRPC_ACK_REQUESTED: -		if (!rxrpc_ack_defer) +		expiry = rxrpc_requested_ack_delay; +		if (!expiry)  			goto cancel_timer;  		if (!immediate || serial == cpu_to_be32(1)) {  			_debug("run defer timer"); -			expiry = rxrpc_ack_defer;  			goto run_timer;  		} @@ -195,7 +243,7 @@ static void rxrpc_resend(struct rxrpc_call *call)  		sp = rxrpc_skb(txb);  		if (sp->need_resend) { -			sp->need_resend = 0; +			sp->need_resend = false;  			/* each Tx packet has a new serial number */  			sp->hdr.serial = @@ -216,7 +264,7 @@ static void rxrpc_resend(struct rxrpc_call *call)  		}  		if (time_after_eq(jiffies + 1, sp->resend_at)) { -			sp->need_resend = 1; +			sp->need_resend = true;  			resend |= 1;  		} else if (resend & 2) {  			if (time_before(sp->resend_at, resend_at)) @@ -265,7 +313,7 @@ static void rxrpc_resend_timer(struct rxrpc_call *call)  		if (sp->need_resend) {  			;  		} else if (time_after_eq(jiffies + 1, sp->resend_at)) { -			sp->need_resend = 1; +			sp->need_resend = true;  			resend |= 1;  		} else if (resend & 2) {  			if (time_before(sp->resend_at, resend_at)) @@ -314,11 +362,11 @@ static int rxrpc_process_soft_ACKs(struct rxrpc_call *call,  		switch (sacks[loop]) {  		case RXRPC_ACK_TYPE_ACK: -			sp->need_resend = 0; +			sp->need_resend = false;  			*p_txb |= 1;  			break;  		case RXRPC_ACK_TYPE_NACK: -			sp->need_resend = 1; +			sp->need_resend = true;  			*p_txb &= ~1;  			resend = 1;  			break; @@ -344,13 +392,13 @@ static int rxrpc_process_soft_ACKs(struct rxrpc_call *call,  		if (*p_txb & 1) {  			/* packet must have been discarded */ -			sp->need_resend = 1; +			sp->need_resend = true;  			*p_txb &= ~1;  			resend |= 1;  		} else if (sp->need_resend) {  			;  		} else if (time_after_eq(jiffies + 1, sp->resend_at)) { -			sp->need_resend = 1; +			sp->need_resend = true;  			resend |= 1;  		} else if (resend & 2) {  			if (time_before(sp->resend_at, resend_at)) @@ -375,7 +423,6 @@ protocol_error:   */  static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard)  { -	struct rxrpc_skb_priv *sp;  	unsigned long _skb;  	int tail = call->acks_tail, old_tail;  	int win = CIRC_CNT(call->acks_head, tail, call->acks_winsz); @@ -387,7 +434,6 @@ static void rxrpc_rotate_tx_window(struct rxrpc_call *call, u32 hard)  	while (call->acks_hard < hard) {  		smp_read_barrier_depends();  		_skb = call->acks_window[tail] & ~1; -		sp = rxrpc_skb((struct sk_buff *) _skb);  		rxrpc_free_skb((struct sk_buff *) _skb);  		old_tail = tail;  		tail = (tail + 1) & (call->acks_winsz - 1); @@ -550,11 +596,11 @@ static void rxrpc_zap_tx_window(struct rxrpc_call *call)   * process the extra information that may be appended to an ACK packet   */  static void rxrpc_extract_ackinfo(struct rxrpc_call *call, struct sk_buff *skb, -				  unsigned latest, int nAcks) +				  unsigned int latest, int nAcks)  {  	struct rxrpc_ackinfo ackinfo;  	struct rxrpc_peer *peer; -	unsigned mtu; +	unsigned int mtu;  	if (skb_copy_bits(skb, nAcks + 3, &ackinfo, sizeof(ackinfo)) < 0) {  		_leave(" [no ackinfo]"); @@ -639,7 +685,7 @@ process_further:  		       hard,  		       ntohl(ack.previousPacket),  		       ntohl(ack.serial), -		       rxrpc_acks[ack.reason], +		       rxrpc_acks(ack.reason),  		       ack.nAcks);  		rxrpc_extract_ackinfo(call, skb, latest, ack.nAcks); @@ -1169,11 +1215,11 @@ send_ACK:  	mtu = call->conn->trans->peer->if_mtu;  	mtu -= call->conn->trans->peer->hdrsize;  	ackinfo.maxMTU	= htonl(mtu); -	ackinfo.rwind	= htonl(32); +	ackinfo.rwind	= htonl(rxrpc_rx_window_size);  	/* permit the peer to send us jumbo packets if it wants to */ -	ackinfo.rxMTU	= htonl(5692); -	ackinfo.jumbo_max = htonl(4); +	ackinfo.rxMTU	= htonl(rxrpc_rx_mtu); +	ackinfo.jumbo_max = htonl(rxrpc_rx_jumbo_max);  	hdr.serial = htonl(atomic_inc_return(&call->conn->serial));  	_proto("Tx ACK %%%u { m=%hu f=#%u p=#%u s=%%%u r=%s n=%u }", @@ -1182,7 +1228,7 @@ send_ACK:  	       ntohl(ack.firstPacket),  	       ntohl(ack.previousPacket),  	       ntohl(ack.serial), -	       rxrpc_acks[ack.reason], +	       rxrpc_acks(ack.reason),  	       ack.nAcks);  	del_timer_sync(&call->ack_timer); diff --git a/net/rxrpc/ar-call.c b/net/rxrpc/ar-call.c index bf656c230ba..a9e05db0f5d 100644 --- a/net/rxrpc/ar-call.c +++ b/net/rxrpc/ar-call.c @@ -12,10 +12,22 @@  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/circ_buf.h> +#include <linux/hashtable.h> +#include <linux/spinlock_types.h>  #include <net/sock.h>  #include <net/af_rxrpc.h>  #include "ar-internal.h" +/* + * Maximum lifetime of a call (in jiffies). + */ +unsigned rxrpc_max_call_lifetime = 60 * HZ; + +/* + * Time till dead call expires after last use (in jiffies). + */ +unsigned rxrpc_dead_call_expiry = 2 * HZ; +  const char *const rxrpc_call_states[] = {  	[RXRPC_CALL_CLIENT_SEND_REQUEST]	= "ClSndReq",  	[RXRPC_CALL_CLIENT_AWAIT_REPLY]		= "ClAwtRpl", @@ -38,8 +50,6 @@ const char *const rxrpc_call_states[] = {  struct kmem_cache *rxrpc_call_jar;  LIST_HEAD(rxrpc_calls);  DEFINE_RWLOCK(rxrpc_call_lock); -static unsigned rxrpc_call_max_lifetime = 60; -static unsigned rxrpc_dead_call_timeout = 2;  static void rxrpc_destroy_call(struct work_struct *work);  static void rxrpc_call_life_expired(unsigned long _call); @@ -47,6 +57,145 @@ static void rxrpc_dead_call_expired(unsigned long _call);  static void rxrpc_ack_time_expired(unsigned long _call);  static void rxrpc_resend_time_expired(unsigned long _call); +static DEFINE_SPINLOCK(rxrpc_call_hash_lock); +static DEFINE_HASHTABLE(rxrpc_call_hash, 10); + +/* + * Hash function for rxrpc_call_hash + */ +static unsigned long rxrpc_call_hashfunc( +	u8		clientflag, +	__be32		cid, +	__be32		call_id, +	__be32		epoch, +	__be16		service_id, +	sa_family_t	proto, +	void		*localptr, +	unsigned int	addr_size, +	const u8	*peer_addr) +{ +	const u16 *p; +	unsigned int i; +	unsigned long key; +	u32 hcid = ntohl(cid); + +	_enter(""); + +	key = (unsigned long)localptr; +	/* We just want to add up the __be32 values, so forcing the +	 * cast should be okay. +	 */ +	key += (__force u32)epoch; +	key += (__force u16)service_id; +	key += (__force u32)call_id; +	key += (hcid & RXRPC_CIDMASK) >> RXRPC_CIDSHIFT; +	key += hcid & RXRPC_CHANNELMASK; +	key += clientflag; +	key += proto; +	/* Step through the peer address in 16-bit portions for speed */ +	for (i = 0, p = (const u16 *)peer_addr; i < addr_size >> 1; i++, p++) +		key += *p; +	_leave(" key = 0x%lx", key); +	return key; +} + +/* + * Add a call to the hashtable + */ +static void rxrpc_call_hash_add(struct rxrpc_call *call) +{ +	unsigned long key; +	unsigned int addr_size = 0; + +	_enter(""); +	switch (call->proto) { +	case AF_INET: +		addr_size = sizeof(call->peer_ip.ipv4_addr); +		break; +	case AF_INET6: +		addr_size = sizeof(call->peer_ip.ipv6_addr); +		break; +	default: +		break; +	} +	key = rxrpc_call_hashfunc(call->in_clientflag, call->cid, +				  call->call_id, call->epoch, +				  call->service_id, call->proto, +				  call->conn->trans->local, addr_size, +				  call->peer_ip.ipv6_addr); +	/* Store the full key in the call */ +	call->hash_key = key; +	spin_lock(&rxrpc_call_hash_lock); +	hash_add_rcu(rxrpc_call_hash, &call->hash_node, key); +	spin_unlock(&rxrpc_call_hash_lock); +	_leave(""); +} + +/* + * Remove a call from the hashtable + */ +static void rxrpc_call_hash_del(struct rxrpc_call *call) +{ +	_enter(""); +	spin_lock(&rxrpc_call_hash_lock); +	hash_del_rcu(&call->hash_node); +	spin_unlock(&rxrpc_call_hash_lock); +	_leave(""); +} + +/* + * Find a call in the hashtable and return it, or NULL if it + * isn't there. + */ +struct rxrpc_call *rxrpc_find_call_hash( +	u8		clientflag, +	__be32		cid, +	__be32		call_id, +	__be32		epoch, +	__be16		service_id, +	void		*localptr, +	sa_family_t	proto, +	const u8	*peer_addr) +{ +	unsigned long key; +	unsigned int addr_size = 0; +	struct rxrpc_call *call = NULL; +	struct rxrpc_call *ret = NULL; + +	_enter(""); +	switch (proto) { +	case AF_INET: +		addr_size = sizeof(call->peer_ip.ipv4_addr); +		break; +	case AF_INET6: +		addr_size = sizeof(call->peer_ip.ipv6_addr); +		break; +	default: +		break; +	} + +	key = rxrpc_call_hashfunc(clientflag, cid, call_id, epoch, +				  service_id, proto, localptr, addr_size, +				  peer_addr); +	hash_for_each_possible_rcu(rxrpc_call_hash, call, hash_node, key) { +		if (call->hash_key == key && +		    call->call_id == call_id && +		    call->cid == cid && +		    call->in_clientflag == clientflag && +		    call->service_id == service_id && +		    call->proto == proto && +		    call->local == localptr && +		    memcmp(call->peer_ip.ipv6_addr, peer_addr, +			      addr_size) == 0 && +		    call->epoch == epoch) { +			ret = call; +			break; +		} +	} +	_leave(" = %p", ret); +	return ret; +} +  /*   * allocate a new call   */ @@ -91,7 +240,7 @@ static struct rxrpc_call *rxrpc_alloc_call(gfp_t gfp)  	call->rx_data_expect = 1;  	call->rx_data_eaten = 0;  	call->rx_first_oos = 0; -	call->ackr_win_top = call->rx_data_eaten + 1 + RXRPC_MAXACKS; +	call->ackr_win_top = call->rx_data_eaten + 1 + rxrpc_rx_window_size;  	call->creation_jif = jiffies;  	return call;  } @@ -128,11 +277,31 @@ static struct rxrpc_call *rxrpc_alloc_client_call(  		return ERR_PTR(ret);  	} +	/* Record copies of information for hashtable lookup */ +	call->proto = rx->proto; +	call->local = trans->local; +	switch (call->proto) { +	case AF_INET: +		call->peer_ip.ipv4_addr = +			trans->peer->srx.transport.sin.sin_addr.s_addr; +		break; +	case AF_INET6: +		memcpy(call->peer_ip.ipv6_addr, +		       trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8, +		       sizeof(call->peer_ip.ipv6_addr)); +		break; +	} +	call->epoch = call->conn->epoch; +	call->service_id = call->conn->service_id; +	call->in_clientflag = call->conn->in_clientflag; +	/* Add the new call to the hashtable */ +	rxrpc_call_hash_add(call); +  	spin_lock(&call->conn->trans->peer->lock);  	list_add(&call->error_link, &call->conn->trans->peer->error_targets);  	spin_unlock(&call->conn->trans->peer->lock); -	call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ; +	call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;  	add_timer(&call->lifetimer);  	_leave(" = %p", call); @@ -320,9 +489,12 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,  		parent = *p;  		call = rb_entry(parent, struct rxrpc_call, conn_node); -		if (call_id < call->call_id) +		/* The tree is sorted in order of the __be32 value without +		 * turning it into host order. +		 */ +		if ((__force u32)call_id < (__force u32)call->call_id)  			p = &(*p)->rb_left; -		else if (call_id > call->call_id) +		else if ((__force u32)call_id > (__force u32)call->call_id)  			p = &(*p)->rb_right;  		else  			goto old_call; @@ -347,9 +519,31 @@ struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *rx,  	list_add_tail(&call->link, &rxrpc_calls);  	write_unlock_bh(&rxrpc_call_lock); +	/* Record copies of information for hashtable lookup */ +	call->proto = rx->proto; +	call->local = conn->trans->local; +	switch (call->proto) { +	case AF_INET: +		call->peer_ip.ipv4_addr = +			conn->trans->peer->srx.transport.sin.sin_addr.s_addr; +		break; +	case AF_INET6: +		memcpy(call->peer_ip.ipv6_addr, +		       conn->trans->peer->srx.transport.sin6.sin6_addr.in6_u.u6_addr8, +		       sizeof(call->peer_ip.ipv6_addr)); +		break; +	default: +		break; +	} +	call->epoch = conn->epoch; +	call->service_id = conn->service_id; +	call->in_clientflag = conn->in_clientflag; +	/* Add the new call to the hashtable */ +	rxrpc_call_hash_add(call); +  	_net("CALL incoming %d on CONN %d", call->debug_id, call->conn->debug_id); -	call->lifetimer.expires = jiffies + rxrpc_call_max_lifetime * HZ; +	call->lifetimer.expires = jiffies + rxrpc_max_call_lifetime;  	add_timer(&call->lifetimer);  	_leave(" = %p {%d} [new]", call, call->debug_id);  	return call; @@ -533,7 +727,7 @@ void rxrpc_release_call(struct rxrpc_call *call)  	del_timer_sync(&call->resend_timer);  	del_timer_sync(&call->ack_timer);  	del_timer_sync(&call->lifetimer); -	call->deadspan.expires = jiffies + rxrpc_dead_call_timeout * HZ; +	call->deadspan.expires = jiffies + rxrpc_dead_call_expiry;  	add_timer(&call->deadspan);  	_leave(""); @@ -665,6 +859,9 @@ static void rxrpc_cleanup_call(struct rxrpc_call *call)  		rxrpc_put_connection(call->conn);  	} +	/* Remove the call from the hash */ +	rxrpc_call_hash_del(call); +  	if (call->acks_window) {  		_debug("kill Tx window %d",  		       CIRC_CNT(call->acks_head, call->acks_tail, diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 4106ca95ec8..6631f4f1e39 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c @@ -18,11 +18,15 @@  #include <net/af_rxrpc.h>  #include "ar-internal.h" +/* + * Time till a connection expires after last use (in seconds). + */ +unsigned rxrpc_connection_expiry = 10 * 60; +  static void rxrpc_connection_reaper(struct work_struct *work);  LIST_HEAD(rxrpc_connections);  DEFINE_RWLOCK(rxrpc_connection_lock); -static unsigned long rxrpc_connection_timeout = 10 * 60;  static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);  /* @@ -381,6 +385,8 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,  		rxrpc_assign_connection_id(conn);  		rx->conn = conn; +	} else { +		spin_lock(&trans->client_lock);  	}  	/* we've got a connection with a free channel and we can now attach the @@ -860,7 +866,7 @@ static void rxrpc_connection_reaper(struct work_struct *work)  		spin_lock(&conn->trans->client_lock);  		write_lock(&conn->trans->conn_lock); -		reap_time = conn->put_time + rxrpc_connection_timeout; +		reap_time = conn->put_time + rxrpc_connection_expiry;  		if (atomic_read(&conn->usage) > 0) {  			; @@ -914,7 +920,7 @@ void __exit rxrpc_destroy_all_connections(void)  {  	_enter(""); -	rxrpc_connection_timeout = 0; +	rxrpc_connection_expiry = 0;  	cancel_delayed_work(&rxrpc_connection_reap);  	rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0); diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c index 0505cdc4d6d..e7ed43a54c4 100644 --- a/net/rxrpc/ar-connevent.c +++ b/net/rxrpc/ar-connevent.c @@ -259,7 +259,6 @@ void rxrpc_process_connection(struct work_struct *work)  {  	struct rxrpc_connection *conn =  		container_of(work, struct rxrpc_connection, processor); -	struct rxrpc_skb_priv *sp;  	struct sk_buff *skb;  	u32 abort_code = RX_PROTOCOL_ERROR;  	int ret; @@ -276,8 +275,6 @@ void rxrpc_process_connection(struct work_struct *work)  	/* go through the conn-level event packets, releasing the ref on this  	 * connection that each one has when we've finished with it */  	while ((skb = skb_dequeue(&conn->rx_queue))) { -		sp = rxrpc_skb(skb); -  		ret = rxrpc_process_event(conn, skb, &abort_code);  		switch (ret) {  		case -EPROTO: diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c index d4d1ae26d29..db57458c824 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c @@ -81,12 +81,9 @@ void rxrpc_UDP_error_report(struct sock *sk)  			_net("I/F MTU %u", mtu);  		} -		/* ip_rt_frag_needed() may have eaten the info */ -		if (mtu == 0) -			mtu = ntohs(icmp_hdr(skb)->un.frag.mtu); -  		if (mtu == 0) {  			/* they didn't give us a size, estimate one */ +			mtu = peer->if_mtu;  			if (mtu > 1500) {  				mtu >>= 1;  				if (mtu < 1500) @@ -139,7 +136,7 @@ void rxrpc_UDP_error_handler(struct work_struct *work)  	struct rxrpc_transport *trans =  		container_of(work, struct rxrpc_transport, error_handler);  	struct sk_buff *skb; -	int local, err; +	int err;  	_enter(""); @@ -157,7 +154,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work)  	switch (ee->ee_origin) {  	case SO_EE_ORIGIN_ICMP: -		local = 0;  		switch (ee->ee_type) {  		case ICMP_DEST_UNREACH:  			switch (ee->ee_code) { @@ -207,7 +203,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work)  	case SO_EE_ORIGIN_LOCAL:  		_proto("Rx Received local error { error=%d }",  		       ee->ee_errno); -		local = 1;  		break;  	case SO_EE_ORIGIN_NONE: @@ -215,7 +210,6 @@ void rxrpc_UDP_error_handler(struct work_struct *work)  	default:  		_proto("Rx Received error report { orig=%u }",  		       ee->ee_origin); -		local = 0;  		break;  	} diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 89315009bab..63b21e580de 100644 --- a/net/rxrpc/ar-input.c +++ b/net/rxrpc/ar-input.c @@ -25,8 +25,6 @@  #include <net/net_namespace.h>  #include "ar-internal.h" -unsigned long rxrpc_ack_timeout = 1; -  const char *rxrpc_pkts[] = {  	"?00",  	"DATA", "ACK", "BUSY", "ABORT", "ACKALL", "CHALL", "RESP", "DEBUG", @@ -76,7 +74,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,  		 * --ANK */  //		ret = -ENOBUFS;  //		if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= -//		    (unsigned) sk->sk_rcvbuf) +//		    (unsigned int) sk->sk_rcvbuf)  //			goto out;  		ret = sk_filter(sk, skb); @@ -115,7 +113,7 @@ int rxrpc_queue_rcv_skb(struct rxrpc_call *call, struct sk_buff *skb,  			spin_unlock_bh(&sk->sk_receive_queue.lock);  			if (!sock_flag(sk, SOCK_DEAD)) -				sk->sk_data_ready(sk, skb_len); +				sk->sk_data_ready(sk);  		}  		skb = NULL;  	} else { @@ -349,8 +347,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)  	 * it */  	if (sp->hdr.flags & RXRPC_REQUEST_ACK) {  		_proto("ACK Requested on %%%u", serial); -		rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, -				  !(sp->hdr.flags & RXRPC_MORE_PACKETS)); +		rxrpc_propose_ACK(call, RXRPC_ACK_REQUESTED, sp->hdr.serial, false);  	}  	switch (sp->hdr.type) { @@ -423,6 +420,7 @@ void rxrpc_fast_process_packet(struct rxrpc_call *call, struct sk_buff *skb)  			goto protocol_error;  		} +	case RXRPC_PACKET_TYPE_ACKALL:  	case RXRPC_PACKET_TYPE_ACK:  		/* ACK processing is done in process context */  		read_lock_bh(&call->state_lock); @@ -525,36 +523,38 @@ protocol_error:   * post an incoming packet to the appropriate call/socket to deal with   * - must get rid of the sk_buff, either by freeing it or by queuing it   */ -static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn, +static void rxrpc_post_packet_to_call(struct rxrpc_call *call,  				      struct sk_buff *skb)  {  	struct rxrpc_skb_priv *sp; -	struct rxrpc_call *call; -	struct rb_node *p; -	__be32 call_id; - -	_enter("%p,%p", conn, skb); -	read_lock_bh(&conn->lock); +	_enter("%p,%p", call, skb);  	sp = rxrpc_skb(skb); -	/* look at extant calls by channel number first */ -	call = conn->channels[ntohl(sp->hdr.cid) & RXRPC_CHANNELMASK]; -	if (!call || call->call_id != sp->hdr.callNumber) -		goto call_not_extant; -  	_debug("extant call [%d]", call->state); -	ASSERTCMP(call->conn, ==, conn);  	read_lock(&call->state_lock);  	switch (call->state) {  	case RXRPC_CALL_LOCALLY_ABORTED: -		if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) +		if (!test_and_set_bit(RXRPC_CALL_ABORT, &call->events)) {  			rxrpc_queue_call(call); +			goto free_unlock; +		}  	case RXRPC_CALL_REMOTELY_ABORTED:  	case RXRPC_CALL_NETWORK_ERROR:  	case RXRPC_CALL_DEAD: +		goto dead_call; +	case RXRPC_CALL_COMPLETE: +	case RXRPC_CALL_CLIENT_FINAL_ACK: +		/* complete server call */ +		if (call->conn->in_clientflag) +			goto dead_call; +		/* resend last packet of a completed call */ +		_debug("final ack again"); +		rxrpc_get_call(call); +		set_bit(RXRPC_CALL_ACK_FINAL, &call->events); +		rxrpc_queue_call(call);  		goto free_unlock;  	default:  		break; @@ -562,7 +562,6 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,  	read_unlock(&call->state_lock);  	rxrpc_get_call(call); -	read_unlock_bh(&conn->lock);  	if (sp->hdr.type == RXRPC_PACKET_TYPE_DATA &&  	    sp->hdr.flags & RXRPC_JUMBO_PACKET) @@ -573,78 +572,16 @@ static void rxrpc_post_packet_to_call(struct rxrpc_connection *conn,  	rxrpc_put_call(call);  	goto done; -call_not_extant: -	/* search the completed calls in case what we're dealing with is -	 * there */ -	_debug("call not extant"); - -	call_id = sp->hdr.callNumber; -	p = conn->calls.rb_node; -	while (p) { -		call = rb_entry(p, struct rxrpc_call, conn_node); - -		if (call_id < call->call_id) -			p = p->rb_left; -		else if (call_id > call->call_id) -			p = p->rb_right; -		else -			goto found_completed_call; -	} -  dead_call: -	/* it's a either a really old call that we no longer remember or its a -	 * new incoming call */ -	read_unlock_bh(&conn->lock); - -	if (sp->hdr.flags & RXRPC_CLIENT_INITIATED && -	    sp->hdr.seq == cpu_to_be32(1)) { -		_debug("incoming call"); -		skb_queue_tail(&conn->trans->local->accept_queue, skb); -		rxrpc_queue_work(&conn->trans->local->acceptor); -		goto done; -	} - -	_debug("dead call"); -	skb->priority = RX_CALL_DEAD; -	rxrpc_reject_packet(conn->trans->local, skb); -	goto done; - -	/* resend last packet of a completed call -	 * - client calls may have been aborted or ACK'd -	 * - server calls may have been aborted -	 */ -found_completed_call: -	_debug("completed call"); - -	if (atomic_read(&call->usage) == 0) -		goto dead_call; - -	/* synchronise any state changes */ -	read_lock(&call->state_lock); -	ASSERTIFCMP(call->state != RXRPC_CALL_CLIENT_FINAL_ACK, -		    call->state, >=, RXRPC_CALL_COMPLETE); - -	if (call->state == RXRPC_CALL_LOCALLY_ABORTED || -	    call->state == RXRPC_CALL_REMOTELY_ABORTED || -	    call->state == RXRPC_CALL_DEAD) { -		read_unlock(&call->state_lock); -		goto dead_call; -	} - -	if (call->conn->in_clientflag) { -		read_unlock(&call->state_lock); -		goto dead_call; /* complete server call */ +	if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { +		skb->priority = RX_CALL_DEAD; +		rxrpc_reject_packet(call->conn->trans->local, skb); +		goto unlock;  	} - -	_debug("final ack again"); -	rxrpc_get_call(call); -	set_bit(RXRPC_CALL_ACK_FINAL, &call->events); -	rxrpc_queue_call(call); -  free_unlock: -	read_unlock(&call->state_lock); -	read_unlock_bh(&conn->lock);  	rxrpc_free_skb(skb); +unlock: +	read_unlock(&call->state_lock);  done:  	_leave("");  } @@ -663,21 +600,46 @@ static void rxrpc_post_packet_to_conn(struct rxrpc_connection *conn,  	rxrpc_queue_conn(conn);  } +static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local, +					       struct sk_buff *skb, +					       struct rxrpc_skb_priv *sp) +{ +	struct rxrpc_peer *peer; +	struct rxrpc_transport *trans; +	struct rxrpc_connection *conn; + +	peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, +				udp_hdr(skb)->source); +	if (IS_ERR(peer)) +		goto cant_find_conn; + +	trans = rxrpc_find_transport(local, peer); +	rxrpc_put_peer(peer); +	if (!trans) +		goto cant_find_conn; + +	conn = rxrpc_find_connection(trans, &sp->hdr); +	rxrpc_put_transport(trans); +	if (!conn) +		goto cant_find_conn; + +	return conn; +cant_find_conn: +	return NULL; +} +  /*   * handle data received on the local endpoint   * - may be called in interrupt context   */ -void rxrpc_data_ready(struct sock *sk, int count) +void rxrpc_data_ready(struct sock *sk)  { -	struct rxrpc_connection *conn; -	struct rxrpc_transport *trans;  	struct rxrpc_skb_priv *sp;  	struct rxrpc_local *local; -	struct rxrpc_peer *peer;  	struct sk_buff *skb;  	int ret; -	_enter("%p, %d", sk, count); +	_enter("%p", sk);  	ASSERT(!irqs_disabled()); @@ -748,27 +710,34 @@ void rxrpc_data_ready(struct sock *sk, int count)  	    (sp->hdr.callNumber == 0 || sp->hdr.seq == 0))  		goto bad_message; -	peer = rxrpc_find_peer(local, ip_hdr(skb)->saddr, udp_hdr(skb)->source); -	if (IS_ERR(peer)) -		goto cant_route_call; +	if (sp->hdr.callNumber == 0) { +		/* This is a connection-level packet. These should be +		 * fairly rare, so the extra overhead of looking them up the +		 * old-fashioned way doesn't really hurt */ +		struct rxrpc_connection *conn; -	trans = rxrpc_find_transport(local, peer); -	rxrpc_put_peer(peer); -	if (!trans) -		goto cant_route_call; +		conn = rxrpc_conn_from_local(local, skb, sp); +		if (!conn) +			goto cant_route_call; -	conn = rxrpc_find_connection(trans, &sp->hdr); -	rxrpc_put_transport(trans); -	if (!conn) -		goto cant_route_call; - -	_debug("CONN %p {%d}", conn, conn->debug_id); - -	if (sp->hdr.callNumber == 0) +		_debug("CONN %p {%d}", conn, conn->debug_id);  		rxrpc_post_packet_to_conn(conn, skb); -	else -		rxrpc_post_packet_to_call(conn, skb); -	rxrpc_put_connection(conn); +		rxrpc_put_connection(conn); +	} else { +		struct rxrpc_call *call; +		u8 in_clientflag = 0; + +		if (sp->hdr.flags & RXRPC_CLIENT_INITIATED) +			in_clientflag = RXRPC_CLIENT_INITIATED; +		call = rxrpc_find_call_hash(in_clientflag, sp->hdr.cid, +					    sp->hdr.callNumber, sp->hdr.epoch, +					    sp->hdr.serviceId, local, AF_INET, +					    (u8 *)&ip_hdr(skb)->saddr); +		if (call) +			rxrpc_post_packet_to_call(call, skb); +		else +			goto cant_route_call; +	}  	rxrpc_put_local(local);  	return; @@ -789,8 +758,10 @@ cant_route_call:  		skb->priority = RX_CALL_DEAD;  	} -	_debug("reject"); -	rxrpc_reject_packet(local, skb); +	if (sp->hdr.type != RXRPC_PACKET_TYPE_ABORT) { +		_debug("reject type %d",sp->hdr.type); +		rxrpc_reject_packet(local, skb); +	}  	rxrpc_put_local(local);  	_leave(" [no call]");  	return; diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 8e22bd345e7..ba9fd36d3f1 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -83,7 +83,7 @@ struct rxrpc_skb_priv {  	struct rxrpc_call	*call;		/* call with which associated */  	unsigned long		resend_at;	/* time in jiffies at which to resend */  	union { -		unsigned	offset;		/* offset into buffer of next read */ +		unsigned int	offset;		/* offset into buffer of next read */  		int		remain;		/* amount of space remaining for next write */  		u32		error;		/* network error code */  		bool		need_resend;	/* T if needs resending */ @@ -176,9 +176,9 @@ struct rxrpc_peer {  	struct list_head	error_targets;	/* targets for net error distribution */  	spinlock_t		lock;		/* access lock */  	atomic_t		usage; -	unsigned		if_mtu;		/* interface MTU for this peer */ -	unsigned		mtu;		/* network MTU for this peer */ -	unsigned		maxdata;	/* data size (MTU - hdrsize) */ +	unsigned int		if_mtu;		/* interface MTU for this peer */ +	unsigned int		mtu;		/* network MTU for this peer */ +	unsigned int		maxdata;	/* data size (MTU - hdrsize) */  	unsigned short		hdrsize;	/* header size (IP + UDP + RxRPC) */  	int			debug_id;	/* debug ID for printks */  	int			net_error;	/* network error distributed */ @@ -187,8 +187,8 @@ struct rxrpc_peer {  	/* calculated RTT cache */  #define RXRPC_RTT_CACHE_SIZE 32  	suseconds_t		rtt;		/* current RTT estimate (in uS) */ -	unsigned		rtt_point;	/* next entry at which to insert */ -	unsigned		rtt_usage;	/* amount of cache actually used */ +	unsigned int		rtt_point;	/* next entry at which to insert */ +	unsigned int		rtt_usage;	/* amount of cache actually used */  	suseconds_t		rtt_cache[RXRPC_RTT_CACHE_SIZE]; /* calculated RTT cache */  }; @@ -271,7 +271,7 @@ struct rxrpc_connection {  	} state;  	int			error;		/* error code for local abort */  	int			debug_id;	/* debug ID for printks */ -	unsigned		call_counter;	/* call ID counter */ +	unsigned int		call_counter;	/* call ID counter */  	atomic_t		serial;		/* packet serial number counter */  	atomic_t		hi_serial;	/* highest serial number received */  	u8			avail_calls;	/* number of calls available */ @@ -396,9 +396,20 @@ struct rxrpc_call {  #define RXRPC_ACKR_WINDOW_ASZ DIV_ROUND_UP(RXRPC_MAXACKS, BITS_PER_LONG)  	unsigned long		ackr_window[RXRPC_ACKR_WINDOW_ASZ + 1]; +	struct hlist_node	hash_node; +	unsigned long		hash_key;	/* Full hash key */ +	u8			in_clientflag;	/* Copy of conn->in_clientflag for hashing */ +	struct rxrpc_local	*local;		/* Local endpoint. Used for hashing. */ +	sa_family_t		proto;		/* Frame protocol */  	/* the following should all be in net order */  	__be32			cid;		/* connection ID + channel index  */  	__be32			call_id;	/* call ID on connection  */ +	__be32			epoch;		/* epoch of this connection */ +	__be16			service_id;	/* service ID */ +	union {					/* Peer IP address for hashing */ +		__be32	ipv4_addr; +		__u8	ipv6_addr[16];		/* Anticipates eventual IPv6 support */ +	} peer_ip;  };  /* @@ -426,58 +437,65 @@ extern struct workqueue_struct *rxrpc_workqueue;  /*   * ar-accept.c   */ -extern void rxrpc_accept_incoming_calls(struct work_struct *); -extern struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, -					    unsigned long); -extern int rxrpc_reject_call(struct rxrpc_sock *); +void rxrpc_accept_incoming_calls(struct work_struct *); +struct rxrpc_call *rxrpc_accept_call(struct rxrpc_sock *, unsigned long); +int rxrpc_reject_call(struct rxrpc_sock *);  /*   * ar-ack.c   */ -extern void __rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); -extern void rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); -extern void rxrpc_process_call(struct work_struct *); +extern unsigned rxrpc_requested_ack_delay; +extern unsigned rxrpc_soft_ack_delay; +extern unsigned rxrpc_idle_ack_delay; +extern unsigned rxrpc_rx_window_size; +extern unsigned rxrpc_rx_mtu; +extern unsigned rxrpc_rx_jumbo_max; + +void __rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); +void rxrpc_propose_ACK(struct rxrpc_call *, u8, __be32, bool); +void rxrpc_process_call(struct work_struct *);  /*   * ar-call.c   */ +extern unsigned rxrpc_max_call_lifetime; +extern unsigned rxrpc_dead_call_expiry;  extern struct kmem_cache *rxrpc_call_jar;  extern struct list_head rxrpc_calls;  extern rwlock_t rxrpc_call_lock; -extern struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *, -						struct rxrpc_transport *, -						struct rxrpc_conn_bundle *, -						unsigned long, int, gfp_t); -extern struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *, -					      struct rxrpc_connection *, -					      struct rxrpc_header *, gfp_t); -extern struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *, -						 unsigned long); -extern void rxrpc_release_call(struct rxrpc_call *); -extern void rxrpc_release_calls_on_socket(struct rxrpc_sock *); -extern void __rxrpc_put_call(struct rxrpc_call *); -extern void __exit rxrpc_destroy_all_calls(void); +struct rxrpc_call *rxrpc_find_call_hash(u8,  __be32, __be32, __be32, +					__be16, void *, sa_family_t, const u8 *); +struct rxrpc_call *rxrpc_get_client_call(struct rxrpc_sock *, +					 struct rxrpc_transport *, +					 struct rxrpc_conn_bundle *, +					 unsigned long, int, gfp_t); +struct rxrpc_call *rxrpc_incoming_call(struct rxrpc_sock *, +				       struct rxrpc_connection *, +				       struct rxrpc_header *, gfp_t); +struct rxrpc_call *rxrpc_find_server_call(struct rxrpc_sock *, unsigned long); +void rxrpc_release_call(struct rxrpc_call *); +void rxrpc_release_calls_on_socket(struct rxrpc_sock *); +void __rxrpc_put_call(struct rxrpc_call *); +void __exit rxrpc_destroy_all_calls(void);  /*   * ar-connection.c   */ +extern unsigned rxrpc_connection_expiry;  extern struct list_head rxrpc_connections;  extern rwlock_t rxrpc_connection_lock; -extern struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *, -						  struct rxrpc_transport *, -						  struct key *, -						  __be16, gfp_t); -extern void rxrpc_put_bundle(struct rxrpc_transport *, -			     struct rxrpc_conn_bundle *); -extern int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_transport *, -			      struct rxrpc_conn_bundle *, struct rxrpc_call *, -			      gfp_t); -extern void rxrpc_put_connection(struct rxrpc_connection *); -extern void __exit rxrpc_destroy_all_connections(void); -extern struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *, -						      struct rxrpc_header *); +struct rxrpc_conn_bundle *rxrpc_get_bundle(struct rxrpc_sock *, +					   struct rxrpc_transport *, +					   struct key *, __be16, gfp_t); +void rxrpc_put_bundle(struct rxrpc_transport *, struct rxrpc_conn_bundle *); +int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_transport *, +		       struct rxrpc_conn_bundle *, struct rxrpc_call *, gfp_t); +void rxrpc_put_connection(struct rxrpc_connection *); +void __exit rxrpc_destroy_all_connections(void); +struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_transport *, +					       struct rxrpc_header *);  extern struct rxrpc_connection *  rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_header *,  			  gfp_t); @@ -485,34 +503,33 @@ rxrpc_incoming_connection(struct rxrpc_transport *, struct rxrpc_header *,  /*   * ar-connevent.c   */ -extern void rxrpc_process_connection(struct work_struct *); -extern void rxrpc_reject_packet(struct rxrpc_local *, struct sk_buff *); -extern void rxrpc_reject_packets(struct work_struct *); +void rxrpc_process_connection(struct work_struct *); +void rxrpc_reject_packet(struct rxrpc_local *, struct sk_buff *); +void rxrpc_reject_packets(struct work_struct *);  /*   * ar-error.c   */ -extern void rxrpc_UDP_error_report(struct sock *); -extern void rxrpc_UDP_error_handler(struct work_struct *); +void rxrpc_UDP_error_report(struct sock *); +void rxrpc_UDP_error_handler(struct work_struct *);  /*   * ar-input.c   */ -extern unsigned long rxrpc_ack_timeout;  extern const char *rxrpc_pkts[]; -extern void rxrpc_data_ready(struct sock *, int); -extern int rxrpc_queue_rcv_skb(struct rxrpc_call *, struct sk_buff *, bool, -			       bool); -extern void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *); +void rxrpc_data_ready(struct sock *); +int rxrpc_queue_rcv_skb(struct rxrpc_call *, struct sk_buff *, bool, bool); +void rxrpc_fast_process_packet(struct rxrpc_call *, struct sk_buff *);  /*   * ar-local.c   */  extern rwlock_t rxrpc_local_lock; -extern struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *); -extern void rxrpc_put_local(struct rxrpc_local *); -extern void __exit rxrpc_destroy_all_locals(void); + +struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *); +void rxrpc_put_local(struct rxrpc_local *); +void __exit rxrpc_destroy_all_locals(void);  /*   * ar-key.c @@ -520,31 +537,29 @@ extern void __exit rxrpc_destroy_all_locals(void);  extern struct key_type key_type_rxrpc;  extern struct key_type key_type_rxrpc_s; -extern int rxrpc_request_key(struct rxrpc_sock *, char __user *, int); -extern int rxrpc_server_keyring(struct rxrpc_sock *, char __user *, int); -extern int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, -				     time_t, u32); +int rxrpc_request_key(struct rxrpc_sock *, char __user *, int); +int rxrpc_server_keyring(struct rxrpc_sock *, char __user *, int); +int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time_t, +			      u32);  /*   * ar-output.c   */ -extern int rxrpc_resend_timeout; +extern unsigned rxrpc_resend_timeout; -extern int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *); -extern int rxrpc_client_sendmsg(struct kiocb *, struct rxrpc_sock *, -				struct rxrpc_transport *, struct msghdr *, -				size_t); -extern int rxrpc_server_sendmsg(struct kiocb *, struct rxrpc_sock *, -				struct msghdr *, size_t); +int rxrpc_send_packet(struct rxrpc_transport *, struct sk_buff *); +int rxrpc_client_sendmsg(struct kiocb *, struct rxrpc_sock *, +			 struct rxrpc_transport *, struct msghdr *, size_t); +int rxrpc_server_sendmsg(struct kiocb *, struct rxrpc_sock *, struct msghdr *, +			 size_t);  /*   * ar-peer.c   */ -extern struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *, gfp_t); -extern void rxrpc_put_peer(struct rxrpc_peer *); -extern struct rxrpc_peer *rxrpc_find_peer(struct rxrpc_local *, -					  __be32, __be16); -extern void __exit rxrpc_destroy_all_peers(void); +struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *, gfp_t); +void rxrpc_put_peer(struct rxrpc_peer *); +struct rxrpc_peer *rxrpc_find_peer(struct rxrpc_local *, __be32, __be16); +void __exit rxrpc_destroy_all_peers(void);  /*   * ar-proc.c @@ -556,43 +571,54 @@ extern const struct file_operations rxrpc_connection_seq_fops;  /*   * ar-recvmsg.c   */ -extern void rxrpc_remove_user_ID(struct rxrpc_sock *, struct rxrpc_call *); -extern int rxrpc_recvmsg(struct kiocb *, struct socket *, struct msghdr *, -			 size_t, int); +void rxrpc_remove_user_ID(struct rxrpc_sock *, struct rxrpc_call *); +int rxrpc_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t, +		  int);  /*   * ar-security.c   */ -extern int rxrpc_register_security(struct rxrpc_security *); -extern void rxrpc_unregister_security(struct rxrpc_security *); -extern int rxrpc_init_client_conn_security(struct rxrpc_connection *); -extern int rxrpc_init_server_conn_security(struct rxrpc_connection *); -extern int rxrpc_secure_packet(const struct rxrpc_call *, struct sk_buff *, -			       size_t, void *); -extern int rxrpc_verify_packet(const struct rxrpc_call *, struct sk_buff *, -			       u32 *); -extern void rxrpc_clear_conn_security(struct rxrpc_connection *); +int rxrpc_register_security(struct rxrpc_security *); +void rxrpc_unregister_security(struct rxrpc_security *); +int rxrpc_init_client_conn_security(struct rxrpc_connection *); +int rxrpc_init_server_conn_security(struct rxrpc_connection *); +int rxrpc_secure_packet(const struct rxrpc_call *, struct sk_buff *, size_t, +			void *); +int rxrpc_verify_packet(const struct rxrpc_call *, struct sk_buff *, u32 *); +void rxrpc_clear_conn_security(struct rxrpc_connection *);  /*   * ar-skbuff.c   */ -extern void rxrpc_packet_destructor(struct sk_buff *); +void rxrpc_packet_destructor(struct sk_buff *);  /*   * ar-transport.c   */ -extern struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *, -						   struct rxrpc_peer *, -						   gfp_t); -extern void rxrpc_put_transport(struct rxrpc_transport *); -extern void __exit rxrpc_destroy_all_transports(void); -extern struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *, -						    struct rxrpc_peer *); +extern unsigned rxrpc_transport_expiry; + +struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *, +					    struct rxrpc_peer *, gfp_t); +void rxrpc_put_transport(struct rxrpc_transport *); +void __exit rxrpc_destroy_all_transports(void); +struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *, +					     struct rxrpc_peer *); + +/* + * sysctl.c + */ +#ifdef CONFIG_SYSCTL +extern int __init rxrpc_sysctl_init(void); +extern void rxrpc_sysctl_exit(void); +#else +static inline int __init rxrpc_sysctl_init(void) { return 0; } +static inline void rxrpc_sysctl_exit(void) {} +#endif  /*   * debug tracing   */ -extern unsigned rxrpc_debug; +extern unsigned int rxrpc_debug;  #define dbgprintk(FMT,...) \  	printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__) diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 5ee16f0353f..0ad080790a3 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c @@ -25,8 +25,9 @@  #include <keys/user-type.h>  #include "ar-internal.h" -static int rxrpc_instantiate(struct key *, const void *, size_t); -static int rxrpc_instantiate_s(struct key *, const void *, size_t); +static int rxrpc_vet_description_s(const char *); +static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *); +static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);  static void rxrpc_destroy(struct key *);  static void rxrpc_destroy_s(struct key *);  static void rxrpc_describe(const struct key *, struct seq_file *); @@ -52,6 +53,7 @@ EXPORT_SYMBOL(key_type_rxrpc);   */  struct key_type key_type_rxrpc_s = {  	.name		= "rxrpc_s", +	.vet_description = rxrpc_vet_description_s,  	.instantiate	= rxrpc_instantiate_s,  	.match		= user_match,  	.destroy	= rxrpc_destroy_s, @@ -59,11 +61,28 @@ struct key_type key_type_rxrpc_s = {  };  /* + * Vet the description for an RxRPC server key + */ +static int rxrpc_vet_description_s(const char *desc) +{ +	unsigned long num; +	char *p; + +	num = simple_strtoul(desc, &p, 10); +	if (*p != ':' || num > 65535) +		return -EINVAL; +	num = simple_strtoul(p + 1, &p, 10); +	if (*p || num < 1 || num > 255) +		return -EINVAL; +	return 0; +} + +/*   * parse an RxKAD type XDR format token   * - the caller guarantees we have at least 4 words   */  static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr, -				       unsigned toklen) +				       unsigned int toklen)  {  	struct rxrpc_key_token *token, **pptoken;  	size_t plen; @@ -80,7 +99,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,  	_debug("tktlen: %x", tktlen);  	if (tktlen > AFSTOKEN_RK_TIX_MAX)  		return -EKEYREJECTED; -	if (8 * 4 + tktlen != toklen) +	if (toklen < 8 * 4 + tktlen)  		return -EKEYREJECTED;  	plen = sizeof(*token) + sizeof(*token->kad) + tktlen; @@ -89,11 +108,11 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,  		return ret;  	plen -= sizeof(*token); -	token = kmalloc(sizeof(*token), GFP_KERNEL); +	token = kzalloc(sizeof(*token), GFP_KERNEL);  	if (!token)  		return -ENOMEM; -	token->kad = kmalloc(plen, GFP_KERNEL); +	token->kad = kzalloc(plen, GFP_KERNEL);  	if (!token->kad) {  		kfree(token);  		return -ENOMEM; @@ -191,10 +210,10 @@ static void rxrpc_rxk5_free(struct rxk5_key *rxk5)   */  static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,  				       const __be32 **_xdr, -				       unsigned *_toklen) +				       unsigned int *_toklen)  {  	const __be32 *xdr = *_xdr; -	unsigned toklen = *_toklen, n_parts, loop, tmp; +	unsigned int toklen = *_toklen, n_parts, loop, tmp;  	/* there must be at least one name, and at least #names+1 length  	 * words */ @@ -213,7 +232,7 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,  	if (toklen <= (n_parts + 1) * 4)  		return -EINVAL; -	princ->name_parts = kcalloc(sizeof(char *), n_parts, GFP_KERNEL); +	princ->name_parts = kcalloc(n_parts, sizeof(char *), GFP_KERNEL);  	if (!princ->name_parts)  		return -ENOMEM; @@ -267,10 +286,10 @@ static int rxrpc_krb5_decode_principal(struct krb5_principal *princ,  static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,  					 size_t max_data_size,  					 const __be32 **_xdr, -					 unsigned *_toklen) +					 unsigned int *_toklen)  {  	const __be32 *xdr = *_xdr; -	unsigned toklen = *_toklen, len; +	unsigned int toklen = *_toklen, len;  	/* there must be at least one tag and one length word */  	if (toklen <= 8) @@ -287,10 +306,9 @@ static int rxrpc_krb5_decode_tagged_data(struct krb5_tagged_data *td,  	td->data_len = len;  	if (len > 0) { -		td->data = kmalloc(len, GFP_KERNEL); +		td->data = kmemdup(xdr, len, GFP_KERNEL);  		if (!td->data)  			return -ENOMEM; -		memcpy(td->data, xdr, len);  		len = (len + 3) & ~3;  		toklen -= len;  		xdr += len >> 2; @@ -312,11 +330,11 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,  					  u8 max_n_elem,  					  size_t max_elem_size,  					  const __be32 **_xdr, -					  unsigned *_toklen) +					  unsigned int *_toklen)  {  	struct krb5_tagged_data *td;  	const __be32 *xdr = *_xdr; -	unsigned toklen = *_toklen, n_elem, loop; +	unsigned int toklen = *_toklen, n_elem, loop;  	int ret;  	/* there must be at least one count */ @@ -337,7 +355,7 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,  		_debug("n_elem %d", n_elem); -		td = kcalloc(sizeof(struct krb5_tagged_data), n_elem, +		td = kcalloc(n_elem, sizeof(struct krb5_tagged_data),  			     GFP_KERNEL);  		if (!td)  			return -ENOMEM; @@ -362,10 +380,10 @@ static int rxrpc_krb5_decode_tagged_array(struct krb5_tagged_data **_td,   * extract a krb5 ticket   */  static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen, -				    const __be32 **_xdr, unsigned *_toklen) +				    const __be32 **_xdr, unsigned int *_toklen)  {  	const __be32 *xdr = *_xdr; -	unsigned toklen = *_toklen, len; +	unsigned int toklen = *_toklen, len;  	/* there must be at least one length word */  	if (toklen <= 4) @@ -382,10 +400,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,  	_debug("ticket len %u", len);  	if (len > 0) { -		*_ticket = kmalloc(len, GFP_KERNEL); +		*_ticket = kmemdup(xdr, len, GFP_KERNEL);  		if (!*_ticket)  			return -ENOMEM; -		memcpy(*_ticket, xdr, len);  		len = (len + 3) & ~3;  		toklen -= len;  		xdr += len >> 2; @@ -402,7 +419,7 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,   * - the caller guarantees we have at least 4 words   */  static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr, -				      unsigned toklen) +				      unsigned int toklen)  {  	struct rxrpc_key_token *token, **pptoken;  	struct rxk5_key *rxk5; @@ -532,7 +549,7 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal  {  	const __be32 *xdr = data, *token;  	const char *cp; -	unsigned len, tmp, loop, ntoken, toklen, sec_ix; +	unsigned int len, tmp, loop, ntoken, toklen, sec_ix;  	int ret;  	_enter(",{%x,%x,%x,%x},%zu", @@ -661,7 +678,7 @@ error:   *   * if no data is provided, then a no-security key is made   */ -static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen) +static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)  {  	const struct rxrpc_key_data_v1 *v1;  	struct rxrpc_key_token *token, **pp; @@ -669,26 +686,26 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)  	u32 kver;  	int ret; -	_enter("{%x},,%zu", key_serial(key), datalen); +	_enter("{%x},,%zu", key_serial(key), prep->datalen);  	/* handle a no-security key */ -	if (!data && datalen == 0) +	if (!prep->data && prep->datalen == 0)  		return 0;  	/* determine if the XDR payload format is being used */ -	if (datalen > 7 * 4) { -		ret = rxrpc_instantiate_xdr(key, data, datalen); +	if (prep->datalen > 7 * 4) { +		ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);  		if (ret != -EPROTO)  			return ret;  	}  	/* get the key interface version number */  	ret = -EINVAL; -	if (datalen <= 4 || !data) +	if (prep->datalen <= 4 || !prep->data)  		goto error; -	memcpy(&kver, data, sizeof(kver)); -	data += sizeof(kver); -	datalen -= sizeof(kver); +	memcpy(&kver, prep->data, sizeof(kver)); +	prep->data += sizeof(kver); +	prep->datalen -= sizeof(kver);  	_debug("KEY I/F VERSION: %u", kver); @@ -698,11 +715,11 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)  	/* deal with a version 1 key */  	ret = -EINVAL; -	if (datalen < sizeof(*v1)) +	if (prep->datalen < sizeof(*v1))  		goto error; -	v1 = data; -	if (datalen != sizeof(*v1) + v1->ticket_length) +	v1 = prep->data; +	if (prep->datalen != sizeof(*v1) + v1->ticket_length)  		goto error;  	_debug("SCIX: %u", v1->security_index); @@ -731,10 +748,10 @@ static int rxrpc_instantiate(struct key *key, const void *data, size_t datalen)  		goto error;  	ret = -ENOMEM; -	token = kmalloc(sizeof(*token), GFP_KERNEL); +	token = kzalloc(sizeof(*token), GFP_KERNEL);  	if (!token)  		goto error; -	token->kad = kmalloc(plen, GFP_KERNEL); +	token->kad = kzalloc(plen, GFP_KERNEL);  	if (!token->kad)  		goto error_free; @@ -767,17 +784,17 @@ error:   * instantiate a server secret key   * data should be a pointer to the 8-byte secret key   */ -static int rxrpc_instantiate_s(struct key *key, const void *data, -			       size_t datalen) +static int rxrpc_instantiate_s(struct key *key, +			       struct key_preparsed_payload *prep)  {  	struct crypto_blkcipher *ci; -	_enter("{%x},,%zu", key_serial(key), datalen); +	_enter("{%x},,%zu", key_serial(key), prep->datalen); -	if (datalen != 8) +	if (prep->datalen != 8)  		return -EINVAL; -	memcpy(&key->type_data, data, 8); +	memcpy(&key->type_data, prep->data, 8);  	ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);  	if (IS_ERR(ci)) { @@ -785,7 +802,7 @@ static int rxrpc_instantiate_s(struct key *key, const void *data,  		return PTR_ERR(ci);  	} -	if (crypto_blkcipher_setkey(ci, data, 8) < 0) +	if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)  		BUG();  	key->payload.data = ci; @@ -931,7 +948,8 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,  	_enter(""); -	key = key_alloc(&key_type_rxrpc, "x", 0, 0, cred, 0, +	key = key_alloc(&key_type_rxrpc, "x", +			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,  			KEY_ALLOC_NOT_IN_QUOTA);  	if (IS_ERR(key)) {  		_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key)); @@ -977,7 +995,8 @@ struct key *rxrpc_get_null_key(const char *keyname)  	struct key *key;  	int ret; -	key = key_alloc(&key_type_rxrpc, keyname, 0, 0, cred, +	key = key_alloc(&key_type_rxrpc, keyname, +			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,  			KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);  	if (IS_ERR(key))  		return key; diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index 5f22e263eda..0b4b9a79f5a 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -13,11 +13,15 @@  #include <linux/gfp.h>  #include <linux/skbuff.h>  #include <linux/circ_buf.h> +#include <linux/export.h>  #include <net/sock.h>  #include <net/af_rxrpc.h>  #include "ar-internal.h" -int rxrpc_resend_timeout = 4; +/* + * Time till packet resend (in jiffies). + */ +unsigned rxrpc_resend_timeout = 4 * HZ;  static int rxrpc_send_data(struct kiocb *iocb,  			   struct rxrpc_sock *rx, @@ -151,8 +155,8 @@ int rxrpc_client_sendmsg(struct kiocb *iocb, struct rxrpc_sock *rx,  	if (trans) {  		service_id = rx->service_id;  		if (msg->msg_name) { -			struct sockaddr_rxrpc *srx = -				(struct sockaddr_rxrpc *) msg->msg_name; +			DECLARE_SOCKADDR(struct sockaddr_rxrpc *, srx, +					 msg->msg_name);  			service_id = htons(srx->srx_service);  		}  		key = rx->key; @@ -241,7 +245,7 @@ int rxrpc_kernel_send_data(struct rxrpc_call *call, struct msghdr *msg,  EXPORT_SYMBOL(rxrpc_kernel_send_data); -/* +/**   * rxrpc_kernel_abort_call - Allow a kernel service to abort a call   * @call: The call to be aborted   * @abort_code: The abort code to stick into the ABORT packet @@ -485,8 +489,8 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,  	_proto("Tx DATA %%%u { #%u }",  	       ntohl(sp->hdr.serial), ntohl(sp->hdr.seq)); -	sp->need_resend = 0; -	sp->resend_at = jiffies + rxrpc_resend_timeout * HZ; +	sp->need_resend = false; +	sp->resend_at = jiffies + rxrpc_resend_timeout;  	if (!test_and_set_bit(RXRPC_CALL_RUN_RTIMER, &call->flags)) {  		_debug("run timer");  		call->resend_timer.expires = sp->resend_at; @@ -507,7 +511,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,  	if (ret < 0) {  		_debug("need instant resend %d", ret); -		sp->need_resend = 1; +		sp->need_resend = true;  		rxrpc_instant_resend(call);  	} @@ -665,6 +669,7 @@ static int rxrpc_send_data(struct kiocb *iocb,  		/* add the packet to the send queue if it's now full */  		if (sp->remain <= 0 || (segment == 0 && !more)) {  			struct rxrpc_connection *conn = call->conn; +			uint32_t seq;  			size_t pad;  			/* pad out if we're using security */ @@ -677,11 +682,12 @@ static int rxrpc_send_data(struct kiocb *iocb,  					memset(skb_put(skb, pad), 0, pad);  			} +			seq = atomic_inc_return(&call->sequence); +  			sp->hdr.epoch = conn->epoch;  			sp->hdr.cid = call->cid;  			sp->hdr.callNumber = call->call_id; -			sp->hdr.seq = -				htonl(atomic_inc_return(&call->sequence)); +			sp->hdr.seq = htonl(seq);  			sp->hdr.serial =  				htonl(atomic_inc_return(&conn->serial));  			sp->hdr.type = RXRPC_PACKET_TYPE_DATA; @@ -696,6 +702,8 @@ static int rxrpc_send_data(struct kiocb *iocb,  			else if (CIRC_SPACE(call->acks_head, call->acks_tail,  					    call->acks_winsz) > 1)  				sp->hdr.flags |= RXRPC_MORE_PACKETS; +			if (more && seq & 1) +				sp->hdr.flags |= RXRPC_REQUEST_ACK;  			ret = rxrpc_secure_packet(  				call, skb, skb->mark, diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index a53fb25a64e..bebaa43484b 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -36,31 +36,16 @@ static void rxrpc_destroy_peer(struct work_struct *work);  static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)  {  	struct rtable *rt; -	struct flowi fl; -	int ret; +	struct flowi4 fl4;  	peer->if_mtu = 1500; -	memset(&fl, 0, sizeof(fl)); - -	switch (peer->srx.transport.family) { -	case AF_INET: -		fl.oif = 0; -		fl.proto = IPPROTO_UDP, -		fl.fl4_dst = peer->srx.transport.sin.sin_addr.s_addr; -		fl.fl4_src = 0; -		fl.fl4_tos = 0; -		/* assume AFS.CM talking to AFS.FS */ -		fl.fl_ip_sport = htons(7001); -		fl.fl_ip_dport = htons(7000); -		break; -	default: -		BUG(); -	} - -	ret = ip_route_output_key(&init_net, &rt, &fl); -	if (ret < 0) { -		_leave(" [route err %d]", ret); +	rt = ip_route_output_ports(&init_net, &fl4, NULL, +				   peer->srx.transport.sin.sin_addr.s_addr, 0, +				   htons(7000), htons(7001), +				   IPPROTO_UDP, 0, 0); +	if (IS_ERR(rt)) { +		_leave(" [route err %ld]", PTR_ERR(rt));  		return;  	} @@ -172,6 +157,7 @@ struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *srx, gfp_t gfp)  	/* we can now add the new candidate to the list */  	peer = candidate;  	candidate = NULL; +	usage = atomic_read(&peer->usage);  	list_add_tail(&peer->link, &rxrpc_peers);  	write_unlock_bh(&rxrpc_peer_lock); @@ -186,7 +172,7 @@ success:  	     &peer->srx.transport.sin.sin_addr,  	     ntohs(peer->srx.transport.sin.sin_port)); -	_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); +	_leave(" = %p {u=%d}", peer, usage);  	return peer;  	/* we found the peer in the list immediately */ @@ -243,7 +229,7 @@ found_UDP_peer:  	return peer;  new_UDP_peer: -	_net("Rx UDP DGRAM from NEW peer %d", peer->debug_id); +	_net("Rx UDP DGRAM from NEW peer");  	read_unlock_bh(&rxrpc_peer_lock);  	_leave(" = -EBUSY [new]");  	return ERR_PTR(-EBUSY); diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c index 0c65013e3bf..e9aaa65c077 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c @@ -11,6 +11,7 @@  #include <linux/net.h>  #include <linux/skbuff.h> +#include <linux/export.h>  #include <net/sock.h>  #include <net/af_rxrpc.h>  #include "ar-internal.h" @@ -142,10 +143,13 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,  		/* copy the peer address and timestamp */  		if (!continue_call) { -			if (msg->msg_name && msg->msg_namelen > 0) +			if (msg->msg_name) { +				size_t len = +					sizeof(call->conn->trans->peer->srx);  				memcpy(msg->msg_name, -				       &call->conn->trans->peer->srx, -				       sizeof(call->conn->trans->peer->srx)); +				       &call->conn->trans->peer->srx, len); +				msg->msg_namelen = len; +			}  			sock_recv_ts_and_drops(msg, &rx->sk, skb);  		} @@ -176,15 +180,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,  		if (copy > len - copied)  			copy = len - copied; -		if (skb->ip_summed == CHECKSUM_UNNECESSARY) { -			ret = skb_copy_datagram_iovec(skb, offset, -						      msg->msg_iov, copy); -		} else { -			ret = skb_copy_and_csum_datagram_iovec(skb, offset, -							       msg->msg_iov); -			if (ret == -EINVAL) -				goto csum_copy_error; -		} +		ret = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copy);  		if (ret < 0)  			goto copy_error; @@ -343,16 +339,6 @@ copy_error:  	_leave(" = %d", ret);  	return ret; -csum_copy_error: -	_debug("csum error"); -	release_sock(&rx->sk); -	if (continue_call) -		rxrpc_put_call(continue_call); -	rxrpc_kill_skb(skb); -	skb_kill_datagram(&rx->sk, skb, flags); -	rxrpc_put_call(call); -	return -EAGAIN; -  wait_interrupted:  	ret = sock_intr_errno(timeo);  wait_error: diff --git a/net/rxrpc/ar-skbuff.c b/net/rxrpc/ar-skbuff.c index de755e04d29..4cfab49e329 100644 --- a/net/rxrpc/ar-skbuff.c +++ b/net/rxrpc/ar-skbuff.c @@ -83,9 +83,14 @@ static void rxrpc_hard_ACK_data(struct rxrpc_call *call,  		rxrpc_request_final_ACK(call);  	} else if (atomic_dec_and_test(&call->ackr_not_idle) &&  		   test_and_clear_bit(RXRPC_CALL_TX_SOFT_ACK, &call->flags)) { +		/* We previously soft-ACK'd some received packets that have now +		 * been consumed, so send a hard-ACK if no more packets are +		 * immediately forthcoming to allow the transmitter to free up +		 * its Tx bufferage. +		 */  		_debug("send Rx idle ACK");  		__rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, sp->hdr.serial, -				    true); +				    false);  	}  	spin_unlock_bh(&call->lock); diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c index 5e0226fe587..1976dec84f2 100644 --- a/net/rxrpc/ar-transport.c +++ b/net/rxrpc/ar-transport.c @@ -17,11 +17,15 @@  #include <net/af_rxrpc.h>  #include "ar-internal.h" +/* + * Time after last use at which transport record is cleaned up. + */ +unsigned rxrpc_transport_expiry = 3600 * 24; +  static void rxrpc_transport_reaper(struct work_struct *work);  static LIST_HEAD(rxrpc_transports);  static DEFINE_RWLOCK(rxrpc_transport_lock); -static unsigned long rxrpc_transport_timeout = 3600 * 24;  static DECLARE_DELAYED_WORK(rxrpc_transport_reap, rxrpc_transport_reaper);  /* @@ -111,6 +115,7 @@ struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *local,  	/* we can now add the new candidate to the list */  	trans = candidate;  	candidate = NULL; +	usage = atomic_read(&trans->usage);  	rxrpc_get_local(trans->local);  	atomic_inc(&trans->peer->usage); @@ -125,7 +130,7 @@ success:  	     trans->local->debug_id,  	     trans->peer->debug_id); -	_leave(" = %p {u=%d}", trans, atomic_read(&trans->usage)); +	_leave(" = %p {u=%d}", trans, usage);  	return trans;  	/* we found the transport in the list immediately */ @@ -234,7 +239,7 @@ static void rxrpc_transport_reaper(struct work_struct *work)  		if (likely(atomic_read(&trans->usage) > 0))  			continue; -		reap_time = trans->put_time + rxrpc_transport_timeout; +		reap_time = trans->put_time + rxrpc_transport_expiry;  		if (reap_time <= now)  			list_move_tail(&trans->link, &graveyard);  		else if (reap_time < earliest) @@ -270,7 +275,7 @@ void __exit rxrpc_destroy_all_transports(void)  {  	_enter(""); -	rxrpc_transport_timeout = 0; +	rxrpc_transport_expiry = 0;  	cancel_delayed_work(&rxrpc_transport_reap);  	rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0); diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 7635107726c..f226709ebd8 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -31,7 +31,7 @@  #define REALM_SZ			40	/* size of principal's auth domain */  #define SNAME_SZ			40	/* size of service name */ -unsigned rxrpc_debug; +unsigned int rxrpc_debug;  module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);  MODULE_PARM_DESC(debug, "rxkad debugging mask"); @@ -207,7 +207,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,  	struct rxrpc_crypt iv;  	struct scatterlist sg[16];  	struct sk_buff *trailer; -	unsigned len; +	unsigned int len;  	u16 check;  	int nsg; @@ -826,7 +826,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,  	struct rxrpc_crypt iv, key;  	struct scatterlist sg[1];  	struct in_addr addr; -	unsigned life; +	unsigned int life;  	time_t issue, now;  	bool little_endian;  	int ret; diff --git a/net/rxrpc/sysctl.c b/net/rxrpc/sysctl.c new file mode 100644 index 00000000000..50a98a910eb --- /dev/null +++ b/net/rxrpc/sysctl.c @@ -0,0 +1,146 @@ +/* sysctls for configuring RxRPC operating parameters + * + * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include <linux/sysctl.h> +#include <net/sock.h> +#include <net/af_rxrpc.h> +#include "ar-internal.h" + +static struct ctl_table_header *rxrpc_sysctl_reg_table; +static const unsigned zero = 0; +static const unsigned one = 1; +static const unsigned four = 4; +static const unsigned n_65535 = 65535; +static const unsigned n_max_acks = RXRPC_MAXACKS; + +/* + * RxRPC operating parameters. + * + * See Documentation/networking/rxrpc.txt and the variable definitions for more + * information on the individual parameters. + */ +static struct ctl_table rxrpc_sysctl_table[] = { +	/* Values measured in milliseconds */ +	{ +		.procname	= "req_ack_delay", +		.data		= &rxrpc_requested_ack_delay, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_ms_jiffies, +		.extra1		= (void *)&zero, +	}, +	{ +		.procname	= "soft_ack_delay", +		.data		= &rxrpc_soft_ack_delay, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_ms_jiffies, +		.extra1		= (void *)&one, +	}, +	{ +		.procname	= "idle_ack_delay", +		.data		= &rxrpc_idle_ack_delay, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_ms_jiffies, +		.extra1		= (void *)&one, +	}, +	{ +		.procname	= "resend_timeout", +		.data		= &rxrpc_resend_timeout, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_ms_jiffies, +		.extra1		= (void *)&one, +	}, + +	/* Values measured in seconds but used in jiffies */ +	{ +		.procname	= "max_call_lifetime", +		.data		= &rxrpc_max_call_lifetime, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_jiffies, +		.extra1		= (void *)&one, +	}, +	{ +		.procname	= "dead_call_expiry", +		.data		= &rxrpc_dead_call_expiry, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_jiffies, +		.extra1		= (void *)&one, +	}, + +	/* Values measured in seconds */ +	{ +		.procname	= "connection_expiry", +		.data		= &rxrpc_connection_expiry, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= (void *)&one, +	}, +	{ +		.procname	= "transport_expiry", +		.data		= &rxrpc_transport_expiry, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= (void *)&one, +	}, + +	/* Non-time values */ +	{ +		.procname	= "rx_window_size", +		.data		= &rxrpc_rx_window_size, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= (void *)&one, +		.extra2		= (void *)&n_max_acks, +	}, +	{ +		.procname	= "rx_mtu", +		.data		= &rxrpc_rx_mtu, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= (void *)&one, +		.extra1		= (void *)&n_65535, +	}, +	{ +		.procname	= "rx_jumbo_max", +		.data		= &rxrpc_rx_jumbo_max, +		.maxlen		= sizeof(unsigned), +		.mode		= 0644, +		.proc_handler	= proc_dointvec_minmax, +		.extra1		= (void *)&one, +		.extra2		= (void *)&four, +	}, + +	{ } +}; + +int __init rxrpc_sysctl_init(void) +{ +	rxrpc_sysctl_reg_table = register_net_sysctl(&init_net, "net/rxrpc", +						     rxrpc_sysctl_table); +	if (!rxrpc_sysctl_reg_table) +		return -ENOMEM; +	return 0; +} + +void rxrpc_sysctl_exit(void) +{ +	if (rxrpc_sysctl_reg_table) +		unregister_net_sysctl_table(rxrpc_sysctl_reg_table); +}  | 
