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.
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.
11 * Alexander Aring <aar@pengutronix.de>
13 * Based on: net/wireless/nl80211.c
16 #include <linux/rtnetlink.h>
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>
29 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
30 struct genl_info *info);
32 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
33 struct genl_info *info);
35 /* the netlink family */
36 static struct genl_family nl802154_fam = {
37 .id = GENL_ID_GENERATE, /* don't bother with a hardcoded ID */
38 .name = NL802154_GENL_NAME, /* have users key off the name instead */
39 .hdrsize = 0, /* no private header */
40 .version = 1, /* no particular meaning now */
41 .maxattr = NL802154_ATTR_MAX,
43 .pre_doit = nl802154_pre_doit,
44 .post_doit = nl802154_post_doit,
47 /* multicast groups */
48 enum nl802154_multicast_groups {
49 NL802154_MCGRP_CONFIG,
52 static const struct genl_multicast_group nl802154_mcgrps[] = {
53 [NL802154_MCGRP_CONFIG] = { .name = "config", },
56 /* returns ERR_PTR values */
57 static struct wpan_dev *
58 __cfg802154_wpan_dev_from_attrs(struct net *netns, struct nlattr **attrs)
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];
65 int wpan_phy_idx = -1;
70 if (!have_ifidx && !have_wpan_dev_id)
71 return ERR_PTR(-EINVAL);
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;
80 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
81 struct wpan_dev *wpan_dev;
83 /* TODO netns compare */
85 if (have_wpan_dev_id && rdev->wpan_phy_idx != wpan_phy_idx)
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) {
94 if (have_wpan_dev_id &&
95 wpan_dev->identifier == (u32)wpan_dev_id) {
108 return ERR_PTR(-ENODEV);
111 static struct cfg802154_registered_device *
112 __cfg802154_rdev_from_attrs(struct net *netns, struct nlattr **attrs)
114 struct cfg802154_registered_device *rdev = NULL, *tmp;
115 struct net_device *netdev;
119 if (!attrs[NL802154_ATTR_WPAN_PHY] &&
120 !attrs[NL802154_ATTR_IFINDEX] &&
121 !attrs[NL802154_ATTR_WPAN_DEV])
122 return ERR_PTR(-EINVAL);
124 if (attrs[NL802154_ATTR_WPAN_PHY])
125 rdev = cfg802154_rdev_by_wpan_phy_idx(
126 nla_get_u32(attrs[NL802154_ATTR_WPAN_PHY]));
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;
133 tmp = cfg802154_rdev_by_wpan_phy_idx(wpan_dev_id >> 32);
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)
146 if (rdev && tmp != rdev)
147 return ERR_PTR(-EINVAL);
152 if (attrs[NL802154_ATTR_IFINDEX]) {
153 int ifindex = nla_get_u32(attrs[NL802154_ATTR_IFINDEX]);
155 netdev = __dev_get_by_index(netns, ifindex);
157 if (netdev->ieee802154_ptr)
158 tmp = wpan_phy_to_rdev(
159 netdev->ieee802154_ptr->wpan_phy);
163 /* not wireless device -- return error */
165 return ERR_PTR(-EINVAL);
167 /* mismatch -- return error */
168 if (rdev && tmp != rdev)
169 return ERR_PTR(-EINVAL);
176 return ERR_PTR(-ENODEV);
178 /* TODO netns compare */
183 /* This function returns a pointer to the driver
184 * that the genl_info item that is passed refers to.
186 * The result of this can be a PTR_ERR and hence must
187 * be checked with IS_ERR() for errors.
189 static struct cfg802154_registered_device *
190 cfg802154_get_dev_from_info(struct net *netns, struct genl_info *info)
192 return __cfg802154_rdev_from_attrs(netns, info->attrs);
195 /* policy for the attributes */
196 static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = {
197 [NL802154_ATTR_WPAN_PHY] = { .type = NLA_U32 },
198 [NL802154_ATTR_WPAN_PHY_NAME] = { .type = NLA_NUL_STRING,
201 [NL802154_ATTR_IFINDEX] = { .type = NLA_U32 },
202 [NL802154_ATTR_IFTYPE] = { .type = NLA_U32 },
203 [NL802154_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 },
205 [NL802154_ATTR_WPAN_DEV] = { .type = NLA_U64 },
207 [NL802154_ATTR_PAGE] = { .type = NLA_U8, },
208 [NL802154_ATTR_CHANNEL] = { .type = NLA_U8, },
210 [NL802154_ATTR_TX_POWER] = { .type = NLA_S32, },
212 [NL802154_ATTR_CCA_MODE] = { .type = NLA_U32, },
213 [NL802154_ATTR_CCA_OPT] = { .type = NLA_U32, },
214 [NL802154_ATTR_CCA_ED_LEVEL] = { .type = NLA_S32, },
216 [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
218 [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
219 [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
220 [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
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, },
226 [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
228 [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
230 [NL802154_ATTR_WPAN_PHY_CAPS] = { .type = NLA_NESTED },
232 [NL802154_ATTR_SUPPORTED_COMMANDS] = { .type = NLA_NESTED },
234 [NL802154_ATTR_ACKREQ_DEFAULT] = { .type = NLA_U8 },
237 /* message building helper */
238 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
241 /* since there is no private header just add the generic one */
242 return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
246 nl802154_put_flags(struct sk_buff *msg, int attr, u32 mask)
248 struct nlattr *nl_flags = nla_nest_start(msg, attr);
256 if ((mask & 1) && nla_put_flag(msg, i))
263 nla_nest_end(msg, nl_flags);
268 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
271 struct nlattr *nl_page;
274 nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
278 for (page = 0; page <= IEEE802154_MAX_PAGE; page++) {
279 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
280 rdev->wpan_phy.supported.channels[page]))
283 nla_nest_end(msg, nl_page);
289 nl802154_put_capabilities(struct sk_buff *msg,
290 struct cfg802154_registered_device *rdev)
292 const struct wpan_phy_supported *caps = &rdev->wpan_phy.supported;
293 struct nlattr *nl_caps, *nl_channels;
296 nl_caps = nla_nest_start(msg, NL802154_ATTR_WPAN_PHY_CAPS);
300 nl_channels = nla_nest_start(msg, NL802154_CAP_ATTR_CHANNELS);
304 for (i = 0; i <= IEEE802154_MAX_PAGE; i++) {
305 if (caps->channels[i]) {
306 if (nl802154_put_flags(msg, i, caps->channels[i]))
311 nla_nest_end(msg, nl_channels);
313 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
314 struct nlattr *nl_ed_lvls;
316 nl_ed_lvls = nla_nest_start(msg,
317 NL802154_CAP_ATTR_CCA_ED_LEVELS);
321 for (i = 0; i < caps->cca_ed_levels_size; i++) {
322 if (nla_put_s32(msg, i, caps->cca_ed_levels[i]))
326 nla_nest_end(msg, nl_ed_lvls);
329 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
330 struct nlattr *nl_tx_pwrs;
332 nl_tx_pwrs = nla_nest_start(msg, NL802154_CAP_ATTR_TX_POWERS);
336 for (i = 0; i < caps->tx_powers_size; i++) {
337 if (nla_put_s32(msg, i, caps->tx_powers[i]))
341 nla_nest_end(msg, nl_tx_pwrs);
344 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
345 if (nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_MODES,
347 nl802154_put_flags(msg, NL802154_CAP_ATTR_CCA_OPTS,
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,
366 nla_put_u32(msg, NL802154_CAP_ATTR_LBT, caps->lbt))
369 nla_nest_end(msg, nl_caps);
374 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
375 enum nl802154_commands cmd,
376 struct sk_buff *msg, u32 portid, u32 seq,
379 struct nlattr *nl_cmds;
383 hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
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;
394 if (cmd != NL802154_CMD_NEW_WPAN_PHY)
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;
406 /* TODO remove this behaviour, we still keep support it for a while
407 * so users can change the behaviour to the new one.
409 if (nl802154_send_wpan_phy_channels(rdev, msg))
410 goto nla_put_failure;
413 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE) {
414 if (nla_put_u32(msg, NL802154_ATTR_CCA_MODE,
415 rdev->wpan_phy.cca.mode))
416 goto nla_put_failure;
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;
425 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER) {
426 if (nla_put_s32(msg, NL802154_ATTR_TX_POWER,
427 rdev->wpan_phy.transmit_power))
428 goto nla_put_failure;
431 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL) {
432 if (nla_put_s32(msg, NL802154_ATTR_CCA_ED_LEVEL,
433 rdev->wpan_phy.cca_ed_level))
434 goto nla_put_failure;
437 if (nl802154_put_capabilities(msg, rdev))
438 goto nla_put_failure;
440 nl_cmds = nla_nest_start(msg, NL802154_ATTR_SUPPORTED_COMMANDS);
442 goto nla_put_failure;
447 if (rdev->ops->op) { \
449 if (nla_put_u32(msg, i, NL802154_CMD_ ## n)) \
450 goto nla_put_failure; \
454 CMD(add_virtual_intf, NEW_INTERFACE);
455 CMD(del_virtual_intf, DEL_INTERFACE);
456 CMD(set_channel, SET_CHANNEL);
457 CMD(set_pan_id, SET_PAN_ID);
458 CMD(set_short_addr, SET_SHORT_ADDR);
459 CMD(set_backoff_exponent, SET_BACKOFF_EXPONENT);
460 CMD(set_max_csma_backoffs, SET_MAX_CSMA_BACKOFFS);
461 CMD(set_max_frame_retries, SET_MAX_FRAME_RETRIES);
462 CMD(set_lbt_mode, SET_LBT_MODE);
463 CMD(set_ackreq_default, SET_ACKREQ_DEFAULT);
465 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER)
466 CMD(set_tx_power, SET_TX_POWER);
468 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL)
469 CMD(set_cca_ed_level, SET_CCA_ED_LEVEL);
471 if (rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE)
472 CMD(set_cca_mode, SET_CCA_MODE);
475 nla_nest_end(msg, nl_cmds);
478 genlmsg_end(msg, hdr);
482 genlmsg_cancel(msg, hdr);
486 struct nl802154_dump_wpan_phy_state {
492 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
493 struct netlink_callback *cb,
494 struct nl802154_dump_wpan_phy_state *state)
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);
500 /* TODO check if we can handle error here,
501 * we have no backward compatibility
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]);
516 netdev = __dev_get_by_index(&init_net, ifidx);
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;
530 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
533 struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
534 struct cfg802154_registered_device *rdev;
538 state = kzalloc(sizeof(*state), GFP_KERNEL);
543 state->filter_wpan_phy = -1;
544 ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
550 cb->args[0] = (long)state;
553 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
554 /* TODO net ns compare */
555 if (++idx <= state->start)
557 if (state->filter_wpan_phy != -1 &&
558 state->filter_wpan_phy != rdev->wpan_phy_idx)
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,
564 NETLINK_CB(cb->skb).portid,
565 cb->nlh->nlmsg_seq, NLM_F_MULTI);
567 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
568 !skb->len && cb->min_dump_alloc < 4096) {
569 cb->min_dump_alloc = 4096;
585 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
587 kfree((void *)cb->args[0]);
591 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
594 struct cfg802154_registered_device *rdev = info->user_ptr[0];
596 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
600 if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
601 info->snd_portid, info->snd_seq, 0) < 0) {
606 return genlmsg_reply(msg, info);
609 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
611 return (u64)wpan_dev->identifier |
612 ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
616 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
617 struct cfg802154_registered_device *rdev,
618 struct wpan_dev *wpan_dev)
620 struct net_device *dev = wpan_dev->netdev;
623 hdr = nl802154hdr_put(msg, portid, seq, flags,
624 NL802154_CMD_NEW_INTERFACE);
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;
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;
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;
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;
658 /* listen before transmit */
659 if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
660 goto nla_put_failure;
662 /* ackreq default behaviour */
663 if (nla_put_u8(msg, NL802154_ATTR_ACKREQ_DEFAULT, wpan_dev->ackreq))
664 goto nla_put_failure;
666 genlmsg_end(msg, hdr);
670 genlmsg_cancel(msg, hdr);
675 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
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;
685 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
686 /* TODO netns compare */
687 if (wp_idx < wp_start) {
693 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
694 if (if_idx < if_start) {
698 if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
699 cb->nlh->nlmsg_seq, NLM_F_MULTI,
700 rdev, wpan_dev) < 0) {
711 cb->args[0] = wp_idx;
712 cb->args[1] = if_idx;
717 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
720 struct cfg802154_registered_device *rdev = info->user_ptr[0];
721 struct wpan_dev *wdev = info->user_ptr[1];
723 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
727 if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
733 return genlmsg_reply(msg, info);
736 static int nl802154_new_interface(struct sk_buff *skb, struct genl_info *info)
738 struct cfg802154_registered_device *rdev = info->user_ptr[0];
739 enum nl802154_iftype type = NL802154_IFTYPE_UNSPEC;
740 __le64 extended_addr = cpu_to_le64(0x0000000000000000ULL);
742 /* TODO avoid failing a new interface
743 * creation due to pending removal?
746 if (!info->attrs[NL802154_ATTR_IFNAME])
749 if (info->attrs[NL802154_ATTR_IFTYPE]) {
750 type = nla_get_u32(info->attrs[NL802154_ATTR_IFTYPE]);
751 if (type > NL802154_IFTYPE_MAX ||
752 !(rdev->wpan_phy.supported.iftypes & BIT(type)))
756 /* TODO add nla_get_le64 to netlink */
757 if (info->attrs[NL802154_ATTR_EXTENDED_ADDR])
758 extended_addr = (__force __le64)nla_get_u64(
759 info->attrs[NL802154_ATTR_EXTENDED_ADDR]);
761 if (!rdev->ops->add_virtual_intf)
764 return rdev_add_virtual_intf(rdev,
765 nla_data(info->attrs[NL802154_ATTR_IFNAME]),
766 NET_NAME_USER, type, extended_addr);
769 static int nl802154_del_interface(struct sk_buff *skb, struct genl_info *info)
771 struct cfg802154_registered_device *rdev = info->user_ptr[0];
772 struct wpan_dev *wpan_dev = info->user_ptr[1];
774 if (!rdev->ops->del_virtual_intf)
777 /* If we remove a wpan device without a netdev then clear
778 * user_ptr[1] so that nl802154_post_doit won't dereference it
779 * to check if it needs to do dev_put(). Otherwise it crashes
780 * since the wpan_dev has been freed, unlike with a netdev where
781 * we need the dev_put() for the netdev to really be freed.
783 if (!wpan_dev->netdev)
784 info->user_ptr[1] = NULL;
786 return rdev_del_virtual_intf(rdev, wpan_dev);
789 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
791 struct cfg802154_registered_device *rdev = info->user_ptr[0];
794 if (!info->attrs[NL802154_ATTR_PAGE] ||
795 !info->attrs[NL802154_ATTR_CHANNEL])
798 page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
799 channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
801 /* check 802.15.4 constraints */
802 if (page > IEEE802154_MAX_PAGE || channel > IEEE802154_MAX_CHANNEL ||
803 !(rdev->wpan_phy.supported.channels[page] & BIT(channel)))
806 return rdev_set_channel(rdev, page, channel);
809 static int nl802154_set_cca_mode(struct sk_buff *skb, struct genl_info *info)
811 struct cfg802154_registered_device *rdev = info->user_ptr[0];
812 struct wpan_phy_cca cca;
814 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_MODE))
817 if (!info->attrs[NL802154_ATTR_CCA_MODE])
820 cca.mode = nla_get_u32(info->attrs[NL802154_ATTR_CCA_MODE]);
821 /* checking 802.15.4 constraints */
822 if (cca.mode < NL802154_CCA_ENERGY ||
823 cca.mode > NL802154_CCA_ATTR_MAX ||
824 !(rdev->wpan_phy.supported.cca_modes & BIT(cca.mode)))
827 if (cca.mode == NL802154_CCA_ENERGY_CARRIER) {
828 if (!info->attrs[NL802154_ATTR_CCA_OPT])
831 cca.opt = nla_get_u32(info->attrs[NL802154_ATTR_CCA_OPT]);
832 if (cca.opt > NL802154_CCA_OPT_ATTR_MAX ||
833 !(rdev->wpan_phy.supported.cca_opts & BIT(cca.opt)))
837 return rdev_set_cca_mode(rdev, &cca);
840 static int nl802154_set_cca_ed_level(struct sk_buff *skb, struct genl_info *info)
842 struct cfg802154_registered_device *rdev = info->user_ptr[0];
846 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_CCA_ED_LEVEL))
849 if (!info->attrs[NL802154_ATTR_CCA_ED_LEVEL])
852 ed_level = nla_get_s32(info->attrs[NL802154_ATTR_CCA_ED_LEVEL]);
854 for (i = 0; i < rdev->wpan_phy.supported.cca_ed_levels_size; i++) {
855 if (ed_level == rdev->wpan_phy.supported.cca_ed_levels[i])
856 return rdev_set_cca_ed_level(rdev, ed_level);
862 static int nl802154_set_tx_power(struct sk_buff *skb, struct genl_info *info)
864 struct cfg802154_registered_device *rdev = info->user_ptr[0];
868 if (!(rdev->wpan_phy.flags & WPAN_PHY_FLAG_TXPOWER))
871 if (!info->attrs[NL802154_ATTR_TX_POWER])
874 power = nla_get_s32(info->attrs[NL802154_ATTR_TX_POWER]);
876 for (i = 0; i < rdev->wpan_phy.supported.tx_powers_size; i++) {
877 if (power == rdev->wpan_phy.supported.tx_powers[i])
878 return rdev_set_tx_power(rdev, power);
884 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
886 struct cfg802154_registered_device *rdev = info->user_ptr[0];
887 struct net_device *dev = info->user_ptr[1];
888 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
891 /* conflict here while tx/rx calls */
892 if (netif_running(dev))
895 /* don't change address fields on monitor */
896 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
897 !info->attrs[NL802154_ATTR_PAN_ID])
900 pan_id = nla_get_le16(info->attrs[NL802154_ATTR_PAN_ID]);
903 * I am not sure about to check here on broadcast pan_id.
904 * Broadcast is a valid setting, comment from 802.15.4:
905 * If this value is 0xffff, the device is not associated.
907 * This could useful to simple deassociate an device.
909 if (pan_id == cpu_to_le16(IEEE802154_PAN_ID_BROADCAST))
912 return rdev_set_pan_id(rdev, wpan_dev, pan_id);
915 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
917 struct cfg802154_registered_device *rdev = info->user_ptr[0];
918 struct net_device *dev = info->user_ptr[1];
919 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
922 /* conflict here while tx/rx calls */
923 if (netif_running(dev))
926 /* don't change address fields on monitor */
927 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR ||
928 !info->attrs[NL802154_ATTR_SHORT_ADDR])
931 short_addr = nla_get_le16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
934 * I am not sure about to check here on broadcast short_addr.
935 * Broadcast is a valid setting, comment from 802.15.4:
936 * A value of 0xfffe indicates that the device has
937 * associated but has not been allocated an address. A
938 * value of 0xffff indicates that the device does not
939 * have a short address.
941 * I think we should allow to set these settings but
942 * don't allow to allow socket communication with it.
944 if (short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC) ||
945 short_addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST))
948 return rdev_set_short_addr(rdev, wpan_dev, short_addr);
952 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
954 struct cfg802154_registered_device *rdev = info->user_ptr[0];
955 struct net_device *dev = info->user_ptr[1];
956 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
959 /* should be set on netif open inside phy settings */
960 if (netif_running(dev))
963 if (!info->attrs[NL802154_ATTR_MIN_BE] ||
964 !info->attrs[NL802154_ATTR_MAX_BE])
967 min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
968 max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
970 /* check 802.15.4 constraints */
971 if (min_be < rdev->wpan_phy.supported.min_minbe ||
972 min_be > rdev->wpan_phy.supported.max_minbe ||
973 max_be < rdev->wpan_phy.supported.min_maxbe ||
974 max_be > rdev->wpan_phy.supported.max_maxbe ||
978 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
982 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
984 struct cfg802154_registered_device *rdev = info->user_ptr[0];
985 struct net_device *dev = info->user_ptr[1];
986 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
987 u8 max_csma_backoffs;
989 /* conflict here while other running iface settings */
990 if (netif_running(dev))
993 if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
996 max_csma_backoffs = nla_get_u8(
997 info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
999 /* check 802.15.4 constraints */
1000 if (max_csma_backoffs < rdev->wpan_phy.supported.min_csma_backoffs ||
1001 max_csma_backoffs > rdev->wpan_phy.supported.max_csma_backoffs)
1004 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
1008 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
1010 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1011 struct net_device *dev = info->user_ptr[1];
1012 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1013 s8 max_frame_retries;
1015 if (netif_running(dev))
1018 if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
1021 max_frame_retries = nla_get_s8(
1022 info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
1024 /* check 802.15.4 constraints */
1025 if (max_frame_retries < rdev->wpan_phy.supported.min_frame_retries ||
1026 max_frame_retries > rdev->wpan_phy.supported.max_frame_retries)
1029 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
1032 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
1034 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1035 struct net_device *dev = info->user_ptr[1];
1036 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1039 if (netif_running(dev))
1042 if (!info->attrs[NL802154_ATTR_LBT_MODE])
1045 mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
1047 if (mode != 0 && mode != 1)
1050 if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt))
1053 return rdev_set_lbt_mode(rdev, wpan_dev, mode);
1057 nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info)
1059 struct cfg802154_registered_device *rdev = info->user_ptr[0];
1060 struct net_device *dev = info->user_ptr[1];
1061 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
1064 if (netif_running(dev))
1067 if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT])
1070 ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]);
1072 if (ackreq != 0 && ackreq != 1)
1075 return rdev_set_ackreq_default(rdev, wpan_dev, ackreq);
1078 #define NL802154_FLAG_NEED_WPAN_PHY 0x01
1079 #define NL802154_FLAG_NEED_NETDEV 0x02
1080 #define NL802154_FLAG_NEED_RTNL 0x04
1081 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08
1082 #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\
1083 NL802154_FLAG_CHECK_NETDEV_UP)
1084 #define NL802154_FLAG_NEED_WPAN_DEV 0x10
1085 #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\
1086 NL802154_FLAG_CHECK_NETDEV_UP)
1088 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
1089 struct genl_info *info)
1091 struct cfg802154_registered_device *rdev;
1092 struct wpan_dev *wpan_dev;
1093 struct net_device *dev;
1094 bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
1099 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
1100 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
1104 return PTR_ERR(rdev);
1106 info->user_ptr[0] = rdev;
1107 } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
1108 ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1110 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
1112 if (IS_ERR(wpan_dev)) {
1115 return PTR_ERR(wpan_dev);
1118 dev = wpan_dev->netdev;
1119 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
1121 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
1128 info->user_ptr[1] = dev;
1130 info->user_ptr[1] = wpan_dev;
1134 if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
1135 !netif_running(dev)) {
1144 info->user_ptr[0] = rdev;
1150 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
1151 struct genl_info *info)
1153 if (info->user_ptr[1]) {
1154 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
1155 struct wpan_dev *wpan_dev = info->user_ptr[1];
1157 if (wpan_dev->netdev)
1158 dev_put(wpan_dev->netdev);
1160 dev_put(info->user_ptr[1]);
1164 if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
1168 static const struct genl_ops nl802154_ops[] = {
1170 .cmd = NL802154_CMD_GET_WPAN_PHY,
1171 .doit = nl802154_get_wpan_phy,
1172 .dumpit = nl802154_dump_wpan_phy,
1173 .done = nl802154_dump_wpan_phy_done,
1174 .policy = nl802154_policy,
1175 /* can be retrieved by unprivileged users */
1176 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1177 NL802154_FLAG_NEED_RTNL,
1180 .cmd = NL802154_CMD_GET_INTERFACE,
1181 .doit = nl802154_get_interface,
1182 .dumpit = nl802154_dump_interface,
1183 .policy = nl802154_policy,
1184 /* can be retrieved by unprivileged users */
1185 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1186 NL802154_FLAG_NEED_RTNL,
1189 .cmd = NL802154_CMD_NEW_INTERFACE,
1190 .doit = nl802154_new_interface,
1191 .policy = nl802154_policy,
1192 .flags = GENL_ADMIN_PERM,
1193 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1194 NL802154_FLAG_NEED_RTNL,
1197 .cmd = NL802154_CMD_DEL_INTERFACE,
1198 .doit = nl802154_del_interface,
1199 .policy = nl802154_policy,
1200 .flags = GENL_ADMIN_PERM,
1201 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
1202 NL802154_FLAG_NEED_RTNL,
1205 .cmd = NL802154_CMD_SET_CHANNEL,
1206 .doit = nl802154_set_channel,
1207 .policy = nl802154_policy,
1208 .flags = GENL_ADMIN_PERM,
1209 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1210 NL802154_FLAG_NEED_RTNL,
1213 .cmd = NL802154_CMD_SET_CCA_MODE,
1214 .doit = nl802154_set_cca_mode,
1215 .policy = nl802154_policy,
1216 .flags = GENL_ADMIN_PERM,
1217 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1218 NL802154_FLAG_NEED_RTNL,
1221 .cmd = NL802154_CMD_SET_CCA_ED_LEVEL,
1222 .doit = nl802154_set_cca_ed_level,
1223 .policy = nl802154_policy,
1224 .flags = GENL_ADMIN_PERM,
1225 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1226 NL802154_FLAG_NEED_RTNL,
1229 .cmd = NL802154_CMD_SET_TX_POWER,
1230 .doit = nl802154_set_tx_power,
1231 .policy = nl802154_policy,
1232 .flags = GENL_ADMIN_PERM,
1233 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
1234 NL802154_FLAG_NEED_RTNL,
1237 .cmd = NL802154_CMD_SET_PAN_ID,
1238 .doit = nl802154_set_pan_id,
1239 .policy = nl802154_policy,
1240 .flags = GENL_ADMIN_PERM,
1241 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1242 NL802154_FLAG_NEED_RTNL,
1245 .cmd = NL802154_CMD_SET_SHORT_ADDR,
1246 .doit = nl802154_set_short_addr,
1247 .policy = nl802154_policy,
1248 .flags = GENL_ADMIN_PERM,
1249 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1250 NL802154_FLAG_NEED_RTNL,
1253 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
1254 .doit = nl802154_set_backoff_exponent,
1255 .policy = nl802154_policy,
1256 .flags = GENL_ADMIN_PERM,
1257 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1258 NL802154_FLAG_NEED_RTNL,
1261 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
1262 .doit = nl802154_set_max_csma_backoffs,
1263 .policy = nl802154_policy,
1264 .flags = GENL_ADMIN_PERM,
1265 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1266 NL802154_FLAG_NEED_RTNL,
1269 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
1270 .doit = nl802154_set_max_frame_retries,
1271 .policy = nl802154_policy,
1272 .flags = GENL_ADMIN_PERM,
1273 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1274 NL802154_FLAG_NEED_RTNL,
1277 .cmd = NL802154_CMD_SET_LBT_MODE,
1278 .doit = nl802154_set_lbt_mode,
1279 .policy = nl802154_policy,
1280 .flags = GENL_ADMIN_PERM,
1281 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1282 NL802154_FLAG_NEED_RTNL,
1285 .cmd = NL802154_CMD_SET_ACKREQ_DEFAULT,
1286 .doit = nl802154_set_ackreq_default,
1287 .policy = nl802154_policy,
1288 .flags = GENL_ADMIN_PERM,
1289 .internal_flags = NL802154_FLAG_NEED_NETDEV |
1290 NL802154_FLAG_NEED_RTNL,
1294 /* initialisation/exit functions */
1295 int nl802154_init(void)
1297 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
1301 void nl802154_exit(void)
1303 genl_unregister_family(&nl802154_fam);