1 /* Service connection management
3 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
12 #include <linux/slab.h>
13 #include "ar-internal.h"
16 * Find a service connection under RCU conditions.
18 * We could use a hash table, but that is subject to bucket stuffing by an
19 * attacker as the client gets to pick the epoch and cid values and would know
20 * the hash function. So, instead, we use a hash table for the peer and from
21 * that an rbtree to find the service connection. Under ordinary circumstances
22 * it might be slower than a large hash table, but it is at least limited in
25 struct rxrpc_connection
*rxrpc_find_service_conn_rcu(struct rxrpc_peer
*peer
,
28 struct rxrpc_connection
*conn
= NULL
;
29 struct rxrpc_conn_proto k
;
30 struct rxrpc_skb_priv
*sp
= rxrpc_skb(skb
);
34 k
.epoch
= sp
->hdr
.epoch
;
35 k
.cid
= sp
->hdr
.cid
& RXRPC_CIDMASK
;
38 /* Unfortunately, rbtree walking doesn't give reliable results
39 * under just the RCU read lock, so we have to check for
42 read_seqbegin_or_lock(&peer
->service_conn_lock
, &seq
);
44 p
= rcu_dereference_raw(peer
->service_conns
.rb_node
);
46 conn
= rb_entry(p
, struct rxrpc_connection
, service_node
);
48 if (conn
->proto
.index_key
< k
.index_key
)
49 p
= rcu_dereference_raw(p
->rb_left
);
50 else if (conn
->proto
.index_key
> k
.index_key
)
51 p
= rcu_dereference_raw(p
->rb_right
);
56 } while (need_seqretry(&peer
->service_conn_lock
, seq
));
59 done_seqretry(&peer
->service_conn_lock
, seq
);
60 _leave(" = %d", conn
? conn
->debug_id
: -1);
65 * Insert a service connection into a peer's tree, thereby making it a target
66 * for incoming packets.
68 static void rxrpc_publish_service_conn(struct rxrpc_peer
*peer
,
69 struct rxrpc_connection
*conn
)
71 struct rxrpc_connection
*cursor
= NULL
;
72 struct rxrpc_conn_proto k
= conn
->proto
;
73 struct rb_node
**pp
, *parent
;
75 write_seqlock_bh(&peer
->service_conn_lock
);
77 pp
= &peer
->service_conns
.rb_node
;
81 cursor
= rb_entry(parent
,
82 struct rxrpc_connection
, service_node
);
84 if (cursor
->proto
.index_key
< k
.index_key
)
86 else if (cursor
->proto
.index_key
> k
.index_key
)
87 pp
= &(*pp
)->rb_right
;
89 goto found_extant_conn
;
92 rb_link_node_rcu(&conn
->service_node
, parent
, pp
);
93 rb_insert_color(&conn
->service_node
, &peer
->service_conns
);
95 set_bit(RXRPC_CONN_IN_SERVICE_CONNS
, &conn
->flags
);
96 write_sequnlock_bh(&peer
->service_conn_lock
);
97 _leave(" = %d [new]", conn
->debug_id
);
101 if (atomic_read(&cursor
->usage
) == 0)
102 goto replace_old_connection
;
103 write_sequnlock_bh(&peer
->service_conn_lock
);
104 /* We should not be able to get here. rxrpc_incoming_connection() is
105 * called in a non-reentrant context, so there can't be a race to
106 * insert a new connection.
110 replace_old_connection
:
111 /* The old connection is from an outdated epoch. */
112 _debug("replace conn");
113 rb_replace_node_rcu(&cursor
->service_node
,
115 &peer
->service_conns
);
116 clear_bit(RXRPC_CONN_IN_SERVICE_CONNS
, &cursor
->flags
);
121 * Preallocate a service connection. The connection is placed on the proc and
122 * reap lists so that we don't have to get the lock from BH context.
124 struct rxrpc_connection
*rxrpc_prealloc_service_connection(gfp_t gfp
)
126 struct rxrpc_connection
*conn
= rxrpc_alloc_connection(gfp
);
129 /* We maintain an extra ref on the connection whilst it is on
130 * the rxrpc_connections list.
132 conn
->state
= RXRPC_CONN_SERVICE_PREALLOC
;
133 atomic_set(&conn
->usage
, 2);
135 write_lock(&rxrpc_connection_lock
);
136 list_add_tail(&conn
->link
, &rxrpc_connections
);
137 list_add_tail(&conn
->proc_link
, &rxrpc_connection_proc_list
);
138 write_unlock(&rxrpc_connection_lock
);
140 trace_rxrpc_conn(conn
, rxrpc_conn_new_service
,
141 atomic_read(&conn
->usage
),
142 __builtin_return_address(0));
149 * Set up an incoming connection. This is called in BH context with the RCU
152 void rxrpc_new_incoming_connection(struct rxrpc_connection
*conn
,
155 struct rxrpc_skb_priv
*sp
= rxrpc_skb(skb
);
159 conn
->proto
.epoch
= sp
->hdr
.epoch
;
160 conn
->proto
.cid
= sp
->hdr
.cid
& RXRPC_CIDMASK
;
161 conn
->params
.service_id
= sp
->hdr
.serviceId
;
162 conn
->security_ix
= sp
->hdr
.securityIndex
;
163 conn
->out_clientflag
= 0;
164 if (conn
->security_ix
)
165 conn
->state
= RXRPC_CONN_SERVICE_UNSECURED
;
167 conn
->state
= RXRPC_CONN_SERVICE
;
169 /* Make the connection a target for incoming packets. */
170 rxrpc_publish_service_conn(conn
->params
.peer
, conn
);
172 _net("CONNECTION new %d {%x}", conn
->debug_id
, conn
->proto
.cid
);
176 * Remove the service connection from the peer's tree, thereby removing it as a
177 * target for incoming packets.
179 void rxrpc_unpublish_service_conn(struct rxrpc_connection
*conn
)
181 struct rxrpc_peer
*peer
= conn
->params
.peer
;
183 write_seqlock_bh(&peer
->service_conn_lock
);
184 if (test_and_clear_bit(RXRPC_CONN_IN_SERVICE_CONNS
, &conn
->flags
))
185 rb_erase(&conn
->service_node
, &peer
->service_conns
);
186 write_sequnlock_bh(&peer
->service_conn_lock
);