]> Git Repo - linux.git/blob - net/netfilter/nf_tables_netdev.c
drm: omapdrm: sdi: Allocate the sdi private data structure dynamically
[linux.git] / net / netfilter / nf_tables_netdev.c
1 /*
2  * Copyright (c) 2015 Pablo Neira Ayuso <[email protected]>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/netdevice.h>
12 #include <net/netfilter/nf_tables.h>
13 #include <linux/ip.h>
14 #include <linux/ipv6.h>
15 #include <net/netfilter/nf_tables_ipv4.h>
16 #include <net/netfilter/nf_tables_ipv6.h>
17
18 static unsigned int
19 nft_do_chain_netdev(void *priv, struct sk_buff *skb,
20                     const struct nf_hook_state *state)
21 {
22         struct nft_pktinfo pkt;
23
24         nft_set_pktinfo(&pkt, skb, state);
25
26         switch (skb->protocol) {
27         case htons(ETH_P_IP):
28                 nft_set_pktinfo_ipv4_validate(&pkt, skb);
29                 break;
30         case htons(ETH_P_IPV6):
31                 nft_set_pktinfo_ipv6_validate(&pkt, skb);
32                 break;
33         default:
34                 nft_set_pktinfo_unspec(&pkt, skb);
35                 break;
36         }
37
38         return nft_do_chain(&pkt, priv);
39 }
40
41 static const struct nf_chain_type nft_filter_chain_netdev = {
42         .name           = "filter",
43         .type           = NFT_CHAIN_T_DEFAULT,
44         .family         = NFPROTO_NETDEV,
45         .owner          = THIS_MODULE,
46         .hook_mask      = (1 << NF_NETDEV_INGRESS),
47         .hooks          = {
48                 [NF_NETDEV_INGRESS]     = nft_do_chain_netdev,
49         },
50 };
51
52 static void nft_netdev_event(unsigned long event, struct net_device *dev,
53                              struct nft_ctx *ctx)
54 {
55         struct nft_base_chain *basechain = nft_base_chain(ctx->chain);
56
57         switch (event) {
58         case NETDEV_UNREGISTER:
59                 if (strcmp(basechain->dev_name, dev->name) != 0)
60                         return;
61
62                 __nft_release_basechain(ctx);
63                 break;
64         case NETDEV_CHANGENAME:
65                 if (dev->ifindex != basechain->ops.dev->ifindex)
66                         return;
67
68                 strncpy(basechain->dev_name, dev->name, IFNAMSIZ);
69                 break;
70         }
71 }
72
73 static int nf_tables_netdev_event(struct notifier_block *this,
74                                   unsigned long event, void *ptr)
75 {
76         struct net_device *dev = netdev_notifier_info_to_dev(ptr);
77         struct nft_table *table;
78         struct nft_chain *chain, *nr;
79         struct nft_ctx ctx = {
80                 .net    = dev_net(dev),
81         };
82
83         if (event != NETDEV_UNREGISTER &&
84             event != NETDEV_CHANGENAME)
85                 return NOTIFY_DONE;
86
87         nfnl_lock(NFNL_SUBSYS_NFTABLES);
88         list_for_each_entry(table, &ctx.net->nft.tables, list) {
89                 if (table->family != NFPROTO_NETDEV)
90                         continue;
91
92                 ctx.family = table->family;
93                 ctx.table = table;
94                 list_for_each_entry_safe(chain, nr, &table->chains, list) {
95                         if (!nft_is_base_chain(chain))
96                                 continue;
97
98                         ctx.chain = chain;
99                         nft_netdev_event(event, dev, &ctx);
100                 }
101         }
102         nfnl_unlock(NFNL_SUBSYS_NFTABLES);
103
104         return NOTIFY_DONE;
105 }
106
107 static struct notifier_block nf_tables_netdev_notifier = {
108         .notifier_call  = nf_tables_netdev_event,
109 };
110
111 static int __init nf_tables_netdev_init(void)
112 {
113         int ret;
114
115         ret = nft_register_chain_type(&nft_filter_chain_netdev);
116         if (ret)
117                 return ret;
118
119         ret = register_netdevice_notifier(&nf_tables_netdev_notifier);
120         if (ret)
121                 goto err_register_netdevice_notifier;
122
123         return 0;
124
125 err_register_netdevice_notifier:
126         nft_unregister_chain_type(&nft_filter_chain_netdev);
127
128         return ret;
129 }
130
131 static void __exit nf_tables_netdev_exit(void)
132 {
133         unregister_netdevice_notifier(&nf_tables_netdev_notifier);
134         nft_unregister_chain_type(&nft_filter_chain_netdev);
135 }
136
137 module_init(nf_tables_netdev_init);
138 module_exit(nf_tables_netdev_exit);
139
140 MODULE_LICENSE("GPL");
141 MODULE_AUTHOR("Pablo Neira Ayuso <[email protected]>");
142 MODULE_ALIAS_NFT_CHAIN(5, "filter"); /* NFPROTO_NETDEV */
This page took 0.041089 seconds and 4 git commands to generate.