xref: /linux/net/sctp/proc.c (revision 36ca1195ad7f760a6af3814cb002bd3a3d4b4db1)
1 /* SCTP kernel reference Implementation
2  * Copyright (c) 2003 International Business Machines, Corp.
3  *
4  * This file is part of the SCTP kernel reference Implementation
5  *
6  * The SCTP reference implementation is free software;
7  * you can redistribute it and/or modify it under the terms of
8  * the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * The SCTP reference implementation is distributed in the hope that it
13  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
14  *                 ************************
15  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with GNU CC; see the file COPYING.  If not, write to
20  * the Free Software Foundation, 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * Please send any bug reports or fixes you make to the
24  * email address(es):
25  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
26  *
27  * Or submit a bug report through the following website:
28  *    http://www.sf.net/projects/lksctp
29  *
30  * Written or modified by:
31  *    Sridhar Samudrala <sri@us.ibm.com>
32  *
33  * Any bugs reported given to us we will try to fix... any fixes shared will
34  * be incorporated into the next SCTP release.
35  */
36 
37 #include <linux/types.h>
38 #include <linux/seq_file.h>
39 #include <linux/init.h>
40 #include <net/sctp/sctp.h>
41 
42 static struct snmp_mib sctp_snmp_list[] = {
43 	SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
44 	SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
45 	SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
46 	SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS),
47 	SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS),
48 	SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES),
49 	SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS),
50 	SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS),
51 	SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS),
52 	SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS),
53 	SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS),
54 	SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS),
55 	SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS),
56 	SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS),
57 	SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS),
58 	SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS),
59 	SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS),
60 };
61 
62 /* Return the current value of a particular entry in the mib by adding its
63  * per cpu counters.
64  */
65 static unsigned long
66 fold_field(void *mib[], int nr)
67 {
68 	unsigned long res = 0;
69 	int i;
70 
71 	for (i = 0; i < NR_CPUS; i++) {
72 		if (!cpu_possible(i))
73 			continue;
74 		res +=
75 		    *((unsigned long *) (((void *) per_cpu_ptr(mib[0], i)) +
76 					 sizeof (unsigned long) * nr));
77 		res +=
78 		    *((unsigned long *) (((void *) per_cpu_ptr(mib[1], i)) +
79 					 sizeof (unsigned long) * nr));
80 	}
81 	return res;
82 }
83 
84 /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
85 static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
86 {
87 	int i;
88 
89 	for (i = 0; sctp_snmp_list[i].name != NULL; i++)
90 		seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
91 			   fold_field((void **)sctp_statistics,
92 				      sctp_snmp_list[i].entry));
93 
94 	return 0;
95 }
96 
97 /* Initialize the seq file operations for 'snmp' object. */
98 static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
99 {
100 	return single_open(file, sctp_snmp_seq_show, NULL);
101 }
102 
103 static struct file_operations sctp_snmp_seq_fops = {
104 	.owner	 = THIS_MODULE,
105 	.open	 = sctp_snmp_seq_open,
106 	.read	 = seq_read,
107 	.llseek	 = seq_lseek,
108 	.release = single_release,
109 };
110 
111 /* Set up the proc fs entry for 'snmp' object. */
112 int __init sctp_snmp_proc_init(void)
113 {
114 	struct proc_dir_entry *p;
115 
116 	p = create_proc_entry("snmp", S_IRUGO, proc_net_sctp);
117 	if (!p)
118 		return -ENOMEM;
119 
120 	p->proc_fops = &sctp_snmp_seq_fops;
121 
122 	return 0;
123 }
124 
125 /* Cleanup the proc fs entry for 'snmp' object. */
126 void sctp_snmp_proc_exit(void)
127 {
128 	remove_proc_entry("snmp", proc_net_sctp);
129 }
130 
131 /* Dump local addresses of an association/endpoint. */
132 static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
133 {
134 	struct list_head *pos;
135 	struct sctp_association *asoc;
136 	struct sctp_sockaddr_entry *laddr;
137 	struct sctp_transport *peer;
138 	union sctp_addr *addr, *primary = NULL;
139 	struct sctp_af *af;
140 
141 	if (epb->type == SCTP_EP_TYPE_ASSOCIATION) {
142 	    asoc = sctp_assoc(epb);
143 	    peer = asoc->peer.primary_path;
144 	    primary = &peer->saddr;
145 	}
146 
147 	list_for_each(pos, &epb->bind_addr.address_list) {
148 		laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
149 		addr = (union sctp_addr *)&laddr->a;
150 		af = sctp_get_af_specific(addr->sa.sa_family);
151 		if (primary && af->cmp_addr(addr, primary)) {
152 			seq_printf(seq, "*");
153 		}
154 		af->seq_dump_addr(seq, addr);
155 	}
156 }
157 
158 /* Dump remote addresses of an association. */
159 static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
160 {
161 	struct list_head *pos;
162 	struct sctp_transport *transport;
163 	union sctp_addr *addr, *primary;
164 	struct sctp_af *af;
165 
166 	primary = &(assoc->peer.primary_addr);
167 	list_for_each(pos, &assoc->peer.transport_addr_list) {
168 		transport = list_entry(pos, struct sctp_transport, transports);
169 		addr = (union sctp_addr *)&transport->ipaddr;
170 		af = sctp_get_af_specific(addr->sa.sa_family);
171 		if (af->cmp_addr(addr, primary)) {
172 			seq_printf(seq, "*");
173 		}
174 		af->seq_dump_addr(seq, addr);
175 	}
176 }
177 
178 static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos)
179 {
180 	if (*pos > sctp_ep_hashsize)
181 		return NULL;
182 
183 	if (*pos < 0)
184 		*pos = 0;
185 
186 	if (*pos == 0)
187 		seq_printf(seq, " ENDPT     SOCK   STY SST HBKT LPORT   UID INODE LADDRS\n");
188 
189 	++*pos;
190 
191 	return (void *)pos;
192 }
193 
194 static void sctp_eps_seq_stop(struct seq_file *seq, void *v)
195 {
196 	return;
197 }
198 
199 
200 static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos)
201 {
202 	if (*pos > sctp_ep_hashsize)
203 		return NULL;
204 
205 	++*pos;
206 
207 	return pos;
208 }
209 
210 
211 /* Display sctp endpoints (/proc/net/sctp/eps). */
212 static int sctp_eps_seq_show(struct seq_file *seq, void *v)
213 {
214 	struct sctp_hashbucket *head;
215 	struct sctp_ep_common *epb;
216 	struct sctp_endpoint *ep;
217 	struct sock *sk;
218 	int    hash = *(int *)v;
219 
220 	if (hash > sctp_ep_hashsize)
221 		return -ENOMEM;
222 
223 	head = &sctp_ep_hashtable[hash-1];
224 	sctp_local_bh_disable();
225 	read_lock(&head->lock);
226 	for (epb = head->chain; epb; epb = epb->next) {
227 		ep = sctp_ep(epb);
228 		sk = epb->sk;
229 		seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
230 			   sctp_sk(sk)->type, sk->sk_state, hash-1,
231 			   epb->bind_addr.port,
232 			   sock_i_uid(sk), sock_i_ino(sk));
233 
234 		sctp_seq_dump_local_addrs(seq, epb);
235 		seq_printf(seq, "\n");
236 	}
237 	read_unlock(&head->lock);
238 	sctp_local_bh_enable();
239 
240 	return 0;
241 }
242 
243 static struct seq_operations sctp_eps_ops = {
244 	.start = sctp_eps_seq_start,
245 	.next  = sctp_eps_seq_next,
246 	.stop  = sctp_eps_seq_stop,
247 	.show  = sctp_eps_seq_show,
248 };
249 
250 
251 /* Initialize the seq file operations for 'eps' object. */
252 static int sctp_eps_seq_open(struct inode *inode, struct file *file)
253 {
254 	return seq_open(file, &sctp_eps_ops);
255 }
256 
257 static struct file_operations sctp_eps_seq_fops = {
258 	.open	 = sctp_eps_seq_open,
259 	.read	 = seq_read,
260 	.llseek	 = seq_lseek,
261 	.release = seq_release,
262 };
263 
264 /* Set up the proc fs entry for 'eps' object. */
265 int __init sctp_eps_proc_init(void)
266 {
267 	struct proc_dir_entry *p;
268 
269 	p = create_proc_entry("eps", S_IRUGO, proc_net_sctp);
270 	if (!p)
271 		return -ENOMEM;
272 
273 	p->proc_fops = &sctp_eps_seq_fops;
274 
275 	return 0;
276 }
277 
278 /* Cleanup the proc fs entry for 'eps' object. */
279 void sctp_eps_proc_exit(void)
280 {
281 	remove_proc_entry("eps", proc_net_sctp);
282 }
283 
284 
285 static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos)
286 {
287 	if (*pos > sctp_assoc_hashsize)
288 		return NULL;
289 
290 	if (*pos < 0)
291 		*pos = 0;
292 
293 	if (*pos == 0)
294 		seq_printf(seq, " ASSOC     SOCK   STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT "
295 				"RPORT LADDRS <-> RADDRS\n");
296 
297 	++*pos;
298 
299 	return (void *)pos;
300 }
301 
302 static void sctp_assocs_seq_stop(struct seq_file *seq, void *v)
303 {
304 	return;
305 }
306 
307 
308 static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos)
309 {
310 	if (*pos > sctp_assoc_hashsize)
311 		return NULL;
312 
313 	++*pos;
314 
315 	return pos;
316 }
317 
318 /* Display sctp associations (/proc/net/sctp/assocs). */
319 static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
320 {
321 	struct sctp_hashbucket *head;
322 	struct sctp_ep_common *epb;
323 	struct sctp_association *assoc;
324 	struct sock *sk;
325 	int    hash = *(int *)v;
326 
327 	if (hash > sctp_assoc_hashsize)
328 		return -ENOMEM;
329 
330 	head = &sctp_assoc_hashtable[hash-1];
331 	sctp_local_bh_disable();
332 	read_lock(&head->lock);
333 	for (epb = head->chain; epb; epb = epb->next) {
334 		assoc = sctp_assoc(epb);
335 		sk = epb->sk;
336 		seq_printf(seq,
337 			   "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ",
338 			   assoc, sk, sctp_sk(sk)->type, sk->sk_state,
339 			   assoc->state, hash-1, assoc->assoc_id,
340 			   (sk->sk_rcvbuf - assoc->rwnd),
341 			   assoc->sndbuf_used,
342 			   sock_i_uid(sk), sock_i_ino(sk),
343 			   epb->bind_addr.port,
344 			   assoc->peer.port);
345 
346 		seq_printf(seq, " ");
347 		sctp_seq_dump_local_addrs(seq, epb);
348 		seq_printf(seq, "<-> ");
349 		sctp_seq_dump_remote_addrs(seq, assoc);
350 		seq_printf(seq, "\n");
351 	}
352 	read_unlock(&head->lock);
353 	sctp_local_bh_enable();
354 
355 	return 0;
356 }
357 
358 static struct seq_operations sctp_assoc_ops = {
359 	.start = sctp_assocs_seq_start,
360 	.next  = sctp_assocs_seq_next,
361 	.stop  = sctp_assocs_seq_stop,
362 	.show  = sctp_assocs_seq_show,
363 };
364 
365 /* Initialize the seq file operations for 'assocs' object. */
366 static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
367 {
368 	return seq_open(file, &sctp_assoc_ops);
369 }
370 
371 static struct file_operations sctp_assocs_seq_fops = {
372 	.open	 = sctp_assocs_seq_open,
373 	.read	 = seq_read,
374 	.llseek	 = seq_lseek,
375 	.release = seq_release,
376 };
377 
378 /* Set up the proc fs entry for 'assocs' object. */
379 int __init sctp_assocs_proc_init(void)
380 {
381 	struct proc_dir_entry *p;
382 
383 	p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp);
384 	if (!p)
385 		return -ENOMEM;
386 
387 	p->proc_fops = &sctp_assocs_seq_fops;
388 
389 	return 0;
390 }
391 
392 /* Cleanup the proc fs entry for 'assocs' object. */
393 void sctp_assocs_proc_exit(void)
394 {
395 	remove_proc_entry("assocs", proc_net_sctp);
396 }
397