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