spi/davinci: fix module build error
[firefly-linux-kernel-4.4.55.git] / net / netfilter / ipset / ip_set_list_set.c
1 /* Copyright (C) 2008-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License version 2 as
5  * published by the Free Software Foundation.
6  */
7
8 /* Kernel module implementing an IP set type: the list:set type */
9
10 #include <linux/module.h>
11 #include <linux/ip.h>
12 #include <linux/skbuff.h>
13 #include <linux/errno.h>
14
15 #include <linux/netfilter/ipset/ip_set.h>
16 #include <linux/netfilter/ipset/ip_set_timeout.h>
17 #include <linux/netfilter/ipset/ip_set_list.h>
18
19 #define REVISION_MIN    0
20 #define REVISION_MAX    0
21
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
24 IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
25 MODULE_ALIAS("ip_set_list:set");
26
27 /* Member elements without and with timeout */
28 struct set_elem {
29         ip_set_id_t id;
30 };
31
32 struct set_telem {
33         ip_set_id_t id;
34         unsigned long timeout;
35 };
36
37 /* Type structure */
38 struct list_set {
39         size_t dsize;           /* element size */
40         u32 size;               /* size of set list array */
41         u32 timeout;            /* timeout value */
42         struct timer_list gc;   /* garbage collection */
43         struct set_elem members[0]; /* the set members */
44 };
45
46 static inline struct set_elem *
47 list_set_elem(const struct list_set *map, u32 id)
48 {
49         return (struct set_elem *)((void *)map->members + id * map->dsize);
50 }
51
52 static inline struct set_telem *
53 list_set_telem(const struct list_set *map, u32 id)
54 {
55         return (struct set_telem *)((void *)map->members + id * map->dsize);
56 }
57
58 static inline bool
59 list_set_timeout(const struct list_set *map, u32 id)
60 {
61         const struct set_telem *elem = list_set_telem(map, id);
62
63         return ip_set_timeout_test(elem->timeout);
64 }
65
66 static inline bool
67 list_set_expired(const struct list_set *map, u32 id)
68 {
69         const struct set_telem *elem = list_set_telem(map, id);
70
71         return ip_set_timeout_expired(elem->timeout);
72 }
73
74 /* Set list without and with timeout */
75
76 static int
77 list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
78               const struct xt_action_param *par,
79               enum ipset_adt adt, const struct ip_set_adt_opt *opt)
80 {
81         struct list_set *map = set->data;
82         struct set_elem *elem;
83         u32 i;
84         int ret;
85
86         for (i = 0; i < map->size; i++) {
87                 elem = list_set_elem(map, i);
88                 if (elem->id == IPSET_INVALID_ID)
89                         return 0;
90                 if (with_timeout(map->timeout) && list_set_expired(map, i))
91                         continue;
92                 switch (adt) {
93                 case IPSET_TEST:
94                         ret = ip_set_test(elem->id, skb, par, opt);
95                         if (ret > 0)
96                                 return ret;
97                         break;
98                 case IPSET_ADD:
99                         ret = ip_set_add(elem->id, skb, par, opt);
100                         if (ret == 0)
101                                 return ret;
102                         break;
103                 case IPSET_DEL:
104                         ret = ip_set_del(elem->id, skb, par, opt);
105                         if (ret == 0)
106                                 return ret;
107                         break;
108                 default:
109                         break;
110                 }
111         }
112         return -EINVAL;
113 }
114
115 static bool
116 id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
117 {
118         const struct set_elem *elem;
119
120         if (i < map->size) {
121                 elem = list_set_elem(map, i);
122                 return elem->id == id;
123         }
124
125         return 0;
126 }
127
128 static bool
129 id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
130 {
131         const struct set_elem *elem;
132
133         if (i < map->size) {
134                 elem = list_set_elem(map, i);
135                 return !!(elem->id == id &&
136                           !(with_timeout(map->timeout) &&
137                             list_set_expired(map, i)));
138         }
139
140         return 0;
141 }
142
143 static void
144 list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
145 {
146         struct set_elem *e;
147
148         for (; i < map->size; i++) {
149                 e = list_set_elem(map, i);
150                 swap(e->id, id);
151                 if (e->id == IPSET_INVALID_ID)
152                         break;
153         }
154 }
155
156 static void
157 list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
158                unsigned long timeout)
159 {
160         struct set_telem *e;
161
162         for (; i < map->size; i++) {
163                 e = list_set_telem(map, i);
164                 swap(e->id, id);
165                 swap(e->timeout, timeout);
166                 if (e->id == IPSET_INVALID_ID)
167                         break;
168         }
169 }
170
171 static int
172 list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
173              unsigned long timeout)
174 {
175         const struct set_elem *e = list_set_elem(map, i);
176
177         if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
178                 /* Last element replaced: e.g. add new,before,last */
179                 ip_set_put_byindex(e->id);
180         if (with_timeout(map->timeout))
181                 list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
182         else
183                 list_elem_add(map, i, id);
184
185         return 0;
186 }
187
188 static int
189 list_set_del(struct list_set *map, u32 i)
190 {
191         struct set_elem *a = list_set_elem(map, i), *b;
192
193         ip_set_put_byindex(a->id);
194
195         for (; i < map->size - 1; i++) {
196                 b = list_set_elem(map, i + 1);
197                 a->id = b->id;
198                 if (with_timeout(map->timeout))
199                         ((struct set_telem *)a)->timeout =
200                                 ((struct set_telem *)b)->timeout;
201                 a = b;
202                 if (a->id == IPSET_INVALID_ID)
203                         break;
204         }
205         /* Last element */
206         a->id = IPSET_INVALID_ID;
207         return 0;
208 }
209
210 static void
211 cleanup_entries(struct list_set *map)
212 {
213         struct set_telem *e;
214         u32 i;
215
216         for (i = 0; i < map->size; i++) {
217                 e = list_set_telem(map, i);
218                 if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
219                         list_set_del(map, i);
220         }
221 }
222
223 static int
224 list_set_uadt(struct ip_set *set, struct nlattr *tb[],
225               enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
226 {
227         struct list_set *map = set->data;
228         bool with_timeout = with_timeout(map->timeout);
229         bool flag_exist = flags & IPSET_FLAG_EXIST;
230         int before = 0;
231         u32 timeout = map->timeout;
232         ip_set_id_t id, refid = IPSET_INVALID_ID;
233         const struct set_elem *elem;
234         struct ip_set *s;
235         u32 i;
236         int ret = 0;
237
238         if (unlikely(!tb[IPSET_ATTR_NAME] ||
239                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
240                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
241                 return -IPSET_ERR_PROTOCOL;
242
243         if (tb[IPSET_ATTR_LINENO])
244                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
245
246         id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
247         if (id == IPSET_INVALID_ID)
248                 return -IPSET_ERR_NAME;
249         /* "Loop detection" */
250         if (s->type->features & IPSET_TYPE_NAME) {
251                 ret = -IPSET_ERR_LOOP;
252                 goto finish;
253         }
254
255         if (tb[IPSET_ATTR_CADT_FLAGS]) {
256                 u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
257                 before = f & IPSET_FLAG_BEFORE;
258         }
259
260         if (before && !tb[IPSET_ATTR_NAMEREF]) {
261                 ret = -IPSET_ERR_BEFORE;
262                 goto finish;
263         }
264
265         if (tb[IPSET_ATTR_NAMEREF]) {
266                 refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
267                                           &s);
268                 if (refid == IPSET_INVALID_ID) {
269                         ret = -IPSET_ERR_NAMEREF;
270                         goto finish;
271                 }
272                 if (!before)
273                         before = -1;
274         }
275         if (tb[IPSET_ATTR_TIMEOUT]) {
276                 if (!with_timeout) {
277                         ret = -IPSET_ERR_TIMEOUT;
278                         goto finish;
279                 }
280                 timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
281         }
282         if (with_timeout && adt != IPSET_TEST)
283                 cleanup_entries(map);
284
285         switch (adt) {
286         case IPSET_TEST:
287                 for (i = 0; i < map->size && !ret; i++) {
288                         elem = list_set_elem(map, i);
289                         if (elem->id == IPSET_INVALID_ID ||
290                             (before != 0 && i + 1 >= map->size))
291                                 break;
292                         else if (with_timeout && list_set_expired(map, i))
293                                 continue;
294                         else if (before > 0 && elem->id == id)
295                                 ret = id_eq_timeout(map, i + 1, refid);
296                         else if (before < 0 && elem->id == refid)
297                                 ret = id_eq_timeout(map, i + 1, id);
298                         else if (before == 0 && elem->id == id)
299                                 ret = 1;
300                 }
301                 break;
302         case IPSET_ADD:
303                 for (i = 0; i < map->size; i++) {
304                         elem = list_set_elem(map, i);
305                         if (elem->id != id)
306                                 continue;
307                         if (!(with_timeout && flag_exist)) {
308                                 ret = -IPSET_ERR_EXIST;
309                                 goto finish;
310                         } else {
311                                 struct set_telem *e = list_set_telem(map, i);
312
313                                 if ((before > 1 &&
314                                      !id_eq(map, i + 1, refid)) ||
315                                     (before < 0 &&
316                                      (i == 0 || !id_eq(map, i - 1, refid)))) {
317                                         ret = -IPSET_ERR_EXIST;
318                                         goto finish;
319                                 }
320                                 e->timeout = ip_set_timeout_set(timeout);
321                                 ip_set_put_byindex(id);
322                                 ret = 0;
323                                 goto finish;
324                         }
325                 }
326                 ret = -IPSET_ERR_LIST_FULL;
327                 for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
328                         elem = list_set_elem(map, i);
329                         if (elem->id == IPSET_INVALID_ID)
330                                 ret = before != 0 ? -IPSET_ERR_REF_EXIST
331                                         : list_set_add(map, i, id, timeout);
332                         else if (elem->id != refid)
333                                 continue;
334                         else if (before > 0)
335                                 ret = list_set_add(map, i, id, timeout);
336                         else if (i + 1 < map->size)
337                                 ret = list_set_add(map, i + 1, id, timeout);
338                 }
339                 break;
340         case IPSET_DEL:
341                 ret = -IPSET_ERR_EXIST;
342                 for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
343                         elem = list_set_elem(map, i);
344                         if (elem->id == IPSET_INVALID_ID) {
345                                 ret = before != 0 ? -IPSET_ERR_REF_EXIST
346                                                   : -IPSET_ERR_EXIST;
347                                 break;
348                         } else if (elem->id == id &&
349                                    (before == 0 ||
350                                     (before > 0 && id_eq(map, i + 1, refid))))
351                                 ret = list_set_del(map, i);
352                         else if (elem->id == refid &&
353                                  before < 0 && id_eq(map, i + 1, id))
354                                 ret = list_set_del(map, i + 1);
355                 }
356                 break;
357         default:
358                 break;
359         }
360
361 finish:
362         if (refid != IPSET_INVALID_ID)
363                 ip_set_put_byindex(refid);
364         if (adt != IPSET_ADD || ret)
365                 ip_set_put_byindex(id);
366
367         return ip_set_eexist(ret, flags) ? 0 : ret;
368 }
369
370 static void
371 list_set_flush(struct ip_set *set)
372 {
373         struct list_set *map = set->data;
374         struct set_elem *elem;
375         u32 i;
376
377         for (i = 0; i < map->size; i++) {
378                 elem = list_set_elem(map, i);
379                 if (elem->id != IPSET_INVALID_ID) {
380                         ip_set_put_byindex(elem->id);
381                         elem->id = IPSET_INVALID_ID;
382                 }
383         }
384 }
385
386 static void
387 list_set_destroy(struct ip_set *set)
388 {
389         struct list_set *map = set->data;
390
391         if (with_timeout(map->timeout))
392                 del_timer_sync(&map->gc);
393         list_set_flush(set);
394         kfree(map);
395
396         set->data = NULL;
397 }
398
399 static int
400 list_set_head(struct ip_set *set, struct sk_buff *skb)
401 {
402         const struct list_set *map = set->data;
403         struct nlattr *nested;
404
405         nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
406         if (!nested)
407                 goto nla_put_failure;
408         if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
409             (with_timeout(map->timeout) &&
410              nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
411             nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
412             nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
413                           htonl(sizeof(*map) + map->size * map->dsize)))
414                 goto nla_put_failure;
415         ipset_nest_end(skb, nested);
416
417         return 0;
418 nla_put_failure:
419         return -EMSGSIZE;
420 }
421
422 static int
423 list_set_list(const struct ip_set *set,
424               struct sk_buff *skb, struct netlink_callback *cb)
425 {
426         const struct list_set *map = set->data;
427         struct nlattr *atd, *nested;
428         u32 i, first = cb->args[2];
429         const struct set_elem *e;
430
431         atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
432         if (!atd)
433                 return -EMSGSIZE;
434         for (; cb->args[2] < map->size; cb->args[2]++) {
435                 i = cb->args[2];
436                 e = list_set_elem(map, i);
437                 if (e->id == IPSET_INVALID_ID)
438                         goto finish;
439                 if (with_timeout(map->timeout) && list_set_expired(map, i))
440                         continue;
441                 nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
442                 if (!nested) {
443                         if (i == first) {
444                                 nla_nest_cancel(skb, atd);
445                                 return -EMSGSIZE;
446                         } else
447                                 goto nla_put_failure;
448                 }
449                 if (nla_put_string(skb, IPSET_ATTR_NAME,
450                                    ip_set_name_byindex(e->id)))
451                         goto nla_put_failure;
452                 if (with_timeout(map->timeout)) {
453                         const struct set_telem *te =
454                                 (const struct set_telem *) e;
455                         __be32 to = htonl(ip_set_timeout_get(te->timeout));
456                         if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT, to))
457                                 goto nla_put_failure;
458                 }
459                 ipset_nest_end(skb, nested);
460         }
461 finish:
462         ipset_nest_end(skb, atd);
463         /* Set listing finished */
464         cb->args[2] = 0;
465         return 0;
466
467 nla_put_failure:
468         nla_nest_cancel(skb, nested);
469         ipset_nest_end(skb, atd);
470         if (unlikely(i == first)) {
471                 cb->args[2] = 0;
472                 return -EMSGSIZE;
473         }
474         return 0;
475 }
476
477 static bool
478 list_set_same_set(const struct ip_set *a, const struct ip_set *b)
479 {
480         const struct list_set *x = a->data;
481         const struct list_set *y = b->data;
482
483         return x->size == y->size &&
484                x->timeout == y->timeout;
485 }
486
487 static const struct ip_set_type_variant list_set = {
488         .kadt   = list_set_kadt,
489         .uadt   = list_set_uadt,
490         .destroy = list_set_destroy,
491         .flush  = list_set_flush,
492         .head   = list_set_head,
493         .list   = list_set_list,
494         .same_set = list_set_same_set,
495 };
496
497 static void
498 list_set_gc(unsigned long ul_set)
499 {
500         struct ip_set *set = (struct ip_set *) ul_set;
501         struct list_set *map = set->data;
502
503         write_lock_bh(&set->lock);
504         cleanup_entries(map);
505         write_unlock_bh(&set->lock);
506
507         map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
508         add_timer(&map->gc);
509 }
510
511 static void
512 list_set_gc_init(struct ip_set *set)
513 {
514         struct list_set *map = set->data;
515
516         init_timer(&map->gc);
517         map->gc.data = (unsigned long) set;
518         map->gc.function = list_set_gc;
519         map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
520         add_timer(&map->gc);
521 }
522
523 /* Create list:set type of sets */
524
525 static bool
526 init_list_set(struct ip_set *set, u32 size, size_t dsize,
527               unsigned long timeout)
528 {
529         struct list_set *map;
530         struct set_elem *e;
531         u32 i;
532
533         map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
534         if (!map)
535                 return false;
536
537         map->size = size;
538         map->dsize = dsize;
539         map->timeout = timeout;
540         set->data = map;
541
542         for (i = 0; i < size; i++) {
543                 e = list_set_elem(map, i);
544                 e->id = IPSET_INVALID_ID;
545         }
546
547         return true;
548 }
549
550 static int
551 list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
552 {
553         u32 size = IP_SET_LIST_DEFAULT_SIZE;
554
555         if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
556                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
557                 return -IPSET_ERR_PROTOCOL;
558
559         if (tb[IPSET_ATTR_SIZE])
560                 size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
561         if (size < IP_SET_LIST_MIN_SIZE)
562                 size = IP_SET_LIST_MIN_SIZE;
563
564         if (tb[IPSET_ATTR_TIMEOUT]) {
565                 if (!init_list_set(set, size, sizeof(struct set_telem),
566                                    ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
567                         return -ENOMEM;
568
569                 list_set_gc_init(set);
570         } else {
571                 if (!init_list_set(set, size, sizeof(struct set_elem),
572                                    IPSET_NO_TIMEOUT))
573                         return -ENOMEM;
574         }
575         set->variant = &list_set;
576         return 0;
577 }
578
579 static struct ip_set_type list_set_type __read_mostly = {
580         .name           = "list:set",
581         .protocol       = IPSET_PROTOCOL,
582         .features       = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
583         .dimension      = IPSET_DIM_ONE,
584         .family         = NFPROTO_UNSPEC,
585         .revision_min   = REVISION_MIN,
586         .revision_max   = REVISION_MAX,
587         .create         = list_set_create,
588         .create_policy  = {
589                 [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
590                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
591         },
592         .adt_policy     = {
593                 [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
594                                             .len = IPSET_MAXNAMELEN },
595                 [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
596                                             .len = IPSET_MAXNAMELEN },
597                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
598                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
599                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
600         },
601         .me             = THIS_MODULE,
602 };
603
604 static int __init
605 list_set_init(void)
606 {
607         return ip_set_type_register(&list_set_type);
608 }
609
610 static void __exit
611 list_set_fini(void)
612 {
613         ip_set_type_unregister(&list_set_type);
614 }
615
616 module_init(list_set_init);
617 module_exit(list_set_fini);