diff options
Diffstat (limited to 'net/rxrpc')
| -rw-r--r-- | net/rxrpc/Makefile | 5 | ||||
| -rw-r--r-- | net/rxrpc/af_rxrpc.c | 9 | ||||
| -rw-r--r-- | net/rxrpc/ar-ack.c | 82 | ||||
| -rw-r--r-- | net/rxrpc/ar-call.c | 213 | ||||
| -rw-r--r-- | net/rxrpc/ar-connection.c | 12 | ||||
| -rw-r--r-- | net/rxrpc/ar-error.c | 1 | ||||
| -rw-r--r-- | net/rxrpc/ar-input.c | 196 | ||||
| -rw-r--r-- | net/rxrpc/ar-internal.h | 190 | ||||
| -rw-r--r-- | net/rxrpc/ar-key.c | 2 | ||||
| -rw-r--r-- | net/rxrpc/ar-output.c | 19 | ||||
| -rw-r--r-- | net/rxrpc/ar-recvmsg.c | 29 | ||||
| -rw-r--r-- | net/rxrpc/ar-skbuff.c | 7 | ||||
| -rw-r--r-- | net/rxrpc/ar-transport.c | 10 | ||||
| -rw-r--r-- | net/rxrpc/sysctl.c | 146 | 
14 files changed, 662 insertions, 259 deletions
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 e61aa6001c6..7b167048963 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -838,6 +838,12 @@ 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_create("rxrpc_calls", 0, init_net.proc_net, &rxrpc_call_seq_fops);  	proc_create("rxrpc_conns", 0, init_net.proc_net, @@ -845,6 +851,8 @@ static int __init af_rxrpc_init(void)  #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: @@ -865,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); diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index e4d9cbcff40..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 int 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;  		} @@ -637,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); @@ -1167,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 }", @@ -1180,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 a3bbb360a3f..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 int rxrpc_call_max_lifetime = 60; -static unsigned int 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-error.c b/net/rxrpc/ar-error.c index a9206087b4d..db57458c824 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c @@ -83,6 +83,7 @@ void rxrpc_UDP_error_report(struct sock *sk)  		if (mtu == 0) {  			/* they didn't give us a size, estimate one */ +			mtu = peer->if_mtu;  			if (mtu > 1500) {  				mtu >>= 1;  				if (mtu < 1500) diff --git a/net/rxrpc/ar-input.c b/net/rxrpc/ar-input.c index 529572f18d1..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", @@ -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) { @@ -526,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; @@ -563,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) @@ -574,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("");  } @@ -664,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()); @@ -749,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; @@ -790,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 a693aca2ae2..ba9fd36d3f1 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -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,38 +571,49 @@ 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 diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c index 7633a752c65..0ad080790a3 100644 --- a/net/rxrpc/ar-key.c +++ b/net/rxrpc/ar-key.c @@ -99,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; diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c index e1ac183d50b..0b4b9a79f5a 100644 --- a/net/rxrpc/ar-output.c +++ b/net/rxrpc/ar-output.c @@ -18,7 +18,10 @@  #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, @@ -152,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; @@ -487,7 +490,7 @@ static void rxrpc_queue_packet(struct rxrpc_call *call, struct sk_buff *skb,  	       ntohl(sp->hdr.serial), ntohl(sp->hdr.seq));  	sp->need_resend = false; -	sp->resend_at = jiffies + rxrpc_resend_timeout * HZ; +	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; @@ -666,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 */ @@ -678,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; @@ -697,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-recvmsg.c b/net/rxrpc/ar-recvmsg.c index 4b48687c389..e9aaa65c077 100644 --- a/net/rxrpc/ar-recvmsg.c +++ b/net/rxrpc/ar-recvmsg.c @@ -143,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);  		} @@ -177,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; @@ -344,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 92df566930b..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);  /* @@ -235,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) @@ -271,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/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); +}  | 
