diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index c844ae63bc04..0d3e9af00198 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -506,6 +506,7 @@ struct wpan_dev { struct mutex association_lock; struct ieee802154_pan_device *parent; struct list_head children; + unsigned int max_associations; }; #define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) @@ -583,6 +584,13 @@ struct ieee802154_pan_device * cfg802154_device_is_child(struct wpan_dev *wpan_dev, struct ieee802154_addr *target); +/** + * cfg802154_set_max_associations - Limit the number of future associations + * @wpan_dev: the wpan device + * @max: the maximum number of devices we accept to associate + */ +void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max); + /** * cfg802154_get_free_short_addr - Get a free address among the known devices * @wpan_dev: the wpan device diff --git a/include/net/nl802154.h b/include/net/nl802154.h index 8a47c14c72f0..8b26faae49e8 100644 --- a/include/net/nl802154.h +++ b/include/net/nl802154.h @@ -80,6 +80,7 @@ enum nl802154_commands { NL802154_CMD_STOP_BEACONS, NL802154_CMD_ASSOCIATE, NL802154_CMD_DISASSOCIATE, + NL802154_CMD_SET_MAX_ASSOCIATIONS, /* add new commands above here */ @@ -149,6 +150,7 @@ enum nl802154_attrs { NL802154_ATTR_SCAN_DURATION, NL802154_ATTR_SCAN_DONE_REASON, NL802154_ATTR_BEACON_INTERVAL, + NL802154_ATTR_MAX_ASSOCIATIONS, /* add attributes here, update the policy in nl802154.c */ diff --git a/net/ieee802154/core.c b/net/ieee802154/core.c index 1670a71327a7..2d6fe45efa05 100644 --- a/net/ieee802154/core.c +++ b/net/ieee802154/core.c @@ -295,6 +295,7 @@ static int cfg802154_netdev_notifier_call(struct notifier_block *nb, rdev->devlist_generation++; mutex_init(&wpan_dev->association_lock); INIT_LIST_HEAD(&wpan_dev->children); + wpan_dev->max_associations = SZ_16K; wpan_dev->netdev = dev; break; diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index dd86ecd7b193..06e0bd6ffcca 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -234,6 +234,7 @@ static const struct nla_policy nl802154_policy[NL802154_ATTR_MAX+1] = { NL802154_SCAN_DONE_REASON_ABORTED), [NL802154_ATTR_BEACON_INTERVAL] = NLA_POLICY_MAX(NLA_U8, IEEE802154_ACTIVE_SCAN_DURATION), + [NL802154_ATTR_MAX_ASSOCIATIONS] = { .type = NLA_U32 }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL [NL802154_ATTR_SEC_ENABLED] = { .type = NLA_U8, }, @@ -1696,6 +1697,26 @@ static int nl802154_disassociate(struct sk_buff *skb, struct genl_info *info) return 0; } +static int nl802154_set_max_associations(struct sk_buff *skb, struct genl_info *info) +{ + struct net_device *dev = info->user_ptr[1]; + struct wpan_dev *wpan_dev = dev->ieee802154_ptr; + unsigned int max_assoc; + + if (!info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]) { + NL_SET_ERR_MSG(info->extack, "No maximum number of association given"); + return -EINVAL; + } + + max_assoc = nla_get_u32(info->attrs[NL802154_ATTR_MAX_ASSOCIATIONS]); + + mutex_lock(&wpan_dev->association_lock); + cfg802154_set_max_associations(wpan_dev, max_assoc); + mutex_unlock(&wpan_dev->association_lock); + + return 0; +} + #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL static const struct nla_policy nl802154_dev_addr_policy[NL802154_DEV_ADDR_ATTR_MAX + 1] = { [NL802154_DEV_ADDR_ATTR_PAN_ID] = { .type = NLA_U16 }, @@ -2833,6 +2854,13 @@ static const struct genl_ops nl802154_ops[] = { NL802154_FLAG_CHECK_NETDEV_UP | NL802154_FLAG_NEED_RTNL, }, + { + .cmd = NL802154_CMD_SET_MAX_ASSOCIATIONS, + .doit = nl802154_set_max_associations, + .flags = GENL_ADMIN_PERM, + .internal_flags = NL802154_FLAG_NEED_NETDEV | + NL802154_FLAG_NEED_RTNL, + }, #ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL { .cmd = NL802154_CMD_SET_SEC_PARAMS, diff --git a/net/ieee802154/pan.c b/net/ieee802154/pan.c index 545461069197..fb5b0af2ef68 100644 --- a/net/ieee802154/pan.c +++ b/net/ieee802154/pan.c @@ -93,3 +93,11 @@ __le16 cfg802154_get_free_short_addr(struct wpan_dev *wpan_dev) return addr; } EXPORT_SYMBOL_GPL(cfg802154_get_free_short_addr); + +void cfg802154_set_max_associations(struct wpan_dev *wpan_dev, unsigned int max) +{ + lockdep_assert_held(&wpan_dev->association_lock); + + wpan_dev->max_associations = max; +} +EXPORT_SYMBOL_GPL(cfg802154_set_max_associations);