rxrpc: Move data_ready peer lookup into rxrpc_find_connection()
authorDavid Howells <dhowells@redhat.com>
Thu, 30 Jun 2016 11:02:53 +0000 (12:02 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 6 Jul 2016 09:51:14 +0000 (10:51 +0100)
Move the peer lookup done in input.c by data_ready into
rxrpc_find_connection().

Signed-off-by: David Howells <dhowells@redhat.com>
net/rxrpc/ar-internal.h
net/rxrpc/conn_object.c
net/rxrpc/input.c
net/rxrpc/utils.c

index 6fdee761dd0b062e9963cebf2a8aed1ba9d3e4ee..0fe63baf128687b2bb10374c95840b1e0005010e 100644 (file)
@@ -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 *);
 
 /*
index 89bc6480b4e283e79e5da8cf26e8598f167d4d03..130713869a1681827487eaa4fa9afdac872c22a3 100644 (file)
@@ -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;
 
-       cid     = sp->hdr.cid & RXRPC_CIDMASK;
-       epoch   = sp->hdr.epoch;
+       /* 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;
+       }
+
+       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();
+               }
+
+               conn = rxrpc_get_connection_maybe(conn);
+               _leave(" = %p", conn);
+               return conn;
        }
 
-       read_unlock_bh(&peer->conn_lock);
+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);
index b993f2dc5a09c736eaa48c2568769f2ce7290022..c2436476f793db0e4c3794866005a4fb1d6b1115 100644 (file)
@@ -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;
 
index d3db02ecc37f3b719cda4b712416bca4651082de..b88914d53ca5e10eb63f2172e01609baf1598f4c 100644 (file)
 #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.
  */