Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1291e9d1 authored by David Howells's avatar David Howells
Browse files

rxrpc: Move data_ready peer lookup into rxrpc_find_connection()



Move the peer lookup done in input.c by data_ready into
rxrpc_find_connection().

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent e8d70ce1
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -564,7 +564,6 @@ void rxrpc_extract_conn_params(struct rxrpc_conn_proto *,
			       struct rxrpc_local *, struct sk_buff *);
struct rxrpc_connection *rxrpc_alloc_connection(gfp_t);
struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *,
					       struct rxrpc_peer *,
					       struct sk_buff *);
void __rxrpc_disconnect_call(struct rxrpc_call *);
void rxrpc_disconnect_call(struct rxrpc_call *);
@@ -768,8 +767,6 @@ static inline void rxrpc_sysctl_exit(void) {}
/*
 * utils.c
 */
void rxrpc_get_addr_from_skb(struct rxrpc_local *, const struct sk_buff *,
			     struct sockaddr_rxrpc *);
int rxrpc_extract_addr_from_skb(struct sockaddr_rxrpc *, struct sk_buff *);

/*
+56 −17
Original line number Diff line number Diff line
@@ -68,52 +68,91 @@ struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
 * packet
 */
struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local,
					       struct rxrpc_peer *peer,
					       struct sk_buff *skb)
{
	struct rxrpc_connection *conn;
	struct rxrpc_conn_proto k;
	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
	struct sockaddr_rxrpc srx;
	struct rxrpc_peer *peer;
	struct rb_node *p;
	u32 epoch, cid;

	_enter(",{%x,%x}", sp->hdr.cid, sp->hdr.flags);

	read_lock_bh(&peer->conn_lock);
	if (rxrpc_extract_addr_from_skb(&srx, skb) < 0)
		goto not_found;

	/* We may have to handle mixing IPv4 and IPv6 */
	if (srx.transport.family != local->srx.transport.family) {
		pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n",
				    srx.transport.family,
				    local->srx.transport.family);
		goto not_found;
	}

	cid	= sp->hdr.cid & RXRPC_CIDMASK;
	epoch	= sp->hdr.epoch;
	k.epoch	= sp->hdr.epoch;
	k.cid	= sp->hdr.cid & RXRPC_CIDMASK;

	if (sp->hdr.flags & RXRPC_CLIENT_INITIATED) {
		/* We need to look up service connections by the full protocol
		 * parameter set.  We look up the peer first as an intermediate
		 * step and then the connection from the peer's tree.
		 */
		peer = rxrpc_lookup_peer_rcu(local, &srx);
		if (!peer)
			goto not_found;

		read_lock_bh(&peer->conn_lock);

		p = peer->service_conns.rb_node;
		while (p) {
			conn = rb_entry(p, struct rxrpc_connection, service_node);

			_debug("maybe %x", conn->proto.cid);

			if (epoch < conn->proto.epoch)
			if (k.epoch < conn->proto.epoch)
				p = p->rb_left;
			else if (epoch > conn->proto.epoch)
			else if (k.epoch > conn->proto.epoch)
				p = p->rb_right;
			else if (cid < conn->proto.cid)
			else if (k.cid < conn->proto.cid)
				p = p->rb_left;
			else if (cid > conn->proto.cid)
			else if (k.cid > conn->proto.cid)
				p = p->rb_right;
			else
				goto found;
				goto found_service_conn;
		}
		read_unlock_bh(&peer->conn_lock);
	} else {
		conn = idr_find(&rxrpc_client_conn_ids, cid >> RXRPC_CIDSHIFT);
		if (conn &&
		    conn->proto.epoch == epoch &&
		    conn->params.peer == peer)
			goto found;
		conn = idr_find(&rxrpc_client_conn_ids,
				k.cid >> RXRPC_CIDSHIFT);
		if (!conn ||
		    conn->proto.epoch != k.epoch ||
		    conn->params.local != local)
			goto not_found;

		peer = conn->params.peer;
		switch (srx.transport.family) {
		case AF_INET:
			if (peer->srx.transport.sin.sin_port !=
			    srx.transport.sin.sin_port ||
			    peer->srx.transport.sin.sin_addr.s_addr !=
			    srx.transport.sin.sin_addr.s_addr)
				goto not_found;
			break;
		default:
			BUG();
		}

	read_unlock_bh(&peer->conn_lock);
		conn = rxrpc_get_connection_maybe(conn);
		_leave(" = %p", conn);
		return conn;
	}

not_found:
	_leave(" = NULL");
	return NULL;

found:
found_service_conn:
	conn = rxrpc_get_connection_maybe(conn);
	read_unlock_bh(&peer->conn_lock);
	_leave(" = %p", conn);
+3 −27
Original line number Diff line number Diff line
@@ -626,32 +626,6 @@ int rxrpc_extract_header(struct rxrpc_skb_priv *sp, struct sk_buff *skb)
	return 0;
}

static struct rxrpc_connection *rxrpc_conn_from_local(struct rxrpc_local *local,
						      struct sk_buff *skb)
{
	struct rxrpc_peer *peer;
	struct rxrpc_connection *conn;
	struct sockaddr_rxrpc srx;

	rxrpc_get_addr_from_skb(local, skb, &srx);
	rcu_read_lock();
	peer = rxrpc_lookup_peer_rcu(local, &srx);
	if (!peer)
		goto cant_find_peer;

	conn = rxrpc_find_connection(local, peer, skb);
	rcu_read_unlock();
	if (!conn)
		goto cant_find_conn;

	return conn;

cant_find_peer:
	rcu_read_unlock();
cant_find_conn:
	return NULL;
}

/*
 * handle data received on the local endpoint
 * - may be called in interrupt context
@@ -731,7 +705,9 @@ void rxrpc_data_ready(struct sock *sk)
		 * old-fashioned way doesn't really hurt */
		struct rxrpc_connection *conn;

		conn = rxrpc_conn_from_local(local, skb);
		rcu_read_lock();
		conn = rxrpc_find_connection(local, skb);
		rcu_read_unlock();
		if (!conn)
			goto cant_route_call;

+0 −27
Original line number Diff line number Diff line
@@ -14,33 +14,6 @@
#include <linux/udp.h>
#include "ar-internal.h"

/*
 * Set up an RxRPC address from a socket buffer.
 */
void rxrpc_get_addr_from_skb(struct rxrpc_local *local,
			     const struct sk_buff *skb,
			     struct sockaddr_rxrpc *srx)
{
	memset(srx, 0, sizeof(*srx));
	srx->transport_type = local->srx.transport_type;
	srx->transport.family = local->srx.transport.family;

	/* Can we see an ipv4 UDP packet on an ipv6 UDP socket?  and vice
	 * versa?
	 */
	switch (srx->transport.family) {
	case AF_INET:
		srx->transport.sin.sin_port = udp_hdr(skb)->source;
		srx->transport_len = sizeof(struct sockaddr_in);
		memcpy(&srx->transport.sin.sin_addr, &ip_hdr(skb)->saddr,
		       sizeof(struct in_addr));
		break;

	default:
		BUG();
	}
}

/*
 * Fill out a peer address from a socket buffer containing a packet.
 */