xref: /aosp_15_r20/external/ethtool/netlink/bitset.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /*
2  * bitset.h - netlink bitset helpers
3  *
4  * Functions for easier handling of ethtool netlink bitset attributes.
5  */
6 
7 #include <stdio.h>
8 #include <errno.h>
9 
10 #include "../common.h"
11 #include "netlink.h"
12 #include "bitset.h"
13 
bitset_get_count(const struct nlattr * bitset,int * retptr)14 uint32_t bitset_get_count(const struct nlattr *bitset, int *retptr)
15 {
16 	const struct nlattr *attr;
17 
18 	mnl_attr_for_each_nested(attr, bitset) {
19 		if (mnl_attr_get_type(attr) != ETHTOOL_A_BITSET_SIZE)
20 			continue;
21 		*retptr = 0;
22 		return mnl_attr_get_u32(attr);
23 	}
24 
25 	*retptr = -EFAULT;
26 	return 0;
27 }
28 
bitset_is_compact(const struct nlattr * bitset)29 bool bitset_is_compact(const struct nlattr *bitset)
30 {
31 	const struct nlattr *attr;
32 
33 	mnl_attr_for_each_nested(attr, bitset) {
34 		switch(mnl_attr_get_type(attr)) {
35 		case ETHTOOL_A_BITSET_BITS:
36 			return 0;
37 		case ETHTOOL_A_BITSET_VALUE:
38 		case ETHTOOL_A_BITSET_MASK:
39 			return 1;
40 		}
41 	}
42 
43 	return false;
44 }
45 
bitset_get_bit(const struct nlattr * bitset,bool mask,unsigned int idx,int * retptr)46 bool bitset_get_bit(const struct nlattr *bitset, bool mask, unsigned int idx,
47 		    int *retptr)
48 {
49 	const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
50 	DECLARE_ATTR_TB_INFO(bitset_tb);
51 	const struct nlattr *bits;
52 	const struct nlattr *bit;
53 	bool nomask;
54 	int ret;
55 
56 	*retptr = 0;
57 	ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
58 	if (ret < 0)
59 		goto err;
60 
61 	nomask = bitset_tb[ETHTOOL_A_BITSET_NOMASK];
62 	if (mask && nomask) {
63 		/* Trying to determine if a bit is set in the mask of a "no
64 		 * mask" bitset doesn't make sense.
65 		 */
66 		ret = -EFAULT;
67 		goto err;
68 	}
69 
70 	bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] :
71 		      bitset_tb[ETHTOOL_A_BITSET_VALUE];
72 	if (bits) {
73 		const uint32_t *bitmap =
74 			(const uint32_t *)mnl_attr_get_payload(bits);
75 
76 		if (idx >= 8 * mnl_attr_get_payload_len(bits))
77 			return false;
78 		return bitmap[idx / 32] & (1U << (idx % 32));
79 	}
80 
81 	bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
82 	if (!bits)
83 		goto err;
84 	mnl_attr_for_each_nested(bit, bits) {
85 		const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
86 		DECLARE_ATTR_TB_INFO(tb);
87 		unsigned int my_idx;
88 
89 		if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
90 			continue;
91 		ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
92 		if (ret < 0)
93 			goto err;
94 		ret = -EFAULT;
95 		if (!tb[ETHTOOL_A_BITSET_BIT_INDEX])
96 			goto err;
97 
98 		my_idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
99 		if (my_idx == idx)
100 			return mask || nomask || tb[ETHTOOL_A_BITSET_BIT_VALUE];
101 	}
102 
103 	return false;
104 err:
105 	fprintf(stderr, "malformed netlink message (bitset)\n");
106 	*retptr = ret;
107 	return false;
108 }
109 
bitset_is_empty(const struct nlattr * bitset,bool mask,int * retptr)110 bool bitset_is_empty(const struct nlattr *bitset, bool mask, int *retptr)
111 {
112 	const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
113 	DECLARE_ATTR_TB_INFO(bitset_tb);
114 	const struct nlattr *bits;
115 	const struct nlattr *bit;
116 	int ret;
117 
118 	*retptr = 0;
119 	ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
120 	if (ret < 0)
121 		goto err;
122 
123 	bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] :
124 		      bitset_tb[ETHTOOL_A_BITSET_VALUE];
125 	if (bits) {
126 		const uint32_t *bitmap =
127 			(const uint32_t *)mnl_attr_get_payload(bits);
128 		unsigned int n = mnl_attr_get_payload_len(bits);
129 		unsigned int i;
130 
131 		ret = -EFAULT;
132 		if (n % 4)
133 			goto err;
134 		for (i = 0; i < n / 4; i++)
135 			if (bitmap[i])
136 				return false;
137 		return true;
138 	}
139 
140 	bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
141 	if (!bits)
142 		goto err;
143 	mnl_attr_for_each_nested(bit, bits) {
144 		const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
145 		DECLARE_ATTR_TB_INFO(tb);
146 
147 		if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
148 			continue;
149 		if (mask || bitset_tb[ETHTOOL_A_BITSET_NOMASK])
150 			return false;
151 
152 		ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
153 		if (ret < 0)
154 			goto err;
155 		if (tb[ETHTOOL_A_BITSET_BIT_VALUE])
156 			return false;
157 	}
158 
159 	return true;
160 err:
161 	fprintf(stderr, "malformed netlink message (bitset)\n");
162 	*retptr = ret;
163 	return true;
164 }
165 
get_compact_bitset_attr(const struct nlattr * bitset,uint16_t type)166 static uint32_t *get_compact_bitset_attr(const struct nlattr *bitset,
167 					 uint16_t type)
168 {
169 	const struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1] = {};
170 	DECLARE_ATTR_TB_INFO(tb);
171 	unsigned int count;
172 	int ret;
173 
174 	ret = mnl_attr_parse_nested(bitset, attr_cb, &tb_info);
175 	if (ret < 0)
176 		return NULL;
177 	if (!tb[ETHTOOL_A_BITSET_SIZE] || !tb[ETHTOOL_A_BITSET_VALUE] ||
178 	    !tb[type])
179 		return NULL;
180 	count = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_SIZE]);
181 	if (8 * mnl_attr_get_payload_len(tb[type]) < count)
182 		return NULL;
183 
184 	return mnl_attr_get_payload(tb[type]);
185 }
186 
get_compact_bitset_value(const struct nlattr * bitset)187 uint32_t *get_compact_bitset_value(const struct nlattr *bitset)
188 {
189 	return get_compact_bitset_attr(bitset, ETHTOOL_A_BITSET_VALUE);
190 }
191 
get_compact_bitset_mask(const struct nlattr * bitset)192 uint32_t *get_compact_bitset_mask(const struct nlattr *bitset)
193 {
194 	return get_compact_bitset_attr(bitset, ETHTOOL_A_BITSET_MASK);
195 }
196 
walk_bitset(const struct nlattr * bitset,const struct stringset * labels,bitset_walk_callback cb,void * data)197 int walk_bitset(const struct nlattr *bitset, const struct stringset *labels,
198 		bitset_walk_callback cb, void *data)
199 {
200 	const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {};
201 	DECLARE_ATTR_TB_INFO(bitset_tb);
202 	const struct nlattr *bits;
203 	const struct nlattr *bit;
204 	bool is_list;
205 	int ret;
206 
207 	ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info);
208 	if (ret < 0)
209 		return ret;
210 	is_list = bitset_tb[ETHTOOL_A_BITSET_NOMASK];
211 
212 	bits = bitset_tb[ETHTOOL_A_BITSET_VALUE];
213 	if (bits) {
214 		const struct nlattr *mask = bitset_tb[ETHTOOL_A_BITSET_MASK];
215 		unsigned int count, nwords, idx;
216 		uint32_t *val_bm;
217 		uint32_t *mask_bm;
218 
219 		if (!bitset_tb[ETHTOOL_A_BITSET_SIZE])
220 			return -EFAULT;
221 		count = mnl_attr_get_u32(bitset_tb[ETHTOOL_A_BITSET_SIZE]);
222 		nwords = (count + 31) / 32;
223 		if ((mnl_attr_get_payload_len(bits) / 4 < nwords) ||
224 		    (mask && mnl_attr_get_payload_len(mask) / 4 < nwords))
225 			return -EFAULT;
226 
227 		val_bm = mnl_attr_get_payload(bits);
228 		mask_bm = mask ? mnl_attr_get_payload(mask) : NULL;
229 		for (idx = 0; idx < count; idx++)
230 			if (!mask_bm || (mask_bm[idx / 32] & (1 << (idx % 32))))
231 				cb(idx, get_string(labels, idx),
232 				   val_bm[idx / 32] & (1 << (idx % 32)), data);
233 		return 0;
234 	}
235 
236 	bits = bitset_tb[ETHTOOL_A_BITSET_BITS];
237 	if (!bits)
238 		return -EFAULT;
239 	mnl_attr_for_each_nested(bit, bits) {
240 		const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {};
241 		DECLARE_ATTR_TB_INFO(tb);
242 		const char *name;
243 		unsigned int idx;
244 
245 		if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT)
246 			continue;
247 
248 		ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info);
249 		if (ret < 0 || !tb[ETHTOOL_A_BITSET_BIT_INDEX] ||
250 		    !tb[ETHTOOL_A_BITSET_BIT_NAME])
251 			return -EFAULT;
252 
253 		idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]);
254 		name = mnl_attr_get_str(tb[ETHTOOL_A_BITSET_BIT_NAME]);
255 		cb(idx, name, is_list || tb[ETHTOOL_A_BITSET_BIT_VALUE], data);
256 	}
257 
258 	return 0;
259 }
260