linux/net/netfilter/nf_conntrack_labels.c
<<
>>
Prefs
   1/*
   2 * test/set flag bits stored in conntrack extension area.
   3 *
   4 * (C) 2013 Astaro GmbH & Co KG
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/export.h>
  12#include <linux/types.h>
  13
  14#include <net/netfilter/nf_conntrack_ecache.h>
  15#include <net/netfilter/nf_conntrack_labels.h>
  16
  17static unsigned int label_bits(const struct nf_conn_labels *l)
  18{
  19        unsigned int longs = l->words;
  20        return longs * BITS_PER_LONG;
  21}
  22
  23bool nf_connlabel_match(const struct nf_conn *ct, u16 bit)
  24{
  25        struct nf_conn_labels *labels = nf_ct_labels_find(ct);
  26
  27        if (!labels)
  28                return false;
  29
  30        return bit < label_bits(labels) && test_bit(bit, labels->bits);
  31}
  32EXPORT_SYMBOL_GPL(nf_connlabel_match);
  33
  34int nf_connlabel_set(struct nf_conn *ct, u16 bit)
  35{
  36        struct nf_conn_labels *labels = nf_ct_labels_find(ct);
  37
  38        if (!labels || bit >= label_bits(labels))
  39                return -ENOSPC;
  40
  41        if (test_bit(bit, labels->bits))
  42                return 0;
  43
  44        if (!test_and_set_bit(bit, labels->bits))
  45                nf_conntrack_event_cache(IPCT_LABEL, ct);
  46
  47        return 0;
  48}
  49EXPORT_SYMBOL_GPL(nf_connlabel_set);
  50
  51#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
  52static void replace_u32(u32 *address, u32 mask, u32 new)
  53{
  54        u32 old, tmp;
  55
  56        do {
  57                old = *address;
  58                tmp = (old & mask) ^ new;
  59        } while (cmpxchg(address, old, tmp) != old);
  60}
  61
  62int nf_connlabels_replace(struct nf_conn *ct,
  63                          const u32 *data,
  64                          const u32 *mask, unsigned int words32)
  65{
  66        struct nf_conn_labels *labels;
  67        unsigned int size, i;
  68        u32 *dst;
  69
  70        labels = nf_ct_labels_find(ct);
  71        if (!labels)
  72                return -ENOSPC;
  73
  74        size = labels->words * sizeof(long);
  75        if (size < (words32 * sizeof(u32)))
  76                words32 = size / sizeof(u32);
  77
  78        dst = (u32 *) labels->bits;
  79        if (words32) {
  80                for (i = 0; i < words32; i++)
  81                        replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
  82        }
  83
  84        size /= sizeof(u32);
  85        for (i = words32; i < size; i++) /* pad */
  86                replace_u32(&dst[i], 0, 0);
  87
  88        nf_conntrack_event_cache(IPCT_LABEL, ct);
  89        return 0;
  90}
  91EXPORT_SYMBOL_GPL(nf_connlabels_replace);
  92#endif
  93
  94static struct nf_ct_ext_type labels_extend __read_mostly = {
  95        .len    = sizeof(struct nf_conn_labels),
  96        .align  = __alignof__(struct nf_conn_labels),
  97        .id     = NF_CT_EXT_LABELS,
  98};
  99
 100int nf_conntrack_labels_init(void)
 101{
 102        return nf_ct_extend_register(&labels_extend);
 103}
 104
 105void nf_conntrack_labels_fini(void)
 106{
 107        nf_ct_extend_unregister(&labels_extend);
 108}
 109