atalk_proc.c revision 6ab3d5624e172c553004ecc862bfeac16d9d68b7
1/* 2 * atalk_proc.c - proc support for Appletalk 3 * 4 * Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation, version 2. 9 */ 10 11#include <linux/init.h> 12#include <linux/proc_fs.h> 13#include <linux/seq_file.h> 14#include <net/sock.h> 15#include <linux/atalk.h> 16 17 18static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos) 19{ 20 struct atalk_iface *i; 21 22 for (i = atalk_interfaces; pos && i; i = i->next) 23 --pos; 24 25 return i; 26} 27 28static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos) 29{ 30 loff_t l = *pos; 31 32 read_lock_bh(&atalk_interfaces_lock); 33 return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN; 34} 35 36static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) 37{ 38 struct atalk_iface *i; 39 40 ++*pos; 41 if (v == SEQ_START_TOKEN) { 42 i = NULL; 43 if (atalk_interfaces) 44 i = atalk_interfaces; 45 goto out; 46 } 47 i = v; 48 i = i->next; 49out: 50 return i; 51} 52 53static void atalk_seq_interface_stop(struct seq_file *seq, void *v) 54{ 55 read_unlock_bh(&atalk_interfaces_lock); 56} 57 58static int atalk_seq_interface_show(struct seq_file *seq, void *v) 59{ 60 struct atalk_iface *iface; 61 62 if (v == SEQ_START_TOKEN) { 63 seq_puts(seq, "Interface Address Networks " 64 "Status\n"); 65 goto out; 66 } 67 68 iface = v; 69 seq_printf(seq, "%-16s %04X:%02X %04X-%04X %d\n", 70 iface->dev->name, ntohs(iface->address.s_net), 71 iface->address.s_node, ntohs(iface->nets.nr_firstnet), 72 ntohs(iface->nets.nr_lastnet), iface->status); 73out: 74 return 0; 75} 76 77static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos) 78{ 79 struct atalk_route *r; 80 81 for (r = atalk_routes; pos && r; r = r->next) 82 --pos; 83 84 return r; 85} 86 87static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos) 88{ 89 loff_t l = *pos; 90 91 read_lock_bh(&atalk_routes_lock); 92 return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN; 93} 94 95static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) 96{ 97 struct atalk_route *r; 98 99 ++*pos; 100 if (v == SEQ_START_TOKEN) { 101 r = NULL; 102 if (atalk_routes) 103 r = atalk_routes; 104 goto out; 105 } 106 r = v; 107 r = r->next; 108out: 109 return r; 110} 111 112static void atalk_seq_route_stop(struct seq_file *seq, void *v) 113{ 114 read_unlock_bh(&atalk_routes_lock); 115} 116 117static int atalk_seq_route_show(struct seq_file *seq, void *v) 118{ 119 struct atalk_route *rt; 120 121 if (v == SEQ_START_TOKEN) { 122 seq_puts(seq, "Target Router Flags Dev\n"); 123 goto out; 124 } 125 126 if (atrtr_default.dev) { 127 rt = &atrtr_default; 128 seq_printf(seq, "Default %04X:%02X %-4d %s\n", 129 ntohs(rt->gateway.s_net), rt->gateway.s_node, 130 rt->flags, rt->dev->name); 131 } 132 133 rt = v; 134 seq_printf(seq, "%04X:%02X %04X:%02X %-4d %s\n", 135 ntohs(rt->target.s_net), rt->target.s_node, 136 ntohs(rt->gateway.s_net), rt->gateway.s_node, 137 rt->flags, rt->dev->name); 138out: 139 return 0; 140} 141 142static __inline__ struct sock *atalk_get_socket_idx(loff_t pos) 143{ 144 struct sock *s; 145 struct hlist_node *node; 146 147 sk_for_each(s, node, &atalk_sockets) 148 if (!pos--) 149 goto found; 150 s = NULL; 151found: 152 return s; 153} 154 155static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos) 156{ 157 loff_t l = *pos; 158 159 read_lock_bh(&atalk_sockets_lock); 160 return l ? atalk_get_socket_idx(--l) : SEQ_START_TOKEN; 161} 162 163static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) 164{ 165 struct sock *i; 166 167 ++*pos; 168 if (v == SEQ_START_TOKEN) { 169 i = sk_head(&atalk_sockets); 170 goto out; 171 } 172 i = sk_next(v); 173out: 174 return i; 175} 176 177static void atalk_seq_socket_stop(struct seq_file *seq, void *v) 178{ 179 read_unlock_bh(&atalk_sockets_lock); 180} 181 182static int atalk_seq_socket_show(struct seq_file *seq, void *v) 183{ 184 struct sock *s; 185 struct atalk_sock *at; 186 187 if (v == SEQ_START_TOKEN) { 188 seq_printf(seq, "Type Local_addr Remote_addr Tx_queue " 189 "Rx_queue St UID\n"); 190 goto out; 191 } 192 193 s = v; 194 at = at_sk(s); 195 196 seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " 197 "%02X %d\n", 198 s->sk_type, ntohs(at->src_net), at->src_node, at->src_port, 199 ntohs(at->dest_net), at->dest_node, at->dest_port, 200 atomic_read(&s->sk_wmem_alloc), 201 atomic_read(&s->sk_rmem_alloc), 202 s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); 203out: 204 return 0; 205} 206 207static struct seq_operations atalk_seq_interface_ops = { 208 .start = atalk_seq_interface_start, 209 .next = atalk_seq_interface_next, 210 .stop = atalk_seq_interface_stop, 211 .show = atalk_seq_interface_show, 212}; 213 214static struct seq_operations atalk_seq_route_ops = { 215 .start = atalk_seq_route_start, 216 .next = atalk_seq_route_next, 217 .stop = atalk_seq_route_stop, 218 .show = atalk_seq_route_show, 219}; 220 221static struct seq_operations atalk_seq_socket_ops = { 222 .start = atalk_seq_socket_start, 223 .next = atalk_seq_socket_next, 224 .stop = atalk_seq_socket_stop, 225 .show = atalk_seq_socket_show, 226}; 227 228static int atalk_seq_interface_open(struct inode *inode, struct file *file) 229{ 230 return seq_open(file, &atalk_seq_interface_ops); 231} 232 233static int atalk_seq_route_open(struct inode *inode, struct file *file) 234{ 235 return seq_open(file, &atalk_seq_route_ops); 236} 237 238static int atalk_seq_socket_open(struct inode *inode, struct file *file) 239{ 240 return seq_open(file, &atalk_seq_socket_ops); 241} 242 243static struct file_operations atalk_seq_interface_fops = { 244 .owner = THIS_MODULE, 245 .open = atalk_seq_interface_open, 246 .read = seq_read, 247 .llseek = seq_lseek, 248 .release = seq_release, 249}; 250 251static struct file_operations atalk_seq_route_fops = { 252 .owner = THIS_MODULE, 253 .open = atalk_seq_route_open, 254 .read = seq_read, 255 .llseek = seq_lseek, 256 .release = seq_release, 257}; 258 259static struct file_operations atalk_seq_socket_fops = { 260 .owner = THIS_MODULE, 261 .open = atalk_seq_socket_open, 262 .read = seq_read, 263 .llseek = seq_lseek, 264 .release = seq_release, 265}; 266 267static struct proc_dir_entry *atalk_proc_dir; 268 269int __init atalk_proc_init(void) 270{ 271 struct proc_dir_entry *p; 272 int rc = -ENOMEM; 273 274 atalk_proc_dir = proc_mkdir("atalk", proc_net); 275 if (!atalk_proc_dir) 276 goto out; 277 atalk_proc_dir->owner = THIS_MODULE; 278 279 p = create_proc_entry("interface", S_IRUGO, atalk_proc_dir); 280 if (!p) 281 goto out_interface; 282 p->proc_fops = &atalk_seq_interface_fops; 283 284 p = create_proc_entry("route", S_IRUGO, atalk_proc_dir); 285 if (!p) 286 goto out_route; 287 p->proc_fops = &atalk_seq_route_fops; 288 289 p = create_proc_entry("socket", S_IRUGO, atalk_proc_dir); 290 if (!p) 291 goto out_socket; 292 p->proc_fops = &atalk_seq_socket_fops; 293 294 p = create_proc_entry("arp", S_IRUGO, atalk_proc_dir); 295 if (!p) 296 goto out_arp; 297 p->proc_fops = &atalk_seq_arp_fops; 298 299 rc = 0; 300out: 301 return rc; 302out_arp: 303 remove_proc_entry("socket", atalk_proc_dir); 304out_socket: 305 remove_proc_entry("route", atalk_proc_dir); 306out_route: 307 remove_proc_entry("interface", atalk_proc_dir); 308out_interface: 309 remove_proc_entry("atalk", proc_net); 310 goto out; 311} 312 313void __exit atalk_proc_exit(void) 314{ 315 remove_proc_entry("interface", atalk_proc_dir); 316 remove_proc_entry("route", atalk_proc_dir); 317 remove_proc_entry("socket", atalk_proc_dir); 318 remove_proc_entry("arp", atalk_proc_dir); 319 remove_proc_entry("atalk", proc_net); 320} 321