]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
authorDavid S. Miller <davem@davemloft.net>
Mon, 1 May 2017 14:46:50 +0000 (10:46 -0400)
committerDavid S. Miller <davem@davemloft.net>
Mon, 1 May 2017 14:47:53 +0000 (10:47 -0400)
Pablo Neira Ayuso says:

====================
Netfilter/IPVS updates for net-next

The following patchset contains Netfilter updates for your net-next
tree. A large bunch of code cleanups, simplify the conntrack extension
codebase, get rid of the fake conntrack object, speed up netns by
selective synchronize_net() calls. More specifically, they are:

1) Check for ct->status bit instead of using nfct_nat() from IPVS and
   Netfilter codebase, patch from Florian Westphal.

2) Use kcalloc() wherever possible in the IPVS code, from Varsha Rao.

3) Simplify FTP IPVS helper module registration path, from Arushi Singhal.

4) Introduce nft_is_base_chain() helper function.

5) Enforce expectation limit from userspace conntrack helper,
   from Gao Feng.

6) Add nf_ct_remove_expect() helper function, from Gao Feng.

7) NAT mangle helper function return boolean, from Gao Feng.

8) ctnetlink_alloc_expect() should only work for conntrack with
   helpers, from Gao Feng.

9) Add nfnl_msg_type() helper function to nfnetlink to build the
   netlink message type.

10) Get rid of unnecessary cast on void, from simran singhal.

11) Use seq_puts()/seq_putc() instead of seq_printf() where possible,
    also from simran singhal.

12) Use list_prev_entry() from nf_tables, from simran signhal.

13) Remove unnecessary & on pointer function in the Netfilter and IPVS
    code.

14) Remove obsolete comment on set of rules per CPU in ip6_tables,
    no longer true. From Arushi Singhal.

15) Remove duplicated nf_conntrack_l4proto_udplite4, from Gao Feng.

16) Remove unnecessary nested rcu_read_lock() in
    __nf_nat_decode_session(). Code running from hooks are already
    guaranteed to run under RCU read side.

17) Remove deadcode in nf_tables_getobj(), from Aaron Conole.

18) Remove double assignment in nf_ct_l4proto_pernet_unregister_one(),
    also from Aaron.

19) Get rid of unsed __ip_set_get_netlink(), from Aaron Conole.

20) Don't propagate NF_DROP error to userspace via ctnetlink in
    __nf_nat_alloc_null_binding() function, from Gao Feng.

21) Revisit nf_ct_deliver_cached_events() to remove unnecessary checks,
    from Gao Feng.

22) Kill the fake untracked conntrack objects, use ctinfo instead to
    annotate a conntrack object is untracked, from Florian Westphal.

23) Remove nf_ct_is_untracked(), now obsolete since we have no
    conntrack template anymore, from Florian.

24) Add event mask support to nft_ct, also from Florian.

25) Move nf_conn_help structure to
    include/net/netfilter/nf_conntrack_helper.h.

26) Add a fixed 32 bytes scratchpad area for conntrack helpers.
    Thus, we don't deal with variable conntrack extensions anymore.
    Make sure userspace conntrack helper doesn't go over that size.
    Remove variable size ct extension infrastructure now this code
    got no more clients. From Florian Westphal.

27) Restore offset and length of nf_ct_ext structure to 8 bytes now
    that wraparound is not possible any longer, also from Florian.

28) Allow to get rid of unassured flows under stress in conntrack,
    this applies to DCCP, SCTP and TCP protocols, from Florian.

29) Shrink size of nf_conntrack_ecache structure, from Florian.

30) Use TCP_MAX_WSCALE instead of hardcoded 14 in TCP tracker,
    from Gao Feng.

31) Register SYNPROXY hooks on demand, from Florian Westphal.

32) Use pernet hook whenever possible, instead of global hook
    registration, from Florian Westphal.

33) Pass hook structure to ebt_register_table() to consolidate some
    infrastructure code, from Florian Westphal.

34) Use consume_skb() and return NF_STOLEN, instead of NF_DROP in the
    SYNPROXY code, to make sure device stats are not fooled, patch
    from Gao Feng.

35) Remove NF_CT_EXT_F_PREALLOC this kills quite some code that we
    don't need anymore if we just select a fixed size instead of
    expensive runtime time calculation of this. From Florian.

36) Constify nf_ct_extend_register() and nf_ct_extend_unregister(),
    from Florian.

37) Simplify nf_ct_ext_add(), this kills nf_ct_ext_create(), from
    Florian.

38) Attach NAT extension on-demand from masquerade and pptp helper
    path, from Florian.

39) Get rid of useless ip_vs_set_state_timeout(), from Aaron Conole.

40) Speed up netns by selective calls of synchronize_net(), from
    Florian Westphal.

41) Silence stack size warning gcc in 32-bit arch in snmp helper,
    from Florian.

42) Inconditionally call nf_ct_ext_destroy(), even if we have no
    extensions, to deal with the NF_NAT_MANIP_SRC case. Patch from
    Liping Zhang.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
19 files changed:
1  2 
net/decnet/netfilter/dn_rtmsg.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_nat_core.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nfnetlink_acct.c
net/netfilter/nfnetlink_cthelper.c
net/netfilter/nfnetlink_cttimeout.c
net/netfilter/nfnetlink_queue.c
net/netfilter/nft_compat.c
net/netfilter/nft_hash.c
net/openvswitch/conntrack.c

index c8bf5136a72bcb19db1b0523c743e4a4dce6514a,f44303a401056c58767e20446ac0fa820d43f33e..1ed81ac6dd1a28b79dff9f9f4e8c1d0f99306a33
@@@ -96,7 -96,7 +96,7 @@@ static unsigned int dnrmg_hook(void *pr
  }
  
  
 -#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
 +#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err), NULL); return; } while (0)
  
  static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
  {
@@@ -134,7 -134,7 +134,7 @@@ static int __init dn_rtmsg_init(void
                return -ENOMEM;
        }
  
-       rv = nf_register_hook(&dnrmg_ops);
+       rv = nf_register_net_hook(&init_net, &dnrmg_ops);
        if (rv) {
                netlink_kernel_release(dnrmg);
        }
  
  static void __exit dn_rtmsg_fini(void)
  {
-       nf_unregister_hook(&dnrmg_ops);
+       nf_unregister_net_hook(&init_net, &dnrmg_ops);
        netlink_kernel_release(dnrmg);
  }
  
index 9bd5b6636181074eebb5324376ea47eeb2bf2fc1,2b87d9fd3f72d9c37a48410ccddfb2dd7b884f0e..ba6a5516dc7c724b172ee13c0456b461c47f7281
@@@ -295,8 -295,7 +295,8 @@@ ip_set_get_ipaddr4(struct nlattr *nla
  
        if (unlikely(!flag_nested(nla)))
                return -IPSET_ERR_PROTOCOL;
 -      if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
 +      if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla,
 +                           ipaddr_policy, NULL))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV4)))
                return -IPSET_ERR_PROTOCOL;
@@@ -314,8 -313,7 +314,8 @@@ ip_set_get_ipaddr6(struct nlattr *nla, 
        if (unlikely(!flag_nested(nla)))
                return -IPSET_ERR_PROTOCOL;
  
 -      if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla, ipaddr_policy))
 +      if (nla_parse_nested(tb, IPSET_ATTR_IPADDR_MAX, nla,
 +                           ipaddr_policy, NULL))
                return -IPSET_ERR_PROTOCOL;
        if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_IPADDR_IPV6)))
                return -IPSET_ERR_PROTOCOL;
@@@ -502,14 -500,6 +502,6 @@@ __ip_set_put(struct ip_set *set
  /* set->ref can be swapped out by ip_set_swap, netlink events (like dump) need
   * a separate reference counter
   */
- static inline void
- __ip_set_get_netlink(struct ip_set *set)
- {
-       write_lock_bh(&ip_set_ref_lock);
-       set->ref_netlink++;
-       write_unlock_bh(&ip_set_ref_lock);
- }
  static inline void
  __ip_set_put_netlink(struct ip_set *set)
  {
@@@ -771,7 -761,7 +763,7 @@@ start_msg(struct sk_buff *skb, u32 port
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
  
-       nlh = nlmsg_put(skb, portid, seq, cmd | (NFNL_SUBSYS_IPSET << 8),
+       nlh = nlmsg_put(skb, portid, seq, nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd),
                        sizeof(*nfmsg), flags);
        if (!nlh)
                return NULL;
@@@ -908,7 -898,7 +900,7 @@@ static int ip_set_create(struct net *ne
        /* Without holding any locks, create private part. */
        if (attr[IPSET_ATTR_DATA] &&
            nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA],
 -                           set->type->create_policy)) {
 +                           set->type->create_policy, NULL)) {
                ret = -IPSET_ERR_PROTOCOL;
                goto put_out;
        }
@@@ -1259,8 -1249,8 +1251,8 @@@ dump_init(struct netlink_callback *cb, 
        ip_set_id_t index;
  
        /* Second pass, so parser can't fail */
 -      nla_parse(cda, IPSET_ATTR_CMD_MAX,
 -                attr, nlh->nlmsg_len - min_len, ip_set_setname_policy);
 +      nla_parse(cda, IPSET_ATTR_CMD_MAX, attr, nlh->nlmsg_len - min_len,
 +                ip_set_setname_policy, NULL);
  
        if (cda[IPSET_ATTR_SETNAME]) {
                struct ip_set *set;
@@@ -1307,7 -1297,7 +1299,7 @@@ ip_set_dump_start(struct sk_buff *skb, 
                         * manually :-(
                         */
                        if (nlh->nlmsg_flags & NLM_F_ACK)
 -                              netlink_ack(cb->skb, nlh, ret);
 +                              netlink_ack(cb->skb, nlh, ret, NULL);
                        return ret;
                }
        }
@@@ -1503,8 -1493,9 +1495,8 @@@ call_ad(struct sock *ctnl, struct sk_bu
                memcpy(&errmsg->msg, nlh, nlh->nlmsg_len);
                cmdattr = (void *)&errmsg->msg + min_len;
  
 -              nla_parse(cda, IPSET_ATTR_CMD_MAX,
 -                        cmdattr, nlh->nlmsg_len - min_len,
 -                        ip_set_adt_policy);
 +              nla_parse(cda, IPSET_ATTR_CMD_MAX, cmdattr,
 +                        nlh->nlmsg_len - min_len, ip_set_adt_policy, NULL);
  
                errline = nla_data(cda[IPSET_ATTR_LINENO]);
  
@@@ -1550,7 -1541,7 +1542,7 @@@ static int ip_set_uadd(struct net *net
        if (attr[IPSET_ATTR_DATA]) {
                if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
                                     attr[IPSET_ATTR_DATA],
 -                                   set->type->adt_policy))
 +                                   set->type->adt_policy, NULL))
                        return -IPSET_ERR_PROTOCOL;
                ret = call_ad(ctnl, skb, set, tb, IPSET_ADD, flags,
                              use_lineno);
                        if (nla_type(nla) != IPSET_ATTR_DATA ||
                            !flag_nested(nla) ||
                            nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
 -                                           set->type->adt_policy))
 +                                           set->type->adt_policy, NULL))
                                return -IPSET_ERR_PROTOCOL;
                        ret = call_ad(ctnl, skb, set, tb, IPSET_ADD,
                                      flags, use_lineno);
@@@ -1604,7 -1595,7 +1596,7 @@@ static int ip_set_udel(struct net *net
        if (attr[IPSET_ATTR_DATA]) {
                if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX,
                                     attr[IPSET_ATTR_DATA],
 -                                   set->type->adt_policy))
 +                                   set->type->adt_policy, NULL))
                        return -IPSET_ERR_PROTOCOL;
                ret = call_ad(ctnl, skb, set, tb, IPSET_DEL, flags,
                              use_lineno);
                        if (nla_type(nla) != IPSET_ATTR_DATA ||
                            !flag_nested(nla) ||
                            nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, nla,
 -                                           set->type->adt_policy))
 +                                           set->type->adt_policy, NULL))
                                return -IPSET_ERR_PROTOCOL;
                        ret = call_ad(ctnl, skb, set, tb, IPSET_DEL,
                                      flags, use_lineno);
@@@ -1647,7 -1638,7 +1639,7 @@@ static int ip_set_utest(struct net *net
                return -ENOENT;
  
        if (nla_parse_nested(tb, IPSET_ATTR_ADT_MAX, attr[IPSET_ATTR_DATA],
 -                           set->type->adt_policy))
 +                           set->type->adt_policy, NULL))
                return -IPSET_ERR_PROTOCOL;
  
        rcu_read_lock_bh();
@@@ -1916,7 -1907,7 +1908,7 @@@ ip_set_sockfn_get(struct sock *sk, int 
                ret = -EFAULT;
                goto done;
        }
-       op = (unsigned int *)data;
+       op = data;
  
        if (*op < IP_SET_OP_VERSION) {
                /* Check the version at the beginning of operations */
@@@ -2014,7 -2005,7 +2006,7 @@@ static struct nf_sockopt_ops so_set __r
        .pf             = PF_INET,
        .get_optmin     = SO_IP_SET,
        .get_optmax     = SO_IP_SET + 1,
-       .get            = &ip_set_sockfn_get,
+       .get            = ip_set_sockfn_get,
        .owner          = THIS_MODULE,
  };
  
index 892da70866d6407630b5f76a27b682d62ad7de2e,90ac6bc1bd287638ea673e57f5e4206bf0015d83..668d9643f0cc7a9e410a73f961ec1730fc57033d
@@@ -1774,13 -1774,13 +1774,13 @@@ static struct ctl_table vs_vars[] = 
                .procname       = "sync_version",
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_do_sync_mode,
+               .proc_handler   = proc_do_sync_mode,
        },
        {
                .procname       = "sync_ports",
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = &proc_do_sync_ports,
+               .proc_handler   = proc_do_sync_ports,
        },
        {
                .procname       = "sync_persist_mode",
@@@ -2130,8 -2130,8 +2130,8 @@@ static int ip_vs_stats_show(struct seq_
  /*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
        seq_puts(seq,
                 "   Total Incoming Outgoing         Incoming         Outgoing\n");
-       seq_printf(seq,
-                  "   Conns  Packets  Packets            Bytes            Bytes\n");
+       seq_puts(seq,
+                "   Conns  Packets  Packets            Bytes            Bytes\n");
  
        ip_vs_copy_stats(&show, &net_ipvs(net)->tot_stats);
        seq_printf(seq, "%8LX %8LX %8LX %16LX %16LX\n\n",
@@@ -2178,8 -2178,8 +2178,8 @@@ static int ip_vs_stats_percpu_show(stru
  /*               01234567 01234567 01234567 0123456701234567 0123456701234567 */
        seq_puts(seq,
                 "       Total Incoming Outgoing         Incoming         Outgoing\n");
-       seq_printf(seq,
-                  "CPU    Conns  Packets  Packets            Bytes            Bytes\n");
+       seq_puts(seq,
+                "CPU    Conns  Packets  Packets            Bytes            Bytes\n");
  
        for_each_possible_cpu(i) {
                struct ip_vs_cpu_stats *u = per_cpu_ptr(cpustats, i);
@@@ -3089,8 -3089,7 +3089,8 @@@ static int ip_vs_genl_parse_service(str
  
        /* Parse mandatory identifying service fields first */
        if (nla == NULL ||
 -          nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla, ip_vs_svc_policy))
 +          nla_parse_nested(attrs, IPVS_SVC_ATTR_MAX, nla,
 +                           ip_vs_svc_policy, NULL))
                return -EINVAL;
  
        nla_af          = attrs[IPVS_SVC_ATTR_AF];
@@@ -3252,8 -3251,8 +3252,8 @@@ static int ip_vs_genl_dump_dests(struc
        mutex_lock(&__ip_vs_mutex);
  
        /* Try to find the service for which to dump destinations */
 -      if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs,
 -                      IPVS_CMD_ATTR_MAX, ip_vs_cmd_policy))
 +      if (nlmsg_parse(cb->nlh, GENL_HDRLEN, attrs, IPVS_CMD_ATTR_MAX,
 +                      ip_vs_cmd_policy, NULL))
                goto out_err;
  
  
@@@ -3289,8 -3288,7 +3289,8 @@@ static int ip_vs_genl_parse_dest(struc
  
        /* Parse mandatory identifying destination fields first */
        if (nla == NULL ||
 -          nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla, ip_vs_dest_policy))
 +          nla_parse_nested(attrs, IPVS_DEST_ATTR_MAX, nla,
 +                           ip_vs_dest_policy, NULL))
                return -EINVAL;
  
        nla_addr        = attrs[IPVS_DEST_ATTR_ADDR];
@@@ -3532,7 -3530,7 +3532,7 @@@ static int ip_vs_genl_set_daemon(struc
                if (!info->attrs[IPVS_CMD_ATTR_DAEMON] ||
                    nla_parse_nested(daemon_attrs, IPVS_DAEMON_ATTR_MAX,
                                     info->attrs[IPVS_CMD_ATTR_DAEMON],
 -                                   ip_vs_daemon_policy))
 +                                   ip_vs_daemon_policy, info->extack))
                        goto out;
  
                if (cmd == IPVS_CMD_NEW_DAEMON)
index a5ca5e426bae2aca4e543320fffd1d608f2fff2b,7f12c8a7811222d4fcbf6d9f0eabf183d0677d53..e03d16ed550d6bf07a537f4b150148a3cd967f59
@@@ -57,7 -57,7 +57,7 @@@ void nf_ct_unlink_expect_report(struct 
        hlist_del_rcu(&exp->hnode);
        net->ct.expect_count--;
  
 -      hlist_del(&exp->lnode);
 +      hlist_del_rcu(&exp->lnode);
        master_help->expecting[exp->class]--;
  
        nf_ct_expect_event_report(IPEXP_DESTROY, exp, portid, report);
@@@ -103,6 -103,17 +103,17 @@@ nf_ct_exp_equal(const struct nf_conntra
               nf_ct_zone_equal_any(i->master, zone);
  }
  
+ bool nf_ct_remove_expect(struct nf_conntrack_expect *exp)
+ {
+       if (del_timer(&exp->timeout)) {
+               nf_ct_unlink_expect(exp);
+               nf_ct_expect_put(exp);
+               return true;
+       }
+       return false;
+ }
+ EXPORT_SYMBOL_GPL(nf_ct_remove_expect);
  struct nf_conntrack_expect *
  __nf_ct_expect_find(struct net *net,
                    const struct nf_conntrack_zone *zone,
@@@ -211,10 -222,7 +222,7 @@@ void nf_ct_remove_expectations(struct n
  
        spin_lock_bh(&nf_conntrack_expect_lock);
        hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) {
-               if (del_timer(&exp->timeout)) {
-                       nf_ct_unlink_expect(exp);
-                       nf_ct_expect_put(exp);
-               }
+               nf_ct_remove_expect(exp);
        }
        spin_unlock_bh(&nf_conntrack_expect_lock);
  }
@@@ -255,10 -263,7 +263,7 @@@ static inline int expect_matches(const 
  void nf_ct_unexpect_related(struct nf_conntrack_expect *exp)
  {
        spin_lock_bh(&nf_conntrack_expect_lock);
-       if (del_timer(&exp->timeout)) {
-               nf_ct_unlink_expect(exp);
-               nf_ct_expect_put(exp);
-       }
+       nf_ct_remove_expect(exp);
        spin_unlock_bh(&nf_conntrack_expect_lock);
  }
  EXPORT_SYMBOL_GPL(nf_ct_unexpect_related);
@@@ -363,7 -368,7 +368,7 @@@ static void nf_ct_expect_insert(struct 
        /* two references : one for hash insert, one for the timer */
        refcount_add(2, &exp->use);
  
 -      hlist_add_head(&exp->lnode, &master_help->expectations);
 +      hlist_add_head_rcu(&exp->lnode, &master_help->expectations);
        master_help->expecting[exp->class]++;
  
        hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]);
@@@ -394,10 -399,8 +399,8 @@@ static void evict_oldest_expect(struct 
                        last = exp;
        }
  
-       if (last && del_timer(&last->timeout)) {
-               nf_ct_unlink_expect(last);
-               nf_ct_expect_put(last);
-       }
+       if (last)
+               nf_ct_remove_expect(last);
  }
  
  static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
        h = nf_ct_expect_dst_hash(net, &expect->tuple);
        hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) {
                if (expect_matches(i, expect)) {
-                       if (del_timer(&i->timeout)) {
-                               nf_ct_unlink_expect(i);
-                               nf_ct_expect_put(i);
+                       if (nf_ct_remove_expect(expect))
                                break;
-                       }
                } else if (expect_clash(i, expect)) {
                        ret = -EBUSY;
                        goto out;
@@@ -549,7 -549,7 +549,7 @@@ static int exp_seq_show(struct seq_fil
                seq_printf(s, "%ld ", timer_pending(&expect->timeout)
                           ? (long)(expect->timeout.expires - jiffies)/HZ : 0);
        else
-               seq_printf(s, "- ");
+               seq_puts(s, "- ");
        seq_printf(s, "l3proto = %u proto=%u ",
                   expect->tuple.src.l3num,
                   expect->tuple.dst.protonum);
                                       expect->tuple.dst.protonum));
  
        if (expect->flags & NF_CT_EXPECT_PERMANENT) {
-               seq_printf(s, "PERMANENT");
+               seq_puts(s, "PERMANENT");
                delim = ",";
        }
        if (expect->flags & NF_CT_EXPECT_INACTIVE) {
index 4eeb3418366ad5473945395346b6e4e5fc213fbc,a57a52f173f7023b2df4301ac92d33bdce448e13..4b9dfe3eef6241756d6474e1f6caad568a942b63
@@@ -158,25 -158,16 +158,25 @@@ nf_conntrack_helper_try_module_get(cons
  {
        struct nf_conntrack_helper *h;
  
 +      rcu_read_lock();
 +
        h = __nf_conntrack_helper_find(name, l3num, protonum);
  #ifdef CONFIG_MODULES
        if (h == NULL) {
 -              if (request_module("nfct-helper-%s", name) == 0)
 +              rcu_read_unlock();
 +              if (request_module("nfct-helper-%s", name) == 0) {
 +                      rcu_read_lock();
                        h = __nf_conntrack_helper_find(name, l3num, protonum);
 +              } else {
 +                      return h;
 +              }
        }
  #endif
        if (h != NULL && !try_module_get(h->me))
                h = NULL;
  
 +      rcu_read_unlock();
 +
        return h;
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helper_try_module_get);
@@@ -187,8 -178,7 +187,7 @@@ nf_ct_helper_ext_add(struct nf_conn *ct
  {
        struct nf_conn_help *help;
  
-       help = nf_ct_ext_add_length(ct, NF_CT_EXT_HELPER,
-                                   helper->data_len, gfp);
+       help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
        if (help)
                INIT_HLIST_HEAD(&help->expectations);
        else
@@@ -320,36 -310,38 +319,36 @@@ void nf_ct_helper_expectfn_unregister(s
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_unregister);
  
 +/* Caller should hold the rcu lock */
  struct nf_ct_helper_expectfn *
  nf_ct_helper_expectfn_find_by_name(const char *name)
  {
        struct nf_ct_helper_expectfn *cur;
        bool found = false;
  
 -      rcu_read_lock();
        list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
                if (!strcmp(cur->name, name)) {
                        found = true;
                        break;
                }
        }
 -      rcu_read_unlock();
        return found ? cur : NULL;
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_name);
  
 +/* Caller should hold the rcu lock */
  struct nf_ct_helper_expectfn *
  nf_ct_helper_expectfn_find_by_symbol(const void *symbol)
  {
        struct nf_ct_helper_expectfn *cur;
        bool found = false;
  
 -      rcu_read_lock();
        list_for_each_entry_rcu(cur, &nf_ct_helper_expectfn_list, head) {
                if (cur->expectfn == symbol) {
                        found = true;
                        break;
                }
        }
 -      rcu_read_unlock();
        return found ? cur : NULL;
  }
  EXPORT_SYMBOL_GPL(nf_ct_helper_expectfn_find_by_symbol);
@@@ -392,6 -384,9 +391,9 @@@ int nf_conntrack_helper_register(struc
        BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES);
        BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1);
  
+       if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
+               return -EINVAL;
        mutex_lock(&nf_ct_helper_mutex);
        hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) {
                if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, &mask)) {
@@@ -455,11 -450,8 +457,8 @@@ void nf_conntrack_helper_unregister(str
                        if ((rcu_dereference_protected(
                                        help->helper,
                                        lockdep_is_held(&nf_conntrack_expect_lock)
-                                       ) == me || exp->helper == me) &&
-                           del_timer(&exp->timeout)) {
-                               nf_ct_unlink_expect(exp);
-                               nf_ct_expect_put(exp);
-                       }
+                                       ) == me || exp->helper == me))
+                               nf_ct_remove_expect(exp);
                }
        }
        spin_unlock_bh(&nf_conntrack_expect_lock);
@@@ -491,7 -483,7 +490,7 @@@ void nf_ct_helper_init(struct nf_conntr
                       u16 l3num, u16 protonum, const char *name,
                       u16 default_port, u16 spec_port, u32 id,
                       const struct nf_conntrack_expect_policy *exp_pol,
-                      u32 expect_class_max, u32 data_len,
+                      u32 expect_class_max,
                       int (*help)(struct sk_buff *skb, unsigned int protoff,
                                   struct nf_conn *ct,
                                   enum ip_conntrack_info ctinfo),
        helper->tuple.src.u.all = htons(spec_port);
        helper->expect_policy = exp_pol;
        helper->expect_class_max = expect_class_max;
-       helper->data_len = data_len;
        helper->help = help;
        helper->from_nlattr = from_nlattr;
        helper->me = module;
@@@ -544,7 -535,7 +542,7 @@@ void nf_conntrack_helpers_unregister(st
  }
  EXPORT_SYMBOL_GPL(nf_conntrack_helpers_unregister);
  
- static struct nf_ct_ext_type helper_extend __read_mostly = {
+ static const struct nf_ct_ext_type helper_extend = {
        .len    = sizeof(struct nf_conn_help),
        .align  = __alignof__(struct nf_conn_help),
        .id     = NF_CT_EXT_HELPER,
index aafd25dff8c0d1ca018dd3199dd715af25faf88f,83a1190504b40c1c35c57a9cdcda40b6dca03b73..5f6f2f388928130a2717911fef15c72325ebe2f3
@@@ -467,7 -467,7 +467,7 @@@ ctnetlink_fill_info(struct sk_buff *skb
        struct nlattr *nest_parms;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
  
-       event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_NEW);
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_NEW);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -627,10 -627,6 +627,6 @@@ ctnetlink_conntrack_event(unsigned int 
        unsigned int flags = 0, group;
        int err;
  
-       /* ignore our fake conntrack entry */
-       if (nf_ct_is_untracked(ct))
-               return 0;
        if (events & (1 << IPCT_DESTROY)) {
                type = IPCTNL_MSG_CT_DELETE;
                group = NFNLGRP_CONNTRACK_DESTROY;
        if (skb == NULL)
                goto errout;
  
-       type |= NFNL_SUBSYS_CTNETLINK << 8;
+       type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK, type);
        nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -908,7 -904,7 +904,7 @@@ static int ctnetlink_parse_tuple_ip(str
        struct nf_conntrack_l3proto *l3proto;
        int ret = 0;
  
 -      ret = nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
 +      ret = nla_parse_nested(tb, CTA_IP_MAX, attr, NULL, NULL);
        if (ret < 0)
                return ret;
  
  
        if (likely(l3proto->nlattr_to_tuple)) {
                ret = nla_validate_nested(attr, CTA_IP_MAX,
 -                                        l3proto->nla_policy);
 +                                        l3proto->nla_policy, NULL);
                if (ret == 0)
                        ret = l3proto->nlattr_to_tuple(tb, tuple);
        }
@@@ -938,8 -934,7 +934,8 @@@ static int ctnetlink_parse_tuple_proto(
        struct nf_conntrack_l4proto *l4proto;
        int ret = 0;
  
 -      ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy);
 +      ret = nla_parse_nested(tb, CTA_PROTO_MAX, attr, proto_nla_policy,
 +                             NULL);
        if (ret < 0)
                return ret;
  
  
        if (likely(l4proto->nlattr_to_tuple)) {
                ret = nla_validate_nested(attr, CTA_PROTO_MAX,
 -                                        l4proto->nla_policy);
 +                                        l4proto->nla_policy, NULL);
                if (ret == 0)
                        ret = l4proto->nlattr_to_tuple(tb, tuple);
        }
@@@ -1016,8 -1011,7 +1012,8 @@@ ctnetlink_parse_tuple(const struct nlat
  
        memset(tuple, 0, sizeof(*tuple));
  
 -      err = nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], tuple_nla_policy);
 +      err = nla_parse_nested(tb, CTA_TUPLE_MAX, cda[type], tuple_nla_policy,
 +                             NULL);
        if (err < 0)
                return err;
  
@@@ -1067,7 -1061,7 +1063,7 @@@ static int ctnetlink_parse_help(const s
        int err;
        struct nlattr *tb[CTA_HELP_MAX+1];
  
 -      err = nla_parse_nested(tb, CTA_HELP_MAX, attr, help_nla_policy);
 +      err = nla_parse_nested(tb, CTA_HELP_MAX, attr, help_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -1490,16 -1484,11 +1486,16 @@@ static int ctnetlink_change_helper(stru
                 * treat the second attempt as a no-op instead of returning
                 * an error.
                 */
 -              if (help && help->helper &&
 -                  !strcmp(help->helper->name, helpname))
 -                      return 0;
 -              else
 -                      return -EBUSY;
 +              err = -EBUSY;
 +              if (help) {
 +                      rcu_read_lock();
 +                      helper = rcu_dereference(help->helper);
 +                      if (helper && !strcmp(helper->name, helpname))
 +                              err = 0;
 +                      rcu_read_unlock();
 +              }
 +
 +              return err;
        }
  
        if (!strcmp(helpname, "")) {
@@@ -1573,8 -1562,7 +1569,8 @@@ static int ctnetlink_change_protoinfo(s
        struct nf_conntrack_l4proto *l4proto;
        int err = 0;
  
 -      err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, protoinfo_policy);
 +      err = nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, protoinfo_policy,
 +                             NULL);
        if (err < 0)
                return err;
  
@@@ -1599,7 -1587,7 +1595,7 @@@ static int change_seq_adj(struct nf_ct_
        int err;
        struct nlattr *cda[CTA_SEQADJ_MAX+1];
  
 -      err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy);
 +      err = nla_parse_nested(cda, CTA_SEQADJ_MAX, attr, seqadj_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -1937,9 -1925,9 +1933,9 @@@ static int ctnetlink_new_conntrack(stru
  
                        err = 0;
                        if (test_bit(IPS_EXPECTED_BIT, &ct->status))
 -                              events = IPCT_RELATED;
 +                              events = 1 << IPCT_RELATED;
                        else
 -                              events = IPCT_NEW;
 +                              events = 1 << IPCT_NEW;
  
                        if (cda[CTA_LABELS] &&
                            ctnetlink_attach_labels(ct, cda) == 0)
@@@ -1991,7 -1979,8 +1987,8 @@@ ctnetlink_ct_stat_cpu_fill_info(struct 
        struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
  
-       event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS_CPU);
+       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)
                goto nlmsg_failure;
@@@ -2074,7 -2063,7 +2071,7 @@@ ctnetlink_stat_ct_fill_info(struct sk_b
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
        unsigned int nr_conntracks = atomic_read(&net->ct.count);
  
-       event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_GET_STATS);
+       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)
                goto nlmsg_failure;
@@@ -2180,13 -2169,7 +2177,7 @@@ ctnetlink_glue_build_size(const struct 
  static struct nf_conn *ctnetlink_glue_get_ct(const struct sk_buff *skb,
                                             enum ip_conntrack_info *ctinfo)
  {
-       struct nf_conn *ct;
-       ct = nf_ct_get(skb, ctinfo);
-       if (ct && nf_ct_is_untracked(ct))
-               ct = NULL;
-       return ct;
+       return nf_ct_get(skb, ctinfo);
  }
  
  static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
@@@ -2356,7 -2339,7 +2347,7 @@@ ctnetlink_glue_parse(const struct nlatt
        struct nlattr *cda[CTA_MAX+1];
        int ret;
  
 -      ret = nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
 +      ret = nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy, NULL);
        if (ret < 0)
                return ret;
  
@@@ -2393,8 -2376,7 +2384,8 @@@ ctnetlink_glue_attach_expect(const stru
        struct nf_conntrack_expect *exp;
        int err;
  
 -      err = nla_parse_nested(cda, CTA_EXPECT_MAX, attr, exp_nla_policy);
 +      err = nla_parse_nested(cda, CTA_EXPECT_MAX, attr, exp_nla_policy,
 +                             NULL);
        if (err < 0)
                return err;
  
@@@ -2585,7 -2567,7 +2576,7 @@@ ctnetlink_exp_fill_info(struct sk_buff 
        struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0;
  
-       event |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -2636,7 -2618,7 +2627,7 @@@ ctnetlink_expect_event(unsigned int eve
        if (skb == NULL)
                goto errout;
  
-       type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
+       type = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_EXP, type);
        nlh = nlmsg_put(skb, item->portid, 0, type, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -2684,8 -2666,8 +2675,8 @@@ ctnetlink_exp_dump_table(struct sk_buf
        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, &nf_ct_expect_hash[cb->args[0]],
 -                                   hnode) {
 +              hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]],
 +                                       hnode) {
                        if (l3proto && exp->tuple.src.l3num != l3proto)
                                continue;
  
@@@ -2736,7 -2718,7 +2727,7 @@@ ctnetlink_exp_ct_dump_table(struct sk_b
        rcu_read_lock();
        last = (struct nf_conntrack_expect *)cb->args[1];
  restart:
 -      hlist_for_each_entry(exp, &help->expectations, lnode) {
 +      hlist_for_each_entry_rcu(exp, &help->expectations, lnode) {
                if (l3proto && exp->tuple.src.l3num != l3proto)
                        continue;
                if (cb->args[1]) {
@@@ -2798,12 -2780,6 +2789,12 @@@ static int ctnetlink_dump_exp_ct(struc
                return -ENOENT;
  
        ct = nf_ct_tuplehash_to_ctrack(h);
 +      /* No expectation linked to this connection tracking. */
 +      if (!nfct_help(ct)) {
 +              nf_ct_put(ct);
 +              return 0;
 +      }
 +
        c.data = ct;
  
        err = netlink_dump_start(ctnl, skb, nlh, &c);
@@@ -3019,8 -2995,7 +3010,8 @@@ ctnetlink_parse_expect_nat(const struc
        struct nf_conntrack_tuple nat_tuple = {};
        int err;
  
 -      err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr, exp_nat_nla_policy);
 +      err = nla_parse_nested(tb, CTA_EXPECT_NAT_MAX, attr,
 +                             exp_nat_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -3054,6 -3029,10 +3045,10 @@@ ctnetlink_alloc_expect(const struct nla
        struct nf_conn_help *help;
        int err;
  
+       help = nfct_help(ct);
+       if (!help)
+               return ERR_PTR(-EOPNOTSUPP);
        if (cda[CTA_EXPECT_CLASS] && helper) {
                class = ntohl(nla_get_be32(cda[CTA_EXPECT_CLASS]));
                if (class > helper->expect_class_max)
        if (!exp)
                return ERR_PTR(-ENOMEM);
  
-       help = nfct_help(ct);
-       if (!help) {
-               if (!cda[CTA_EXPECT_TIMEOUT]) {
-                       err = -EINVAL;
-                       goto err_out;
-               }
-               exp->timeout.expires =
-                 jiffies + ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ;
-               exp->flags = NF_CT_EXPECT_USERSPACE;
-               if (cda[CTA_EXPECT_FLAGS]) {
-                       exp->flags |=
-                               ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
-               }
+       if (cda[CTA_EXPECT_FLAGS]) {
+               exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
+               exp->flags &= ~NF_CT_EXPECT_USERSPACE;
        } else {
-               if (cda[CTA_EXPECT_FLAGS]) {
-                       exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
-                       exp->flags &= ~NF_CT_EXPECT_USERSPACE;
-               } else
-                       exp->flags = 0;
+               exp->flags = 0;
        }
        if (cda[CTA_EXPECT_FN]) {
                const char *name = nla_data(cda[CTA_EXPECT_FN]);
@@@ -3149,27 -3113,23 +3129,27 @@@ ctnetlink_create_expect(struct net *net
                return -ENOENT;
        ct = nf_ct_tuplehash_to_ctrack(h);
  
 +      rcu_read_lock();
        if (cda[CTA_EXPECT_HELP_NAME]) {
                const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]);
  
                helper = __nf_conntrack_helper_find(helpname, u3,
                                                    nf_ct_protonum(ct));
                if (helper == NULL) {
 +                      rcu_read_unlock();
  #ifdef CONFIG_MODULES
                        if (request_module("nfct-helper-%s", helpname) < 0) {
                                err = -EOPNOTSUPP;
                                goto err_ct;
                        }
 +                      rcu_read_lock();
                        helper = __nf_conntrack_helper_find(helpname, u3,
                                                            nf_ct_protonum(ct));
                        if (helper) {
                                err = -EAGAIN;
 -                              goto err_ct;
 +                              goto err_rcu;
                        }
 +                      rcu_read_unlock();
  #endif
                        err = -EOPNOTSUPP;
                        goto err_ct;
        exp = ctnetlink_alloc_expect(cda, ct, helper, &tuple, &mask);
        if (IS_ERR(exp)) {
                err = PTR_ERR(exp);
 -              goto err_ct;
 +              goto err_rcu;
        }
  
        err = nf_ct_expect_related_report(exp, portid, report);
        nf_ct_expect_put(exp);
 +err_rcu:
 +      rcu_read_unlock();
  err_ct:
        nf_ct_put(ct);
        return err;
@@@ -3245,7 -3203,8 +3225,8 @@@ ctnetlink_exp_stat_fill_info(struct sk_
        struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0, event;
  
-       event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_EXP_GET_STATS_CPU);
+       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)
                goto nlmsg_failure;
index b2e02dfe7fa8a0a53e6b7faab84c2a9fc3d459c4,4b3b6e1cadc94f7cf6c31f050e07665ced2fbfbe..b553fdd68816b98a0f6f58cba3bd7363959479cf
@@@ -609,6 -609,20 +609,20 @@@ out_invalid
        return -NF_ACCEPT;
  }
  
+ static bool dccp_can_early_drop(const struct nf_conn *ct)
+ {
+       switch (ct->proto.dccp.state) {
+       case CT_DCCP_CLOSEREQ:
+       case CT_DCCP_CLOSING:
+       case CT_DCCP_TIMEWAIT:
+               return true;
+       default:
+               break;
+       }
+       return false;
+ }
  static void dccp_print_tuple(struct seq_file *s,
                             const struct nf_conntrack_tuple *tuple)
  {
@@@ -665,7 -679,7 +679,7 @@@ static int nlattr_to_dccp(struct nlatt
                return 0;
  
        err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr,
 -                             dccp_nla_policy);
 +                             dccp_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -868,6 -882,7 +882,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .packet                 = dccp_packet,
        .get_timeouts           = dccp_get_timeouts,
        .error                  = dccp_error,
+       .can_early_drop         = dccp_can_early_drop,
        .print_tuple            = dccp_print_tuple,
        .print_conntrack        = dccp_print_conntrack,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@@ -902,6 -917,7 +917,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .packet                 = dccp_packet,
        .get_timeouts           = dccp_get_timeouts,
        .error                  = dccp_error,
+       .can_early_drop         = dccp_can_early_drop,
        .print_tuple            = dccp_print_tuple,
        .print_conntrack        = dccp_print_conntrack,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
index 2a7300587c87ce6c8cf921bba0bb50f929532885,b34b49c59a1cc979ed426a9fb02f49e0c8827d2e..13875d599a85713bbfeb2fee7b8978fa498a10ed
@@@ -535,6 -535,20 +535,20 @@@ out_invalid
        return -NF_ACCEPT;
  }
  
+ static bool sctp_can_early_drop(const struct nf_conn *ct)
+ {
+       switch (ct->proto.sctp.state) {
+       case SCTP_CONNTRACK_SHUTDOWN_SENT:
+       case SCTP_CONNTRACK_SHUTDOWN_RECD:
+       case SCTP_CONNTRACK_SHUTDOWN_ACK_SENT:
+               return true;
+       default:
+               break;
+       }
+       return false;
+ }
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  
  #include <linux/netfilter/nfnetlink.h>
@@@ -584,8 -598,10 +598,8 @@@ static int nlattr_to_sctp(struct nlatt
        if (!attr)
                return 0;
  
 -      err = nla_parse_nested(tb,
 -                             CTA_PROTOINFO_SCTP_MAX,
 -                             attr,
 -                             sctp_nla_policy);
 +      err = nla_parse_nested(tb, CTA_PROTOINFO_SCTP_MAX, attr,
 +                             sctp_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -781,6 -797,7 +795,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .get_timeouts           = sctp_get_timeouts,
        .new                    = sctp_new,
        .error                  = sctp_error,
+       .can_early_drop         = sctp_can_early_drop,
        .me                     = THIS_MODULE,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .to_nlattr              = sctp_to_nlattr,
@@@ -816,6 -833,7 +831,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .get_timeouts           = sctp_get_timeouts,
        .new                    = sctp_new,
        .error                  = sctp_error,
+       .can_early_drop         = sctp_can_early_drop,
        .me                     = THIS_MODULE,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .to_nlattr              = sctp_to_nlattr,
index 85bde77ad9674eb25aa670bcea3d70173e6840ba,d61a68759deaa723ab5ce49f488f0f713cb41bcc..9758a7dfd83ef95c0bcab1257d63cb38d9faed88
@@@ -419,10 -419,9 +419,9 @@@ static void tcp_options(const struct sk
                                 && opsize == TCPOLEN_WINDOW) {
                                state->td_scale = *(u_int8_t *)ptr;
  
-                               if (state->td_scale > 14) {
-                                       /* See RFC1323 */
-                                       state->td_scale = 14;
-                               }
+                               if (state->td_scale > TCP_MAX_WSCALE)
+                                       state->td_scale = TCP_MAX_WSCALE;
                                state->flags |=
                                        IP_CT_TCP_FLAG_WINDOW_SCALE;
                        }
@@@ -1172,6 -1171,22 +1171,22 @@@ static bool tcp_new(struct nf_conn *ct
        return true;
  }
  
+ static bool tcp_can_early_drop(const struct nf_conn *ct)
+ {
+       switch (ct->proto.tcp.state) {
+       case TCP_CONNTRACK_FIN_WAIT:
+       case TCP_CONNTRACK_LAST_ACK:
+       case TCP_CONNTRACK_TIME_WAIT:
+       case TCP_CONNTRACK_CLOSE:
+       case TCP_CONNTRACK_CLOSE_WAIT:
+               return true;
+       default:
+               break;
+       }
+       return false;
+ }
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  
  #include <linux/netfilter/nfnetlink.h>
@@@ -1234,8 -1249,7 +1249,8 @@@ static int nlattr_to_tcp(struct nlattr 
        if (!pattr)
                return 0;
  
 -      err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr, tcp_nla_policy);
 +      err = nla_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, pattr,
 +                             tcp_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -1550,6 -1564,7 +1565,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
+       .can_early_drop         = tcp_can_early_drop,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .to_nlattr              = tcp_to_nlattr,
        .nlattr_size            = tcp_nlattr_size,
@@@ -1587,6 -1602,7 +1603,7 @@@ struct nf_conntrack_l4proto nf_conntrac
        .get_timeouts           = tcp_get_timeouts,
        .new                    = tcp_new,
        .error                  = tcp_error,
+       .can_early_drop         = tcp_can_early_drop,
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
        .to_nlattr              = tcp_to_nlattr,
        .nlattr_size            = tcp_nlattr_size,
index 908ba5abbc0b156821d0eec83ec0b1dc2b6b2798,ec9e6d8101b91120d3efe2509ca17b02ea01c578..b48d6b5aae8a87d4ea69cae0e025739ebe3f1658
@@@ -71,11 -71,10 +71,10 @@@ static void __nf_nat_decode_session(str
        if (ct == NULL)
                return;
  
-       family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;
-       rcu_read_lock();
+       family = nf_ct_l3num(ct);
        l3proto = __nf_nat_l3proto_find(family);
        if (l3proto == NULL)
-               goto out;
+               return;
  
        dir = CTINFO2DIR(ctinfo);
        if (dir == IP_CT_DIR_ORIGINAL)
@@@ -84,8 -83,6 +83,6 @@@
                statusbit = IPS_SRC_NAT;
  
        l3proto->decode_session(skb, ct, dir, statusbit, fl);
- out:
-       rcu_read_unlock();
  }
  
  int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
@@@ -411,12 -408,6 +408,6 @@@ nf_nat_setup_info(struct nf_conn *ct
                  enum nf_nat_manip_type maniptype)
  {
        struct nf_conntrack_tuple curr_tuple, new_tuple;
-       struct nf_conn_nat *nat;
-       /* nat helper or nfctnetlink also setup binding */
-       nat = nf_ct_nat_ext_add(ct);
-       if (nat == NULL)
-               return NF_ACCEPT;
  
        NF_CT_ASSERT(maniptype == NF_NAT_MANIP_SRC ||
                     maniptype == NF_NAT_MANIP_DST);
@@@ -549,10 -540,6 +540,6 @@@ struct nf_nat_proto_clean 
  static int nf_nat_proto_remove(struct nf_conn *i, void *data)
  {
        const struct nf_nat_proto_clean *clean = data;
-       struct nf_conn_nat *nat = nfct_nat(i);
-       if (!nat)
-               return 0;
  
        if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
            (clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
  
  static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
  {
-       struct nf_conn_nat *nat = nfct_nat(ct);
        if (nf_nat_proto_remove(ct, data))
                return 1;
  
-       if (!nat)
+       if ((ct->status & IPS_SRC_NAT_DONE) == 0)
                return 0;
  
        /* This netns is being destroyed, and conntrack has nat null binding.
@@@ -716,13 -701,9 +701,9 @@@ EXPORT_SYMBOL_GPL(nf_nat_l3proto_unregi
  /* No one using conntrack by the time this called. */
  static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
  {
-       struct nf_conn_nat *nat = nf_ct_ext_find(ct, NF_CT_EXT_NAT);
-       if (!nat)
-               return;
-       rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
-                       nf_nat_bysource_params);
+       if (ct->status & IPS_SRC_NAT_DONE)
+               rhltable_remove(&nf_nat_bysource_table, &ct->nat_bysource,
+                               nf_nat_bysource_params);
  }
  
  static struct nf_ct_ext_type nat_extend __read_mostly = {
        .align          = __alignof__(struct nf_conn_nat),
        .destroy        = nf_nat_cleanup_conntrack,
        .id             = NF_CT_EXT_NAT,
-       .flags          = NF_CT_EXT_F_PREALLOC,
  };
  
  #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
@@@ -751,8 -731,7 +731,8 @@@ static int nfnetlink_parse_nat_proto(st
        const struct nf_nat_l4proto *l4proto;
        int err;
  
 -      err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy);
 +      err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr,
 +                             protonat_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -781,7 -760,7 +761,7 @@@ nfnetlink_parse_nat(const struct nlatt
  
        memset(range, 0, sizeof(*range));
  
 -      err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy);
 +      err = nla_parse_nested(tb, CTA_NAT_MAX, nat, nat_nla_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -820,7 -799,7 +800,7 @@@ nfnetlink_parse_nat_setup(struct nf_con
  
        /* No NAT information has been passed, allocate the null-binding */
        if (attr == NULL)
-               return __nf_nat_alloc_null_binding(ct, manip);
+               return __nf_nat_alloc_null_binding(ct, manip) == NF_DROP ? -ENOMEM : 0;
  
        err = nfnetlink_parse_nat(attr, ct, &range, l3proto);
        if (err < 0)
@@@ -875,9 -854,6 +855,6 @@@ static int __init nf_nat_init(void
  
        nf_ct_helper_expectfn_register(&follow_master_nat);
  
-       /* Initialize fake conntrack so that NAT will skip it */
-       nf_ct_untracked_status_or(IPS_NAT_DONE_MASK);
        BUG_ON(nfnetlink_parse_nat_setup_hook != NULL);
        RCU_INIT_POINTER(nfnetlink_parse_nat_setup_hook,
                           nfnetlink_parse_nat_setup);
index 907431318637852692259af4b12294e0f5e02ce7,91e9191a43d83bb5375c8ac69255a538ae841d93..1c6482d2c4dcfe9299a8094a138d446fc0d9e5c8
@@@ -144,7 -144,7 +144,7 @@@ static int nf_tables_register_hooks(str
                                    unsigned int hook_nops)
  {
        if (table->flags & NFT_TABLE_F_DORMANT ||
-           !(chain->flags & NFT_BASE_CHAIN))
+           !nft_is_base_chain(chain))
                return 0;
  
        return nf_register_net_hooks(net, nft_base_chain(chain)->ops,
@@@ -157,7 -157,7 +157,7 @@@ static void nf_tables_unregister_hooks(
                                       unsigned int hook_nops)
  {
        if (table->flags & NFT_TABLE_F_DORMANT ||
-           !(chain->flags & NFT_BASE_CHAIN))
+           !nft_is_base_chain(chain))
                return;
  
        nf_unregister_net_hooks(net, nft_base_chain(chain)->ops, hook_nops);
@@@ -438,7 -438,7 +438,7 @@@ static int nf_tables_fill_table_info(st
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
  
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
@@@ -587,7 -587,7 +587,7 @@@ static void _nf_tables_table_disable(st
        list_for_each_entry(chain, &table->chains, list) {
                if (!nft_is_active_next(net, chain))
                        continue;
-               if (!(chain->flags & NFT_BASE_CHAIN))
+               if (!nft_is_base_chain(chain))
                        continue;
  
                if (cnt && i++ == cnt)
@@@ -608,7 -608,7 +608,7 @@@ static int nf_tables_table_enable(struc
        list_for_each_entry(chain, &table->chains, list) {
                if (!nft_is_active_next(net, chain))
                        continue;
-               if (!(chain->flags & NFT_BASE_CHAIN))
+               if (!nft_is_base_chain(chain))
                        continue;
  
                err = nf_register_net_hooks(net, nft_base_chain(chain)->ops,
@@@ -989,7 -989,7 +989,7 @@@ static int nf_tables_fill_chain_info(st
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
  
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
        if (nla_put_string(skb, NFTA_CHAIN_NAME, chain->name))
                goto nla_put_failure;
  
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                const struct nft_base_chain *basechain = nft_base_chain(chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
                struct nlattr *nest;
@@@ -1182,8 -1182,7 +1182,8 @@@ static struct nft_stats __percpu *nft_s
        struct nft_stats *stats;
        int err;
  
 -      err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy);
 +      err = nla_parse_nested(tb, NFTA_COUNTER_MAX, attr, nft_counter_policy,
 +                             NULL);
        if (err < 0)
                return ERR_PTR(err);
  
@@@ -1227,7 -1226,7 +1227,7 @@@ static void nf_tables_chain_destroy(str
  {
        BUG_ON(chain->use > 0);
  
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                struct nft_base_chain *basechain = nft_base_chain(chain);
  
                module_put(basechain->type->owner);
@@@ -1258,7 -1257,7 +1258,7 @@@ static int nft_chain_parse_hook(struct 
        int err;
  
        err = nla_parse_nested(ha, NFTA_HOOK_MAX, nla[NFTA_CHAIN_HOOK],
 -                             nft_hook_policy);
 +                             nft_hook_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -1365,8 -1364,8 +1365,8 @@@ static int nf_tables_newchain(struct ne
        }
  
        if (nla[NFTA_CHAIN_POLICY]) {
-               if ((chain != NULL &&
-                   !(chain->flags & NFT_BASE_CHAIN)))
+               if (chain != NULL &&
+                   !nft_is_base_chain(chain))
                        return -EOPNOTSUPP;
  
                if (chain == NULL &&
                        struct nft_chain_hook hook;
                        struct nf_hook_ops *ops;
  
-                       if (!(chain->flags & NFT_BASE_CHAIN))
+                       if (!nft_is_base_chain(chain))
                                return -EBUSY;
  
                        err = nft_chain_parse_hook(net, nla, afi, &hook,
                }
  
                if (nla[NFTA_CHAIN_COUNTERS]) {
-                       if (!(chain->flags & NFT_BASE_CHAIN))
+                       if (!nft_is_base_chain(chain))
                                return -EOPNOTSUPP;
  
                        stats = nft_stats_alloc(nla[NFTA_CHAIN_COUNTERS]);
@@@ -1725,7 -1724,7 +1725,7 @@@ static int nf_tables_expr_parse(const s
        struct nlattr *tb[NFTA_EXPR_MAX + 1];
        int err;
  
 -      err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy);
 +      err = nla_parse_nested(tb, NFTA_EXPR_MAX, nla, nft_expr_policy, NULL);
        if (err < 0)
                return err;
  
  
        if (tb[NFTA_EXPR_DATA]) {
                err = nla_parse_nested(info->tb, type->maxattr,
 -                                     tb[NFTA_EXPR_DATA], type->policy);
 +                                     tb[NFTA_EXPR_DATA], type->policy, NULL);
                if (err < 0)
                        goto err1;
        } else
@@@ -1886,10 -1885,9 +1886,9 @@@ static int nf_tables_fill_rule_info(str
        const struct nft_expr *expr, *next;
        struct nlattr *list;
        const struct nft_rule *prule;
-       int type = event | NFNL_SUBSYS_NFTABLES << 8;
+       u16 type = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
  
-       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg),
-                       flags);
+       nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
  
                goto nla_put_failure;
  
        if ((event != NFT_MSG_DELRULE) && (rule->list.prev != &chain->rules)) {
-               prule = list_entry(rule->list.prev, struct nft_rule, list);
+               prule = list_prev_entry(rule, list);
                if (nla_put_be64(skb, NFTA_RULE_POSITION,
                                 cpu_to_be64(prule->handle),
                                 NFTA_RULE_PAD))
@@@ -2646,7 -2644,7 +2645,7 @@@ static int nf_tables_fill_set(struct sk
        u32 portid = ctx->portid;
        u32 seq = ctx->seq;
  
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
                        flags);
        if (nlh == NULL)
@@@ -2880,8 -2878,7 +2879,8 @@@ static int nf_tables_set_desc_parse(con
        struct nlattr *da[NFTA_SET_DESC_MAX + 1];
        int err;
  
 -      err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla, nft_set_desc_policy);
 +      err = nla_parse_nested(da, NFTA_SET_DESC_MAX, nla,
 +                             nft_set_desc_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -3383,8 -3380,7 +3382,8 @@@ static int nf_tables_dump_set(struct sk
        int event, err;
  
        err = nlmsg_parse(cb->nlh, sizeof(struct nfgenmsg), nla,
 -                        NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy);
 +                        NFTA_SET_ELEM_LIST_MAX, nft_set_elem_list_policy,
 +                        NULL);
        if (err < 0)
                return err;
  
        if (IS_ERR(set))
                return PTR_ERR(set);
  
-       event  = NFT_MSG_NEWSETELEM;
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event  = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWSETELEM);
        portid = NETLINK_CB(cb->skb).portid;
        seq    = cb->nlh->nlmsg_seq;
  
@@@ -3484,7 -3479,7 +3482,7 @@@ static int nf_tables_fill_setelem_info(
        struct nlattr *nest;
        int err;
  
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
                        flags);
        if (nlh == NULL)
@@@ -3643,7 -3638,7 +3641,7 @@@ static int nft_add_set_elem(struct nft_
        int err;
  
        err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
 -                             nft_set_elem_policy);
 +                             nft_set_elem_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -3873,7 -3868,7 +3871,7 @@@ static int nft_del_setelem(struct nft_c
        int err;
  
        err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
 -                             nft_set_elem_policy);
 +                             nft_set_elem_policy, NULL);
        if (err < 0)
                goto err1;
  
@@@ -4104,8 -4099,7 +4102,8 @@@ static struct nft_object *nft_obj_init(
        int err;
  
        if (attr) {
 -              err = nla_parse_nested(tb, type->maxattr, attr, type->policy);
 +              err = nla_parse_nested(tb, type->maxattr, attr, type->policy,
 +                                     NULL);
                if (err < 0)
                        goto err1;
        } else {
@@@ -4257,7 -4251,7 +4255,7 @@@ static int nf_tables_fill_obj_info(stru
        struct nfgenmsg *nfmsg;
        struct nlmsghdr *nlh;
  
-       event |= NFNL_SUBSYS_NFTABLES << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), flags);
        if (nlh == NULL)
                goto nla_put_failure;
@@@ -4439,8 -4433,6 +4437,6 @@@ static int nf_tables_getobj(struct net 
  err:
        kfree_skb(skb2);
        return err;
-       return 0;
  }
  
  static void nft_obj_destroy(struct nft_object *obj)
@@@ -4530,7 -4522,7 +4526,7 @@@ static int nf_tables_fill_gen_info(stru
  {
        struct nlmsghdr *nlh;
        struct nfgenmsg *nfmsg;
-       int event = (NFNL_SUBSYS_NFTABLES << 8) | NFT_MSG_NEWGEN;
+       int event = nfnl_msg_type(NFNL_SUBSYS_NFTABLES, NFT_MSG_NEWGEN);
  
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg), 0);
        if (nlh == NULL)
@@@ -4712,7 -4704,7 +4708,7 @@@ static void nft_chain_commit_update(str
        if (nft_trans_chain_name(trans)[0])
                strcpy(trans->ctx.chain->name, nft_trans_chain_name(trans));
  
-       if (!(trans->ctx.chain->flags & NFT_BASE_CHAIN))
+       if (!nft_is_base_chain(trans->ctx.chain))
                return;
  
        basechain = nft_base_chain(trans->ctx.chain);
@@@ -5026,7 -5018,7 +5022,7 @@@ int nft_chain_validate_dependency(cons
  {
        const struct nft_base_chain *basechain;
  
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                basechain = nft_base_chain(chain);
                if (basechain->type->type != type)
                        return -EOPNOTSUPP;
@@@ -5040,7 -5032,7 +5036,7 @@@ int nft_chain_validate_hooks(const stru
  {
        struct nft_base_chain *basechain;
  
-       if (chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(chain)) {
                basechain = nft_base_chain(chain);
  
                if ((1 << basechain->ops[0].hooknum) & hook_flags)
@@@ -5318,8 -5310,7 +5314,8 @@@ static int nft_verdict_init(const struc
        struct nft_chain *chain;
        int err;
  
 -      err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy);
 +      err = nla_parse_nested(tb, NFTA_VERDICT_MAX, nla, nft_verdict_policy,
 +                             NULL);
        if (err < 0)
                return err;
  
                                               tb[NFTA_VERDICT_CHAIN], genmask);
                if (IS_ERR(chain))
                        return PTR_ERR(chain);
-               if (chain->flags & NFT_BASE_CHAIN)
+               if (nft_is_base_chain(chain))
                        return -EOPNOTSUPP;
  
                chain->use++;
@@@ -5449,7 -5440,7 +5445,7 @@@ int nft_data_init(const struct nft_ctx 
        struct nlattr *tb[NFTA_DATA_MAX + 1];
        int err;
  
 -      err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy);
 +      err = nla_parse_nested(tb, NFTA_DATA_MAX, nla, nft_data_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -5523,7 -5514,7 +5519,7 @@@ int __nft_release_basechain(struct nft_
  {
        struct nft_rule *rule, *nr;
  
-       BUG_ON(!(ctx->chain->flags & NFT_BASE_CHAIN));
+       BUG_ON(!nft_is_base_chain(ctx->chain));
  
        nf_tables_unregister_hooks(ctx->net, ctx->chain->table, ctx->chain,
                                   ctx->afi->nops);
index e42f858b91d2479b4df46e0fea10a384787af77f,185f9786a5a4c51ffa1eaa65ea35ff86336735c1..80f5ecf2c3d7096f579361663da5d2e651eebd3e
@@@ -148,8 -148,7 +148,8 @@@ int nfnetlink_unicast(struct sk_buff *s
  EXPORT_SYMBOL_GPL(nfnetlink_unicast);
  
  /* Process one complete nfnetlink message. */
 -static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 +static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
 +                           struct netlink_ext_ack *extack)
  {
        struct net *net = sock_net(skb->sk);
        const struct nfnl_callback *nc;
@@@ -192,8 -191,8 +192,8 @@@ replay
                int attrlen = nlh->nlmsg_len - min_len;
                __u8 subsys_id = NFNL_SUBSYS_ID(type);
  
 -              err = nla_parse(cda, ss->cb[cb_id].attr_count,
 -                              attr, attrlen, ss->cb[cb_id].policy);
 +              err = nla_parse(cda, ss->cb[cb_id].attr_count, attr, attrlen,
 +                              ss->cb[cb_id].policy, extack);
                if (err < 0) {
                        rcu_read_unlock();
                        return err;
@@@ -262,7 -261,7 +262,7 @@@ static void nfnl_err_deliver(struct lis
        struct nfnl_err *nfnl_err, *next;
  
        list_for_each_entry_safe(nfnl_err, next, err_list, head) {
 -              netlink_ack(skb, nfnl_err->nlh, nfnl_err->err);
 +              netlink_ack(skb, nfnl_err->nlh, nfnl_err->err, NULL);
                nfnl_err_del(nfnl_err);
        }
  }
@@@ -285,13 -284,13 +285,13 @@@ static void nfnetlink_rcv_batch(struct 
        int err;
  
        if (subsys_id >= NFNL_SUBSYS_COUNT)
 -              return netlink_ack(skb, nlh, -EINVAL);
 +              return netlink_ack(skb, nlh, -EINVAL, NULL);
  replay:
        status = 0;
  
        skb = netlink_skb_clone(oskb, GFP_KERNEL);
        if (!skb)
 -              return netlink_ack(oskb, nlh, -ENOMEM);
 +              return netlink_ack(oskb, nlh, -ENOMEM, NULL);
  
        nfnl_lock(subsys_id);
        ss = nfnl_dereference_protected(subsys_id);
  #endif
                {
                        nfnl_unlock(subsys_id);
 -                      netlink_ack(oskb, nlh, -EOPNOTSUPP);
 +                      netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
                        return kfree_skb(skb);
                }
        }
  
        if (!ss->commit || !ss->abort) {
                nfnl_unlock(subsys_id);
 -              netlink_ack(oskb, nlh, -EOPNOTSUPP);
 +              netlink_ack(oskb, nlh, -EOPNOTSUPP, NULL);
                return kfree_skb(skb);
        }
  
        if (genid && ss->valid_genid && !ss->valid_genid(net, genid)) {
                nfnl_unlock(subsys_id);
 -              netlink_ack(oskb, nlh, -ERESTART);
 +              netlink_ack(oskb, nlh, -ERESTART, NULL);
                return kfree_skb(skb);
        }
  
                        struct nlattr *attr = (void *)nlh + min_len;
                        int attrlen = nlh->nlmsg_len - min_len;
  
 -                      err = nla_parse(cda, ss->cb[cb_id].attr_count,
 -                                      attr, attrlen, ss->cb[cb_id].policy);
 +                      err = nla_parse(cda, ss->cb[cb_id].attr_count, attr,
 +                                      attrlen, ss->cb[cb_id].policy, NULL);
                        if (err < 0)
                                goto ack;
  
@@@ -408,8 -407,7 +408,8 @@@ ack
                                 * pointing to the batch header.
                                 */
                                nfnl_err_reset(&err_list);
 -                              netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM);
 +                              netlink_ack(oskb, nlmsg_hdr(oskb), -ENOMEM,
 +                                          NULL);
                                status |= NFNL_BATCH_FAILURE;
                                goto done;
                        }
@@@ -467,10 -465,9 +467,10 @@@ static void nfnetlink_rcv_skb_batch(str
            skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
                return;
  
 -      err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy);
 +      err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy,
 +                      NULL);
        if (err < 0) {
 -              netlink_ack(skb, nlh, err);
 +              netlink_ack(skb, nlh, err, NULL);
                return;
        }
        if (cda[NFNL_BATCH_GENID])
@@@ -496,14 -493,14 +496,14 @@@ static void nfnetlink_rcv(struct sk_buf
                return;
  
        if (!netlink_net_capable(skb, CAP_NET_ADMIN)) {
 -              netlink_ack(skb, nlh, -EPERM);
 +              netlink_ack(skb, nlh, -EPERM, NULL);
                return;
        }
  
        if (nlh->nlmsg_type == NFNL_MSG_BATCH_BEGIN)
                nfnetlink_rcv_skb_batch(skb, nlh);
        else
-               netlink_rcv_skb(skb, &nfnetlink_rcv_msg);
+               netlink_rcv_skb(skb, nfnetlink_rcv_msg);
  }
  
  #ifdef CONFIG_MODULES
index 2837d5fb98bd17d283bc64a0e657ee95bb0281dd,1b9a5d6099dcb1ad9dbc31a62bec2b82ffb74fef..9898fb4d0512ce80d0bf970340e5da43db25ce15
@@@ -139,7 -139,7 +139,7 @@@ nfnl_acct_fill_info(struct sk_buff *skb
        u64 pkts, bytes;
        u32 old_flags;
  
-       event |= NFNL_SUBSYS_ACCT << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_ACCT, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -244,8 -244,7 +244,8 @@@ nfacct_filter_alloc(const struct nlatt
        struct nlattr *tb[NFACCT_FILTER_MAX + 1];
        int err;
  
 -      err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy);
 +      err = nla_parse_nested(tb, NFACCT_FILTER_MAX, attr, filter_policy,
 +                             NULL);
        if (err < 0)
                return ERR_PTR(err);
  
index 5b6c683115668e3a8f1abc88af3210bdc393fccb,eef7120e1f741ae773a24d4ddd4ee0470f9fb4ac..950bf6eadc6578516ac92b50427fe682cba3976d
@@@ -77,8 -77,7 +77,8 @@@ nfnl_cthelper_parse_tuple(struct nf_con
        int err;
        struct nlattr *tb[NFCTH_TUPLE_MAX+1];
  
 -      err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr, nfnl_cthelper_tuple_pol);
 +      err = nla_parse_nested(tb, NFCTH_TUPLE_MAX, attr,
 +                             nfnl_cthelper_tuple_pol, NULL);
        if (err < 0)
                return err;
  
@@@ -105,7 -104,7 +105,7 @@@ nfnl_cthelper_from_nlattr(struct nlatt
        if (help->helper->data_len == 0)
                return -EINVAL;
  
-       memcpy(help->data, nla_data(attr), help->helper->data_len);
+       nla_memcpy(help->data, nla_data(attr), sizeof(help->data));
        return 0;
  }
  
@@@ -138,8 -137,7 +138,8 @@@ nfnl_cthelper_expect_policy(struct nf_c
        int err;
        struct nlattr *tb[NFCTH_POLICY_MAX+1];
  
 -      err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr, nfnl_cthelper_expect_pol);
 +      err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr,
 +                             nfnl_cthelper_expect_pol, NULL);
        if (err < 0)
                return err;
  
                nla_data(tb[NFCTH_POLICY_NAME]), NF_CT_HELPER_NAME_LEN);
        expect_policy->max_expected =
                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
+       if (expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
+               return -EINVAL;
        expect_policy->timeout =
                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
  
@@@ -173,7 -174,7 +176,7 @@@ nfnl_cthelper_parse_expect_policy(struc
        unsigned int class_max;
  
        ret = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
 -                             nfnl_cthelper_expect_policy_set);
 +                             nfnl_cthelper_expect_policy_set, NULL);
        if (ret < 0)
                return ret;
  
@@@ -215,6 -216,7 +218,7 @@@ nfnl_cthelper_create(const struct nlatt
  {
        struct nf_conntrack_helper *helper;
        struct nfnl_cthelper *nfcth;
+       unsigned int size;
        int ret;
  
        if (!tb[NFCTH_TUPLE] || !tb[NFCTH_POLICY] || !tb[NFCTH_PRIV_DATA_LEN])
                goto err1;
  
        strncpy(helper->name, nla_data(tb[NFCTH_NAME]), NF_CT_HELPER_NAME_LEN);
-       helper->data_len = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
+       size = ntohl(nla_get_be32(tb[NFCTH_PRIV_DATA_LEN]));
+       if (size > FIELD_SIZEOF(struct nf_conn_help, data)) {
+               ret = -ENOMEM;
+               goto err2;
+       }
        helper->flags |= NF_CT_HELPER_F_USERSPACE;
        memcpy(&helper->tuple, tuple, sizeof(struct nf_conntrack_tuple));
  
@@@ -278,7 -285,7 +287,7 @@@ nfnl_cthelper_update_policy_one(const s
        int err;
  
        err = nla_parse_nested(tb, NFCTH_POLICY_MAX, attr,
 -                             nfnl_cthelper_expect_pol);
 +                             nfnl_cthelper_expect_pol, NULL);
        if (err < 0)
                return err;
  
  
        new_policy->max_expected =
                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_MAX]));
+       if (new_policy->max_expected > NF_CT_EXPECT_MAX_CNT)
+               return -EINVAL;
        new_policy->timeout =
                ntohl(nla_get_be32(tb[NFCTH_POLICY_EXPECT_TIMEOUT]));
  
@@@ -338,7 -348,7 +350,7 @@@ static int nfnl_cthelper_update_policy(
        int err;
  
        err = nla_parse_nested(tb, NFCTH_POLICY_SET_MAX, attr,
 -                             nfnl_cthelper_expect_policy_set);
 +                             nfnl_cthelper_expect_policy_set, NULL);
        if (err < 0)
                return err;
  
@@@ -503,7 -513,7 +515,7 @@@ nfnl_cthelper_fill_info(struct sk_buff 
        unsigned int flags = portid ? NLM_F_MULTI : 0;
        int status;
  
-       event |= NFNL_SUBSYS_CTHELPER << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTHELPER, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
index 0a3510e7e3960f01844b071733453301ef5fdf26,0927a6ae61774771b5256d14d500096f2c1a01ad..a3e7bb54d96acf2e7ac570077d57502d5b23625b
@@@ -56,8 -56,7 +56,8 @@@ ctnl_timeout_parse_policy(void *timeout
                struct nlattr *tb[l4proto->ctnl_timeout.nlattr_max+1];
  
                ret = nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max,
 -                                     attr, l4proto->ctnl_timeout.nla_policy);
 +                                     attr, l4proto->ctnl_timeout.nla_policy,
 +                                     NULL);
                if (ret < 0)
                        return ret;
  
@@@ -159,7 -158,7 +159,7 @@@ ctnl_timeout_fill_info(struct sk_buff *
        unsigned int flags = portid ? NLM_F_MULTI : 0;
        struct nf_conntrack_l4proto *l4proto = timeout->l4proto;
  
-       event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
@@@ -432,7 -431,7 +432,7 @@@ cttimeout_default_fill_info(struct net 
        struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0;
  
-       event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_CTNETLINK_TIMEOUT, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
index 3be6fef30581593c9dde59030ac33af6249abcba,dd8ec5b0fcd9a6e5cf1695430601693b8ef5a947..8a0f218b79380bb66176b54a7bcd54e43e909a0a
@@@ -447,7 -447,7 +447,7 @@@ nfqnl_build_packet_message(struct net *
        }
  
        nlh = nlmsg_put(skb, 0, 0,
-                       NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET,
+                       nfnl_msg_type(NFNL_SUBSYS_QUEUE, NFQNL_MSG_PACKET),
                        sizeof(struct nfgenmsg), 0);
        if (!nlh) {
                skb_tx_error(entskb);
@@@ -922,16 -922,10 +922,10 @@@ static struct notifier_block nfqnl_dev_
        .notifier_call  = nfqnl_rcv_dev_event,
  };
  
- static int nf_hook_cmp(struct nf_queue_entry *entry, unsigned long entry_ptr)
- {
-       return rcu_access_pointer(entry->hook) ==
-               (struct nf_hook_entry *)entry_ptr;
- }
- static void nfqnl_nf_hook_drop(struct net *net,
-                              const struct nf_hook_entry *hook)
+ static unsigned int nfqnl_nf_hook_drop(struct net *net)
  {
        struct nfnl_queue_net *q = nfnl_queue_pernet(net);
+       unsigned int instances = 0;
        int i;
  
        rcu_read_lock();
                struct nfqnl_instance *inst;
                struct hlist_head *head = &q->instance_table[i];
  
-               hlist_for_each_entry_rcu(inst, head, hlist)
-                       nfqnl_flush(inst, nf_hook_cmp, (unsigned long)hook);
+               hlist_for_each_entry_rcu(inst, head, hlist) {
+                       nfqnl_flush(inst, NULL, 0);
+                       instances++;
+               }
        }
        rcu_read_unlock();
+       return instances;
  }
  
  static int
@@@ -1109,7 -1107,7 +1107,7 @@@ static int nfqa_parse_bridge(struct nf_
                int err;
  
                err = nla_parse_nested(tb, NFQA_VLAN_MAX, nfqa[NFQA_VLAN],
 -                                     nfqa_vlan_policy);
 +                                     nfqa_vlan_policy, NULL);
                if (err < 0)
                        return err;
  
@@@ -1213,8 -1211,8 +1211,8 @@@ static const struct nla_policy nfqa_cfg
  };
  
  static const struct nf_queue_handler nfqh = {
-       .outfn          = &nfqnl_enqueue_packet,
-       .nf_hook_drop   = &nfqnl_nf_hook_drop,
+       .outfn          = nfqnl_enqueue_packet,
+       .nf_hook_drop   = nfqnl_nf_hook_drop,
  };
  
  static int nfqnl_recv_config(struct net *net, struct sock *ctnl,
index d76d0f36799f60d5ccb40449b029be2c87652b6e,ed969caf01bea8f499a6533f393ec34f2a00eeea..f753ec69f7902b80c9f448f764ecc1e48f6a2680
@@@ -42,7 -42,8 +42,8 @@@ static int nft_compat_chain_validate_de
  {
        const struct nft_base_chain *basechain;
  
-       if (!tablename || !(chain->flags & NFT_BASE_CHAIN))
+       if (!tablename ||
+           !nft_is_base_chain(chain))
                return 0;
  
        basechain = nft_base_chain(chain);
@@@ -165,7 -166,7 +166,7 @@@ nft_target_set_tgchk_param(struct xt_tg
        par->entryinfo  = entry;
        par->target     = target;
        par->targinfo   = info;
-       if (ctx->chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
@@@ -200,7 -201,7 +201,7 @@@ static int nft_parse_compat(const struc
        int err;
  
        err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr,
 -                             nft_rule_compat_policy);
 +                             nft_rule_compat_policy, NULL);
        if (err < 0)
                return err;
  
@@@ -298,7 -299,7 +299,7 @@@ static int nft_target_validate(const st
        unsigned int hook_mask = 0;
        int ret;
  
-       if (ctx->chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
@@@ -379,7 -380,7 +380,7 @@@ nft_match_set_mtchk_param(struct xt_mtc
        par->entryinfo  = entry;
        par->match      = match;
        par->matchinfo  = info;
-       if (ctx->chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
@@@ -477,7 -478,7 +478,7 @@@ static int nft_match_validate(const str
        unsigned int hook_mask = 0;
        int ret;
  
-       if (ctx->chain->flags & NFT_BASE_CHAIN) {
+       if (nft_is_base_chain(ctx->chain)) {
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops[0];
@@@ -503,7 -504,7 +504,7 @@@ nfnl_compat_fill_info(struct sk_buff *s
        struct nfgenmsg *nfmsg;
        unsigned int flags = portid ? NLM_F_MULTI : 0;
  
-       event |= NFNL_SUBSYS_NFT_COMPAT << 8;
+       event = nfnl_msg_type(NFNL_SUBSYS_NFT_COMPAT, event);
        nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
        if (nlh == NULL)
                goto nlmsg_failure;
diff --combined net/netfilter/nft_hash.c
index 52a5079a91a36fa056cf54463b6e8bc78111c850,4cfe524d87292b3bd9fc75f80c7655290957a70d..24f2f7567ddb779af44ee5050df36292f413d4d6
@@@ -21,7 -21,6 +21,7 @@@ struct nft_jhash 
        enum nft_registers      sreg:8;
        enum nft_registers      dreg:8;
        u8                      len;
 +      bool                    autogen_seed:1;
        u32                     modulus;
        u32                     seed;
        u32                     offset;
@@@ -103,12 -102,10 +103,12 @@@ static int nft_jhash_init(const struct 
        if (priv->offset + priv->modulus - 1 < priv->offset)
                return -EOVERFLOW;
  
 -      if (tb[NFTA_HASH_SEED])
 +      if (tb[NFTA_HASH_SEED]) {
                priv->seed = ntohl(nla_get_be32(tb[NFTA_HASH_SEED]));
 -      else
 +      } else {
 +              priv->autogen_seed = true;
                get_random_bytes(&priv->seed, sizeof(priv->seed));
 +      }
  
        return nft_validate_register_load(priv->sreg, len) &&
               nft_validate_register_store(ctx, priv->dreg, NULL,
@@@ -154,8 -151,7 +154,8 @@@ static int nft_jhash_dump(struct sk_buf
                goto nla_put_failure;
        if (nla_put_be32(skb, NFTA_HASH_MODULUS, htonl(priv->modulus)))
                goto nla_put_failure;
 -      if (nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
 +      if (!priv->autogen_seed &&
 +          nla_put_be32(skb, NFTA_HASH_SEED, htonl(priv->seed)))
                goto nla_put_failure;
        if (priv->offset != 0)
                if (nla_put_be32(skb, NFTA_HASH_OFFSET, htonl(priv->offset)))
@@@ -228,7 -224,7 +228,7 @@@ nft_hash_select_ops(const struct nft_ct
  
  static struct nft_expr_type nft_hash_type __read_mostly = {
        .name           = "hash",
-       .select_ops     = &nft_hash_select_ops,
+       .select_ops     = nft_hash_select_ops,
        .policy         = nft_hash_policy,
        .maxattr        = NFTA_HASH_MAX,
        .owner          = THIS_MODULE,
index 4f7c3b5c080b40f4ef822215620e85dd3db42647,57c68664d09cdcafb9fe003c8e5151d1f7a9e955..42a95919df094ba0f21cf4e4c1ade6c570f10284
@@@ -66,9 -66,7 +66,9 @@@ struct ovs_conntrack_info 
        u8 commit : 1;
        u8 nat : 3;                 /* enum ovs_ct_nat */
        u8 force : 1;
 +      u8 have_eventmask : 1;
        u16 family;
 +      u32 eventmask;              /* Mask of 1 << IPCT_*. */
        struct md_mark mark;
        struct md_labels labels;
  #ifdef CONFIG_NF_NAT_NEEDED
@@@ -375,7 -373,7 +375,7 @@@ static int ovs_ct_init_labels(struct nf
        }
  
        /* Labels are included in the IPCTNL_MSG_CT_NEW event only if the
 -       * IPCT_LABEL bit it set in the event cache.
 +       * IPCT_LABEL bit is set in the event cache.
         */
        nf_conntrack_event_cache(IPCT_LABEL, ct);
  
@@@ -797,11 -795,6 +797,6 @@@ static int ovs_ct_nat(struct net *net, 
        enum nf_nat_manip_type maniptype;
        int err;
  
-       if (nf_ct_is_untracked(ct)) {
-               /* A NAT action may only be performed on tracked packets. */
-               return NF_ACCEPT;
-       }
        /* Add NAT extension if not confirmed yet. */
        if (!nf_ct_is_confirmed(ct) && !nf_ct_nat_ext_add(ct))
                return NF_ACCEPT;   /* Can't NAT. */
@@@ -1009,20 -1002,6 +1004,20 @@@ static int ovs_ct_commit(struct net *ne
        if (!ct)
                return 0;
  
 +      /* Set the conntrack event mask if given.  NEW and DELETE events have
 +       * their own groups, but the NFNLGRP_CONNTRACK_UPDATE group listener
 +       * typically would receive many kinds of updates.  Setting the event
 +       * mask allows those events to be filtered.  The set event mask will
 +       * remain in effect for the lifetime of the connection unless changed
 +       * by a further CT action with both the commit flag and the eventmask
 +       * option. */
 +      if (info->have_eventmask) {
 +              struct nf_conntrack_ecache *cache = nf_ct_ecache_find(ct);
 +
 +              if (cache)
 +                      cache->ctmask = info->eventmask;
 +      }
 +
        /* Apply changes before confirming the connection so that the initial
         * conntrack NEW netlink event carries the values given in the CT
         * action.
@@@ -1254,8 -1233,6 +1249,8 @@@ static const struct ovs_ct_len_tbl ovs_
        /* NAT length is checked when parsing the nested attributes. */
        [OVS_CT_ATTR_NAT]       = { .minlen = 0, .maxlen = INT_MAX },
  #endif
 +      [OVS_CT_ATTR_EVENTMASK] = { .minlen = sizeof(u32),
 +                                  .maxlen = sizeof(u32) },
  };
  
  static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info,
                        break;
                }
  #endif
 +              case OVS_CT_ATTR_EVENTMASK:
 +                      info->have_eventmask = true;
 +                      info->eventmask = nla_get_u32(a);
 +                      break;
 +
                default:
                        OVS_NLERR(log, "Unknown conntrack attr (%d)",
                                  type);
@@@ -1538,10 -1510,6 +1533,10 @@@ int ovs_ct_action_to_attr(const struct 
                                   ct_info->helper->name))
                        return -EMSGSIZE;
        }
 +      if (ct_info->have_eventmask &&
 +          nla_put_u32(skb, OVS_CT_ATTR_EVENTMASK, ct_info->eventmask))
 +              return -EMSGSIZE;
 +
  #ifdef CONFIG_NF_NAT_NEEDED
        if (ct_info->nat && !ovs_ct_nat_to_attr(ct_info, skb))
                return -EMSGSIZE;