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 */ 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 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 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 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 " UserID 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 %lx %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->user_call_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 */ 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 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 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 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\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 */ 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 Rc\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 %12llu %2u\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->rtt, 247 peer->rtt_cursor); 248 249 return 0; 250 } 251 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 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 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