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 spinlock_t nf_connlabels_lock;
  18
  19static unsigned int label_bits(const struct nf_conn_labels *l)
  20{
  21        unsigned int longs = l->words;
  22        return longs * BITS_PER_LONG;
  23}
  24
  25bool nf_connlabel_match(const struct nf_conn *ct, u16 bit)
  26{
  27        struct nf_conn_labels *labels = nf_ct_labels_find(ct);
  28
  29        if (!labels)
  30                return false;
  31
  32        return bit < label_bits(labels) && test_bit(bit, labels->bits);
  33}
  34EXPORT_SYMBOL_GPL(nf_connlabel_match);
  35
  36int nf_connlabel_set(struct nf_conn *ct, u16 bit)
  37{
  38        struct nf_conn_labels *labels = nf_ct_labels_find(ct);
  39
  40        if (!labels || bit >= label_bits(labels))
  41                return -ENOSPC;
  42
  43        if (test_bit(bit, labels->bits))
  44                return 0;
  45
  46        if (!test_and_set_bit(bit, labels->bits))
  47                nf_conntrack_event_cache(IPCT_LABEL, ct);
  48
  49        return 0;
  50}
  51EXPORT_SYMBOL_GPL(nf_connlabel_set);
  52
  53static void replace_u32(u32 *address, u32 mask, u32 new)
  54{
  55        u32 old, tmp;
  56
  57        do {
  58                old = *address;
  59                tmp = (old & mask) ^ new;
  60        } while (cmpxchg(address, old, tmp) != old);
  61}
  62
  63int nf_connlabels_replace(struct nf_conn *ct,
  64                          const u32 *data,
  65                          const u32 *mask, unsigned int words32)
  66{
  67        struct nf_conn_labels *labels;
  68        unsigned int size, i;
  69        u32 *dst;
  70
  71        labels = nf_ct_labels_find(ct);
  72        if (!labels)
  73                return -ENOSPC;
  74
  75        size = labels->words * sizeof(long);
  76        if (size < (words32 * sizeof(u32)))
  77                words32 = size / sizeof(u32);
  78
  79        dst = (u32 *) labels->bits;
  80        if (words32) {
  81                for (i = 0; i < words32; i++)
  82                        replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
  83        }
  84
  85        size /= sizeof(u32);
  86        for (i = words32; i < size; i++) /* pad */
  87                replace_u32(&dst[i], 0, 0);
  88
  89        nf_conntrack_event_cache(IPCT_LABEL, ct);
  90        return 0;
  91}
  92EXPORT_SYMBOL_GPL(nf_connlabels_replace);
  93
  94int nf_connlabels_get(struct net *net, unsigned int n_bits)
  95{
  96        size_t words;
  97
  98        if (n_bits > (NF_CT_LABELS_MAX_SIZE * BITS_PER_BYTE))
  99                return -ERANGE;
 100
 101        words = BITS_TO_LONGS(n_bits);
 102
 103        spin_lock(&nf_connlabels_lock);
 104        net->ct.labels_used++;
 105        if (words > net->ct.label_words)
 106                net->ct.label_words = words;
 107        spin_unlock(&nf_connlabels_lock);
 108
 109        return 0;
 110}
 111EXPORT_SYMBOL_GPL(nf_connlabels_get);
 112
 113void nf_connlabels_put(struct net *net)
 114{
 115        spin_lock(&nf_connlabels_lock);
 116        net->ct.labels_used--;
 117        if (net->ct.labels_used == 0)
 118                net->ct.label_words = 0;
 119        spin_unlock(&nf_connlabels_lock);
 120}
 121EXPORT_SYMBOL_GPL(nf_connlabels_put);
 122
 123static struct nf_ct_ext_type labels_extend __read_mostly = {
 124        .len    = sizeof(struct nf_conn_labels),
 125        .align  = __alignof__(struct nf_conn_labels),
 126        .id     = NF_CT_EXT_LABELS,
 127};
 128
 129int nf_conntrack_labels_init(void)
 130{
 131        spin_lock_init(&nf_connlabels_lock);
 132        return nf_ct_extend_register(&labels_extend);
 133}
 134
 135void nf_conntrack_labels_fini(void)
 136{
 137        nf_ct_extend_unregister(&labels_extend);
 138}
 139