Commit 0da9a0c2638c8476b4a5021841912f249e3187dc
Committed by
David S. Miller
1 parent
80d11788fb
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
sctp: fix /proc/net/sctp/ memory leak
Commit 13d782f ("sctp: Make the proc files per network namespace.") changed the /proc/net/sctp/ struct file_operations opener functions to use single_open_net() and seq_open_net(). Avoid leaking memory by using single_release_net() and seq_release_net() as the release functions. Discovered with Trinity (the syscall fuzzer). Signed-off-by: Tommi Rantala <tt.rantala@gmail.com> Acked-by: Neil Horman <nhorman@tuxdriver.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 4 additions and 4 deletions Inline Diff
net/sctp/proc.c
1 | /* SCTP kernel implementation | 1 | /* SCTP kernel implementation |
2 | * Copyright (c) 2003 International Business Machines, Corp. | 2 | * Copyright (c) 2003 International Business Machines, Corp. |
3 | * | 3 | * |
4 | * This file is part of the SCTP kernel implementation | 4 | * This file is part of the SCTP kernel implementation |
5 | * | 5 | * |
6 | * This SCTP implementation is free software; | 6 | * This SCTP implementation is free software; |
7 | * you can redistribute it and/or modify it under the terms of | 7 | * you can redistribute it and/or modify it under the terms of |
8 | * the GNU General Public License as published by | 8 | * the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2, or (at your option) | 9 | * the Free Software Foundation; either version 2, or (at your option) |
10 | * any later version. | 10 | * any later version. |
11 | * | 11 | * |
12 | * This SCTP implementation is distributed in the hope that it | 12 | * This SCTP implementation is distributed in the hope that it |
13 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied | 13 | * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
14 | * ************************ | 14 | * ************************ |
15 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 15 | * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
16 | * See the GNU General Public License for more details. | 16 | * See the GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 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 | 19 | * along with GNU CC; see the file COPYING. If not, write to |
20 | * the Free Software Foundation, 59 Temple Place - Suite 330, | 20 | * the Free Software Foundation, 59 Temple Place - Suite 330, |
21 | * Boston, MA 02111-1307, USA. | 21 | * Boston, MA 02111-1307, USA. |
22 | * | 22 | * |
23 | * Please send any bug reports or fixes you make to the | 23 | * Please send any bug reports or fixes you make to the |
24 | * email address(es): | 24 | * email address(es): |
25 | * lksctp developers <lksctp-developers@lists.sourceforge.net> | 25 | * lksctp developers <lksctp-developers@lists.sourceforge.net> |
26 | * | 26 | * |
27 | * Or submit a bug report through the following website: | 27 | * Or submit a bug report through the following website: |
28 | * http://www.sf.net/projects/lksctp | 28 | * http://www.sf.net/projects/lksctp |
29 | * | 29 | * |
30 | * Written or modified by: | 30 | * Written or modified by: |
31 | * Sridhar Samudrala <sri@us.ibm.com> | 31 | * Sridhar Samudrala <sri@us.ibm.com> |
32 | * | 32 | * |
33 | * Any bugs reported given to us we will try to fix... any fixes shared will | 33 | * Any bugs reported given to us we will try to fix... any fixes shared will |
34 | * be incorporated into the next SCTP release. | 34 | * be incorporated into the next SCTP release. |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/types.h> | 37 | #include <linux/types.h> |
38 | #include <linux/seq_file.h> | 38 | #include <linux/seq_file.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/export.h> | 40 | #include <linux/export.h> |
41 | #include <net/sctp/sctp.h> | 41 | #include <net/sctp/sctp.h> |
42 | #include <net/ip.h> /* for snmp_fold_field */ | 42 | #include <net/ip.h> /* for snmp_fold_field */ |
43 | 43 | ||
44 | static const struct snmp_mib sctp_snmp_list[] = { | 44 | static const struct snmp_mib sctp_snmp_list[] = { |
45 | SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB), | 45 | SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB), |
46 | SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS), | 46 | SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS), |
47 | SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS), | 47 | SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS), |
48 | SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS), | 48 | SNMP_MIB_ITEM("SctpAborteds", SCTP_MIB_ABORTEDS), |
49 | SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS), | 49 | SNMP_MIB_ITEM("SctpShutdowns", SCTP_MIB_SHUTDOWNS), |
50 | SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES), | 50 | SNMP_MIB_ITEM("SctpOutOfBlues", SCTP_MIB_OUTOFBLUES), |
51 | SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS), | 51 | SNMP_MIB_ITEM("SctpChecksumErrors", SCTP_MIB_CHECKSUMERRORS), |
52 | SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS), | 52 | SNMP_MIB_ITEM("SctpOutCtrlChunks", SCTP_MIB_OUTCTRLCHUNKS), |
53 | SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS), | 53 | SNMP_MIB_ITEM("SctpOutOrderChunks", SCTP_MIB_OUTORDERCHUNKS), |
54 | SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS), | 54 | SNMP_MIB_ITEM("SctpOutUnorderChunks", SCTP_MIB_OUTUNORDERCHUNKS), |
55 | SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS), | 55 | SNMP_MIB_ITEM("SctpInCtrlChunks", SCTP_MIB_INCTRLCHUNKS), |
56 | SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS), | 56 | SNMP_MIB_ITEM("SctpInOrderChunks", SCTP_MIB_INORDERCHUNKS), |
57 | SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS), | 57 | SNMP_MIB_ITEM("SctpInUnorderChunks", SCTP_MIB_INUNORDERCHUNKS), |
58 | SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS), | 58 | SNMP_MIB_ITEM("SctpFragUsrMsgs", SCTP_MIB_FRAGUSRMSGS), |
59 | SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS), | 59 | SNMP_MIB_ITEM("SctpReasmUsrMsgs", SCTP_MIB_REASMUSRMSGS), |
60 | SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS), | 60 | SNMP_MIB_ITEM("SctpOutSCTPPacks", SCTP_MIB_OUTSCTPPACKS), |
61 | SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS), | 61 | SNMP_MIB_ITEM("SctpInSCTPPacks", SCTP_MIB_INSCTPPACKS), |
62 | SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS), | 62 | SNMP_MIB_ITEM("SctpT1InitExpireds", SCTP_MIB_T1_INIT_EXPIREDS), |
63 | SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS), | 63 | SNMP_MIB_ITEM("SctpT1CookieExpireds", SCTP_MIB_T1_COOKIE_EXPIREDS), |
64 | SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS), | 64 | SNMP_MIB_ITEM("SctpT2ShutdownExpireds", SCTP_MIB_T2_SHUTDOWN_EXPIREDS), |
65 | SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS), | 65 | SNMP_MIB_ITEM("SctpT3RtxExpireds", SCTP_MIB_T3_RTX_EXPIREDS), |
66 | SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS), | 66 | SNMP_MIB_ITEM("SctpT4RtoExpireds", SCTP_MIB_T4_RTO_EXPIREDS), |
67 | SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS), | 67 | SNMP_MIB_ITEM("SctpT5ShutdownGuardExpireds", SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS), |
68 | SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS), | 68 | SNMP_MIB_ITEM("SctpDelaySackExpireds", SCTP_MIB_DELAY_SACK_EXPIREDS), |
69 | SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS), | 69 | SNMP_MIB_ITEM("SctpAutocloseExpireds", SCTP_MIB_AUTOCLOSE_EXPIREDS), |
70 | SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS), | 70 | SNMP_MIB_ITEM("SctpT3Retransmits", SCTP_MIB_T3_RETRANSMITS), |
71 | SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS), | 71 | SNMP_MIB_ITEM("SctpPmtudRetransmits", SCTP_MIB_PMTUD_RETRANSMITS), |
72 | SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS), | 72 | SNMP_MIB_ITEM("SctpFastRetransmits", SCTP_MIB_FAST_RETRANSMITS), |
73 | SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ), | 73 | SNMP_MIB_ITEM("SctpInPktSoftirq", SCTP_MIB_IN_PKT_SOFTIRQ), |
74 | SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG), | 74 | SNMP_MIB_ITEM("SctpInPktBacklog", SCTP_MIB_IN_PKT_BACKLOG), |
75 | SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS), | 75 | SNMP_MIB_ITEM("SctpInPktDiscards", SCTP_MIB_IN_PKT_DISCARDS), |
76 | SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS), | 76 | SNMP_MIB_ITEM("SctpInDataChunkDiscards", SCTP_MIB_IN_DATA_CHUNK_DISCARDS), |
77 | SNMP_MIB_SENTINEL | 77 | SNMP_MIB_SENTINEL |
78 | }; | 78 | }; |
79 | 79 | ||
80 | /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */ | 80 | /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */ |
81 | static int sctp_snmp_seq_show(struct seq_file *seq, void *v) | 81 | static int sctp_snmp_seq_show(struct seq_file *seq, void *v) |
82 | { | 82 | { |
83 | struct net *net = seq->private; | 83 | struct net *net = seq->private; |
84 | int i; | 84 | int i; |
85 | 85 | ||
86 | for (i = 0; sctp_snmp_list[i].name != NULL; i++) | 86 | for (i = 0; sctp_snmp_list[i].name != NULL; i++) |
87 | seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name, | 87 | seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name, |
88 | snmp_fold_field((void __percpu **)net->sctp.sctp_statistics, | 88 | snmp_fold_field((void __percpu **)net->sctp.sctp_statistics, |
89 | sctp_snmp_list[i].entry)); | 89 | sctp_snmp_list[i].entry)); |
90 | 90 | ||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | /* Initialize the seq file operations for 'snmp' object. */ | 94 | /* Initialize the seq file operations for 'snmp' object. */ |
95 | static int sctp_snmp_seq_open(struct inode *inode, struct file *file) | 95 | static int sctp_snmp_seq_open(struct inode *inode, struct file *file) |
96 | { | 96 | { |
97 | return single_open_net(inode, file, sctp_snmp_seq_show); | 97 | return single_open_net(inode, file, sctp_snmp_seq_show); |
98 | } | 98 | } |
99 | 99 | ||
100 | static const struct file_operations sctp_snmp_seq_fops = { | 100 | static const struct file_operations sctp_snmp_seq_fops = { |
101 | .owner = THIS_MODULE, | 101 | .owner = THIS_MODULE, |
102 | .open = sctp_snmp_seq_open, | 102 | .open = sctp_snmp_seq_open, |
103 | .read = seq_read, | 103 | .read = seq_read, |
104 | .llseek = seq_lseek, | 104 | .llseek = seq_lseek, |
105 | .release = single_release, | 105 | .release = single_release_net, |
106 | }; | 106 | }; |
107 | 107 | ||
108 | /* Set up the proc fs entry for 'snmp' object. */ | 108 | /* Set up the proc fs entry for 'snmp' object. */ |
109 | int __net_init sctp_snmp_proc_init(struct net *net) | 109 | int __net_init sctp_snmp_proc_init(struct net *net) |
110 | { | 110 | { |
111 | struct proc_dir_entry *p; | 111 | struct proc_dir_entry *p; |
112 | 112 | ||
113 | p = proc_create("snmp", S_IRUGO, net->sctp.proc_net_sctp, | 113 | p = proc_create("snmp", S_IRUGO, net->sctp.proc_net_sctp, |
114 | &sctp_snmp_seq_fops); | 114 | &sctp_snmp_seq_fops); |
115 | if (!p) | 115 | if (!p) |
116 | return -ENOMEM; | 116 | return -ENOMEM; |
117 | 117 | ||
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | /* Cleanup the proc fs entry for 'snmp' object. */ | 121 | /* Cleanup the proc fs entry for 'snmp' object. */ |
122 | void sctp_snmp_proc_exit(struct net *net) | 122 | void sctp_snmp_proc_exit(struct net *net) |
123 | { | 123 | { |
124 | remove_proc_entry("snmp", net->sctp.proc_net_sctp); | 124 | remove_proc_entry("snmp", net->sctp.proc_net_sctp); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* Dump local addresses of an association/endpoint. */ | 127 | /* Dump local addresses of an association/endpoint. */ |
128 | static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) | 128 | static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) |
129 | { | 129 | { |
130 | struct sctp_association *asoc; | 130 | struct sctp_association *asoc; |
131 | struct sctp_sockaddr_entry *laddr; | 131 | struct sctp_sockaddr_entry *laddr; |
132 | struct sctp_transport *peer; | 132 | struct sctp_transport *peer; |
133 | union sctp_addr *addr, *primary = NULL; | 133 | union sctp_addr *addr, *primary = NULL; |
134 | struct sctp_af *af; | 134 | struct sctp_af *af; |
135 | 135 | ||
136 | if (epb->type == SCTP_EP_TYPE_ASSOCIATION) { | 136 | if (epb->type == SCTP_EP_TYPE_ASSOCIATION) { |
137 | asoc = sctp_assoc(epb); | 137 | asoc = sctp_assoc(epb); |
138 | peer = asoc->peer.primary_path; | 138 | peer = asoc->peer.primary_path; |
139 | primary = &peer->saddr; | 139 | primary = &peer->saddr; |
140 | } | 140 | } |
141 | 141 | ||
142 | list_for_each_entry(laddr, &epb->bind_addr.address_list, list) { | 142 | list_for_each_entry(laddr, &epb->bind_addr.address_list, list) { |
143 | addr = &laddr->a; | 143 | addr = &laddr->a; |
144 | af = sctp_get_af_specific(addr->sa.sa_family); | 144 | af = sctp_get_af_specific(addr->sa.sa_family); |
145 | if (primary && af->cmp_addr(addr, primary)) { | 145 | if (primary && af->cmp_addr(addr, primary)) { |
146 | seq_printf(seq, "*"); | 146 | seq_printf(seq, "*"); |
147 | } | 147 | } |
148 | af->seq_dump_addr(seq, addr); | 148 | af->seq_dump_addr(seq, addr); |
149 | } | 149 | } |
150 | } | 150 | } |
151 | 151 | ||
152 | /* Dump remote addresses of an association. */ | 152 | /* Dump remote addresses of an association. */ |
153 | static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc) | 153 | static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc) |
154 | { | 154 | { |
155 | struct sctp_transport *transport; | 155 | struct sctp_transport *transport; |
156 | union sctp_addr *addr, *primary; | 156 | union sctp_addr *addr, *primary; |
157 | struct sctp_af *af; | 157 | struct sctp_af *af; |
158 | 158 | ||
159 | primary = &assoc->peer.primary_addr; | 159 | primary = &assoc->peer.primary_addr; |
160 | list_for_each_entry(transport, &assoc->peer.transport_addr_list, | 160 | list_for_each_entry(transport, &assoc->peer.transport_addr_list, |
161 | transports) { | 161 | transports) { |
162 | addr = &transport->ipaddr; | 162 | addr = &transport->ipaddr; |
163 | af = sctp_get_af_specific(addr->sa.sa_family); | 163 | af = sctp_get_af_specific(addr->sa.sa_family); |
164 | if (af->cmp_addr(addr, primary)) { | 164 | if (af->cmp_addr(addr, primary)) { |
165 | seq_printf(seq, "*"); | 165 | seq_printf(seq, "*"); |
166 | } | 166 | } |
167 | af->seq_dump_addr(seq, addr); | 167 | af->seq_dump_addr(seq, addr); |
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) | 171 | static void * sctp_eps_seq_start(struct seq_file *seq, loff_t *pos) |
172 | { | 172 | { |
173 | if (*pos >= sctp_ep_hashsize) | 173 | if (*pos >= sctp_ep_hashsize) |
174 | return NULL; | 174 | return NULL; |
175 | 175 | ||
176 | if (*pos < 0) | 176 | if (*pos < 0) |
177 | *pos = 0; | 177 | *pos = 0; |
178 | 178 | ||
179 | if (*pos == 0) | 179 | if (*pos == 0) |
180 | seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n"); | 180 | seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT UID INODE LADDRS\n"); |
181 | 181 | ||
182 | return (void *)pos; | 182 | return (void *)pos; |
183 | } | 183 | } |
184 | 184 | ||
185 | static void sctp_eps_seq_stop(struct seq_file *seq, void *v) | 185 | static void sctp_eps_seq_stop(struct seq_file *seq, void *v) |
186 | { | 186 | { |
187 | } | 187 | } |
188 | 188 | ||
189 | 189 | ||
190 | static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 190 | static void * sctp_eps_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
191 | { | 191 | { |
192 | if (++*pos >= sctp_ep_hashsize) | 192 | if (++*pos >= sctp_ep_hashsize) |
193 | return NULL; | 193 | return NULL; |
194 | 194 | ||
195 | return pos; | 195 | return pos; |
196 | } | 196 | } |
197 | 197 | ||
198 | 198 | ||
199 | /* Display sctp endpoints (/proc/net/sctp/eps). */ | 199 | /* Display sctp endpoints (/proc/net/sctp/eps). */ |
200 | static int sctp_eps_seq_show(struct seq_file *seq, void *v) | 200 | static int sctp_eps_seq_show(struct seq_file *seq, void *v) |
201 | { | 201 | { |
202 | struct sctp_hashbucket *head; | 202 | struct sctp_hashbucket *head; |
203 | struct sctp_ep_common *epb; | 203 | struct sctp_ep_common *epb; |
204 | struct sctp_endpoint *ep; | 204 | struct sctp_endpoint *ep; |
205 | struct sock *sk; | 205 | struct sock *sk; |
206 | struct hlist_node *node; | 206 | struct hlist_node *node; |
207 | int hash = *(loff_t *)v; | 207 | int hash = *(loff_t *)v; |
208 | 208 | ||
209 | if (hash >= sctp_ep_hashsize) | 209 | if (hash >= sctp_ep_hashsize) |
210 | return -ENOMEM; | 210 | return -ENOMEM; |
211 | 211 | ||
212 | head = &sctp_ep_hashtable[hash]; | 212 | head = &sctp_ep_hashtable[hash]; |
213 | sctp_local_bh_disable(); | 213 | sctp_local_bh_disable(); |
214 | read_lock(&head->lock); | 214 | read_lock(&head->lock); |
215 | sctp_for_each_hentry(epb, node, &head->chain) { | 215 | sctp_for_each_hentry(epb, node, &head->chain) { |
216 | ep = sctp_ep(epb); | 216 | ep = sctp_ep(epb); |
217 | sk = epb->sk; | 217 | sk = epb->sk; |
218 | if (!net_eq(sock_net(sk), seq_file_net(seq))) | 218 | if (!net_eq(sock_net(sk), seq_file_net(seq))) |
219 | continue; | 219 | continue; |
220 | seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, | 220 | seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk, |
221 | sctp_sk(sk)->type, sk->sk_state, hash, | 221 | sctp_sk(sk)->type, sk->sk_state, hash, |
222 | epb->bind_addr.port, | 222 | epb->bind_addr.port, |
223 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), | 223 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), |
224 | sock_i_ino(sk)); | 224 | sock_i_ino(sk)); |
225 | 225 | ||
226 | sctp_seq_dump_local_addrs(seq, epb); | 226 | sctp_seq_dump_local_addrs(seq, epb); |
227 | seq_printf(seq, "\n"); | 227 | seq_printf(seq, "\n"); |
228 | } | 228 | } |
229 | read_unlock(&head->lock); | 229 | read_unlock(&head->lock); |
230 | sctp_local_bh_enable(); | 230 | sctp_local_bh_enable(); |
231 | 231 | ||
232 | return 0; | 232 | return 0; |
233 | } | 233 | } |
234 | 234 | ||
235 | static const struct seq_operations sctp_eps_ops = { | 235 | static const struct seq_operations sctp_eps_ops = { |
236 | .start = sctp_eps_seq_start, | 236 | .start = sctp_eps_seq_start, |
237 | .next = sctp_eps_seq_next, | 237 | .next = sctp_eps_seq_next, |
238 | .stop = sctp_eps_seq_stop, | 238 | .stop = sctp_eps_seq_stop, |
239 | .show = sctp_eps_seq_show, | 239 | .show = sctp_eps_seq_show, |
240 | }; | 240 | }; |
241 | 241 | ||
242 | 242 | ||
243 | /* Initialize the seq file operations for 'eps' object. */ | 243 | /* Initialize the seq file operations for 'eps' object. */ |
244 | static int sctp_eps_seq_open(struct inode *inode, struct file *file) | 244 | static int sctp_eps_seq_open(struct inode *inode, struct file *file) |
245 | { | 245 | { |
246 | return seq_open_net(inode, file, &sctp_eps_ops, | 246 | return seq_open_net(inode, file, &sctp_eps_ops, |
247 | sizeof(struct seq_net_private)); | 247 | sizeof(struct seq_net_private)); |
248 | } | 248 | } |
249 | 249 | ||
250 | static const struct file_operations sctp_eps_seq_fops = { | 250 | static const struct file_operations sctp_eps_seq_fops = { |
251 | .open = sctp_eps_seq_open, | 251 | .open = sctp_eps_seq_open, |
252 | .read = seq_read, | 252 | .read = seq_read, |
253 | .llseek = seq_lseek, | 253 | .llseek = seq_lseek, |
254 | .release = seq_release, | 254 | .release = seq_release_net, |
255 | }; | 255 | }; |
256 | 256 | ||
257 | /* Set up the proc fs entry for 'eps' object. */ | 257 | /* Set up the proc fs entry for 'eps' object. */ |
258 | int __net_init sctp_eps_proc_init(struct net *net) | 258 | int __net_init sctp_eps_proc_init(struct net *net) |
259 | { | 259 | { |
260 | struct proc_dir_entry *p; | 260 | struct proc_dir_entry *p; |
261 | 261 | ||
262 | p = proc_create("eps", S_IRUGO, net->sctp.proc_net_sctp, | 262 | p = proc_create("eps", S_IRUGO, net->sctp.proc_net_sctp, |
263 | &sctp_eps_seq_fops); | 263 | &sctp_eps_seq_fops); |
264 | if (!p) | 264 | if (!p) |
265 | return -ENOMEM; | 265 | return -ENOMEM; |
266 | 266 | ||
267 | return 0; | 267 | return 0; |
268 | } | 268 | } |
269 | 269 | ||
270 | /* Cleanup the proc fs entry for 'eps' object. */ | 270 | /* Cleanup the proc fs entry for 'eps' object. */ |
271 | void sctp_eps_proc_exit(struct net *net) | 271 | void sctp_eps_proc_exit(struct net *net) |
272 | { | 272 | { |
273 | remove_proc_entry("eps", net->sctp.proc_net_sctp); | 273 | remove_proc_entry("eps", net->sctp.proc_net_sctp); |
274 | } | 274 | } |
275 | 275 | ||
276 | 276 | ||
277 | static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) | 277 | static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) |
278 | { | 278 | { |
279 | if (*pos >= sctp_assoc_hashsize) | 279 | if (*pos >= sctp_assoc_hashsize) |
280 | return NULL; | 280 | return NULL; |
281 | 281 | ||
282 | if (*pos < 0) | 282 | if (*pos < 0) |
283 | *pos = 0; | 283 | *pos = 0; |
284 | 284 | ||
285 | if (*pos == 0) | 285 | if (*pos == 0) |
286 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT " | 286 | seq_printf(seq, " ASSOC SOCK STY SST ST HBKT " |
287 | "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " | 287 | "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " |
288 | "RPORT LADDRS <-> RADDRS " | 288 | "RPORT LADDRS <-> RADDRS " |
289 | "HBINT INS OUTS MAXRT T1X T2X RTXC\n"); | 289 | "HBINT INS OUTS MAXRT T1X T2X RTXC\n"); |
290 | 290 | ||
291 | return (void *)pos; | 291 | return (void *)pos; |
292 | } | 292 | } |
293 | 293 | ||
294 | static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) | 294 | static void sctp_assocs_seq_stop(struct seq_file *seq, void *v) |
295 | { | 295 | { |
296 | } | 296 | } |
297 | 297 | ||
298 | 298 | ||
299 | static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 299 | static void * sctp_assocs_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
300 | { | 300 | { |
301 | if (++*pos >= sctp_assoc_hashsize) | 301 | if (++*pos >= sctp_assoc_hashsize) |
302 | return NULL; | 302 | return NULL; |
303 | 303 | ||
304 | return pos; | 304 | return pos; |
305 | } | 305 | } |
306 | 306 | ||
307 | /* Display sctp associations (/proc/net/sctp/assocs). */ | 307 | /* Display sctp associations (/proc/net/sctp/assocs). */ |
308 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) | 308 | static int sctp_assocs_seq_show(struct seq_file *seq, void *v) |
309 | { | 309 | { |
310 | struct sctp_hashbucket *head; | 310 | struct sctp_hashbucket *head; |
311 | struct sctp_ep_common *epb; | 311 | struct sctp_ep_common *epb; |
312 | struct sctp_association *assoc; | 312 | struct sctp_association *assoc; |
313 | struct sock *sk; | 313 | struct sock *sk; |
314 | struct hlist_node *node; | 314 | struct hlist_node *node; |
315 | int hash = *(loff_t *)v; | 315 | int hash = *(loff_t *)v; |
316 | 316 | ||
317 | if (hash >= sctp_assoc_hashsize) | 317 | if (hash >= sctp_assoc_hashsize) |
318 | return -ENOMEM; | 318 | return -ENOMEM; |
319 | 319 | ||
320 | head = &sctp_assoc_hashtable[hash]; | 320 | head = &sctp_assoc_hashtable[hash]; |
321 | sctp_local_bh_disable(); | 321 | sctp_local_bh_disable(); |
322 | read_lock(&head->lock); | 322 | read_lock(&head->lock); |
323 | sctp_for_each_hentry(epb, node, &head->chain) { | 323 | sctp_for_each_hentry(epb, node, &head->chain) { |
324 | assoc = sctp_assoc(epb); | 324 | assoc = sctp_assoc(epb); |
325 | sk = epb->sk; | 325 | sk = epb->sk; |
326 | if (!net_eq(sock_net(sk), seq_file_net(seq))) | 326 | if (!net_eq(sock_net(sk), seq_file_net(seq))) |
327 | continue; | 327 | continue; |
328 | seq_printf(seq, | 328 | seq_printf(seq, |
329 | "%8pK %8pK %-3d %-3d %-2d %-4d " | 329 | "%8pK %8pK %-3d %-3d %-2d %-4d " |
330 | "%4d %8d %8d %7d %5lu %-5d %5d ", | 330 | "%4d %8d %8d %7d %5lu %-5d %5d ", |
331 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, | 331 | assoc, sk, sctp_sk(sk)->type, sk->sk_state, |
332 | assoc->state, hash, | 332 | assoc->state, hash, |
333 | assoc->assoc_id, | 333 | assoc->assoc_id, |
334 | assoc->sndbuf_used, | 334 | assoc->sndbuf_used, |
335 | atomic_read(&assoc->rmem_alloc), | 335 | atomic_read(&assoc->rmem_alloc), |
336 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), | 336 | from_kuid_munged(seq_user_ns(seq), sock_i_uid(sk)), |
337 | sock_i_ino(sk), | 337 | sock_i_ino(sk), |
338 | epb->bind_addr.port, | 338 | epb->bind_addr.port, |
339 | assoc->peer.port); | 339 | assoc->peer.port); |
340 | seq_printf(seq, " "); | 340 | seq_printf(seq, " "); |
341 | sctp_seq_dump_local_addrs(seq, epb); | 341 | sctp_seq_dump_local_addrs(seq, epb); |
342 | seq_printf(seq, "<-> "); | 342 | seq_printf(seq, "<-> "); |
343 | sctp_seq_dump_remote_addrs(seq, assoc); | 343 | sctp_seq_dump_remote_addrs(seq, assoc); |
344 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ", | 344 | seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ", |
345 | assoc->hbinterval, assoc->c.sinit_max_instreams, | 345 | assoc->hbinterval, assoc->c.sinit_max_instreams, |
346 | assoc->c.sinit_num_ostreams, assoc->max_retrans, | 346 | assoc->c.sinit_num_ostreams, assoc->max_retrans, |
347 | assoc->init_retries, assoc->shutdown_retries, | 347 | assoc->init_retries, assoc->shutdown_retries, |
348 | assoc->rtx_data_chunks); | 348 | assoc->rtx_data_chunks); |
349 | seq_printf(seq, "\n"); | 349 | seq_printf(seq, "\n"); |
350 | } | 350 | } |
351 | read_unlock(&head->lock); | 351 | read_unlock(&head->lock); |
352 | sctp_local_bh_enable(); | 352 | sctp_local_bh_enable(); |
353 | 353 | ||
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
356 | 356 | ||
357 | static const struct seq_operations sctp_assoc_ops = { | 357 | static const struct seq_operations sctp_assoc_ops = { |
358 | .start = sctp_assocs_seq_start, | 358 | .start = sctp_assocs_seq_start, |
359 | .next = sctp_assocs_seq_next, | 359 | .next = sctp_assocs_seq_next, |
360 | .stop = sctp_assocs_seq_stop, | 360 | .stop = sctp_assocs_seq_stop, |
361 | .show = sctp_assocs_seq_show, | 361 | .show = sctp_assocs_seq_show, |
362 | }; | 362 | }; |
363 | 363 | ||
364 | /* Initialize the seq file operations for 'assocs' object. */ | 364 | /* Initialize the seq file operations for 'assocs' object. */ |
365 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) | 365 | static int sctp_assocs_seq_open(struct inode *inode, struct file *file) |
366 | { | 366 | { |
367 | return seq_open_net(inode, file, &sctp_assoc_ops, | 367 | return seq_open_net(inode, file, &sctp_assoc_ops, |
368 | sizeof(struct seq_net_private)); | 368 | sizeof(struct seq_net_private)); |
369 | } | 369 | } |
370 | 370 | ||
371 | static const struct file_operations sctp_assocs_seq_fops = { | 371 | static const struct file_operations sctp_assocs_seq_fops = { |
372 | .open = sctp_assocs_seq_open, | 372 | .open = sctp_assocs_seq_open, |
373 | .read = seq_read, | 373 | .read = seq_read, |
374 | .llseek = seq_lseek, | 374 | .llseek = seq_lseek, |
375 | .release = seq_release, | 375 | .release = seq_release_net, |
376 | }; | 376 | }; |
377 | 377 | ||
378 | /* Set up the proc fs entry for 'assocs' object. */ | 378 | /* Set up the proc fs entry for 'assocs' object. */ |
379 | int __net_init sctp_assocs_proc_init(struct net *net) | 379 | int __net_init sctp_assocs_proc_init(struct net *net) |
380 | { | 380 | { |
381 | struct proc_dir_entry *p; | 381 | struct proc_dir_entry *p; |
382 | 382 | ||
383 | p = proc_create("assocs", S_IRUGO, net->sctp.proc_net_sctp, | 383 | p = proc_create("assocs", S_IRUGO, net->sctp.proc_net_sctp, |
384 | &sctp_assocs_seq_fops); | 384 | &sctp_assocs_seq_fops); |
385 | if (!p) | 385 | if (!p) |
386 | return -ENOMEM; | 386 | return -ENOMEM; |
387 | 387 | ||
388 | return 0; | 388 | return 0; |
389 | } | 389 | } |
390 | 390 | ||
391 | /* Cleanup the proc fs entry for 'assocs' object. */ | 391 | /* Cleanup the proc fs entry for 'assocs' object. */ |
392 | void sctp_assocs_proc_exit(struct net *net) | 392 | void sctp_assocs_proc_exit(struct net *net) |
393 | { | 393 | { |
394 | remove_proc_entry("assocs", net->sctp.proc_net_sctp); | 394 | remove_proc_entry("assocs", net->sctp.proc_net_sctp); |
395 | } | 395 | } |
396 | 396 | ||
397 | static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) | 397 | static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos) |
398 | { | 398 | { |
399 | if (*pos >= sctp_assoc_hashsize) | 399 | if (*pos >= sctp_assoc_hashsize) |
400 | return NULL; | 400 | return NULL; |
401 | 401 | ||
402 | if (*pos < 0) | 402 | if (*pos < 0) |
403 | *pos = 0; | 403 | *pos = 0; |
404 | 404 | ||
405 | if (*pos == 0) | 405 | if (*pos == 0) |
406 | seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " | 406 | seq_printf(seq, "ADDR ASSOC_ID HB_ACT RTO MAX_PATH_RTX " |
407 | "REM_ADDR_RTX START\n"); | 407 | "REM_ADDR_RTX START\n"); |
408 | 408 | ||
409 | return (void *)pos; | 409 | return (void *)pos; |
410 | } | 410 | } |
411 | 411 | ||
412 | static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 412 | static void *sctp_remaddr_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
413 | { | 413 | { |
414 | if (++*pos >= sctp_assoc_hashsize) | 414 | if (++*pos >= sctp_assoc_hashsize) |
415 | return NULL; | 415 | return NULL; |
416 | 416 | ||
417 | return pos; | 417 | return pos; |
418 | } | 418 | } |
419 | 419 | ||
420 | static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) | 420 | static void sctp_remaddr_seq_stop(struct seq_file *seq, void *v) |
421 | { | 421 | { |
422 | } | 422 | } |
423 | 423 | ||
424 | static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) | 424 | static int sctp_remaddr_seq_show(struct seq_file *seq, void *v) |
425 | { | 425 | { |
426 | struct sctp_hashbucket *head; | 426 | struct sctp_hashbucket *head; |
427 | struct sctp_ep_common *epb; | 427 | struct sctp_ep_common *epb; |
428 | struct sctp_association *assoc; | 428 | struct sctp_association *assoc; |
429 | struct hlist_node *node; | 429 | struct hlist_node *node; |
430 | struct sctp_transport *tsp; | 430 | struct sctp_transport *tsp; |
431 | int hash = *(loff_t *)v; | 431 | int hash = *(loff_t *)v; |
432 | 432 | ||
433 | if (hash >= sctp_assoc_hashsize) | 433 | if (hash >= sctp_assoc_hashsize) |
434 | return -ENOMEM; | 434 | return -ENOMEM; |
435 | 435 | ||
436 | head = &sctp_assoc_hashtable[hash]; | 436 | head = &sctp_assoc_hashtable[hash]; |
437 | sctp_local_bh_disable(); | 437 | sctp_local_bh_disable(); |
438 | read_lock(&head->lock); | 438 | read_lock(&head->lock); |
439 | sctp_for_each_hentry(epb, node, &head->chain) { | 439 | sctp_for_each_hentry(epb, node, &head->chain) { |
440 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) | 440 | if (!net_eq(sock_net(epb->sk), seq_file_net(seq))) |
441 | continue; | 441 | continue; |
442 | assoc = sctp_assoc(epb); | 442 | assoc = sctp_assoc(epb); |
443 | list_for_each_entry(tsp, &assoc->peer.transport_addr_list, | 443 | list_for_each_entry(tsp, &assoc->peer.transport_addr_list, |
444 | transports) { | 444 | transports) { |
445 | /* | 445 | /* |
446 | * The remote address (ADDR) | 446 | * The remote address (ADDR) |
447 | */ | 447 | */ |
448 | tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); | 448 | tsp->af_specific->seq_dump_addr(seq, &tsp->ipaddr); |
449 | seq_printf(seq, " "); | 449 | seq_printf(seq, " "); |
450 | 450 | ||
451 | /* | 451 | /* |
452 | * The association ID (ASSOC_ID) | 452 | * The association ID (ASSOC_ID) |
453 | */ | 453 | */ |
454 | seq_printf(seq, "%d ", tsp->asoc->assoc_id); | 454 | seq_printf(seq, "%d ", tsp->asoc->assoc_id); |
455 | 455 | ||
456 | /* | 456 | /* |
457 | * If the Heartbeat is active (HB_ACT) | 457 | * If the Heartbeat is active (HB_ACT) |
458 | * Note: 1 = Active, 0 = Inactive | 458 | * Note: 1 = Active, 0 = Inactive |
459 | */ | 459 | */ |
460 | seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); | 460 | seq_printf(seq, "%d ", timer_pending(&tsp->hb_timer)); |
461 | 461 | ||
462 | /* | 462 | /* |
463 | * Retransmit time out (RTO) | 463 | * Retransmit time out (RTO) |
464 | */ | 464 | */ |
465 | seq_printf(seq, "%lu ", tsp->rto); | 465 | seq_printf(seq, "%lu ", tsp->rto); |
466 | 466 | ||
467 | /* | 467 | /* |
468 | * Maximum path retransmit count (PATH_MAX_RTX) | 468 | * Maximum path retransmit count (PATH_MAX_RTX) |
469 | */ | 469 | */ |
470 | seq_printf(seq, "%d ", tsp->pathmaxrxt); | 470 | seq_printf(seq, "%d ", tsp->pathmaxrxt); |
471 | 471 | ||
472 | /* | 472 | /* |
473 | * remote address retransmit count (REM_ADDR_RTX) | 473 | * remote address retransmit count (REM_ADDR_RTX) |
474 | * Note: We don't have a way to tally this at the moment | 474 | * Note: We don't have a way to tally this at the moment |
475 | * so lets just leave it as zero for the moment | 475 | * so lets just leave it as zero for the moment |
476 | */ | 476 | */ |
477 | seq_printf(seq, "0 "); | 477 | seq_printf(seq, "0 "); |
478 | 478 | ||
479 | /* | 479 | /* |
480 | * remote address start time (START). This is also not | 480 | * remote address start time (START). This is also not |
481 | * currently implemented, but we can record it with a | 481 | * currently implemented, but we can record it with a |
482 | * jiffies marker in a subsequent patch | 482 | * jiffies marker in a subsequent patch |
483 | */ | 483 | */ |
484 | seq_printf(seq, "0"); | 484 | seq_printf(seq, "0"); |
485 | 485 | ||
486 | seq_printf(seq, "\n"); | 486 | seq_printf(seq, "\n"); |
487 | } | 487 | } |
488 | } | 488 | } |
489 | 489 | ||
490 | read_unlock(&head->lock); | 490 | read_unlock(&head->lock); |
491 | sctp_local_bh_enable(); | 491 | sctp_local_bh_enable(); |
492 | 492 | ||
493 | return 0; | 493 | return 0; |
494 | 494 | ||
495 | } | 495 | } |
496 | 496 | ||
497 | static const struct seq_operations sctp_remaddr_ops = { | 497 | static const struct seq_operations sctp_remaddr_ops = { |
498 | .start = sctp_remaddr_seq_start, | 498 | .start = sctp_remaddr_seq_start, |
499 | .next = sctp_remaddr_seq_next, | 499 | .next = sctp_remaddr_seq_next, |
500 | .stop = sctp_remaddr_seq_stop, | 500 | .stop = sctp_remaddr_seq_stop, |
501 | .show = sctp_remaddr_seq_show, | 501 | .show = sctp_remaddr_seq_show, |
502 | }; | 502 | }; |
503 | 503 | ||
504 | /* Cleanup the proc fs entry for 'remaddr' object. */ | 504 | /* Cleanup the proc fs entry for 'remaddr' object. */ |
505 | void sctp_remaddr_proc_exit(struct net *net) | 505 | void sctp_remaddr_proc_exit(struct net *net) |
506 | { | 506 | { |
507 | remove_proc_entry("remaddr", net->sctp.proc_net_sctp); | 507 | remove_proc_entry("remaddr", net->sctp.proc_net_sctp); |
508 | } | 508 | } |
509 | 509 | ||
510 | static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) | 510 | static int sctp_remaddr_seq_open(struct inode *inode, struct file *file) |
511 | { | 511 | { |
512 | return seq_open_net(inode, file, &sctp_remaddr_ops, | 512 | return seq_open_net(inode, file, &sctp_remaddr_ops, |
513 | sizeof(struct seq_net_private)); | 513 | sizeof(struct seq_net_private)); |
514 | } | 514 | } |
515 | 515 | ||
516 | static const struct file_operations sctp_remaddr_seq_fops = { | 516 | static const struct file_operations sctp_remaddr_seq_fops = { |
517 | .open = sctp_remaddr_seq_open, | 517 | .open = sctp_remaddr_seq_open, |
518 | .read = seq_read, | 518 | .read = seq_read, |
519 | .llseek = seq_lseek, | 519 | .llseek = seq_lseek, |
520 | .release = seq_release, | 520 | .release = seq_release_net, |
521 | }; | 521 | }; |
522 | 522 | ||
523 | int __net_init sctp_remaddr_proc_init(struct net *net) | 523 | int __net_init sctp_remaddr_proc_init(struct net *net) |
524 | { | 524 | { |
525 | struct proc_dir_entry *p; | 525 | struct proc_dir_entry *p; |
526 | 526 | ||
527 | p = proc_create("remaddr", S_IRUGO, net->sctp.proc_net_sctp, | 527 | p = proc_create("remaddr", S_IRUGO, net->sctp.proc_net_sctp, |
528 | &sctp_remaddr_seq_fops); | 528 | &sctp_remaddr_seq_fops); |
529 | if (!p) | 529 | if (!p) |
530 | return -ENOMEM; | 530 | return -ENOMEM; |
531 | return 0; | 531 | return 0; |
532 | } | 532 | } |
533 | 533 |