Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  atalk_proc.c - proc support for Appletalk
0004  *
0005  *  Copyright(c) Arnaldo Carvalho de Melo <acme@conectiva.com.br>
0006  */
0007 
0008 #include <linux/init.h>
0009 #include <linux/proc_fs.h>
0010 #include <linux/seq_file.h>
0011 #include <net/net_namespace.h>
0012 #include <net/sock.h>
0013 #include <linux/atalk.h>
0014 #include <linux/export.h>
0015 
0016 
0017 static __inline__ struct atalk_iface *atalk_get_interface_idx(loff_t pos)
0018 {
0019     struct atalk_iface *i;
0020 
0021     for (i = atalk_interfaces; pos && i; i = i->next)
0022         --pos;
0023 
0024     return i;
0025 }
0026 
0027 static void *atalk_seq_interface_start(struct seq_file *seq, loff_t *pos)
0028     __acquires(atalk_interfaces_lock)
0029 {
0030     loff_t l = *pos;
0031 
0032     read_lock_bh(&atalk_interfaces_lock);
0033     return l ? atalk_get_interface_idx(--l) : SEQ_START_TOKEN;
0034 }
0035 
0036 static void *atalk_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos)
0037 {
0038     struct atalk_iface *i;
0039 
0040     ++*pos;
0041     if (v == SEQ_START_TOKEN) {
0042         i = NULL;
0043         if (atalk_interfaces)
0044             i = atalk_interfaces;
0045         goto out;
0046     }
0047     i = v;
0048     i = i->next;
0049 out:
0050     return i;
0051 }
0052 
0053 static void atalk_seq_interface_stop(struct seq_file *seq, void *v)
0054     __releases(atalk_interfaces_lock)
0055 {
0056     read_unlock_bh(&atalk_interfaces_lock);
0057 }
0058 
0059 static int atalk_seq_interface_show(struct seq_file *seq, void *v)
0060 {
0061     struct atalk_iface *iface;
0062 
0063     if (v == SEQ_START_TOKEN) {
0064         seq_puts(seq, "Interface        Address   Networks  "
0065                   "Status\n");
0066         goto out;
0067     }
0068 
0069     iface = v;
0070     seq_printf(seq, "%-16s %04X:%02X  %04X-%04X  %d\n",
0071            iface->dev->name, ntohs(iface->address.s_net),
0072            iface->address.s_node, ntohs(iface->nets.nr_firstnet),
0073            ntohs(iface->nets.nr_lastnet), iface->status);
0074 out:
0075     return 0;
0076 }
0077 
0078 static __inline__ struct atalk_route *atalk_get_route_idx(loff_t pos)
0079 {
0080     struct atalk_route *r;
0081 
0082     for (r = atalk_routes; pos && r; r = r->next)
0083         --pos;
0084 
0085     return r;
0086 }
0087 
0088 static void *atalk_seq_route_start(struct seq_file *seq, loff_t *pos)
0089     __acquires(atalk_routes_lock)
0090 {
0091     loff_t l = *pos;
0092 
0093     read_lock_bh(&atalk_routes_lock);
0094     return l ? atalk_get_route_idx(--l) : SEQ_START_TOKEN;
0095 }
0096 
0097 static void *atalk_seq_route_next(struct seq_file *seq, void *v, loff_t *pos)
0098 {
0099     struct atalk_route *r;
0100 
0101     ++*pos;
0102     if (v == SEQ_START_TOKEN) {
0103         r = NULL;
0104         if (atalk_routes)
0105             r = atalk_routes;
0106         goto out;
0107     }
0108     r = v;
0109     r = r->next;
0110 out:
0111     return r;
0112 }
0113 
0114 static void atalk_seq_route_stop(struct seq_file *seq, void *v)
0115     __releases(atalk_routes_lock)
0116 {
0117     read_unlock_bh(&atalk_routes_lock);
0118 }
0119 
0120 static int atalk_seq_route_show(struct seq_file *seq, void *v)
0121 {
0122     struct atalk_route *rt;
0123 
0124     if (v == SEQ_START_TOKEN) {
0125         seq_puts(seq, "Target        Router  Flags Dev\n");
0126         goto out;
0127     }
0128 
0129     if (atrtr_default.dev) {
0130         rt = &atrtr_default;
0131         seq_printf(seq, "Default     %04X:%02X  %-4d  %s\n",
0132                    ntohs(rt->gateway.s_net), rt->gateway.s_node,
0133                    rt->flags, rt->dev->name);
0134     }
0135 
0136     rt = v;
0137     seq_printf(seq, "%04X:%02X     %04X:%02X  %-4d  %s\n",
0138            ntohs(rt->target.s_net), rt->target.s_node,
0139            ntohs(rt->gateway.s_net), rt->gateway.s_node,
0140            rt->flags, rt->dev->name);
0141 out:
0142     return 0;
0143 }
0144 
0145 static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
0146     __acquires(atalk_sockets_lock)
0147 {
0148     read_lock_bh(&atalk_sockets_lock);
0149     return seq_hlist_start_head(&atalk_sockets, *pos);
0150 }
0151 
0152 static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
0153 {
0154     return seq_hlist_next(v, &atalk_sockets, pos);
0155 }
0156 
0157 static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
0158     __releases(atalk_sockets_lock)
0159 {
0160     read_unlock_bh(&atalk_sockets_lock);
0161 }
0162 
0163 static int atalk_seq_socket_show(struct seq_file *seq, void *v)
0164 {
0165     struct sock *s;
0166     struct atalk_sock *at;
0167 
0168     if (v == SEQ_START_TOKEN) {
0169         seq_printf(seq, "Type Local_addr  Remote_addr Tx_queue "
0170                 "Rx_queue St UID\n");
0171         goto out;
0172     }
0173 
0174     s = sk_entry(v);
0175     at = at_sk(s);
0176 
0177     seq_printf(seq, "%02X   %04X:%02X:%02X  %04X:%02X:%02X  %08X:%08X "
0178             "%02X %u\n",
0179            s->sk_type, ntohs(at->src_net), at->src_node, at->src_port,
0180            ntohs(at->dest_net), at->dest_node, at->dest_port,
0181            sk_wmem_alloc_get(s),
0182            sk_rmem_alloc_get(s),
0183            s->sk_state,
0184            from_kuid_munged(seq_user_ns(seq), sock_i_uid(s)));
0185 out:
0186     return 0;
0187 }
0188 
0189 static const struct seq_operations atalk_seq_interface_ops = {
0190     .start  = atalk_seq_interface_start,
0191     .next   = atalk_seq_interface_next,
0192     .stop   = atalk_seq_interface_stop,
0193     .show   = atalk_seq_interface_show,
0194 };
0195 
0196 static const struct seq_operations atalk_seq_route_ops = {
0197     .start  = atalk_seq_route_start,
0198     .next   = atalk_seq_route_next,
0199     .stop   = atalk_seq_route_stop,
0200     .show   = atalk_seq_route_show,
0201 };
0202 
0203 static const struct seq_operations atalk_seq_socket_ops = {
0204     .start  = atalk_seq_socket_start,
0205     .next   = atalk_seq_socket_next,
0206     .stop   = atalk_seq_socket_stop,
0207     .show   = atalk_seq_socket_show,
0208 };
0209 
0210 int __init atalk_proc_init(void)
0211 {
0212     if (!proc_mkdir("atalk", init_net.proc_net))
0213         return -ENOMEM;
0214 
0215     if (!proc_create_seq("atalk/interface", 0444, init_net.proc_net,
0216                 &atalk_seq_interface_ops))
0217         goto out;
0218 
0219     if (!proc_create_seq("atalk/route", 0444, init_net.proc_net,
0220                 &atalk_seq_route_ops))
0221         goto out;
0222 
0223     if (!proc_create_seq("atalk/socket", 0444, init_net.proc_net,
0224                 &atalk_seq_socket_ops))
0225         goto out;
0226 
0227     if (!proc_create_seq_private("atalk/arp", 0444, init_net.proc_net,
0228                      &aarp_seq_ops,
0229                      sizeof(struct aarp_iter_state), NULL))
0230         goto out;
0231 
0232     return 0;
0233 
0234 out:
0235     remove_proc_subtree("atalk", init_net.proc_net);
0236     return -ENOMEM;
0237 }
0238 
0239 void atalk_proc_exit(void)
0240 {
0241     remove_proc_subtree("atalk", init_net.proc_net);
0242 }