xref: /openbmc/linux/net/netlink/policy.c (revision b0672895)
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 
add_policy(struct netlink_policy_dump_state ** statep,const struct nla_policy * policy,unsigned int maxtype)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  */
netlink_policy_dump_get_policy_idx(struct netlink_policy_dump_state * state,const struct nla_policy * policy,unsigned int maxtype)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 
alloc_state(void)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  */
netlink_policy_dump_add_policy(struct netlink_policy_dump_state ** pstate,const struct nla_policy * policy,unsigned int maxtype)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)
147b0672895SJakub Kicinski 		goto err_try_undo;
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)
167b0672895SJakub Kicinski 					goto err_try_undo;
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;
177b0672895SJakub Kicinski 
178b0672895SJakub Kicinski err_try_undo:
179b0672895SJakub Kicinski 	/* Try to preserve reasonable unwind semantics - if we're starting from
180b0672895SJakub Kicinski 	 * scratch clean up fully, otherwise record what we got and caller will.
181b0672895SJakub Kicinski 	 */
182b0672895SJakub Kicinski 	if (!*pstate)
183b0672895SJakub Kicinski 		netlink_policy_dump_free(state);
184b0672895SJakub Kicinski 	else
185b0672895SJakub Kicinski 		*pstate = state;
186b0672895SJakub Kicinski 	return err;
187d07dcf9aSJohannes Berg }
188d07dcf9aSJohannes Berg 
189adc84845SJakub Kicinski static bool
netlink_policy_dump_finished(struct netlink_policy_dump_state * state)190adc84845SJakub Kicinski netlink_policy_dump_finished(struct netlink_policy_dump_state *state)
191d07dcf9aSJohannes Berg {
192d07dcf9aSJohannes Berg 	return state->policy_idx >= state->n_alloc ||
193d07dcf9aSJohannes Berg 	       !state->policies[state->policy_idx].policy;
194d07dcf9aSJohannes Berg }
195d07dcf9aSJohannes Berg 
19604a351a6SJohannes Berg /**
19704a351a6SJohannes Berg  * netlink_policy_dump_loop - dumping loop indicator
19804a351a6SJohannes Berg  * @state: the policy dump state
19904a351a6SJohannes Berg  *
20004a351a6SJohannes Berg  * Returns: %true if the dump continues, %false otherwise
20104a351a6SJohannes Berg  *
20204a351a6SJohannes Berg  * Note: this frees the dump state when finishing
20304a351a6SJohannes Berg  */
netlink_policy_dump_loop(struct netlink_policy_dump_state * state)204adc84845SJakub Kicinski bool netlink_policy_dump_loop(struct netlink_policy_dump_state *state)
205d07dcf9aSJohannes Berg {
206949ca6b8SJohannes Berg 	return !netlink_policy_dump_finished(state);
207d07dcf9aSJohannes Berg }
208d07dcf9aSJohannes Berg 
netlink_policy_dump_attr_size_estimate(const struct nla_policy * pt)20944f3625bSJohannes Berg int netlink_policy_dump_attr_size_estimate(const struct nla_policy *pt)
21044f3625bSJohannes Berg {
21144f3625bSJohannes Berg 	/* nested + type */
21244f3625bSJohannes Berg 	int common = 2 * nla_attr_size(sizeof(u32));
21344f3625bSJohannes Berg 
21444f3625bSJohannes Berg 	switch (pt->type) {
21544f3625bSJohannes Berg 	case NLA_UNSPEC:
21644f3625bSJohannes Berg 	case NLA_REJECT:
21744f3625bSJohannes Berg 		/* these actually don't need any space */
21844f3625bSJohannes Berg 		return 0;
21944f3625bSJohannes Berg 	case NLA_NESTED:
22044f3625bSJohannes Berg 	case NLA_NESTED_ARRAY:
22144f3625bSJohannes Berg 		/* common, policy idx, policy maxattr */
22244f3625bSJohannes Berg 		return common + 2 * nla_attr_size(sizeof(u32));
22344f3625bSJohannes Berg 	case NLA_U8:
22444f3625bSJohannes Berg 	case NLA_U16:
22544f3625bSJohannes Berg 	case NLA_U32:
22644f3625bSJohannes Berg 	case NLA_U64:
22744f3625bSJohannes Berg 	case NLA_MSECS:
22844f3625bSJohannes Berg 	case NLA_S8:
22944f3625bSJohannes Berg 	case NLA_S16:
23044f3625bSJohannes Berg 	case NLA_S32:
23144f3625bSJohannes Berg 	case NLA_S64:
23244f3625bSJohannes Berg 		/* maximum is common, u64 min/max with padding */
23344f3625bSJohannes Berg 		return common +
23444f3625bSJohannes Berg 		       2 * (nla_attr_size(0) + nla_attr_size(sizeof(u64)));
23544f3625bSJohannes Berg 	case NLA_BITFIELD32:
23644f3625bSJohannes Berg 		return common + nla_attr_size(sizeof(u32));
23744f3625bSJohannes Berg 	case NLA_STRING:
23844f3625bSJohannes Berg 	case NLA_NUL_STRING:
23944f3625bSJohannes Berg 	case NLA_BINARY:
24044f3625bSJohannes Berg 		/* maximum is common, u32 min-length/max-length */
24144f3625bSJohannes Berg 		return common + 2 * nla_attr_size(sizeof(u32));
24244f3625bSJohannes Berg 	case NLA_FLAG:
24344f3625bSJohannes Berg 		return common;
24444f3625bSJohannes Berg 	}
24544f3625bSJohannes Berg 
24644f3625bSJohannes Berg 	/* this should then cause a warning later */
24744f3625bSJohannes Berg 	return 0;
24844f3625bSJohannes Berg }
24944f3625bSJohannes Berg 
250d2681e93SJohannes Berg static int
__netlink_policy_dump_write_attr(struct netlink_policy_dump_state * state,struct sk_buff * skb,const struct nla_policy * pt,int nestattr)251d2681e93SJohannes Berg __netlink_policy_dump_write_attr(struct netlink_policy_dump_state *state,
252d2681e93SJohannes Berg 				 struct sk_buff *skb,
253d2681e93SJohannes Berg 				 const struct nla_policy *pt,
254d2681e93SJohannes Berg 				 int nestattr)
255d07dcf9aSJohannes Berg {
25644f3625bSJohannes Berg 	int estimate = netlink_policy_dump_attr_size_estimate(pt);
257d07dcf9aSJohannes Berg 	enum netlink_attribute_type type;
258d2681e93SJohannes Berg 	struct nlattr *attr;
259d07dcf9aSJohannes Berg 
260d2681e93SJohannes Berg 	attr = nla_nest_start(skb, nestattr);
261d07dcf9aSJohannes Berg 	if (!attr)
262d2681e93SJohannes Berg 		return -ENOBUFS;
263d07dcf9aSJohannes Berg 
264d07dcf9aSJohannes Berg 	switch (pt->type) {
265d07dcf9aSJohannes Berg 	default:
266d07dcf9aSJohannes Berg 	case NLA_UNSPEC:
267d07dcf9aSJohannes Berg 	case NLA_REJECT:
268d07dcf9aSJohannes Berg 		/* skip - use NLA_MIN_LEN to advertise such */
269d2681e93SJohannes Berg 		nla_nest_cancel(skb, attr);
270d2681e93SJohannes Berg 		return -ENODATA;
271d07dcf9aSJohannes Berg 	case NLA_NESTED:
272d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_NESTED;
273df561f66SGustavo A. R. Silva 		fallthrough;
274d07dcf9aSJohannes Berg 	case NLA_NESTED_ARRAY:
275d07dcf9aSJohannes Berg 		if (pt->type == NLA_NESTED_ARRAY)
276d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_NESTED_ARRAY;
277d2681e93SJohannes Berg 		if (state && pt->nested_policy && pt->len &&
278d07dcf9aSJohannes Berg 		    (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_IDX,
27904a351a6SJohannes Berg 				 netlink_policy_dump_get_policy_idx(state,
28004a351a6SJohannes Berg 								    pt->nested_policy,
281899b07c5SJohannes Berg 								    pt->len)) ||
282d07dcf9aSJohannes Berg 		     nla_put_u32(skb, NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE,
283d07dcf9aSJohannes Berg 				 pt->len)))
284d07dcf9aSJohannes Berg 			goto nla_put_failure;
285d07dcf9aSJohannes Berg 		break;
286d07dcf9aSJohannes Berg 	case NLA_U8:
287d07dcf9aSJohannes Berg 	case NLA_U16:
288d07dcf9aSJohannes Berg 	case NLA_U32:
289d07dcf9aSJohannes Berg 	case NLA_U64:
290d07dcf9aSJohannes Berg 	case NLA_MSECS: {
291d07dcf9aSJohannes Berg 		struct netlink_range_validation range;
292d07dcf9aSJohannes Berg 
293d07dcf9aSJohannes Berg 		if (pt->type == NLA_U8)
294d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U8;
295d07dcf9aSJohannes Berg 		else if (pt->type == NLA_U16)
296d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U16;
297d07dcf9aSJohannes Berg 		else if (pt->type == NLA_U32)
298d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U32;
299d07dcf9aSJohannes Berg 		else
300d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_U64;
301d07dcf9aSJohannes Berg 
302bdbb4e29SJakub Kicinski 		if (pt->validation_type == NLA_VALIDATE_MASK) {
303bdbb4e29SJakub Kicinski 			if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK,
304bdbb4e29SJakub Kicinski 					      pt->mask,
305bdbb4e29SJakub Kicinski 					      NL_POLICY_TYPE_ATTR_PAD))
306bdbb4e29SJakub Kicinski 				goto nla_put_failure;
307bdbb4e29SJakub Kicinski 			break;
308bdbb4e29SJakub Kicinski 		}
309bdbb4e29SJakub Kicinski 
310d07dcf9aSJohannes Berg 		nla_get_range_unsigned(pt, &range);
311d07dcf9aSJohannes Berg 
312d07dcf9aSJohannes Berg 		if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,
313d07dcf9aSJohannes Berg 				      range.min, NL_POLICY_TYPE_ATTR_PAD) ||
314d07dcf9aSJohannes Berg 		    nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_U,
315d07dcf9aSJohannes Berg 				      range.max, NL_POLICY_TYPE_ATTR_PAD))
316d07dcf9aSJohannes Berg 			goto nla_put_failure;
317d07dcf9aSJohannes Berg 		break;
318d07dcf9aSJohannes Berg 	}
319d07dcf9aSJohannes Berg 	case NLA_S8:
320d07dcf9aSJohannes Berg 	case NLA_S16:
321d07dcf9aSJohannes Berg 	case NLA_S32:
322d07dcf9aSJohannes Berg 	case NLA_S64: {
323d07dcf9aSJohannes Berg 		struct netlink_range_validation_signed range;
324d07dcf9aSJohannes Berg 
325d07dcf9aSJohannes Berg 		if (pt->type == NLA_S8)
326d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S8;
327d07dcf9aSJohannes Berg 		else if (pt->type == NLA_S16)
328d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S16;
329d07dcf9aSJohannes Berg 		else if (pt->type == NLA_S32)
330d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S32;
331d07dcf9aSJohannes Berg 		else
332d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_S64;
333d07dcf9aSJohannes Berg 
334d07dcf9aSJohannes Berg 		nla_get_range_signed(pt, &range);
335d07dcf9aSJohannes Berg 
336d07dcf9aSJohannes Berg 		if (nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_S,
337d07dcf9aSJohannes Berg 				range.min, NL_POLICY_TYPE_ATTR_PAD) ||
338d07dcf9aSJohannes Berg 		    nla_put_s64(skb, NL_POLICY_TYPE_ATTR_MAX_VALUE_S,
339d07dcf9aSJohannes Berg 				range.max, NL_POLICY_TYPE_ATTR_PAD))
340d07dcf9aSJohannes Berg 			goto nla_put_failure;
341d07dcf9aSJohannes Berg 		break;
342d07dcf9aSJohannes Berg 	}
343d07dcf9aSJohannes Berg 	case NLA_BITFIELD32:
344d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_BITFIELD32;
345d07dcf9aSJohannes Berg 		if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK,
346d07dcf9aSJohannes Berg 				pt->bitfield32_valid))
347d07dcf9aSJohannes Berg 			goto nla_put_failure;
348d07dcf9aSJohannes Berg 		break;
349d07dcf9aSJohannes Berg 	case NLA_STRING:
350d07dcf9aSJohannes Berg 	case NLA_NUL_STRING:
351d07dcf9aSJohannes Berg 	case NLA_BINARY:
352d07dcf9aSJohannes Berg 		if (pt->type == NLA_STRING)
353d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_STRING;
354d07dcf9aSJohannes Berg 		else if (pt->type == NLA_NUL_STRING)
355d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_NUL_STRING;
356d07dcf9aSJohannes Berg 		else
357d07dcf9aSJohannes Berg 			type = NL_ATTR_TYPE_BINARY;
3588aa26c57SJohannes Berg 
359c30a3c95SJohannes Berg 		if (pt->validation_type == NLA_VALIDATE_RANGE ||
360c30a3c95SJohannes Berg 		    pt->validation_type == NLA_VALIDATE_RANGE_WARN_TOO_LONG) {
3618aa26c57SJohannes Berg 			struct netlink_range_validation range;
3628aa26c57SJohannes Berg 
3638aa26c57SJohannes Berg 			nla_get_range_unsigned(pt, &range);
3648aa26c57SJohannes Berg 
3658aa26c57SJohannes Berg 			if (range.min &&
3668aa26c57SJohannes Berg 			    nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MIN_LENGTH,
3678aa26c57SJohannes Berg 					range.min))
368d07dcf9aSJohannes Berg 				goto nla_put_failure;
3698aa26c57SJohannes Berg 
3708aa26c57SJohannes Berg 			if (range.max < U16_MAX &&
3718aa26c57SJohannes Berg 			    nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
3728aa26c57SJohannes Berg 					range.max))
373d07dcf9aSJohannes Berg 				goto nla_put_failure;
3748aa26c57SJohannes Berg 		} else if (pt->len &&
3758aa26c57SJohannes Berg 			   nla_put_u32(skb, NL_POLICY_TYPE_ATTR_MAX_LENGTH,
3768aa26c57SJohannes Berg 				       pt->len)) {
3778aa26c57SJohannes Berg 			goto nla_put_failure;
3788aa26c57SJohannes Berg 		}
379d07dcf9aSJohannes Berg 		break;
380d07dcf9aSJohannes Berg 	case NLA_FLAG:
381d07dcf9aSJohannes Berg 		type = NL_ATTR_TYPE_FLAG;
382d07dcf9aSJohannes Berg 		break;
383d07dcf9aSJohannes Berg 	}
384d07dcf9aSJohannes Berg 
385d07dcf9aSJohannes Berg 	if (nla_put_u32(skb, NL_POLICY_TYPE_ATTR_TYPE, type))
386d07dcf9aSJohannes Berg 		goto nla_put_failure;
387d07dcf9aSJohannes Berg 
388d07dcf9aSJohannes Berg 	nla_nest_end(skb, attr);
38944f3625bSJohannes Berg 	WARN_ON(attr->nla_len > estimate);
39044f3625bSJohannes Berg 
391d2681e93SJohannes Berg 	return 0;
392d2681e93SJohannes Berg nla_put_failure:
393d2681e93SJohannes Berg 	nla_nest_cancel(skb, attr);
394d2681e93SJohannes Berg 	return -ENOBUFS;
395d2681e93SJohannes Berg }
396d2681e93SJohannes Berg 
397d2681e93SJohannes Berg /**
39844f3625bSJohannes Berg  * netlink_policy_dump_write_attr - write a given attribute policy
39944f3625bSJohannes Berg  * @skb: the message skb to write to
40044f3625bSJohannes Berg  * @pt: the attribute's policy
40144f3625bSJohannes Berg  * @nestattr: the nested attribute ID to use
40244f3625bSJohannes Berg  *
40344f3625bSJohannes Berg  * Returns: 0 on success, an error code otherwise; -%ENODATA is
40444f3625bSJohannes Berg  *	    special, indicating that there's no policy data and
40544f3625bSJohannes Berg  *	    the attribute is generally rejected.
40644f3625bSJohannes Berg  */
netlink_policy_dump_write_attr(struct sk_buff * skb,const struct nla_policy * pt,int nestattr)40744f3625bSJohannes Berg int netlink_policy_dump_write_attr(struct sk_buff *skb,
40844f3625bSJohannes Berg 				   const struct nla_policy *pt,
40944f3625bSJohannes Berg 				   int nestattr)
41044f3625bSJohannes Berg {
41144f3625bSJohannes Berg 	return __netlink_policy_dump_write_attr(NULL, skb, pt, nestattr);
41244f3625bSJohannes Berg }
41344f3625bSJohannes Berg 
41444f3625bSJohannes Berg /**
415d2681e93SJohannes Berg  * netlink_policy_dump_write - write current policy dump attributes
416d2681e93SJohannes Berg  * @skb: the message skb to write to
417d2681e93SJohannes Berg  * @state: the policy dump state
418d2681e93SJohannes Berg  *
419d2681e93SJohannes Berg  * Returns: 0 on success, an error code otherwise
420d2681e93SJohannes Berg  */
netlink_policy_dump_write(struct sk_buff * skb,struct netlink_policy_dump_state * state)421d2681e93SJohannes Berg int netlink_policy_dump_write(struct sk_buff *skb,
422d2681e93SJohannes Berg 			      struct netlink_policy_dump_state *state)
423d2681e93SJohannes Berg {
424d2681e93SJohannes Berg 	const struct nla_policy *pt;
425d2681e93SJohannes Berg 	struct nlattr *policy;
426d2681e93SJohannes Berg 	bool again;
427d2681e93SJohannes Berg 	int err;
428d2681e93SJohannes Berg 
429d2681e93SJohannes Berg send_attribute:
430d2681e93SJohannes Berg 	again = false;
431d2681e93SJohannes Berg 
432d2681e93SJohannes Berg 	pt = &state->policies[state->policy_idx].policy[state->attr_idx];
433d2681e93SJohannes Berg 
434d2681e93SJohannes Berg 	policy = nla_nest_start(skb, state->policy_idx);
435d2681e93SJohannes Berg 	if (!policy)
436d2681e93SJohannes Berg 		return -ENOBUFS;
437d2681e93SJohannes Berg 
438d2681e93SJohannes Berg 	err = __netlink_policy_dump_write_attr(state, skb, pt, state->attr_idx);
439d2681e93SJohannes Berg 	if (err == -ENODATA) {
440d2681e93SJohannes Berg 		nla_nest_cancel(skb, policy);
441d2681e93SJohannes Berg 		again = true;
442d2681e93SJohannes Berg 		goto next;
443d2681e93SJohannes Berg 	} else if (err) {
444d2681e93SJohannes Berg 		goto nla_put_failure;
445d2681e93SJohannes Berg 	}
446d2681e93SJohannes Berg 
447d2681e93SJohannes Berg 	/* finish and move state to next attribute */
448d07dcf9aSJohannes Berg 	nla_nest_end(skb, policy);
449d07dcf9aSJohannes Berg 
450d07dcf9aSJohannes Berg next:
451d07dcf9aSJohannes Berg 	state->attr_idx += 1;
452d07dcf9aSJohannes Berg 	if (state->attr_idx > state->policies[state->policy_idx].maxtype) {
453d07dcf9aSJohannes Berg 		state->attr_idx = 0;
454d07dcf9aSJohannes Berg 		state->policy_idx++;
455d07dcf9aSJohannes Berg 	}
456d07dcf9aSJohannes Berg 
457d07dcf9aSJohannes Berg 	if (again) {
458d07dcf9aSJohannes Berg 		if (netlink_policy_dump_finished(state))
459d07dcf9aSJohannes Berg 			return -ENODATA;
460d07dcf9aSJohannes Berg 		goto send_attribute;
461d07dcf9aSJohannes Berg 	}
462d07dcf9aSJohannes Berg 
463d07dcf9aSJohannes Berg 	return 0;
464d07dcf9aSJohannes Berg 
465d07dcf9aSJohannes Berg nla_put_failure:
466d07dcf9aSJohannes Berg 	nla_nest_cancel(skb, policy);
467d07dcf9aSJohannes Berg 	return -ENOBUFS;
468d07dcf9aSJohannes Berg }
469949ca6b8SJohannes Berg 
47004a351a6SJohannes Berg /**
47104a351a6SJohannes Berg  * netlink_policy_dump_free - free policy dump state
47204a351a6SJohannes Berg  * @state: the policy dump state to free
47304a351a6SJohannes Berg  *
47404a351a6SJohannes Berg  * Call this from the done() method to ensure dump state is freed.
47504a351a6SJohannes Berg  */
netlink_policy_dump_free(struct netlink_policy_dump_state * state)476adc84845SJakub Kicinski void netlink_policy_dump_free(struct netlink_policy_dump_state *state)
477949ca6b8SJohannes Berg {
478949ca6b8SJohannes Berg 	kfree(state);
479949ca6b8SJohannes Berg }
480