hlist: drop the node parameter from iterators
[deliverable/linux.git] / net / netfilter / nf_conntrack_netlink.c
index 627b0e50b2389120e86ed107a3af01d690e07a29..9904b15f600e96f6d0285cff241339a364dc6200 100644 (file)
@@ -43,6 +43,7 @@
 #include <net/netfilter/nf_conntrack_acct.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/nf_conntrack_timestamp.h>
+#include <net/netfilter/nf_conntrack_labels.h>
 #ifdef CONFIG_NF_NAT_NEEDED
 #include <net/netfilter/nf_nat_core.h>
 #include <net/netfilter/nf_nat_l4proto.h>
@@ -323,6 +324,40 @@ nla_put_failure:
 #define ctnetlink_dump_secctx(a, b) (0)
 #endif
 
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+static int ctnetlink_label_size(const struct nf_conn *ct)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+
+       if (!labels)
+               return 0;
+       return nla_total_size(labels->words * sizeof(long));
+}
+
+static int
+ctnetlink_dump_labels(struct sk_buff *skb, const struct nf_conn *ct)
+{
+       struct nf_conn_labels *labels = nf_ct_labels_find(ct);
+       unsigned int len, i;
+
+       if (!labels)
+               return 0;
+
+       len = labels->words * sizeof(long);
+       i = 0;
+       do {
+               if (labels->bits[i] != 0)
+                       return nla_put(skb, CTA_LABELS, len, labels->bits);
+               i++;
+       } while (i < labels->words);
+
+       return 0;
+}
+#else
+#define ctnetlink_dump_labels(a, b) (0)
+#define ctnetlink_label_size(a)        (0)
+#endif
+
 #define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple)
 
 static inline int
@@ -463,6 +498,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
            ctnetlink_dump_helpinfo(skb, ct) < 0 ||
            ctnetlink_dump_mark(skb, ct) < 0 ||
            ctnetlink_dump_secctx(skb, ct) < 0 ||
+           ctnetlink_dump_labels(skb, ct) < 0 ||
            ctnetlink_dump_id(skb, ct) < 0 ||
            ctnetlink_dump_use(skb, ct) < 0 ||
            ctnetlink_dump_master(skb, ct) < 0 ||
@@ -561,6 +597,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct)
               + nla_total_size(sizeof(u_int32_t)) /* CTA_MARK */
 #endif
               + ctnetlink_proto_size(ct)
+              + ctnetlink_label_size(ct)
               ;
 }
 
@@ -662,6 +699,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
                    && ctnetlink_dump_secctx(skb, ct) < 0)
                        goto nla_put_failure;
 #endif
+               if (events & (1 << IPCT_LABEL) &&
+                    ctnetlink_dump_labels(skb, ct) < 0)
+                       goto nla_put_failure;
 
                if (events & (1 << IPCT_RELATED) &&
                    ctnetlink_dump_master(skb, ct) < 0)
@@ -921,6 +961,7 @@ ctnetlink_parse_help(const struct nlattr *attr, char **helper_name,
        return 0;
 }
 
+#define __CTA_LABELS_MAX_LENGTH ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE)
 static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_TUPLE_ORIG]        = { .type = NLA_NESTED },
        [CTA_TUPLE_REPLY]       = { .type = NLA_NESTED },
@@ -937,6 +978,10 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
        [CTA_NAT_SEQ_ADJ_REPLY] = { .type = NLA_NESTED },
        [CTA_ZONE]              = { .type = NLA_U16 },
        [CTA_MARK_MASK]         = { .type = NLA_U32 },
+       [CTA_LABELS]            = { .type = NLA_BINARY,
+                                   .len = __CTA_LABELS_MAX_LENGTH },
+       [CTA_LABELS_MASK]       = { .type = NLA_BINARY,
+                                   .len = __CTA_LABELS_MAX_LENGTH },
 };
 
 static int
@@ -1211,13 +1256,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
        if (!parse_nat_setup) {
 #ifdef CONFIG_MODULES
                rcu_read_unlock();
-               nfnl_unlock();
+               nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
                if (request_module("nf-nat") < 0) {
-                       nfnl_lock();
+                       nfnl_lock(NFNL_SUBSYS_CTNETLINK);
                        rcu_read_lock();
                        return -EOPNOTSUPP;
                }
-               nfnl_lock();
+               nfnl_lock(NFNL_SUBSYS_CTNETLINK);
                rcu_read_lock();
                if (nfnetlink_parse_nat_setup_hook)
                        return -EAGAIN;
@@ -1229,13 +1274,13 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct,
        if (err == -EAGAIN) {
 #ifdef CONFIG_MODULES
                rcu_read_unlock();
-               nfnl_unlock();
+               nfnl_unlock(NFNL_SUBSYS_CTNETLINK);
                if (request_module("nf-nat-%u", nf_ct_l3num(ct)) < 0) {
-                       nfnl_lock();
+                       nfnl_lock(NFNL_SUBSYS_CTNETLINK);
                        rcu_read_lock();
                        return -EOPNOTSUPP;
                }
-               nfnl_lock();
+               nfnl_lock(NFNL_SUBSYS_CTNETLINK);
                rcu_read_lock();
 #else
                err = -EOPNOTSUPP;
@@ -1464,6 +1509,31 @@ ctnetlink_change_nat_seq_adj(struct nf_conn *ct,
 }
 #endif
 
+static int
+ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
+{
+#ifdef CONFIG_NF_CONNTRACK_LABELS
+       size_t len = nla_len(cda[CTA_LABELS]);
+       const void *mask = cda[CTA_LABELS_MASK];
+
+       if (len & (sizeof(u32)-1)) /* must be multiple of u32 */
+               return -EINVAL;
+
+       if (mask) {
+               if (nla_len(cda[CTA_LABELS_MASK]) == 0 ||
+                   nla_len(cda[CTA_LABELS_MASK]) != len)
+                       return -EINVAL;
+               mask = nla_data(cda[CTA_LABELS_MASK]);
+       }
+
+       len /= sizeof(u32);
+
+       return nf_connlabels_replace(ct, nla_data(cda[CTA_LABELS]), mask, len);
+#else
+       return -EOPNOTSUPP;
+#endif
+}
+
 static int
 ctnetlink_change_conntrack(struct nf_conn *ct,
                           const struct nlattr * const cda[])
@@ -1510,6 +1580,11 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
                        return err;
        }
 #endif
+       if (cda[CTA_LABELS]) {
+               err = ctnetlink_attach_labels(ct, cda);
+               if (err < 0)
+                       return err;
+       }
 
        return 0;
 }
@@ -1598,6 +1673,8 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
        nf_ct_acct_ext_add(ct, GFP_ATOMIC);
        nf_ct_tstamp_ext_add(ct, GFP_ATOMIC);
        nf_ct_ecache_ext_add(ct, 0, 0, GFP_ATOMIC);
+       nf_ct_labels_ext_add(ct);
+
        /* we must add conntrack extensions before confirmation. */
        ct->status |= IPS_CONFIRMED;
 
@@ -1705,6 +1782,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                if (nlh->nlmsg_flags & NLM_F_CREATE) {
                        enum ip_conntrack_events events;
 
+                       if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY])
+                               return -EINVAL;
+
                        ct = ctnetlink_create_conntrack(net, zone, cda, &otuple,
                                                        &rtuple, u3);
                        if (IS_ERR(ct))
@@ -1716,6 +1796,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
                        else
                                events = IPCT_NEW;
 
+                       if (cda[CTA_LABELS] &&
+                           ctnetlink_attach_labels(ct, cda) == 0)
+                               events |= (1 << IPCT_LABEL);
+
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
                                                      (1 << IPCT_ASSURED) |
                                                      (1 << IPCT_HELPER) |
@@ -1983,6 +2067,8 @@ ctnetlink_nfqueue_build(struct sk_buff *skb, struct nf_conn *ct)
        if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
                goto nla_put_failure;
 #endif
+       if (ctnetlink_dump_labels(skb, ct) < 0)
+               goto nla_put_failure;
        rcu_read_unlock();
        return 0;
 
@@ -2011,6 +2097,11 @@ ctnetlink_nfqueue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct)
                if (err < 0)
                        return err;
        }
+       if (cda[CTA_LABELS]) {
+               err = ctnetlink_attach_labels(ct, cda);
+               if (err < 0)
+                       return err;
+       }
 #if defined(CONFIG_NF_CONNTRACK_MARK)
        if (cda[CTA_MARK])
                ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
@@ -2279,14 +2370,13 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
        struct net *net = sock_net(skb->sk);
        struct nf_conntrack_expect *exp, *last;
        struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
-       struct hlist_node *n;
        u_int8_t l3proto = nfmsg->nfgen_family;
 
        rcu_read_lock();
        last = (struct nf_conntrack_expect *)cb->args[1];
        for (; cb->args[0] < nf_ct_expect_hsize; cb->args[0]++) {
 restart:
-               hlist_for_each_entry(exp, n, &net->ct.expect_hash[cb->args[0]],
+               hlist_for_each_entry(exp, &net->ct.expect_hash[cb->args[0]],
                                     hnode) {
                        if (l3proto && exp->tuple.src.l3num != l3proto)
                                continue;
@@ -2419,7 +2509,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple tuple;
        struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       struct hlist_node *n, *next;
+       struct hlist_node *next;
        u_int8_t u3 = nfmsg->nfgen_family;
        unsigned int i;
        u16 zone;
@@ -2466,7 +2556,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                /* delete all expectations for this helper */
                spin_lock_bh(&nf_conntrack_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
-                       hlist_for_each_entry_safe(exp, n, next,
+                       hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
                                                  hnode) {
                                m_help = nfct_help(exp->master);
@@ -2484,7 +2574,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
                /* This basically means we have to flush everything*/
                spin_lock_bh(&nf_conntrack_lock);
                for (i = 0; i < nf_ct_expect_hsize; i++) {
-                       hlist_for_each_entry_safe(exp, n, next,
+                       hlist_for_each_entry_safe(exp, next,
                                                  &net->ct.expect_hash[i],
                                                  hnode) {
                                if (del_timer(&exp->timeout)) {
This page took 0.029598 seconds and 5 git commands to generate.