1/* 2 * IPX proc routines 3 * 4 * Copyright(C) Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2002 5 */ 6 7#include <linux/init.h> 8#ifdef CONFIG_PROC_FS 9#include <linux/proc_fs.h> 10#include <linux/spinlock.h> 11#include <linux/seq_file.h> 12#include <linux/export.h> 13#include <net/net_namespace.h> 14#include <net/tcp_states.h> 15#include <net/ipx.h> 16 17static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) 18{ 19 spin_lock_bh(&ipx_interfaces_lock); 20 return seq_list_start_head(&ipx_interfaces, *pos); 21} 22 23static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) 24{ 25 return seq_list_next(v, &ipx_interfaces, pos); 26} 27 28static void ipx_seq_interface_stop(struct seq_file *seq, void *v) 29{ 30 spin_unlock_bh(&ipx_interfaces_lock); 31} 32 33static int ipx_seq_interface_show(struct seq_file *seq, void *v) 34{ 35 struct ipx_interface *i; 36 37 if (v == &ipx_interfaces) { 38 seq_puts(seq, "Network Node_Address Primary Device " 39 "Frame_Type"); 40#ifdef IPX_REFCNT_DEBUG 41 seq_puts(seq, " refcnt"); 42#endif 43 seq_puts(seq, "\n"); 44 goto out; 45 } 46 47 i = list_entry(v, struct ipx_interface, node); 48 seq_printf(seq, "%08X ", ntohl(i->if_netnum)); 49 seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", 50 i->if_node[0], i->if_node[1], i->if_node[2], 51 i->if_node[3], i->if_node[4], i->if_node[5]); 52 seq_printf(seq, "%-9s", i == ipx_primary_net ? "Yes" : "No"); 53 seq_printf(seq, "%-11s", ipx_device_name(i)); 54 seq_printf(seq, "%-9s", ipx_frame_name(i->if_dlink_type)); 55#ifdef IPX_REFCNT_DEBUG 56 seq_printf(seq, "%6d", atomic_read(&i->refcnt)); 57#endif 58 seq_puts(seq, "\n"); 59out: 60 return 0; 61} 62 63static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) 64{ 65 read_lock_bh(&ipx_routes_lock); 66 return seq_list_start_head(&ipx_routes, *pos); 67} 68 69static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) 70{ 71 return seq_list_next(v, &ipx_routes, pos); 72} 73 74static void ipx_seq_route_stop(struct seq_file *seq, void *v) 75{ 76 read_unlock_bh(&ipx_routes_lock); 77} 78 79static int ipx_seq_route_show(struct seq_file *seq, void *v) 80{ 81 struct ipx_route *rt; 82 83 if (v == &ipx_routes) { 84 seq_puts(seq, "Network Router_Net Router_Node\n"); 85 goto out; 86 } 87 88 rt = list_entry(v, struct ipx_route, node); 89 90 seq_printf(seq, "%08X ", ntohl(rt->ir_net)); 91 if (rt->ir_routed) 92 seq_printf(seq, "%08X %02X%02X%02X%02X%02X%02X\n", 93 ntohl(rt->ir_intrfc->if_netnum), 94 rt->ir_router_node[0], rt->ir_router_node[1], 95 rt->ir_router_node[2], rt->ir_router_node[3], 96 rt->ir_router_node[4], rt->ir_router_node[5]); 97 else 98 seq_puts(seq, "Directly Connected\n"); 99out: 100 return 0; 101} 102 103static __inline__ struct sock *ipx_get_socket_idx(loff_t pos) 104{ 105 struct sock *s = NULL; 106 struct ipx_interface *i; 107 108 list_for_each_entry(i, &ipx_interfaces, node) { 109 spin_lock_bh(&i->if_sklist_lock); 110 sk_for_each(s, &i->if_sklist) { 111 if (!pos) 112 break; 113 --pos; 114 } 115 spin_unlock_bh(&i->if_sklist_lock); 116 if (!pos) { 117 if (s) 118 goto found; 119 break; 120 } 121 } 122 s = NULL; 123found: 124 return s; 125} 126 127static void *ipx_seq_socket_start(struct seq_file *seq, loff_t *pos) 128{ 129 loff_t l = *pos; 130 131 spin_lock_bh(&ipx_interfaces_lock); 132 return l ? ipx_get_socket_idx(--l) : SEQ_START_TOKEN; 133} 134 135static void *ipx_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos) 136{ 137 struct sock* sk, *next; 138 struct ipx_interface *i; 139 struct ipx_sock *ipxs; 140 141 ++*pos; 142 if (v == SEQ_START_TOKEN) { 143 sk = NULL; 144 i = ipx_interfaces_head(); 145 if (!i) 146 goto out; 147 sk = sk_head(&i->if_sklist); 148 if (sk) 149 spin_lock_bh(&i->if_sklist_lock); 150 goto out; 151 } 152 sk = v; 153 next = sk_next(sk); 154 if (next) { 155 sk = next; 156 goto out; 157 } 158 ipxs = ipx_sk(sk); 159 i = ipxs->intrfc; 160 spin_unlock_bh(&i->if_sklist_lock); 161 sk = NULL; 162 for (;;) { 163 if (i->node.next == &ipx_interfaces) 164 break; 165 i = list_entry(i->node.next, struct ipx_interface, node); 166 spin_lock_bh(&i->if_sklist_lock); 167 if (!hlist_empty(&i->if_sklist)) { 168 sk = sk_head(&i->if_sklist); 169 break; 170 } 171 spin_unlock_bh(&i->if_sklist_lock); 172 } 173out: 174 return sk; 175} 176 177static int ipx_seq_socket_show(struct seq_file *seq, void *v) 178{ 179 struct sock *s; 180 struct ipx_sock *ipxs; 181 182 if (v == SEQ_START_TOKEN) { 183#ifdef CONFIG_IPX_INTERN 184 seq_puts(seq, "Local_Address " 185 "Remote_Address Tx_Queue " 186 "Rx_Queue State Uid\n"); 187#else 188 seq_puts(seq, "Local_Address Remote_Address " 189 "Tx_Queue Rx_Queue State Uid\n"); 190#endif 191 goto out; 192 } 193 194 s = v; 195 ipxs = ipx_sk(s); 196#ifdef CONFIG_IPX_INTERN 197 seq_printf(seq, "%08X:%02X%02X%02X%02X%02X%02X:%04X ", 198 ntohl(ipxs->intrfc->if_netnum), 199 ipxs->node[0], ipxs->node[1], ipxs->node[2], ipxs->node[3], 200 ipxs->node[4], ipxs->node[5], ntohs(ipxs->port)); 201#else 202 seq_printf(seq, "%08X:%04X ", ntohl(ipxs->intrfc->if_netnum), 203 ntohs(ipxs->port)); 204#endif /* CONFIG_IPX_INTERN */ 205 if (s->sk_state != TCP_ESTABLISHED) 206 seq_printf(seq, "%-28s", "Not_Connected"); 207 else { 208 seq_printf(seq, "%08X:%02X%02X%02X%02X%02X%02X:%04X ", 209 ntohl(ipxs->dest_addr.net), 210 ipxs->dest_addr.node[0], ipxs->dest_addr.node[1], 211 ipxs->dest_addr.node[2], ipxs->dest_addr.node[3], 212 ipxs->dest_addr.node[4], ipxs->dest_addr.node[5], 213 ntohs(ipxs->dest_addr.sock)); 214 } 215 216 seq_printf(seq, "%08X %08X %02X %03u\n", 217 sk_wmem_alloc_get(s), 218 sk_rmem_alloc_get(s), 219 s->sk_state, 220 from_kuid_munged(seq_user_ns(seq), sock_i_uid(s))); 221out: 222 return 0; 223} 224 225static const struct seq_operations ipx_seq_interface_ops = { 226 .start = ipx_seq_interface_start, 227 .next = ipx_seq_interface_next, 228 .stop = ipx_seq_interface_stop, 229 .show = ipx_seq_interface_show, 230}; 231 232static const struct seq_operations ipx_seq_route_ops = { 233 .start = ipx_seq_route_start, 234 .next = ipx_seq_route_next, 235 .stop = ipx_seq_route_stop, 236 .show = ipx_seq_route_show, 237}; 238 239static const struct seq_operations ipx_seq_socket_ops = { 240 .start = ipx_seq_socket_start, 241 .next = ipx_seq_socket_next, 242 .stop = ipx_seq_interface_stop, 243 .show = ipx_seq_socket_show, 244}; 245 246static int ipx_seq_route_open(struct inode *inode, struct file *file) 247{ 248 return seq_open(file, &ipx_seq_route_ops); 249} 250 251static int ipx_seq_interface_open(struct inode *inode, struct file *file) 252{ 253 return seq_open(file, &ipx_seq_interface_ops); 254} 255 256static int ipx_seq_socket_open(struct inode *inode, struct file *file) 257{ 258 return seq_open(file, &ipx_seq_socket_ops); 259} 260 261static const struct file_operations ipx_seq_interface_fops = { 262 .owner = THIS_MODULE, 263 .open = ipx_seq_interface_open, 264 .read = seq_read, 265 .llseek = seq_lseek, 266 .release = seq_release, 267}; 268 269static const struct file_operations ipx_seq_route_fops = { 270 .owner = THIS_MODULE, 271 .open = ipx_seq_route_open, 272 .read = seq_read, 273 .llseek = seq_lseek, 274 .release = seq_release, 275}; 276 277static const struct file_operations ipx_seq_socket_fops = { 278 .owner = THIS_MODULE, 279 .open = ipx_seq_socket_open, 280 .read = seq_read, 281 .llseek = seq_lseek, 282 .release = seq_release, 283}; 284 285static struct proc_dir_entry *ipx_proc_dir; 286 287int __init ipx_proc_init(void) 288{ 289 struct proc_dir_entry *p; 290 int rc = -ENOMEM; 291 292 ipx_proc_dir = proc_mkdir("ipx", init_net.proc_net); 293 294 if (!ipx_proc_dir) 295 goto out; 296 p = proc_create("interface", S_IRUGO, 297 ipx_proc_dir, &ipx_seq_interface_fops); 298 if (!p) 299 goto out_interface; 300 301 p = proc_create("route", S_IRUGO, ipx_proc_dir, &ipx_seq_route_fops); 302 if (!p) 303 goto out_route; 304 305 p = proc_create("socket", S_IRUGO, ipx_proc_dir, &ipx_seq_socket_fops); 306 if (!p) 307 goto out_socket; 308 309 rc = 0; 310out: 311 return rc; 312out_socket: 313 remove_proc_entry("route", ipx_proc_dir); 314out_route: 315 remove_proc_entry("interface", ipx_proc_dir); 316out_interface: 317 remove_proc_entry("ipx", init_net.proc_net); 318 goto out; 319} 320 321void __exit ipx_proc_exit(void) 322{ 323 remove_proc_entry("interface", ipx_proc_dir); 324 remove_proc_entry("route", ipx_proc_dir); 325 remove_proc_entry("socket", ipx_proc_dir); 326 remove_proc_entry("ipx", init_net.proc_net); 327} 328 329#else /* CONFIG_PROC_FS */ 330 331int __init ipx_proc_init(void) 332{ 333 return 0; 334} 335 336void __exit ipx_proc_exit(void) 337{ 338} 339 340#endif /* CONFIG_PROC_FS */ 341