xref: /openbmc/linux/net/ieee802154/nl802154.c (revision 61c610ec)
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 
235 /* message building helper */
236 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
237 				    int flags, u8 cmd)
238 {
239 	/* since there is no private header just add the generic one */
240 	return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
241 }
242 
243 static int
244 nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
245 {
246 	struct nlattr *nl_flags = nla_nest_start(msg, attr);
247 	int i;
248 
249 	if (!nl_flags)
250 		return -ENOBUFS;
251 
252 	i = 0;
253 	while (mask) {
254 		if ((mask & 1) && nla_put_flag(msg, i))
255 			return -ENOBUFS;
256 
257 		mask >>= 1;
258 		i++;
259 	}
260 
261 	nla_nest_end(msg, nl_flags);
262 	return 0;
263 }
264 
265 static int
266 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
267 				struct sk_buff *msg)
268 {
269 	struct nlattr *nl_page;
270 	unsigned long page;
271 
272 	nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
273 	if (!nl_page)
274 		return -ENOBUFS;
275 
276 	for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
277 		if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
278 				rdev->wpan_phy.supported.channels[page]))
279 			return -ENOBUFS;
280 	}
281 	nla_nest_end(msg, nl_page);
282 
283 	return 0;
284 }
285 
286 static int
287 nl802154_put_capabilities(struct sk_buff *msg,
288 			  struct cfg802154_registered_device *rdev)
289 {
290 	const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
291 	struct nlattr *nl_caps, *nl_channels;
292 	int i;
293 
294 	nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
295 	if (!nl_caps)
296 		return -ENOBUFS;
297 
298 	nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
299 	if (!nl_channels)
300 		return -ENOBUFS;
301 
302 	for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
303 		if (caps->channels[i]) {
304 			if (nl802154_put_flags(msg, i, caps->channels[i]))
305 				return -ENOBUFS;
306 		}
307 	}
308 
309 	nla_nest_end(msg, nl_channels);
310 
311 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
312 		struct nlattr *nl_ed_lvls;
313 
314 		nl_ed_lvls = nla_nest_start(msg,
315 					    NL802154_CAP_ATTR_CCA_ED_LEVELS);
316 		if (!nl_ed_lvls)
317 			return -ENOBUFS;
318 
319 		for (i = 0; i < caps->cca_ed_levels_size; i++) {
320 			if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
321 				return -ENOBUFS;
322 		}
323 
324 		nla_nest_end(msg, nl_ed_lvls);
325 	}
326 
327 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
328 		struct nlattr *nl_tx_pwrs;
329 
330 		nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
331 		if (!nl_tx_pwrs)
332 			return -ENOBUFS;
333 
334 		for (i = 0; i < caps->tx_powers_size; i++) {
335 			if (nla_put_s32(msg, i, caps->tx_powers[i]))
336 				return -ENOBUFS;
337 		}
338 
339 		nla_nest_end(msg, nl_tx_pwrs);
340 	}
341 
342 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
343 		if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
344 				       caps->cca_modes) ||
345 		    nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
346 				       caps->cca_opts))
347 			return -ENOBUFS;
348 	}
349 
350 	if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
351 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
352 	    nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
353 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
354 	    nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
355 		       caps->min_csma_backoffs) ||
356 	    nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
357 		       caps->max_csma_backoffs) ||
358 	    nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
359 		       caps->min_frame_retries) ||
360 	    nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
361 		       caps->max_frame_retries) ||
362 	    nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
363 			       caps->iftypes) ||
364 	    nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
365 		return -ENOBUFS;
366 
367 	nla_nest_end(msg, nl_caps);
368 
369 	return 0;
370 }
371 
372 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
373 				  enum nl802154_commands cmd,
374 				  struct sk_buff *msg, u32 portid, u32 seq,
375 				  int flags)
376 {
377 	struct nlattr *nl_cmds;
378 	void *hdr;
379 	int i;
380 
381 	hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
382 	if (!hdr)
383 		return -ENOBUFS;
384 
385 	if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
386 	    nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
387 			   wpan_phy_name(&rdev->wpan_phy)) ||
388 	    nla_put_u32(msg, NL802154_ATTR_GENERATION,
389 			cfg802154_rdev_list_generation))
390 		goto nla_put_failure;
391 
392 	if (cmd != NL802154_CMD_NEW_WPAN_PHY)
393 		goto finish;
394 
395 	/* DUMP PHY PIB */
396 
397 	/* current channel settings */
398 	if (nla_put_u8(msg, NL802154_ATTR_PAGE,
399 		       rdev->wpan_phy.current_page) ||
400 	    nla_put_u8(msg, NL802154_ATTR_CHANNEL,
401 		       rdev->wpan_phy.current_channel))
402 		goto nla_put_failure;
403 
404 	/* TODO remove this behaviour, we still keep support it for a while
405 	 * so users can change the behaviour to the new one.
406 	 */
407 	if (nl802154_send_wpan_phy_channels(rdev, msg))
408 		goto nla_put_failure;
409 
410 	/* cca mode */
411 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
412 		if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
413 				rdev->wpan_phy.cca.mode))
414 			goto nla_put_failure;
415 
416 		if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
417 			if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
418 					rdev->wpan_phy.cca.opt))
419 				goto nla_put_failure;
420 		}
421 	}
422 
423 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
424 		if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
425 				rdev->wpan_phy.transmit_power))
426 			goto nla_put_failure;
427 	}
428 
429 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
430 		if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
431 				rdev->wpan_phy.cca_ed_level))
432 			goto nla_put_failure;
433 	}
434 
435 	if (nl802154_put_capabilities(msg, rdev))
436 		goto nla_put_failure;
437 
438 	nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
439 	if (!nl_cmds)
440 		goto nla_put_failure;
441 
442 	i = 0;
443 #define CMD(op, n)							\
444 	do {								\
445 		if (rdev->ops->op) {					\
446 			i++;						\
447 			if (nla_put_u32(msg, i, NL802154_CMD_ ## n))	\
448 				goto nla_put_failure;			\
449 		}							\
450 	} while (0)
451 
452 	CMD(add_virtual_intf, NEW_INTERFACE);
453 	CMD(del_virtual_intf, DEL_INTERFACE);
454 	CMD(set_channel, SET_CHANNEL);
455 	CMD(set_pan_id, SET_PAN_ID);
456 	CMD(set_short_addr, SET_SHORT_ADDR);
457 	CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
458 	CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
459 	CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
460 	CMD(set_lbt_mode, SET_LBT_MODE);
461 
462 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
463 		CMD(set_tx_power, SET_TX_POWER);
464 
465 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
466 		CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
467 
468 	if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
469 		CMD(set_cca_mode, SET_CCA_MODE);
470 
471 #undef CMD
472 	nla_nest_end(msg, nl_cmds);
473 
474 finish:
475 	genlmsg_end(msg, hdr);
476 	return 0;
477 
478 nla_put_failure:
479 	genlmsg_cancel(msg, hdr);
480 	return -EMSGSIZE;
481 }
482 
483 struct nl802154_dump_wpan_phy_state {
484 	s64 filter_wpan_phy;
485 	long start;
486 
487 };
488 
489 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
490 					struct netlink_callback *cb,
491 					struct nl802154_dump_wpan_phy_state *state)
492 {
493 	struct nlattr **tb = nl802154_fam.attrbuf;
494 	int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
495 			      tb, nl802154_fam.maxattr, nl802154_policy);
496 
497 	/* TODO check if we can handle error here,
498 	 * we have no backward compatibility
499 	 */
500 	if (ret)
501 		return 0;
502 
503 	if (tb[NL802154_ATTR_WPAN_PHY])
504 		state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
505 	if (tb[NL802154_ATTR_WPAN_DEV])
506 		state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
507 	if (tb[NL802154_ATTR_IFINDEX]) {
508 		struct net_device *netdev;
509 		struct cfg802154_registered_device *rdev;
510 		int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
511 
512 		/* TODO netns */
513 		netdev = __dev_get_by_index(&init_net, ifidx);
514 		if (!netdev)
515 			return -ENODEV;
516 		if (netdev->ieee802154_ptr) {
517 			rdev = wpan_phy_to_rdev(
518 					netdev->ieee802154_ptr->wpan_phy);
519 			state->filter_wpan_phy = rdev->wpan_phy_idx;
520 		}
521 	}
522 
523 	return 0;
524 }
525 
526 static int
527 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
528 {
529 	int idx = 0, ret;
530 	struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
531 	struct cfg802154_registered_device *rdev;
532 
533 	rtnl_lock();
534 	if (!state) {
535 		state = kzalloc(sizeof(*state), GFP_KERNEL);
536 		if (!state) {
537 			rtnl_unlock();
538 			return -ENOMEM;
539 		}
540 		state->filter_wpan_phy = -1;
541 		ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
542 		if (ret) {
543 			kfree(state);
544 			rtnl_unlock();
545 			return ret;
546 		}
547 		cb->args[0] = (long)state;
548 	}
549 
550 	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
551 		/* TODO net ns compare */
552 		if (++idx <= state->start)
553 			continue;
554 		if (state->filter_wpan_phy != -1 &&
555 		    state->filter_wpan_phy != rdev->wpan_phy_idx)
556 			continue;
557 		/* attempt to fit multiple wpan_phy data chunks into the skb */
558 		ret = nl802154_send_wpan_phy(rdev,
559 					     NL802154_CMD_NEW_WPAN_PHY,
560 					     skb,
561 					     NETLINK_CB(cb->skb).portid,
562 					     cb->nlh->nlmsg_seq, NLM_F_MULTI);
563 		if (ret < 0) {
564 			if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
565 			    !skb->len && cb->min_dump_alloc < 4096) {
566 				cb->min_dump_alloc = 4096;
567 				rtnl_unlock();
568 				return 1;
569 			}
570 			idx--;
571 			break;
572 		}
573 		break;
574 	}
575 	rtnl_unlock();
576 
577 	state->start = idx;
578 
579 	return skb->len;
580 }
581 
582 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
583 {
584 	kfree((void *)cb->args[0]);
585 	return 0;
586 }
587 
588 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
589 {
590 	struct sk_buff *msg;
591 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
592 
593 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
594 	if (!msg)
595 		return -ENOMEM;
596 
597 	if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
598 				   info->snd_portid, info->snd_seq, 0) < 0) {
599 		nlmsg_free(msg);
600 		return -ENOBUFS;
601 	}
602 
603 	return genlmsg_reply(msg, info);
604 }
605 
606 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
607 {
608 	return (u64)wpan_dev->identifier |
609 	       ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
610 }
611 
612 static int
613 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
614 		    struct cfg802154_registered_device *rdev,
615 		    struct wpan_dev *wpan_dev)
616 {
617 	struct net_device *dev = wpan_dev->netdev;
618 	void *hdr;
619 
620 	hdr = nl802154hdr_put(msg, portid, seq, flags,
621 			      NL802154_CMD_NEW_INTERFACE);
622 	if (!hdr)
623 		return -1;
624 
625 	if (dev &&
626 	    (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
627 	     nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
628 		goto nla_put_failure;
629 
630 	if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
631 	    nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
632 	    nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
633 	    nla_put_u32(msg, NL802154_ATTR_GENERATION,
634 			rdev->devlist_generation ^
635 			(cfg802154_rdev_list_generation << 2)))
636 		goto nla_put_failure;
637 
638 	/* address settings */
639 	if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
640 			 wpan_dev->extended_addr) ||
641 	    nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
642 			 wpan_dev->short_addr) ||
643 	    nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
644 		goto nla_put_failure;
645 
646 	/* ARET handling */
647 	if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
648 		       wpan_dev->frame_retries) ||
649 	    nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
650 	    nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
651 		       wpan_dev->csma_retries) ||
652 	    nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
653 		goto nla_put_failure;
654 
655 	/* listen before transmit */
656 	if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
657 		goto nla_put_failure;
658 
659 	genlmsg_end(msg, hdr);
660 	return 0;
661 
662 nla_put_failure:
663 	genlmsg_cancel(msg, hdr);
664 	return -EMSGSIZE;
665 }
666 
667 static int
668 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
669 {
670 	int wp_idx = 0;
671 	int if_idx = 0;
672 	int wp_start = cb->args[0];
673 	int if_start = cb->args[1];
674 	struct cfg802154_registered_device *rdev;
675 	struct wpan_dev *wpan_dev;
676 
677 	rtnl_lock();
678 	list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
679 		/* TODO netns compare */
680 		if (wp_idx < wp_start) {
681 			wp_idx++;
682 			continue;
683 		}
684 		if_idx = 0;
685 
686 		list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
687 			if (if_idx < if_start) {
688 				if_idx++;
689 				continue;
690 			}
691 			if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
692 						cb->nlh->nlmsg_seq, NLM_F_MULTI,
693 						rdev, wpan_dev) < 0) {
694 				goto out;
695 			}
696 			if_idx++;
697 		}
698 
699 		wp_idx++;
700 	}
701 out:
702 	rtnl_unlock();
703 
704 	cb->args[0] = wp_idx;
705 	cb->args[1] = if_idx;
706 
707 	return skb->len;
708 }
709 
710 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
711 {
712 	struct sk_buff *msg;
713 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
714 	struct wpan_dev *wdev = info->user_ptr[1];
715 
716 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
717 	if (!msg)
718 		return -ENOMEM;
719 
720 	if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
721 				rdev, wdev) < 0) {
722 		nlmsg_free(msg);
723 		return -ENOBUFS;
724 	}
725 
726 	return genlmsg_reply(msg, info);
727 }
728 
729 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
730 {
731 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
732 	enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
733 	__le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
734 
735 	/* TODO avoid failing a new interface
736 	 * creation due to pending removal?
737 	 */
738 
739 	if (!info->attrs[NL802154_ATTR_IFNAME])
740 		return -EINVAL;
741 
742 	if (info->attrs[NL802154_ATTR_IFTYPE]) {
743 		type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
744 		if (type > NL802154_IFTYPE_MAX ||
745 		    !(rdev->wpan_phy.supported.iftypes & BIT(type)))
746 			return -EINVAL;
747 	}
748 
749 	/* TODO add nla_get_le64 to netlink */
750 	if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
751 		extended_addr = (__force __le64)nla_get_u64(
752 				info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
753 
754 	if (!rdev->ops->add_virtual_intf)
755 		return -EOPNOTSUPP;
756 
757 	return rdev_add_virtual_intf(rdev,
758 				     nla_data(info->attrs[NL802154_ATTR_IFNAME]),
759 				     NET_NAME_USER, type, extended_addr);
760 }
761 
762 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
763 {
764 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
765 	struct wpan_dev *wpan_dev = info->user_ptr[1];
766 
767 	if (!rdev->ops->del_virtual_intf)
768 		return -EOPNOTSUPP;
769 
770 	/* If we remove a wpan device without a netdev then clear
771 	 * user_ptr[1] so that nl802154_post_doit won't dereference it
772 	 * to check if it needs to do dev_put(). Otherwise it crashes
773 	 * since the wpan_dev has been freed, unlike with a netdev where
774 	 * we need the dev_put() for the netdev to really be freed.
775 	 */
776 	if (!wpan_dev->netdev)
777 		info->user_ptr[1] = NULL;
778 
779 	return rdev_del_virtual_intf(rdev, wpan_dev);
780 }
781 
782 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
783 {
784 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
785 	u8 channel, page;
786 
787 	if (!info->attrs[NL802154_ATTR_PAGE] ||
788 	    !info->attrs[NL802154_ATTR_CHANNEL])
789 		return -EINVAL;
790 
791 	page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
792 	channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
793 
794 	/* check 802.15.4 constraints */
795 	if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
796 	    !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
797 		return -EINVAL;
798 
799 	return rdev_set_channel(rdev, page, channel);
800 }
801 
802 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
803 {
804 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
805 	struct wpan_phy_cca cca;
806 
807 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
808 		return -EOPNOTSUPP;
809 
810 	if (!info->attrs[NL802154_ATTR_CCA_MODE])
811 		return -EINVAL;
812 
813 	cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
814 	/* checking 802.15.4 constraints */
815 	if (cca.mode < NL802154_CCA_ENERGY ||
816 	    cca.mode > NL802154_CCA_ATTR_MAX ||
817 	    !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
818 		return -EINVAL;
819 
820 	if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
821 		if (!info->attrs[NL802154_ATTR_CCA_OPT])
822 			return -EINVAL;
823 
824 		cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
825 		if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
826 		    !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
827 			return -EINVAL;
828 	}
829 
830 	return rdev_set_cca_mode(rdev, &cca);
831 }
832 
833 static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
834 {
835 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
836 	s32 ed_level;
837 	int i;
838 
839 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
840 		return -EOPNOTSUPP;
841 
842 	if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
843 		return -EINVAL;
844 
845 	ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
846 
847 	for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
848 		if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
849 			return rdev_set_cca_ed_level(rdev, ed_level);
850 	}
851 
852 	return -EINVAL;
853 }
854 
855 static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
856 {
857 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
858 	s32 power;
859 	int i;
860 
861 	if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
862 		return -EOPNOTSUPP;
863 
864 	if (!info->attrs[NL802154_ATTR_TX_POWER])
865 		return -EINVAL;
866 
867 	power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
868 
869 	for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
870 		if (power == rdev->wpan_phy.supported.tx_powers[i])
871 			return rdev_set_tx_power(rdev, power);
872 	}
873 
874 	return -EINVAL;
875 }
876 
877 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
878 {
879 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
880 	struct net_device *dev = info->user_ptr[1];
881 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
882 	__le16 pan_id;
883 
884 	/* conflict here while tx/rx calls */
885 	if (netif_running(dev))
886 		return -EBUSY;
887 
888 	/* don't change address fields on monitor */
889 	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
890 	    !info->attrs[NL802154_ATTR_PAN_ID])
891 		return -EINVAL;
892 
893 	pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
894 
895 	/* TODO
896 	 * I am not sure about to check here on broadcast pan_id.
897 	 * Broadcast is a valid setting, comment from 802.15.4:
898 	 * If this value is 0xffff, the device is not associated.
899 	 *
900 	 * This could useful to simple deassociate an device.
901 	 */
902 	if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
903 		return -EINVAL;
904 
905 	return rdev_set_pan_id(rdev, wpan_dev, pan_id);
906 }
907 
908 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
909 {
910 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
911 	struct net_device *dev = info->user_ptr[1];
912 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
913 	__le16 short_addr;
914 
915 	/* conflict here while tx/rx calls */
916 	if (netif_running(dev))
917 		return -EBUSY;
918 
919 	/* don't change address fields on monitor */
920 	if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
921 	    !info->attrs[NL802154_ATTR_SHORT_ADDR])
922 		return -EINVAL;
923 
924 	short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
925 
926 	/* TODO
927 	 * I am not sure about to check here on broadcast short_addr.
928 	 * Broadcast is a valid setting, comment from 802.15.4:
929 	 * A value of 0xfffe indicates that the device has
930 	 * associated but has not been allocated an address. A
931 	 * value of 0xffff indicates that the device does not
932 	 * have a short address.
933 	 *
934 	 * I think we should allow to set these settings but
935 	 * don't allow to allow socket communication with it.
936 	 */
937 	if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
938 	    short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
939 		return -EINVAL;
940 
941 	return rdev_set_short_addr(rdev, wpan_dev, short_addr);
942 }
943 
944 static int
945 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
946 {
947 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
948 	struct net_device *dev = info->user_ptr[1];
949 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
950 	u8 min_be, max_be;
951 
952 	/* should be set on netif open inside phy settings */
953 	if (netif_running(dev))
954 		return -EBUSY;
955 
956 	if (!info->attrs[NL802154_ATTR_MIN_BE] ||
957 	    !info->attrs[NL802154_ATTR_MAX_BE])
958 		return -EINVAL;
959 
960 	min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
961 	max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
962 
963 	/* check 802.15.4 constraints */
964 	if (min_be < rdev->wpan_phy.supported.min_minbe ||
965 	    min_be > rdev->wpan_phy.supported.max_minbe ||
966 	    max_be < rdev->wpan_phy.supported.min_maxbe ||
967 	    max_be > rdev->wpan_phy.supported.max_maxbe ||
968 	    min_be > max_be)
969 		return -EINVAL;
970 
971 	return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
972 }
973 
974 static int
975 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
976 {
977 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
978 	struct net_device *dev = info->user_ptr[1];
979 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
980 	u8 max_csma_backoffs;
981 
982 	/* conflict here while other running iface settings */
983 	if (netif_running(dev))
984 		return -EBUSY;
985 
986 	if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
987 		return -EINVAL;
988 
989 	max_csma_backoffs = nla_get_u8(
990 			info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
991 
992 	/* check 802.15.4 constraints */
993 	if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
994 	    max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
995 		return -EINVAL;
996 
997 	return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
998 }
999 
1000 static int
1001 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1002 {
1003 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
1004 	struct net_device *dev = info->user_ptr[1];
1005 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1006 	s8 max_frame_retries;
1007 
1008 	if (netif_running(dev))
1009 		return -EBUSY;
1010 
1011 	if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1012 		return -EINVAL;
1013 
1014 	max_frame_retries = nla_get_s8(
1015 			info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1016 
1017 	/* check 802.15.4 constraints */
1018 	if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1019 	    max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1020 		return -EINVAL;
1021 
1022 	return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1023 }
1024 
1025 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1026 {
1027 	struct cfg802154_registered_device *rdev = info->user_ptr[0];
1028 	struct net_device *dev = info->user_ptr[1];
1029 	struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1030 	bool mode;
1031 
1032 	if (netif_running(dev))
1033 		return -EBUSY;
1034 
1035 	if (!info->attrs[NL802154_ATTR_LBT_MODE])
1036 		return -EINVAL;
1037 
1038 	mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1039 	if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1040 		return -EINVAL;
1041 
1042 	return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1043 }
1044 
1045 #define NL802154_FLAG_NEED_WPAN_PHY	0x01
1046 #define NL802154_FLAG_NEED_NETDEV	0x02
1047 #define NL802154_FLAG_NEED_RTNL		0x04
1048 #define NL802154_FLAG_CHECK_NETDEV_UP	0x08
1049 #define NL802154_FLAG_NEED_NETDEV_UP	(NL802154_FLAG_NEED_NETDEV |\
1050 					 NL802154_FLAG_CHECK_NETDEV_UP)
1051 #define NL802154_FLAG_NEED_WPAN_DEV	0x10
1052 #define NL802154_FLAG_NEED_WPAN_DEV_UP	(NL802154_FLAG_NEED_WPAN_DEV |\
1053 					 NL802154_FLAG_CHECK_NETDEV_UP)
1054 
1055 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1056 			     struct genl_info *info)
1057 {
1058 	struct cfg802154_registered_device *rdev;
1059 	struct wpan_dev *wpan_dev;
1060 	struct net_device *dev;
1061 	bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1062 
1063 	if (rtnl)
1064 		rtnl_lock();
1065 
1066 	if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1067 		rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1068 		if (IS_ERR(rdev)) {
1069 			if (rtnl)
1070 				rtnl_unlock();
1071 			return PTR_ERR(rdev);
1072 		}
1073 		info->user_ptr[0] = rdev;
1074 	} else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1075 		   ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1076 		ASSERT_RTNL();
1077 		wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1078 							   info->attrs);
1079 		if (IS_ERR(wpan_dev)) {
1080 			if (rtnl)
1081 				rtnl_unlock();
1082 			return PTR_ERR(wpan_dev);
1083 		}
1084 
1085 		dev = wpan_dev->netdev;
1086 		rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1087 
1088 		if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1089 			if (!dev) {
1090 				if (rtnl)
1091 					rtnl_unlock();
1092 				return -EINVAL;
1093 			}
1094 
1095 			info->user_ptr[1] = dev;
1096 		} else {
1097 			info->user_ptr[1] = wpan_dev;
1098 		}
1099 
1100 		if (dev) {
1101 			if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1102 			    !netif_running(dev)) {
1103 				if (rtnl)
1104 					rtnl_unlock();
1105 				return -ENETDOWN;
1106 			}
1107 
1108 			dev_hold(dev);
1109 		}
1110 
1111 		info->user_ptr[0] = rdev;
1112 	}
1113 
1114 	return 0;
1115 }
1116 
1117 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1118 			       struct genl_info *info)
1119 {
1120 	if (info->user_ptr[1]) {
1121 		if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1122 			struct wpan_dev *wpan_dev = info->user_ptr[1];
1123 
1124 			if (wpan_dev->netdev)
1125 				dev_put(wpan_dev->netdev);
1126 		} else {
1127 			dev_put(info->user_ptr[1]);
1128 		}
1129 	}
1130 
1131 	if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1132 		rtnl_unlock();
1133 }
1134 
1135 static const struct genl_ops nl802154_ops[] = {
1136 	{
1137 		.cmd = NL802154_CMD_GET_WPAN_PHY,
1138 		.doit = nl802154_get_wpan_phy,
1139 		.dumpit = nl802154_dump_wpan_phy,
1140 		.done = nl802154_dump_wpan_phy_done,
1141 		.policy = nl802154_policy,
1142 		/* can be retrieved by unprivileged users */
1143 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1144 				  NL802154_FLAG_NEED_RTNL,
1145 	},
1146 	{
1147 		.cmd = NL802154_CMD_GET_INTERFACE,
1148 		.doit = nl802154_get_interface,
1149 		.dumpit = nl802154_dump_interface,
1150 		.policy = nl802154_policy,
1151 		/* can be retrieved by unprivileged users */
1152 		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1153 				  NL802154_FLAG_NEED_RTNL,
1154 	},
1155 	{
1156 		.cmd = NL802154_CMD_NEW_INTERFACE,
1157 		.doit = nl802154_new_interface,
1158 		.policy = nl802154_policy,
1159 		.flags = GENL_ADMIN_PERM,
1160 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1161 				  NL802154_FLAG_NEED_RTNL,
1162 	},
1163 	{
1164 		.cmd = NL802154_CMD_DEL_INTERFACE,
1165 		.doit = nl802154_del_interface,
1166 		.policy = nl802154_policy,
1167 		.flags = GENL_ADMIN_PERM,
1168 		.internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1169 				  NL802154_FLAG_NEED_RTNL,
1170 	},
1171 	{
1172 		.cmd = NL802154_CMD_SET_CHANNEL,
1173 		.doit = nl802154_set_channel,
1174 		.policy = nl802154_policy,
1175 		.flags = GENL_ADMIN_PERM,
1176 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1177 				  NL802154_FLAG_NEED_RTNL,
1178 	},
1179 	{
1180 		.cmd = NL802154_CMD_SET_CCA_MODE,
1181 		.doit = nl802154_set_cca_mode,
1182 		.policy = nl802154_policy,
1183 		.flags = GENL_ADMIN_PERM,
1184 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1185 				  NL802154_FLAG_NEED_RTNL,
1186 	},
1187 	{
1188 		.cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1189 		.doit = nl802154_set_cca_ed_level,
1190 		.policy = nl802154_policy,
1191 		.flags = GENL_ADMIN_PERM,
1192 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1193 				  NL802154_FLAG_NEED_RTNL,
1194 	},
1195 	{
1196 		.cmd = NL802154_CMD_SET_TX_POWER,
1197 		.doit = nl802154_set_tx_power,
1198 		.policy = nl802154_policy,
1199 		.flags = GENL_ADMIN_PERM,
1200 		.internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1201 				  NL802154_FLAG_NEED_RTNL,
1202 	},
1203 	{
1204 		.cmd = NL802154_CMD_SET_PAN_ID,
1205 		.doit = nl802154_set_pan_id,
1206 		.policy = nl802154_policy,
1207 		.flags = GENL_ADMIN_PERM,
1208 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1209 				  NL802154_FLAG_NEED_RTNL,
1210 	},
1211 	{
1212 		.cmd = NL802154_CMD_SET_SHORT_ADDR,
1213 		.doit = nl802154_set_short_addr,
1214 		.policy = nl802154_policy,
1215 		.flags = GENL_ADMIN_PERM,
1216 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1217 				  NL802154_FLAG_NEED_RTNL,
1218 	},
1219 	{
1220 		.cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1221 		.doit = nl802154_set_backoff_exponent,
1222 		.policy = nl802154_policy,
1223 		.flags = GENL_ADMIN_PERM,
1224 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1225 				  NL802154_FLAG_NEED_RTNL,
1226 	},
1227 	{
1228 		.cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1229 		.doit = nl802154_set_max_csma_backoffs,
1230 		.policy = nl802154_policy,
1231 		.flags = GENL_ADMIN_PERM,
1232 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1233 				  NL802154_FLAG_NEED_RTNL,
1234 	},
1235 	{
1236 		.cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1237 		.doit = nl802154_set_max_frame_retries,
1238 		.policy = nl802154_policy,
1239 		.flags = GENL_ADMIN_PERM,
1240 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1241 				  NL802154_FLAG_NEED_RTNL,
1242 	},
1243 	{
1244 		.cmd = NL802154_CMD_SET_LBT_MODE,
1245 		.doit = nl802154_set_lbt_mode,
1246 		.policy = nl802154_policy,
1247 		.flags = GENL_ADMIN_PERM,
1248 		.internal_flags = NL802154_FLAG_NEED_NETDEV |
1249 				  NL802154_FLAG_NEED_RTNL,
1250 	},
1251 };
1252 
1253 /* initialisation/exit functions */
1254 int nl802154_init(void)
1255 {
1256 	return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1257 						    nl802154_mcgrps);
1258 }
1259 
1260 void nl802154_exit(void)
1261 {
1262 	genl_unregister_family(&nl802154_fam);
1263 }
1264