0001
0002
0003
0004
0005
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 }