projects/linux·blob master · refs

245 lines · 5.7 KiB

1// SPDX-License-Identifier: GPL-2.0
2/*
3 * proc_llc.c - proc interface for LLC
4 *
5 * Copyright (c) 2001 by Jay Schulist <[email protected]>
6 * 2002-2003 by Arnaldo Carvalho de Melo <[email protected]>
7 */
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/proc_fs.h>
12#include <linux/errno.h>
13#include <linux/seq_file.h>
14#include <linux/export.h>
15#include <net/net_namespace.h>
16#include <net/sock.h>
17#include <net/llc.h>
18#include <net/llc_c_ac.h>
19#include <net/llc_c_ev.h>
20#include <net/llc_c_st.h>
21#include <net/llc_conn.h>
22
23static void llc_ui_format_mac(struct seq_file *seq, const u8 *addr)
24{
25 seq_printf(seq, "%pM", addr);
26}
27
28static struct sock *llc_get_sk_idx(loff_t pos)
29{
30 struct llc_sap *sap;
31 struct sock *sk = NULL;
32 int i;
33
34 list_for_each_entry_rcu(sap, &llc_sap_list, node) {
35 spin_lock_bh(&sap->sk_lock);
36 for (i = 0; i < LLC_SK_LADDR_HASH_ENTRIES; i++) {
37 struct hlist_nulls_head *head = &sap->sk_laddr_hash[i];
38 struct hlist_nulls_node *node;
39
40 sk_nulls_for_each(sk, node, head) {
41 if (!pos)
42 goto found; /* keep the lock */
43 --pos;
44 }
45 }
46 spin_unlock_bh(&sap->sk_lock);
47 }
48 sk = NULL;
49found:
50 return sk;
51}
52
53static void *llc_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU)
54{
55 loff_t l = *pos;
56
57 rcu_read_lock_bh();
58 return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
59}
60
61static struct sock *laddr_hash_next(struct llc_sap *sap, int bucket)
62{
63 struct hlist_nulls_node *node;
64 struct sock *sk = NULL;
65
66 while (++bucket < LLC_SK_LADDR_HASH_ENTRIES)
67 sk_nulls_for_each(sk, node, &sap->sk_laddr_hash[bucket])
68 goto out;
69
70out:
71 return sk;
72}
73
74static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
75{
76 struct sock* sk, *next;
77 struct llc_sock *llc;
78 struct llc_sap *sap;
79
80 ++*pos;
81 if (v == SEQ_START_TOKEN) {
82 sk = llc_get_sk_idx(0);
83 goto out;
84 }
85 sk = v;
86 next = sk_nulls_next(sk);
87 if (next) {
88 sk = next;
89 goto out;
90 }
91 llc = llc_sk(sk);
92 sap = llc->sap;
93 sk = laddr_hash_next(sap, llc_sk_laddr_hashfn(sap, &llc->laddr));
94 if (sk)
95 goto out;
96 spin_unlock_bh(&sap->sk_lock);
97 list_for_each_entry_continue_rcu(sap, &llc_sap_list, node) {
98 spin_lock_bh(&sap->sk_lock);
99 sk = laddr_hash_next(sap, -1);
100 if (sk)
101 break; /* keep the lock */
102 spin_unlock_bh(&sap->sk_lock);
103 }
104out:
105 return sk;
106}
107
108static void llc_seq_stop(struct seq_file *seq, void *v)
109{
110 if (v && v != SEQ_START_TOKEN) {
111 struct sock *sk = v;
112 struct llc_sock *llc = llc_sk(sk);
113 struct llc_sap *sap = llc->sap;
114
115 spin_unlock_bh(&sap->sk_lock);
116 }
117 rcu_read_unlock_bh();
118}
119
120static int llc_seq_socket_show(struct seq_file *seq, void *v)
121{
122 struct sock* sk;
123 struct llc_sock *llc;
124
125 if (v == SEQ_START_TOKEN) {
126 seq_puts(seq, "SKt Mc local_mac_sap remote_mac_sap "
127 " tx_queue rx_queue st uid link\n");
128 goto out;
129 }
130 sk = v;
131 llc = llc_sk(sk);
132
133 /* FIXME: check if the address is multicast */
134 seq_printf(seq, "%2X %2X ", sk->sk_type, 0);
135
136 if (llc->dev)
137 llc_ui_format_mac(seq, llc->dev->dev_addr);
138 else {
139 u8 addr[6] = {0,0,0,0,0,0};
140 llc_ui_format_mac(seq, addr);
141 }
142 seq_printf(seq, "@%02X ", llc->sap->laddr.lsap);
143 llc_ui_format_mac(seq, llc->daddr.mac);
144 seq_printf(seq, "@%02X %8d %8d %2d %3u %4d\n", llc->daddr.lsap,
145 sk_wmem_alloc_get(sk),
146 sk_rmem_alloc_get(sk) - llc->copied_seq,
147 sk->sk_state,
148 from_kuid_munged(seq_user_ns(seq), sk_uid(sk)),
149 llc->link);
150out:
151 return 0;
152}
153
154static const char *const llc_conn_state_names[] = {
155 [LLC_CONN_STATE_ADM] = "adm",
156 [LLC_CONN_STATE_SETUP] = "setup",
157 [LLC_CONN_STATE_NORMAL] = "normal",
158 [LLC_CONN_STATE_BUSY] = "busy",
159 [LLC_CONN_STATE_REJ] = "rej",
160 [LLC_CONN_STATE_AWAIT] = "await",
161 [LLC_CONN_STATE_AWAIT_BUSY] = "await_busy",
162 [LLC_CONN_STATE_AWAIT_REJ] = "await_rej",
163 [LLC_CONN_STATE_D_CONN] = "d_conn",
164 [LLC_CONN_STATE_RESET] = "reset",
165 [LLC_CONN_STATE_ERROR] = "error",
166 [LLC_CONN_STATE_TEMP] = "temp",
167};
168
169static int llc_seq_core_show(struct seq_file *seq, void *v)
170{
171 struct sock* sk;
172 struct llc_sock *llc;
173
174 if (v == SEQ_START_TOKEN) {
175 seq_puts(seq, "Connection list:\n"
176 "dsap state retr txw rxw pf ff sf df rs cs "
177 "tack tpfc trs tbs blog busr\n");
178 goto out;
179 }
180 sk = v;
181 llc = llc_sk(sk);
182
183 seq_printf(seq, " %02X %-10s %3d %3d %3d %2d %2d %2d %2d %2d %2d "
184 "%4d %4d %3d %3d %4d %4d\n",
185 llc->daddr.lsap, llc_conn_state_names[llc->state],
186 llc->retry_count, llc->k, llc->rw, llc->p_flag, llc->f_flag,
187 llc->s_flag, llc->data_flag, llc->remote_busy_flag,
188 llc->cause_flag, timer_pending(&llc->ack_timer.timer),
189 timer_pending(&llc->pf_cycle_timer.timer),
190 timer_pending(&llc->rej_sent_timer.timer),
191 timer_pending(&llc->busy_state_timer.timer),
192 !!sk->sk_backlog.tail, sock_owned_by_user_nocheck(sk));
193out:
194 return 0;
195}
196
197static const struct seq_operations llc_seq_socket_ops = {
198 .start = llc_seq_start,
199 .next = llc_seq_next,
200 .stop = llc_seq_stop,
201 .show = llc_seq_socket_show,
202};
203
204static const struct seq_operations llc_seq_core_ops = {
205 .start = llc_seq_start,
206 .next = llc_seq_next,
207 .stop = llc_seq_stop,
208 .show = llc_seq_core_show,
209};
210
211static struct proc_dir_entry *llc_proc_dir;
212
213int __init llc_proc_init(void)
214{
215 int rc = -ENOMEM;
216 struct proc_dir_entry *p;
217
218 llc_proc_dir = proc_mkdir("llc", init_net.proc_net);
219 if (!llc_proc_dir)
220 goto out;
221
222 p = proc_create_seq("socket", 0444, llc_proc_dir, &llc_seq_socket_ops);
223 if (!p)
224 goto out_socket;
225
226 p = proc_create_seq("core", 0444, llc_proc_dir, &llc_seq_core_ops);
227 if (!p)
228 goto out_core;
229
230 rc = 0;
231out:
232 return rc;
233out_core:
234 remove_proc_entry("socket", llc_proc_dir);
235out_socket:
236 remove_proc_entry("llc", init_net.proc_net);
237 goto out;
238}
239
240void llc_proc_exit(void)
241{
242 remove_proc_entry("socket", llc_proc_dir);
243 remove_proc_entry("core", llc_proc_dir);
244 remove_proc_entry("llc", init_net.proc_net);
245}