Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * test/set flag bits stored in conntrack extension area.
0004  *
0005  * (C) 2013 Astaro GmbH & Co KG
0006  */
0007 
0008 #include <linux/export.h>
0009 #include <linux/types.h>
0010 
0011 #include <net/netfilter/nf_conntrack_ecache.h>
0012 #include <net/netfilter/nf_conntrack_labels.h>
0013 
0014 static DEFINE_SPINLOCK(nf_connlabels_lock);
0015 
0016 static int replace_u32(u32 *address, u32 mask, u32 new)
0017 {
0018     u32 old, tmp;
0019 
0020     do {
0021         old = *address;
0022         tmp = (old & mask) ^ new;
0023         if (old == tmp)
0024             return 0;
0025     } while (cmpxchg(address, old, tmp) != old);
0026 
0027     return 1;
0028 }
0029 
0030 int nf_connlabels_replace(struct nf_conn *ct,
0031               const u32 *data,
0032               const u32 *mask, unsigned int words32)
0033 {
0034     struct nf_conn_labels *labels;
0035     unsigned int size, i;
0036     int changed = 0;
0037     u32 *dst;
0038 
0039     labels = nf_ct_labels_find(ct);
0040     if (!labels)
0041         return -ENOSPC;
0042 
0043     size = sizeof(labels->bits);
0044     if (size < (words32 * sizeof(u32)))
0045         words32 = size / sizeof(u32);
0046 
0047     dst = (u32 *) labels->bits;
0048     for (i = 0; i < words32; i++)
0049         changed |= replace_u32(&dst[i], mask ? ~mask[i] : 0, data[i]);
0050 
0051     size /= sizeof(u32);
0052     for (i = words32; i < size; i++) /* pad */
0053         replace_u32(&dst[i], 0, 0);
0054 
0055     if (changed)
0056         nf_conntrack_event_cache(IPCT_LABEL, ct);
0057     return 0;
0058 }
0059 EXPORT_SYMBOL_GPL(nf_connlabels_replace);
0060 
0061 int nf_connlabels_get(struct net *net, unsigned int bits)
0062 {
0063     if (BIT_WORD(bits) >= NF_CT_LABELS_MAX_SIZE / sizeof(long))
0064         return -ERANGE;
0065 
0066     spin_lock(&nf_connlabels_lock);
0067     net->ct.labels_used++;
0068     spin_unlock(&nf_connlabels_lock);
0069 
0070     BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE / sizeof(long) >= U8_MAX);
0071 
0072     return 0;
0073 }
0074 EXPORT_SYMBOL_GPL(nf_connlabels_get);
0075 
0076 void nf_connlabels_put(struct net *net)
0077 {
0078     spin_lock(&nf_connlabels_lock);
0079     net->ct.labels_used--;
0080     spin_unlock(&nf_connlabels_lock);
0081 }
0082 EXPORT_SYMBOL_GPL(nf_connlabels_put);