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 	__acquires(rxnet->call_lock)
30 {
31 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
32 
33 	rcu_read_lock();
34 	read_lock(&rxnet->call_lock);
35 	return seq_list_start_head(&rxnet->calls, *_pos);
36 }
37 
rxrpc_call_seq_next(struct seq_file * seq,void * v,loff_t * pos)38 static void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
39 {
40 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
41 
42 	return seq_list_next(v, &rxnet->calls, pos);
43 }
44 
rxrpc_call_seq_stop(struct seq_file * seq,void * v)45 static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
46 	__releases(rxnet->call_lock)
47 	__releases(rcu)
48 {
49 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
50 
51 	read_unlock(&rxnet->call_lock);
52 	rcu_read_unlock();
53 }
54 
rxrpc_call_seq_show(struct seq_file * seq,void * v)55 static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
56 {
57 	struct rxrpc_local *local;
58 	struct rxrpc_sock *rx;
59 	struct rxrpc_peer *peer;
60 	struct rxrpc_call *call;
61 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
62 	unsigned long timeout = 0;
63 	rxrpc_seq_t tx_hard_ack, rx_hard_ack;
64 	char lbuff[50], rbuff[50];
65 
66 	if (v == &rxnet->calls) {
67 		seq_puts(seq,
68 			 "Proto Local                                          "
69 			 " Remote                                         "
70 			 " SvID ConnID   CallID   End Use State    Abort   "
71 			 " DebugId  TxSeq    TW RxSeq    RW RxSerial RxTimo\n");
72 		return 0;
73 	}
74 
75 	call = list_entry(v, struct rxrpc_call, link);
76 
77 	rx = rcu_dereference(call->socket);
78 	if (rx) {
79 		local = READ_ONCE(rx->local);
80 		if (local)
81 			sprintf(lbuff, "%pISpc", &local->srx.transport);
82 		else
83 			strcpy(lbuff, "no_local");
84 	} else {
85 		strcpy(lbuff, "no_socket");
86 	}
87 
88 	peer = call->peer;
89 	if (peer)
90 		sprintf(rbuff, "%pISpc", &peer->srx.transport);
91 	else
92 		strcpy(rbuff, "no_connection");
93 
94 	if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
95 		timeout = READ_ONCE(call->expect_rx_by);
96 		timeout -= jiffies;
97 	}
98 
99 	tx_hard_ack = READ_ONCE(call->tx_hard_ack);
100 	rx_hard_ack = READ_ONCE(call->rx_hard_ack);
101 	seq_printf(seq,
102 		   "UDP   %-47.47s %-47.47s %4x %08x %08x %s %3u"
103 		   " %-8.8s %08x %08x %08x %02x %08x %02x %08x %06lx\n",
104 		   lbuff,
105 		   rbuff,
106 		   call->service_id,
107 		   call->cid,
108 		   call->call_id,
109 		   rxrpc_is_service_call(call) ? "Svc" : "Clt",
110 		   atomic_read(&call->usage),
111 		   rxrpc_call_states[call->state],
112 		   call->abort_code,
113 		   call->debug_id,
114 		   tx_hard_ack, READ_ONCE(call->tx_top) - tx_hard_ack,
115 		   rx_hard_ack, READ_ONCE(call->rx_top) - rx_hard_ack,
116 		   call->rx_serial,
117 		   timeout);
118 
119 	return 0;
120 }
121 
122 const struct seq_operations rxrpc_call_seq_ops = {
123 	.start  = rxrpc_call_seq_start,
124 	.next   = rxrpc_call_seq_next,
125 	.stop   = rxrpc_call_seq_stop,
126 	.show   = rxrpc_call_seq_show,
127 };
128 
129 /*
130  * generate a list of extant virtual connections in /proc/net/rxrpc_conns
131  */
rxrpc_connection_seq_start(struct seq_file * seq,loff_t * _pos)132 static void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
133 	__acquires(rxnet->conn_lock)
134 {
135 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
136 
137 	read_lock(&rxnet->conn_lock);
138 	return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
139 }
140 
rxrpc_connection_seq_next(struct seq_file * seq,void * v,loff_t * pos)141 static void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
142 				       loff_t *pos)
143 {
144 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
145 
146 	return seq_list_next(v, &rxnet->conn_proc_list, pos);
147 }
148 
rxrpc_connection_seq_stop(struct seq_file * seq,void * v)149 static void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
150 	__releases(rxnet->conn_lock)
151 {
152 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
153 
154 	read_unlock(&rxnet->conn_lock);
155 }
156 
rxrpc_connection_seq_show(struct seq_file * seq,void * v)157 static int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
158 {
159 	struct rxrpc_connection *conn;
160 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
161 	char lbuff[50], rbuff[50];
162 
163 	if (v == &rxnet->conn_proc_list) {
164 		seq_puts(seq,
165 			 "Proto Local                                          "
166 			 " Remote                                         "
167 			 " SvID ConnID   End Use State    Key     "
168 			 " Serial   ISerial  CallId0  CallId1  CallId2  CallId3\n"
169 			 );
170 		return 0;
171 	}
172 
173 	conn = list_entry(v, struct rxrpc_connection, proc_link);
174 	if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
175 		strcpy(lbuff, "no_local");
176 		strcpy(rbuff, "no_connection");
177 		goto print;
178 	}
179 
180 	sprintf(lbuff, "%pISpc", &conn->params.local->srx.transport);
181 
182 	sprintf(rbuff, "%pISpc", &conn->params.peer->srx.transport);
183 print:
184 	seq_printf(seq,
185 		   "UDP   %-47.47s %-47.47s %4x %08x %s %3u"
186 		   " %s %08x %08x %08x %08x %08x %08x %08x\n",
187 		   lbuff,
188 		   rbuff,
189 		   conn->service_id,
190 		   conn->proto.cid,
191 		   rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
192 		   atomic_read(&conn->usage),
193 		   rxrpc_conn_states[conn->state],
194 		   key_serial(conn->params.key),
195 		   atomic_read(&conn->serial),
196 		   conn->hi_serial,
197 		   conn->channels[0].call_id,
198 		   conn->channels[1].call_id,
199 		   conn->channels[2].call_id,
200 		   conn->channels[3].call_id);
201 
202 	return 0;
203 }
204 
205 const struct seq_operations rxrpc_connection_seq_ops = {
206 	.start  = rxrpc_connection_seq_start,
207 	.next   = rxrpc_connection_seq_next,
208 	.stop   = rxrpc_connection_seq_stop,
209 	.show   = rxrpc_connection_seq_show,
210 };
211 
212 /*
213  * generate a list of extant virtual peers in /proc/net/rxrpc/peers
214  */
rxrpc_peer_seq_show(struct seq_file * seq,void * v)215 static int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
216 {
217 	struct rxrpc_peer *peer;
218 	time64_t now;
219 	char lbuff[50], rbuff[50];
220 
221 	if (v == SEQ_START_TOKEN) {
222 		seq_puts(seq,
223 			 "Proto Local                                          "
224 			 " Remote                                         "
225 			 " Use  CW   MTU LastUse      RTT      RTO\n"
226 			 );
227 		return 0;
228 	}
229 
230 	peer = list_entry(v, struct rxrpc_peer, hash_link);
231 
232 	sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
233 
234 	sprintf(rbuff, "%pISpc", &peer->srx.transport);
235 
236 	now = ktime_get_seconds();
237 	seq_printf(seq,
238 		   "UDP   %-47.47s %-47.47s %3u"
239 		   " %3u %5u %6llus %8u %8u\n",
240 		   lbuff,
241 		   rbuff,
242 		   atomic_read(&peer->usage),
243 		   peer->cong_cwnd,
244 		   peer->mtu,
245 		   now - peer->last_tx_at,
246 		   peer->srtt_us >> 3,
247 		   jiffies_to_usecs(peer->rto_j));
248 
249 	return 0;
250 }
251 
rxrpc_peer_seq_start(struct seq_file * seq,loff_t * _pos)252 static void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
253 	__acquires(rcu)
254 {
255 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
256 	unsigned int bucket, n;
257 	unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
258 	void *p;
259 
260 	rcu_read_lock();
261 
262 	if (*_pos >= UINT_MAX)
263 		return NULL;
264 
265 	n = *_pos & ((1U << shift) - 1);
266 	bucket = *_pos >> shift;
267 	for (;;) {
268 		if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
269 			*_pos = UINT_MAX;
270 			return NULL;
271 		}
272 		if (n == 0) {
273 			if (bucket == 0)
274 				return SEQ_START_TOKEN;
275 			*_pos += 1;
276 			n++;
277 		}
278 
279 		p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
280 		if (p)
281 			return p;
282 		bucket++;
283 		n = 1;
284 		*_pos = (bucket << shift) | n;
285 	}
286 }
287 
rxrpc_peer_seq_next(struct seq_file * seq,void * v,loff_t * _pos)288 static void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
289 {
290 	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
291 	unsigned int bucket, n;
292 	unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
293 	void *p;
294 
295 	if (*_pos >= UINT_MAX)
296 		return NULL;
297 
298 	bucket = *_pos >> shift;
299 
300 	p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
301 	if (p)
302 		return p;
303 
304 	for (;;) {
305 		bucket++;
306 		n = 1;
307 		*_pos = (bucket << shift) | n;
308 
309 		if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
310 			*_pos = UINT_MAX;
311 			return NULL;
312 		}
313 		if (n == 0) {
314 			*_pos += 1;
315 			n++;
316 		}
317 
318 		p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
319 		if (p)
320 			return p;
321 	}
322 }
323 
rxrpc_peer_seq_stop(struct seq_file * seq,void * v)324 static void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
325 	__releases(rcu)
326 {
327 	rcu_read_unlock();
328 }
329 
330 
331 const struct seq_operations rxrpc_peer_seq_ops = {
332 	.start  = rxrpc_peer_seq_start,
333 	.next   = rxrpc_peer_seq_next,
334 	.stop   = rxrpc_peer_seq_stop,
335 	.show   = rxrpc_peer_seq_show,
336 };
337