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