xref: /openbmc/linux/net/netlink/policy.c (revision d2681e93)
1d07dcf9aSJohannes Berg // SPDX-License-Identifier: GPL-2.0
2d07dcf9aSJohannes Berg /*
3d07dcf9aSJohannes Berg  * NETLINK      Policy advertisement to userspace
4d07dcf9aSJohannes Berg  *
5d07dcf9aSJohannes Berg  * 		Authors:	Johannes Berg <johannes@sipsolutions.net>
6d07dcf9aSJohannes Berg  *
7d07dcf9aSJohannes Berg  * Copyright 2019 Intel Corporation
8d07dcf9aSJohannes Berg  */
9d07dcf9aSJohannes Berg 
10d07dcf9aSJohannes Berg #include <linux/kernel.h>
11d07dcf9aSJohannes Berg #include <linux/errno.h>
12d07dcf9aSJohannes Berg #include <linux/types.h>
13d07dcf9aSJohannes Berg #include <net/netlink.h>
14d07dcf9aSJohannes Berg 
15d07dcf9aSJohannes Berg #define INITIAL_POLICIES_ALLOC	10
16d07dcf9aSJohannes Berg 
17adc84845SJakub Kicinski struct netlink_policy_dump_state {
18d07dcf9aSJohannes Berg 	unsigned int policy_idx;
19d07dcf9aSJohannes Berg 	unsigned int attr_idx;
20d07dcf9aSJohannes Berg 	unsigned int n_alloc;
21d07dcf9aSJohannes Berg 	struct {
22d07dcf9aSJohannes Berg 		const struct nla_policy *policy;
23d07dcf9aSJohannes Berg 		unsigned int maxtype;
24d07dcf9aSJohannes Berg 	} policies[];
25d07dcf9aSJohannes Berg };
26d07dcf9aSJohannes Berg 
27adc84845SJakub Kicinski static int add_policy(struct netlink_policy_dump_state **statep,
28d07dcf9aSJohannes Berg 		      const struct nla_policy *policy,
29d07dcf9aSJohannes Berg 		      unsigned int maxtype)
30d07dcf9aSJohannes Berg {
31adc84845SJakub Kicinski 	struct netlink_policy_dump_state *state = *statep;
32d07dcf9aSJohannes Berg 	unsigned int n_alloc, i;
33d07dcf9aSJohannes Berg 
34d07dcf9aSJohannes Berg 	if (!policy || !maxtype)
35d07dcf9aSJohannes Berg 		return 0;
36d07dcf9aSJohannes Berg 
37d07dcf9aSJohannes Berg 	for (i = 0; i < state->n_alloc; i++) {
38899b07c5SJohannes Berg 		if (state->policies[i].policy == policy &&
39899b07c5SJohannes Berg 		    state->policies[i].maxtype == maxtype)
40d07dcf9aSJohannes Berg 			return 0;
41d07dcf9aSJohannes Berg 
42d07dcf9aSJohannes Berg 		if (!state->policies[i].policy) {
43d07dcf9aSJohannes Berg 			state->policies[i].policy = policy;
44d07dcf9aSJohannes Berg 			state->policies[i].maxtype = maxtype;
45d07dcf9aSJohannes Berg 			return 0;
46d07dcf9aSJohannes Berg 		}
47d07dcf9aSJohannes Berg 	}
48d07dcf9aSJohannes Berg 
49d07dcf9aSJohannes Berg 	n_alloc = state->n_alloc + INITIAL_POLICIES_ALLOC;
50d07dcf9aSJohannes Berg 	state = krealloc(state, struct_size(state, policies, n_alloc),
51d07dcf9aSJohannes Berg 			 GFP_KERNEL);
52d07dcf9aSJohannes Berg 	if (!state)
53d07dcf9aSJohannes Berg 		return -ENOMEM;
54d07dcf9aSJohannes Berg 
55d1fb5559SJohannes Berg 	memset(&state->policies[state->n_alloc], 0,
56d1fb5559SJohannes Berg 	       flex_array_size(state, policies, n_alloc - state->n_alloc));
57d1fb5559SJohannes Berg 
58d07dcf9aSJohannes Berg 	state->policies[state->n_alloc].policy = policy;
59d07dcf9aSJohannes Berg 	state->policies[state->n_alloc].maxtype = maxtype;
60d07dcf9aSJohannes Berg 	state->n_alloc = n_alloc;
61d07dcf9aSJohannes Berg 	*statep = state;
62d07dcf9aSJohannes Berg 
63d07dcf9aSJohannes Berg 	return 0;
64d07dcf9aSJohannes Berg }
65d07dcf9aSJohannes Berg 
6604a351a6SJohannes Berg /**
6704a351a6SJohannes Berg  * netlink_policy_dump_get_policy_idx - retrieve policy index
6804a351a6SJohannes Berg  * @state: the policy dump state
6904a351a6SJohannes Berg  * @policy: the policy to find
7004a351a6SJohannes Berg  * @maxtype: the policy's maxattr
7104a351a6SJohannes Berg  *
7204a351a6SJohannes Berg  * Returns: the index of the given policy in the dump state
7304a351a6SJohannes Berg  *
7404a351a6SJohannes Berg  * Call this to find a policy index when you've added multiple and e.g.
7504a351a6SJohannes Berg  * need to tell userspace which command has which policy (by index).
7604a351a6SJohannes Berg  *
7704a351a6SJohannes Berg  * Note: this will WARN and return 0 if the policy isn't found, which
7804a351a6SJohannes Berg  *	 means it wasn't added in the first place, which would be an
7904a351a6SJohannes Berg  *	 internal consistency bug.
8004a351a6SJohannes Berg  */
8104a351a6SJohannes Berg int netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state *state,
82899b07c5SJohannes Berg 				       const struct nla_policy *policy,
83899b07c5SJohannes Berg 				       unsigned int maxtype)
84d07dcf9aSJohannes Berg {
85d07dcf9aSJohannes Berg 	unsigned int i;
86d07dcf9aSJohannes Berg 
8704a351a6SJohannes Berg 	if (WARN_ON(!policy || !maxtype))
8804a351a6SJohannes Berg                 return 0;
8904a351a6SJohannes Berg 
90d07dcf9aSJohannes Berg 	for (i = 0; i < state->n_alloc; i++) {
91899b07c5SJohannes Berg 		if (state->policies[i].policy == policy &&
92899b07c5SJohannes Berg 		    state->policies[i].maxtype == maxtype)
93d07dcf9aSJohannes Berg 			return i;
94d07dcf9aSJohannes Berg 	}
95d07dcf9aSJohannes Berg 
9604a351a6SJohannes Berg 	WARN_ON(1);
9704a351a6SJohannes Berg 	return 0;
98d07dcf9aSJohannes Berg }
99d07dcf9aSJohannes Berg 
10004a351a6SJohannes Berg static struct netlink_policy_dump_state *alloc_state(void)
101d07dcf9aSJohannes Berg {
102adc84845SJakub Kicinski 	struct netlink_policy_dump_state *state;
10304a351a6SJohannes Berg 
10404a351a6SJohannes Berg 	state = kzalloc(struct_size(state, policies, INITIAL_POLICIES_ALLOC),
10504a351a6SJohannes Berg 			GFP_KERNEL);
10604a351a6SJohannes Berg 	if (!state)
10704a351a6SJohannes Berg 		return ERR_PTR(-ENOMEM);
10804a351a6SJohannes Berg 	state->n_alloc = INITIAL_POLICIES_ALLOC;
10904a351a6SJohannes Berg 
11004a351a6SJohannes Berg 	return state;
11104a351a6SJohannes Berg }
11204a351a6SJohannes Berg 
11304a351a6SJohannes Berg /**
11404a351a6SJohannes Berg  * netlink_policy_dump_add_policy - add a policy to the dump
11504a351a6SJohannes Berg  * @pstate: state to add to, may be reallocated, must be %NULL the first time
11604a351a6SJohannes Berg  * @policy: the new policy to add to the dump
11704a351a6SJohannes Berg  * @maxtype: the new policy's max attr type
11804a351a6SJohannes Berg  *
11904a351a6SJohannes Berg  * Returns: 0 on success, a negative error code otherwise.
12004a351a6SJohannes Berg  *
12104a351a6SJohannes Berg  * Call this to allocate a policy dump state, and to add policies to it. This
12204a351a6SJohannes Berg  * should be called from the dump start() callback.
12304a351a6SJohannes Berg  *
12404a351a6SJohannes Berg  * Note: on failures, any previously allocated state is freed.
12504a351a6SJohannes Berg  */
12604a351a6SJohannes Berg int netlink_policy_dump_add_policy(struct netlink_policy_dump_state **pstate,
12704a351a6SJohannes Berg 				   const struct nla_policy *policy,
12804a351a6SJohannes Berg 				   unsigned int maxtype)
12904a351a6SJohannes Berg {
13004a351a6SJohannes Berg 	struct netlink_policy_dump_state *state = *pstate;
131d07dcf9aSJohannes Berg 	unsigned int policy_idx;
132d07dcf9aSJohannes Berg 	int err;
133d07dcf9aSJohannes Berg 
13404a351a6SJohannes Berg 	if (!state) {
13504a351a6SJohannes Berg 		state = alloc_state();
13604a351a6SJohannes Berg 		if (IS_ERR(state))
13704a351a6SJohannes Berg 			return PTR_ERR(state);
13804a351a6SJohannes Berg 	}
139d07dcf9aSJohannes Berg 
140d07dcf9aSJohannes Berg 	/*
141d07dcf9aSJohannes Berg 	 * walk the policies and nested ones first, and build
142d07dcf9aSJohannes Berg 	 * a linear list of them.
143d07dcf9aSJohannes Berg 	 */
144d07dcf9aSJohannes Berg 
145d07dcf9aSJohannes Berg 	err = add_policy(&state, policy, maxtype);
146d07dcf9aSJohannes Berg 	if (err)
147d07dcf9aSJohannes Berg 		return err;
148d07dcf9aSJohannes Berg 
149d07dcf9aSJohannes Berg 	for (policy_idx = 0;
150d07dcf9aSJohannes Berg 	     policy_idx < state->n_alloc && state->policies[policy_idx].policy;
151d07dcf9aSJohannes Berg 	     policy_idx++) {
152d07dcf9aSJohannes Berg 		const struct nla_policy *policy;
153d07dcf9aSJohannes Berg 		unsigned int type;
154d07dcf9aSJohannes Berg 
155d07dcf9aSJohannes Berg 		policy = state->policies[policy_idx].policy;
156d07dcf9aSJohannes Berg 
157d07dcf9aSJohannes Berg 		for (type = 0;
158d07dcf9aSJohannes Berg 		     type <= state->policies[policy_idx].maxtype;
159d07dcf9aSJohannes Berg 		     type++) {
160d07dcf9aSJohannes Berg 			switch (policy[type].type) {
161d07dcf9aSJohannes Berg 			case NLA_NESTED:
162d07dcf9aSJohannes Berg 			case NLA_NESTED_ARRAY:
163d07dcf9aSJohannes Berg 				err = add_policy(&state,
164d07dcf9aSJohannes Berg 						 policy[type].nested_policy,
165d07dcf9aSJohannes Berg 						 policy[type].len);
166d07dcf9aSJohannes Berg 				if (err)
167d07dcf9aSJohannes Berg 					return err;
168d07dcf9aSJohannes Berg 				break;
169d07dcf9aSJohannes Berg 			default:
170d07dcf9aSJohannes Berg 				break;
171d07dcf9aSJohannes Berg 			}
172d07dcf9aSJohannes Berg 		}
173d07dcf9aSJohannes Berg 	}
174d07dcf9aSJohannes Berg 
17504a351a6SJohannes Berg 	*pstate = state;
176d07dcf9aSJohannes Berg 	return 0;
177d07dcf9aSJohannes Berg }
178d07dcf9aSJohannes Berg 
179adc84845SJakub Kicinski static bool
180adc84845SJakub Kicinski netlink_policy_dump_finished(struct netlink_policy_dump_state *state)
181d07dcf9aSJohannes Berg {
182d07dcf9aSJohannes Berg 	return state->policy_idx >= state->n_alloc ||
183d07dcf9aSJohannes Berg 	       !state->policies[state->policy_idx].policy;
184d07dcf9aSJohannes Berg }
185d07dcf9aSJohannes Berg 
18604a351a6SJohannes Berg /**
18704a351a6SJohannes Berg  * netlink_policy_dump_loop - dumping loop indicator
18804a351a6SJohannes Berg  * @state: the policy dump state
18904a351a6SJohannes Berg  *
19004a351a6SJohannes Berg  * Returns: %true if the dump continues, %false otherwise
19104a351a6SJohannes Berg  *
19204a351a6SJohannes Berg  * Note: this frees the dump state when finishing
19304a351a6SJohannes Berg  */
194adc84845SJakub Kicinski bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state)
195d07dcf9aSJohannes Berg {
196949ca6b8SJohannes Berg 	return !netlink_policy_dump_finished(state);
197d07dcf9aSJohannes Berg }
198d07dcf9aSJohannes Berg 
199d2681e93SJohannes Berg static int
200d2681e93SJohannes Berg __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state,
201d2681e93SJohannes Berg 				 struct sk_buff *skb,
202d2681e93SJohannes Berg 				 const struct nla_policy *pt,
203d2681e93SJohannes Berg 				 int nestattr)
204d07dcf9aSJohannes Berg {
205d07dcf9aSJohannes Berg 	enum netlink_attribute_type type;
206d2681e93SJohannes Berg 	struct nlattr *attr;
207d07dcf9aSJohannes Berg 
208d2681e93SJohannes Berg 	attr = nla_nest_start(skb, nestattr);
209d07dcf9aSJohannes Berg 	if (!attr)
210d2681e93SJohannes Berg 		return -ENOBUFS;
211d07dcf9aSJohannes Berg 
212d07dcf9aSJohannes Berg 	switch (pt->type) {
213d07dcf9aSJohannes Berg 	default:
214d07dcf9aSJohannes Berg 	case NLA_UNSPEC:
215d07dcf9aSJohannes Berg 	case NLA_REJECT:
216d07dcf9aSJohannes Berg 		/* skip - use NLA_MIN_LEN to advertise such */
217d2681e93SJohannes Berg 		nla_nest_cancel(skb, attr);
218d2681e93SJohannes Berg 		return -ENODATA;
219d07dcf9aSJohannes Berg 	case NLA_NESTED:
220d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_NESTED;
221df561f66SGustavo A. R. Silva 		fallthrough;
222d07dcf9aSJohannes Berg 	case NLA_NESTED_ARRAY:
223d07dcf9aSJohannes Berg 		if (pt->type == NLA_NESTED_ARRAY)
224d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_NESTED_ARRAY;
225d2681e93SJohannes Berg 		if (state && pt->nested_policy && pt->len &&
226d07dcf9aSJohannes Berg 		    (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
22704a351a6SJohannes Berg 				 netlink_policy_dump_get_policy_idx(state,
22804a351a6SJohannes Berg 								    pt->nested_policy,
229899b07c5SJohannes Berg 								    pt->len)) ||
230d07dcf9aSJohannes Berg 		     nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
231d07dcf9aSJohannes Berg 				 pt->len)))
232d07dcf9aSJohannes Berg 			goto nla_put_failure;
233d07dcf9aSJohannes Berg 		break;
234d07dcf9aSJohannes Berg 	case NLA_U8:
235d07dcf9aSJohannes Berg 	case NLA_U16:
236d07dcf9aSJohannes Berg 	case NLA_U32:
237d07dcf9aSJohannes Berg 	case NLA_U64:
238d07dcf9aSJohannes Berg 	case NLA_MSECS: {
239d07dcf9aSJohannes Berg 		struct netlink_range_validation range;
240d07dcf9aSJohannes Berg 
241d07dcf9aSJohannes Berg 		if (pt->type == NLA_U8)
242d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U8;
243d07dcf9aSJohannes Berg 		else if (pt->type == NLA_U16)
244d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U16;
245d07dcf9aSJohannes Berg 		else if (pt->type == NLA_U32)
246d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U32;
247d07dcf9aSJohannes Berg 		else
248d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U64;
249d07dcf9aSJohannes Berg 
250bdbb4e29SJakub Kicinski 		if (pt->validation_type == NLA_VALIDATE_MASK) {
251bdbb4e29SJakub Kicinski 			if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK,
252bdbb4e29SJakub Kicinski 					      pt->mask,
253bdbb4e29SJakub Kicinski 					      NL_POLICY_TYPE_ATTR_PAD))
254bdbb4e29SJakub Kicinski 				goto nla_put_failure;
255bdbb4e29SJakub Kicinski 			break;
256bdbb4e29SJakub Kicinski 		}
257bdbb4e29SJakub Kicinski 
258d07dcf9aSJohannes Berg 		nla_get_range_unsigned(pt, &range);
259d07dcf9aSJohannes Berg 
260d07dcf9aSJohannes Berg 		if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
261d07dcf9aSJohannes Berg 				      range.min, NL_POLICY_TYPE_ATTR_PAD) ||
262d07dcf9aSJohannes Berg 		    nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
263d07dcf9aSJohannes Berg 				      range.max, NL_POLICY_TYPE_ATTR_PAD))
264d07dcf9aSJohannes Berg 			goto nla_put_failure;
265d07dcf9aSJohannes Berg 		break;
266d07dcf9aSJohannes Berg 	}
267d07dcf9aSJohannes Berg 	case NLA_S8:
268d07dcf9aSJohannes Berg 	case NLA_S16:
269d07dcf9aSJohannes Berg 	case NLA_S32:
270d07dcf9aSJohannes Berg 	case NLA_S64: {
271d07dcf9aSJohannes Berg 		struct netlink_range_validation_signed range;
272d07dcf9aSJohannes Berg 
273d07dcf9aSJohannes Berg 		if (pt->type == NLA_S8)
274d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S8;
275d07dcf9aSJohannes Berg 		else if (pt->type == NLA_S16)
276d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S16;
277d07dcf9aSJohannes Berg 		else if (pt->type == NLA_S32)
278d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S32;
279d07dcf9aSJohannes Berg 		else
280d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S64;
281d07dcf9aSJohannes Berg 
282d07dcf9aSJohannes Berg 		nla_get_range_signed(pt, &range);
283d07dcf9aSJohannes Berg 
284d07dcf9aSJohannes Berg 		if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
285d07dcf9aSJohannes Berg 				range.min, NL_POLICY_TYPE_ATTR_PAD) ||
286d07dcf9aSJohannes Berg 		    nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
287d07dcf9aSJohannes Berg 				range.max, NL_POLICY_TYPE_ATTR_PAD))
288d07dcf9aSJohannes Berg 			goto nla_put_failure;
289d07dcf9aSJohannes Berg 		break;
290d07dcf9aSJohannes Berg 	}
291d07dcf9aSJohannes Berg 	case NLA_BITFIELD32:
292d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_BITFIELD32;
293d07dcf9aSJohannes Berg 		if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
294d07dcf9aSJohannes Berg 				pt->bitfield32_valid))
295d07dcf9aSJohannes Berg 			goto nla_put_failure;
296d07dcf9aSJohannes Berg 		break;
297d07dcf9aSJohannes Berg 	case NLA_STRING:
298d07dcf9aSJohannes Berg 	case NLA_NUL_STRING:
299d07dcf9aSJohannes Berg 	case NLA_BINARY:
300d07dcf9aSJohannes Berg 		if (pt->type == NLA_STRING)
301d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_STRING;
302d07dcf9aSJohannes Berg 		else if (pt->type == NLA_NUL_STRING)
303d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_NUL_STRING;
304d07dcf9aSJohannes Berg 		else
305d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_BINARY;
3068aa26c57SJohannes Berg 
307c30a3c95SJohannes Berg 		if (pt->validation_type == NLA_VALIDATE_RANGE ||
308c30a3c95SJohannes Berg 		    pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG) {
3098aa26c57SJohannes Berg 			struct netlink_range_validation range;
3108aa26c57SJohannes Berg 
3118aa26c57SJohannes Berg 			nla_get_range_unsigned(pt, &range);
3128aa26c57SJohannes Berg 
3138aa26c57SJohannes Berg 			if (range.min &&
3148aa26c57SJohannes Berg 			    nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH,
3158aa26c57SJohannes Berg 					range.min))
316d07dcf9aSJohannes Berg 				goto nla_put_failure;
3178aa26c57SJohannes Berg 
3188aa26c57SJohannes Berg 			if (range.max < U16_MAX &&
3198aa26c57SJohannes Berg 			    nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
3208aa26c57SJohannes Berg 					range.max))
321d07dcf9aSJohannes Berg 				goto nla_put_failure;
3228aa26c57SJohannes Berg 		} else if (pt->len &&
3238aa26c57SJohannes Berg 			   nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
3248aa26c57SJohannes Berg 				       pt->len)) {
3258aa26c57SJohannes Berg 			goto nla_put_failure;
3268aa26c57SJohannes Berg 		}
327d07dcf9aSJohannes Berg 		break;
328d07dcf9aSJohannes Berg 	case NLA_FLAG:
329d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_FLAG;
330d07dcf9aSJohannes Berg 		break;
331d07dcf9aSJohannes Berg 	}
332d07dcf9aSJohannes Berg 
333d07dcf9aSJohannes Berg 	if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
334d07dcf9aSJohannes Berg 		goto nla_put_failure;
335d07dcf9aSJohannes Berg 
336d07dcf9aSJohannes Berg 	nla_nest_end(skb, attr);
337d2681e93SJohannes Berg 	return 0;
338d2681e93SJohannes Berg nla_put_failure:
339d2681e93SJohannes Berg 	nla_nest_cancel(skb, attr);
340d2681e93SJohannes Berg 	return -ENOBUFS;
341d2681e93SJohannes Berg }
342d2681e93SJohannes Berg 
343d2681e93SJohannes Berg /**
344d2681e93SJohannes Berg  * netlink_policy_dump_write - write current policy dump attributes
345d2681e93SJohannes Berg  * @skb: the message skb to write to
346d2681e93SJohannes Berg  * @state: the policy dump state
347d2681e93SJohannes Berg  *
348d2681e93SJohannes Berg  * Returns: 0 on success, an error code otherwise
349d2681e93SJohannes Berg  */
350d2681e93SJohannes Berg int netlink_policy_dump_write(struct sk_buff *skb,
351d2681e93SJohannes Berg 			      struct netlink_policy_dump_state *state)
352d2681e93SJohannes Berg {
353d2681e93SJohannes Berg 	const struct nla_policy *pt;
354d2681e93SJohannes Berg 	struct nlattr *policy;
355d2681e93SJohannes Berg 	bool again;
356d2681e93SJohannes Berg 	int err;
357d2681e93SJohannes Berg 
358d2681e93SJohannes Berg send_attribute:
359d2681e93SJohannes Berg 	again = false;
360d2681e93SJohannes Berg 
361d2681e93SJohannes Berg 	pt = &state->policies[state->policy_idx].policy[state->attr_idx];
362d2681e93SJohannes Berg 
363d2681e93SJohannes Berg 	policy = nla_nest_start(skb, state->policy_idx);
364d2681e93SJohannes Berg 	if (!policy)
365d2681e93SJohannes Berg 		return -ENOBUFS;
366d2681e93SJohannes Berg 
367d2681e93SJohannes Berg 	err = __netlink_policy_dump_write_attr(state, skb, pt, state->attr_idx);
368d2681e93SJohannes Berg 	if (err == -ENODATA) {
369d2681e93SJohannes Berg 		nla_nest_cancel(skb, policy);
370d2681e93SJohannes Berg 		again = true;
371d2681e93SJohannes Berg 		goto next;
372d2681e93SJohannes Berg 	} else if (err) {
373d2681e93SJohannes Berg 		goto nla_put_failure;
374d2681e93SJohannes Berg 	}
375d2681e93SJohannes Berg 
376d2681e93SJohannes Berg 	/* finish and move state to next attribute */
377d07dcf9aSJohannes Berg 	nla_nest_end(skb, policy);
378d07dcf9aSJohannes Berg 
379d07dcf9aSJohannes Berg next:
380d07dcf9aSJohannes Berg 	state->attr_idx += 1;
381d07dcf9aSJohannes Berg 	if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
382d07dcf9aSJohannes Berg 		state->attr_idx = 0;
383d07dcf9aSJohannes Berg 		state->policy_idx++;
384d07dcf9aSJohannes Berg 	}
385d07dcf9aSJohannes Berg 
386d07dcf9aSJohannes Berg 	if (again) {
387d07dcf9aSJohannes Berg 		if (netlink_policy_dump_finished(state))
388d07dcf9aSJohannes Berg 			return -ENODATA;
389d07dcf9aSJohannes Berg 		goto send_attribute;
390d07dcf9aSJohannes Berg 	}
391d07dcf9aSJohannes Berg 
392d07dcf9aSJohannes Berg 	return 0;
393d07dcf9aSJohannes Berg 
394d07dcf9aSJohannes Berg nla_put_failure:
395d07dcf9aSJohannes Berg 	nla_nest_cancel(skb, policy);
396d07dcf9aSJohannes Berg 	return -ENOBUFS;
397d07dcf9aSJohannes Berg }
398949ca6b8SJohannes Berg 
39904a351a6SJohannes Berg /**
40004a351a6SJohannes Berg  * netlink_policy_dump_free - free policy dump state
40104a351a6SJohannes Berg  * @state: the policy dump state to free
40204a351a6SJohannes Berg  *
40304a351a6SJohannes Berg  * Call this from the done() method to ensure dump state is freed.
40404a351a6SJohannes Berg  */
405adc84845SJakub Kicinski void netlink_policy_dump_free(struct netlink_policy_dump_state *state)
406949ca6b8SJohannes Berg {
407949ca6b8SJohannes Berg 	kfree(state);
408949ca6b8SJohannes Berg }
409