1 /* 2 * X.25 Packet Layer release 002 3 * 4 * This is ALPHA test software. This code may break your machine, 5 * randomly fail to work with new releases, misbehave and/or generally 6 * screw up. It might even work. 7 * 8 * This code REQUIRES 2.4 with seq_file support 9 * 10 * This module: 11 * This module is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License 13 * as published by the Free Software Foundation; either version 14 * 2 of the License, or (at your option) any later version. 15 * 16 * History 17 * 2002/10/06 Arnaldo Carvalho de Melo seq_file support 18 */ 19 20 #include <linux/init.h> 21 #include <linux/proc_fs.h> 22 #include <linux/seq_file.h> 23 #include <net/net_namespace.h> 24 #include <net/sock.h> 25 #include <net/x25.h> 26 27 #ifdef CONFIG_PROC_FS 28 static __inline__ struct x25_route *x25_get_route_idx(loff_t pos) 29 { 30 struct list_head *route_entry; 31 struct x25_route *rt = NULL; 32 33 list_for_each(route_entry, &x25_route_list) { 34 rt = list_entry(route_entry, struct x25_route, node); 35 if (!pos--) 36 goto found; 37 } 38 rt = NULL; 39 found: 40 return rt; 41 } 42 43 static void *x25_seq_route_start(struct seq_file *seq, loff_t *pos) 44 __acquires(x25_route_list_lock) 45 { 46 loff_t l = *pos; 47 48 read_lock_bh(&x25_route_list_lock); 49 return l ? x25_get_route_idx(--l) : SEQ_START_TOKEN; 50 } 51 52 static void *x25_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) 53 { 54 struct x25_route *rt; 55 56 ++*pos; 57 if (v == SEQ_START_TOKEN) { 58 rt = NULL; 59 if (!list_empty(&x25_route_list)) 60 rt = list_entry(x25_route_list.next, 61 struct x25_route, node); 62 goto out; 63 } 64 rt = v; 65 if (rt->node.next != &x25_route_list) 66 rt = list_entry(rt->node.next, struct x25_route, node); 67 else 68 rt = NULL; 69 out: 70 return rt; 71 } 72 73 static void x25_seq_route_stop(struct seq_file *seq, void *v) 74 __releases(x25_route_list_lock) 75 { 76 read_unlock_bh(&x25_route_list_lock); 77 } 78 79 static int x25_seq_route_show(struct seq_file *seq, void *v) 80 { 81 struct x25_route *rt; 82 83 if (v == SEQ_START_TOKEN) { 84 seq_puts(seq, "Address Digits Device\n"); 85 goto out; 86 } 87 88 rt = v; 89 seq_printf(seq, "%-15s %-6d %-5s\n", 90 rt->address.x25_addr, rt->sigdigits, 91 rt->dev ? rt->dev->name : "???"); 92 out: 93 return 0; 94 } 95 96 static __inline__ struct sock *x25_get_socket_idx(loff_t pos) 97 { 98 struct sock *s; 99 struct hlist_node *node; 100 101 sk_for_each(s, node, &x25_list) 102 if (!pos--) 103 goto found; 104 s = NULL; 105 found: 106 return s; 107 } 108 109 static void *x25_seq_socket_start(struct seq_file *seq, loff_t *pos) 110 __acquires(x25_list_lock) 111 { 112 loff_t l = *pos; 113 114 read_lock_bh(&x25_list_lock); 115 return l ? x25_get_socket_idx(--l) : SEQ_START_TOKEN; 116 } 117 118 static void *x25_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) 119 { 120 struct sock *s; 121 122 ++*pos; 123 if (v == SEQ_START_TOKEN) { 124 s = sk_head(&x25_list); 125 goto out; 126 } 127 s = sk_next(v); 128 out: 129 return s; 130 } 131 132 static void x25_seq_socket_stop(struct seq_file *seq, void *v) 133 __releases(x25_list_lock) 134 { 135 read_unlock_bh(&x25_list_lock); 136 } 137 138 static int x25_seq_socket_show(struct seq_file *seq, void *v) 139 { 140 struct sock *s; 141 struct x25_sock *x25; 142 struct net_device *dev; 143 const char *devname; 144 145 if (v == SEQ_START_TOKEN) { 146 seq_printf(seq, "dest_addr src_addr dev lci st vs vr " 147 "va t t2 t21 t22 t23 Snd-Q Rcv-Q inode\n"); 148 goto out; 149 } 150 151 s = v; 152 x25 = x25_sk(s); 153 154 if (!x25->neighbour || (dev = x25->neighbour->dev) == NULL) 155 devname = "???"; 156 else 157 devname = x25->neighbour->dev->name; 158 159 seq_printf(seq, "%-10s %-10s %-5s %3.3X %d %d %d %d %3lu %3lu " 160 "%3lu %3lu %3lu %5d %5d %ld\n", 161 !x25->dest_addr.x25_addr[0] ? "*" : x25->dest_addr.x25_addr, 162 !x25->source_addr.x25_addr[0] ? "*" : x25->source_addr.x25_addr, 163 devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr, 164 x25->va, x25_display_timer(s) / HZ, x25->t2 / HZ, 165 x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ, 166 sk_wmem_alloc_get(s), 167 sk_rmem_alloc_get(s), 168 s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); 169 out: 170 return 0; 171 } 172 173 static __inline__ struct x25_forward *x25_get_forward_idx(loff_t pos) 174 { 175 struct x25_forward *f; 176 struct list_head *entry; 177 178 list_for_each(entry, &x25_forward_list) { 179 f = list_entry(entry, struct x25_forward, node); 180 if (!pos--) 181 goto found; 182 } 183 184 f = NULL; 185 found: 186 return f; 187 } 188 189 static void *x25_seq_forward_start(struct seq_file *seq, loff_t *pos) 190 __acquires(x25_forward_list_lock) 191 { 192 loff_t l = *pos; 193 194 read_lock_bh(&x25_forward_list_lock); 195 return l ? x25_get_forward_idx(--l) : SEQ_START_TOKEN; 196 } 197 198 static void *x25_seq_forward_next(struct seq_file *seq, void *v, loff_t *pos) 199 { 200 struct x25_forward *f; 201 202 ++*pos; 203 if (v == SEQ_START_TOKEN) { 204 f = NULL; 205 if (!list_empty(&x25_forward_list)) 206 f = list_entry(x25_forward_list.next, 207 struct x25_forward, node); 208 goto out; 209 } 210 f = v; 211 if (f->node.next != &x25_forward_list) 212 f = list_entry(f->node.next, struct x25_forward, node); 213 else 214 f = NULL; 215 out: 216 return f; 217 218 } 219 220 static void x25_seq_forward_stop(struct seq_file *seq, void *v) 221 __releases(x25_forward_list_lock) 222 { 223 read_unlock_bh(&x25_forward_list_lock); 224 } 225 226 static int x25_seq_forward_show(struct seq_file *seq, void *v) 227 { 228 struct x25_forward *f; 229 230 if (v == SEQ_START_TOKEN) { 231 seq_printf(seq, "lci dev1 dev2\n"); 232 goto out; 233 } 234 235 f = v; 236 237 seq_printf(seq, "%d %-10s %-10s\n", 238 f->lci, f->dev1->name, f->dev2->name); 239 240 out: 241 return 0; 242 } 243 244 static const struct seq_operations x25_seq_route_ops = { 245 .start = x25_seq_route_start, 246 .next = x25_seq_route_next, 247 .stop = x25_seq_route_stop, 248 .show = x25_seq_route_show, 249 }; 250 251 static const struct seq_operations x25_seq_socket_ops = { 252 .start = x25_seq_socket_start, 253 .next = x25_seq_socket_next, 254 .stop = x25_seq_socket_stop, 255 .show = x25_seq_socket_show, 256 }; 257 258 static const struct seq_operations x25_seq_forward_ops = { 259 .start = x25_seq_forward_start, 260 .next = x25_seq_forward_next, 261 .stop = x25_seq_forward_stop, 262 .show = x25_seq_forward_show, 263 }; 264 265 static int x25_seq_socket_open(struct inode *inode, struct file *file) 266 { 267 return seq_open(file, &x25_seq_socket_ops); 268 } 269 270 static int x25_seq_route_open(struct inode *inode, struct file *file) 271 { 272 return seq_open(file, &x25_seq_route_ops); 273 } 274 275 static int x25_seq_forward_open(struct inode *inode, struct file *file) 276 { 277 return seq_open(file, &x25_seq_forward_ops); 278 } 279 280 static const struct file_operations x25_seq_socket_fops = { 281 .owner = THIS_MODULE, 282 .open = x25_seq_socket_open, 283 .read = seq_read, 284 .llseek = seq_lseek, 285 .release = seq_release, 286 }; 287 288 static const struct file_operations x25_seq_route_fops = { 289 .owner = THIS_MODULE, 290 .open = x25_seq_route_open, 291 .read = seq_read, 292 .llseek = seq_lseek, 293 .release = seq_release, 294 }; 295 296 static const struct file_operations x25_seq_forward_fops = { 297 .owner = THIS_MODULE, 298 .open = x25_seq_forward_open, 299 .read = seq_read, 300 .llseek = seq_lseek, 301 .release = seq_release, 302 }; 303 304 static struct proc_dir_entry *x25_proc_dir; 305 306 int __init x25_proc_init(void) 307 { 308 struct proc_dir_entry *p; 309 int rc = -ENOMEM; 310 311 x25_proc_dir = proc_mkdir("x25", init_net.proc_net); 312 if (!x25_proc_dir) 313 goto out; 314 315 p = proc_create("route", S_IRUGO, x25_proc_dir, &x25_seq_route_fops); 316 if (!p) 317 goto out_route; 318 319 p = proc_create("socket", S_IRUGO, x25_proc_dir, &x25_seq_socket_fops); 320 if (!p) 321 goto out_socket; 322 323 p = proc_create("forward", S_IRUGO, x25_proc_dir, 324 &x25_seq_forward_fops); 325 if (!p) 326 goto out_forward; 327 rc = 0; 328 329 out: 330 return rc; 331 out_forward: 332 remove_proc_entry("socket", x25_proc_dir); 333 out_socket: 334 remove_proc_entry("route", x25_proc_dir); 335 out_route: 336 remove_proc_entry("x25", init_net.proc_net); 337 goto out; 338 } 339 340 void __exit x25_proc_exit(void) 341 { 342 remove_proc_entry("forward", x25_proc_dir); 343 remove_proc_entry("route", x25_proc_dir); 344 remove_proc_entry("socket", x25_proc_dir); 345 remove_proc_entry("x25", init_net.proc_net); 346 } 347 348 #else /* CONFIG_PROC_FS */ 349 350 int __init x25_proc_init(void) 351 { 352 return 0; 353 } 354 355 void __exit x25_proc_exit(void) 356 { 357 } 358 #endif /* CONFIG_PROC_FS */ 359