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