*
  * (C) 2001 by Jay Schulist <jschlst@samba.org>,
  * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org>
- * (C) 2005,2007 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2005-2017 by Pablo Neira Ayuso <pablo@netfilter.org>
  *
  * Initial netfilter messages via netlink development funded and
  * generally made possible by Network Robots, Inc. (www.networkrobots.com)
 };
 
 static void nfnetlink_rcv_batch(struct sk_buff *skb, struct nlmsghdr *nlh,
-                               u16 subsys_id)
+                               u16 subsys_id, u32 genid)
 {
        struct sk_buff *oskb = skb;
        struct net *net = sock_net(skb->sk);
                return kfree_skb(skb);
        }
 
+       if (genid && ss->valid_genid && !ss->valid_genid(net, genid)) {
+               nfnl_unlock(subsys_id);
+               netlink_ack(oskb, nlh, -ERESTART);
+               return kfree_skb(skb);
+       }
+
        while (skb->len >= nlmsg_total_size(0)) {
                int msglen, type;
 
        kfree_skb(skb);
 }
 
+static const struct nla_policy nfnl_batch_policy[NFNL_BATCH_MAX + 1] = {
+       [NFNL_BATCH_GENID]      = { .type = NLA_U32 },
+};
+
 static void nfnetlink_rcv_skb_batch(struct sk_buff *skb, struct nlmsghdr *nlh)
 {
+       int min_len = nlmsg_total_size(sizeof(struct nfgenmsg));
+       struct nlattr *attr = (void *)nlh + min_len;
+       struct nlattr *cda[NFNL_BATCH_MAX + 1];
+       int attrlen = nlh->nlmsg_len - min_len;
        struct nfgenmsg *nfgenmsg;
+       int msglen, err;
+       u32 gen_id = 0;
        u16 res_id;
-       int msglen;
 
        msglen = NLMSG_ALIGN(nlh->nlmsg_len);
        if (msglen > skb->len)
            skb->len < NLMSG_HDRLEN + sizeof(struct nfgenmsg))
                return;
 
+       err = nla_parse(cda, NFNL_BATCH_MAX, attr, attrlen, nfnl_batch_policy);
+       if (err < 0) {
+               netlink_ack(skb, nlh, err);
+               return;
+       }
+       if (cda[NFNL_BATCH_GENID])
+               gen_id = ntohl(nla_get_be32(cda[NFNL_BATCH_GENID]));
+
        nfgenmsg = nlmsg_data(nlh);
        skb_pull(skb, msglen);
        /* Work around old nft using host byte order */
        else
                res_id = ntohs(nfgenmsg->res_id);
 
-       nfnetlink_rcv_batch(skb, nlh, res_id);
+       nfnetlink_rcv_batch(skb, nlh, res_id, gen_id);
 }
 
 static void nfnetlink_rcv(struct sk_buff *skb)