811e4badce81fd4920d5bb45854d34c1b805fe0f
[linux-2.6.git] / net / ipx / ipx_proc.c
1 /*
2  *      IPX proc routines
3  *
4  *      Copyright(C) Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2002
5  */
6
7 #include <linux/init.h>
8 #ifdef CONFIG_PROC_FS
9 #include <linux/proc_fs.h>
10 #include <linux/spinlock.h>
11 #include <linux/seq_file.h>
12 #include <net/tcp_states.h>
13 #include <net/ipx.h>
14
15 static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos)
16 {
17         struct ipx_interface *i;
18
19         list_for_each_entry(i, &ipx_interfaces, node)
20                 if (!pos--)
21                         goto out;
22         i = NULL;
23 out:
24         return i;
25 }
26
27 static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i)
28 {
29         struct ipx_interface *rc = NULL;
30
31         if (i->node.next != &ipx_interfaces)
32                 rc = list_entry(i->node.next, struct ipx_interface, node);
33         return rc;
34 }
35
36 static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos)
37 {
38         loff_t l = *pos;
39
40         spin_lock_bh(&ipx_interfaces_lock);
41         return l ? ipx_get_interface_idx(--l) : SEQ_START_TOKEN;
42 }
43
44 static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos)
45 {
46         struct ipx_interface *i;
47
48         ++*pos;
49         if (v == SEQ_START_TOKEN)
50                 i = ipx_interfaces_head();
51         else
52                 i = ipx_interfaces_next(v);
53         return i;
54 }
55
56 static void ipx_seq_interface_stop(struct seq_file *seq, void *v)
57 {
58         spin_unlock_bh(&ipx_interfaces_lock);
59 }
60
61 static int ipx_seq_interface_show(struct seq_file *seq, void *v)
62 {
63         struct ipx_interface *i;
64
65         if (v == SEQ_START_TOKEN) {
66                 seq_puts(seq, "Network    Node_Address   Primary  Device     "
67                               "Frame_Type");
68 #ifdef IPX_REFCNT_DEBUG
69                 seq_puts(seq, "  refcnt");
70 #endif
71                 seq_puts(seq, "\n");
72                 goto out;
73         }
74
75         i = v;
76         seq_printf(seq, "%08lX   ", (unsigned long int)ntohl(i->if_netnum));
77         seq_printf(seq, "%02X%02X%02X%02X%02X%02X   ",
78                         i->if_node[0], i->if_node[1], i->if_node[2],
79                         i->if_node[3], i->if_node[4], i->if_node[5]);
80         seq_printf(seq, "%-9s", i == ipx_primary_net ? "Yes" : "No");
81         seq_printf(seq, "%-11s", ipx_device_name(i));
82         seq_printf(seq, "%-9s", ipx_frame_name(i->if_dlink_type));
83 #ifdef IPX_REFCNT_DEBUG
84         seq_printf(seq, "%6d", atomic_read(&i->refcnt));
85 #endif
86         seq_puts(seq, "\n");
87 out:
88         return 0;
89 }
90
91 static struct ipx_route *ipx_routes_head(void)
92 {
93         struct ipx_route *rc = NULL;
94
95         if (!list_empty(&ipx_routes))
96                 rc = list_entry(ipx_routes.next, struct ipx_route, node);
97         return rc;
98 }
99
100 static struct ipx_route *ipx_routes_next(struct ipx_route *r)
101 {
102         struct ipx_route *rc = NULL;
103
104         if (r->node.next != &ipx_routes)
105                 rc = list_entry(r->node.next, struct ipx_route, node);
106         return rc;
107 }
108
109 static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos)
110 {
111         struct ipx_route *r;
112
113         list_for_each_entry(r, &ipx_routes, node)
114                 if (!pos--)
115                         goto out;
116         r = NULL;
117 out:
118         return r;
119 }
120
121 static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos)
122 {
123         loff_t l = *pos;
124         read_lock_bh(&ipx_routes_lock);
125         return l ? ipx_get_route_idx(--l) : SEQ_START_TOKEN;
126 }
127
128 static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
129 {
130         struct ipx_route *r;
131
132         ++*pos;
133         if (v == SEQ_START_TOKEN)
134                 r = ipx_routes_head();
135         else
136                 r = ipx_routes_next(v);
137         return r;
138 }
139
140 static void ipx_seq_route_stop(struct seq_file *seq, void *v)
141 {
142         read_unlock_bh(&ipx_routes_lock);
143 }
144
145 static int ipx_seq_route_show(struct seq_file *seq, void *v)
146 {
147         struct ipx_route *rt;
148
149         if (v == SEQ_START_TOKEN) {
150                 seq_puts(seq, "Network    Router_Net   Router_Node\n");
151                 goto out;
152         }
153         rt = v;
154         seq_printf(seq, "%08lX   ", (unsigned long int)ntohl(rt->ir_net));
155         if (rt->ir_routed)
156                 seq_printf(seq, "%08lX     %02X%02X%02X%02X%02X%02X\n",
157                            (long unsigned int)ntohl(rt->ir_intrfc->if_netnum),
158                            rt->ir_router_node[0], rt->ir_router_node[1],
159                            rt->ir_router_node[2], rt->ir_router_node[3],
160                            rt->ir_router_node[4], rt->ir_router_node[5]);
161         else
162                 seq_puts(seq, "Directly     Connected\n");
163 out:
164         return 0;
165 }
166
167 static __inline__ struct sock *ipx_get_socket_idx(loff_t pos)
168 {
169         struct sock *s = NULL;
170         struct hlist_node *node;
171         struct ipx_interface *i;
172
173         list_for_each_entry(i, &ipx_interfaces, node) {
174                 spin_lock_bh(&i->if_sklist_lock);
175                 sk_for_each(s, node, &i->if_sklist) {
176                         if (!pos)
177                                 break;
178                         --pos;
179                 }
180                 spin_unlock_bh(&i->if_sklist_lock);
181                 if (!pos) {
182                         if (node)
183                                 goto found;
184                         break;
185                 }
186         }
187         s = NULL;
188 found:
189         return s;
190 }
191
192 static void *ipx_seq_socket_start(struct seq_file *seq, loff_t *pos)
193 {
194         loff_t l = *pos;
195
196         spin_lock_bh(&ipx_interfaces_lock);
197         return l ? ipx_get_socket_idx(--l) : SEQ_START_TOKEN;
198 }
199
200 static void *ipx_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
201 {
202         struct sock* sk, *next;
203         struct ipx_interface *i;
204         struct ipx_sock *ipxs;
205
206         ++*pos;
207         if (v == SEQ_START_TOKEN) {
208                 sk = NULL;
209                 i = ipx_interfaces_head();
210                 if (!i)
211                         goto out;
212                 sk = sk_head(&i->if_sklist);
213                 if (sk)
214                         spin_lock_bh(&i->if_sklist_lock);
215                 goto out;
216         }
217         sk = v;
218         next = sk_next(sk);
219         if (next) {
220                 sk = next;
221                 goto out;
222         }
223         ipxs = ipx_sk(sk);
224         i = ipxs->intrfc;
225         spin_unlock_bh(&i->if_sklist_lock);
226         sk = NULL;
227         for (;;) {
228                 i = ipx_interfaces_next(i);
229                 if (!i)
230                         break;
231                 spin_lock_bh(&i->if_sklist_lock);
232                 if (!hlist_empty(&i->if_sklist)) {
233                         sk = sk_head(&i->if_sklist);
234                         break;
235                 }
236                 spin_unlock_bh(&i->if_sklist_lock);
237         }
238 out:
239         return sk;
240 }
241
242 static int ipx_seq_socket_show(struct seq_file *seq, void *v)
243 {
244         struct sock *s;
245         struct ipx_sock *ipxs;
246
247         if (v == SEQ_START_TOKEN) {
248 #ifdef CONFIG_IPX_INTERN
249                 seq_puts(seq, "Local_Address               "
250                               "Remote_Address              Tx_Queue  "
251                               "Rx_Queue  State  Uid\n");
252 #else
253                 seq_puts(seq, "Local_Address  Remote_Address              "
254                               "Tx_Queue  Rx_Queue  State  Uid\n");
255 #endif
256                 goto out;
257         }
258
259         s = v;
260         ipxs = ipx_sk(s);
261 #ifdef CONFIG_IPX_INTERN
262         seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X  ",
263                    (unsigned long)ntohl(ipxs->intrfc->if_netnum),
264                    ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3],
265                    ipxs->node[4], ipxs->node[5], ntohs(ipxs->port));
266 #else
267         seq_printf(seq, "%08lX:%04X  ", (unsigned long) ntohl(ipxs->intrfc->if_netnum),
268                    ntohs(ipxs->port));
269 #endif  /* CONFIG_IPX_INTERN */
270         if (s->sk_state != TCP_ESTABLISHED)
271                 seq_printf(seq, "%-28s", "Not_Connected");
272         else {
273                 seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X  ",
274                            (unsigned long)ntohl(ipxs->dest_addr.net),
275                            ipxs->dest_addr.node[0], ipxs->dest_addr.node[1],
276                            ipxs->dest_addr.node[2], ipxs->dest_addr.node[3],
277                            ipxs->dest_addr.node[4], ipxs->dest_addr.node[5],
278                            ntohs(ipxs->dest_addr.sock));
279         }
280
281         seq_printf(seq, "%08X  %08X  %02X     %03d\n",
282                    atomic_read(&s->sk_wmem_alloc),
283                    atomic_read(&s->sk_rmem_alloc),
284                    s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
285 out:
286         return 0;
287 }
288
289 static struct seq_operations ipx_seq_interface_ops = {
290         .start  = ipx_seq_interface_start,
291         .next   = ipx_seq_interface_next,
292         .stop   = ipx_seq_interface_stop,
293         .show   = ipx_seq_interface_show,
294 };
295
296 static struct seq_operations ipx_seq_route_ops = {
297         .start  = ipx_seq_route_start,
298         .next   = ipx_seq_route_next,
299         .stop   = ipx_seq_route_stop,
300         .show   = ipx_seq_route_show,
301 };
302
303 static struct seq_operations ipx_seq_socket_ops = {
304         .start  = ipx_seq_socket_start,
305         .next   = ipx_seq_socket_next,
306         .stop   = ipx_seq_interface_stop,
307         .show   = ipx_seq_socket_show,
308 };
309
310 static int ipx_seq_route_open(struct inode *inode, struct file *file)
311 {
312         return seq_open(file, &ipx_seq_route_ops);
313 }
314
315 static int ipx_seq_interface_open(struct inode *inode, struct file *file)
316 {
317         return seq_open(file, &ipx_seq_interface_ops);
318 }
319
320 static int ipx_seq_socket_open(struct inode *inode, struct file *file)
321 {
322         return seq_open(file, &ipx_seq_socket_ops);
323 }
324
325 static struct file_operations ipx_seq_interface_fops = {
326         .owner          = THIS_MODULE,
327         .open           = ipx_seq_interface_open,
328         .read           = seq_read,
329         .llseek         = seq_lseek,
330         .release        = seq_release,
331 };
332
333 static struct file_operations ipx_seq_route_fops = {
334         .owner          = THIS_MODULE,
335         .open           = ipx_seq_route_open,
336         .read           = seq_read,
337         .llseek         = seq_lseek,
338         .release        = seq_release,
339 };
340
341 static struct file_operations ipx_seq_socket_fops = {
342         .owner          = THIS_MODULE,
343         .open           = ipx_seq_socket_open,
344         .read           = seq_read,
345         .llseek         = seq_lseek,
346         .release        = seq_release,
347 };
348
349 static struct proc_dir_entry *ipx_proc_dir;
350
351 int __init ipx_proc_init(void)
352 {
353         struct proc_dir_entry *p;
354         int rc = -ENOMEM;
355
356         ipx_proc_dir = proc_mkdir("ipx", proc_net);
357
358         if (!ipx_proc_dir)
359                 goto out;
360         p = create_proc_entry("interface", S_IRUGO, ipx_proc_dir);
361         if (!p)
362                 goto out_interface;
363
364         p->proc_fops = &ipx_seq_interface_fops;
365         p = create_proc_entry("route", S_IRUGO, ipx_proc_dir);
366         if (!p)
367                 goto out_route;
368
369         p->proc_fops = &ipx_seq_route_fops;
370         p = create_proc_entry("socket", S_IRUGO, ipx_proc_dir);
371         if (!p)
372                 goto out_socket;
373
374         p->proc_fops = &ipx_seq_socket_fops;
375
376         rc = 0;
377 out:
378         return rc;
379 out_socket:
380         remove_proc_entry("route", ipx_proc_dir);
381 out_route:
382         remove_proc_entry("interface", ipx_proc_dir);
383 out_interface:
384         remove_proc_entry("ipx", proc_net);
385         goto out;
386 }
387
388 void __exit ipx_proc_exit(void)
389 {
390         remove_proc_entry("interface", ipx_proc_dir);
391         remove_proc_entry("route", ipx_proc_dir);
392         remove_proc_entry("socket", ipx_proc_dir);
393         remove_proc_entry("ipx", proc_net);
394 }
395
396 #else /* CONFIG_PROC_FS */
397
398 int __init ipx_proc_init(void)
399 {
400         return 0;
401 }
402
403 void __exit ipx_proc_exit(void)
404 {
405 }
406
407 #endif /* CONFIG_PROC_FS */