linux/net/netfilter/nf_conntrack_labels.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * test/set flag bits stored in conntrack extension area.
   4 *
   5 * (C) 2013 Astaro GmbH & Co KG
   6 */
   7
   8#include <linux/export.h>
   9#include <linux/types.h>
  10
  11#include <net/netfilter/nf_conntrack_ecache.h>
  12#include <net/netfilter/nf_conntrack_labels.h>
  13
  14static DEFINE_SPINLOCK(nf_connlabels_lock);
  15
  16static int replace_u32(u32 *address, u32 mask, u32 new)
  17{
  18        u32 old, tmp;
  19
  20        do {
  21                old = *address;
  22                tmp = (old & mask) ^ new;
  23                if (old == tmp)
  24                        return 0;
  25        } while (cmpxchg(address, old, tmp) != old);
  26
  27        return 1;
  28}
  29
  30int nf_connlabels_replace(struct nf_conn *ct,
  31                          const u32 *data,
  32                          const u32 *mask, unsigned int words32)
  33{
  34        struct nf_conn_labels *labels;
  35        unsigned int size, i;
  36        int changed = 0;
  37        u32 *dst;
  38
  39        labels = nf_ct_labels_find(ct);
  40        if (!labels)
  41                return -ENOSPC;
  42
  43        size = sizeof(labels->bits);
  44        if (size < (words32 * sizeof(u32)))
  45                words32 = size / sizeof(u32);
  46
  47        dst = (u32 *) labels->bits;
  48        for (i = 0; i < words32; i++)
  49                changed |= replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
  50
  51        size /= sizeof(u32);
  52        for (i = words32; i < size; i++) /* pad */
  53                replace_u32(&dst[i], 0, 0);
  54
  55        if (changed)
  56                nf_conntrack_event_cache(IPCT_LABEL, ct);
  57        return 0;
  58}
  59EXPORT_SYMBOL_GPL(nf_connlabels_replace);
  60
  61int nf_connlabels_get(struct net *net, unsigned int bits)
  62{
  63        if (BIT_WORD(bits) >= NF_CT_LABELS_MAX_SIZE / sizeof(long))
  64                return -ERANGE;
  65
  66        spin_lock(&nf_connlabels_lock);
  67        net->ct.labels_used++;
  68        spin_unlock(&nf_connlabels_lock);
  69
  70        return 0;
  71}
  72EXPORT_SYMBOL_GPL(nf_connlabels_get);
  73
  74void nf_connlabels_put(struct net *net)
  75{
  76        spin_lock(&nf_connlabels_lock);
  77        net->ct.labels_used--;
  78        spin_unlock(&nf_connlabels_lock);
  79}
  80EXPORT_SYMBOL_GPL(nf_connlabels_put);
  81
  82static const struct nf_ct_ext_type labels_extend = {
  83        .len    = sizeof(struct nf_conn_labels),
  84        .align  = __alignof__(struct nf_conn_labels),
  85        .id     = NF_CT_EXT_LABELS,
  86};
  87
  88int nf_conntrack_labels_init(void)
  89{
  90        BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE / sizeof(long) >= U8_MAX);
  91
  92        return nf_ct_extend_register(&labels_extend);
  93}
  94
  95void nf_conntrack_labels_fini(void)
  96{
  97        nf_ct_extend_unregister(&labels_extend);
  98}
  99