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