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 <net/net_namespace.h> 13#include <net/tcp_states.h> 14#include <net/ipx.h> 15 16static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos) 17{ 18 spin_lock_bh(&ipx_interfaces_lock); 19 return seq_list_start_head(&ipx_interfaces, *pos); 20} 21 22static void *ipx_seq_interface_next(struct seq_file *seq, void *v, loff_t *pos) 23{ 24 return seq_list_next(v, &ipx_interfaces, pos); 25} 26 27static void ipx_seq_interface_stop(struct seq_file *seq, void *v) 28{ 29 spin_unlock_bh(&ipx_interfaces_lock); 30} 31 32static int ipx_seq_interface_show(struct seq_file *seq, void *v) 33{ 34 struct ipx_interface *i; 35 36 if (v == &ipx_interfaces) { 37 seq_puts(seq, "Network Node_Address Primary Device " 38 "Frame_Type"); 39#ifdef IPX_REFCNT_DEBUG 40 seq_puts(seq, " refcnt"); 41#endif 42 seq_puts(seq, "\n"); 43 goto out; 44 } 45 46 i = list_entry(v, struct ipx_interface, node); 47 seq_printf(seq, "%08lX ", (unsigned long int)ntohl(i->if_netnum)); 48 seq_printf(seq, "%02X%02X%02X%02X%02X%02X ", 49 i->if_node[0], i->if_node[1], i->if_node[2], 50 i->if_node[3], i->if_node[4], i->if_node[5]); 51 seq_printf(seq, "%-9s", i == ipx_primary_net ? "Yes" : "No"); 52 seq_printf(seq, "%-11s", ipx_device_name(i)); 53 seq_printf(seq, "%-9s", ipx_frame_name(i->if_dlink_type)); 54#ifdef IPX_REFCNT_DEBUG 55 seq_printf(seq, "%6d", atomic_read(&i->refcnt)); 56#endif 57 seq_puts(seq, "\n"); 58out: 59 return 0; 60} 61 62static void *ipx_seq_route_start(struct seq_file *seq, loff_t *pos) 63{ 64 read_lock_bh(&ipx_routes_lock); 65 return seq_list_start_head(&ipx_routes, *pos); 66} 67 68static void *ipx_seq_route_next(struct seq_file *seq, void *v, loff_t *pos) 69{ 70 return seq_list_next(v, &ipx_routes, pos); 71} 72 73static void ipx_seq_route_stop(struct seq_file *seq, void *v) 74{ 75 read_unlock_bh(&ipx_routes_lock); 76} 77 78static int ipx_seq_route_show(struct seq_file *seq, void *v) 79{ 80 struct ipx_route *rt; 81 82 if (v == &ipx_routes) { 83 seq_puts(seq, "Network Router_Net Router_Node\n"); 84 goto out; 85 } 86 87 rt = list_entry(v, struct ipx_route, node); 88 89 seq_printf(seq, "%08lX ", (unsigned long int)ntohl(rt->ir_net)); 90 if (rt->ir_routed) 91 seq_printf(seq, "%08lX %02X%02X%02X%02X%02X%02X\n", 92 (long unsigned int)ntohl(rt->ir_intrfc->if_netnum), 93 rt->ir_router_node[0], rt->ir_router_node[1], 94 rt->ir_router_node[2], rt->ir_router_node[3], 95 rt->ir_router_node[4], rt->ir_router_node[5]); 96 else 97 seq_puts(seq, "Directly Connected\n"); 98out: 99 return 0; 100} 101 102static __inline__ struct sock *ipx_get_socket_idx(loff_t pos) 103{ 104 struct sock *s = NULL; 105 struct hlist_node *node; 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, node, &i->if_sklist) { 111 if (!pos) 112 break; 113 --pos; 114 } 115 spin_unlock_bh(&i->if_sklist_lock); 116 if (!pos) { 117 if (node) 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, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", 198 (unsigned long)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, "%08lX:%04X ", (unsigned long) 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, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", 209 (unsigned long)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 %03d\n", 217 sk_wmem_alloc_get(s), 218 sk_rmem_alloc_get(s), 219 s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); 220out: 221 return 0; 222} 223 224static const struct seq_operations ipx_seq_interface_ops = { 225 .start = ipx_seq_interface_start, 226 .next = ipx_seq_interface_next, 227 .stop = ipx_seq_interface_stop, 228 .show = ipx_seq_interface_show, 229}; 230 231static const struct seq_operations ipx_seq_route_ops = { 232 .start = ipx_seq_route_start, 233 .next = ipx_seq_route_next, 234 .stop = ipx_seq_route_stop, 235 .show = ipx_seq_route_show, 236}; 237 238static const struct seq_operations ipx_seq_socket_ops = { 239 .start = ipx_seq_socket_start, 240 .next = ipx_seq_socket_next, 241 .stop = ipx_seq_interface_stop, 242 .show = ipx_seq_socket_show, 243}; 244 245static int ipx_seq_route_open(struct inode *inode, struct file *file) 246{ 247 return seq_open(file, &ipx_seq_route_ops); 248} 249 250static int ipx_seq_interface_open(struct inode *inode, struct file *file) 251{ 252 return seq_open(file, &ipx_seq_interface_ops); 253} 254 255static int ipx_seq_socket_open(struct inode *inode, struct file *file) 256{ 257 return seq_open(file, &ipx_seq_socket_ops); 258} 259 260static const struct file_operations ipx_seq_interface_fops = { 261 .owner = THIS_MODULE, 262 .open = ipx_seq_interface_open, 263 .read = seq_read, 264 .llseek = seq_lseek, 265 .release = seq_release, 266}; 267 268static const struct file_operations ipx_seq_route_fops = { 269 .owner = THIS_MODULE, 270 .open = ipx_seq_route_open, 271 .read = seq_read, 272 .llseek = seq_lseek, 273 .release = seq_release, 274}; 275 276static const struct file_operations ipx_seq_socket_fops = { 277 .owner = THIS_MODULE, 278 .open = ipx_seq_socket_open, 279 .read = seq_read, 280 .llseek = seq_lseek, 281 .release = seq_release, 282}; 283 284static struct proc_dir_entry *ipx_proc_dir; 285 286int __init ipx_proc_init(void) 287{ 288 struct proc_dir_entry *p; 289 int rc = -ENOMEM; 290 291 ipx_proc_dir = proc_mkdir("ipx", init_net.proc_net); 292 293 if (!ipx_proc_dir) 294 goto out; 295 p = proc_create("interface", S_IRUGO, 296 ipx_proc_dir, &ipx_seq_interface_fops); 297 if (!p) 298 goto out_interface; 299 300 p = proc_create("route", S_IRUGO, ipx_proc_dir, &ipx_seq_route_fops); 301 if (!p) 302 goto out_route; 303 304 p = proc_create("socket", S_IRUGO, ipx_proc_dir, &ipx_seq_socket_fops); 305 if (!p) 306 goto out_socket; 307 308 rc = 0; 309out: 310 return rc; 311out_socket: 312 remove_proc_entry("route", ipx_proc_dir); 313out_route: 314 remove_proc_entry("interface", ipx_proc_dir); 315out_interface: 316 remove_proc_entry("ipx", init_net.proc_net); 317 goto out; 318} 319 320void __exit ipx_proc_exit(void) 321{ 322 remove_proc_entry("interface", ipx_proc_dir); 323 remove_proc_entry("route", ipx_proc_dir); 324 remove_proc_entry("socket", ipx_proc_dir); 325 remove_proc_entry("ipx", init_net.proc_net); 326} 327 328#else /* CONFIG_PROC_FS */ 329 330int __init ipx_proc_init(void) 331{ 332 return 0; 333} 334 335void __exit ipx_proc_exit(void) 336{ 337} 338 339#endif /* CONFIG_PROC_FS */ 340