4 * Copyright(C) Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2002
7 #include <linux/init.h>
9 #include <linux/proc_fs.h>
10 #include <linux/spinlock.h>
11 #include <linux/seq_file.h>
12 #include <net/net_namespace.h>
13 #include <net/tcp_states.h>
16 static __inline__
struct ipx_interface
*ipx_get_interface_idx(loff_t pos
)
18 struct ipx_interface
*i
;
20 list_for_each_entry(i
, &ipx_interfaces
, node
)
28 static struct ipx_interface
*ipx_interfaces_next(struct ipx_interface
*i
)
30 struct ipx_interface
*rc
= NULL
;
32 if (i
->node
.next
!= &ipx_interfaces
)
33 rc
= list_entry(i
->node
.next
, struct ipx_interface
, node
);
37 static void *ipx_seq_interface_start(struct seq_file
*seq
, loff_t
*pos
)
41 spin_lock_bh(&ipx_interfaces_lock
);
42 return l
? ipx_get_interface_idx(--l
) : SEQ_START_TOKEN
;
45 static void *ipx_seq_interface_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
47 struct ipx_interface
*i
;
50 if (v
== SEQ_START_TOKEN
)
51 i
= ipx_interfaces_head();
53 i
= ipx_interfaces_next(v
);
57 static void ipx_seq_interface_stop(struct seq_file
*seq
, void *v
)
59 spin_unlock_bh(&ipx_interfaces_lock
);
62 static int ipx_seq_interface_show(struct seq_file
*seq
, void *v
)
64 struct ipx_interface
*i
;
66 if (v
== SEQ_START_TOKEN
) {
67 seq_puts(seq
, "Network Node_Address Primary Device "
69 #ifdef IPX_REFCNT_DEBUG
70 seq_puts(seq
, " refcnt");
77 seq_printf(seq
, "%08lX ", (unsigned long int)ntohl(i
->if_netnum
));
78 seq_printf(seq
, "%02X%02X%02X%02X%02X%02X ",
79 i
->if_node
[0], i
->if_node
[1], i
->if_node
[2],
80 i
->if_node
[3], i
->if_node
[4], i
->if_node
[5]);
81 seq_printf(seq
, "%-9s", i
== ipx_primary_net
? "Yes" : "No");
82 seq_printf(seq
, "%-11s", ipx_device_name(i
));
83 seq_printf(seq
, "%-9s", ipx_frame_name(i
->if_dlink_type
));
84 #ifdef IPX_REFCNT_DEBUG
85 seq_printf(seq
, "%6d", atomic_read(&i
->refcnt
));
92 static struct ipx_route
*ipx_routes_head(void)
94 struct ipx_route
*rc
= NULL
;
96 if (!list_empty(&ipx_routes
))
97 rc
= list_entry(ipx_routes
.next
, struct ipx_route
, node
);
101 static struct ipx_route
*ipx_routes_next(struct ipx_route
*r
)
103 struct ipx_route
*rc
= NULL
;
105 if (r
->node
.next
!= &ipx_routes
)
106 rc
= list_entry(r
->node
.next
, struct ipx_route
, node
);
110 static __inline__
struct ipx_route
*ipx_get_route_idx(loff_t pos
)
114 list_for_each_entry(r
, &ipx_routes
, node
)
122 static void *ipx_seq_route_start(struct seq_file
*seq
, loff_t
*pos
)
125 read_lock_bh(&ipx_routes_lock
);
126 return l
? ipx_get_route_idx(--l
) : SEQ_START_TOKEN
;
129 static void *ipx_seq_route_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
134 if (v
== SEQ_START_TOKEN
)
135 r
= ipx_routes_head();
137 r
= ipx_routes_next(v
);
141 static void ipx_seq_route_stop(struct seq_file
*seq
, void *v
)
143 read_unlock_bh(&ipx_routes_lock
);
146 static int ipx_seq_route_show(struct seq_file
*seq
, void *v
)
148 struct ipx_route
*rt
;
150 if (v
== SEQ_START_TOKEN
) {
151 seq_puts(seq
, "Network Router_Net Router_Node\n");
155 seq_printf(seq
, "%08lX ", (unsigned long int)ntohl(rt
->ir_net
));
157 seq_printf(seq
, "%08lX %02X%02X%02X%02X%02X%02X\n",
158 (long unsigned int)ntohl(rt
->ir_intrfc
->if_netnum
),
159 rt
->ir_router_node
[0], rt
->ir_router_node
[1],
160 rt
->ir_router_node
[2], rt
->ir_router_node
[3],
161 rt
->ir_router_node
[4], rt
->ir_router_node
[5]);
163 seq_puts(seq
, "Directly Connected\n");
168 static __inline__
struct sock
*ipx_get_socket_idx(loff_t pos
)
170 struct sock
*s
= NULL
;
171 struct hlist_node
*node
;
172 struct ipx_interface
*i
;
174 list_for_each_entry(i
, &ipx_interfaces
, node
) {
175 spin_lock_bh(&i
->if_sklist_lock
);
176 sk_for_each(s
, node
, &i
->if_sklist
) {
181 spin_unlock_bh(&i
->if_sklist_lock
);
193 static void *ipx_seq_socket_start(struct seq_file
*seq
, loff_t
*pos
)
197 spin_lock_bh(&ipx_interfaces_lock
);
198 return l
? ipx_get_socket_idx(--l
) : SEQ_START_TOKEN
;
201 static void *ipx_seq_socket_next(struct seq_file
*seq
, void *v
, loff_t
*pos
)
203 struct sock
* sk
, *next
;
204 struct ipx_interface
*i
;
205 struct ipx_sock
*ipxs
;
208 if (v
== SEQ_START_TOKEN
) {
210 i
= ipx_interfaces_head();
213 sk
= sk_head(&i
->if_sklist
);
215 spin_lock_bh(&i
->if_sklist_lock
);
226 spin_unlock_bh(&i
->if_sklist_lock
);
229 i
= ipx_interfaces_next(i
);
232 spin_lock_bh(&i
->if_sklist_lock
);
233 if (!hlist_empty(&i
->if_sklist
)) {
234 sk
= sk_head(&i
->if_sklist
);
237 spin_unlock_bh(&i
->if_sklist_lock
);
243 static int ipx_seq_socket_show(struct seq_file
*seq
, void *v
)
246 struct ipx_sock
*ipxs
;
248 if (v
== SEQ_START_TOKEN
) {
249 #ifdef CONFIG_IPX_INTERN
250 seq_puts(seq
, "Local_Address "
251 "Remote_Address Tx_Queue "
252 "Rx_Queue State Uid\n");
254 seq_puts(seq
, "Local_Address Remote_Address "
255 "Tx_Queue Rx_Queue State Uid\n");
262 #ifdef CONFIG_IPX_INTERN
263 seq_printf(seq
, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
264 (unsigned long)ntohl(ipxs
->intrfc
->if_netnum
),
265 ipxs
->node
[0], ipxs
->node
[1], ipxs
->node
[2], ipxs
->node
[3],
266 ipxs
->node
[4], ipxs
->node
[5], ntohs(ipxs
->port
));
268 seq_printf(seq
, "%08lX:%04X ", (unsigned long) ntohl(ipxs
->intrfc
->if_netnum
),
270 #endif /* CONFIG_IPX_INTERN */
271 if (s
->sk_state
!= TCP_ESTABLISHED
)
272 seq_printf(seq
, "%-28s", "Not_Connected");
274 seq_printf(seq
, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
275 (unsigned long)ntohl(ipxs
->dest_addr
.net
),
276 ipxs
->dest_addr
.node
[0], ipxs
->dest_addr
.node
[1],
277 ipxs
->dest_addr
.node
[2], ipxs
->dest_addr
.node
[3],
278 ipxs
->dest_addr
.node
[4], ipxs
->dest_addr
.node
[5],
279 ntohs(ipxs
->dest_addr
.sock
));
282 seq_printf(seq
, "%08X %08X %02X %03d\n",
283 atomic_read(&s
->sk_wmem_alloc
),
284 atomic_read(&s
->sk_rmem_alloc
),
285 s
->sk_state
, SOCK_INODE(s
->sk_socket
)->i_uid
);
290 static const struct seq_operations ipx_seq_interface_ops
= {
291 .start
= ipx_seq_interface_start
,
292 .next
= ipx_seq_interface_next
,
293 .stop
= ipx_seq_interface_stop
,
294 .show
= ipx_seq_interface_show
,
297 static const struct seq_operations ipx_seq_route_ops
= {
298 .start
= ipx_seq_route_start
,
299 .next
= ipx_seq_route_next
,
300 .stop
= ipx_seq_route_stop
,
301 .show
= ipx_seq_route_show
,
304 static const struct seq_operations ipx_seq_socket_ops
= {
305 .start
= ipx_seq_socket_start
,
306 .next
= ipx_seq_socket_next
,
307 .stop
= ipx_seq_interface_stop
,
308 .show
= ipx_seq_socket_show
,
311 static int ipx_seq_route_open(struct inode
*inode
, struct file
*file
)
313 return seq_open(file
, &ipx_seq_route_ops
);
316 static int ipx_seq_interface_open(struct inode
*inode
, struct file
*file
)
318 return seq_open(file
, &ipx_seq_interface_ops
);
321 static int ipx_seq_socket_open(struct inode
*inode
, struct file
*file
)
323 return seq_open(file
, &ipx_seq_socket_ops
);
326 static const struct file_operations ipx_seq_interface_fops
= {
327 .owner
= THIS_MODULE
,
328 .open
= ipx_seq_interface_open
,
331 .release
= seq_release
,
334 static const struct file_operations ipx_seq_route_fops
= {
335 .owner
= THIS_MODULE
,
336 .open
= ipx_seq_route_open
,
339 .release
= seq_release
,
342 static const struct file_operations ipx_seq_socket_fops
= {
343 .owner
= THIS_MODULE
,
344 .open
= ipx_seq_socket_open
,
347 .release
= seq_release
,
350 static struct proc_dir_entry
*ipx_proc_dir
;
352 int __init
ipx_proc_init(void)
354 struct proc_dir_entry
*p
;
357 ipx_proc_dir
= proc_mkdir("ipx", init_net
.proc_net
);
361 p
= proc_create("interface", S_IRUGO
,
362 ipx_proc_dir
, &ipx_seq_interface_fops
);
366 p
= proc_create("route", S_IRUGO
, ipx_proc_dir
, &ipx_seq_route_fops
);
370 p
= proc_create("socket", S_IRUGO
, ipx_proc_dir
, &ipx_seq_socket_fops
);
378 remove_proc_entry("route", ipx_proc_dir
);
380 remove_proc_entry("interface", ipx_proc_dir
);
382 remove_proc_entry("ipx", init_net
.proc_net
);
386 void __exit
ipx_proc_exit(void)
388 remove_proc_entry("interface", ipx_proc_dir
);
389 remove_proc_entry("route", ipx_proc_dir
);
390 remove_proc_entry("socket", ipx_proc_dir
);
391 remove_proc_entry("ipx", init_net
.proc_net
);
394 #else /* CONFIG_PROC_FS */
396 int __init
ipx_proc_init(void)
401 void __exit
ipx_proc_exit(void)
405 #endif /* CONFIG_PROC_FS */