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 int replace_u32(u32 *address, u32 mask, u32 new)
  20{
  21        u32 old, tmp;
  22
  23        do {
  24                old = *address;
  25                tmp = (old & mask) ^ new;
  26                if (old == tmp)
  27                        return 0;
  28        } while (cmpxchg(address, old, tmp) != old);
  29
  30        return 1;
  31}
  32
  33int nf_connlabels_replace(struct nf_conn *ct,
  34                          const u32 *data,
  35                          const u32 *mask, unsigned int words32)
  36{
  37        struct nf_conn_labels *labels;
  38        unsigned int size, i;
  39        int changed = 0;
  40        u32 *dst;
  41
  42        labels = nf_ct_labels_find(ct);
  43        if (!labels)
  44                return -ENOSPC;
  45
  46        size = sizeof(labels->bits);
  47        if (size < (words32 * sizeof(u32)))
  48                words32 = size / sizeof(u32);
  49
  50        dst = (u32 *) labels->bits;
  51        for (i = 0; i < words32; i++)
  52                changed |= replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
  53
  54        size /= sizeof(u32);
  55        for (i = words32; i < size; i++) /* pad */
  56                replace_u32(&dst[i], 0, 0);
  57
  58        if (changed)
  59                nf_conntrack_event_cache(IPCT_LABEL, ct);
  60        return 0;
  61}
  62EXPORT_SYMBOL_GPL(nf_connlabels_replace);
  63
  64int nf_connlabels_get(struct net *net, unsigned int bits)
  65{
  66        if (BIT_WORD(bits) >= NF_CT_LABELS_MAX_SIZE / sizeof(long))
  67                return -ERANGE;
  68
  69        spin_lock(&nf_connlabels_lock);
  70        net->ct.labels_used++;
  71        spin_unlock(&nf_connlabels_lock);
  72
  73        return 0;
  74}
  75EXPORT_SYMBOL_GPL(nf_connlabels_get);
  76
  77void nf_connlabels_put(struct net *net)
  78{
  79        spin_lock(&nf_connlabels_lock);
  80        net->ct.labels_used--;
  81        spin_unlock(&nf_connlabels_lock);
  82}
  83EXPORT_SYMBOL_GPL(nf_connlabels_put);
  84
  85static const struct nf_ct_ext_type labels_extend = {
  86        .len    = sizeof(struct nf_conn_labels),
  87        .align  = __alignof__(struct nf_conn_labels),
  88        .id     = NF_CT_EXT_LABELS,
  89};
  90
  91int nf_conntrack_labels_init(void)
  92{
  93        BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE / sizeof(long) >= U8_MAX);
  94
  95        spin_lock_init(&nf_connlabels_lock);
  96        return nf_ct_extend_register(&labels_extend);
  97}
  98
  99void nf_conntrack_labels_fini(void)
 100{
 101        nf_ct_extend_unregister(&labels_extend);
 102}
 103