1 // SPDX-License-Identifier: GPL-2.0
2 /* net/atm/proc.c - ATM /proc interface
4 * Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA
6 * seq_file api usage by romieu@fr.zoreil.com
8 * Evaluating the efficiency of the whole thing if left as an exercise to
12 #include <linux/module.h> /* for EXPORT_SYMBOL */
13 #include <linux/string.h>
14 #include <linux/types.h>
17 #include <linux/stat.h>
18 #include <linux/proc_fs.h>
19 #include <linux/seq_file.h>
20 #include <linux/errno.h>
21 #include <linux/atm.h>
22 #include <linux/atmdev.h>
23 #include <linux/netdevice.h>
24 #include <linux/atmclip.h>
25 #include <linux/init.h> /* for __init */
26 #include <linux/slab.h>
27 #include <net/net_namespace.h>
28 #include <net/atmclip.h>
29 #include <linux/uaccess.h>
30 #include <linux/param.h> /* for HZ */
31 #include <linux/atomic.h>
32 #include "resources.h"
33 #include "common.h" /* atm_proc_init prototype */
34 #include "signaling.h" /* to get sigd - ugly too */
36 static ssize_t
proc_dev_atm_read(struct file
*file
, char __user
*buf
,
37 size_t count
, loff_t
*pos
);
39 static const struct file_operations proc_atm_dev_ops
= {
40 .read
= proc_dev_atm_read
,
41 .llseek
= noop_llseek
,
44 static void add_stats(struct seq_file
*seq
, const char *aal
,
45 const struct k_atm_aal_stats
*stats
)
47 seq_printf(seq
, "%s ( %d %d %d %d %d )", aal
,
48 atomic_read(&stats
->tx
), atomic_read(&stats
->tx_err
),
49 atomic_read(&stats
->rx
), atomic_read(&stats
->rx_err
),
50 atomic_read(&stats
->rx_drop
));
53 static void atm_dev_info(struct seq_file
*seq
, const struct atm_dev
*dev
)
57 seq_printf(seq
, "%3d %-8s", dev
->number
, dev
->type
);
58 for (i
= 0; i
< ESI_LEN
; i
++)
59 seq_printf(seq
, "%02x", dev
->esi
[i
]);
61 add_stats(seq
, "0", &dev
->stats
.aal0
);
63 add_stats(seq
, "5", &dev
->stats
.aal5
);
64 seq_printf(seq
, "\t[%d]", refcount_read(&dev
->refcnt
));
73 static inline int compare_family(struct sock
*sk
, int family
)
75 return !family
|| (sk
->sk_family
== family
);
78 static int __vcc_walk(struct sock
**sock
, int family
, int *bucket
, loff_t l
)
80 struct sock
*sk
= *sock
;
82 if (sk
== SEQ_START_TOKEN
) {
83 for (*bucket
= 0; *bucket
< VCC_HTABLE_SIZE
; ++*bucket
) {
84 struct hlist_head
*head
= &vcc_hash
[*bucket
];
86 sk
= hlist_empty(head
) ? NULL
: __sk_head(head
);
93 for (; sk
; sk
= sk_next(sk
)) {
94 l
-= compare_family(sk
, family
);
98 if (!sk
&& ++*bucket
< VCC_HTABLE_SIZE
) {
99 sk
= sk_head(&vcc_hash
[*bucket
]);
102 sk
= SEQ_START_TOKEN
;
108 static inline void *vcc_walk(struct seq_file
*seq
, loff_t l
)
110 struct vcc_state
*state
= seq
->private;
111 int family
= (uintptr_t)(PDE_DATA(file_inode(seq
->file
)));
113 return __vcc_walk(&state
->sk
, family
, &state
->bucket
, l
) ?
117 static void *vcc_seq_start(struct seq_file
*seq
, loff_t
*pos
)
118 __acquires(vcc_sklist_lock
)
120 struct vcc_state
*state
= seq
->private;
123 read_lock(&vcc_sklist_lock
);
124 state
->sk
= SEQ_START_TOKEN
;
125 return left
? vcc_walk(seq
, left
) : SEQ_START_TOKEN
;
128 static void vcc_seq_stop(struct seq_file
*seq
, void *v
)
129 __releases(vcc_sklist_lock
)
131 read_unlock(&vcc_sklist_lock
);
134 static void *vcc_seq_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
136 v
= vcc_walk(seq
, 1);
137 *pos
+= !!PTR_ERR(v
);
141 static void pvc_info(struct seq_file
*seq
, struct atm_vcc
*vcc
)
143 static const char *const class_name
[] = {
144 "off", "UBR", "CBR", "VBR", "ABR"};
145 static const char *const aal_name
[] = {
146 "---", "1", "2", "3/4", /* 0- 3 */
147 "???", "5", "???", "???", /* 4- 7 */
148 "???", "???", "???", "???", /* 8-11 */
149 "???", "0", "???", "???"}; /* 12-15 */
151 seq_printf(seq
, "%3d %3d %5d %-3s %7d %-5s %7d %-6s",
152 vcc
->dev
->number
, vcc
->vpi
, vcc
->vci
,
153 vcc
->qos
.aal
>= ARRAY_SIZE(aal_name
) ? "err" :
154 aal_name
[vcc
->qos
.aal
], vcc
->qos
.rxtp
.min_pcr
,
155 class_name
[vcc
->qos
.rxtp
.traffic_class
],
156 vcc
->qos
.txtp
.min_pcr
,
157 class_name
[vcc
->qos
.txtp
.traffic_class
]);
158 if (test_bit(ATM_VF_IS_CLIP
, &vcc
->flags
)) {
159 struct clip_vcc
*clip_vcc
= CLIP_VCC(vcc
);
160 struct net_device
*dev
;
162 dev
= clip_vcc
->entry
? clip_vcc
->entry
->neigh
->dev
: NULL
;
163 seq_printf(seq
, "CLIP, Itf:%s, Encap:",
164 dev
? dev
->name
: "none?");
165 seq_printf(seq
, "%s", clip_vcc
->encap
? "LLC/SNAP" : "None");
170 static const char *vcc_state(struct atm_vcc
*vcc
)
172 static const char *const map
[] = { ATM_VS2TXT_MAP
};
174 return map
[ATM_VF2VS(vcc
->flags
)];
177 static void vcc_info(struct seq_file
*seq
, struct atm_vcc
*vcc
)
179 struct sock
*sk
= sk_atm(vcc
);
181 seq_printf(seq
, "%pK ", vcc
);
183 seq_printf(seq
, "Unassigned ");
185 seq_printf(seq
, "%3d %3d %5d ", vcc
->dev
->number
, vcc
->vpi
,
187 switch (sk
->sk_family
) {
189 seq_printf(seq
, "PVC");
192 seq_printf(seq
, "SVC");
195 seq_printf(seq
, "%3d", sk
->sk_family
);
197 seq_printf(seq
, " %04lx %5d %7d/%7d %7d/%7d [%d]\n",
198 vcc
->flags
, sk
->sk_err
,
199 sk_wmem_alloc_get(sk
), sk
->sk_sndbuf
,
200 sk_rmem_alloc_get(sk
), sk
->sk_rcvbuf
,
201 refcount_read(&sk
->sk_refcnt
));
204 static void svc_info(struct seq_file
*seq
, struct atm_vcc
*vcc
)
207 seq_printf(seq
, sizeof(void *) == 4 ?
208 "N/A@%pK%10s" : "N/A@%pK%2s", vcc
, "");
210 seq_printf(seq
, "%3d %3d %5d ",
211 vcc
->dev
->number
, vcc
->vpi
, vcc
->vci
);
212 seq_printf(seq
, "%-10s ", vcc_state(vcc
));
213 seq_printf(seq
, "%s%s", vcc
->remote
.sas_addr
.pub
,
214 *vcc
->remote
.sas_addr
.pub
&& *vcc
->remote
.sas_addr
.prv
? "+" : "");
215 if (*vcc
->remote
.sas_addr
.prv
) {
218 for (i
= 0; i
< ATM_ESA_LEN
; i
++)
219 seq_printf(seq
, "%02x", vcc
->remote
.sas_addr
.prv
[i
]);
224 static int atm_dev_seq_show(struct seq_file
*seq
, void *v
)
226 static char atm_dev_banner
[] =
227 "Itf Type ESI/\"MAC\"addr "
228 "AAL(TX,err,RX,err,drop) ... [refcnt]\n";
231 seq_puts(seq
, atm_dev_banner
);
233 struct atm_dev
*dev
= list_entry(v
, struct atm_dev
, dev_list
);
235 atm_dev_info(seq
, dev
);
240 static const struct seq_operations atm_dev_seq_ops
= {
241 .start
= atm_dev_seq_start
,
242 .next
= atm_dev_seq_next
,
243 .stop
= atm_dev_seq_stop
,
244 .show
= atm_dev_seq_show
,
247 static int pvc_seq_show(struct seq_file
*seq
, void *v
)
249 static char atm_pvc_banner
[] =
250 "Itf VPI VCI AAL RX(PCR,Class) TX(PCR,Class)\n";
252 if (v
== SEQ_START_TOKEN
)
253 seq_puts(seq
, atm_pvc_banner
);
255 struct vcc_state
*state
= seq
->private;
256 struct atm_vcc
*vcc
= atm_sk(state
->sk
);
263 static const struct seq_operations pvc_seq_ops
= {
264 .start
= vcc_seq_start
,
265 .next
= vcc_seq_next
,
266 .stop
= vcc_seq_stop
,
267 .show
= pvc_seq_show
,
270 static int vcc_seq_show(struct seq_file
*seq
, void *v
)
272 if (v
== SEQ_START_TOKEN
) {
273 seq_printf(seq
, sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s",
274 "Address ", "Itf VPI VCI Fam Flags Reply "
275 "Send buffer Recv buffer [refcnt]\n");
277 struct vcc_state
*state
= seq
->private;
278 struct atm_vcc
*vcc
= atm_sk(state
->sk
);
285 static const struct seq_operations vcc_seq_ops
= {
286 .start
= vcc_seq_start
,
287 .next
= vcc_seq_next
,
288 .stop
= vcc_seq_stop
,
289 .show
= vcc_seq_show
,
292 static int svc_seq_show(struct seq_file
*seq
, void *v
)
294 static const char atm_svc_banner
[] =
295 "Itf VPI VCI State Remote\n";
297 if (v
== SEQ_START_TOKEN
)
298 seq_puts(seq
, atm_svc_banner
);
300 struct vcc_state
*state
= seq
->private;
301 struct atm_vcc
*vcc
= atm_sk(state
->sk
);
308 static const struct seq_operations svc_seq_ops
= {
309 .start
= vcc_seq_start
,
310 .next
= vcc_seq_next
,
311 .stop
= vcc_seq_stop
,
312 .show
= svc_seq_show
,
315 static ssize_t
proc_dev_atm_read(struct file
*file
, char __user
*buf
,
316 size_t count
, loff_t
*pos
)
324 page
= get_zeroed_page(GFP_KERNEL
);
327 dev
= PDE_DATA(file_inode(file
));
328 if (!dev
->ops
->proc_read
)
331 length
= dev
->ops
->proc_read(dev
, pos
, (char *)page
);
336 if (copy_to_user(buf
, (char *)page
, length
))
344 struct proc_dir_entry
*atm_proc_root
;
345 EXPORT_SYMBOL(atm_proc_root
);
348 int atm_proc_dev_register(struct atm_dev
*dev
)
353 if (!dev
->ops
->proc_read
)
357 dev
->proc_name
= kasprintf(GFP_KERNEL
, "%s:%d", dev
->type
, dev
->number
);
361 dev
->proc_entry
= proc_create_data(dev
->proc_name
, 0, atm_proc_root
,
362 &proc_atm_dev_ops
, dev
);
363 if (!dev
->proc_entry
)
368 kfree(dev
->proc_name
);
373 void atm_proc_dev_deregister(struct atm_dev
*dev
)
375 if (!dev
->ops
->proc_read
)
378 remove_proc_entry(dev
->proc_name
, atm_proc_root
);
379 kfree(dev
->proc_name
);
382 int __init
atm_proc_init(void)
384 atm_proc_root
= proc_net_mkdir(&init_net
, "atm", init_net
.proc_net
);
387 proc_create_seq("devices", 0444, atm_proc_root
, &atm_dev_seq_ops
);
388 proc_create_seq_private("pvc", 0444, atm_proc_root
, &pvc_seq_ops
,
389 sizeof(struct vcc_state
), (void *)(uintptr_t)PF_ATMPVC
);
390 proc_create_seq_private("svc", 0444, atm_proc_root
, &svc_seq_ops
,
391 sizeof(struct vcc_state
), (void *)(uintptr_t)PF_ATMSVC
);
392 proc_create_seq_private("vc", 0444, atm_proc_root
, &vcc_seq_ops
,
393 sizeof(struct vcc_state
), NULL
);
397 void atm_proc_exit(void)
399 remove_proc_subtree("atm", init_net
.proc_net
);