diff options
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 32 |
1 files changed, 25 insertions, 7 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 206491488f4e..65a7ebcf86f6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -1235,32 +1235,50 @@ nfattr_failure: | |||
1235 | return NOTIFY_DONE; | 1235 | return NOTIFY_DONE; |
1236 | } | 1236 | } |
1237 | #endif | 1237 | #endif |
1238 | static int ctnetlink_exp_done(struct netlink_callback *cb) | ||
1239 | { | ||
1240 | if (cb->args[0]) | ||
1241 | nf_ct_expect_put((struct nf_conntrack_expect *)cb->args[0]); | ||
1242 | return 0; | ||
1243 | } | ||
1238 | 1244 | ||
1239 | static int | 1245 | static int |
1240 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | 1246 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) |
1241 | { | 1247 | { |
1242 | struct nf_conntrack_expect *exp = NULL; | 1248 | struct nf_conntrack_expect *exp, *last; |
1243 | struct list_head *i; | 1249 | struct list_head *i; |
1244 | u_int32_t *id = (u_int32_t *) &cb->args[0]; | ||
1245 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | 1250 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); |
1246 | u_int8_t l3proto = nfmsg->nfgen_family; | 1251 | u_int8_t l3proto = nfmsg->nfgen_family; |
1247 | 1252 | ||
1248 | read_lock_bh(&nf_conntrack_lock); | 1253 | read_lock_bh(&nf_conntrack_lock); |
1254 | last = (struct nf_conntrack_expect *)cb->args[0]; | ||
1255 | restart: | ||
1249 | list_for_each_prev(i, &nf_ct_expect_list) { | 1256 | list_for_each_prev(i, &nf_ct_expect_list) { |
1250 | exp = (struct nf_conntrack_expect *) i; | 1257 | exp = (struct nf_conntrack_expect *) i; |
1251 | if (l3proto && exp->tuple.src.l3num != l3proto) | 1258 | if (l3proto && exp->tuple.src.l3num != l3proto) |
1252 | continue; | 1259 | continue; |
1253 | if (exp->id <= *id) | 1260 | if (cb->args[0]) { |
1254 | continue; | 1261 | if (exp != last) |
1262 | continue; | ||
1263 | cb->args[0] = 0; | ||
1264 | } | ||
1255 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, | 1265 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, |
1256 | cb->nlh->nlmsg_seq, | 1266 | cb->nlh->nlmsg_seq, |
1257 | IPCTNL_MSG_EXP_NEW, | 1267 | IPCTNL_MSG_EXP_NEW, |
1258 | 1, exp) < 0) | 1268 | 1, exp) < 0) { |
1269 | atomic_inc(&exp->use); | ||
1270 | cb->args[0] = (unsigned long)exp; | ||
1259 | goto out; | 1271 | goto out; |
1260 | *id = exp->id; | 1272 | } |
1273 | } | ||
1274 | if (cb->args[0]) { | ||
1275 | cb->args[0] = 0; | ||
1276 | goto restart; | ||
1261 | } | 1277 | } |
1262 | out: | 1278 | out: |
1263 | read_unlock_bh(&nf_conntrack_lock); | 1279 | read_unlock_bh(&nf_conntrack_lock); |
1280 | if (last) | ||
1281 | nf_ct_expect_put(last); | ||
1264 | 1282 | ||
1265 | return skb->len; | 1283 | return skb->len; |
1266 | } | 1284 | } |
@@ -1287,7 +1305,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | |||
1287 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | 1305 | if (nlh->nlmsg_flags & NLM_F_DUMP) { |
1288 | return netlink_dump_start(ctnl, skb, nlh, | 1306 | return netlink_dump_start(ctnl, skb, nlh, |
1289 | ctnetlink_exp_dump_table, | 1307 | ctnetlink_exp_dump_table, |
1290 | ctnetlink_done); | 1308 | ctnetlink_exp_done); |
1291 | } | 1309 | } |
1292 | 1310 | ||
1293 | if (cda[CTA_EXPECT_MASTER-1]) | 1311 | if (cda[CTA_EXPECT_MASTER-1]) |