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