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 void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
 148        __acquires(atalk_sockets_lock)
 149{
 150        read_lock_bh(&atalk_sockets_lock);
 151        return seq_hlist_start_head(&atalk_sockets, *pos);
 152}
 153
 154static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
 155{
 156        return seq_hlist_next(v, &atalk_sockets, pos);
 157}
 158
 159static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
 160        __releases(atalk_sockets_lock)
 161{
 162        read_unlock_bh(&atalk_sockets_lock);
 163}
 164
 165static int atalk_seq_socket_show(struct seq_file *seq, void *v)
 166{
 167        struct sock *s;
 168        struct atalk_sock *at;
 169
 170        if (v == SEQ_START_TOKEN) {
 171                seq_printf(seq, "Type Local_addr  Remote_addr Tx_queue "
 172                                "Rx_queue St UID\n");
 173                goto out;
 174        }
 175
 176        s = sk_entry(v);
 177        at = at_sk(s);
 178
 179        seq_printf(seq, "%02X   %04X:%02X:%02X  %04X:%02X:%02X  %08X:%08X "
 180                        "%02X %d\n",
 181                   s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
 182                   ntohs(at->dest_net), at->dest_node, at->dest_port,
 183                   sk_wmem_alloc_get(s),
 184                   sk_rmem_alloc_get(s),
 185                   s->sk_state, SOCK_INODE(s->sk_socket)->i_uid);
 186out:
 187        return 0;
 188}
 189
 190static const struct seq_operations atalk_seq_interface_ops = {
 191        .start  = atalk_seq_interface_start,
 192        .next   = atalk_seq_interface_next,
 193        .stop   = atalk_seq_interface_stop,
 194        .show   = atalk_seq_interface_show,
 195};
 196
 197static const struct seq_operations atalk_seq_route_ops = {
 198        .start  = atalk_seq_route_start,
 199        .next   = atalk_seq_route_next,
 200        .stop   = atalk_seq_route_stop,
 201        .show   = atalk_seq_route_show,
 202};
 203
 204static const struct seq_operations atalk_seq_socket_ops = {
 205        .start  = atalk_seq_socket_start,
 206        .next   = atalk_seq_socket_next,
 207        .stop   = atalk_seq_socket_stop,
 208        .show   = atalk_seq_socket_show,
 209};
 210
 211static int atalk_seq_interface_open(struct inode *inode, struct file *file)
 212{
 213        return seq_open(file, &atalk_seq_interface_ops);
 214}
 215
 216static int atalk_seq_route_open(struct inode *inode, struct file *file)
 217{
 218        return seq_open(file, &atalk_seq_route_ops);
 219}
 220
 221static int atalk_seq_socket_open(struct inode *inode, struct file *file)
 222{
 223        return seq_open(file, &atalk_seq_socket_ops);
 224}
 225
 226static const struct file_operations atalk_seq_interface_fops = {
 227        .owner          = THIS_MODULE,
 228        .open           = atalk_seq_interface_open,
 229        .read           = seq_read,
 230        .llseek         = seq_lseek,
 231        .release        = seq_release,
 232};
 233
 234static const struct file_operations atalk_seq_route_fops = {
 235        .owner          = THIS_MODULE,
 236        .open           = atalk_seq_route_open,
 237        .read           = seq_read,
 238        .llseek         = seq_lseek,
 239        .release        = seq_release,
 240};
 241
 242static const struct file_operations atalk_seq_socket_fops = {
 243        .owner          = THIS_MODULE,
 244        .open           = atalk_seq_socket_open,
 245        .read           = seq_read,
 246        .llseek         = seq_lseek,
 247        .release        = seq_release,
 248};
 249
 250static struct proc_dir_entry *atalk_proc_dir;
 251
 252int __init atalk_proc_init(void)
 253{
 254        struct proc_dir_entry *p;
 255        int rc = -ENOMEM;
 256
 257        atalk_proc_dir = proc_mkdir("atalk", init_net.proc_net);
 258        if (!atalk_proc_dir)
 259                goto out;
 260
 261        p = proc_create("interface", S_IRUGO, atalk_proc_dir,
 262                        &atalk_seq_interface_fops);
 263        if (!p)
 264                goto out_interface;
 265
 266        p = proc_create("route", S_IRUGO, atalk_proc_dir,
 267                        &atalk_seq_route_fops);
 268        if (!p)
 269                goto out_route;
 270
 271        p = proc_create("socket", S_IRUGO, atalk_proc_dir,
 272                        &atalk_seq_socket_fops);
 273        if (!p)
 274                goto out_socket;
 275
 276        p = proc_create("arp", S_IRUGO, atalk_proc_dir, &atalk_seq_arp_fops);
 277        if (!p)
 278                goto out_arp;
 279
 280        rc = 0;
 281out:
 282        return rc;
 283out_arp:
 284        remove_proc_entry("socket", atalk_proc_dir);
 285out_socket:
 286        remove_proc_entry("route", atalk_proc_dir);
 287out_route:
 288        remove_proc_entry("interface", atalk_proc_dir);
 289out_interface:
 290        remove_proc_entry("atalk", init_net.proc_net);
 291        goto out;
 292}
 293
 294void __exit atalk_proc_exit(void)
 295{
 296        remove_proc_entry("interface", atalk_proc_dir);
 297        remove_proc_entry("route", atalk_proc_dir);
 298        remove_proc_entry("socket", atalk_proc_dir);
 299        remove_proc_entry("arp", atalk_proc_dir);
 300        remove_proc_entry("atalk", init_net.proc_net);
 301}
 302