scsi: ufs: core: Fix divide by zero in ufshcd_map_queues()
[platform/kernel/linux-starfive.git] / net / netfilter / nft_connlimit.c
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/module.h>
5 #include <linux/spinlock.h>
6 #include <linux/netlink.h>
7 #include <linux/netfilter.h>
8 #include <linux/netfilter/nf_tables.h>
9 #include <net/netfilter/nf_tables.h>
10 #include <net/netfilter/nf_conntrack.h>
11 #include <net/netfilter/nf_conntrack_count.h>
12 #include <net/netfilter/nf_conntrack_core.h>
13 #include <net/netfilter/nf_conntrack_tuple.h>
14 #include <net/netfilter/nf_conntrack_zones.h>
15
16 struct nft_connlimit {
17         struct nf_conncount_list        *list;
18         u32                             limit;
19         bool                            invert;
20 };
21
22 static inline void nft_connlimit_do_eval(struct nft_connlimit *priv,
23                                          struct nft_regs *regs,
24                                          const struct nft_pktinfo *pkt,
25                                          const struct nft_set_ext *ext)
26 {
27         const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
28         const struct nf_conntrack_tuple *tuple_ptr;
29         struct nf_conntrack_tuple tuple;
30         enum ip_conntrack_info ctinfo;
31         const struct nf_conn *ct;
32         unsigned int count;
33
34         tuple_ptr = &tuple;
35
36         ct = nf_ct_get(pkt->skb, &ctinfo);
37         if (ct != NULL) {
38                 tuple_ptr = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
39                 zone = nf_ct_zone(ct);
40         } else if (!nf_ct_get_tuplepr(pkt->skb, skb_network_offset(pkt->skb),
41                                       nft_pf(pkt), nft_net(pkt), &tuple)) {
42                 regs->verdict.code = NF_DROP;
43                 return;
44         }
45
46         if (nf_conncount_add(nft_net(pkt), priv->list, tuple_ptr, zone)) {
47                 regs->verdict.code = NF_DROP;
48                 return;
49         }
50
51         count = priv->list->count;
52
53         if ((count > priv->limit) ^ priv->invert) {
54                 regs->verdict.code = NFT_BREAK;
55                 return;
56         }
57 }
58
59 static int nft_connlimit_do_init(const struct nft_ctx *ctx,
60                                  const struct nlattr * const tb[],
61                                  struct nft_connlimit *priv)
62 {
63         bool invert = false;
64         u32 flags, limit;
65
66         if (!tb[NFTA_CONNLIMIT_COUNT])
67                 return -EINVAL;
68
69         limit = ntohl(nla_get_be32(tb[NFTA_CONNLIMIT_COUNT]));
70
71         if (tb[NFTA_CONNLIMIT_FLAGS]) {
72                 flags = ntohl(nla_get_be32(tb[NFTA_CONNLIMIT_FLAGS]));
73                 if (flags & ~NFT_CONNLIMIT_F_INV)
74                         return -EOPNOTSUPP;
75                 if (flags & NFT_CONNLIMIT_F_INV)
76                         invert = true;
77         }
78
79         priv->list = kmalloc(sizeof(*priv->list), GFP_KERNEL);
80         if (!priv->list)
81                 return -ENOMEM;
82
83         nf_conncount_list_init(priv->list);
84         priv->limit     = limit;
85         priv->invert    = invert;
86
87         return nf_ct_netns_get(ctx->net, ctx->family);
88 }
89
90 static void nft_connlimit_do_destroy(const struct nft_ctx *ctx,
91                                      struct nft_connlimit *priv)
92 {
93         nf_ct_netns_put(ctx->net, ctx->family);
94         nf_conncount_cache_free(priv->list);
95         kfree(priv->list);
96 }
97
98 static int nft_connlimit_do_dump(struct sk_buff *skb,
99                                  struct nft_connlimit *priv)
100 {
101         if (nla_put_be32(skb, NFTA_CONNLIMIT_COUNT, htonl(priv->limit)))
102                 goto nla_put_failure;
103         if (priv->invert &&
104             nla_put_be32(skb, NFTA_CONNLIMIT_FLAGS, htonl(NFT_CONNLIMIT_F_INV)))
105                 goto nla_put_failure;
106
107         return 0;
108
109 nla_put_failure:
110         return -1;
111 }
112
113 static inline void nft_connlimit_obj_eval(struct nft_object *obj,
114                                         struct nft_regs *regs,
115                                         const struct nft_pktinfo *pkt)
116 {
117         struct nft_connlimit *priv = nft_obj_data(obj);
118
119         nft_connlimit_do_eval(priv, regs, pkt, NULL);
120 }
121
122 static int nft_connlimit_obj_init(const struct nft_ctx *ctx,
123                                 const struct nlattr * const tb[],
124                                 struct nft_object *obj)
125 {
126         struct nft_connlimit *priv = nft_obj_data(obj);
127
128         return nft_connlimit_do_init(ctx, tb, priv);
129 }
130
131 static void nft_connlimit_obj_destroy(const struct nft_ctx *ctx,
132                                       struct nft_object *obj)
133 {
134         struct nft_connlimit *priv = nft_obj_data(obj);
135
136         nft_connlimit_do_destroy(ctx, priv);
137 }
138
139 static int nft_connlimit_obj_dump(struct sk_buff *skb,
140                                   struct nft_object *obj, bool reset)
141 {
142         struct nft_connlimit *priv = nft_obj_data(obj);
143
144         return nft_connlimit_do_dump(skb, priv);
145 }
146
147 static const struct nla_policy nft_connlimit_policy[NFTA_CONNLIMIT_MAX + 1] = {
148         [NFTA_CONNLIMIT_COUNT]  = { .type = NLA_U32 },
149         [NFTA_CONNLIMIT_FLAGS]  = { .type = NLA_U32 },
150 };
151
152 static struct nft_object_type nft_connlimit_obj_type;
153 static const struct nft_object_ops nft_connlimit_obj_ops = {
154         .type           = &nft_connlimit_obj_type,
155         .size           = sizeof(struct nft_connlimit),
156         .eval           = nft_connlimit_obj_eval,
157         .init           = nft_connlimit_obj_init,
158         .destroy        = nft_connlimit_obj_destroy,
159         .dump           = nft_connlimit_obj_dump,
160 };
161
162 static struct nft_object_type nft_connlimit_obj_type __read_mostly = {
163         .type           = NFT_OBJECT_CONNLIMIT,
164         .ops            = &nft_connlimit_obj_ops,
165         .maxattr        = NFTA_CONNLIMIT_MAX,
166         .policy         = nft_connlimit_policy,
167         .owner          = THIS_MODULE,
168 };
169
170 static void nft_connlimit_eval(const struct nft_expr *expr,
171                                struct nft_regs *regs,
172                                const struct nft_pktinfo *pkt)
173 {
174         struct nft_connlimit *priv = nft_expr_priv(expr);
175
176         nft_connlimit_do_eval(priv, regs, pkt, NULL);
177 }
178
179 static int nft_connlimit_dump(struct sk_buff *skb, const struct nft_expr *expr)
180 {
181         struct nft_connlimit *priv = nft_expr_priv(expr);
182
183         return nft_connlimit_do_dump(skb, priv);
184 }
185
186 static int nft_connlimit_init(const struct nft_ctx *ctx,
187                               const struct nft_expr *expr,
188                               const struct nlattr * const tb[])
189 {
190         struct nft_connlimit *priv = nft_expr_priv(expr);
191
192         return nft_connlimit_do_init(ctx, tb, priv);
193 }
194
195 static void nft_connlimit_destroy(const struct nft_ctx *ctx,
196                                 const struct nft_expr *expr)
197 {
198         struct nft_connlimit *priv = nft_expr_priv(expr);
199
200         nft_connlimit_do_destroy(ctx, priv);
201 }
202
203 static int nft_connlimit_clone(struct nft_expr *dst, const struct nft_expr *src)
204 {
205         struct nft_connlimit *priv_dst = nft_expr_priv(dst);
206         struct nft_connlimit *priv_src = nft_expr_priv(src);
207
208         priv_dst->list = kmalloc(sizeof(*priv_dst->list), GFP_ATOMIC);
209         if (!priv_dst->list)
210                 return -ENOMEM;
211
212         nf_conncount_list_init(priv_dst->list);
213         priv_dst->limit  = priv_src->limit;
214         priv_dst->invert = priv_src->invert;
215
216         return 0;
217 }
218
219 static void nft_connlimit_destroy_clone(const struct nft_ctx *ctx,
220                                         const struct nft_expr *expr)
221 {
222         struct nft_connlimit *priv = nft_expr_priv(expr);
223
224         nf_conncount_cache_free(priv->list);
225         kfree(priv->list);
226 }
227
228 static bool nft_connlimit_gc(struct net *net, const struct nft_expr *expr)
229 {
230         struct nft_connlimit *priv = nft_expr_priv(expr);
231         bool ret;
232
233         local_bh_disable();
234         ret = nf_conncount_gc_list(net, priv->list);
235         local_bh_enable();
236
237         return ret;
238 }
239
240 static struct nft_expr_type nft_connlimit_type;
241 static const struct nft_expr_ops nft_connlimit_ops = {
242         .type           = &nft_connlimit_type,
243         .size           = NFT_EXPR_SIZE(sizeof(struct nft_connlimit)),
244         .eval           = nft_connlimit_eval,
245         .init           = nft_connlimit_init,
246         .destroy        = nft_connlimit_destroy,
247         .clone          = nft_connlimit_clone,
248         .destroy_clone  = nft_connlimit_destroy_clone,
249         .dump           = nft_connlimit_dump,
250         .gc             = nft_connlimit_gc,
251 };
252
253 static struct nft_expr_type nft_connlimit_type __read_mostly = {
254         .name           = "connlimit",
255         .ops            = &nft_connlimit_ops,
256         .policy         = nft_connlimit_policy,
257         .maxattr        = NFTA_CONNLIMIT_MAX,
258         .flags          = NFT_EXPR_STATEFUL | NFT_EXPR_GC,
259         .owner          = THIS_MODULE,
260 };
261
262 static int __init nft_connlimit_module_init(void)
263 {
264         int err;
265
266         err = nft_register_obj(&nft_connlimit_obj_type);
267         if (err < 0)
268                 return err;
269
270         err = nft_register_expr(&nft_connlimit_type);
271         if (err < 0)
272                 goto err1;
273
274         return 0;
275 err1:
276         nft_unregister_obj(&nft_connlimit_obj_type);
277         return err;
278 }
279
280 static void __exit nft_connlimit_module_exit(void)
281 {
282         nft_unregister_expr(&nft_connlimit_type);
283         nft_unregister_obj(&nft_connlimit_obj_type);
284 }
285
286 module_init(nft_connlimit_module_init);
287 module_exit(nft_connlimit_module_exit);
288
289 MODULE_LICENSE("GPL");
290 MODULE_AUTHOR("Pablo Neira Ayuso");
291 MODULE_ALIAS_NFT_EXPR("connlimit");
292 MODULE_ALIAS_NFT_OBJ(NFT_OBJECT_CONNLIMIT);
293 MODULE_DESCRIPTION("nftables connlimit rule support");