aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/sctp_diag.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/sctp_diag.c')
-rw-r--r--net/sctp/sctp_diag.c58
1 files changed, 40 insertions, 18 deletions
diff --git a/net/sctp/sctp_diag.c b/net/sctp/sctp_diag.c
index f3508aa75815..cef0cee182d4 100644
--- a/net/sctp/sctp_diag.c
+++ b/net/sctp/sctp_diag.c
@@ -272,28 +272,17 @@ out:
272 return err; 272 return err;
273} 273}
274 274
275static int sctp_tsp_dump(struct sctp_transport *tsp, void *p) 275static int sctp_sock_dump(struct sock *sk, void *p)
276{ 276{
277 struct sctp_endpoint *ep = tsp->asoc->ep; 277 struct sctp_endpoint *ep = sctp_sk(sk)->ep;
278 struct sctp_comm_param *commp = p; 278 struct sctp_comm_param *commp = p;
279 struct sock *sk = ep->base.sk;
280 struct sk_buff *skb = commp->skb; 279 struct sk_buff *skb = commp->skb;
281 struct netlink_callback *cb = commp->cb; 280 struct netlink_callback *cb = commp->cb;
282 const struct inet_diag_req_v2 *r = commp->r; 281 const struct inet_diag_req_v2 *r = commp->r;
283 struct sctp_association *assoc = 282 struct sctp_association *assoc;
284 list_entry(ep->asocs.next, struct sctp_association, asocs);
285 int err = 0; 283 int err = 0;
286 284
287 /* find the ep only once through the transports by this condition */
288 if (tsp->asoc != assoc)
289 goto out;
290
291 if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family)
292 goto out;
293
294 lock_sock(sk); 285 lock_sock(sk);
295 if (sk != assoc->base.sk)
296 goto release;
297 list_for_each_entry(assoc, &ep->asocs, asocs) { 286 list_for_each_entry(assoc, &ep->asocs, asocs) {
298 if (cb->args[4] < cb->args[1]) 287 if (cb->args[4] < cb->args[1])
299 goto next; 288 goto next;
@@ -312,7 +301,7 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p)
312 cb->nlh->nlmsg_seq, 301 cb->nlh->nlmsg_seq,
313 NLM_F_MULTI, cb->nlh) < 0) { 302 NLM_F_MULTI, cb->nlh) < 0) {
314 cb->args[3] = 1; 303 cb->args[3] = 1;
315 err = 2; 304 err = 1;
316 goto release; 305 goto release;
317 } 306 }
318 cb->args[3] = 1; 307 cb->args[3] = 1;
@@ -321,7 +310,7 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p)
321 sk_user_ns(NETLINK_CB(cb->skb).sk), 310 sk_user_ns(NETLINK_CB(cb->skb).sk),
322 NETLINK_CB(cb->skb).portid, 311 NETLINK_CB(cb->skb).portid,
323 cb->nlh->nlmsg_seq, 0, cb->nlh) < 0) { 312 cb->nlh->nlmsg_seq, 0, cb->nlh) < 0) {
324 err = 2; 313 err = 1;
325 goto release; 314 goto release;
326 } 315 }
327next: 316next:
@@ -333,10 +322,35 @@ next:
333 cb->args[4] = 0; 322 cb->args[4] = 0;
334release: 323release:
335 release_sock(sk); 324 release_sock(sk);
325 sock_put(sk);
336 return err; 326 return err;
327}
328
329static int sctp_get_sock(struct sctp_transport *tsp, void *p)
330{
331 struct sctp_endpoint *ep = tsp->asoc->ep;
332 struct sctp_comm_param *commp = p;
333 struct sock *sk = ep->base.sk;
334 struct netlink_callback *cb = commp->cb;
335 const struct inet_diag_req_v2 *r = commp->r;
336 struct sctp_association *assoc =
337 list_entry(ep->asocs.next, struct sctp_association, asocs);
338
339 /* find the ep only once through the transports by this condition */
340 if (tsp->asoc != assoc)
341 goto out;
342
343 if (r->sdiag_family != AF_UNSPEC && sk->sk_family != r->sdiag_family)
344 goto out;
345
346 sock_hold(sk);
347 cb->args[5] = (long)sk;
348
349 return 1;
350
337out: 351out:
338 cb->args[2]++; 352 cb->args[2]++;
339 return err; 353 return 0;
340} 354}
341 355
342static int sctp_ep_dump(struct sctp_endpoint *ep, void *p) 356static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
@@ -472,10 +486,18 @@ skip:
472 * 2 : to record the transport pos of this time's traversal 486 * 2 : to record the transport pos of this time's traversal
473 * 3 : to mark if we have dumped the ep info of the current asoc 487 * 3 : to mark if we have dumped the ep info of the current asoc
474 * 4 : to work as a temporary variable to traversal list 488 * 4 : to work as a temporary variable to traversal list
489 * 5 : to save the sk we get from travelsing the tsp list.
475 */ 490 */
476 if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE))) 491 if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
477 goto done; 492 goto done;
478 sctp_for_each_transport(sctp_tsp_dump, net, cb->args[2], &commp); 493
494next:
495 cb->args[5] = 0;
496 sctp_for_each_transport(sctp_get_sock, net, cb->args[2], &commp);
497
498 if (cb->args[5] && !sctp_sock_dump((struct sock *)cb->args[5], &commp))
499 goto next;
500
479done: 501done:
480 cb->args[1] = cb->args[4]; 502 cb->args[1] = cb->args[4];
481 cb->args[4] = 0; 503 cb->args[4] = 0;