xref: /openbmc/linux/net/ieee802154/nl802154.c (revision b96fc2f3)
1 /* This program is free software; you can redistribute it and/or modify
2  * it under the terms of the GNU General Public License version 2
3  * as published by the Free Software Foundation.
4  *
5  * This program is distributed in the hope that it will be useful,
6  * but WITHOUT ANY WARRANTY; without even the implied warranty of
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  * GNU General Public License for more details.
9  *
10  * Authors:
11  * Alexander Aring <aar@pengutronix.de>
12  *
13  * Based on: net/wireless/nl80211.c
14  */
15 
16 #include <linux/rtnetlink.h>
17 
18 #include <net/cfg802154.h>
19 #include <net/genetlink.h>
20 #include <net/mac802154.h>
21 #include <net/netlink.h>
22 #include <net/nl802154.h>
23 #include <net/sock.h>
24 
25 #include "nl802154.h"
26 #include "rdev-ops.h"
27 #include "core.h"
28 
29 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
30 			     struct genl_info *info);
31 
32 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
33 			       struct genl_info *info);
34 
35 /* the netlink family */
36 static struct genl_family nl802154_fam = {
37 	.id = GENL_ID_GENERATE,		/* don't bother with a hardcoded ID */
38 	.name = NL802154_GENL_NAME,	/* have users key off the name instead */
39 	.hdrsize = 0,			/* no private header */
40 	.version = 1,			/* no particular meaning now */
41 	.maxattr = NL802154_ATTR_MAX,
42 	.netnsok = true,
43 	.pre_doit = nl802154_pre_doit,
44 	.post_doit = nl802154_post_doit,
45 };
46 
47 /* multicast groups */
48 enum nl802154_multicast_groups {
49 	NL802154_MCGRP_CONFIG,
50 };
51 
52 static const struct genl_multicast_group nl802154_mcgrps[] = {
53 	[NL802154_MCGRP_CONFIG] = { .name = "config", },
54 };
55 
56 /* returns ERR_PTR values */
57 static struct wpan_dev *
58 __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
59 {
60 	struct cfg802154_registered_device *rdev;
61 	struct wpan_dev *result = NULL;
62 	bool have_ifidx = attrs[NL802154_ATTR_IFINDEX];
63 	bool have_wpan_dev_id = attrs[NL802154_ATTR_WPAN_DEV];
64 	u64 wpan_dev_id;
65 	int wpan_phy_idx = -1;
66 	int ifidx = -1;
67 
68 	ASSERT_RTNL();
69 
70 	if (!have_ifidx && !have_wpan_dev_id)
71 		return ERR_PTR(-EINVAL);
72 
73 	if (have_ifidx)
74 		ifidx = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
75 	if (have_wpan_dev_id) {
76 		wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
77 		wpan_phy_idx = wpan_dev_id >> 32;
78 	}
79 
80 	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
81 		struct wpan_dev *wpan_dev;
82 
83 		/* TODO netns compare */
84 
85 		if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
86 			continue;
87 
88 		list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
89 			if (have_ifidx && wpan_dev->netdev &&
90 			    wpan_dev->netdev->ifindex == ifidx) {
91 				result = wpan_dev;
92 				break;
93 			}
94 			if (have_wpan_dev_id &&
95 			    wpan_dev->identifier == (u32)wpan_dev_id) {
96 				result = wpan_dev;
97 				break;
98 			}
99 		}
100 
101 		if (result)
102 			break;
103 	}
104 
105 	if (result)
106 		return result;
107 
108 	return ERR_PTR(-ENODEV);
109 }
110 
111 static struct cfg802154_registered_device *
112 __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
113 {
114 	struct cfg802154_registered_device *rdev = NULL, *tmp;
115 	struct net_device *netdev;
116 
117 	ASSERT_RTNL();
118 
119 	if (!attrs[NL802154_ATTR_WPAN_PHY] &&
120 	    !attrs[NL802154_ATTR_IFINDEX] &&
121 	    !attrs[NL802154_ATTR_WPAN_DEV])
122 		return ERR_PTR(-EINVAL);
123 
124 	if (attrs[NL802154_ATTR_WPAN_PHY])
125 		rdev = cfg802154_rdev_by_wpan_phy_idx(
126 				nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY]));
127 
128 	if (attrs[NL802154_ATTR_WPAN_DEV]) {
129 		u64 wpan_dev_id = nla_get_u64(attrs[NL802154_ATTR_WPAN_DEV]);
130 		struct wpan_dev *wpan_dev;
131 		bool found = false;
132 
133 		tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32);
134 		if (tmp) {
135 			/* make sure wpan_dev exists */
136 			list_for_each_entry(wpan_dev, &tmp->wpan_dev_list, list) {
137 				if (wpan_dev->identifier != (u32)wpan_dev_id)
138 					continue;
139 				found = true;
140 				break;
141 			}
142 
143 			if (!found)
144 				tmp = NULL;
145 
146 			if (rdev && tmp != rdev)
147 				return ERR_PTR(-EINVAL);
148 			rdev = tmp;
149 		}
150 	}
151 
152 	if (attrs[NL802154_ATTR_IFINDEX]) {
153 		int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
154 
155 		netdev = __dev_get_by_index(netns, ifindex);
156 		if (netdev) {
157 			if (netdev->ieee802154_ptr)
158 				tmp = wpan_phy_to_rdev(
159 						netdev->ieee802154_ptr->wpan_phy);
160 			else
161 				tmp = NULL;
162 
163 			/* not wireless device -- return error */
164 			if (!tmp)
165 				return ERR_PTR(-EINVAL);
166 
167 			/* mismatch -- return error */
168 			if (rdev && tmp != rdev)
169 				return ERR_PTR(-EINVAL);
170 
171 			rdev = tmp;
172 		}
173 	}
174 
175 	if (!rdev)
176 		return ERR_PTR(-ENODEV);
177 
178 	/* TODO netns compare */
179 
180 	return rdev;
181 }
182 
183 /* This function returns a pointer to the driver
184  * that the genl_info item that is passed refers to.
185  *
186  * The result of this can be a PTR_ERR and hence must
187  * be checked with IS_ERR() for errors.
188  */
189 static struct cfg802154_registered_device *
190 cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info)
191 {
192 	return __cfg802154_rdev_from_attrs(netns, info->attrs);
193 }
194 
195 /* policy for the attributes */
196 static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
197 	[NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 },
198 	[NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING,
199 					  .len = 20-1 },
200 
201 	[NL802154_ATTR_IFINDEX] = { .type = NLA_U32 },
202 	[NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
203 	[NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
204 
205 	[NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
206 
207 	[NL802154_ATTR_PAGE] = { .type = NLA_U8, },
208 	[NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
209 
210 	[NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
211 
212 	[NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
213 	[NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
214 	[NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
215 
216 	[NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
217 
218 	[NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
219 	[NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
220 	[NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
221 
222 	[NL802154_ATTR_MIN_BE] = { .type = NLA_U8, },
223 	[NL802154_ATTR_MAX_BE] = { .type = NLA_U8, },
224 	[NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, },
225 
226 	[NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
227 
228 	[NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
229 
230 	[NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
231 
232 	[NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
233 
234 	[NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
235 };
236 
237 /* message building helper */
238 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
239 				    int flags, u8 cmd)
240 {
241 	/* since there is no private header just add the generic one */
242 	return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
243 }
244 
245 static int
246 nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
247 {
248 	struct nlattr *nl_flags = nla_nest_start(msg, attr);
249 	int i;
250 
251 	if (!nl_flags)
252 		return -ENOBUFS;
253 
254 	i = 0;
255 	while (mask) {
256 		if ((mask & 1) && nla_put_flag(msg, i))
257 			return -ENOBUFS;
258 
259 		mask >>= 1;
260 		i++;
261 	}
262 
263 	nla_nest_end(msg, nl_flags);
264 	return 0;
265 }
266 
267 static int
268 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
269 				struct sk_buff *msg)
270 {
271 	struct nlattr *nl_page;
272 	unsigned long page;
273 
274 	nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
275 	if (!nl_page)
276 		return -ENOBUFS;
277 
278 	for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
279 		if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
280 				rdev->wpan_phy.supported.channels[page]))
281 			return -ENOBUFS;
282 	}
283 	nla_nest_end(msg, nl_page);
284 
285 	return 0;
286 }
287 
288 static int
289 nl802154_put_capabilities(struct sk_buff *msg,
290 			  struct cfg802154_registered_device *rdev)
291 {
292 	const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
293 	struct nlattr *nl_caps, *nl_channels;
294 	int i;
295 
296 	nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
297 	if (!nl_caps)
298 		return -ENOBUFS;
299 
300 	nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
301 	if (!nl_channels)
302 		return -ENOBUFS;
303 
304 	for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
305 		if (caps->channels[i]) {
306 			if (nl802154_put_flags(msg, i, caps->channels[i]))
307 				return -ENOBUFS;
308 		}
309 	}
310 
311 	nla_nest_end(msg, nl_channels);
312 
313 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
314 		struct nlattr *nl_ed_lvls;
315 
316 		nl_ed_lvls = nla_nest_start(msg,
317 					    NL802154_CAP_ATTR_CCA_ED_LEVELS);
318 		if (!nl_ed_lvls)
319 			return -ENOBUFS;
320 
321 		for (i = 0; i < caps->cca_ed_levels_size; i++) {
322 			if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
323 				return -ENOBUFS;
324 		}
325 
326 		nla_nest_end(msg, nl_ed_lvls);
327 	}
328 
329 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
330 		struct nlattr *nl_tx_pwrs;
331 
332 		nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
333 		if (!nl_tx_pwrs)
334 			return -ENOBUFS;
335 
336 		for (i = 0; i < caps->tx_powers_size; i++) {
337 			if (nla_put_s32(msg, i, caps->tx_powers[i]))
338 				return -ENOBUFS;
339 		}
340 
341 		nla_nest_end(msg, nl_tx_pwrs);
342 	}
343 
344 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
345 		if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
346 				       caps->cca_modes) ||
347 		    nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
348 				       caps->cca_opts))
349 			return -ENOBUFS;
350 	}
351 
352 	if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
353 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
354 	    nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
355 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
356 	    nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
357 		       caps->min_csma_backoffs) ||
358 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
359 		       caps->max_csma_backoffs) ||
360 	    nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
361 		       caps->min_frame_retries) ||
362 	    nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
363 		       caps->max_frame_retries) ||
364 	    nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
365 			       caps->iftypes) ||
366 	    nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
367 		return -ENOBUFS;
368 
369 	nla_nest_end(msg, nl_caps);
370 
371 	return 0;
372 }
373 
374 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
375 				  enum nl802154_commands cmd,
376 				  struct sk_buff *msg, u32 portid, u32 seq,
377 				  int flags)
378 {
379 	struct nlattr *nl_cmds;
380 	void *hdr;
381 	int i;
382 
383 	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
384 	if (!hdr)
385 		return -ENOBUFS;
386 
387 	if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
388 	    nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
389 			   wpan_phy_name(&rdev->wpan_phy)) ||
390 	    nla_put_u32(msg, NL802154_ATTR_GENERATION,
391 			cfg802154_rdev_list_generation))
392 		goto nla_put_failure;
393 
394 	if (cmd != NL802154_CMD_NEW_WPAN_PHY)
395 		goto finish;
396 
397 	/* DUMP PHY PIB */
398 
399 	/* current channel settings */
400 	if (nla_put_u8(msg, NL802154_ATTR_PAGE,
401 		       rdev->wpan_phy.current_page) ||
402 	    nla_put_u8(msg, NL802154_ATTR_CHANNEL,
403 		       rdev->wpan_phy.current_channel))
404 		goto nla_put_failure;
405 
406 	/* TODO remove this behaviour, we still keep support it for a while
407 	 * so users can change the behaviour to the new one.
408 	 */
409 	if (nl802154_send_wpan_phy_channels(rdev, msg))
410 		goto nla_put_failure;
411 
412 	/* cca mode */
413 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
414 		if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
415 				rdev->wpan_phy.cca.mode))
416 			goto nla_put_failure;
417 
418 		if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
419 			if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
420 					rdev->wpan_phy.cca.opt))
421 				goto nla_put_failure;
422 		}
423 	}
424 
425 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
426 		if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
427 				rdev->wpan_phy.transmit_power))
428 			goto nla_put_failure;
429 	}
430 
431 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
432 		if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
433 				rdev->wpan_phy.cca_ed_level))
434 			goto nla_put_failure;
435 	}
436 
437 	if (nl802154_put_capabilities(msg, rdev))
438 		goto nla_put_failure;
439 
440 	nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
441 	if (!nl_cmds)
442 		goto nla_put_failure;
443 
444 	i = 0;
445 #define CMD(op, n)							\
446 	do {								\
447 		if (rdev->ops->op) {					\
448 			i++;						\
449 			if (nla_put_u32(msg, i, NL802154_CMD_ ## n))	\
450 				goto nla_put_failure;			\
451 		}							\
452 	} while (0)
453 
454 	CMD(add_virtual_intf, NEW_INTERFACE);
455 	CMD(del_virtual_intf, DEL_INTERFACE);
456 	CMD(set_channel, SET_CHANNEL);
457 	CMD(set_pan_id, SET_PAN_ID);
458 	CMD(set_short_addr, SET_SHORT_ADDR);
459 	CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
460 	CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
461 	CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
462 	CMD(set_lbt_mode, SET_LBT_MODE);
463 	CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
464 
465 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
466 		CMD(set_tx_power, SET_TX_POWER);
467 
468 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
469 		CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
470 
471 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
472 		CMD(set_cca_mode, SET_CCA_MODE);
473 
474 #undef CMD
475 	nla_nest_end(msg, nl_cmds);
476 
477 finish:
478 	genlmsg_end(msg, hdr);
479 	return 0;
480 
481 nla_put_failure:
482 	genlmsg_cancel(msg, hdr);
483 	return -EMSGSIZE;
484 }
485 
486 struct nl802154_dump_wpan_phy_state {
487 	s64 filter_wpan_phy;
488 	long start;
489 
490 };
491 
492 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
493 					struct netlink_callback *cb,
494 					struct nl802154_dump_wpan_phy_state *state)
495 {
496 	struct nlattr **tb = nl802154_fam.attrbuf;
497 	int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
498 			      tb, nl802154_fam.maxattr, nl802154_policy);
499 
500 	/* TODO check if we can handle error here,
501 	 * we have no backward compatibility
502 	 */
503 	if (ret)
504 		return 0;
505 
506 	if (tb[NL802154_ATTR_WPAN_PHY])
507 		state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
508 	if (tb[NL802154_ATTR_WPAN_DEV])
509 		state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
510 	if (tb[NL802154_ATTR_IFINDEX]) {
511 		struct net_device *netdev;
512 		struct cfg802154_registered_device *rdev;
513 		int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
514 
515 		/* TODO netns */
516 		netdev = __dev_get_by_index(&init_net, ifidx);
517 		if (!netdev)
518 			return -ENODEV;
519 		if (netdev->ieee802154_ptr) {
520 			rdev = wpan_phy_to_rdev(
521 					netdev->ieee802154_ptr->wpan_phy);
522 			state->filter_wpan_phy = rdev->wpan_phy_idx;
523 		}
524 	}
525 
526 	return 0;
527 }
528 
529 static int
530 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
531 {
532 	int idx = 0, ret;
533 	struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
534 	struct cfg802154_registered_device *rdev;
535 
536 	rtnl_lock();
537 	if (!state) {
538 		state = kzalloc(sizeof(*state), GFP_KERNEL);
539 		if (!state) {
540 			rtnl_unlock();
541 			return -ENOMEM;
542 		}
543 		state->filter_wpan_phy = -1;
544 		ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
545 		if (ret) {
546 			kfree(state);
547 			rtnl_unlock();
548 			return ret;
549 		}
550 		cb->args[0] = (long)state;
551 	}
552 
553 	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
554 		/* TODO net ns compare */
555 		if (++idx <= state->start)
556 			continue;
557 		if (state->filter_wpan_phy != -1 &&
558 		    state->filter_wpan_phy != rdev->wpan_phy_idx)
559 			continue;
560 		/* attempt to fit multiple wpan_phy data chunks into the skb */
561 		ret = nl802154_send_wpan_phy(rdev,
562 					     NL802154_CMD_NEW_WPAN_PHY,
563 					     skb,
564 					     NETLINK_CB(cb->skb).portid,
565 					     cb->nlh->nlmsg_seq, NLM_F_MULTI);
566 		if (ret < 0) {
567 			if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
568 			    !skb->len && cb->min_dump_alloc < 4096) {
569 				cb->min_dump_alloc = 4096;
570 				rtnl_unlock();
571 				return 1;
572 			}
573 			idx--;
574 			break;
575 		}
576 		break;
577 	}
578 	rtnl_unlock();
579 
580 	state->start = idx;
581 
582 	return skb->len;
583 }
584 
585 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
586 {
587 	kfree((void *)cb->args[0]);
588 	return 0;
589 }
590 
591 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
592 {
593 	struct sk_buff *msg;
594 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
595 
596 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
597 	if (!msg)
598 		return -ENOMEM;
599 
600 	if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
601 				   info->snd_portid, info->snd_seq, 0) < 0) {
602 		nlmsg_free(msg);
603 		return -ENOBUFS;
604 	}
605 
606 	return genlmsg_reply(msg, info);
607 }
608 
609 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
610 {
611 	return (u64)wpan_dev->identifier |
612 	       ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
613 }
614 
615 static int
616 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
617 		    struct cfg802154_registered_device *rdev,
618 		    struct wpan_dev *wpan_dev)
619 {
620 	struct net_device *dev = wpan_dev->netdev;
621 	void *hdr;
622 
623 	hdr = nl802154hdr_put(msg, portid, seq, flags,
624 			      NL802154_CMD_NEW_INTERFACE);
625 	if (!hdr)
626 		return -1;
627 
628 	if (dev &&
629 	    (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
630 	     nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
631 		goto nla_put_failure;
632 
633 	if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
634 	    nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
635 	    nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
636 	    nla_put_u32(msg, NL802154_ATTR_GENERATION,
637 			rdev->devlist_generation ^
638 			(cfg802154_rdev_list_generation << 2)))
639 		goto nla_put_failure;
640 
641 	/* address settings */
642 	if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
643 			 wpan_dev->extended_addr) ||
644 	    nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
645 			 wpan_dev->short_addr) ||
646 	    nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
647 		goto nla_put_failure;
648 
649 	/* ARET handling */
650 	if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
651 		       wpan_dev->frame_retries) ||
652 	    nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
653 	    nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
654 		       wpan_dev->csma_retries) ||
655 	    nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
656 		goto nla_put_failure;
657 
658 	/* listen before transmit */
659 	if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
660 		goto nla_put_failure;
661 
662 	/* ackreq default behaviour */
663 	if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
664 		goto nla_put_failure;
665 
666 	genlmsg_end(msg, hdr);
667 	return 0;
668 
669 nla_put_failure:
670 	genlmsg_cancel(msg, hdr);
671 	return -EMSGSIZE;
672 }
673 
674 static int
675 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
676 {
677 	int wp_idx = 0;
678 	int if_idx = 0;
679 	int wp_start = cb->args[0];
680 	int if_start = cb->args[1];
681 	struct cfg802154_registered_device *rdev;
682 	struct wpan_dev *wpan_dev;
683 
684 	rtnl_lock();
685 	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
686 		/* TODO netns compare */
687 		if (wp_idx < wp_start) {
688 			wp_idx++;
689 			continue;
690 		}
691 		if_idx = 0;
692 
693 		list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
694 			if (if_idx < if_start) {
695 				if_idx++;
696 				continue;
697 			}
698 			if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
699 						cb->nlh->nlmsg_seq, NLM_F_MULTI,
700 						rdev, wpan_dev) < 0) {
701 				goto out;
702 			}
703 			if_idx++;
704 		}
705 
706 		wp_idx++;
707 	}
708 out:
709 	rtnl_unlock();
710 
711 	cb->args[0] = wp_idx;
712 	cb->args[1] = if_idx;
713 
714 	return skb->len;
715 }
716 
717 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
718 {
719 	struct sk_buff *msg;
720 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
721 	struct wpan_dev *wdev = info->user_ptr[1];
722 
723 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
724 	if (!msg)
725 		return -ENOMEM;
726 
727 	if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
728 				rdev, wdev) < 0) {
729 		nlmsg_free(msg);
730 		return -ENOBUFS;
731 	}
732 
733 	return genlmsg_reply(msg, info);
734 }
735 
736 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
737 {
738 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
739 	enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
740 	__le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
741 
742 	/* TODO avoid failing a new interface
743 	 * creation due to pending removal?
744 	 */
745 
746 	if (!info->attrs[NL802154_ATTR_IFNAME])
747 		return -EINVAL;
748 
749 	if (info->attrs[NL802154_ATTR_IFTYPE]) {
750 		type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
751 		if (type > NL802154_IFTYPE_MAX ||
752 		    !(rdev->wpan_phy.supported.iftypes & BIT(type)))
753 			return -EINVAL;
754 	}
755 
756 	/* TODO add nla_get_le64 to netlink */
757 	if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
758 		extended_addr = (__force __le64)nla_get_u64(
759 				info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
760 
761 	if (!rdev->ops->add_virtual_intf)
762 		return -EOPNOTSUPP;
763 
764 	return rdev_add_virtual_intf(rdev,
765 				     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
766 				     NET_NAME_USER, type, extended_addr);
767 }
768 
769 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
770 {
771 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
772 	struct wpan_dev *wpan_dev = info->user_ptr[1];
773 
774 	if (!rdev->ops->del_virtual_intf)
775 		return -EOPNOTSUPP;
776 
777 	/* If we remove a wpan device without a netdev then clear
778 	 * user_ptr[1] so that nl802154_post_doit won't dereference it
779 	 * to check if it needs to do dev_put(). Otherwise it crashes
780 	 * since the wpan_dev has been freed, unlike with a netdev where
781 	 * we need the dev_put() for the netdev to really be freed.
782 	 */
783 	if (!wpan_dev->netdev)
784 		info->user_ptr[1] = NULL;
785 
786 	return rdev_del_virtual_intf(rdev, wpan_dev);
787 }
788 
789 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
790 {
791 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
792 	u8 channel, page;
793 
794 	if (!info->attrs[NL802154_ATTR_PAGE] ||
795 	    !info->attrs[NL802154_ATTR_CHANNEL])
796 		return -EINVAL;
797 
798 	page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
799 	channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
800 
801 	/* check 802.15.4 constraints */
802 	if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
803 	    !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
804 		return -EINVAL;
805 
806 	return rdev_set_channel(rdev, page, channel);
807 }
808 
809 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
810 {
811 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
812 	struct wpan_phy_cca cca;
813 
814 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
815 		return -EOPNOTSUPP;
816 
817 	if (!info->attrs[NL802154_ATTR_CCA_MODE])
818 		return -EINVAL;
819 
820 	cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
821 	/* checking 802.15.4 constraints */
822 	if (cca.mode < NL802154_CCA_ENERGY ||
823 	    cca.mode > NL802154_CCA_ATTR_MAX ||
824 	    !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
825 		return -EINVAL;
826 
827 	if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
828 		if (!info->attrs[NL802154_ATTR_CCA_OPT])
829 			return -EINVAL;
830 
831 		cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
832 		if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
833 		    !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
834 			return -EINVAL;
835 	}
836 
837 	return rdev_set_cca_mode(rdev, &cca);
838 }
839 
840 static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
841 {
842 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
843 	s32 ed_level;
844 	int i;
845 
846 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
847 		return -EOPNOTSUPP;
848 
849 	if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
850 		return -EINVAL;
851 
852 	ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
853 
854 	for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
855 		if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
856 			return rdev_set_cca_ed_level(rdev, ed_level);
857 	}
858 
859 	return -EINVAL;
860 }
861 
862 static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
863 {
864 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
865 	s32 power;
866 	int i;
867 
868 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
869 		return -EOPNOTSUPP;
870 
871 	if (!info->attrs[NL802154_ATTR_TX_POWER])
872 		return -EINVAL;
873 
874 	power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
875 
876 	for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
877 		if (power == rdev->wpan_phy.supported.tx_powers[i])
878 			return rdev_set_tx_power(rdev, power);
879 	}
880 
881 	return -EINVAL;
882 }
883 
884 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
885 {
886 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
887 	struct net_device *dev = info->user_ptr[1];
888 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
889 	__le16 pan_id;
890 
891 	/* conflict here while tx/rx calls */
892 	if (netif_running(dev))
893 		return -EBUSY;
894 
895 	/* don't change address fields on monitor */
896 	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
897 	    !info->attrs[NL802154_ATTR_PAN_ID])
898 		return -EINVAL;
899 
900 	pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
901 
902 	/* TODO
903 	 * I am not sure about to check here on broadcast pan_id.
904 	 * Broadcast is a valid setting, comment from 802.15.4:
905 	 * If this value is 0xffff, the device is not associated.
906 	 *
907 	 * This could useful to simple deassociate an device.
908 	 */
909 	if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
910 		return -EINVAL;
911 
912 	return rdev_set_pan_id(rdev, wpan_dev, pan_id);
913 }
914 
915 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
916 {
917 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
918 	struct net_device *dev = info->user_ptr[1];
919 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
920 	__le16 short_addr;
921 
922 	/* conflict here while tx/rx calls */
923 	if (netif_running(dev))
924 		return -EBUSY;
925 
926 	/* don't change address fields on monitor */
927 	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
928 	    !info->attrs[NL802154_ATTR_SHORT_ADDR])
929 		return -EINVAL;
930 
931 	short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
932 
933 	/* TODO
934 	 * I am not sure about to check here on broadcast short_addr.
935 	 * Broadcast is a valid setting, comment from 802.15.4:
936 	 * A value of 0xfffe indicates that the device has
937 	 * associated but has not been allocated an address. A
938 	 * value of 0xffff indicates that the device does not
939 	 * have a short address.
940 	 *
941 	 * I think we should allow to set these settings but
942 	 * don't allow to allow socket communication with it.
943 	 */
944 	if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
945 	    short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
946 		return -EINVAL;
947 
948 	return rdev_set_short_addr(rdev, wpan_dev, short_addr);
949 }
950 
951 static int
952 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
953 {
954 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
955 	struct net_device *dev = info->user_ptr[1];
956 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
957 	u8 min_be, max_be;
958 
959 	/* should be set on netif open inside phy settings */
960 	if (netif_running(dev))
961 		return -EBUSY;
962 
963 	if (!info->attrs[NL802154_ATTR_MIN_BE] ||
964 	    !info->attrs[NL802154_ATTR_MAX_BE])
965 		return -EINVAL;
966 
967 	min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
968 	max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
969 
970 	/* check 802.15.4 constraints */
971 	if (min_be < rdev->wpan_phy.supported.min_minbe ||
972 	    min_be > rdev->wpan_phy.supported.max_minbe ||
973 	    max_be < rdev->wpan_phy.supported.min_maxbe ||
974 	    max_be > rdev->wpan_phy.supported.max_maxbe ||
975 	    min_be > max_be)
976 		return -EINVAL;
977 
978 	return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
979 }
980 
981 static int
982 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
983 {
984 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
985 	struct net_device *dev = info->user_ptr[1];
986 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
987 	u8 max_csma_backoffs;
988 
989 	/* conflict here while other running iface settings */
990 	if (netif_running(dev))
991 		return -EBUSY;
992 
993 	if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
994 		return -EINVAL;
995 
996 	max_csma_backoffs = nla_get_u8(
997 			info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
998 
999 	/* check 802.15.4 constraints */
1000 	if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
1001 	    max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
1002 		return -EINVAL;
1003 
1004 	return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1005 }
1006 
1007 static int
1008 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1009 {
1010 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
1011 	struct net_device *dev = info->user_ptr[1];
1012 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1013 	s8 max_frame_retries;
1014 
1015 	if (netif_running(dev))
1016 		return -EBUSY;
1017 
1018 	if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1019 		return -EINVAL;
1020 
1021 	max_frame_retries = nla_get_s8(
1022 			info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1023 
1024 	/* check 802.15.4 constraints */
1025 	if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1026 	    max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1027 		return -EINVAL;
1028 
1029 	return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1030 }
1031 
1032 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1033 {
1034 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
1035 	struct net_device *dev = info->user_ptr[1];
1036 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1037 	int mode;
1038 
1039 	if (netif_running(dev))
1040 		return -EBUSY;
1041 
1042 	if (!info->attrs[NL802154_ATTR_LBT_MODE])
1043 		return -EINVAL;
1044 
1045 	mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1046 
1047 	if (mode != 0 && mode != 1)
1048 		return -EINVAL;
1049 
1050 	if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1051 		return -EINVAL;
1052 
1053 	return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1054 }
1055 
1056 static int
1057 nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1058 {
1059 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
1060 	struct net_device *dev = info->user_ptr[1];
1061 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1062 	int ackreq;
1063 
1064 	if (netif_running(dev))
1065 		return -EBUSY;
1066 
1067 	if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1068 		return -EINVAL;
1069 
1070 	ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1071 
1072 	if (ackreq != 0 && ackreq != 1)
1073 		return -EINVAL;
1074 
1075 	return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1076 }
1077 
1078 #define NL802154_FLAG_NEED_WPAN_PHY	0x01
1079 #define NL802154_FLAG_NEED_NETDEV	0x02
1080 #define NL802154_FLAG_NEED_RTNL		0x04
1081 #define NL802154_FLAG_CHECK_NETDEV_UP	0x08
1082 #define NL802154_FLAG_NEED_NETDEV_UP	(NL802154_FLAG_NEED_NETDEV |\
1083 					 NL802154_FLAG_CHECK_NETDEV_UP)
1084 #define NL802154_FLAG_NEED_WPAN_DEV	0x10
1085 #define NL802154_FLAG_NEED_WPAN_DEV_UP	(NL802154_FLAG_NEED_WPAN_DEV |\
1086 					 NL802154_FLAG_CHECK_NETDEV_UP)
1087 
1088 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1089 			     struct genl_info *info)
1090 {
1091 	struct cfg802154_registered_device *rdev;
1092 	struct wpan_dev *wpan_dev;
1093 	struct net_device *dev;
1094 	bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1095 
1096 	if (rtnl)
1097 		rtnl_lock();
1098 
1099 	if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1100 		rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1101 		if (IS_ERR(rdev)) {
1102 			if (rtnl)
1103 				rtnl_unlock();
1104 			return PTR_ERR(rdev);
1105 		}
1106 		info->user_ptr[0] = rdev;
1107 	} else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1108 		   ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1109 		ASSERT_RTNL();
1110 		wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1111 							   info->attrs);
1112 		if (IS_ERR(wpan_dev)) {
1113 			if (rtnl)
1114 				rtnl_unlock();
1115 			return PTR_ERR(wpan_dev);
1116 		}
1117 
1118 		dev = wpan_dev->netdev;
1119 		rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1120 
1121 		if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1122 			if (!dev) {
1123 				if (rtnl)
1124 					rtnl_unlock();
1125 				return -EINVAL;
1126 			}
1127 
1128 			info->user_ptr[1] = dev;
1129 		} else {
1130 			info->user_ptr[1] = wpan_dev;
1131 		}
1132 
1133 		if (dev) {
1134 			if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1135 			    !netif_running(dev)) {
1136 				if (rtnl)
1137 					rtnl_unlock();
1138 				return -ENETDOWN;
1139 			}
1140 
1141 			dev_hold(dev);
1142 		}
1143 
1144 		info->user_ptr[0] = rdev;
1145 	}
1146 
1147 	return 0;
1148 }
1149 
1150 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1151 			       struct genl_info *info)
1152 {
1153 	if (info->user_ptr[1]) {
1154 		if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1155 			struct wpan_dev *wpan_dev = info->user_ptr[1];
1156 
1157 			if (wpan_dev->netdev)
1158 				dev_put(wpan_dev->netdev);
1159 		} else {
1160 			dev_put(info->user_ptr[1]);
1161 		}
1162 	}
1163 
1164 	if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1165 		rtnl_unlock();
1166 }
1167 
1168 static const struct genl_ops nl802154_ops[] = {
1169 	{
1170 		.cmd = NL802154_CMD_GET_WPAN_PHY,
1171 		.doit = nl802154_get_wpan_phy,
1172 		.dumpit = nl802154_dump_wpan_phy,
1173 		.done = nl802154_dump_wpan_phy_done,
1174 		.policy = nl802154_policy,
1175 		/* can be retrieved by unprivileged users */
1176 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1177 				  NL802154_FLAG_NEED_RTNL,
1178 	},
1179 	{
1180 		.cmd = NL802154_CMD_GET_INTERFACE,
1181 		.doit = nl802154_get_interface,
1182 		.dumpit = nl802154_dump_interface,
1183 		.policy = nl802154_policy,
1184 		/* can be retrieved by unprivileged users */
1185 		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1186 				  NL802154_FLAG_NEED_RTNL,
1187 	},
1188 	{
1189 		.cmd = NL802154_CMD_NEW_INTERFACE,
1190 		.doit = nl802154_new_interface,
1191 		.policy = nl802154_policy,
1192 		.flags = GENL_ADMIN_PERM,
1193 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1194 				  NL802154_FLAG_NEED_RTNL,
1195 	},
1196 	{
1197 		.cmd = NL802154_CMD_DEL_INTERFACE,
1198 		.doit = nl802154_del_interface,
1199 		.policy = nl802154_policy,
1200 		.flags = GENL_ADMIN_PERM,
1201 		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1202 				  NL802154_FLAG_NEED_RTNL,
1203 	},
1204 	{
1205 		.cmd = NL802154_CMD_SET_CHANNEL,
1206 		.doit = nl802154_set_channel,
1207 		.policy = nl802154_policy,
1208 		.flags = GENL_ADMIN_PERM,
1209 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1210 				  NL802154_FLAG_NEED_RTNL,
1211 	},
1212 	{
1213 		.cmd = NL802154_CMD_SET_CCA_MODE,
1214 		.doit = nl802154_set_cca_mode,
1215 		.policy = nl802154_policy,
1216 		.flags = GENL_ADMIN_PERM,
1217 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1218 				  NL802154_FLAG_NEED_RTNL,
1219 	},
1220 	{
1221 		.cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1222 		.doit = nl802154_set_cca_ed_level,
1223 		.policy = nl802154_policy,
1224 		.flags = GENL_ADMIN_PERM,
1225 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1226 				  NL802154_FLAG_NEED_RTNL,
1227 	},
1228 	{
1229 		.cmd = NL802154_CMD_SET_TX_POWER,
1230 		.doit = nl802154_set_tx_power,
1231 		.policy = nl802154_policy,
1232 		.flags = GENL_ADMIN_PERM,
1233 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1234 				  NL802154_FLAG_NEED_RTNL,
1235 	},
1236 	{
1237 		.cmd = NL802154_CMD_SET_PAN_ID,
1238 		.doit = nl802154_set_pan_id,
1239 		.policy = nl802154_policy,
1240 		.flags = GENL_ADMIN_PERM,
1241 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1242 				  NL802154_FLAG_NEED_RTNL,
1243 	},
1244 	{
1245 		.cmd = NL802154_CMD_SET_SHORT_ADDR,
1246 		.doit = nl802154_set_short_addr,
1247 		.policy = nl802154_policy,
1248 		.flags = GENL_ADMIN_PERM,
1249 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1250 				  NL802154_FLAG_NEED_RTNL,
1251 	},
1252 	{
1253 		.cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1254 		.doit = nl802154_set_backoff_exponent,
1255 		.policy = nl802154_policy,
1256 		.flags = GENL_ADMIN_PERM,
1257 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1258 				  NL802154_FLAG_NEED_RTNL,
1259 	},
1260 	{
1261 		.cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1262 		.doit = nl802154_set_max_csma_backoffs,
1263 		.policy = nl802154_policy,
1264 		.flags = GENL_ADMIN_PERM,
1265 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1266 				  NL802154_FLAG_NEED_RTNL,
1267 	},
1268 	{
1269 		.cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1270 		.doit = nl802154_set_max_frame_retries,
1271 		.policy = nl802154_policy,
1272 		.flags = GENL_ADMIN_PERM,
1273 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1274 				  NL802154_FLAG_NEED_RTNL,
1275 	},
1276 	{
1277 		.cmd = NL802154_CMD_SET_LBT_MODE,
1278 		.doit = nl802154_set_lbt_mode,
1279 		.policy = nl802154_policy,
1280 		.flags = GENL_ADMIN_PERM,
1281 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1282 				  NL802154_FLAG_NEED_RTNL,
1283 	},
1284 	{
1285 		.cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
1286 		.doit = nl802154_set_ackreq_default,
1287 		.policy = nl802154_policy,
1288 		.flags = GENL_ADMIN_PERM,
1289 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1290 				  NL802154_FLAG_NEED_RTNL,
1291 	},
1292 };
1293 
1294 /* initialisation/exit functions */
1295 int nl802154_init(void)
1296 {
1297 	return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1298 						    nl802154_mcgrps);
1299 }
1300 
1301 void nl802154_exit(void)
1302 {
1303 	genl_unregister_family(&nl802154_fam);
1304 }
1305