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_sockaddr_entry *laddr; 136 union sctp_addr *addr; 137 struct sctp_af *af; 138 139 list_for_each(pos, &epb->bind_addr.address_list) { 140 laddr = list_entry(pos, struct sctp_sockaddr_entry, list); 141 addr = (union sctp_addr *)&laddr->a; 142 af = sctp_get_af_specific(addr->sa.sa_family); 143 af->seq_dump_addr(seq, addr); 144 } 145 } 146 147 /* Dump remote addresses of an association. */ 148 static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc) 149 { 150 struct list_head *pos; 151 struct sctp_transport *transport; 152 union sctp_addr *addr; 153 struct sctp_af *af; 154 155 list_for_each(pos, &assoc->peer.transport_addr_list) { 156 transport = list_entry(pos, struct sctp_transport, transports); 157 addr = (union sctp_addr *)&transport->ipaddr; 158 af = sctp_get_af_specific(addr->sa.sa_family); 159 af->seq_dump_addr(seq, addr); 160 } 161 } 162 163 /* Display sctp endpoints (/proc/net/sctp/eps). */ 164 static int sctp_eps_seq_show(struct seq_file *seq, void *v) 165 { 166 struct sctp_hashbucket *head; 167 struct sctp_ep_common *epb; 168 struct sctp_endpoint *ep; 169 struct sock *sk; 170 int hash; 171 172 seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT LADDRS\n"); 173 for (hash = 0; hash < sctp_ep_hashsize; hash++) { 174 head = &sctp_ep_hashtable[hash]; 175 read_lock(&head->lock); 176 for (epb = head->chain; epb; epb = epb->next) { 177 ep = sctp_ep(epb); 178 sk = epb->sk; 179 seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk, 180 sctp_sk(sk)->type, sk->sk_state, hash, 181 epb->bind_addr.port); 182 sctp_seq_dump_local_addrs(seq, epb); 183 seq_printf(seq, "\n"); 184 } 185 read_unlock(&head->lock); 186 } 187 188 return 0; 189 } 190 191 /* Initialize the seq file operations for 'eps' object. */ 192 static int sctp_eps_seq_open(struct inode *inode, struct file *file) 193 { 194 return single_open(file, sctp_eps_seq_show, NULL); 195 } 196 197 static struct file_operations sctp_eps_seq_fops = { 198 .open = sctp_eps_seq_open, 199 .read = seq_read, 200 .llseek = seq_lseek, 201 .release = single_release, 202 }; 203 204 /* Set up the proc fs entry for 'eps' object. */ 205 int __init sctp_eps_proc_init(void) 206 { 207 struct proc_dir_entry *p; 208 209 p = create_proc_entry("eps", S_IRUGO, proc_net_sctp); 210 if (!p) 211 return -ENOMEM; 212 213 p->proc_fops = &sctp_eps_seq_fops; 214 215 return 0; 216 } 217 218 /* Cleanup the proc fs entry for 'eps' object. */ 219 void sctp_eps_proc_exit(void) 220 { 221 remove_proc_entry("eps", proc_net_sctp); 222 } 223 224 /* Display sctp associations (/proc/net/sctp/assocs). */ 225 static int sctp_assocs_seq_show(struct seq_file *seq, void *v) 226 { 227 struct sctp_hashbucket *head; 228 struct sctp_ep_common *epb; 229 struct sctp_association *assoc; 230 struct sock *sk; 231 int hash; 232 233 seq_printf(seq, " ASSOC SOCK STY SST ST HBKT LPORT RPORT " 234 "LADDRS <-> RADDRS\n"); 235 for (hash = 0; hash < sctp_assoc_hashsize; hash++) { 236 head = &sctp_assoc_hashtable[hash]; 237 read_lock(&head->lock); 238 for (epb = head->chain; epb; epb = epb->next) { 239 assoc = sctp_assoc(epb); 240 sk = epb->sk; 241 seq_printf(seq, 242 "%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ", 243 assoc, sk, sctp_sk(sk)->type, sk->sk_state, 244 assoc->state, hash, epb->bind_addr.port, 245 assoc->peer.port); 246 sctp_seq_dump_local_addrs(seq, epb); 247 seq_printf(seq, "<-> "); 248 sctp_seq_dump_remote_addrs(seq, assoc); 249 seq_printf(seq, "\n"); 250 } 251 read_unlock(&head->lock); 252 } 253 254 return 0; 255 } 256 257 /* Initialize the seq file operations for 'assocs' object. */ 258 static int sctp_assocs_seq_open(struct inode *inode, struct file *file) 259 { 260 return single_open(file, sctp_assocs_seq_show, NULL); 261 } 262 263 static struct file_operations sctp_assocs_seq_fops = { 264 .open = sctp_assocs_seq_open, 265 .read = seq_read, 266 .llseek = seq_lseek, 267 .release = single_release, 268 }; 269 270 /* Set up the proc fs entry for 'assocs' object. */ 271 int __init sctp_assocs_proc_init(void) 272 { 273 struct proc_dir_entry *p; 274 275 p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp); 276 if (!p) 277 return -ENOMEM; 278 279 p->proc_fops = &sctp_assocs_seq_fops; 280 281 return 0; 282 } 283 284 /* Cleanup the proc fs entry for 'assocs' object. */ 285 void sctp_assocs_proc_exit(void) 286 { 287 remove_proc_entry("assocs", proc_net_sctp); 288 } 289