linux/net/netfilter/ipset/ip_set_list_set.c
<<
>>
Prefs
   1/* Copyright (C) 2008-2013 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_list.h>
  17
  18#define REVISION_MIN    0
  19#define REVISION_MAX    1 /* Counters support added */
  20
  21MODULE_LICENSE("GPL");
  22MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  23IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
  24MODULE_ALIAS("ip_set_list:set");
  25
  26/* Member elements  */
  27struct set_elem {
  28        ip_set_id_t id;
  29};
  30
  31struct sett_elem {
  32        struct {
  33                ip_set_id_t id;
  34        } __attribute__ ((aligned));
  35        unsigned long timeout;
  36};
  37
  38struct setc_elem {
  39        struct {
  40                ip_set_id_t id;
  41        } __attribute__ ((aligned));
  42        struct ip_set_counter counter;
  43};
  44
  45struct setct_elem {
  46        struct {
  47                ip_set_id_t id;
  48        } __attribute__ ((aligned));
  49        struct ip_set_counter counter;
  50        unsigned long timeout;
  51};
  52
  53struct set_adt_elem {
  54        ip_set_id_t id;
  55        ip_set_id_t refid;
  56        int before;
  57};
  58
  59/* Type structure */
  60struct list_set {
  61        size_t dsize;           /* element size */
  62        size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
  63        u32 size;               /* size of set list array */
  64        u32 timeout;            /* timeout value */
  65        struct timer_list gc;   /* garbage collection */
  66        struct set_elem members[0]; /* the set members */
  67};
  68
  69static inline struct set_elem *
  70list_set_elem(const struct list_set *map, u32 id)
  71{
  72        return (struct set_elem *)((void *)map->members + id * map->dsize);
  73}
  74
  75#define ext_timeout(e, m)       \
  76(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
  77#define ext_counter(e, m)       \
  78(struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER])
  79
  80static int
  81list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
  82               const struct xt_action_param *par,
  83               struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
  84{
  85        struct list_set *map = set->data;
  86        struct set_elem *e;
  87        u32 i, cmdflags = opt->cmdflags;
  88        int ret;
  89
  90        /* Don't lookup sub-counters at all */
  91        opt->cmdflags &= ~IPSET_FLAG_MATCH_COUNTERS;
  92        if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
  93                opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
  94        for (i = 0; i < map->size; i++) {
  95                e = list_set_elem(map, i);
  96                if (e->id == IPSET_INVALID_ID)
  97                        return 0;
  98                if (SET_WITH_TIMEOUT(set) &&
  99                    ip_set_timeout_expired(ext_timeout(e, map)))
 100                        continue;
 101                ret = ip_set_test(e->id, skb, par, opt);
 102                if (ret > 0) {
 103                        if (SET_WITH_COUNTER(set))
 104                                ip_set_update_counter(ext_counter(e, map),
 105                                                      ext, &opt->ext,
 106                                                      cmdflags);
 107                        return ret;
 108                }
 109        }
 110        return 0;
 111}
 112
 113static int
 114list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
 115              const struct xt_action_param *par,
 116              struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
 117{
 118        struct list_set *map = set->data;
 119        struct set_elem *e;
 120        u32 i;
 121        int ret;
 122
 123        for (i = 0; i < map->size; i++) {
 124                e = list_set_elem(map, i);
 125                if (e->id == IPSET_INVALID_ID)
 126                        return 0;
 127                if (SET_WITH_TIMEOUT(set) &&
 128                    ip_set_timeout_expired(ext_timeout(e, map)))
 129                        continue;
 130                ret = ip_set_add(e->id, skb, par, opt);
 131                if (ret == 0)
 132                        return ret;
 133        }
 134        return 0;
 135}
 136
 137static int
 138list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
 139              const struct xt_action_param *par,
 140              struct ip_set_adt_opt *opt, const struct ip_set_ext *ext)
 141{
 142        struct list_set *map = set->data;
 143        struct set_elem *e;
 144        u32 i;
 145        int ret;
 146
 147        for (i = 0; i < map->size; i++) {
 148                e = list_set_elem(map, i);
 149                if (e->id == IPSET_INVALID_ID)
 150                        return 0;
 151                if (SET_WITH_TIMEOUT(set) &&
 152                    ip_set_timeout_expired(ext_timeout(e, map)))
 153                        continue;
 154                ret = ip_set_del(e->id, skb, par, opt);
 155                if (ret == 0)
 156                        return ret;
 157        }
 158        return 0;
 159}
 160
 161static int
 162list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
 163              const struct xt_action_param *par,
 164              enum ipset_adt adt, struct ip_set_adt_opt *opt)
 165{
 166        struct list_set *map = set->data;
 167        struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
 168
 169        switch (adt) {
 170        case IPSET_TEST:
 171                return list_set_ktest(set, skb, par, opt, &ext);
 172        case IPSET_ADD:
 173                return list_set_kadd(set, skb, par, opt, &ext);
 174        case IPSET_DEL:
 175                return list_set_kdel(set, skb, par, opt, &ext);
 176        default:
 177                break;
 178        }
 179        return -EINVAL;
 180}
 181
 182static bool
 183id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
 184{
 185        const struct list_set *map = set->data;
 186        const struct set_elem *e;
 187
 188        if (i >= map->size)
 189                return 0;
 190
 191        e = list_set_elem(map, i);
 192        return !!(e->id == id &&
 193                 !(SET_WITH_TIMEOUT(set) &&
 194                   ip_set_timeout_expired(ext_timeout(e, map))));
 195}
 196
 197static int
 198list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
 199             const struct ip_set_ext *ext)
 200{
 201        struct list_set *map = set->data;
 202        struct set_elem *e = list_set_elem(map, i);
 203
 204        if (e->id != IPSET_INVALID_ID) {
 205                if (i == map->size - 1)
 206                        /* Last element replaced: e.g. add new,before,last */
 207                        ip_set_put_byindex(e->id);
 208                else {
 209                        struct set_elem *x = list_set_elem(map, map->size - 1);
 210
 211                        /* Last element pushed off */
 212                        if (x->id != IPSET_INVALID_ID)
 213                                ip_set_put_byindex(x->id);
 214                        memmove(list_set_elem(map, i + 1), e,
 215                                map->dsize * (map->size - (i + 1)));
 216                }
 217        }
 218
 219        e->id = d->id;
 220        if (SET_WITH_TIMEOUT(set))
 221                ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
 222        if (SET_WITH_COUNTER(set))
 223                ip_set_init_counter(ext_counter(e, map), ext);
 224        return 0;
 225}
 226
 227static int
 228list_set_del(struct ip_set *set, u32 i)
 229{
 230        struct list_set *map = set->data;
 231        struct set_elem *e = list_set_elem(map, i);
 232
 233        ip_set_put_byindex(e->id);
 234
 235        if (i < map->size - 1)
 236                memmove(e, list_set_elem(map, i + 1),
 237                        map->dsize * (map->size - (i + 1)));
 238
 239        /* Last element */
 240        e = list_set_elem(map, map->size - 1);
 241        e->id = IPSET_INVALID_ID;
 242        return 0;
 243}
 244
 245static void
 246set_cleanup_entries(struct ip_set *set)
 247{
 248        struct list_set *map = set->data;
 249        struct set_elem *e;
 250        u32 i;
 251
 252        for (i = 0; i < map->size; i++) {
 253                e = list_set_elem(map, i);
 254                if (e->id != IPSET_INVALID_ID &&
 255                    ip_set_timeout_expired(ext_timeout(e, map)))
 256                        list_set_del(set, i);
 257        }
 258}
 259
 260static int
 261list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 262               struct ip_set_ext *mext, u32 flags)
 263{
 264        struct list_set *map = set->data;
 265        struct set_adt_elem *d = value;
 266        struct set_elem *e;
 267        u32 i;
 268        int ret;
 269
 270        for (i = 0; i < map->size; i++) {
 271                e = list_set_elem(map, i);
 272                if (e->id == IPSET_INVALID_ID)
 273                        return 0;
 274                else if (SET_WITH_TIMEOUT(set) &&
 275                         ip_set_timeout_expired(ext_timeout(e, map)))
 276                        continue;
 277                else if (e->id != d->id)
 278                        continue;
 279
 280                if (d->before == 0)
 281                        return 1;
 282                else if (d->before > 0)
 283                        ret = id_eq(set, i + 1, d->refid);
 284                else
 285                        ret = i > 0 && id_eq(set, i - 1, d->refid);
 286                return ret;
 287        }
 288        return 0;
 289}
 290
 291
 292static int
 293list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 294              struct ip_set_ext *mext, u32 flags)
 295{
 296        struct list_set *map = set->data;
 297        struct set_adt_elem *d = value;
 298        struct set_elem *e;
 299        bool flag_exist = flags & IPSET_FLAG_EXIST;
 300        u32 i, ret = 0;
 301
 302        /* Check already added element */
 303        for (i = 0; i < map->size; i++) {
 304                e = list_set_elem(map, i);
 305                if (e->id == IPSET_INVALID_ID)
 306                        goto insert;
 307                else if (SET_WITH_TIMEOUT(set) &&
 308                         ip_set_timeout_expired(ext_timeout(e, map)))
 309                        continue;
 310                else if (e->id != d->id)
 311                        continue;
 312
 313                if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) ||
 314                    (d->before < 0 &&
 315                     (i == 0 || !id_eq(set, i - 1, d->refid))))
 316                        /* Before/after doesn't match */
 317                        return -IPSET_ERR_REF_EXIST;
 318                if (!flag_exist)
 319                        /* Can't re-add */
 320                        return -IPSET_ERR_EXIST;
 321                /* Update extensions */
 322                if (SET_WITH_TIMEOUT(set))
 323                        ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
 324                if (SET_WITH_COUNTER(set))
 325                        ip_set_init_counter(ext_counter(e, map), ext);
 326                /* Set is already added to the list */
 327                ip_set_put_byindex(d->id);
 328                return 0;
 329        }
 330insert:
 331        ret = -IPSET_ERR_LIST_FULL;
 332        for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
 333                e = list_set_elem(map, i);
 334                if (e->id == IPSET_INVALID_ID)
 335                        ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
 336                                : list_set_add(set, i, d, ext);
 337                else if (e->id != d->refid)
 338                        continue;
 339                else if (d->before > 0)
 340                        ret = list_set_add(set, i, d, ext);
 341                else if (i + 1 < map->size)
 342                        ret = list_set_add(set, i + 1, d, ext);
 343        }
 344
 345        return ret;
 346}
 347
 348static int
 349list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
 350              struct ip_set_ext *mext, u32 flags)
 351{
 352        struct list_set *map = set->data;
 353        struct set_adt_elem *d = value;
 354        struct set_elem *e;
 355        u32 i;
 356
 357        for (i = 0; i < map->size; i++) {
 358                e = list_set_elem(map, i);
 359                if (e->id == IPSET_INVALID_ID)
 360                        return d->before != 0 ? -IPSET_ERR_REF_EXIST
 361                                              : -IPSET_ERR_EXIST;
 362                else if (SET_WITH_TIMEOUT(set) &&
 363                         ip_set_timeout_expired(ext_timeout(e, map)))
 364                        continue;
 365                else if (e->id != d->id)
 366                        continue;
 367
 368                if (d->before == 0)
 369                        return list_set_del(set, i);
 370                else if (d->before > 0) {
 371                        if (!id_eq(set, i + 1, d->refid))
 372                                return -IPSET_ERR_REF_EXIST;
 373                        return list_set_del(set, i);
 374                } else if (i == 0 || !id_eq(set, i - 1, d->refid))
 375                        return -IPSET_ERR_REF_EXIST;
 376                else
 377                        return list_set_del(set, i);
 378        }
 379        return -IPSET_ERR_EXIST;
 380}
 381
 382static int
 383list_set_uadt(struct ip_set *set, struct nlattr *tb[],
 384              enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 385{
 386        struct list_set *map = set->data;
 387        ipset_adtfn adtfn = set->variant->adt[adt];
 388        struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
 389        struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
 390        struct ip_set *s;
 391        int ret = 0;
 392
 393        if (unlikely(!tb[IPSET_ATTR_NAME] ||
 394                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 395                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
 396                     !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 397                     !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
 398                return -IPSET_ERR_PROTOCOL;
 399
 400        if (tb[IPSET_ATTR_LINENO])
 401                *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 402
 403        ret = ip_set_get_extensions(set, tb, &ext);
 404        if (ret)
 405                return ret;
 406        e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
 407        if (e.id == IPSET_INVALID_ID)
 408                return -IPSET_ERR_NAME;
 409        /* "Loop detection" */
 410        if (s->type->features & IPSET_TYPE_NAME) {
 411                ret = -IPSET_ERR_LOOP;
 412                goto finish;
 413        }
 414
 415        if (tb[IPSET_ATTR_CADT_FLAGS]) {
 416                u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 417                e.before = f & IPSET_FLAG_BEFORE;
 418        }
 419
 420        if (e.before && !tb[IPSET_ATTR_NAMEREF]) {
 421                ret = -IPSET_ERR_BEFORE;
 422                goto finish;
 423        }
 424
 425        if (tb[IPSET_ATTR_NAMEREF]) {
 426                e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
 427                                            &s);
 428                if (e.refid == IPSET_INVALID_ID) {
 429                        ret = -IPSET_ERR_NAMEREF;
 430                        goto finish;
 431                }
 432                if (!e.before)
 433                        e.before = -1;
 434        }
 435        if (adt != IPSET_TEST && SET_WITH_TIMEOUT(set))
 436                set_cleanup_entries(set);
 437
 438        ret = adtfn(set, &e, &ext, &ext, flags);
 439
 440finish:
 441        if (e.refid != IPSET_INVALID_ID)
 442                ip_set_put_byindex(e.refid);
 443        if (adt != IPSET_ADD || ret)
 444                ip_set_put_byindex(e.id);
 445
 446        return ip_set_eexist(ret, flags) ? 0 : ret;
 447}
 448
 449static void
 450list_set_flush(struct ip_set *set)
 451{
 452        struct list_set *map = set->data;
 453        struct set_elem *e;
 454        u32 i;
 455
 456        for (i = 0; i < map->size; i++) {
 457                e = list_set_elem(map, i);
 458                if (e->id != IPSET_INVALID_ID) {
 459                        ip_set_put_byindex(e->id);
 460                        e->id = IPSET_INVALID_ID;
 461                }
 462        }
 463}
 464
 465static void
 466list_set_destroy(struct ip_set *set)
 467{
 468        struct list_set *map = set->data;
 469
 470        if (SET_WITH_TIMEOUT(set))
 471                del_timer_sync(&map->gc);
 472        list_set_flush(set);
 473        kfree(map);
 474
 475        set->data = NULL;
 476}
 477
 478static int
 479list_set_head(struct ip_set *set, struct sk_buff *skb)
 480{
 481        const struct list_set *map = set->data;
 482        struct nlattr *nested;
 483
 484        nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
 485        if (!nested)
 486                goto nla_put_failure;
 487        if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
 488            (SET_WITH_TIMEOUT(set) &&
 489             nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
 490            (SET_WITH_COUNTER(set) &&
 491             nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
 492                           htonl(IPSET_FLAG_WITH_COUNTERS))) ||
 493            nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
 494            nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
 495                          htonl(sizeof(*map) + map->size * map->dsize)))
 496                goto nla_put_failure;
 497        ipset_nest_end(skb, nested);
 498
 499        return 0;
 500nla_put_failure:
 501        return -EMSGSIZE;
 502}
 503
 504static int
 505list_set_list(const struct ip_set *set,
 506              struct sk_buff *skb, struct netlink_callback *cb)
 507{
 508        const struct list_set *map = set->data;
 509        struct nlattr *atd, *nested;
 510        u32 i, first = cb->args[2];
 511        const struct set_elem *e;
 512
 513        atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
 514        if (!atd)
 515                return -EMSGSIZE;
 516        for (; cb->args[2] < map->size; cb->args[2]++) {
 517                i = cb->args[2];
 518                e = list_set_elem(map, i);
 519                if (e->id == IPSET_INVALID_ID)
 520                        goto finish;
 521                if (SET_WITH_TIMEOUT(set) &&
 522                    ip_set_timeout_expired(ext_timeout(e, map)))
 523                        continue;
 524                nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
 525                if (!nested) {
 526                        if (i == first) {
 527                                nla_nest_cancel(skb, atd);
 528                                return -EMSGSIZE;
 529                        } else
 530                                goto nla_put_failure;
 531                }
 532                if (nla_put_string(skb, IPSET_ATTR_NAME,
 533                                   ip_set_name_byindex(e->id)))
 534                        goto nla_put_failure;
 535                if (SET_WITH_TIMEOUT(set) &&
 536                    nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
 537                                  htonl(ip_set_timeout_get(
 538                                                ext_timeout(e, map)))))
 539                        goto nla_put_failure;
 540                if (SET_WITH_COUNTER(set) &&
 541                    ip_set_put_counter(skb, ext_counter(e, map)))
 542                        goto nla_put_failure;
 543                ipset_nest_end(skb, nested);
 544        }
 545finish:
 546        ipset_nest_end(skb, atd);
 547        /* Set listing finished */
 548        cb->args[2] = 0;
 549        return 0;
 550
 551nla_put_failure:
 552        nla_nest_cancel(skb, nested);
 553        ipset_nest_end(skb, atd);
 554        if (unlikely(i == first)) {
 555                cb->args[2] = 0;
 556                return -EMSGSIZE;
 557        }
 558        return 0;
 559}
 560
 561static bool
 562list_set_same_set(const struct ip_set *a, const struct ip_set *b)
 563{
 564        const struct list_set *x = a->data;
 565        const struct list_set *y = b->data;
 566
 567        return x->size == y->size &&
 568               x->timeout == y->timeout &&
 569               a->extensions == b->extensions;
 570}
 571
 572static const struct ip_set_type_variant set_variant = {
 573        .kadt   = list_set_kadt,
 574        .uadt   = list_set_uadt,
 575        .adt    = {
 576                [IPSET_ADD] = list_set_uadd,
 577                [IPSET_DEL] = list_set_udel,
 578                [IPSET_TEST] = list_set_utest,
 579        },
 580        .destroy = list_set_destroy,
 581        .flush  = list_set_flush,
 582        .head   = list_set_head,
 583        .list   = list_set_list,
 584        .same_set = list_set_same_set,
 585};
 586
 587static void
 588list_set_gc(unsigned long ul_set)
 589{
 590        struct ip_set *set = (struct ip_set *) ul_set;
 591        struct list_set *map = set->data;
 592
 593        write_lock_bh(&set->lock);
 594        set_cleanup_entries(set);
 595        write_unlock_bh(&set->lock);
 596
 597        map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
 598        add_timer(&map->gc);
 599}
 600
 601static void
 602list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
 603{
 604        struct list_set *map = set->data;
 605
 606        init_timer(&map->gc);
 607        map->gc.data = (unsigned long) set;
 608        map->gc.function = gc;
 609        map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
 610        add_timer(&map->gc);
 611}
 612
 613/* Create list:set type of sets */
 614
 615static struct list_set *
 616init_list_set(struct ip_set *set, u32 size, size_t dsize,
 617              unsigned long timeout)
 618{
 619        struct list_set *map;
 620        struct set_elem *e;
 621        u32 i;
 622
 623        map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
 624        if (!map)
 625                return NULL;
 626
 627        map->size = size;
 628        map->dsize = dsize;
 629        map->timeout = timeout;
 630        set->data = map;
 631
 632        for (i = 0; i < size; i++) {
 633                e = list_set_elem(map, i);
 634                e->id = IPSET_INVALID_ID;
 635        }
 636
 637        return map;
 638}
 639
 640static int
 641list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
 642{
 643        struct list_set *map;
 644        u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0;
 645        unsigned long timeout = 0;
 646
 647        if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
 648                     !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 649                     !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
 650                return -IPSET_ERR_PROTOCOL;
 651
 652        if (tb[IPSET_ATTR_SIZE])
 653                size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
 654        if (size < IP_SET_LIST_MIN_SIZE)
 655                size = IP_SET_LIST_MIN_SIZE;
 656
 657        if (tb[IPSET_ATTR_CADT_FLAGS])
 658                cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
 659        if (tb[IPSET_ATTR_TIMEOUT])
 660                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
 661        set->variant = &set_variant;
 662        if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
 663                set->extensions |= IPSET_EXT_COUNTER;
 664                if (tb[IPSET_ATTR_TIMEOUT]) {
 665                        map = init_list_set(set, size,
 666                                        sizeof(struct setct_elem), timeout);
 667                        if (!map)
 668                                return -ENOMEM;
 669                        set->extensions |= IPSET_EXT_TIMEOUT;
 670                        map->offset[IPSET_OFFSET_TIMEOUT] =
 671                                offsetof(struct setct_elem, timeout);
 672                        map->offset[IPSET_OFFSET_COUNTER] =
 673                                offsetof(struct setct_elem, counter);
 674                        list_set_gc_init(set, list_set_gc);
 675                } else {
 676                        map = init_list_set(set, size,
 677                                            sizeof(struct setc_elem), 0);
 678                        if (!map)
 679                                return -ENOMEM;
 680                        map->offset[IPSET_OFFSET_COUNTER] =
 681                                offsetof(struct setc_elem, counter);
 682                }
 683        } else if (tb[IPSET_ATTR_TIMEOUT]) {
 684                map = init_list_set(set, size,
 685                                    sizeof(struct sett_elem), timeout);
 686                if (!map)
 687                        return -ENOMEM;
 688                set->extensions |= IPSET_EXT_TIMEOUT;
 689                map->offset[IPSET_OFFSET_TIMEOUT] =
 690                        offsetof(struct sett_elem, timeout);
 691                list_set_gc_init(set, list_set_gc);
 692        } else {
 693                map = init_list_set(set, size, sizeof(struct set_elem), 0);
 694                if (!map)
 695                        return -ENOMEM;
 696        }
 697        return 0;
 698}
 699
 700static struct ip_set_type list_set_type __read_mostly = {
 701        .name           = "list:set",
 702        .protocol       = IPSET_PROTOCOL,
 703        .features       = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
 704        .dimension      = IPSET_DIM_ONE,
 705        .family         = NFPROTO_UNSPEC,
 706        .revision_min   = REVISION_MIN,
 707        .revision_max   = REVISION_MAX,
 708        .create         = list_set_create,
 709        .create_policy  = {
 710                [IPSET_ATTR_SIZE]       = { .type = NLA_U32 },
 711                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 712                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 713        },
 714        .adt_policy     = {
 715                [IPSET_ATTR_NAME]       = { .type = NLA_STRING,
 716                                            .len = IPSET_MAXNAMELEN },
 717                [IPSET_ATTR_NAMEREF]    = { .type = NLA_STRING,
 718                                            .len = IPSET_MAXNAMELEN },
 719                [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 720                [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 721                [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 722                [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 723                [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 724        },
 725        .me             = THIS_MODULE,
 726};
 727
 728static int __init
 729list_set_init(void)
 730{
 731        return ip_set_type_register(&list_set_type);
 732}
 733
 734static void __exit
 735list_set_fini(void)
 736{
 737        ip_set_type_unregister(&list_set_type);
 738}
 739
 740module_init(list_set_init);
 741module_exit(list_set_fini);
 742