1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* /proc/net/ support for AF_RXRPC
3 *
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8 #include <linux/module.h>
9 #include <net/sock.h>
10 #include <net/af_rxrpc.h>
11 #include "ar-internal.h"
12
13 static const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
14 [RXRPC_CONN_UNUSED] = "Unused ",
15 [RXRPC_CONN_CLIENT] = "Client ",
16 [RXRPC_CONN_SERVICE_PREALLOC] = "SvPrealc",
17 [RXRPC_CONN_SERVICE_UNSECURED] = "SvUnsec ",
18 [RXRPC_CONN_SERVICE_CHALLENGING] = "SvChall ",
19 [RXRPC_CONN_SERVICE] = "SvSecure",
20 [RXRPC_CONN_REMOTELY_ABORTED] = "RmtAbort",
21 [RXRPC_CONN_LOCALLY_ABORTED] = "LocAbort",
22 };
23
24 /*
25 * generate a list of extant and dead calls in /proc/net/rxrpc_calls
26 */
rxrpc_call_seq_start(struct seq_file * seq,loff_t * _pos)27 static void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
28 __acquires(rcu)
29 {
30 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
31
32 rcu_read_lock();
33 return seq_list_start_head_rcu(&rxnet->calls, *_pos);
34 }
35
rxrpc_call_seq_next(struct seq_file * seq,void * v,loff_t * pos)36 static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
37 {
38 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
39
40 return seq_list_next_rcu(v, &rxnet->calls, pos);
41 }
42
rxrpc_call_seq_stop(struct seq_file * seq,void * v)43 static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
44 __releases(rcu)
45 {
46 rcu_read_unlock();
47 }
48
rxrpc_call_seq_show(struct seq_file * seq,void * v)49 static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
50 {
51 struct rxrpc_local *local;
52 struct rxrpc_sock *rx;
53 struct rxrpc_peer *peer;
54 struct rxrpc_call *call;
55 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
56 unsigned long timeout = 0;
57 rxrpc_seq_t tx_hard_ack, rx_hard_ack;
58 char lbuff[50], rbuff[50];
59
60 if (v == &rxnet->calls) {
61 seq_puts(seq,
62 "Proto Local "
63 " Remote "
64 " SvID ConnID CallID End Use State Abort "
65 " DebugId TxSeq TW RxSeq RW RxSerial RxTimo\n");
66 return 0;
67 }
68
69 call = list_entry(v, struct rxrpc_call, link);
70
71 rx = rcu_dereference(call->socket);
72 if (rx) {
73 local = READ_ONCE(rx->local);
74 if (local)
75 sprintf(lbuff, "%pISpc", &local->srx.transport);
76 else
77 strcpy(lbuff, "no_local");
78 } else {
79 strcpy(lbuff, "no_socket");
80 }
81
82 peer = call->peer;
83 if (peer)
84 sprintf(rbuff, "%pISpc", &peer->srx.transport);
85 else
86 strcpy(rbuff, "no_connection");
87
88 if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
89 timeout = READ_ONCE(call->expect_rx_by);
90 timeout -= jiffies;
91 }
92
93 tx_hard_ack = READ_ONCE(call->tx_hard_ack);
94 rx_hard_ack = READ_ONCE(call->rx_hard_ack);
95 seq_printf(seq,
96 "UDP %-47.47s %-47.47s %4x %08x %08x %s %3u"
97 " %-8.8s %08x %08x %08x %02x %08x %02x %08x %06lx\n",
98 lbuff,
99 rbuff,
100 call->service_id,
101 call->cid,
102 call->call_id,
103 rxrpc_is_service_call(call) ? "Svc" : "Clt",
104 refcount_read(&call->ref),
105 rxrpc_call_states[call->state],
106 call->abort_code,
107 call->debug_id,
108 tx_hard_ack, READ_ONCE(call->tx_top) - tx_hard_ack,
109 rx_hard_ack, READ_ONCE(call->rx_top) - rx_hard_ack,
110 call->rx_serial,
111 timeout);
112
113 return 0;
114 }
115
116 const struct seq_operations rxrpc_call_seq_ops = {
117 .start = rxrpc_call_seq_start,
118 .next = rxrpc_call_seq_next,
119 .stop = rxrpc_call_seq_stop,
120 .show = rxrpc_call_seq_show,
121 };
122
123 /*
124 * generate a list of extant virtual connections in /proc/net/rxrpc_conns
125 */
rxrpc_connection_seq_start(struct seq_file * seq,loff_t * _pos)126 static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
127 __acquires(rxnet->conn_lock)
128 {
129 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
130
131 read_lock(&rxnet->conn_lock);
132 return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
133 }
134
rxrpc_connection_seq_next(struct seq_file * seq,void * v,loff_t * pos)135 static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
136 loff_t *pos)
137 {
138 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
139
140 return seq_list_next(v, &rxnet->conn_proc_list, pos);
141 }
142
rxrpc_connection_seq_stop(struct seq_file * seq,void * v)143 static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
144 __releases(rxnet->conn_lock)
145 {
146 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
147
148 read_unlock(&rxnet->conn_lock);
149 }
150
rxrpc_connection_seq_show(struct seq_file * seq,void * v)151 static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
152 {
153 struct rxrpc_connection *conn;
154 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
155 char lbuff[50], rbuff[50];
156
157 if (v == &rxnet->conn_proc_list) {
158 seq_puts(seq,
159 "Proto Local "
160 " Remote "
161 " SvID ConnID End Use State Key "
162 " Serial ISerial CallId0 CallId1 CallId2 CallId3\n"
163 );
164 return 0;
165 }
166
167 conn = list_entry(v, struct rxrpc_connection, proc_link);
168 if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
169 strcpy(lbuff, "no_local");
170 strcpy(rbuff, "no_connection");
171 goto print;
172 }
173
174 sprintf(lbuff, "%pISpc", &conn->params.local->srx.transport);
175
176 sprintf(rbuff, "%pISpc", &conn->params.peer->srx.transport);
177 print:
178 seq_printf(seq,
179 "UDP %-47.47s %-47.47s %4x %08x %s %3u"
180 " %s %08x %08x %08x %08x %08x %08x %08x\n",
181 lbuff,
182 rbuff,
183 conn->service_id,
184 conn->proto.cid,
185 rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
186 refcount_read(&conn->ref),
187 rxrpc_conn_states[conn->state],
188 key_serial(conn->params.key),
189 atomic_read(&conn->serial),
190 conn->hi_serial,
191 conn->channels[0].call_id,
192 conn->channels[1].call_id,
193 conn->channels[2].call_id,
194 conn->channels[3].call_id);
195
196 return 0;
197 }
198
199 const struct seq_operations rxrpc_connection_seq_ops = {
200 .start = rxrpc_connection_seq_start,
201 .next = rxrpc_connection_seq_next,
202 .stop = rxrpc_connection_seq_stop,
203 .show = rxrpc_connection_seq_show,
204 };
205
206 /*
207 * generate a list of extant virtual peers in /proc/net/rxrpc/peers
208 */
rxrpc_peer_seq_show(struct seq_file * seq,void * v)209 static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
210 {
211 struct rxrpc_peer *peer;
212 time64_t now;
213 char lbuff[50], rbuff[50];
214
215 if (v == SEQ_START_TOKEN) {
216 seq_puts(seq,
217 "Proto Local "
218 " Remote "
219 " Use CW MTU LastUse RTT RTO\n"
220 );
221 return 0;
222 }
223
224 peer = list_entry(v, struct rxrpc_peer, hash_link);
225
226 sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
227
228 sprintf(rbuff, "%pISpc", &peer->srx.transport);
229
230 now = ktime_get_seconds();
231 seq_printf(seq,
232 "UDP %-47.47s %-47.47s %3u"
233 " %3u %5u %6llus %8u %8u\n",
234 lbuff,
235 rbuff,
236 refcount_read(&peer->ref),
237 peer->cong_cwnd,
238 peer->mtu,
239 now - peer->last_tx_at,
240 peer->srtt_us >> 3,
241 jiffies_to_usecs(peer->rto_j));
242
243 return 0;
244 }
245
rxrpc_peer_seq_start(struct seq_file * seq,loff_t * _pos)246 static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
247 __acquires(rcu)
248 {
249 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
250 unsigned int bucket, n;
251 unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
252 void *p;
253
254 rcu_read_lock();
255
256 if (*_pos >= UINT_MAX)
257 return NULL;
258
259 n = *_pos & ((1U << shift) - 1);
260 bucket = *_pos >> shift;
261 for (;;) {
262 if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
263 *_pos = UINT_MAX;
264 return NULL;
265 }
266 if (n == 0) {
267 if (bucket == 0)
268 return SEQ_START_TOKEN;
269 *_pos += 1;
270 n++;
271 }
272
273 p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
274 if (p)
275 return p;
276 bucket++;
277 n = 1;
278 *_pos = (bucket << shift) | n;
279 }
280 }
281
rxrpc_peer_seq_next(struct seq_file * seq,void * v,loff_t * _pos)282 static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
283 {
284 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
285 unsigned int bucket, n;
286 unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
287 void *p;
288
289 if (*_pos >= UINT_MAX)
290 return NULL;
291
292 bucket = *_pos >> shift;
293
294 p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
295 if (p)
296 return p;
297
298 for (;;) {
299 bucket++;
300 n = 1;
301 *_pos = (bucket << shift) | n;
302
303 if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
304 *_pos = UINT_MAX;
305 return NULL;
306 }
307 if (n == 0) {
308 *_pos += 1;
309 n++;
310 }
311
312 p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
313 if (p)
314 return p;
315 }
316 }
317
rxrpc_peer_seq_stop(struct seq_file * seq,void * v)318 static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
319 __releases(rcu)
320 {
321 rcu_read_unlock();
322 }
323
324
325 const struct seq_operations rxrpc_peer_seq_ops = {
326 .start = rxrpc_peer_seq_start,
327 .next = rxrpc_peer_seq_next,
328 .stop = rxrpc_peer_seq_stop,
329 .show = rxrpc_peer_seq_show,
330 };
331
332 /*
333 * Generate a list of extant virtual local endpoints in /proc/net/rxrpc/locals
334 */
rxrpc_local_seq_show(struct seq_file * seq,void * v)335 static int rxrpc_local_seq_show(struct seq_file *seq, void *v)
336 {
337 struct rxrpc_local *local;
338 char lbuff[50];
339
340 if (v == SEQ_START_TOKEN) {
341 seq_puts(seq,
342 "Proto Local "
343 " Use Act\n");
344 return 0;
345 }
346
347 local = hlist_entry(v, struct rxrpc_local, link);
348
349 sprintf(lbuff, "%pISpc", &local->srx.transport);
350
351 seq_printf(seq,
352 "UDP %-47.47s %3u %3u\n",
353 lbuff,
354 refcount_read(&local->ref),
355 atomic_read(&local->active_users));
356
357 return 0;
358 }
359
rxrpc_local_seq_start(struct seq_file * seq,loff_t * _pos)360 static void *rxrpc_local_seq_start(struct seq_file *seq, loff_t *_pos)
361 __acquires(rcu)
362 {
363 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
364 unsigned int n;
365
366 rcu_read_lock();
367
368 if (*_pos >= UINT_MAX)
369 return NULL;
370
371 n = *_pos;
372 if (n == 0)
373 return SEQ_START_TOKEN;
374
375 return seq_hlist_start_rcu(&rxnet->local_endpoints, n - 1);
376 }
377
rxrpc_local_seq_next(struct seq_file * seq,void * v,loff_t * _pos)378 static void *rxrpc_local_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
379 {
380 struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
381
382 if (*_pos >= UINT_MAX)
383 return NULL;
384
385 return seq_hlist_next_rcu(v, &rxnet->local_endpoints, _pos);
386 }
387
rxrpc_local_seq_stop(struct seq_file * seq,void * v)388 static void rxrpc_local_seq_stop(struct seq_file *seq, void *v)
389 __releases(rcu)
390 {
391 rcu_read_unlock();
392 }
393
394 const struct seq_operations rxrpc_local_seq_ops = {
395 .start = rxrpc_local_seq_start,
396 .next = rxrpc_local_seq_next,
397 .stop = rxrpc_local_seq_stop,
398 .show = rxrpc_local_seq_show,
399 };
400