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
);