linux/net/x25/x25_proc.c
<<
>>
Prefs
   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
  28static __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;
  39found:
  40        return rt;
  41}
  42
  43static 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
  52static 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;
  69out:
  70        return rt;
  71}
  72
  73static 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
  79static 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 : "???");
  92out:
  93        return 0;
  94}
  95
  96static __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;
 105found:
 106        return s;
 107}
 108
 109static 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
 118static 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);
 128out:
 129        return s;
 130}
 131
 132static 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
 138static 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);
 169out:
 170        return 0;
 171}
 172
 173static __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;
 185found:
 186        return f;
 187}
 188
 189static 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
 198static 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;
 215out:
 216        return f;
 217
 218}
 219
 220static 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
 226static 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
 240out:
 241        return 0;
 242}
 243
 244static 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
 251static 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
 258static 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
 265static int x25_seq_socket_open(struct inode *inode, struct file *file)
 266{
 267        return seq_open(file, &x25_seq_socket_ops);
 268}
 269
 270static int x25_seq_route_open(struct inode *inode, struct file *file)
 271{
 272        return seq_open(file, &x25_seq_route_ops);
 273}
 274
 275static int x25_seq_forward_open(struct inode *inode, struct file *file)
 276{
 277        return seq_open(file, &x25_seq_forward_ops);
 278}
 279
 280static 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
 288static 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
 296static 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
 304static struct proc_dir_entry *x25_proc_dir;
 305
 306int __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
 329out:
 330        return rc;
 331out_forward:
 332        remove_proc_entry("socket", x25_proc_dir);
 333out_socket:
 334        remove_proc_entry("route", x25_proc_dir);
 335out_route:
 336        remove_proc_entry("x25", init_net.proc_net);
 337        goto out;
 338}
 339
 340void __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
 350int __init x25_proc_init(void)
 351{
 352        return 0;
 353}
 354
 355void __exit x25_proc_exit(void)
 356{
 357}
 358#endif /* CONFIG_PROC_FS */
 359