Hook into new devices if their name matches the hook spec. Signed-off-by: Phil Sutter <phil@xxxxxx> --- net/netfilter/nft_chain_filter.c | 40 +++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/net/netfilter/nft_chain_filter.c b/net/netfilter/nft_chain_filter.c index 2507e3beac5c..ec44c27a9d91 100644 --- a/net/netfilter/nft_chain_filter.c +++ b/net/netfilter/nft_chain_filter.c @@ -326,14 +326,37 @@ static void nft_netdev_event(unsigned long event, struct net_device *dev, struct nft_hook *hook; list_for_each_entry(hook, &basechain->hook_list, list) { - ops = nft_hook_find_ops(hook, dev); - if (!ops) - continue; + switch (event) { + case NETDEV_UNREGISTER: + ops = nft_hook_find_ops(hook, dev); + if (!ops) + continue; - if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT)) - nf_unregister_net_hook(ctx->net, ops); - list_del(&ops->list); - kfree(ops); + if (!(ctx->chain->table->flags & NFT_TABLE_F_DORMANT)) + nf_unregister_net_hook(ctx->net, ops); + list_del(&ops->list); + kfree(ops); + break; + case NETDEV_REGISTER: + if (strcmp(hook->ifname, dev->name)) + continue; + ops = kzalloc(sizeof(struct nf_hook_ops), + GFP_KERNEL_ACCOUNT); + if (ops) { + memcpy(ops, &basechain->ops, sizeof(*ops)); + ops->dev = dev; + } + if (ops && + (ctx->chain->table->flags & NFT_TABLE_F_DORMANT || + !nf_register_net_hook(dev_net(dev), ops))) { + list_add_tail(&ops->list, &hook->ops_list); + break; + } + printk(KERN_ERR "chain %s: Can't hook into device %s\n", + ctx->chain->name, dev->name); + kfree(ops); + continue; + } } } @@ -349,7 +372,8 @@ static int nf_tables_netdev_event(struct notifier_block *this, .net = dev_net(dev), }; - if (event != NETDEV_UNREGISTER) + if (event != NETDEV_REGISTER && + event != NETDEV_UNREGISTER) return NOTIFY_DONE; nft_net = nft_pernet(ctx.net); -- 2.43.0