blob: 51110a6d3674b1e57b4dacce34b268f4c36f4e95 [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 Aringc91208d2015-08-10 21:15:58 +0200233
234 [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
Alexander Aring79fe1a22014-11-09 08:36:53 +0100235};
236
237/* message building helper */
238static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
239 int flags, u8 cmd)
240{
241 /* since there is no private header just add the generic one */
242 return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
243}
244
Alexander Aringca20ce202014-11-09 08:36:54 +0100245static int
Alexander Aring0e665452015-05-17 21:44:53 +0200246nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
247{
248 struct nlattr *nl_flags = nla_nest_start(msg, attr);
249 int i;
250
251 if (!nl_flags)
252 return -ENOBUFS;
253
254 i = 0;
255 while (mask) {
256 if ((mask & 1) && nla_put_flag(msg, i))
257 return -ENOBUFS;
258
259 mask >>= 1;
260 i++;
261 }
262
263 nla_nest_end(msg, nl_flags);
264 return 0;
265}
266
267static int
Alexander Aringca20ce202014-11-09 08:36:54 +0100268nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
269 struct sk_buff *msg)
270{
271 struct nlattr *nl_page;
272 unsigned long page;
273
274 nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
275 if (!nl_page)
276 return -ENOBUFS;
277
Alexander Aringcb41c8d2014-11-17 08:20:54 +0100278 for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
Alexander Aringca20ce202014-11-09 08:36:54 +0100279 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
Alexander Aring72f655e2015-05-17 21:44:42 +0200280 rdev->wpan_phy.supported.channels[page]))
Alexander Aringca20ce202014-11-09 08:36:54 +0100281 return -ENOBUFS;
282 }
283 nla_nest_end(msg, nl_page);
284
285 return 0;
286}
287
Alexander Aring0e665452015-05-17 21:44:53 +0200288static int
289nl802154_put_capabilities(struct sk_buff *msg,
290 struct cfg802154_registered_device *rdev)
291{
292 const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
293 struct nlattr *nl_caps, *nl_channels;
294 int i;
295
296 nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
297 if (!nl_caps)
298 return -ENOBUFS;
299
300 nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
301 if (!nl_channels)
302 return -ENOBUFS;
303
304 for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
305 if (caps->channels[i]) {
306 if (nl802154_put_flags(msg, i, caps->channels[i]))
307 return -ENOBUFS;
308 }
309 }
310
311 nla_nest_end(msg, nl_channels);
312
313 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
314 struct nlattr *nl_ed_lvls;
315
316 nl_ed_lvls = nla_nest_start(msg,
317 NL802154_CAP_ATTR_CCA_ED_LEVELS);
318 if (!nl_ed_lvls)
319 return -ENOBUFS;
320
321 for (i = 0; i < caps->cca_ed_levels_size; i++) {
322 if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
323 return -ENOBUFS;
324 }
325
326 nla_nest_end(msg, nl_ed_lvls);
327 }
328
329 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
330 struct nlattr *nl_tx_pwrs;
331
332 nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
333 if (!nl_tx_pwrs)
334 return -ENOBUFS;
335
336 for (i = 0; i < caps->tx_powers_size; i++) {
337 if (nla_put_s32(msg, i, caps->tx_powers[i]))
338 return -ENOBUFS;
339 }
340
341 nla_nest_end(msg, nl_tx_pwrs);
342 }
343
344 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
345 if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
346 caps->cca_modes) ||
347 nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
348 caps->cca_opts))
349 return -ENOBUFS;
350 }
351
352 if (nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MINBE, caps->min_minbe) ||
353 nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MINBE, caps->max_minbe) ||
354 nla_put_u8(msg, NL802154_CAP_ATTR_MIN_MAXBE, caps->min_maxbe) ||
355 nla_put_u8(msg, NL802154_CAP_ATTR_MAX_MAXBE, caps->max_maxbe) ||
356 nla_put_u8(msg, NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS,
357 caps->min_csma_backoffs) ||
358 nla_put_u8(msg, NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS,
359 caps->max_csma_backoffs) ||
360 nla_put_s8(msg, NL802154_CAP_ATTR_MIN_FRAME_RETRIES,
361 caps->min_frame_retries) ||
362 nla_put_s8(msg, NL802154_CAP_ATTR_MAX_FRAME_RETRIES,
363 caps->max_frame_retries) ||
364 nl802154_put_flags(msg, NL802154_CAP_ATTR_IFTYPES,
365 caps->iftypes) ||
366 nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
367 return -ENOBUFS;
368
369 nla_nest_end(msg, nl_caps);
370
371 return 0;
372}
373
Alexander Aringca20ce202014-11-09 08:36:54 +0100374static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
375 enum nl802154_commands cmd,
376 struct sk_buff *msg, u32 portid, u32 seq,
377 int flags)
378{
Varka Bhadram133be022015-06-04 13:07:36 +0530379 struct nlattr *nl_cmds;
Alexander Aringca20ce202014-11-09 08:36:54 +0100380 void *hdr;
Varka Bhadram133be022015-06-04 13:07:36 +0530381 int i;
Alexander Aringca20ce202014-11-09 08:36:54 +0100382
383 hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
384 if (!hdr)
385 return -ENOBUFS;
386
387 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
388 nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
389 wpan_phy_name(&rdev->wpan_phy)) ||
390 nla_put_u32(msg, NL802154_ATTR_GENERATION,
391 cfg802154_rdev_list_generation))
392 goto nla_put_failure;
393
394 if (cmd != NL802154_CMD_NEW_WPAN_PHY)
395 goto finish;
396
397 /* DUMP PHY PIB */
398
399 /* current channel settings */
400 if (nla_put_u8(msg, NL802154_ATTR_PAGE,
401 rdev->wpan_phy.current_page) ||
402 nla_put_u8(msg, NL802154_ATTR_CHANNEL,
403 rdev->wpan_phy.current_channel))
404 goto nla_put_failure;
405
Alexander Aring0e665452015-05-17 21:44:53 +0200406 /* TODO remove this behaviour, we still keep support it for a while
407 * so users can change the behaviour to the new one.
408 */
Alexander Aringca20ce202014-11-09 08:36:54 +0100409 if (nl802154_send_wpan_phy_channels(rdev, msg))
410 goto nla_put_failure;
411
412 /* cca mode */
Alexander Aringedea8f72015-05-17 21:44:46 +0200413 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
414 if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
415 rdev->wpan_phy.cca.mode))
Alexander Aringba2a9502014-12-10 15:33:13 +0100416 goto nla_put_failure;
Alexander Aringedea8f72015-05-17 21:44:46 +0200417
418 if (rdev->wpan_phy.cca.mode == NL802154_CCA_ENERGY_CARRIER) {
419 if (nla_put_u32(msg, NL802154_ATTR_CCA_OPT,
420 rdev->wpan_phy.cca.opt))
421 goto nla_put_failure;
422 }
Alexander Aringba2a9502014-12-10 15:33:13 +0100423 }
424
Alexander Aringedea8f72015-05-17 21:44:46 +0200425 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
426 if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
427 rdev->wpan_phy.transmit_power))
428 goto nla_put_failure;
429 }
Alexander Aringca20ce202014-11-09 08:36:54 +0100430
Alexander Aringe4390592015-05-27 13:42:09 +0200431 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
432 if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
433 rdev->wpan_phy.cca_ed_level))
434 goto nla_put_failure;
435 }
436
Alexander Aring0e665452015-05-17 21:44:53 +0200437 if (nl802154_put_capabilities(msg, rdev))
438 goto nla_put_failure;
439
Varka Bhadram133be022015-06-04 13:07:36 +0530440 nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
441 if (!nl_cmds)
442 goto nla_put_failure;
443
444 i = 0;
445#define CMD(op, n) \
446 do { \
447 if (rdev->ops->op) { \
448 i++; \
449 if (nla_put_u32(msg, i, NL802154_CMD_ ## n)) \
450 goto nla_put_failure; \
451 } \
452 } while (0)
453
454 CMD(add_virtual_intf, NEW_INTERFACE);
455 CMD(del_virtual_intf, DEL_INTERFACE);
456 CMD(set_channel, SET_CHANNEL);
457 CMD(set_pan_id, SET_PAN_ID);
458 CMD(set_short_addr, SET_SHORT_ADDR);
459 CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
460 CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
461 CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
462 CMD(set_lbt_mode, SET_LBT_MODE);
Alexander Aringc91208d2015-08-10 21:15:58 +0200463 CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
Varka Bhadram133be022015-06-04 13:07:36 +0530464
465 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
466 CMD(set_tx_power, SET_TX_POWER);
467
468 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
469 CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
470
471 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
472 CMD(set_cca_mode, SET_CCA_MODE);
473
474#undef CMD
475 nla_nest_end(msg, nl_cmds);
476
Alexander Aringca20ce202014-11-09 08:36:54 +0100477finish:
Johannes Berg053c0952015-01-16 22:09:00 +0100478 genlmsg_end(msg, hdr);
479 return 0;
Alexander Aringca20ce202014-11-09 08:36:54 +0100480
481nla_put_failure:
482 genlmsg_cancel(msg, hdr);
483 return -EMSGSIZE;
484}
485
486struct nl802154_dump_wpan_phy_state {
487 s64 filter_wpan_phy;
488 long start;
489
490};
491
492static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
493 struct netlink_callback *cb,
494 struct nl802154_dump_wpan_phy_state *state)
495{
496 struct nlattr **tb = nl802154_fam.attrbuf;
497 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
498 tb, nl802154_fam.maxattr, nl802154_policy);
499
500 /* TODO check if we can handle error here,
501 * we have no backward compatibility
502 */
503 if (ret)
504 return 0;
505
506 if (tb[NL802154_ATTR_WPAN_PHY])
507 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
508 if (tb[NL802154_ATTR_WPAN_DEV])
509 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
510 if (tb[NL802154_ATTR_IFINDEX]) {
511 struct net_device *netdev;
512 struct cfg802154_registered_device *rdev;
513 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
514
515 /* TODO netns */
516 netdev = __dev_get_by_index(&init_net, ifidx);
517 if (!netdev)
518 return -ENODEV;
519 if (netdev->ieee802154_ptr) {
520 rdev = wpan_phy_to_rdev(
521 netdev->ieee802154_ptr->wpan_phy);
522 state->filter_wpan_phy = rdev->wpan_phy_idx;
523 }
524 }
525
526 return 0;
527}
528
529static int
530nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
531{
532 int idx = 0, ret;
533 struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
534 struct cfg802154_registered_device *rdev;
535
536 rtnl_lock();
537 if (!state) {
538 state = kzalloc(sizeof(*state), GFP_KERNEL);
539 if (!state) {
540 rtnl_unlock();
541 return -ENOMEM;
542 }
543 state->filter_wpan_phy = -1;
544 ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
545 if (ret) {
546 kfree(state);
547 rtnl_unlock();
548 return ret;
549 }
550 cb->args[0] = (long)state;
551 }
552
553 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
554 /* TODO net ns compare */
555 if (++idx <= state->start)
556 continue;
557 if (state->filter_wpan_phy != -1 &&
558 state->filter_wpan_phy != rdev->wpan_phy_idx)
559 continue;
560 /* attempt to fit multiple wpan_phy data chunks into the skb */
561 ret = nl802154_send_wpan_phy(rdev,
562 NL802154_CMD_NEW_WPAN_PHY,
563 skb,
564 NETLINK_CB(cb->skb).portid,
565 cb->nlh->nlmsg_seq, NLM_F_MULTI);
566 if (ret < 0) {
567 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
568 !skb->len && cb->min_dump_alloc < 4096) {
569 cb->min_dump_alloc = 4096;
570 rtnl_unlock();
571 return 1;
572 }
573 idx--;
574 break;
575 }
576 break;
577 }
578 rtnl_unlock();
579
580 state->start = idx;
581
582 return skb->len;
583}
584
585static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
586{
587 kfree((void *)cb->args[0]);
588 return 0;
589}
590
591static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
592{
593 struct sk_buff *msg;
594 struct cfg802154_registered_device *rdev = info->user_ptr[0];
595
596 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
597 if (!msg)
598 return -ENOMEM;
599
600 if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
601 info->snd_portid, info->snd_seq, 0) < 0) {
602 nlmsg_free(msg);
603 return -ENOBUFS;
604 }
605
606 return genlmsg_reply(msg, info);
607}
608
Alexander Aring4b96aea2014-11-09 08:36:55 +0100609static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
610{
611 return (u64)wpan_dev->identifier |
612 ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
613}
614
615static int
616nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
617 struct cfg802154_registered_device *rdev,
618 struct wpan_dev *wpan_dev)
619{
620 struct net_device *dev = wpan_dev->netdev;
621 void *hdr;
622
623 hdr = nl802154hdr_put(msg, portid, seq, flags,
624 NL802154_CMD_NEW_INTERFACE);
625 if (!hdr)
626 return -1;
627
628 if (dev &&
629 (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
630 nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
631 goto nla_put_failure;
632
633 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
634 nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
635 nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
636 nla_put_u32(msg, NL802154_ATTR_GENERATION,
637 rdev->devlist_generation ^
638 (cfg802154_rdev_list_generation << 2)))
639 goto nla_put_failure;
640
641 /* address settings */
642 if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
643 wpan_dev->extended_addr) ||
644 nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
645 wpan_dev->short_addr) ||
646 nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
647 goto nla_put_failure;
648
649 /* ARET handling */
650 if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
651 wpan_dev->frame_retries) ||
652 nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
653 nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
654 wpan_dev->csma_retries) ||
655 nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
656 goto nla_put_failure;
657
658 /* listen before transmit */
659 if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
660 goto nla_put_failure;
661
Alexander Aringc91208d2015-08-10 21:15:58 +0200662 /* ackreq default behaviour */
663 if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
664 goto nla_put_failure;
665
Johannes Berg053c0952015-01-16 22:09:00 +0100666 genlmsg_end(msg, hdr);
667 return 0;
Alexander Aring4b96aea2014-11-09 08:36:55 +0100668
669nla_put_failure:
670 genlmsg_cancel(msg, hdr);
671 return -EMSGSIZE;
672}
673
674static int
675nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
676{
677 int wp_idx = 0;
678 int if_idx = 0;
679 int wp_start = cb->args[0];
680 int if_start = cb->args[1];
681 struct cfg802154_registered_device *rdev;
682 struct wpan_dev *wpan_dev;
683
684 rtnl_lock();
685 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
686 /* TODO netns compare */
687 if (wp_idx < wp_start) {
688 wp_idx++;
689 continue;
690 }
691 if_idx = 0;
692
693 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
694 if (if_idx < if_start) {
695 if_idx++;
696 continue;
697 }
698 if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
699 cb->nlh->nlmsg_seq, NLM_F_MULTI,
700 rdev, wpan_dev) < 0) {
701 goto out;
702 }
703 if_idx++;
704 }
705
706 wp_idx++;
707 }
708out:
709 rtnl_unlock();
710
711 cb->args[0] = wp_idx;
712 cb->args[1] = if_idx;
713
714 return skb->len;
715}
716
717static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
718{
719 struct sk_buff *msg;
720 struct cfg802154_registered_device *rdev = info->user_ptr[0];
721 struct wpan_dev *wdev = info->user_ptr[1];
722
723 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
724 if (!msg)
725 return -ENOMEM;
726
727 if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
728 rdev, wdev) < 0) {
729 nlmsg_free(msg);
730 return -ENOBUFS;
731 }
732
733 return genlmsg_reply(msg, info);
734}
735
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100736static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
737{
738 struct cfg802154_registered_device *rdev = info->user_ptr[0];
739 enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
Alexander Aring0e575472014-11-17 08:20:52 +0100740 __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100741
742 /* TODO avoid failing a new interface
743 * creation due to pending removal?
744 */
745
746 if (!info->attrs[NL802154_ATTR_IFNAME])
747 return -EINVAL;
748
749 if (info->attrs[NL802154_ATTR_IFTYPE]) {
750 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
Alexander Aring65318682015-05-17 21:44:47 +0200751 if (type > NL802154_IFTYPE_MAX ||
752 !(rdev->wpan_phy.supported.iftypes & BIT(type)))
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100753 return -EINVAL;
754 }
755
Alexander Aring0e575472014-11-17 08:20:52 +0100756 if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
Alexander Aring1ee06ef2015-09-28 09:00:24 +0200757 extended_addr = nla_get_le64(info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
Alexander Aring0e575472014-11-17 08:20:52 +0100758
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100759 if (!rdev->ops->add_virtual_intf)
760 return -EOPNOTSUPP;
761
762 return rdev_add_virtual_intf(rdev,
763 nla_data(info->attrs[NL802154_ATTR_IFNAME]),
Varka Bhadram5b4a10392015-04-30 17:44:57 +0200764 NET_NAME_USER, type, extended_addr);
Alexander Aringf3ea5e42014-11-17 08:20:51 +0100765}
766
Alexander Aringb821ecd2014-11-17 08:20:53 +0100767static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
768{
769 struct cfg802154_registered_device *rdev = info->user_ptr[0];
770 struct wpan_dev *wpan_dev = info->user_ptr[1];
771
772 if (!rdev->ops->del_virtual_intf)
773 return -EOPNOTSUPP;
774
775 /* If we remove a wpan device without a netdev then clear
776 * user_ptr[1] so that nl802154_post_doit won't dereference it
777 * to check if it needs to do dev_put(). Otherwise it crashes
778 * since the wpan_dev has been freed, unlike with a netdev where
779 * we need the dev_put() for the netdev to really be freed.
780 */
781 if (!wpan_dev->netdev)
782 info->user_ptr[1] = NULL;
783
784 return rdev_del_virtual_intf(rdev, wpan_dev);
785}
786
Alexander Aringab0bd562014-11-12 03:36:55 +0100787static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
788{
789 struct cfg802154_registered_device *rdev = info->user_ptr[0];
790 u8 channel, page;
791
792 if (!info->attrs[NL802154_ATTR_PAGE] ||
793 !info->attrs[NL802154_ATTR_CHANNEL])
794 return -EINVAL;
795
796 page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
797 channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
798
799 /* check 802.15.4 constraints */
Alexander Aring673692f2015-05-17 21:44:38 +0200800 if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
Alexander Aring72f655e2015-05-17 21:44:42 +0200801 !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
Alexander Aringab0bd562014-11-12 03:36:55 +0100802 return -EINVAL;
803
804 return rdev_set_channel(rdev, page, channel);
805}
806
Alexander Aringba2a9502014-12-10 15:33:13 +0100807static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
808{
809 struct cfg802154_registered_device *rdev = info->user_ptr[0];
810 struct wpan_phy_cca cca;
811
Alexander Aringfc4f8052015-05-26 23:11:31 +0200812 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
Alexander Aringedea8f72015-05-17 21:44:46 +0200813 return -EOPNOTSUPP;
814
Alexander Aringba2a9502014-12-10 15:33:13 +0100815 if (!info->attrs[NL802154_ATTR_CCA_MODE])
816 return -EINVAL;
817
818 cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
819 /* checking 802.15.4 constraints */
Alexander Aringfea33182015-05-17 21:44:43 +0200820 if (cca.mode < NL802154_CCA_ENERGY ||
821 cca.mode > NL802154_CCA_ATTR_MAX ||
822 !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
Alexander Aringba2a9502014-12-10 15:33:13 +0100823 return -EINVAL;
824
825 if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
826 if (!info->attrs[NL802154_ATTR_CCA_OPT])
827 return -EINVAL;
828
829 cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
Alexander Aringfea33182015-05-17 21:44:43 +0200830 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
831 !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
Alexander Aringba2a9502014-12-10 15:33:13 +0100832 return -EINVAL;
833 }
834
835 return rdev_set_cca_mode(rdev, &cca);
836}
837
Alexander Aringb69644c2015-05-27 13:42:10 +0200838static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
839{
840 struct cfg802154_registered_device *rdev = info->user_ptr[0];
841 s32 ed_level;
842 int i;
843
844 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
845 return -EOPNOTSUPP;
846
847 if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
848 return -EINVAL;
849
850 ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
851
852 for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
853 if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
854 return rdev_set_cca_ed_level(rdev, ed_level);
855 }
856
857 return -EINVAL;
858}
859
Varka Bhadram0f999b02015-05-27 09:10:54 +0530860static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
861{
862 struct cfg802154_registered_device *rdev = info->user_ptr[0];
863 s32 power;
864 int i;
865
866 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
867 return -EOPNOTSUPP;
868
869 if (!info->attrs[NL802154_ATTR_TX_POWER])
870 return -EINVAL;
871
872 power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
873
874 for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
875 if (power == rdev->wpan_phy.supported.tx_powers[i])
876 return rdev_set_tx_power(rdev, power);
877 }
878
879 return -EINVAL;
880}
881
Alexander Aring702bf372014-11-12 03:36:57 +0100882static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
883{
884 struct cfg802154_registered_device *rdev = info->user_ptr[0];
885 struct net_device *dev = info->user_ptr[1];
886 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
Alexander Aringee7b9052014-11-17 08:20:55 +0100887 __le16 pan_id;
Alexander Aring702bf372014-11-12 03:36:57 +0100888
889 /* conflict here while tx/rx calls */
890 if (netif_running(dev))
891 return -EBUSY;
892
893 /* don't change address fields on monitor */
Alexander Aring0cf08792015-05-17 21:44:37 +0200894 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
895 !info->attrs[NL802154_ATTR_PAN_ID])
Alexander Aring702bf372014-11-12 03:36:57 +0100896 return -EINVAL;
897
Alexander Aringee7b9052014-11-17 08:20:55 +0100898 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
Alexander Aring702bf372014-11-12 03:36:57 +0100899
Alexander Aring673692f2015-05-17 21:44:38 +0200900 /* TODO
901 * I am not sure about to check here on broadcast pan_id.
902 * Broadcast is a valid setting, comment from 802.15.4:
903 * If this value is 0xffff, the device is not associated.
904 *
905 * This could useful to simple deassociate an device.
906 */
907 if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
908 return -EINVAL;
909
Alexander Aring702bf372014-11-12 03:36:57 +0100910 return rdev_set_pan_id(rdev, wpan_dev, pan_id);
911}
912
Alexander Aring9830c622014-11-12 03:36:58 +0100913static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
914{
915 struct cfg802154_registered_device *rdev = info->user_ptr[0];
916 struct net_device *dev = info->user_ptr[1];
917 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
Alexander Aringee7b9052014-11-17 08:20:55 +0100918 __le16 short_addr;
Alexander Aring9830c622014-11-12 03:36:58 +0100919
920 /* conflict here while tx/rx calls */
921 if (netif_running(dev))
922 return -EBUSY;
923
924 /* don't change address fields on monitor */
Alexander Aring0cf08792015-05-17 21:44:37 +0200925 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
926 !info->attrs[NL802154_ATTR_SHORT_ADDR])
Alexander Aring9830c622014-11-12 03:36:58 +0100927 return -EINVAL;
928
Alexander Aringee7b9052014-11-17 08:20:55 +0100929 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
Alexander Aring9830c622014-11-12 03:36:58 +0100930
Alexander Aring673692f2015-05-17 21:44:38 +0200931 /* TODO
932 * I am not sure about to check here on broadcast short_addr.
933 * Broadcast is a valid setting, comment from 802.15.4:
934 * A value of 0xfffe indicates that the device has
935 * associated but has not been allocated an address. A
936 * value of 0xffff indicates that the device does not
937 * have a short address.
938 *
939 * I think we should allow to set these settings but
940 * don't allow to allow socket communication with it.
941 */
942 if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
943 short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
944 return -EINVAL;
945
Alexander Aring9830c622014-11-12 03:36:58 +0100946 return rdev_set_short_addr(rdev, wpan_dev, short_addr);
947}
948
Alexander Aring656a9992014-11-12 03:36:59 +0100949static int
950nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
951{
952 struct cfg802154_registered_device *rdev = info->user_ptr[0];
953 struct net_device *dev = info->user_ptr[1];
954 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
955 u8 min_be, max_be;
956
957 /* should be set on netif open inside phy settings */
958 if (netif_running(dev))
959 return -EBUSY;
960
961 if (!info->attrs[NL802154_ATTR_MIN_BE] ||
962 !info->attrs[NL802154_ATTR_MAX_BE])
963 return -EINVAL;
964
965 min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
966 max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
967
968 /* check 802.15.4 constraints */
Alexander Aringfea33182015-05-17 21:44:43 +0200969 if (min_be < rdev->wpan_phy.supported.min_minbe ||
970 min_be > rdev->wpan_phy.supported.max_minbe ||
971 max_be < rdev->wpan_phy.supported.min_maxbe ||
972 max_be > rdev->wpan_phy.supported.max_maxbe ||
973 min_be > max_be)
Alexander Aring656a9992014-11-12 03:36:59 +0100974 return -EINVAL;
975
976 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
977}
978
Alexander Aringa01ba762014-11-12 03:37:01 +0100979static int
980nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
981{
982 struct cfg802154_registered_device *rdev = info->user_ptr[0];
983 struct net_device *dev = info->user_ptr[1];
984 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
985 u8 max_csma_backoffs;
986
987 /* conflict here while other running iface settings */
988 if (netif_running(dev))
989 return -EBUSY;
990
991 if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
992 return -EINVAL;
993
994 max_csma_backoffs = nla_get_u8(
995 info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
996
997 /* check 802.15.4 constraints */
Alexander Aringfea33182015-05-17 21:44:43 +0200998 if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
999 max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
Alexander Aringa01ba762014-11-12 03:37:01 +01001000 return -EINVAL;
1001
1002 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1003}
1004
Alexander Aring17a3a462014-11-12 03:37:03 +01001005static int
1006nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1007{
1008 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1009 struct net_device *dev = info->user_ptr[1];
1010 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1011 s8 max_frame_retries;
1012
1013 if (netif_running(dev))
1014 return -EBUSY;
1015
1016 if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1017 return -EINVAL;
1018
1019 max_frame_retries = nla_get_s8(
1020 info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1021
1022 /* check 802.15.4 constraints */
Alexander Aringfea33182015-05-17 21:44:43 +02001023 if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1024 max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
Alexander Aring17a3a462014-11-12 03:37:03 +01001025 return -EINVAL;
1026
1027 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1028}
1029
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001030static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1031{
1032 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1033 struct net_device *dev = info->user_ptr[1];
1034 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
Stefan Schmidt4e1795d2015-08-20 12:09:47 +02001035 int mode;
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001036
1037 if (netif_running(dev))
1038 return -EBUSY;
1039
1040 if (!info->attrs[NL802154_ATTR_LBT_MODE])
1041 return -EINVAL;
1042
Stefan Schmidt4e1795d2015-08-20 12:09:47 +02001043 mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1044
1045 if (mode != 0 && mode != 1)
1046 return -EINVAL;
1047
Alexander Aringfea33182015-05-17 21:44:43 +02001048 if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1049 return -EINVAL;
1050
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001051 return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1052}
1053
Alexander Aringc91208d2015-08-10 21:15:58 +02001054static int
1055nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1056{
1057 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1058 struct net_device *dev = info->user_ptr[1];
1059 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
Stefan Schmidt4e1795d2015-08-20 12:09:47 +02001060 int ackreq;
Alexander Aringc91208d2015-08-10 21:15:58 +02001061
1062 if (netif_running(dev))
1063 return -EBUSY;
1064
1065 if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1066 return -EINVAL;
1067
Stefan Schmidt4e1795d2015-08-20 12:09:47 +02001068 ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1069
1070 if (ackreq != 0 && ackreq != 1)
1071 return -EINVAL;
1072
Alexander Aringc91208d2015-08-10 21:15:58 +02001073 return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1074}
1075
Alexander Aring79fe1a22014-11-09 08:36:53 +01001076#define NL802154_FLAG_NEED_WPAN_PHY 0x01
1077#define NL802154_FLAG_NEED_NETDEV 0x02
1078#define NL802154_FLAG_NEED_RTNL 0x04
1079#define NL802154_FLAG_CHECK_NETDEV_UP 0x08
1080#define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\
1081 NL802154_FLAG_CHECK_NETDEV_UP)
1082#define NL802154_FLAG_NEED_WPAN_DEV 0x10
1083#define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\
1084 NL802154_FLAG_CHECK_NETDEV_UP)
1085
1086static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1087 struct genl_info *info)
1088{
1089 struct cfg802154_registered_device *rdev;
1090 struct wpan_dev *wpan_dev;
1091 struct net_device *dev;
1092 bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1093
1094 if (rtnl)
1095 rtnl_lock();
1096
1097 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1098 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1099 if (IS_ERR(rdev)) {
1100 if (rtnl)
1101 rtnl_unlock();
1102 return PTR_ERR(rdev);
1103 }
1104 info->user_ptr[0] = rdev;
1105 } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1106 ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1107 ASSERT_RTNL();
1108 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1109 info->attrs);
1110 if (IS_ERR(wpan_dev)) {
1111 if (rtnl)
1112 rtnl_unlock();
1113 return PTR_ERR(wpan_dev);
1114 }
1115
1116 dev = wpan_dev->netdev;
1117 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1118
1119 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1120 if (!dev) {
1121 if (rtnl)
1122 rtnl_unlock();
1123 return -EINVAL;
1124 }
1125
1126 info->user_ptr[1] = dev;
1127 } else {
1128 info->user_ptr[1] = wpan_dev;
1129 }
1130
1131 if (dev) {
1132 if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1133 !netif_running(dev)) {
1134 if (rtnl)
1135 rtnl_unlock();
1136 return -ENETDOWN;
1137 }
1138
1139 dev_hold(dev);
1140 }
1141
1142 info->user_ptr[0] = rdev;
1143 }
1144
1145 return 0;
1146}
1147
1148static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1149 struct genl_info *info)
1150{
1151 if (info->user_ptr[1]) {
1152 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1153 struct wpan_dev *wpan_dev = info->user_ptr[1];
1154
1155 if (wpan_dev->netdev)
1156 dev_put(wpan_dev->netdev);
1157 } else {
1158 dev_put(info->user_ptr[1]);
1159 }
1160 }
1161
1162 if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1163 rtnl_unlock();
1164}
1165
1166static const struct genl_ops nl802154_ops[] = {
Alexander Aringca20ce202014-11-09 08:36:54 +01001167 {
1168 .cmd = NL802154_CMD_GET_WPAN_PHY,
1169 .doit = nl802154_get_wpan_phy,
1170 .dumpit = nl802154_dump_wpan_phy,
1171 .done = nl802154_dump_wpan_phy_done,
1172 .policy = nl802154_policy,
1173 /* can be retrieved by unprivileged users */
1174 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1175 NL802154_FLAG_NEED_RTNL,
1176 },
Alexander Aring4b96aea2014-11-09 08:36:55 +01001177 {
1178 .cmd = NL802154_CMD_GET_INTERFACE,
1179 .doit = nl802154_get_interface,
1180 .dumpit = nl802154_dump_interface,
1181 .policy = nl802154_policy,
1182 /* can be retrieved by unprivileged users */
1183 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1184 NL802154_FLAG_NEED_RTNL,
1185 },
Alexander Aringab0bd562014-11-12 03:36:55 +01001186 {
Alexander Aringf3ea5e42014-11-17 08:20:51 +01001187 .cmd = NL802154_CMD_NEW_INTERFACE,
1188 .doit = nl802154_new_interface,
1189 .policy = nl802154_policy,
1190 .flags = GENL_ADMIN_PERM,
1191 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1192 NL802154_FLAG_NEED_RTNL,
1193 },
1194 {
Alexander Aringb821ecd2014-11-17 08:20:53 +01001195 .cmd = NL802154_CMD_DEL_INTERFACE,
1196 .doit = nl802154_del_interface,
1197 .policy = nl802154_policy,
1198 .flags = GENL_ADMIN_PERM,
1199 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1200 NL802154_FLAG_NEED_RTNL,
1201 },
1202 {
Alexander Aringab0bd562014-11-12 03:36:55 +01001203 .cmd = NL802154_CMD_SET_CHANNEL,
1204 .doit = nl802154_set_channel,
1205 .policy = nl802154_policy,
1206 .flags = GENL_ADMIN_PERM,
1207 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1208 NL802154_FLAG_NEED_RTNL,
1209 },
Alexander Aring702bf372014-11-12 03:36:57 +01001210 {
Alexander Aringba2a9502014-12-10 15:33:13 +01001211 .cmd = NL802154_CMD_SET_CCA_MODE,
1212 .doit = nl802154_set_cca_mode,
1213 .policy = nl802154_policy,
1214 .flags = GENL_ADMIN_PERM,
1215 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1216 NL802154_FLAG_NEED_RTNL,
1217 },
1218 {
Alexander Aringb69644c2015-05-27 13:42:10 +02001219 .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1220 .doit = nl802154_set_cca_ed_level,
1221 .policy = nl802154_policy,
1222 .flags = GENL_ADMIN_PERM,
1223 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1224 NL802154_FLAG_NEED_RTNL,
1225 },
1226 {
Varka Bhadram0f999b02015-05-27 09:10:54 +05301227 .cmd = NL802154_CMD_SET_TX_POWER,
1228 .doit = nl802154_set_tx_power,
1229 .policy = nl802154_policy,
1230 .flags = GENL_ADMIN_PERM,
1231 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1232 NL802154_FLAG_NEED_RTNL,
1233 },
1234 {
Alexander Aring702bf372014-11-12 03:36:57 +01001235 .cmd = NL802154_CMD_SET_PAN_ID,
1236 .doit = nl802154_set_pan_id,
1237 .policy = nl802154_policy,
1238 .flags = GENL_ADMIN_PERM,
1239 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1240 NL802154_FLAG_NEED_RTNL,
1241 },
Alexander Aring9830c622014-11-12 03:36:58 +01001242 {
1243 .cmd = NL802154_CMD_SET_SHORT_ADDR,
1244 .doit = nl802154_set_short_addr,
1245 .policy = nl802154_policy,
1246 .flags = GENL_ADMIN_PERM,
1247 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1248 NL802154_FLAG_NEED_RTNL,
1249 },
Alexander Aring656a9992014-11-12 03:36:59 +01001250 {
1251 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1252 .doit = nl802154_set_backoff_exponent,
1253 .policy = nl802154_policy,
1254 .flags = GENL_ADMIN_PERM,
1255 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1256 NL802154_FLAG_NEED_RTNL,
1257 },
Alexander Aringa01ba762014-11-12 03:37:01 +01001258 {
1259 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1260 .doit = nl802154_set_max_csma_backoffs,
1261 .policy = nl802154_policy,
1262 .flags = GENL_ADMIN_PERM,
1263 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1264 NL802154_FLAG_NEED_RTNL,
1265 },
Alexander Aring17a3a462014-11-12 03:37:03 +01001266 {
1267 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1268 .doit = nl802154_set_max_frame_retries,
1269 .policy = nl802154_policy,
1270 .flags = GENL_ADMIN_PERM,
1271 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1272 NL802154_FLAG_NEED_RTNL,
1273 },
Alexander Aringc8937a1d2014-11-12 03:37:05 +01001274 {
1275 .cmd = NL802154_CMD_SET_LBT_MODE,
1276 .doit = nl802154_set_lbt_mode,
1277 .policy = nl802154_policy,
1278 .flags = GENL_ADMIN_PERM,
1279 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1280 NL802154_FLAG_NEED_RTNL,
1281 },
Alexander Aringc91208d2015-08-10 21:15:58 +02001282 {
1283 .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
1284 .doit = nl802154_set_ackreq_default,
1285 .policy = nl802154_policy,
1286 .flags = GENL_ADMIN_PERM,
1287 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1288 NL802154_FLAG_NEED_RTNL,
1289 },
Alexander Aring79fe1a22014-11-09 08:36:53 +01001290};
1291
1292/* initialisation/exit functions */
1293int nl802154_init(void)
1294{
1295 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1296 nl802154_mcgrps);
1297}
1298
1299void nl802154_exit(void)
1300{
1301 genl_unregister_family(&nl802154_fam);
1302}