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