]> Git Repo - linux.git/blob - net/netlink/policy.c
arch, drivers: replace for_each_membock() with for_each_mem_range()
[linux.git] / net / netlink / policy.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * NETLINK      Policy advertisement to userspace
4  *
5  *              Authors:        Johannes Berg <[email protected]>
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
17 struct 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
27 static 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
65 static 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
79 int 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
136 static 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
142 bool 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
149 int 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
157 send_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
282 next:
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
297 nla_put_failure:
298         nla_nest_cancel(skb, policy);
299         return -ENOBUFS;
300 }
301
302 void netlink_policy_dump_free(unsigned long _state)
303 {
304         struct nl_policy_dump *state = (void *)_state;
305
306         kfree(state);
307 }
This page took 0.078673 seconds and 4 git commands to generate.