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 17 static spinlock_t nf_connlabels_lock; 18 19 static 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 33 int 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 } 62 EXPORT_SYMBOL_GPL(nf_connlabels_replace); 63 64 int 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 } 75 EXPORT_SYMBOL_GPL(nf_connlabels_get); 76 77 void 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 } 83 EXPORT_SYMBOL_GPL(nf_connlabels_put); 84 85 static 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 91 int 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 99 void nf_conntrack_labels_fini(void) 100 { 101 nf_ct_extend_unregister(&labels_extend); 102 } 103