162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/* /proc/net/ support for AF_RXRPC
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <net/sock.h>
1062306a36Sopenharmony_ci#include <net/af_rxrpc.h>
1162306a36Sopenharmony_ci#include "ar-internal.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic const char *const rxrpc_conn_states[RXRPC_CONN__NR_STATES] = {
1462306a36Sopenharmony_ci	[RXRPC_CONN_UNUSED]			= "Unused  ",
1562306a36Sopenharmony_ci	[RXRPC_CONN_CLIENT_UNSECURED]		= "ClUnsec ",
1662306a36Sopenharmony_ci	[RXRPC_CONN_CLIENT]			= "Client  ",
1762306a36Sopenharmony_ci	[RXRPC_CONN_SERVICE_PREALLOC]		= "SvPrealc",
1862306a36Sopenharmony_ci	[RXRPC_CONN_SERVICE_UNSECURED]		= "SvUnsec ",
1962306a36Sopenharmony_ci	[RXRPC_CONN_SERVICE_CHALLENGING]	= "SvChall ",
2062306a36Sopenharmony_ci	[RXRPC_CONN_SERVICE]			= "SvSecure",
2162306a36Sopenharmony_ci	[RXRPC_CONN_ABORTED]			= "Aborted ",
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * generate a list of extant and dead calls in /proc/net/rxrpc_calls
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistatic void *rxrpc_call_seq_start(struct seq_file *seq, loff_t *_pos)
2862306a36Sopenharmony_ci	__acquires(rcu)
2962306a36Sopenharmony_ci{
3062306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	rcu_read_lock();
3362306a36Sopenharmony_ci	return seq_list_start_head_rcu(&rxnet->calls, *_pos);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic void *rxrpc_call_seq_next(struct seq_file *seq, void *v, loff_t *pos)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return seq_list_next_rcu(v, &rxnet->calls, pos);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
4462306a36Sopenharmony_ci	__releases(rcu)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	rcu_read_unlock();
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic int rxrpc_call_seq_show(struct seq_file *seq, void *v)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct rxrpc_local *local;
5262306a36Sopenharmony_ci	struct rxrpc_call *call;
5362306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
5462306a36Sopenharmony_ci	enum rxrpc_call_state state;
5562306a36Sopenharmony_ci	unsigned long timeout = 0;
5662306a36Sopenharmony_ci	rxrpc_seq_t acks_hard_ack;
5762306a36Sopenharmony_ci	char lbuff[50], rbuff[50];
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (v == &rxnet->calls) {
6062306a36Sopenharmony_ci		seq_puts(seq,
6162306a36Sopenharmony_ci			 "Proto Local                                          "
6262306a36Sopenharmony_ci			 " Remote                                         "
6362306a36Sopenharmony_ci			 " SvID ConnID   CallID   End Use State    Abort   "
6462306a36Sopenharmony_ci			 " DebugId  TxSeq    TW RxSeq    RW RxSerial CW RxTimo\n");
6562306a36Sopenharmony_ci		return 0;
6662306a36Sopenharmony_ci	}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	call = list_entry(v, struct rxrpc_call, link);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	local = call->local;
7162306a36Sopenharmony_ci	if (local)
7262306a36Sopenharmony_ci		sprintf(lbuff, "%pISpc", &local->srx.transport);
7362306a36Sopenharmony_ci	else
7462306a36Sopenharmony_ci		strcpy(lbuff, "no_local");
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	state = rxrpc_call_state(call);
7962306a36Sopenharmony_ci	if (state != RXRPC_CALL_SERVER_PREALLOC) {
8062306a36Sopenharmony_ci		timeout = READ_ONCE(call->expect_rx_by);
8162306a36Sopenharmony_ci		timeout -= jiffies;
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	acks_hard_ack = READ_ONCE(call->acks_hard_ack);
8562306a36Sopenharmony_ci	seq_printf(seq,
8662306a36Sopenharmony_ci		   "UDP   %-47.47s %-47.47s %4x %08x %08x %s %3u"
8762306a36Sopenharmony_ci		   " %-8.8s %08x %08x %08x %02x %08x %02x %08x %02x %06lx\n",
8862306a36Sopenharmony_ci		   lbuff,
8962306a36Sopenharmony_ci		   rbuff,
9062306a36Sopenharmony_ci		   call->dest_srx.srx_service,
9162306a36Sopenharmony_ci		   call->cid,
9262306a36Sopenharmony_ci		   call->call_id,
9362306a36Sopenharmony_ci		   rxrpc_is_service_call(call) ? "Svc" : "Clt",
9462306a36Sopenharmony_ci		   refcount_read(&call->ref),
9562306a36Sopenharmony_ci		   rxrpc_call_states[state],
9662306a36Sopenharmony_ci		   call->abort_code,
9762306a36Sopenharmony_ci		   call->debug_id,
9862306a36Sopenharmony_ci		   acks_hard_ack, READ_ONCE(call->tx_top) - acks_hard_ack,
9962306a36Sopenharmony_ci		   call->ackr_window, call->ackr_wtop - call->ackr_window,
10062306a36Sopenharmony_ci		   call->rx_serial,
10162306a36Sopenharmony_ci		   call->cong_cwnd,
10262306a36Sopenharmony_ci		   timeout);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ciconst struct seq_operations rxrpc_call_seq_ops = {
10862306a36Sopenharmony_ci	.start  = rxrpc_call_seq_start,
10962306a36Sopenharmony_ci	.next   = rxrpc_call_seq_next,
11062306a36Sopenharmony_ci	.stop   = rxrpc_call_seq_stop,
11162306a36Sopenharmony_ci	.show   = rxrpc_call_seq_show,
11262306a36Sopenharmony_ci};
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci/*
11562306a36Sopenharmony_ci * generate a list of extant virtual connections in /proc/net/rxrpc_conns
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_cistatic void *rxrpc_connection_seq_start(struct seq_file *seq, loff_t *_pos)
11862306a36Sopenharmony_ci	__acquires(rxnet->conn_lock)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	read_lock(&rxnet->conn_lock);
12362306a36Sopenharmony_ci	return seq_list_start_head(&rxnet->conn_proc_list, *_pos);
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic void *rxrpc_connection_seq_next(struct seq_file *seq, void *v,
12762306a36Sopenharmony_ci				       loff_t *pos)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return seq_list_next(v, &rxnet->conn_proc_list, pos);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic void rxrpc_connection_seq_stop(struct seq_file *seq, void *v)
13562306a36Sopenharmony_ci	__releases(rxnet->conn_lock)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	read_unlock(&rxnet->conn_lock);
14062306a36Sopenharmony_ci}
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int rxrpc_connection_seq_show(struct seq_file *seq, void *v)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	struct rxrpc_connection *conn;
14562306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
14662306a36Sopenharmony_ci	const char *state;
14762306a36Sopenharmony_ci	char lbuff[50], rbuff[50];
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	if (v == &rxnet->conn_proc_list) {
15062306a36Sopenharmony_ci		seq_puts(seq,
15162306a36Sopenharmony_ci			 "Proto Local                                          "
15262306a36Sopenharmony_ci			 " Remote                                         "
15362306a36Sopenharmony_ci			 " SvID ConnID   End Ref Act State    Key     "
15462306a36Sopenharmony_ci			 " Serial   ISerial  CallId0  CallId1  CallId2  CallId3\n"
15562306a36Sopenharmony_ci			 );
15662306a36Sopenharmony_ci		return 0;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	conn = list_entry(v, struct rxrpc_connection, proc_link);
16062306a36Sopenharmony_ci	if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) {
16162306a36Sopenharmony_ci		strcpy(lbuff, "no_local");
16262306a36Sopenharmony_ci		strcpy(rbuff, "no_connection");
16362306a36Sopenharmony_ci		goto print;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	sprintf(lbuff, "%pISpc", &conn->local->srx.transport);
16762306a36Sopenharmony_ci	sprintf(rbuff, "%pISpc", &conn->peer->srx.transport);
16862306a36Sopenharmony_ciprint:
16962306a36Sopenharmony_ci	state = rxrpc_is_conn_aborted(conn) ?
17062306a36Sopenharmony_ci		rxrpc_call_completions[conn->completion] :
17162306a36Sopenharmony_ci		rxrpc_conn_states[conn->state];
17262306a36Sopenharmony_ci	seq_printf(seq,
17362306a36Sopenharmony_ci		   "UDP   %-47.47s %-47.47s %4x %08x %s %3u %3d"
17462306a36Sopenharmony_ci		   " %s %08x %08x %08x %08x %08x %08x %08x\n",
17562306a36Sopenharmony_ci		   lbuff,
17662306a36Sopenharmony_ci		   rbuff,
17762306a36Sopenharmony_ci		   conn->service_id,
17862306a36Sopenharmony_ci		   conn->proto.cid,
17962306a36Sopenharmony_ci		   rxrpc_conn_is_service(conn) ? "Svc" : "Clt",
18062306a36Sopenharmony_ci		   refcount_read(&conn->ref),
18162306a36Sopenharmony_ci		   atomic_read(&conn->active),
18262306a36Sopenharmony_ci		   state,
18362306a36Sopenharmony_ci		   key_serial(conn->key),
18462306a36Sopenharmony_ci		   conn->tx_serial,
18562306a36Sopenharmony_ci		   conn->hi_serial,
18662306a36Sopenharmony_ci		   conn->channels[0].call_id,
18762306a36Sopenharmony_ci		   conn->channels[1].call_id,
18862306a36Sopenharmony_ci		   conn->channels[2].call_id,
18962306a36Sopenharmony_ci		   conn->channels[3].call_id);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return 0;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ciconst struct seq_operations rxrpc_connection_seq_ops = {
19562306a36Sopenharmony_ci	.start  = rxrpc_connection_seq_start,
19662306a36Sopenharmony_ci	.next   = rxrpc_connection_seq_next,
19762306a36Sopenharmony_ci	.stop   = rxrpc_connection_seq_stop,
19862306a36Sopenharmony_ci	.show   = rxrpc_connection_seq_show,
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci * generate a list of extant virtual peers in /proc/net/rxrpc/peers
20362306a36Sopenharmony_ci */
20462306a36Sopenharmony_cistatic int rxrpc_peer_seq_show(struct seq_file *seq, void *v)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	struct rxrpc_peer *peer;
20762306a36Sopenharmony_ci	time64_t now;
20862306a36Sopenharmony_ci	char lbuff[50], rbuff[50];
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
21162306a36Sopenharmony_ci		seq_puts(seq,
21262306a36Sopenharmony_ci			 "Proto Local                                          "
21362306a36Sopenharmony_ci			 " Remote                                         "
21462306a36Sopenharmony_ci			 " Use SST   MTU LastUse      RTT      RTO\n"
21562306a36Sopenharmony_ci			 );
21662306a36Sopenharmony_ci		return 0;
21762306a36Sopenharmony_ci	}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	peer = list_entry(v, struct rxrpc_peer, hash_link);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	sprintf(lbuff, "%pISpc", &peer->local->srx.transport);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	sprintf(rbuff, "%pISpc", &peer->srx.transport);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	now = ktime_get_seconds();
22662306a36Sopenharmony_ci	seq_printf(seq,
22762306a36Sopenharmony_ci		   "UDP   %-47.47s %-47.47s %3u"
22862306a36Sopenharmony_ci		   " %3u %5u %6llus %8u %8u\n",
22962306a36Sopenharmony_ci		   lbuff,
23062306a36Sopenharmony_ci		   rbuff,
23162306a36Sopenharmony_ci		   refcount_read(&peer->ref),
23262306a36Sopenharmony_ci		   peer->cong_ssthresh,
23362306a36Sopenharmony_ci		   peer->mtu,
23462306a36Sopenharmony_ci		   now - peer->last_tx_at,
23562306a36Sopenharmony_ci		   peer->srtt_us >> 3,
23662306a36Sopenharmony_ci		   jiffies_to_usecs(peer->rto_j));
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	return 0;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void *rxrpc_peer_seq_start(struct seq_file *seq, loff_t *_pos)
24262306a36Sopenharmony_ci	__acquires(rcu)
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
24562306a36Sopenharmony_ci	unsigned int bucket, n;
24662306a36Sopenharmony_ci	unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
24762306a36Sopenharmony_ci	void *p;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	rcu_read_lock();
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (*_pos >= UINT_MAX)
25262306a36Sopenharmony_ci		return NULL;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	n = *_pos & ((1U << shift) - 1);
25562306a36Sopenharmony_ci	bucket = *_pos >> shift;
25662306a36Sopenharmony_ci	for (;;) {
25762306a36Sopenharmony_ci		if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
25862306a36Sopenharmony_ci			*_pos = UINT_MAX;
25962306a36Sopenharmony_ci			return NULL;
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci		if (n == 0) {
26262306a36Sopenharmony_ci			if (bucket == 0)
26362306a36Sopenharmony_ci				return SEQ_START_TOKEN;
26462306a36Sopenharmony_ci			*_pos += 1;
26562306a36Sopenharmony_ci			n++;
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
26962306a36Sopenharmony_ci		if (p)
27062306a36Sopenharmony_ci			return p;
27162306a36Sopenharmony_ci		bucket++;
27262306a36Sopenharmony_ci		n = 1;
27362306a36Sopenharmony_ci		*_pos = (bucket << shift) | n;
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistatic void *rxrpc_peer_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
28062306a36Sopenharmony_ci	unsigned int bucket, n;
28162306a36Sopenharmony_ci	unsigned int shift = 32 - HASH_BITS(rxnet->peer_hash);
28262306a36Sopenharmony_ci	void *p;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (*_pos >= UINT_MAX)
28562306a36Sopenharmony_ci		return NULL;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	bucket = *_pos >> shift;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	p = seq_hlist_next_rcu(v, &rxnet->peer_hash[bucket], _pos);
29062306a36Sopenharmony_ci	if (p)
29162306a36Sopenharmony_ci		return p;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	for (;;) {
29462306a36Sopenharmony_ci		bucket++;
29562306a36Sopenharmony_ci		n = 1;
29662306a36Sopenharmony_ci		*_pos = (bucket << shift) | n;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci		if (bucket >= HASH_SIZE(rxnet->peer_hash)) {
29962306a36Sopenharmony_ci			*_pos = UINT_MAX;
30062306a36Sopenharmony_ci			return NULL;
30162306a36Sopenharmony_ci		}
30262306a36Sopenharmony_ci		if (n == 0) {
30362306a36Sopenharmony_ci			*_pos += 1;
30462306a36Sopenharmony_ci			n++;
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		p = seq_hlist_start_rcu(&rxnet->peer_hash[bucket], n - 1);
30862306a36Sopenharmony_ci		if (p)
30962306a36Sopenharmony_ci			return p;
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_cistatic void rxrpc_peer_seq_stop(struct seq_file *seq, void *v)
31462306a36Sopenharmony_ci	__releases(rcu)
31562306a36Sopenharmony_ci{
31662306a36Sopenharmony_ci	rcu_read_unlock();
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ciconst struct seq_operations rxrpc_peer_seq_ops = {
32162306a36Sopenharmony_ci	.start  = rxrpc_peer_seq_start,
32262306a36Sopenharmony_ci	.next   = rxrpc_peer_seq_next,
32362306a36Sopenharmony_ci	.stop   = rxrpc_peer_seq_stop,
32462306a36Sopenharmony_ci	.show   = rxrpc_peer_seq_show,
32562306a36Sopenharmony_ci};
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci/*
32862306a36Sopenharmony_ci * Generate a list of extant virtual local endpoints in /proc/net/rxrpc/locals
32962306a36Sopenharmony_ci */
33062306a36Sopenharmony_cistatic int rxrpc_local_seq_show(struct seq_file *seq, void *v)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	struct rxrpc_local *local;
33362306a36Sopenharmony_ci	char lbuff[50];
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (v == SEQ_START_TOKEN) {
33662306a36Sopenharmony_ci		seq_puts(seq,
33762306a36Sopenharmony_ci			 "Proto Local                                          "
33862306a36Sopenharmony_ci			 " Use Act RxQ\n");
33962306a36Sopenharmony_ci		return 0;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	local = hlist_entry(v, struct rxrpc_local, link);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	sprintf(lbuff, "%pISpc", &local->srx.transport);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	seq_printf(seq,
34762306a36Sopenharmony_ci		   "UDP   %-47.47s %3u %3u %3u\n",
34862306a36Sopenharmony_ci		   lbuff,
34962306a36Sopenharmony_ci		   refcount_read(&local->ref),
35062306a36Sopenharmony_ci		   atomic_read(&local->active_users),
35162306a36Sopenharmony_ci		   local->rx_queue.qlen);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	return 0;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_cistatic void *rxrpc_local_seq_start(struct seq_file *seq, loff_t *_pos)
35762306a36Sopenharmony_ci	__acquires(rcu)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
36062306a36Sopenharmony_ci	unsigned int n;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	rcu_read_lock();
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (*_pos >= UINT_MAX)
36562306a36Sopenharmony_ci		return NULL;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	n = *_pos;
36862306a36Sopenharmony_ci	if (n == 0)
36962306a36Sopenharmony_ci		return SEQ_START_TOKEN;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return seq_hlist_start_rcu(&rxnet->local_endpoints, n - 1);
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic void *rxrpc_local_seq_next(struct seq_file *seq, void *v, loff_t *_pos)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (*_pos >= UINT_MAX)
37962306a36Sopenharmony_ci		return NULL;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return seq_hlist_next_rcu(v, &rxnet->local_endpoints, _pos);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void rxrpc_local_seq_stop(struct seq_file *seq, void *v)
38562306a36Sopenharmony_ci	__releases(rcu)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	rcu_read_unlock();
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciconst struct seq_operations rxrpc_local_seq_ops = {
39162306a36Sopenharmony_ci	.start  = rxrpc_local_seq_start,
39262306a36Sopenharmony_ci	.next   = rxrpc_local_seq_next,
39362306a36Sopenharmony_ci	.stop   = rxrpc_local_seq_stop,
39462306a36Sopenharmony_ci	.show   = rxrpc_local_seq_show,
39562306a36Sopenharmony_ci};
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci/*
39862306a36Sopenharmony_ci * Display stats in /proc/net/rxrpc/stats
39962306a36Sopenharmony_ci */
40062306a36Sopenharmony_ciint rxrpc_stats_show(struct seq_file *seq, void *v)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_single_net(seq));
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	seq_printf(seq,
40562306a36Sopenharmony_ci		   "Data     : send=%u sendf=%u fail=%u\n",
40662306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_send),
40762306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_send_frag),
40862306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_send_fail));
40962306a36Sopenharmony_ci	seq_printf(seq,
41062306a36Sopenharmony_ci		   "Data-Tx  : nr=%u retrans=%u uf=%u cwr=%u\n",
41162306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data),
41262306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_retrans),
41362306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_underflow),
41462306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_data_cwnd_reset));
41562306a36Sopenharmony_ci	seq_printf(seq,
41662306a36Sopenharmony_ci		   "Data-Rx  : nr=%u reqack=%u jumbo=%u\n",
41762306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_data),
41862306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_data_reqack),
41962306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_data_jumbo));
42062306a36Sopenharmony_ci	seq_printf(seq,
42162306a36Sopenharmony_ci		   "Ack      : fill=%u send=%u skip=%u\n",
42262306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_ack_fill),
42362306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_ack_send),
42462306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_ack_skip));
42562306a36Sopenharmony_ci	seq_printf(seq,
42662306a36Sopenharmony_ci		   "Ack-Tx   : req=%u dup=%u oos=%u exw=%u nos=%u png=%u prs=%u dly=%u idl=%u\n",
42762306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_REQUESTED]),
42862306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_DUPLICATE]),
42962306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_OUT_OF_SEQUENCE]),
43062306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_EXCEEDS_WINDOW]),
43162306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_NOSPACE]),
43262306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_PING]),
43362306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_PING_RESPONSE]),
43462306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_DELAY]),
43562306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_tx_acks[RXRPC_ACK_IDLE]));
43662306a36Sopenharmony_ci	seq_printf(seq,
43762306a36Sopenharmony_ci		   "Ack-Rx   : req=%u dup=%u oos=%u exw=%u nos=%u png=%u prs=%u dly=%u idl=%u\n",
43862306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_REQUESTED]),
43962306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_DUPLICATE]),
44062306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_OUT_OF_SEQUENCE]),
44162306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_EXCEEDS_WINDOW]),
44262306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_NOSPACE]),
44362306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_PING]),
44462306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_PING_RESPONSE]),
44562306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_DELAY]),
44662306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_rx_acks[RXRPC_ACK_IDLE]));
44762306a36Sopenharmony_ci	seq_printf(seq,
44862306a36Sopenharmony_ci		   "Why-Req-A: acklost=%u already=%u mrtt=%u ortt=%u\n",
44962306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_ack_lost]),
45062306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_already_on]),
45162306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_more_rtt]),
45262306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_old_rtt]));
45362306a36Sopenharmony_ci	seq_printf(seq,
45462306a36Sopenharmony_ci		   "Why-Req-A: nolast=%u retx=%u slows=%u smtxw=%u\n",
45562306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_no_srv_last]),
45662306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_retrans]),
45762306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_slow_start]),
45862306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_why_req_ack[rxrpc_reqack_small_txwin]));
45962306a36Sopenharmony_ci	seq_printf(seq,
46062306a36Sopenharmony_ci		   "Buffers  : txb=%u rxb=%u\n",
46162306a36Sopenharmony_ci		   atomic_read(&rxrpc_nr_txbuf),
46262306a36Sopenharmony_ci		   atomic_read(&rxrpc_n_rx_skbs));
46362306a36Sopenharmony_ci	seq_printf(seq,
46462306a36Sopenharmony_ci		   "IO-thread: loops=%u\n",
46562306a36Sopenharmony_ci		   atomic_read(&rxnet->stat_io_loop));
46662306a36Sopenharmony_ci	return 0;
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci/*
47062306a36Sopenharmony_ci * Clear stats if /proc/net/rxrpc/stats is written to.
47162306a36Sopenharmony_ci */
47262306a36Sopenharmony_ciint rxrpc_stats_clear(struct file *file, char *buf, size_t size)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct seq_file *m = file->private_data;
47562306a36Sopenharmony_ci	struct rxrpc_net *rxnet = rxrpc_net(seq_file_single_net(m));
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (size > 1 || (size == 1 && buf[0] != '\n'))
47862306a36Sopenharmony_ci		return -EINVAL;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data, 0);
48162306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_retrans, 0);
48262306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_underflow, 0);
48362306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_cwnd_reset, 0);
48462306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_send, 0);
48562306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_send_frag, 0);
48662306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_data_send_fail, 0);
48762306a36Sopenharmony_ci	atomic_set(&rxnet->stat_rx_data, 0);
48862306a36Sopenharmony_ci	atomic_set(&rxnet->stat_rx_data_reqack, 0);
48962306a36Sopenharmony_ci	atomic_set(&rxnet->stat_rx_data_jumbo, 0);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_ack_fill, 0);
49262306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_ack_send, 0);
49362306a36Sopenharmony_ci	atomic_set(&rxnet->stat_tx_ack_skip, 0);
49462306a36Sopenharmony_ci	memset(&rxnet->stat_tx_acks, 0, sizeof(rxnet->stat_tx_acks));
49562306a36Sopenharmony_ci	memset(&rxnet->stat_rx_acks, 0, sizeof(rxnet->stat_rx_acks));
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	memset(&rxnet->stat_why_req_ack, 0, sizeof(rxnet->stat_why_req_ack));
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	atomic_set(&rxnet->stat_io_loop, 0);
50062306a36Sopenharmony_ci	return size;
50162306a36Sopenharmony_ci}
502