blob: 68f24016860c30c7800b36d45046cf3e7f23b8c9 [file] [log] [blame]
Alexander Aring79fe1a22014-11-09 08:36:53 +01001/* 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"
Alexander Aringab0bd562014-11-12 03:36:55 +010026#include "rdev-ops.h"
Alexander Aring79fe1a22014-11-09 08:36:53 +010027#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] = {
Alexander Aringca20ce202014-11-09 08:36:54 +0100197 [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 },
Alexander Aring4b96aea2014-11-09 08:36:55 +0100202 [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
203 [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
Alexander Aringca20ce202014-11-09 08:36:54 +0100204
205 [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
206
207 [NL802154_ATTR_PAGE] = { .type = NLA_U8, },
208 [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
209
Alexander Aring1a19cb62015-05-17 21:44:39 +0200210 [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
Alexander Aringca20ce202014-11-09 08:36:54 +0100211
Alexander Aringba2a9502014-12-10 15:33:13 +0100212 [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
213 [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
Alexander Aringe4390592015-05-27 13:42:09 +0200214 [NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
Alexander Aringca20ce202014-11-09 08:36:54 +0100215
216 [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
Alexander Aring4b96aea2014-11-09 08:36:55 +0100217
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, },
Alexander Aring0e665452015-05-17 21:44:53 +0200229
230 [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
Varka Bhadram133be022015-06-04 13:07:36 +0530231
232 [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
Alexander Aring79fe1a22014-11-09 08:36:53 +0100233};
234
235/* message building helper */
236static 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
Alexander Aringca20ce202014-11-09 08:36:54 +0100243static int
Alexander Aring0e665452015-05-17 21:44:53 +0200244nl802154_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
265static int
Alexander Aringca20ce202014-11-09 08:36:54 +0100266nl802154_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
Alexander Aringcb41c8d2014-11-17 08:20:54 +0100276 for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
Alexander Aringca20ce202014-11-09 08:36:54 +0100277 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
Alexander Aring72f655e2015-05-17 21:44:42 +0200278 rdev->wpan_phy.supported.channels[page]))
Alexander Aringca20ce202014-11-09 08:36:54 +0100279 return -ENOBUFS;
280 }
281 nla_nest_end(msg, nl_page);
282
283 return 0;
284}
285
Alexander Aring0e665452015-05-17 21:44:53 +0200286static int
287nl802154_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
Alexander Aringca20ce202014-11-09 08:36:54 +0100372static 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{
Varka Bhadram133be022015-06-04 13:07:36 +0530377 struct nlattr *nl_cmds;
Alexander Aringca20ce202014-11-09 08:36:54 +0100378 void *hdr;
Varka Bhadram133be022015-06-04 13:07:36 +0530379 int i;
Alexander Aringca20ce202014-11-09 08:36:54 +0100380
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
Alexander Aring0e665452015-05-17 21:44:53 +0200404 /* TODO remove this behaviour, we still keep support it for a while
405 * so users can change the behaviour to the new one.
406 */
Alexander Aringca20ce202014-11-09 08:36:54 +0100407 if (nl802154_send_wpan_phy_channels(rdev, msg))
408 goto nla_put_failure;
409
410 /* cca mode */
Alexander Aringedea8f72015-05-17 21:44:46 +0200411 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))
Alexander Aringba2a9502014-12-10 15:33:13 +0100414 goto nla_put_failure;
Alexander Aringedea8f72015-05-17 21:44:46 +0200415
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 }
Alexander Aringba2a9502014-12-10 15:33:13 +0100421 }
422
Alexander Aringedea8f72015-05-17 21:44:46 +0200423 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 }
Alexander Aringca20ce202014-11-09 08:36:54 +0100428
Alexander Aringe4390592015-05-27 13:42:09 +0200429 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
Alexander Aring0e665452015-05-17 21:44:53 +0200435 if (nl802154_put_capabilities(msg, rdev))
436 goto nla_put_failure;
437
Varka Bhadram133be022015-06-04 13:07:36 +0530438 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
Alexander Aringca20ce202014-11-09 08:36:54 +0100474finish:
Johannes Berg053c0952015-01-16 22:09:00 +0100475 genlmsg_end(msg, hdr);
476 return 0;
Alexander Aringca20ce202014-11-09 08:36:54 +0100477
478nla_put_failure:
479 genlmsg_cancel(msg, hdr);
480 return -EMSGSIZE;
481}
482
483struct nl802154_dump_wpan_phy_state {
484 s64 filter_wpan_phy;
485 long start;
486
487};
488
489static 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
526static int
527nl802154_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
582static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
583{
584 kfree((void *)cb->args[0]);
585 return 0;
586}
587
588static 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
Alexander Aring4b96aea2014-11-09 08:36:55 +0100606static 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
612static int
613nl802154_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
Johannes Berg053c0952015-01-16 22:09:00 +0100659 genlmsg_end(msg, hdr);
660 return 0;
Alexander Aring4b96aea2014-11-09 08:36:55 +0100661
662nla_put_failure:
663 genlmsg_cancel(msg, hdr);
664 return -EMSGSIZE;
665}
666
667static int
668nl802154_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 }
701out:
702 rtnl_unlock();
703
704 cb->args[0] = wp_idx;
705 cb->args[1] = if_idx;
706
707 return skb->len;
708}
709
710static 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
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100729static 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;
Alexander Aring0e575472014-11-17 08:20:52 +0100733 __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100734
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]);
Alexander Aring65318682015-05-17 21:44:47 +0200744 if (type > NL802154_IFTYPE_MAX ||
745 !(rdev->wpan_phy.supported.iftypes & BIT(type)))
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100746 return -EINVAL;
747 }
748
Alexander Aring0e575472014-11-17 08:20:52 +0100749 /* 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
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100754 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]),
Varka Bhadram5b4a10392015-04-30 17:44:57 +0200759 NET_NAME_USER, type, extended_addr);
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100760}
761
Alexander Aringb821ecd2014-11-17 08:20:53 +0100762static 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
Alexander Aringab0bd562014-11-12 03:36:55 +0100782static 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 */
Alexander Aring673692f2015-05-17 21:44:38 +0200795 if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
Alexander Aring72f655e2015-05-17 21:44:42 +0200796 !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
Alexander Aringab0bd562014-11-12 03:36:55 +0100797 return -EINVAL;
798
799 return rdev_set_channel(rdev, page, channel);
800}
801
Alexander Aringba2a9502014-12-10 15:33:13 +0100802static 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
Alexander Aringfc4f8052015-05-26 23:11:31 +0200807 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
Alexander Aringedea8f72015-05-17 21:44:46 +0200808 return -EOPNOTSUPP;
809
Alexander Aringba2a9502014-12-10 15:33:13 +0100810 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 */
Alexander Aringfea33182015-05-17 21:44:43 +0200815 if (cca.mode < NL802154_CCA_ENERGY ||
816 cca.mode > NL802154_CCA_ATTR_MAX ||
817 !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
Alexander Aringba2a9502014-12-10 15:33:13 +0100818 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]);
Alexander Aringfea33182015-05-17 21:44:43 +0200825 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
826 !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
Alexander Aringba2a9502014-12-10 15:33:13 +0100827 return -EINVAL;
828 }
829
830 return rdev_set_cca_mode(rdev, &cca);
831}
832
Alexander Aringb69644c2015-05-27 13:42:10 +0200833static 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
Varka Bhadram0f999b02015-05-27 09:10:54 +0530855static 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
Alexander Aring702bf372014-11-12 03:36:57 +0100877static 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;
Alexander Aringee7b9052014-11-17 08:20:55 +0100882 __le16 pan_id;
Alexander Aring702bf372014-11-12 03:36:57 +0100883
884 /* conflict here while tx/rx calls */
885 if (netif_running(dev))
886 return -EBUSY;
887
888 /* don't change address fields on monitor */
Alexander Aring0cf08792015-05-17 21:44:37 +0200889 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
890 !info->attrs[NL802154_ATTR_PAN_ID])
Alexander Aring702bf372014-11-12 03:36:57 +0100891 return -EINVAL;
892
Alexander Aringee7b9052014-11-17 08:20:55 +0100893 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
Alexander Aring702bf372014-11-12 03:36:57 +0100894
Alexander Aring673692f2015-05-17 21:44:38 +0200895 /* 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
Alexander Aring702bf372014-11-12 03:36:57 +0100905 return rdev_set_pan_id(rdev, wpan_dev, pan_id);
906}
907
Alexander Aring9830c622014-11-12 03:36:58 +0100908static 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;
Alexander Aringee7b9052014-11-17 08:20:55 +0100913 __le16 short_addr;
Alexander Aring9830c622014-11-12 03:36:58 +0100914
915 /* conflict here while tx/rx calls */
916 if (netif_running(dev))
917 return -EBUSY;
918
919 /* don't change address fields on monitor */
Alexander Aring0cf08792015-05-17 21:44:37 +0200920 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
921 !info->attrs[NL802154_ATTR_SHORT_ADDR])
Alexander Aring9830c622014-11-12 03:36:58 +0100922 return -EINVAL;
923
Alexander Aringee7b9052014-11-17 08:20:55 +0100924 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
Alexander Aring9830c622014-11-12 03:36:58 +0100925
Alexander Aring673692f2015-05-17 21:44:38 +0200926 /* 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
Alexander Aring9830c622014-11-12 03:36:58 +0100941 return rdev_set_short_addr(rdev, wpan_dev, short_addr);
942}
943
Alexander Aring656a9992014-11-12 03:36:59 +0100944static int
945nl802154_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 */
Alexander Aringfea33182015-05-17 21:44:43 +0200964 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)
Alexander Aring656a9992014-11-12 03:36:59 +0100969 return -EINVAL;
970
971 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
972}
973
Alexander Aringa01ba762014-11-12 03:37:01 +0100974static int
975nl802154_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 */
Alexander Aringfea33182015-05-17 21:44:43 +0200993 if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
994 max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
Alexander Aringa01ba762014-11-12 03:37:01 +0100995 return -EINVAL;
996
997 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
998}
999
Alexander Aring17a3a462014-11-12 03:37:03 +01001000static int
1001nl802154_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 */
Alexander Aringfea33182015-05-17 21:44:43 +02001018 if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1019 max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
Alexander Aring17a3a462014-11-12 03:37:03 +01001020 return -EINVAL;
1021
1022 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1023}
1024
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001025static 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]);
Alexander Aringfea33182015-05-17 21:44:43 +02001039 if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1040 return -EINVAL;
1041
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001042 return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1043}
1044
Alexander Aring79fe1a22014-11-09 08:36:53 +01001045#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
1055static 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
1117static 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
1135static const struct genl_ops nl802154_ops[] = {
Alexander Aringca20ce202014-11-09 08:36:54 +01001136 {
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 },
Alexander Aring4b96aea2014-11-09 08:36:55 +01001146 {
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 },
Alexander Aringab0bd562014-11-12 03:36:55 +01001155 {
Alexander Aringf3ea5e42014-11-17 08:20:51 +01001156 .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 {
Alexander Aringb821ecd2014-11-17 08:20:53 +01001164 .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 {
Alexander Aringab0bd562014-11-12 03:36:55 +01001172 .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 },
Alexander Aring702bf372014-11-12 03:36:57 +01001179 {
Alexander Aringba2a9502014-12-10 15:33:13 +01001180 .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 {
Alexander Aringb69644c2015-05-27 13:42:10 +02001188 .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 {
Varka Bhadram0f999b02015-05-27 09:10:54 +05301196 .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 {
Alexander Aring702bf372014-11-12 03:36:57 +01001204 .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 },
Alexander Aring9830c622014-11-12 03:36:58 +01001211 {
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 },
Alexander Aring656a9992014-11-12 03:36:59 +01001219 {
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 },
Alexander Aringa01ba762014-11-12 03:37:01 +01001227 {
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 },
Alexander Aring17a3a462014-11-12 03:37:03 +01001235 {
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 },
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001243 {
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 },
Alexander Aring79fe1a22014-11-09 08:36:53 +01001251};
1252
1253/* initialisation/exit functions */
1254int nl802154_init(void)
1255{
1256 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1257 nl802154_mcgrps);
1258}
1259
1260void nl802154_exit(void)
1261{
1262 genl_unregister_family(&nl802154_fam);
1263}