Loading...
Note: File does not exist in v4.10.11.
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * NETLINK Policy advertisement to userspace
4 *
5 * Authors: Johannes Berg <johannes@sipsolutions.net>
6 *
7 * Copyright 2019 Intel Corporation
8 */
9
10#include <linux/kernel.h>
11#include <linux/errno.h>
12#include <linux/types.h>
13#include <net/netlink.h>
14
15#define INITIAL_POLICIES_ALLOC 10
16
17struct nl_policy_dump {
18 unsigned int policy_idx;
19 unsigned int attr_idx;
20 unsigned int n_alloc;
21 struct {
22 const struct nla_policy *policy;
23 unsigned int maxtype;
24 } policies[];
25};
26
27static int add_policy(struct nl_policy_dump **statep,
28 const struct nla_policy *policy,
29 unsigned int maxtype)
30{
31 struct nl_policy_dump *state = *statep;
32 unsigned int n_alloc, i;
33
34 if (!policy || !maxtype)
35 return 0;
36
37 for (i = 0; i < state->n_alloc; i++) {
38 if (state->policies[i].policy == policy)
39 return 0;
40
41 if (!state->policies[i].policy) {
42 state->policies[i].policy = policy;
43 state->policies[i].maxtype = maxtype;
44 return 0;
45 }
46 }
47
48 n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC;
49 state = krealloc(state, struct_size(state, policies, n_alloc),
50 GFP_KERNEL);
51 if (!state)
52 return -ENOMEM;
53
54 memset(&state->policies[state->n_alloc], 0,
55 flex_array_size(state, policies, n_alloc - state->n_alloc));
56
57 state->policies[state->n_alloc].policy = policy;
58 state->policies[state->n_alloc].maxtype = maxtype;
59 state->n_alloc = n_alloc;
60 *statep = state;
61
62 return 0;
63}
64
65static unsigned int get_policy_idx(struct nl_policy_dump *state,
66 const struct nla_policy *policy)
67{
68 unsigned int i;
69
70 for (i = 0; i < state->n_alloc; i++) {
71 if (state->policies[i].policy == policy)
72 return i;
73 }
74
75 WARN_ON_ONCE(1);
76 return -1;
77}
78
79int netlink_policy_dump_start(const struct nla_policy *policy,
80 unsigned int maxtype,
81 unsigned long *_state)
82{
83 struct nl_policy_dump *state;
84 unsigned int policy_idx;
85 int err;
86
87 if (*_state)
88 return 0;
89
90 /*
91 * walk the policies and nested ones first, and build
92 * a linear list of them.
93 */
94
95 state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
96 GFP_KERNEL);
97 if (!state)
98 return -ENOMEM;
99 state->n_alloc = INITIAL_POLICIES_ALLOC;
100
101 err = add_policy(&state, policy, maxtype);
102 if (err)
103 return err;
104
105 for (policy_idx = 0;
106 policy_idx < state->n_alloc && state->policies[policy_idx].policy;
107 policy_idx++) {
108 const struct nla_policy *policy;
109 unsigned int type;
110
111 policy = state->policies[policy_idx].policy;
112
113 for (type = 0;
114 type <= state->policies[policy_idx].maxtype;
115 type++) {
116 switch (policy[type].type) {
117 case NLA_NESTED:
118 case NLA_NESTED_ARRAY:
119 err = add_policy(&state,
120 policy[type].nested_policy,
121 policy[type].len);
122 if (err)
123 return err;
124 break;
125 default:
126 break;
127 }
128 }
129 }
130
131 *_state = (unsigned long)state;
132
133 return 0;
134}
135
136static bool netlink_policy_dump_finished(struct nl_policy_dump *state)
137{
138 return state->policy_idx >= state->n_alloc ||
139 !state->policies[state->policy_idx].policy;
140}
141
142bool netlink_policy_dump_loop(unsigned long _state)
143{
144 struct nl_policy_dump *state = (void *)_state;
145
146 return !netlink_policy_dump_finished(state);
147}
148
149int netlink_policy_dump_write(struct sk_buff *skb, unsigned long _state)
150{
151 struct nl_policy_dump *state = (void *)_state;
152 const struct nla_policy *pt;
153 struct nlattr *policy, *attr;
154 enum netlink_attribute_type type;
155 bool again;
156
157send_attribute:
158 again = false;
159
160 pt = &state->policies[state->policy_idx].policy[state->attr_idx];
161
162 policy = nla_nest_start(skb, state->policy_idx);
163 if (!policy)
164 return -ENOBUFS;
165
166 attr = nla_nest_start(skb, state->attr_idx);
167 if (!attr)
168 goto nla_put_failure;
169
170 switch (pt->type) {
171 default:
172 case NLA_UNSPEC:
173 case NLA_REJECT:
174 /* skip - use NLA_MIN_LEN to advertise such */
175 nla_nest_cancel(skb, policy);
176 again = true;
177 goto next;
178 case NLA_NESTED:
179 type = NL_ATTR_TYPE_NESTED;
180 fallthrough;
181 case NLA_NESTED_ARRAY:
182 if (pt->type == NLA_NESTED_ARRAY)
183 type = NL_ATTR_TYPE_NESTED_ARRAY;
184 if (pt->nested_policy && pt->len &&
185 (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
186 get_policy_idx(state, pt->nested_policy)) ||
187 nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
188 pt->len)))
189 goto nla_put_failure;
190 break;
191 case NLA_U8:
192 case NLA_U16:
193 case NLA_U32:
194 case NLA_U64:
195 case NLA_MSECS: {
196 struct netlink_range_validation range;
197
198 if (pt->type == NLA_U8)
199 type = NL_ATTR_TYPE_U8;
200 else if (pt->type == NLA_U16)
201 type = NL_ATTR_TYPE_U16;
202 else if (pt->type == NLA_U32)
203 type = NL_ATTR_TYPE_U32;
204 else
205 type = NL_ATTR_TYPE_U64;
206
207 nla_get_range_unsigned(pt, &range);
208
209 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
210 range.min, NL_POLICY_TYPE_ATTR_PAD) ||
211 nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
212 range.max, NL_POLICY_TYPE_ATTR_PAD))
213 goto nla_put_failure;
214 break;
215 }
216 case NLA_S8:
217 case NLA_S16:
218 case NLA_S32:
219 case NLA_S64: {
220 struct netlink_range_validation_signed range;
221
222 if (pt->type == NLA_S8)
223 type = NL_ATTR_TYPE_S8;
224 else if (pt->type == NLA_S16)
225 type = NL_ATTR_TYPE_S16;
226 else if (pt->type == NLA_S32)
227 type = NL_ATTR_TYPE_S32;
228 else
229 type = NL_ATTR_TYPE_S64;
230
231 nla_get_range_signed(pt, &range);
232
233 if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
234 range.min, NL_POLICY_TYPE_ATTR_PAD) ||
235 nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
236 range.max, NL_POLICY_TYPE_ATTR_PAD))
237 goto nla_put_failure;
238 break;
239 }
240 case NLA_BITFIELD32:
241 type = NL_ATTR_TYPE_BITFIELD32;
242 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
243 pt->bitfield32_valid))
244 goto nla_put_failure;
245 break;
246 case NLA_EXACT_LEN:
247 type = NL_ATTR_TYPE_BINARY;
248 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len) ||
249 nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH, pt->len))
250 goto nla_put_failure;
251 break;
252 case NLA_STRING:
253 case NLA_NUL_STRING:
254 case NLA_BINARY:
255 if (pt->type == NLA_STRING)
256 type = NL_ATTR_TYPE_STRING;
257 else if (pt->type == NLA_NUL_STRING)
258 type = NL_ATTR_TYPE_NUL_STRING;
259 else
260 type = NL_ATTR_TYPE_BINARY;
261 if (pt->len && nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
262 pt->len))
263 goto nla_put_failure;
264 break;
265 case NLA_MIN_LEN:
266 type = NL_ATTR_TYPE_BINARY;
267 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH, pt->len))
268 goto nla_put_failure;
269 break;
270 case NLA_FLAG:
271 type = NL_ATTR_TYPE_FLAG;
272 break;
273 }
274
275 if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
276 goto nla_put_failure;
277
278 /* finish and move state to next attribute */
279 nla_nest_end(skb, attr);
280 nla_nest_end(skb, policy);
281
282next:
283 state->attr_idx += 1;
284 if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
285 state->attr_idx = 0;
286 state->policy_idx++;
287 }
288
289 if (again) {
290 if (netlink_policy_dump_finished(state))
291 return -ENODATA;
292 goto send_attribute;
293 }
294
295 return 0;
296
297nla_put_failure:
298 nla_nest_cancel(skb, policy);
299 return -ENOBUFS;
300}
301
302void netlink_policy_dump_free(unsigned long _state)
303{
304 struct nl_policy_dump *state = (void *)_state;
305
306 kfree(state);
307}