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