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
<= IEEE802154_MAX_PAGE
; 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_new_interface(struct sk_buff
*skb
, struct genl_info
*info
)
556 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
557 enum nl802154_iftype type
= NL802154_IFTYPE_UNSPEC
;
558 __le64 extended_addr
= cpu_to_le64(0x0000000000000000ULL
);
560 /* TODO avoid failing a new interface
561 * creation due to pending removal?
564 if (!info
->attrs
[NL802154_ATTR_IFNAME
])
567 if (info
->attrs
[NL802154_ATTR_IFTYPE
]) {
568 type
= nla_get_u32(info
->attrs
[NL802154_ATTR_IFTYPE
]);
569 if (type
> NL802154_IFTYPE_MAX
)
573 /* TODO add nla_get_le64 to netlink */
574 if (info
->attrs
[NL802154_ATTR_EXTENDED_ADDR
])
575 extended_addr
= (__force __le64
)nla_get_u64(
576 info
->attrs
[NL802154_ATTR_EXTENDED_ADDR
]);
578 if (!rdev
->ops
->add_virtual_intf
)
581 return rdev_add_virtual_intf(rdev
,
582 nla_data(info
->attrs
[NL802154_ATTR_IFNAME
]),
583 type
, extended_addr
);
586 static int nl802154_del_interface(struct sk_buff
*skb
, struct genl_info
*info
)
588 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
589 struct wpan_dev
*wpan_dev
= info
->user_ptr
[1];
591 if (!rdev
->ops
->del_virtual_intf
)
594 /* If we remove a wpan device without a netdev then clear
595 * user_ptr[1] so that nl802154_post_doit won't dereference it
596 * to check if it needs to do dev_put(). Otherwise it crashes
597 * since the wpan_dev has been freed, unlike with a netdev where
598 * we need the dev_put() for the netdev to really be freed.
600 if (!wpan_dev
->netdev
)
601 info
->user_ptr
[1] = NULL
;
603 return rdev_del_virtual_intf(rdev
, wpan_dev
);
606 static int nl802154_set_channel(struct sk_buff
*skb
, struct genl_info
*info
)
608 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
611 if (!info
->attrs
[NL802154_ATTR_PAGE
] ||
612 !info
->attrs
[NL802154_ATTR_CHANNEL
])
615 page
= nla_get_u8(info
->attrs
[NL802154_ATTR_PAGE
]);
616 channel
= nla_get_u8(info
->attrs
[NL802154_ATTR_CHANNEL
]);
618 /* check 802.15.4 constraints */
619 if (page
> IEEE802154_MAX_PAGE
|| channel
> IEEE802154_MAX_CHANNEL
)
622 return rdev_set_channel(rdev
, page
, channel
);
625 static int nl802154_set_pan_id(struct sk_buff
*skb
, struct genl_info
*info
)
627 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
628 struct net_device
*dev
= info
->user_ptr
[1];
629 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
632 /* conflict here while tx/rx calls */
633 if (netif_running(dev
))
636 /* don't change address fields on monitor */
637 if (wpan_dev
->iftype
== NL802154_IFTYPE_MONITOR
)
640 if (!info
->attrs
[NL802154_ATTR_PAN_ID
])
643 pan_id
= nla_get_le16(info
->attrs
[NL802154_ATTR_PAN_ID
]);
645 return rdev_set_pan_id(rdev
, wpan_dev
, pan_id
);
648 static int nl802154_set_short_addr(struct sk_buff
*skb
, struct genl_info
*info
)
650 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
651 struct net_device
*dev
= info
->user_ptr
[1];
652 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
655 /* conflict here while tx/rx calls */
656 if (netif_running(dev
))
659 /* don't change address fields on monitor */
660 if (wpan_dev
->iftype
== NL802154_IFTYPE_MONITOR
)
663 if (!info
->attrs
[NL802154_ATTR_SHORT_ADDR
])
666 short_addr
= nla_get_le16(info
->attrs
[NL802154_ATTR_SHORT_ADDR
]);
668 return rdev_set_short_addr(rdev
, wpan_dev
, short_addr
);
672 nl802154_set_backoff_exponent(struct sk_buff
*skb
, struct genl_info
*info
)
674 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
675 struct net_device
*dev
= info
->user_ptr
[1];
676 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
679 /* should be set on netif open inside phy settings */
680 if (netif_running(dev
))
683 if (!info
->attrs
[NL802154_ATTR_MIN_BE
] ||
684 !info
->attrs
[NL802154_ATTR_MAX_BE
])
687 min_be
= nla_get_u8(info
->attrs
[NL802154_ATTR_MIN_BE
]);
688 max_be
= nla_get_u8(info
->attrs
[NL802154_ATTR_MAX_BE
]);
690 /* check 802.15.4 constraints */
691 if (max_be
< 3 || max_be
> 8 || min_be
> max_be
)
694 return rdev_set_backoff_exponent(rdev
, wpan_dev
, min_be
, max_be
);
698 nl802154_set_max_csma_backoffs(struct sk_buff
*skb
, struct genl_info
*info
)
700 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
701 struct net_device
*dev
= info
->user_ptr
[1];
702 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
703 u8 max_csma_backoffs
;
705 /* conflict here while other running iface settings */
706 if (netif_running(dev
))
709 if (!info
->attrs
[NL802154_ATTR_MAX_CSMA_BACKOFFS
])
712 max_csma_backoffs
= nla_get_u8(
713 info
->attrs
[NL802154_ATTR_MAX_CSMA_BACKOFFS
]);
715 /* check 802.15.4 constraints */
716 if (max_csma_backoffs
> 5)
719 return rdev_set_max_csma_backoffs(rdev
, wpan_dev
, max_csma_backoffs
);
723 nl802154_set_max_frame_retries(struct sk_buff
*skb
, struct genl_info
*info
)
725 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
726 struct net_device
*dev
= info
->user_ptr
[1];
727 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
728 s8 max_frame_retries
;
730 if (netif_running(dev
))
733 if (!info
->attrs
[NL802154_ATTR_MAX_FRAME_RETRIES
])
736 max_frame_retries
= nla_get_s8(
737 info
->attrs
[NL802154_ATTR_MAX_FRAME_RETRIES
]);
739 /* check 802.15.4 constraints */
740 if (max_frame_retries
< -1 || max_frame_retries
> 7)
743 return rdev_set_max_frame_retries(rdev
, wpan_dev
, max_frame_retries
);
746 static int nl802154_set_lbt_mode(struct sk_buff
*skb
, struct genl_info
*info
)
748 struct cfg802154_registered_device
*rdev
= info
->user_ptr
[0];
749 struct net_device
*dev
= info
->user_ptr
[1];
750 struct wpan_dev
*wpan_dev
= dev
->ieee802154_ptr
;
753 if (netif_running(dev
))
756 if (!info
->attrs
[NL802154_ATTR_LBT_MODE
])
759 mode
= !!nla_get_u8(info
->attrs
[NL802154_ATTR_LBT_MODE
]);
760 return rdev_set_lbt_mode(rdev
, wpan_dev
, mode
);
763 #define NL802154_FLAG_NEED_WPAN_PHY 0x01
764 #define NL802154_FLAG_NEED_NETDEV 0x02
765 #define NL802154_FLAG_NEED_RTNL 0x04
766 #define NL802154_FLAG_CHECK_NETDEV_UP 0x08
767 #define NL802154_FLAG_NEED_NETDEV_UP (NL802154_FLAG_NEED_NETDEV |\
768 NL802154_FLAG_CHECK_NETDEV_UP)
769 #define NL802154_FLAG_NEED_WPAN_DEV 0x10
770 #define NL802154_FLAG_NEED_WPAN_DEV_UP (NL802154_FLAG_NEED_WPAN_DEV |\
771 NL802154_FLAG_CHECK_NETDEV_UP)
773 static int nl802154_pre_doit(const struct genl_ops
*ops
, struct sk_buff
*skb
,
774 struct genl_info
*info
)
776 struct cfg802154_registered_device
*rdev
;
777 struct wpan_dev
*wpan_dev
;
778 struct net_device
*dev
;
779 bool rtnl
= ops
->internal_flags
& NL802154_FLAG_NEED_RTNL
;
784 if (ops
->internal_flags
& NL802154_FLAG_NEED_WPAN_PHY
) {
785 rdev
= cfg802154_get_dev_from_info(genl_info_net(info
), info
);
789 return PTR_ERR(rdev
);
791 info
->user_ptr
[0] = rdev
;
792 } else if (ops
->internal_flags
& NL802154_FLAG_NEED_NETDEV
||
793 ops
->internal_flags
& NL802154_FLAG_NEED_WPAN_DEV
) {
795 wpan_dev
= __cfg802154_wpan_dev_from_attrs(genl_info_net(info
),
797 if (IS_ERR(wpan_dev
)) {
800 return PTR_ERR(wpan_dev
);
803 dev
= wpan_dev
->netdev
;
804 rdev
= wpan_phy_to_rdev(wpan_dev
->wpan_phy
);
806 if (ops
->internal_flags
& NL802154_FLAG_NEED_NETDEV
) {
813 info
->user_ptr
[1] = dev
;
815 info
->user_ptr
[1] = wpan_dev
;
819 if (ops
->internal_flags
& NL802154_FLAG_CHECK_NETDEV_UP
&&
820 !netif_running(dev
)) {
829 info
->user_ptr
[0] = rdev
;
835 static void nl802154_post_doit(const struct genl_ops
*ops
, struct sk_buff
*skb
,
836 struct genl_info
*info
)
838 if (info
->user_ptr
[1]) {
839 if (ops
->internal_flags
& NL802154_FLAG_NEED_WPAN_DEV
) {
840 struct wpan_dev
*wpan_dev
= info
->user_ptr
[1];
842 if (wpan_dev
->netdev
)
843 dev_put(wpan_dev
->netdev
);
845 dev_put(info
->user_ptr
[1]);
849 if (ops
->internal_flags
& NL802154_FLAG_NEED_RTNL
)
853 static const struct genl_ops nl802154_ops
[] = {
855 .cmd
= NL802154_CMD_GET_WPAN_PHY
,
856 .doit
= nl802154_get_wpan_phy
,
857 .dumpit
= nl802154_dump_wpan_phy
,
858 .done
= nl802154_dump_wpan_phy_done
,
859 .policy
= nl802154_policy
,
860 /* can be retrieved by unprivileged users */
861 .internal_flags
= NL802154_FLAG_NEED_WPAN_PHY
|
862 NL802154_FLAG_NEED_RTNL
,
865 .cmd
= NL802154_CMD_GET_INTERFACE
,
866 .doit
= nl802154_get_interface
,
867 .dumpit
= nl802154_dump_interface
,
868 .policy
= nl802154_policy
,
869 /* can be retrieved by unprivileged users */
870 .internal_flags
= NL802154_FLAG_NEED_WPAN_DEV
|
871 NL802154_FLAG_NEED_RTNL
,
874 .cmd
= NL802154_CMD_NEW_INTERFACE
,
875 .doit
= nl802154_new_interface
,
876 .policy
= nl802154_policy
,
877 .flags
= GENL_ADMIN_PERM
,
878 .internal_flags
= NL802154_FLAG_NEED_WPAN_PHY
|
879 NL802154_FLAG_NEED_RTNL
,
882 .cmd
= NL802154_CMD_DEL_INTERFACE
,
883 .doit
= nl802154_del_interface
,
884 .policy
= nl802154_policy
,
885 .flags
= GENL_ADMIN_PERM
,
886 .internal_flags
= NL802154_FLAG_NEED_WPAN_DEV
|
887 NL802154_FLAG_NEED_RTNL
,
890 .cmd
= NL802154_CMD_SET_CHANNEL
,
891 .doit
= nl802154_set_channel
,
892 .policy
= nl802154_policy
,
893 .flags
= GENL_ADMIN_PERM
,
894 .internal_flags
= NL802154_FLAG_NEED_WPAN_PHY
|
895 NL802154_FLAG_NEED_RTNL
,
898 .cmd
= NL802154_CMD_SET_PAN_ID
,
899 .doit
= nl802154_set_pan_id
,
900 .policy
= nl802154_policy
,
901 .flags
= GENL_ADMIN_PERM
,
902 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
903 NL802154_FLAG_NEED_RTNL
,
906 .cmd
= NL802154_CMD_SET_SHORT_ADDR
,
907 .doit
= nl802154_set_short_addr
,
908 .policy
= nl802154_policy
,
909 .flags
= GENL_ADMIN_PERM
,
910 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
911 NL802154_FLAG_NEED_RTNL
,
914 .cmd
= NL802154_CMD_SET_BACKOFF_EXPONENT
,
915 .doit
= nl802154_set_backoff_exponent
,
916 .policy
= nl802154_policy
,
917 .flags
= GENL_ADMIN_PERM
,
918 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
919 NL802154_FLAG_NEED_RTNL
,
922 .cmd
= NL802154_CMD_SET_MAX_CSMA_BACKOFFS
,
923 .doit
= nl802154_set_max_csma_backoffs
,
924 .policy
= nl802154_policy
,
925 .flags
= GENL_ADMIN_PERM
,
926 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
927 NL802154_FLAG_NEED_RTNL
,
930 .cmd
= NL802154_CMD_SET_MAX_FRAME_RETRIES
,
931 .doit
= nl802154_set_max_frame_retries
,
932 .policy
= nl802154_policy
,
933 .flags
= GENL_ADMIN_PERM
,
934 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
935 NL802154_FLAG_NEED_RTNL
,
938 .cmd
= NL802154_CMD_SET_LBT_MODE
,
939 .doit
= nl802154_set_lbt_mode
,
940 .policy
= nl802154_policy
,
941 .flags
= GENL_ADMIN_PERM
,
942 .internal_flags
= NL802154_FLAG_NEED_NETDEV
|
943 NL802154_FLAG_NEED_RTNL
,
947 /* initialisation/exit functions */
948 int nl802154_init(void)
950 return genl_register_family_with_ops_groups(&nl802154_fam
, nl802154_ops
,
954 void nl802154_exit(void)
956 genl_unregister_family(&nl802154_fam
);