diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_netlink.c | 32 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 32 |
2 files changed, 48 insertions, 16 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index af152e3623dc..33891bb1fde4 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -399,38 +399,54 @@ nfattr_failure: | |||
399 | static int ctnetlink_done(struct netlink_callback *cb) | 399 | static int ctnetlink_done(struct netlink_callback *cb) |
400 | { | 400 | { |
401 | DEBUGP("entered %s\n", __FUNCTION__); | 401 | DEBUGP("entered %s\n", __FUNCTION__); |
402 | if (cb->args[1]) | ||
403 | ip_conntrack_put((struct ip_conntrack *)cb->args[1]); | ||
402 | return 0; | 404 | return 0; |
403 | } | 405 | } |
404 | 406 | ||
405 | static int | 407 | static int |
406 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 408 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
407 | { | 409 | { |
408 | struct ip_conntrack *ct = NULL; | 410 | struct ip_conntrack *ct, *last; |
409 | struct ip_conntrack_tuple_hash *h; | 411 | struct ip_conntrack_tuple_hash *h; |
410 | struct list_head *i; | 412 | struct list_head *i; |
411 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
412 | 413 | ||
413 | DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, | 414 | DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, |
414 | cb->args[0], *id); | 415 | cb->args[0], *id); |
415 | 416 | ||
416 | read_lock_bh(&ip_conntrack_lock); | 417 | read_lock_bh(&ip_conntrack_lock); |
417 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++, *id = 0) { | 418 | for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) { |
419 | restart: | ||
420 | last = (struct ip_conntrack *)cb->args[1]; | ||
418 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { | 421 | list_for_each_prev(i, &ip_conntrack_hash[cb->args[0]]) { |
419 | h = (struct ip_conntrack_tuple_hash *) i; | 422 | h = (struct ip_conntrack_tuple_hash *) i; |
420 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 423 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
421 | continue; | 424 | continue; |
422 | ct = tuplehash_to_ctrack(h); | 425 | ct = tuplehash_to_ctrack(h); |
423 | if (ct->id <= *id) | 426 | if (last != NULL) { |
424 | continue; | 427 | if (ct == last) { |
428 | ip_conntrack_put(last); | ||
429 | cb->args[1] = 0; | ||
430 | last = NULL; | ||
431 | } else | ||
432 | continue; | ||
433 | } | ||
425 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 434 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
426 | cb->nlh->nlmsg_seq, | 435 | cb->nlh->nlmsg_seq, |
427 | IPCTNL_MSG_CT_NEW, | 436 | IPCTNL_MSG_CT_NEW, |
428 | 1, ct) < 0) | 437 | 1, ct) < 0) { |
438 | nf_conntrack_get(&ct->ct_general); | ||
439 | cb->args[1] = (unsigned long)ct; | ||
429 | goto out; | 440 | goto out; |
430 | *id = ct->id; | 441 | } |
442 | } | ||
443 | if (last != NULL) { | ||
444 | ip_conntrack_put(last); | ||
445 | cb->args[1] = 0; | ||
446 | goto restart; | ||
431 | } | 447 | } |
432 | } | 448 | } |
433 | out: | 449 | out: |
434 | read_unlock_bh(&ip_conntrack_lock); | 450 | read_unlock_bh(&ip_conntrack_lock); |
435 | 451 | ||
436 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | 452 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 8f27fe9446f2..b8c7c567c9df 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -407,6 +407,8 @@ nfattr_failure: | |||
407 | 407 | ||
408 | static int ctnetlink_done(struct netlink_callback *cb) | 408 | static int ctnetlink_done(struct netlink_callback *cb) |
409 | { | 409 | { |
410 | if (cb->args[1]) | ||
411 | nf_ct_put((struct nf_conn *)cb->args[1]); | ||
410 | DEBUGP("entered %s\n", __FUNCTION__); | 412 | DEBUGP("entered %s\n", __FUNCTION__); |
411 | return 0; | 413 | return 0; |
412 | } | 414 | } |
@@ -416,10 +418,9 @@ static int ctnetlink_done(struct netlink_callback *cb) | |||
416 | static int | 418 | static int |
417 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 419 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
418 | { | 420 | { |
419 | struct nf_conn *ct = NULL; | 421 | struct nf_conn *ct, *last; |
420 | struct nf_conntrack_tuple_hash *h; | 422 | struct nf_conntrack_tuple_hash *h; |
421 | struct list_head *i; | 423 | struct list_head *i; |
422 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
423 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 424 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
424 | u_int8_t l3proto = nfmsg->nfgen_family; | 425 | u_int8_t l3proto = nfmsg->nfgen_family; |
425 | 426 | ||
@@ -427,7 +428,9 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
427 | cb->args[0], *id); | 428 | cb->args[0], *id); |
428 | 429 | ||
429 | read_lock_bh(&nf_conntrack_lock); | 430 | read_lock_bh(&nf_conntrack_lock); |
430 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) { | 431 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) { |
432 | restart: | ||
433 | last = (struct nf_conn *)cb->args[1]; | ||
431 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { | 434 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { |
432 | h = (struct nf_conntrack_tuple_hash *) i; | 435 | h = (struct nf_conntrack_tuple_hash *) i; |
433 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | 436 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) |
@@ -438,17 +441,30 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | |||
438 | * then dump everything. */ | 441 | * then dump everything. */ |
439 | if (l3proto && L3PROTO(ct) != l3proto) | 442 | if (l3proto && L3PROTO(ct) != l3proto) |
440 | continue; | 443 | continue; |
441 | if (ct->id <= *id) | 444 | if (last != NULL) { |
442 | continue; | 445 | if (ct == last) { |
446 | nf_ct_put(last); | ||
447 | cb->args[1] = 0; | ||
448 | last = NULL; | ||
449 | } else | ||
450 | continue; | ||
451 | } | ||
443 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | 452 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, |
444 | cb->nlh->nlmsg_seq, | 453 | cb->nlh->nlmsg_seq, |
445 | IPCTNL_MSG_CT_NEW, | 454 | IPCTNL_MSG_CT_NEW, |
446 | 1, ct) < 0) | 455 | 1, ct) < 0) { |
456 | nf_conntrack_get(&ct->ct_general); | ||
457 | cb->args[1] = (unsigned long)ct; | ||
447 | goto out; | 458 | goto out; |
448 | *id = ct->id; | 459 | } |
460 | } | ||
461 | if (last != NULL) { | ||
462 | nf_ct_put(last); | ||
463 | cb->args[1] = 0; | ||
464 | goto restart; | ||
449 | } | 465 | } |
450 | } | 466 | } |
451 | out: | 467 | out: |
452 | read_unlock_bh(&nf_conntrack_lock); | 468 | read_unlock_bh(&nf_conntrack_lock); |
453 | 469 | ||
454 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | 470 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); |