return 0;
}
-struct ctnetlink_dump_filter {
+struct ctnetlink_filter {
struct {
u_int32_t val;
u_int32_t mask;
} mark;
};
+static struct ctnetlink_filter *
+ctnetlink_alloc_filter(const struct nlattr * const cda[])
+{
+#ifdef CONFIG_NF_CONNTRACK_MARK
+ struct ctnetlink_filter *filter;
+
+ filter = kzalloc(sizeof(*filter), GFP_KERNEL);
+ if (filter == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
+ filter->mark.mask = ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
+
+ return filter;
+#else
+ return ERR_PTR(-EOPNOTSUPP);
+#endif
+}
+
+static int ctnetlink_filter_match(struct nf_conn *ct, void *data)
+{
+ struct ctnetlink_filter *filter = data;
+
+ if (filter == NULL)
+ return 1;
+
+#ifdef CONFIG_NF_CONNTRACK_MARK
+ if ((ct->mark & filter->mark.mask) == filter->mark.val)
+ return 1;
+#endif
+
+ return 0;
+}
+
static int
ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
{
int res;
spinlock_t *lockp;
-#ifdef CONFIG_NF_CONNTRACK_MARK
- const struct ctnetlink_dump_filter *filter = cb->data;
-#endif
-
last = (struct nf_conn *)cb->args[1];
local_bh_disable();
continue;
cb->args[1] = 0;
}
-#ifdef CONFIG_NF_CONNTRACK_MARK
- if (filter && !((ct->mark & filter->mark.mask) ==
- filter->mark.val)) {
+ if (!ctnetlink_filter_match(ct, cb->data))
continue;
- }
-#endif
+
rcu_read_lock();
res =
ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).portid,
.len = NF_CT_LABELS_MAX_SIZE },
};
+static int ctnetlink_flush_conntrack(struct net *net,
+ const struct nlattr * const cda[],
+ u32 portid, int report)
+{
+ struct ctnetlink_filter *filter = NULL;
+
+ if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
+ filter = ctnetlink_alloc_filter(cda);
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
+ }
+
+ nf_ct_iterate_cleanup(net, ctnetlink_filter_match, filter,
+ portid, report);
+ kfree(filter);
+
+ return 0;
+}
+
static int
ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
else if (cda[CTA_TUPLE_REPLY])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3);
else {
- /* Flush the whole table */
- nf_conntrack_flush_report(net,
- NETLINK_CB(skb).portid,
- nlmsg_report(nlh));
- return 0;
+ return ctnetlink_flush_conntrack(net, cda,
+ NETLINK_CB(skb).portid,
+ nlmsg_report(nlh));
}
if (err < 0)
.dump = ctnetlink_dump_table,
.done = ctnetlink_done,
};
-#ifdef CONFIG_NF_CONNTRACK_MARK
+
if (cda[CTA_MARK] && cda[CTA_MARK_MASK]) {
- struct ctnetlink_dump_filter *filter;
+ struct ctnetlink_filter *filter;
- filter = kzalloc(sizeof(struct ctnetlink_dump_filter),
- GFP_ATOMIC);
- if (filter == NULL)
- return -ENOMEM;
+ filter = ctnetlink_alloc_filter(cda);
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
- filter->mark.val = ntohl(nla_get_be32(cda[CTA_MARK]));
- filter->mark.mask =
- ntohl(nla_get_be32(cda[CTA_MARK_MASK]));
c.data = filter;
}
-#endif
return netlink_dump_start(ctnl, skb, nlh, &c);
}