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_S8, },
212 [NL802154_ATTR_CCA_MODE] = { .type = NLA_U8, },
214 [NL802154_ATTR_SUPPORTED_CHANNEL] = { .type = NLA_U32, },
216 [NL802154_ATTR_PAN_ID] = { .type = NLA_U16, },
217 [NL802154_ATTR_EXTENDED_ADDR] = { .type = NLA_U64 },
218 [NL802154_ATTR_SHORT_ADDR] = { .type = NLA_U16, },
220 [NL802154_ATTR_MIN_BE] = { .type = NLA_U8, },
221 [NL802154_ATTR_MAX_BE] = { .type = NLA_U8, },
222 [NL802154_ATTR_MAX_CSMA_BACKOFFS] = { .type = NLA_U8, },
224 [NL802154_ATTR_MAX_FRAME_RETRIES] = { .type = NLA_S8, },
226 [NL802154_ATTR_LBT_MODE] = { .type = NLA_U8, },
229 /* message building helper */
230 static inline void *nl802154hdr_put(struct sk_buff *skb, u32 portid, u32 seq,
233 /* since there is no private header just add the generic one */
234 return genlmsg_put(skb, portid, seq, &nl802154_fam, flags, cmd);
238 nl802154_send_wpan_phy_channels(struct cfg802154_registered_device *rdev,
241 struct nlattr *nl_page;
244 nl_page = nla_nest_start(msg, NL802154_ATTR_CHANNELS_SUPPORTED);
248 for (page = 0; page < WPAN_NUM_PAGES; page++) {
249 if (nla_put_u32(msg, NL802154_ATTR_SUPPORTED_CHANNEL,
250 rdev->wpan_phy.channels_supported[page]))
253 nla_nest_end(msg, nl_page);
258 static int nl802154_send_wpan_phy(struct cfg802154_registered_device *rdev,
259 enum nl802154_commands cmd,
260 struct sk_buff *msg, u32 portid, u32 seq,
265 hdr = nl802154hdr_put(msg, portid, seq, flags, cmd);
269 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
270 nla_put_string(msg, NL802154_ATTR_WPAN_PHY_NAME,
271 wpan_phy_name(&rdev->wpan_phy)) ||
272 nla_put_u32(msg, NL802154_ATTR_GENERATION,
273 cfg802154_rdev_list_generation))
274 goto nla_put_failure;
276 if (cmd != NL802154_CMD_NEW_WPAN_PHY)
281 /* current channel settings */
282 if (nla_put_u8(msg, NL802154_ATTR_PAGE,
283 rdev->wpan_phy.current_page) ||
284 nla_put_u8(msg, NL802154_ATTR_CHANNEL,
285 rdev->wpan_phy.current_channel))
286 goto nla_put_failure;
288 /* supported channels array */
289 if (nl802154_send_wpan_phy_channels(rdev, msg))
290 goto nla_put_failure;
293 if (nla_put_u8(msg, NL802154_ATTR_CCA_MODE,
294 rdev->wpan_phy.cca_mode))
295 goto nla_put_failure;
297 if (nla_put_s8(msg, NL802154_ATTR_TX_POWER,
298 rdev->wpan_phy.transmit_power))
299 goto nla_put_failure;
302 return genlmsg_end(msg, hdr);
305 genlmsg_cancel(msg, hdr);
309 struct nl802154_dump_wpan_phy_state {
315 static int nl802154_dump_wpan_phy_parse(struct sk_buff *skb,
316 struct netlink_callback *cb,
317 struct nl802154_dump_wpan_phy_state *state)
319 struct nlattr **tb = nl802154_fam.attrbuf;
320 int ret = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl802154_fam.hdrsize,
321 tb, nl802154_fam.maxattr, nl802154_policy);
323 /* TODO check if we can handle error here,
324 * we have no backward compatibility
329 if (tb[NL802154_ATTR_WPAN_PHY])
330 state->filter_wpan_phy = nla_get_u32(tb[NL802154_ATTR_WPAN_PHY]);
331 if (tb[NL802154_ATTR_WPAN_DEV])
332 state->filter_wpan_phy = nla_get_u64(tb[NL802154_ATTR_WPAN_DEV]) >> 32;
333 if (tb[NL802154_ATTR_IFINDEX]) {
334 struct net_device *netdev;
335 struct cfg802154_registered_device *rdev;
336 int ifidx = nla_get_u32(tb[NL802154_ATTR_IFINDEX]);
339 netdev = __dev_get_by_index(&init_net, ifidx);
342 if (netdev->ieee802154_ptr) {
343 rdev = wpan_phy_to_rdev(
344 netdev->ieee802154_ptr->wpan_phy);
345 state->filter_wpan_phy = rdev->wpan_phy_idx;
353 nl802154_dump_wpan_phy(struct sk_buff *skb, struct netlink_callback *cb)
356 struct nl802154_dump_wpan_phy_state *state = (void *)cb->args[0];
357 struct cfg802154_registered_device *rdev;
361 state = kzalloc(sizeof(*state), GFP_KERNEL);
366 state->filter_wpan_phy = -1;
367 ret = nl802154_dump_wpan_phy_parse(skb, cb, state);
373 cb->args[0] = (long)state;
376 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
377 /* TODO net ns compare */
378 if (++idx <= state->start)
380 if (state->filter_wpan_phy != -1 &&
381 state->filter_wpan_phy != rdev->wpan_phy_idx)
383 /* attempt to fit multiple wpan_phy data chunks into the skb */
384 ret = nl802154_send_wpan_phy(rdev,
385 NL802154_CMD_NEW_WPAN_PHY,
387 NETLINK_CB(cb->skb).portid,
388 cb->nlh->nlmsg_seq, NLM_F_MULTI);
390 if ((ret == -ENOBUFS || ret == -EMSGSIZE) &&
391 !skb->len && cb->min_dump_alloc < 4096) {
392 cb->min_dump_alloc = 4096;
408 static int nl802154_dump_wpan_phy_done(struct netlink_callback *cb)
410 kfree((void *)cb->args[0]);
414 static int nl802154_get_wpan_phy(struct sk_buff *skb, struct genl_info *info)
417 struct cfg802154_registered_device *rdev = info->user_ptr[0];
419 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
423 if (nl802154_send_wpan_phy(rdev, NL802154_CMD_NEW_WPAN_PHY, msg,
424 info->snd_portid, info->snd_seq, 0) < 0) {
429 return genlmsg_reply(msg, info);
432 static inline u64 wpan_dev_id(struct wpan_dev *wpan_dev)
434 return (u64)wpan_dev->identifier |
435 ((u64)wpan_phy_to_rdev(wpan_dev->wpan_phy)->wpan_phy_idx << 32);
439 nl802154_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
440 struct cfg802154_registered_device *rdev,
441 struct wpan_dev *wpan_dev)
443 struct net_device *dev = wpan_dev->netdev;
446 hdr = nl802154hdr_put(msg, portid, seq, flags,
447 NL802154_CMD_NEW_INTERFACE);
452 (nla_put_u32(msg, NL802154_ATTR_IFINDEX, dev->ifindex) ||
453 nla_put_string(msg, NL802154_ATTR_IFNAME, dev->name)))
454 goto nla_put_failure;
456 if (nla_put_u32(msg, NL802154_ATTR_WPAN_PHY, rdev->wpan_phy_idx) ||
457 nla_put_u32(msg, NL802154_ATTR_IFTYPE, wpan_dev->iftype) ||
458 nla_put_u64(msg, NL802154_ATTR_WPAN_DEV, wpan_dev_id(wpan_dev)) ||
459 nla_put_u32(msg, NL802154_ATTR_GENERATION,
460 rdev->devlist_generation ^
461 (cfg802154_rdev_list_generation << 2)))
462 goto nla_put_failure;
464 /* address settings */
465 if (nla_put_le64(msg, NL802154_ATTR_EXTENDED_ADDR,
466 wpan_dev->extended_addr) ||
467 nla_put_le16(msg, NL802154_ATTR_SHORT_ADDR,
468 wpan_dev->short_addr) ||
469 nla_put_le16(msg, NL802154_ATTR_PAN_ID, wpan_dev->pan_id))
470 goto nla_put_failure;
473 if (nla_put_s8(msg, NL802154_ATTR_MAX_FRAME_RETRIES,
474 wpan_dev->frame_retries) ||
475 nla_put_u8(msg, NL802154_ATTR_MAX_BE, wpan_dev->max_be) ||
476 nla_put_u8(msg, NL802154_ATTR_MAX_CSMA_BACKOFFS,
477 wpan_dev->csma_retries) ||
478 nla_put_u8(msg, NL802154_ATTR_MIN_BE, wpan_dev->min_be))
479 goto nla_put_failure;
481 /* listen before transmit */
482 if (nla_put_u8(msg, NL802154_ATTR_LBT_MODE, wpan_dev->lbt))
483 goto nla_put_failure;
485 return genlmsg_end(msg, hdr);
488 genlmsg_cancel(msg, hdr);
493 nl802154_dump_interface(struct sk_buff *skb, struct netlink_callback *cb)
497 int wp_start = cb->args[0];
498 int if_start = cb->args[1];
499 struct cfg802154_registered_device *rdev;
500 struct wpan_dev *wpan_dev;
503 list_for_each_entry(rdev, &cfg802154_rdev_list, list) {
504 /* TODO netns compare */
505 if (wp_idx < wp_start) {
511 list_for_each_entry(wpan_dev, &rdev->wpan_dev_list, list) {
512 if (if_idx < if_start) {
516 if (nl802154_send_iface(skb, NETLINK_CB(cb->skb).portid,
517 cb->nlh->nlmsg_seq, NLM_F_MULTI,
518 rdev, wpan_dev) < 0) {
529 cb->args[0] = wp_idx;
530 cb->args[1] = if_idx;
535 static int nl802154_get_interface(struct sk_buff *skb, struct genl_info *info)
538 struct cfg802154_registered_device *rdev = info->user_ptr[0];
539 struct wpan_dev *wdev = info->user_ptr[1];
541 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
545 if (nl802154_send_iface(msg, info->snd_portid, info->snd_seq, 0,
551 return genlmsg_reply(msg, info);
554 static int nl802154_set_channel(struct sk_buff *skb, struct genl_info *info)
556 struct cfg802154_registered_device *rdev = info->user_ptr[0];
559 if (!info->attrs[NL802154_ATTR_PAGE] ||
560 !info->attrs[NL802154_ATTR_CHANNEL])
563 page = nla_get_u8(info->attrs[NL802154_ATTR_PAGE]);
564 channel = nla_get_u8(info->attrs[NL802154_ATTR_CHANNEL]);
566 /* check 802.15.4 constraints */
567 if (page >= WPAN_NUM_PAGES || channel >= WPAN_NUM_CHANNELS)
570 return rdev_set_channel(rdev, page, channel);
573 static int nl802154_set_pan_id(struct sk_buff *skb, struct genl_info *info)
575 struct cfg802154_registered_device *rdev = info->user_ptr[0];
576 struct net_device *dev = info->user_ptr[1];
577 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
580 /* conflict here while tx/rx calls */
581 if (netif_running(dev))
584 /* don't change address fields on monitor */
585 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
588 if (!info->attrs[NL802154_ATTR_PAN_ID])
591 pan_id = nla_get_u16(info->attrs[NL802154_ATTR_PAN_ID]);
593 return rdev_set_pan_id(rdev, wpan_dev, pan_id);
596 static int nl802154_set_short_addr(struct sk_buff *skb, struct genl_info *info)
598 struct cfg802154_registered_device *rdev = info->user_ptr[0];
599 struct net_device *dev = info->user_ptr[1];
600 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
603 /* conflict here while tx/rx calls */
604 if (netif_running(dev))
607 /* don't change address fields on monitor */
608 if (wpan_dev->iftype == NL802154_IFTYPE_MONITOR)
611 if (!info->attrs[NL802154_ATTR_SHORT_ADDR])
614 short_addr = nla_get_u16(info->attrs[NL802154_ATTR_SHORT_ADDR]);
616 return rdev_set_short_addr(rdev, wpan_dev, short_addr);
620 nl802154_set_backoff_exponent(struct sk_buff *skb, struct genl_info *info)
622 struct cfg802154_registered_device *rdev = info->user_ptr[0];
623 struct net_device *dev = info->user_ptr[1];
624 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
627 /* should be set on netif open inside phy settings */
628 if (netif_running(dev))
631 if (!info->attrs[NL802154_ATTR_MIN_BE] ||
632 !info->attrs[NL802154_ATTR_MAX_BE])
635 min_be = nla_get_u8(info->attrs[NL802154_ATTR_MIN_BE]);
636 max_be = nla_get_u8(info->attrs[NL802154_ATTR_MAX_BE]);
638 /* check 802.15.4 constraints */
639 if (max_be < 3 || max_be > 8 || min_be > max_be)
642 return rdev_set_backoff_exponent(rdev, wpan_dev, min_be, max_be);
646 nl802154_set_max_csma_backoffs(struct sk_buff *skb, struct genl_info *info)
648 struct cfg802154_registered_device *rdev = info->user_ptr[0];
649 struct net_device *dev = info->user_ptr[1];
650 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
651 u8 max_csma_backoffs;
653 /* conflict here while other running iface settings */
654 if (netif_running(dev))
657 if (!info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS])
660 max_csma_backoffs = nla_get_u8(
661 info->attrs[NL802154_ATTR_MAX_CSMA_BACKOFFS]);
663 /* check 802.15.4 constraints */
664 if (max_csma_backoffs > 5)
667 return rdev_set_max_csma_backoffs(rdev, wpan_dev, max_csma_backoffs);
671 nl802154_set_max_frame_retries(struct sk_buff *skb, struct genl_info *info)
673 struct cfg802154_registered_device *rdev = info->user_ptr[0];
674 struct net_device *dev = info->user_ptr[1];
675 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
676 s8 max_frame_retries;
678 if (netif_running(dev))
681 if (!info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES])
684 max_frame_retries = nla_get_s8(
685 info->attrs[NL802154_ATTR_MAX_FRAME_RETRIES]);
687 /* check 802.15.4 constraints */
688 if (max_frame_retries < -1 || max_frame_retries > 7)
691 return rdev_set_max_frame_retries(rdev, wpan_dev, max_frame_retries);
694 static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info)
696 struct cfg802154_registered_device *rdev = info->user_ptr[0];
697 struct net_device *dev = info->user_ptr[1];
698 struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
701 if (netif_running(dev))
704 if (!info->attrs[NL802154_ATTR_LBT_MODE])
707 mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]);
708 return rdev_set_lbt_mode(rdev, wpan_dev, mode);
711 #define NL802154_FLAG_NEED_WPAN_PHY 0x01
712 #define NL802154_FLAG_NEED_NETDEV 0x02
713 #define NL802154_FLAG_NEED_RTNL 0x04
714 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08
715 #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\
716 NL802154_FLAG_CHECK_NETDEV_UP)
717 #define NL802154_FLAG_NEED_WPAN_DEV 0x10
718 #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\
719 NL802154_FLAG_CHECK_NETDEV_UP)
721 static int nl802154_pre_doit(const struct genl_ops *ops, struct sk_buff *skb,
722 struct genl_info *info)
724 struct cfg802154_registered_device *rdev;
725 struct wpan_dev *wpan_dev;
726 struct net_device *dev;
727 bool rtnl = ops->internal_flags & NL802154_FLAG_NEED_RTNL;
732 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_PHY) {
733 rdev = cfg802154_get_dev_from_info(genl_info_net(info), info);
737 return PTR_ERR(rdev);
739 info->user_ptr[0] = rdev;
740 } else if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV ||
741 ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
743 wpan_dev = __cfg802154_wpan_dev_from_attrs(genl_info_net(info),
745 if (IS_ERR(wpan_dev)) {
748 return PTR_ERR(wpan_dev);
751 dev = wpan_dev->netdev;
752 rdev = wpan_phy_to_rdev(wpan_dev->wpan_phy);
754 if (ops->internal_flags & NL802154_FLAG_NEED_NETDEV) {
761 info->user_ptr[1] = dev;
763 info->user_ptr[1] = wpan_dev;
767 if (ops->internal_flags & NL802154_FLAG_CHECK_NETDEV_UP &&
768 !netif_running(dev)) {
777 info->user_ptr[0] = rdev;
783 static void nl802154_post_doit(const struct genl_ops *ops, struct sk_buff *skb,
784 struct genl_info *info)
786 if (info->user_ptr[1]) {
787 if (ops->internal_flags & NL802154_FLAG_NEED_WPAN_DEV) {
788 struct wpan_dev *wpan_dev = info->user_ptr[1];
790 if (wpan_dev->netdev)
791 dev_put(wpan_dev->netdev);
793 dev_put(info->user_ptr[1]);
797 if (ops->internal_flags & NL802154_FLAG_NEED_RTNL)
801 static const struct genl_ops nl802154_ops[] = {
803 .cmd = NL802154_CMD_GET_WPAN_PHY,
804 .doit = nl802154_get_wpan_phy,
805 .dumpit = nl802154_dump_wpan_phy,
806 .done = nl802154_dump_wpan_phy_done,
807 .policy = nl802154_policy,
808 /* can be retrieved by unprivileged users */
809 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
810 NL802154_FLAG_NEED_RTNL,
813 .cmd = NL802154_CMD_GET_INTERFACE,
814 .doit = nl802154_get_interface,
815 .dumpit = nl802154_dump_interface,
816 .policy = nl802154_policy,
817 /* can be retrieved by unprivileged users */
818 .internal_flags = NL802154_FLAG_NEED_WPAN_DEV |
819 NL802154_FLAG_NEED_RTNL,
822 .cmd = NL802154_CMD_SET_CHANNEL,
823 .doit = nl802154_set_channel,
824 .policy = nl802154_policy,
825 .flags = GENL_ADMIN_PERM,
826 .internal_flags = NL802154_FLAG_NEED_WPAN_PHY |
827 NL802154_FLAG_NEED_RTNL,
830 .cmd = NL802154_CMD_SET_PAN_ID,
831 .doit = nl802154_set_pan_id,
832 .policy = nl802154_policy,
833 .flags = GENL_ADMIN_PERM,
834 .internal_flags = NL802154_FLAG_NEED_NETDEV |
835 NL802154_FLAG_NEED_RTNL,
838 .cmd = NL802154_CMD_SET_SHORT_ADDR,
839 .doit = nl802154_set_short_addr,
840 .policy = nl802154_policy,
841 .flags = GENL_ADMIN_PERM,
842 .internal_flags = NL802154_FLAG_NEED_NETDEV |
843 NL802154_FLAG_NEED_RTNL,
846 .cmd = NL802154_CMD_SET_BACKOFF_EXPONENT,
847 .doit = nl802154_set_backoff_exponent,
848 .policy = nl802154_policy,
849 .flags = GENL_ADMIN_PERM,
850 .internal_flags = NL802154_FLAG_NEED_NETDEV |
851 NL802154_FLAG_NEED_RTNL,
854 .cmd = NL802154_CMD_SET_MAX_CSMA_BACKOFFS,
855 .doit = nl802154_set_max_csma_backoffs,
856 .policy = nl802154_policy,
857 .flags = GENL_ADMIN_PERM,
858 .internal_flags = NL802154_FLAG_NEED_NETDEV |
859 NL802154_FLAG_NEED_RTNL,
862 .cmd = NL802154_CMD_SET_MAX_FRAME_RETRIES,
863 .doit = nl802154_set_max_frame_retries,
864 .policy = nl802154_policy,
865 .flags = GENL_ADMIN_PERM,
866 .internal_flags = NL802154_FLAG_NEED_NETDEV |
867 NL802154_FLAG_NEED_RTNL,
870 .cmd = NL802154_CMD_SET_LBT_MODE,
871 .doit = nl802154_set_lbt_mode,
872 .policy = nl802154_policy,
873 .flags = GENL_ADMIN_PERM,
874 .internal_flags = NL802154_FLAG_NEED_NETDEV |
875 NL802154_FLAG_NEED_RTNL,
879 /* initialisation/exit functions */
880 int nl802154_init(void)
882 return genl_register_family_with_ops_groups(&nl802154_fam, nl802154_ops,
886 void nl802154_exit(void)
888 genl_unregister_family(&nl802154_fam);