linux/net/appletalk/atalk_proc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *      atalk_proc.c - proc support for Appletalk
   4 *
   5 *      Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   6 */
   7
   8#include <linux/init.h>
   9#include <linux/proc_fs.h>
  10#include <linux/seq_file.h>
  11#include <net/net_namespace.h>
  12#include <net/sock.h>
  13#include <linux/atalk.h>
  14#include <linux/export.h>
  15
  16
  17static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos)
  18{
  19        struct atalk_iface *i;
  20
  21        for (i = atalk_interfaces; pos && i; i = i->next)
  22                --pos;
  23
  24        return i;
  25}
  26
  27static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos)
  28        __acquires(atalk_interfaces_lock)
  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        __releases(atalk_interfaces_lock)
  55{
  56        read_unlock_bh(&atalk_interfaces_lock);
  57}
  58
  59static int atalk_seq_interface_show(struct seq_file *seq, void *v)
  60{
  61        struct atalk_iface *iface;
  62
  63        if (v == SEQ_START_TOKEN) {
  64                seq_puts(seq, "Interface        Address   Networks  "
  65                              "Status\n");
  66                goto out;
  67        }
  68
  69        iface = v;
  70        seq_printf(seq, "%-16s %04X:%02X  %04X-%04X  %d\n",
  71                   iface->dev->name, ntohs(iface->address.s_net),
  72                   iface->address.s_node, ntohs(iface->nets.nr_firstnet),
  73                   ntohs(iface->nets.nr_lastnet), iface->status);
  74out:
  75        return 0;
  76}
  77
  78static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos)
  79{
  80        struct atalk_route *r;
  81
  82        for (r = atalk_routes; pos && r; r = r->next)
  83                --pos;
  84
  85        return r;
  86}
  87
  88static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos)
  89        __acquires(atalk_routes_lock)
  90{
  91        loff_t l = *pos;
  92
  93        read_lock_bh(&atalk_routes_lock);
  94        return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN;
  95}
  96
  97static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
  98{
  99        struct atalk_route *r;
 100
 101        ++*pos;
 102        if (v == SEQ_START_TOKEN) {
 103                r = NULL;
 104                if (atalk_routes)
 105                        r = atalk_routes;
 106                goto out;
 107        }
 108        r = v;
 109        r = r->next;
 110out:
 111        return r;
 112}
 113
 114static void atalk_seq_route_stop(struct seq_file *seq, void *v)
 115        __releases(atalk_routes_lock)
 116{
 117        read_unlock_bh(&atalk_routes_lock);
 118}
 119
 120static int atalk_seq_route_show(struct seq_file *seq, void *v)
 121{
 122        struct atalk_route *rt;
 123
 124        if (v == SEQ_START_TOKEN) {
 125                seq_puts(seq, "Target        Router  Flags Dev\n");
 126                goto out;
 127        }
 128
 129        if (atrtr_default.dev) {
 130                rt = &atrtr_default;
 131                seq_printf(seq, "Default     %04X:%02X  %-4d  %s\n",
 132                               ntohs(rt->gateway.s_net), rt->gateway.s_node,
 133                               rt->flags, rt->dev->name);
 134        }
 135
 136        rt = v;
 137        seq_printf(seq, "%04X:%02X     %04X:%02X  %-4d  %s\n",
 138                   ntohs(rt->target.s_net), rt->target.s_node,
 139                   ntohs(rt->gateway.s_net), rt->gateway.s_node,
 140                   rt->flags, rt->dev->name);
 141out:
 142        return 0;
 143}
 144
 145static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
 146        __acquires(atalk_sockets_lock)
 147{
 148        read_lock_bh(&atalk_sockets_lock);
 149        return seq_hlist_start_head(&atalk_sockets, *pos);
 150}
 151
 152static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
 153{
 154        return seq_hlist_next(v, &atalk_sockets, pos);
 155}
 156
 157static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
 158        __releases(atalk_sockets_lock)
 159{
 160        read_unlock_bh(&atalk_sockets_lock);
 161}
 162
 163static int atalk_seq_socket_show(struct seq_file *seq, void *v)
 164{
 165        struct sock *s;
 166        struct atalk_sock *at;
 167
 168        if (v == SEQ_START_TOKEN) {
 169                seq_printf(seq, "Type Local_addr  Remote_addr Tx_queue "
 170                                "Rx_queue St UID\n");
 171                goto out;
 172        }
 173
 174        s = sk_entry(v);
 175        at = at_sk(s);
 176
 177        seq_printf(seq, "%02X   %04X:%02X:%02X  %04X:%02X:%02X  %08X:%08X "
 178                        "%02X %u\n",
 179                   s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
 180                   ntohs(at->dest_net), at->dest_node, at->dest_port,
 181                   sk_wmem_alloc_get(s),
 182                   sk_rmem_alloc_get(s),
 183                   s->sk_state,
 184                   from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)));
 185out:
 186        return 0;
 187}
 188
 189static const struct seq_operations atalk_seq_interface_ops = {
 190        .start  = atalk_seq_interface_start,
 191        .next   = atalk_seq_interface_next,
 192        .stop   = atalk_seq_interface_stop,
 193        .show   = atalk_seq_interface_show,
 194};
 195
 196static const struct seq_operations atalk_seq_route_ops = {
 197        .start  = atalk_seq_route_start,
 198        .next   = atalk_seq_route_next,
 199        .stop   = atalk_seq_route_stop,
 200        .show   = atalk_seq_route_show,
 201};
 202
 203static const struct seq_operations atalk_seq_socket_ops = {
 204        .start  = atalk_seq_socket_start,
 205        .next   = atalk_seq_socket_next,
 206        .stop   = atalk_seq_socket_stop,
 207        .show   = atalk_seq_socket_show,
 208};
 209
 210int __init atalk_proc_init(void)
 211{
 212        if (!proc_mkdir("atalk", init_net.proc_net))
 213                return -ENOMEM;
 214
 215        if (!proc_create_seq("atalk/interface", 0444, init_net.proc_net,
 216                            &atalk_seq_interface_ops))
 217                goto out;
 218
 219        if (!proc_create_seq("atalk/route", 0444, init_net.proc_net,
 220                            &atalk_seq_route_ops))
 221                goto out;
 222
 223        if (!proc_create_seq("atalk/socket", 0444, init_net.proc_net,
 224                            &atalk_seq_socket_ops))
 225                goto out;
 226
 227        if (!proc_create_seq_private("atalk/arp", 0444, init_net.proc_net,
 228                                     &aarp_seq_ops,
 229                                     sizeof(struct aarp_iter_state), NULL))
 230                goto out;
 231
 232        return 0;
 233
 234out:
 235        remove_proc_subtree("atalk", init_net.proc_net);
 236        return -ENOMEM;
 237}
 238
 239void atalk_proc_exit(void)
 240{
 241        remove_proc_subtree("atalk", init_net.proc_net);
 242}
 243