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