Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ieee802154: Add support for user beaconing requests

Parse user requests for sending beacons, start sending beacons at a
regular pace. If needed, the pace can be updated with a new request. The
process can also be interrupted at any moment.

The page and channel must be changed beforehands if needed. Interval
orders above 14 are reserved to tell a device it must answer BEACON_REQ
coming from another device as part of an active scan procedure and this
is not yet supported.

A netlink "beacon request" structure is created to list the
requirements.

Mac layers may now implement the ->send_beacons() and
->stop_beacons() hooks.

Co-developed-by: David Girault <david.girault@qorvo.com>
Signed-off-by: David Girault <david.girault@qorvo.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Acked-by: Alexander Aring <aahringo@redhat.com>
Link: https://lore.kernel.org/r/20230125102923.135465-2-miquel.raynal@bootlin.com
Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>

authored by

Miquel Raynal and committed by
Stefan Schmidt
9bc11450 57588c71

+169
+23
include/net/cfg802154.h
··· 19 19 struct wpan_phy; 20 20 struct wpan_phy_cca; 21 21 struct cfg802154_scan_request; 22 + struct cfg802154_beacon_request; 22 23 23 24 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 24 25 struct ieee802154_llsec_device_key; ··· 73 72 struct cfg802154_scan_request *request); 74 73 int (*abort_scan)(struct wpan_phy *wpan_phy, 75 74 struct wpan_dev *wpan_dev); 75 + int (*send_beacons)(struct wpan_phy *wpan_phy, 76 + struct cfg802154_beacon_request *request); 77 + int (*stop_beacons)(struct wpan_phy *wpan_phy, 78 + struct wpan_dev *wpan_dev); 76 79 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 77 80 void (*get_llsec_table)(struct wpan_phy *wpan_phy, 78 81 struct wpan_dev *wpan_dev, ··· 315 310 u8 page; 316 311 u32 channels; 317 312 u8 duration; 313 + struct wpan_dev *wpan_dev; 314 + struct wpan_phy *wpan_phy; 315 + }; 316 + 317 + /** 318 + * struct cfg802154_beacon_request - Beacon request descriptor 319 + * 320 + * @interval: interval n between sendings, in multiple order of the super frame 321 + * duration: aBaseSuperframeDuration * (2^n) unless the interval 322 + * order is greater or equal to 15, in this case beacons won't be 323 + * passively sent out at a fixed rate but instead inform the device 324 + * that it should answer beacon requests as part of active scan 325 + * procedures 326 + * @wpan_dev: the concerned wpan device 327 + * @wpan_phy: the wpan phy this was for 328 + */ 329 + struct cfg802154_beacon_request { 330 + u8 interval; 318 331 struct wpan_dev *wpan_dev; 319 332 struct wpan_phy *wpan_phy; 320 333 };
+3
include/net/nl802154.h
··· 76 76 NL802154_CMD_TRIGGER_SCAN, 77 77 NL802154_CMD_ABORT_SCAN, 78 78 NL802154_CMD_SCAN_DONE, 79 + NL802154_CMD_SEND_BEACONS, 80 + NL802154_CMD_STOP_BEACONS, 79 81 80 82 /* add new commands above here */ 81 83 ··· 146 144 NL802154_ATTR_SCAN_MEAN_PRF, 147 145 NL802154_ATTR_SCAN_DURATION, 148 146 NL802154_ATTR_SCAN_DONE_REASON, 147 + NL802154_ATTR_BEACON_INTERVAL, 149 148 150 149 /* add attributes here, update the policy in nl802154.c */ 151 150
+93
net/ieee802154/nl802154.c
··· 227 227 [NL802154_ATTR_SCAN_MEAN_PRF] = { .type = NLA_U8 }, 228 228 [NL802154_ATTR_SCAN_DURATION] = { .type = NLA_U8 }, 229 229 [NL802154_ATTR_SCAN_DONE_REASON] = { .type = NLA_U8 }, 230 + [NL802154_ATTR_BEACON_INTERVAL] = { .type = NLA_U8 }, 230 231 231 232 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 232 233 [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, ··· 1588 1587 return rdev_abort_scan(rdev, wpan_dev); 1589 1588 } 1590 1589 1590 + static int 1591 + nl802154_send_beacons(struct sk_buff *skb, struct genl_info *info) 1592 + { 1593 + struct cfg802154_registered_device *rdev = info->user_ptr[0]; 1594 + struct net_device *dev = info->user_ptr[1]; 1595 + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 1596 + struct wpan_phy *wpan_phy = &rdev->wpan_phy; 1597 + struct cfg802154_beacon_request *request; 1598 + int err; 1599 + 1600 + /* Only coordinators can send beacons */ 1601 + if (wpan_dev->iftype != NL802154_IFTYPE_COORD) 1602 + return -EOPNOTSUPP; 1603 + 1604 + if (wpan_dev->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST)) { 1605 + pr_err("Device is not part of any PAN\n"); 1606 + return -EPERM; 1607 + } 1608 + 1609 + request = kzalloc(sizeof(*request), GFP_KERNEL); 1610 + if (!request) 1611 + return -ENOMEM; 1612 + 1613 + request->wpan_dev = wpan_dev; 1614 + request->wpan_phy = wpan_phy; 1615 + 1616 + if (info->attrs[NL802154_ATTR_BEACON_INTERVAL]) { 1617 + request->interval = nla_get_u8(info->attrs[NL802154_ATTR_BEACON_INTERVAL]); 1618 + if (request->interval > IEEE802154_MAX_SCAN_DURATION) { 1619 + pr_err("Interval is out of range\n"); 1620 + err = -EINVAL; 1621 + goto free_request; 1622 + } 1623 + } else { 1624 + /* Use maximum duration order by default */ 1625 + request->interval = IEEE802154_MAX_SCAN_DURATION; 1626 + } 1627 + 1628 + if (wpan_dev->netdev) 1629 + dev_hold(wpan_dev->netdev); 1630 + 1631 + err = rdev_send_beacons(rdev, request); 1632 + if (err) { 1633 + pr_err("Failure starting sending beacons (%d)\n", err); 1634 + goto free_device; 1635 + } 1636 + 1637 + return 0; 1638 + 1639 + free_device: 1640 + if (wpan_dev->netdev) 1641 + dev_put(wpan_dev->netdev); 1642 + free_request: 1643 + kfree(request); 1644 + 1645 + return err; 1646 + } 1647 + 1648 + void nl802154_beaconing_done(struct wpan_dev *wpan_dev) 1649 + { 1650 + if (wpan_dev->netdev) 1651 + dev_put(wpan_dev->netdev); 1652 + } 1653 + EXPORT_SYMBOL_GPL(nl802154_beaconing_done); 1654 + 1655 + static int 1656 + nl802154_stop_beacons(struct sk_buff *skb, struct genl_info *info) 1657 + { 1658 + struct cfg802154_registered_device *rdev = info->user_ptr[0]; 1659 + struct net_device *dev = info->user_ptr[1]; 1660 + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; 1661 + 1662 + /* Resources are released in the notification helper above */ 1663 + return rdev_stop_beacons(rdev, wpan_dev); 1664 + } 1665 + 1591 1666 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 1592 1667 static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { 1593 1668 [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, ··· 2765 2688 { 2766 2689 .cmd = NL802154_CMD_ABORT_SCAN, 2767 2690 .doit = nl802154_abort_scan, 2691 + .flags = GENL_ADMIN_PERM, 2692 + .internal_flags = NL802154_FLAG_NEED_NETDEV | 2693 + NL802154_FLAG_CHECK_NETDEV_UP | 2694 + NL802154_FLAG_NEED_RTNL, 2695 + }, 2696 + { 2697 + .cmd = NL802154_CMD_SEND_BEACONS, 2698 + .doit = nl802154_send_beacons, 2699 + .flags = GENL_ADMIN_PERM, 2700 + .internal_flags = NL802154_FLAG_NEED_NETDEV | 2701 + NL802154_FLAG_CHECK_NETDEV_UP | 2702 + NL802154_FLAG_NEED_RTNL, 2703 + }, 2704 + { 2705 + .cmd = NL802154_CMD_STOP_BEACONS, 2706 + .doit = nl802154_stop_beacons, 2768 2707 .flags = GENL_ADMIN_PERM, 2769 2708 .internal_flags = NL802154_FLAG_NEED_NETDEV | 2770 2709 NL802154_FLAG_CHECK_NETDEV_UP |
+1
net/ieee802154/nl802154.h
··· 9 9 int nl802154_scan_started(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev); 10 10 int nl802154_scan_done(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, 11 11 enum nl802154_scan_done_reasons reason); 12 + void nl802154_beaconing_done(struct wpan_dev *wpan_dev); 12 13 13 14 #endif /* __IEEE802154_NL802154_H */
+28
net/ieee802154/rdev-ops.h
··· 237 237 return ret; 238 238 } 239 239 240 + static inline int rdev_send_beacons(struct cfg802154_registered_device *rdev, 241 + struct cfg802154_beacon_request *request) 242 + { 243 + int ret; 244 + 245 + if (!rdev->ops->send_beacons) 246 + return -EOPNOTSUPP; 247 + 248 + trace_802154_rdev_send_beacons(&rdev->wpan_phy, request); 249 + ret = rdev->ops->send_beacons(&rdev->wpan_phy, request); 250 + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); 251 + return ret; 252 + } 253 + 254 + static inline int rdev_stop_beacons(struct cfg802154_registered_device *rdev, 255 + struct wpan_dev *wpan_dev) 256 + { 257 + int ret; 258 + 259 + if (!rdev->ops->stop_beacons) 260 + return -EOPNOTSUPP; 261 + 262 + trace_802154_rdev_stop_beacons(&rdev->wpan_phy, wpan_dev); 263 + ret = rdev->ops->stop_beacons(&rdev->wpan_phy, wpan_dev); 264 + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); 265 + return ret; 266 + } 267 + 240 268 #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL 241 269 /* TODO this is already a nl802154, so move into ieee802154 */ 242 270 static inline void
+21
net/ieee802154/trace.h
··· 315 315 WPAN_PHY_PR_ARG, __entry->page, __entry->channels, __entry->duration) 316 316 ); 317 317 318 + TRACE_EVENT(802154_rdev_send_beacons, 319 + TP_PROTO(struct wpan_phy *wpan_phy, 320 + struct cfg802154_beacon_request *request), 321 + TP_ARGS(wpan_phy, request), 322 + TP_STRUCT__entry( 323 + WPAN_PHY_ENTRY 324 + __field(u8, interval) 325 + ), 326 + TP_fast_assign( 327 + WPAN_PHY_ASSIGN; 328 + __entry->interval = request->interval; 329 + ), 330 + TP_printk(WPAN_PHY_PR_FMT ", sending beacons (interval order: %d)", 331 + WPAN_PHY_PR_ARG, __entry->interval) 332 + ); 333 + 318 334 DECLARE_EVENT_CLASS(802154_wdev_template, 319 335 TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), 320 336 TP_ARGS(wpan_phy, wpan_dev), ··· 347 331 ); 348 332 349 333 DEFINE_EVENT(802154_wdev_template, 802154_rdev_abort_scan, 334 + TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), 335 + TP_ARGS(wpan_phy, wpan_dev) 336 + ); 337 + 338 + DEFINE_EVENT(802154_wdev_template, 802154_rdev_stop_beacons, 350 339 TP_PROTO(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev), 351 340 TP_ARGS(wpan_phy, wpan_dev) 352 341 );