Merge tag 'iomap-5.14-fixes-1' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux
[linux-2.6-microblaze.git] / net / netfilter / nf_conntrack_netlink.c
index 1d519b0..e81af33 100644 (file)
@@ -218,6 +218,7 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb,
        if (!help)
                return 0;
 
+       rcu_read_lock();
        helper = rcu_dereference(help->helper);
        if (!helper)
                goto out;
@@ -233,9 +234,11 @@ static int ctnetlink_dump_helpinfo(struct sk_buff *skb,
 
        nla_nest_end(skb, nest_helper);
 out:
+       rcu_read_unlock();
        return 0;
 
 nla_put_failure:
+       rcu_read_unlock();
        return -1;
 }
 
@@ -555,22 +558,17 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
 {
        const struct nf_conntrack_zone *zone;
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        struct nlattr *nest_parms;
        unsigned int event;
 
        if (portid)
                flags |= NLM_F_MULTI;
        event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_NEW);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, nf_ct_l3num(ct),
+                          NFNETLINK_V0, 0);
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = nf_ct_l3num(ct);
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = 0;
-
        zone = nf_ct_zone(ct);
 
        nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG);
@@ -713,7 +711,6 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
        const struct nf_conntrack_zone *zone;
        struct net *net;
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        struct nlattr *nest_parms;
        struct nf_conn *ct = item->ct;
        struct sk_buff *skb;
@@ -743,15 +740,11 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
                goto errout;
 
        type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, type);
-       nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, item->portid, 0, type, flags, nf_ct_l3num(ct),
+                          NFNETLINK_V0, 0);
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = nf_ct_l3num(ct);
-       nfmsg->version  = NFNETLINK_V0;
-       nfmsg->res_id   = 0;
-
        zone = nf_ct_zone(ct);
 
        nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG);
@@ -1534,17 +1527,15 @@ static int ctnetlink_flush_conntrack(struct net *net,
        return 0;
 }
 
-static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
-                                  struct sk_buff *skb,
-                                  const struct nlmsghdr *nlh,
-                                  const struct nlattr * const cda[],
-                                  struct netlink_ext_ack *extack)
+static int ctnetlink_del_conntrack(struct sk_buff *skb,
+                                  const struct nfnl_info *info,
+                                  const struct nlattr * const cda[])
 {
+       u8 family = info->nfmsg->nfgen_family;
        struct nf_conntrack_tuple_hash *h;
        struct nf_conntrack_tuple tuple;
-       struct nf_conn *ct;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        struct nf_conntrack_zone zone;
+       struct nf_conn *ct;
        int err;
 
        err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -1553,22 +1544,22 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
 
        if (cda[CTA_TUPLE_ORIG])
                err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG,
-                                           nfmsg->nfgen_family, &zone);
+                                           family, &zone);
        else if (cda[CTA_TUPLE_REPLY])
                err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY,
-                                           nfmsg->nfgen_family, &zone);
+                                           family, &zone);
        else {
-               u_int8_t u3 = nfmsg->version ? nfmsg->nfgen_family : AF_UNSPEC;
+               u_int8_t u3 = info->nfmsg->version ? family : AF_UNSPEC;
 
-               return ctnetlink_flush_conntrack(net, cda,
+               return ctnetlink_flush_conntrack(info->net, cda,
                                                 NETLINK_CB(skb).portid,
-                                                nlmsg_report(nlh), u3);
+                                                nlmsg_report(info->nlh), u3);
        }
 
        if (err < 0)
                return err;
 
-       h = nf_conntrack_find_get(net, &zone, &tuple);
+       h = nf_conntrack_find_get(info->net, &zone, &tuple);
        if (!h)
                return -ENOENT;
 
@@ -1588,28 +1579,25 @@ static int ctnetlink_del_conntrack(struct net *net, struct sock *ctnl,
                }
        }
 
-       nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(nlh));
+       nf_ct_delete(ct, NETLINK_CB(skb).portid, nlmsg_report(info->nlh));
        nf_ct_put(ct);
 
        return 0;
 }
 
-static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
-                                  struct sk_buff *skb,
-                                  const struct nlmsghdr *nlh,
-                                  const struct nlattr * const cda[],
-                                  struct netlink_ext_ack *extack)
+static int ctnetlink_get_conntrack(struct sk_buff *skb,
+                                  const struct nfnl_info *info,
+                                  const struct nlattr * const cda[])
 {
+       u_int8_t u3 = info->nfmsg->nfgen_family;
        struct nf_conntrack_tuple_hash *h;
        struct nf_conntrack_tuple tuple;
-       struct nf_conn *ct;
-       struct sk_buff *skb2 = NULL;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       u_int8_t u3 = nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
+       struct sk_buff *skb2;
+       struct nf_conn *ct;
        int err;
 
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .start = ctnetlink_start,
                        .dump = ctnetlink_dump_table,
@@ -1617,7 +1605,7 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
                        .data = (void *)cda,
                };
 
-               return netlink_dump_start(ctnl, skb, nlh, &c);
+               return netlink_dump_start(info->sk, skb, info->nlh, &c);
        }
 
        err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -1636,36 +1624,29 @@ static int ctnetlink_get_conntrack(struct net *net, struct sock *ctnl,
        if (err < 0)
                return err;
 
-       h = nf_conntrack_find_get(net, &zone, &tuple);
+       h = nf_conntrack_find_get(info->net, &zone, &tuple);
        if (!h)
                return -ENOENT;
 
        ct = nf_ct_tuplehash_to_ctrack(h);
 
-       err = -ENOMEM;
        skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (skb2 == NULL) {
+       if (!skb2) {
                nf_ct_put(ct);
                return -ENOMEM;
        }
 
-       err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid, nlh->nlmsg_seq,
-                                 NFNL_MSG_TYPE(nlh->nlmsg_type), ct, true, 0);
+       err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).portid,
+                                 info->nlh->nlmsg_seq,
+                                 NFNL_MSG_TYPE(info->nlh->nlmsg_type), ct,
+                                 true, 0);
        nf_ct_put(ct);
-       if (err <= 0)
-               goto free;
-
-       err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
-       if (err < 0)
-               goto out;
-
-       return 0;
+       if (err <= 0) {
+               kfree_skb(skb2);
+               return -ENOMEM;
+       }
 
-free:
-       kfree_skb(skb2);
-out:
-       /* this avoids a loop in nfnetlink. */
-       return err == -EAGAIN ? -ENOBUFS : err;
+       return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
 }
 
 static int ctnetlink_done_list(struct netlink_callback *cb)
@@ -1753,18 +1734,16 @@ ctnetlink_dump_dying(struct sk_buff *skb, struct netlink_callback *cb)
        return ctnetlink_dump_list(skb, cb, true);
 }
 
-static int ctnetlink_get_ct_dying(struct net *net, struct sock *ctnl,
-                                 struct sk_buff *skb,
-                                 const struct nlmsghdr *nlh,
-                                 const struct nlattr * const cda[],
-                                 struct netlink_ext_ack *extack)
+static int ctnetlink_get_ct_dying(struct sk_buff *skb,
+                                 const struct nfnl_info *info,
+                                 const struct nlattr * const cda[])
 {
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ctnetlink_dump_dying,
                        .done = ctnetlink_done_list,
                };
-               return netlink_dump_start(ctnl, skb, nlh, &c);
+               return netlink_dump_start(info->sk, skb, info->nlh, &c);
        }
 
        return -EOPNOTSUPP;
@@ -1776,18 +1755,16 @@ ctnetlink_dump_unconfirmed(struct sk_buff *skb, struct netlink_callback *cb)
        return ctnetlink_dump_list(skb, cb, false);
 }
 
-static int ctnetlink_get_ct_unconfirmed(struct net *net, struct sock *ctnl,
-                                       struct sk_buff *skb,
-                                       const struct nlmsghdr *nlh,
-                                       const struct nlattr * const cda[],
-                                       struct netlink_ext_ack *extack)
+static int ctnetlink_get_ct_unconfirmed(struct sk_buff *skb,
+                                       const struct nfnl_info *info,
+                                       const struct nlattr * const cda[])
 {
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ctnetlink_dump_unconfirmed,
                        .done = ctnetlink_done_list,
                };
-               return netlink_dump_start(ctnl, skb, nlh, &c);
+               return netlink_dump_start(info->sk, skb, info->nlh, &c);
        }
 
        return -EOPNOTSUPP;
@@ -2384,18 +2361,15 @@ err1:
        return ERR_PTR(err);
 }
 
-static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
-                                  struct sk_buff *skb,
-                                  const struct nlmsghdr *nlh,
-                                  const struct nlattr * const cda[],
-                                  struct netlink_ext_ack *extack)
+static int ctnetlink_new_conntrack(struct sk_buff *skb,
+                                  const struct nfnl_info *info,
+                                  const struct nlattr * const cda[])
 {
        struct nf_conntrack_tuple otuple, rtuple;
        struct nf_conntrack_tuple_hash *h = NULL;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       struct nf_conn *ct;
-       u_int8_t u3 = nfmsg->nfgen_family;
+       u_int8_t u3 = info->nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
+       struct nf_conn *ct;
        int err;
 
        err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
@@ -2417,13 +2391,13 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
        }
 
        if (cda[CTA_TUPLE_ORIG])
-               h = nf_conntrack_find_get(net, &zone, &otuple);
+               h = nf_conntrack_find_get(info->net, &zone, &otuple);
        else if (cda[CTA_TUPLE_REPLY])
-               h = nf_conntrack_find_get(net, &zone, &rtuple);
+               h = nf_conntrack_find_get(info->net, &zone, &rtuple);
 
        if (h == NULL) {
                err = -ENOENT;
-               if (nlh->nlmsg_flags & NLM_F_CREATE) {
+               if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
                        enum ip_conntrack_events events;
 
                        if (!cda[CTA_TUPLE_ORIG] || !cda[CTA_TUPLE_REPLY])
@@ -2431,8 +2405,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
                        if (otuple.dst.protonum != rtuple.dst.protonum)
                                return -EINVAL;
 
-                       ct = ctnetlink_create_conntrack(net, &zone, cda, &otuple,
-                                                       &rtuple, u3);
+                       ct = ctnetlink_create_conntrack(info->net, &zone, cda,
+                                                       &otuple, &rtuple, u3);
                        if (IS_ERR(ct))
                                return PTR_ERR(ct);
 
@@ -2455,7 +2429,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
                                                      (1 << IPCT_SYNPROXY) |
                                                      events,
                                                      ct, NETLINK_CB(skb).portid,
-                                                     nlmsg_report(nlh));
+                                                     nlmsg_report(info->nlh));
                        nf_ct_put(ct);
                }
 
@@ -2465,7 +2439,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
 
        err = -EEXIST;
        ct = nf_ct_tuplehash_to_ctrack(h);
-       if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
+       if (!(info->nlh->nlmsg_flags & NLM_F_EXCL)) {
                err = ctnetlink_change_conntrack(ct, cda);
                if (err == 0) {
                        nf_conntrack_eventmask_report((1 << IPCT_REPLY) |
@@ -2477,7 +2451,7 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
                                                      (1 << IPCT_MARK) |
                                                      (1 << IPCT_SYNPROXY),
                                                      ct, NETLINK_CB(skb).portid,
-                                                     nlmsg_report(nlh));
+                                                     nlmsg_report(info->nlh));
                }
        }
 
@@ -2490,20 +2464,15 @@ ctnetlink_ct_stat_cpu_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
                                __u16 cpu, const struct ip_conntrack_stat *st)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
 
        event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK,
                              IPCTNL_MSG_CT_GET_STATS_CPU);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
+                          NFNETLINK_V0, htons(cpu));
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = AF_UNSPEC;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = htons(cpu);
-
        if (nla_put_be32(skb, CTA_STATS_FOUND, htonl(st->found)) ||
            nla_put_be32(skb, CTA_STATS_INVALID, htonl(st->invalid)) ||
            nla_put_be32(skb, CTA_STATS_INSERT, htonl(st->insert)) ||
@@ -2554,17 +2523,15 @@ ctnetlink_ct_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
-static int ctnetlink_stat_ct_cpu(struct net *net, struct sock *ctnl,
-                                struct sk_buff *skb,
-                                const struct nlmsghdr *nlh,
-                                const struct nlattr * const cda[],
-                                struct netlink_ext_ack *extack)
+static int ctnetlink_stat_ct_cpu(struct sk_buff *skb,
+                                const struct nfnl_info *info,
+                                const struct nlattr * const cda[])
 {
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ctnetlink_ct_stat_cpu_dump,
                };
-               return netlink_dump_start(ctnl, skb, nlh, &c);
+               return netlink_dump_start(info->sk, skb, info->nlh, &c);
        }
 
        return 0;
@@ -2574,21 +2541,17 @@ static int
 ctnetlink_stat_ct_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
                            struct net *net)
 {
-       struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
-       unsigned int nr_conntracks = atomic_read(&net->ct.count);
+       unsigned int nr_conntracks;
+       struct nlmsghdr *nlh;
 
        event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
+                          NFNETLINK_V0, 0);
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = AF_UNSPEC;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = 0;
-
+       nr_conntracks = nf_conntrack_count(net);
        if (nla_put_be32(skb, CTA_STATS_GLOBAL_ENTRIES, htonl(nr_conntracks)))
                goto nla_put_failure;
 
@@ -2604,10 +2567,8 @@ nlmsg_failure:
        return -1;
 }
 
-static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
-                            struct sk_buff *skb, const struct nlmsghdr *nlh,
-                            const struct nlattr * const cda[],
-                            struct netlink_ext_ack *extack)
+static int ctnetlink_stat_ct(struct sk_buff *skb, const struct nfnl_info *info,
+                            const struct nlattr * const cda[])
 {
        struct sk_buff *skb2;
        int err;
@@ -2617,23 +2578,15 @@ static int ctnetlink_stat_ct(struct net *net, struct sock *ctnl,
                return -ENOMEM;
 
        err = ctnetlink_stat_ct_fill_info(skb2, NETLINK_CB(skb).portid,
-                                         nlh->nlmsg_seq,
-                                         NFNL_MSG_TYPE(nlh->nlmsg_type),
+                                         info->nlh->nlmsg_seq,
+                                         NFNL_MSG_TYPE(info->nlh->nlmsg_type),
                                          sock_net(skb->sk));
-       if (err <= 0)
-               goto free;
-
-       err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
-       if (err < 0)
-               goto out;
-
-       return 0;
+       if (err <= 0) {
+               kfree_skb(skb2);
+               return -ENOMEM;
+       }
 
-free:
-       kfree_skb(skb2);
-out:
-       /* this avoids a loop in nfnetlink. */
-       return err == -EAGAIN ? -ENOBUFS : err;
+       return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
 }
 
 static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = {
@@ -3085,19 +3038,14 @@ ctnetlink_exp_fill_info(struct sk_buff *skb, u32 portid, u32 seq,
                        int event, const struct nf_conntrack_expect *exp)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0;
 
        event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, event);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags,
+                          exp->tuple.src.l3num, NFNETLINK_V0, 0);
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = exp->tuple.src.l3num;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = 0;
-
        if (ctnetlink_exp_dump_expect(skb, exp) < 0)
                goto nla_put_failure;
 
@@ -3117,7 +3065,6 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
        struct nf_conntrack_expect *exp = item->exp;
        struct net *net = nf_ct_exp_net(exp);
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        struct sk_buff *skb;
        unsigned int type, group;
        int flags = 0;
@@ -3140,15 +3087,11 @@ ctnetlink_expect_event(unsigned int events, struct nf_exp_event *item)
                goto errout;
 
        type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, type);
-       nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, item->portid, 0, type, flags,
+                          exp->tuple.src.l3num, NFNETLINK_V0, 0);
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = exp->tuple.src.l3num;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = 0;
-
        if (ctnetlink_exp_dump_expect(skb, exp) < 0)
                goto nla_put_failure;
 
@@ -3313,29 +3256,28 @@ static int ctnetlink_dump_exp_ct(struct net *net, struct sock *ctnl,
        return err;
 }
 
-static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
-                               struct sk_buff *skb, const struct nlmsghdr *nlh,
-                               const struct nlattr * const cda[],
-                               struct netlink_ext_ack *extack)
+static int ctnetlink_get_expect(struct sk_buff *skb,
+                               const struct nfnl_info *info,
+                               const struct nlattr * const cda[])
 {
+       u_int8_t u3 = info->nfmsg->nfgen_family;
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_expect *exp;
-       struct sk_buff *skb2;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       u_int8_t u3 = nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
+       struct sk_buff *skb2;
        int err;
 
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                if (cda[CTA_EXPECT_MASTER])
-                       return ctnetlink_dump_exp_ct(net, ctnl, skb, nlh, cda,
-                                                    extack);
+                       return ctnetlink_dump_exp_ct(info->net, info->sk, skb,
+                                                    info->nlh, cda,
+                                                    info->extack);
                else {
                        struct netlink_dump_control c = {
                                .dump = ctnetlink_exp_dump_table,
                                .done = ctnetlink_exp_done,
                        };
-                       return netlink_dump_start(ctnl, skb, nlh, &c);
+                       return netlink_dump_start(info->sk, skb, info->nlh, &c);
                }
        }
 
@@ -3355,7 +3297,7 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
        if (err < 0)
                return err;
 
-       exp = nf_ct_expect_find_get(net, &zone, &tuple);
+       exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
        if (!exp)
                return -ENOENT;
 
@@ -3368,32 +3310,24 @@ static int ctnetlink_get_expect(struct net *net, struct sock *ctnl,
                }
        }
 
-       err = -ENOMEM;
        skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (skb2 == NULL) {
+       if (!skb2) {
                nf_ct_expect_put(exp);
-               goto out;
+               return -ENOMEM;
        }
 
        rcu_read_lock();
        err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).portid,
-                                     nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
+                                     info->nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
+                                     exp);
        rcu_read_unlock();
        nf_ct_expect_put(exp);
-       if (err <= 0)
-               goto free;
-
-       err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
-       if (err < 0)
-               goto out;
-
-       return 0;
+       if (err <= 0) {
+               kfree_skb(skb2);
+               return -ENOMEM;
+       }
 
-free:
-       kfree_skb(skb2);
-out:
-       /* this avoids a loop in nfnetlink. */
-       return err == -EAGAIN ? -ENOBUFS : err;
+       return nfnetlink_unicast(skb2, info->net, NETLINK_CB(skb).portid);
 }
 
 static bool expect_iter_name(struct nf_conntrack_expect *exp, void *data)
@@ -3411,15 +3345,13 @@ static bool expect_iter_all(struct nf_conntrack_expect *exp, void *data)
        return true;
 }
 
-static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
-                               struct sk_buff *skb, const struct nlmsghdr *nlh,
-                               const struct nlattr * const cda[],
-                               struct netlink_ext_ack *extack)
+static int ctnetlink_del_expect(struct sk_buff *skb,
+                               const struct nfnl_info *info,
+                               const struct nlattr * const cda[])
 {
+       u_int8_t u3 = info->nfmsg->nfgen_family;
        struct nf_conntrack_expect *exp;
        struct nf_conntrack_tuple tuple;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       u_int8_t u3 = nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
        int err;
 
@@ -3435,7 +3367,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
                        return err;
 
                /* bump usage count to 2 */
-               exp = nf_ct_expect_find_get(net, &zone, &tuple);
+               exp = nf_ct_expect_find_get(info->net, &zone, &tuple);
                if (!exp)
                        return -ENOENT;
 
@@ -3451,7 +3383,7 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
                spin_lock_bh(&nf_conntrack_expect_lock);
                if (del_timer(&exp->timeout)) {
                        nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
-                                                  nlmsg_report(nlh));
+                                                  nlmsg_report(info->nlh));
                        nf_ct_expect_put(exp);
                }
                spin_unlock_bh(&nf_conntrack_expect_lock);
@@ -3461,14 +3393,14 @@ static int ctnetlink_del_expect(struct net *net, struct sock *ctnl,
        } else if (cda[CTA_EXPECT_HELP_NAME]) {
                char *name = nla_data(cda[CTA_EXPECT_HELP_NAME]);
 
-               nf_ct_expect_iterate_net(net, expect_iter_name, name,
+               nf_ct_expect_iterate_net(info->net, expect_iter_name, name,
                                         NETLINK_CB(skb).portid,
-                                        nlmsg_report(nlh));
+                                        nlmsg_report(info->nlh));
        } else {
                /* This basically means we have to flush everything*/
-               nf_ct_expect_iterate_net(net, expect_iter_all, NULL,
+               nf_ct_expect_iterate_net(info->net, expect_iter_all, NULL,
                                         NETLINK_CB(skb).portid,
-                                        nlmsg_report(nlh));
+                                        nlmsg_report(info->nlh));
        }
 
        return 0;
@@ -3664,15 +3596,13 @@ err_ct:
        return err;
 }
 
-static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
-                               struct sk_buff *skb, const struct nlmsghdr *nlh,
-                               const struct nlattr * const cda[],
-                               struct netlink_ext_ack *extack)
+static int ctnetlink_new_expect(struct sk_buff *skb,
+                               const struct nfnl_info *info,
+                               const struct nlattr * const cda[])
 {
+       u_int8_t u3 = info->nfmsg->nfgen_family;
        struct nf_conntrack_tuple tuple;
        struct nf_conntrack_expect *exp;
-       struct nfgenmsg *nfmsg = nlmsg_data(nlh);
-       u_int8_t u3 = nfmsg->nfgen_family;
        struct nf_conntrack_zone zone;
        int err;
 
@@ -3691,20 +3621,20 @@ static int ctnetlink_new_expect(struct net *net, struct sock *ctnl,
                return err;
 
        spin_lock_bh(&nf_conntrack_expect_lock);
-       exp = __nf_ct_expect_find(net, &zone, &tuple);
+       exp = __nf_ct_expect_find(info->net, &zone, &tuple);
        if (!exp) {
                spin_unlock_bh(&nf_conntrack_expect_lock);
                err = -ENOENT;
-               if (nlh->nlmsg_flags & NLM_F_CREATE) {
-                       err = ctnetlink_create_expect(net, &zone, cda, u3,
+               if (info->nlh->nlmsg_flags & NLM_F_CREATE) {
+                       err = ctnetlink_create_expect(info->net, &zone, cda, u3,
                                                      NETLINK_CB(skb).portid,
-                                                     nlmsg_report(nlh));
+                                                     nlmsg_report(info->nlh));
                }
                return err;
        }
 
        err = -EEXIST;
-       if (!(nlh->nlmsg_flags & NLM_F_EXCL))
+       if (!(info->nlh->nlmsg_flags & NLM_F_EXCL))
                err = ctnetlink_change_expect(exp, cda);
        spin_unlock_bh(&nf_conntrack_expect_lock);
 
@@ -3716,20 +3646,15 @@ ctnetlink_exp_stat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, int cpu,
                             const struct ip_conntrack_stat *st)
 {
        struct nlmsghdr *nlh;
-       struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
 
        event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK,
                              IPCTNL_MSG_EXP_GET_STATS_CPU);
-       nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
-       if (nlh == NULL)
+       nlh = nfnl_msg_put(skb, portid, seq, event, flags, AF_UNSPEC,
+                          NFNETLINK_V0, htons(cpu));
+       if (!nlh)
                goto nlmsg_failure;
 
-       nfmsg = nlmsg_data(nlh);
-       nfmsg->nfgen_family = AF_UNSPEC;
-       nfmsg->version      = NFNETLINK_V0;
-       nfmsg->res_id       = htons(cpu);
-
        if (nla_put_be32(skb, CTA_STATS_EXP_NEW, htonl(st->expect_new)) ||
            nla_put_be32(skb, CTA_STATS_EXP_CREATE, htonl(st->expect_create)) ||
            nla_put_be32(skb, CTA_STATS_EXP_DELETE, htonl(st->expect_delete)))
@@ -3770,17 +3695,15 @@ ctnetlink_exp_stat_cpu_dump(struct sk_buff *skb, struct netlink_callback *cb)
        return skb->len;
 }
 
-static int ctnetlink_stat_exp_cpu(struct net *net, struct sock *ctnl,
-                                 struct sk_buff *skb,
-                                 const struct nlmsghdr *nlh,
-                                 const struct nlattr * const cda[],
-                                 struct netlink_ext_ack *extack)
+static int ctnetlink_stat_exp_cpu(struct sk_buff *skb,
+                                 const struct nfnl_info *info,
+                                 const struct nlattr * const cda[])
 {
-       if (nlh->nlmsg_flags & NLM_F_DUMP) {
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
                struct netlink_dump_control c = {
                        .dump = ctnetlink_exp_stat_cpu_dump,
                };
-               return netlink_dump_start(ctnl, skb, nlh, &c);
+               return netlink_dump_start(info->sk, skb, info->nlh, &c);
        }
 
        return 0;
@@ -3797,35 +3720,71 @@ static struct nf_exp_event_notifier ctnl_notifier_exp = {
 #endif
 
 static const struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = {
-       [IPCTNL_MSG_CT_NEW]             = { .call = ctnetlink_new_conntrack,
-                                           .attr_count = CTA_MAX,
-                                           .policy = ct_nla_policy },
-       [IPCTNL_MSG_CT_GET]             = { .call = ctnetlink_get_conntrack,
-                                           .attr_count = CTA_MAX,
-                                           .policy = ct_nla_policy },
-       [IPCTNL_MSG_CT_DELETE]          = { .call = ctnetlink_del_conntrack,
-                                           .attr_count = CTA_MAX,
-                                           .policy = ct_nla_policy },
-       [IPCTNL_MSG_CT_GET_CTRZERO]     = { .call = ctnetlink_get_conntrack,
-                                           .attr_count = CTA_MAX,
-                                           .policy = ct_nla_policy },
-       [IPCTNL_MSG_CT_GET_STATS_CPU]   = { .call = ctnetlink_stat_ct_cpu },
-       [IPCTNL_MSG_CT_GET_STATS]       = { .call = ctnetlink_stat_ct },
-       [IPCTNL_MSG_CT_GET_DYING]       = { .call = ctnetlink_get_ct_dying },
-       [IPCTNL_MSG_CT_GET_UNCONFIRMED] = { .call = ctnetlink_get_ct_unconfirmed },
+       [IPCTNL_MSG_CT_NEW]     = {
+               .call           = ctnetlink_new_conntrack,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_MAX,
+               .policy         = ct_nla_policy
+       },
+       [IPCTNL_MSG_CT_GET]     = {
+               .call           = ctnetlink_get_conntrack,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_MAX,
+               .policy         = ct_nla_policy
+       },
+       [IPCTNL_MSG_CT_DELETE]  = {
+               .call           = ctnetlink_del_conntrack,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_MAX,
+               .policy         = ct_nla_policy
+       },
+       [IPCTNL_MSG_CT_GET_CTRZERO] = {
+               .call           = ctnetlink_get_conntrack,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_MAX,
+               .policy         = ct_nla_policy
+       },
+       [IPCTNL_MSG_CT_GET_STATS_CPU] = {
+               .call           = ctnetlink_stat_ct_cpu,
+               .type           = NFNL_CB_MUTEX,
+       },
+       [IPCTNL_MSG_CT_GET_STATS] = {
+               .call           = ctnetlink_stat_ct,
+               .type           = NFNL_CB_MUTEX,
+       },
+       [IPCTNL_MSG_CT_GET_DYING] = {
+               .call           = ctnetlink_get_ct_dying,
+               .type           = NFNL_CB_MUTEX,
+       },
+       [IPCTNL_MSG_CT_GET_UNCONFIRMED] = {
+               .call           = ctnetlink_get_ct_unconfirmed,
+               .type           = NFNL_CB_MUTEX,
+       },
 };
 
 static const struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = {
-       [IPCTNL_MSG_EXP_GET]            = { .call = ctnetlink_get_expect,
-                                           .attr_count = CTA_EXPECT_MAX,
-                                           .policy = exp_nla_policy },
-       [IPCTNL_MSG_EXP_NEW]            = { .call = ctnetlink_new_expect,
-                                           .attr_count = CTA_EXPECT_MAX,
-                                           .policy = exp_nla_policy },
-       [IPCTNL_MSG_EXP_DELETE]         = { .call = ctnetlink_del_expect,
-                                           .attr_count = CTA_EXPECT_MAX,
-                                           .policy = exp_nla_policy },
-       [IPCTNL_MSG_EXP_GET_STATS_CPU]  = { .call = ctnetlink_stat_exp_cpu },
+       [IPCTNL_MSG_EXP_GET] = {
+               .call           = ctnetlink_get_expect,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_EXPECT_MAX,
+               .policy         = exp_nla_policy
+       },
+       [IPCTNL_MSG_EXP_NEW] = {
+               .call           = ctnetlink_new_expect,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_EXPECT_MAX,
+               .policy         = exp_nla_policy
+       },
+       [IPCTNL_MSG_EXP_DELETE] = {
+               .call           = ctnetlink_del_expect,
+               .type           = NFNL_CB_MUTEX,
+               .attr_count     = CTA_EXPECT_MAX,
+               .policy         = exp_nla_policy
+       },
+       [IPCTNL_MSG_EXP_GET_STATS_CPU] = {
+               .call           = ctnetlink_stat_exp_cpu,
+               .type           = NFNL_CB_MUTEX,
+       },
 };
 
 static const struct nfnetlink_subsystem ctnl_subsys = {