wifi: cfg80211: Add support for controlling EPCS

Add support for configuring Emergency Preparedness Communication
Services (EPCS) for station mode.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250102161730.ea54ac94445c.I11d750188bc0871e13e86146a3b5cc048d853e69@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Ilan Peer 2025-01-02 16:19:59 +02:00 committed by Johannes Berg
parent 36e05b0b83
commit 904c277342
5 changed files with 128 additions and 0 deletions

View File

@ -4594,6 +4594,7 @@ struct mgmt_frame_regs {
*
* @set_hw_timestamp: Enable/disable HW timestamping of TM/FTM frames.
* @set_ttlm: set the TID to link mapping.
* @set_epcs: Enable/Disable EPCS for station mode.
* @get_radio_mask: get bitmask of radios in use.
* (invoked with the wiphy mutex held)
* @assoc_ml_reconf: Request a non-AP MLO connection to perform ML
@ -4971,6 +4972,8 @@ struct cfg80211_ops {
int (*assoc_ml_reconf)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_assoc_link *add_links,
u16 rem_links);
int (*set_epcs)(struct wiphy *wiphy, struct net_device *dev,
bool val);
};
/*
@ -9771,6 +9774,13 @@ void cfg80211_mlo_reconf_add_done(struct net_device *dev,
*/
void cfg80211_schedule_channels_check(struct wireless_dev *wdev);
/**
* cfg80211_epcs_changed - Notify about a change in EPCS state
* @netdev: the wireless device whose EPCS state changed
* @enabled: set to true if EPCS was enabled, otherwise set to false.
*/
void cfg80211_epcs_changed(struct net_device *netdev, bool enabled);
#ifdef CONFIG_CFG80211_DEBUGFS
/**
* wiphy_locked_debugfs_read - do a locked read in debugfs

View File

@ -1332,6 +1332,10 @@
* @NL80211_CMD_ASSOC_MLO_RECONF: For a non-AP MLD station, request to
* add/remove links to/from the association.
*
* @NL80211_CMD_EPCS_CFG: EPCS configuration for a station. Used by userland to
* control EPCS configuration. Used to notify userland on the current state
* of EPCS.
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -1590,6 +1594,7 @@ enum nl80211_commands {
NL80211_CMD_SET_TID_TO_LINK_MAPPING,
NL80211_CMD_ASSOC_MLO_RECONF,
NL80211_CMD_EPCS_CFG,
/* add new commands above here */
@ -2885,6 +2890,9 @@ enum nl80211_commands {
* @NL80211_ATTR_MLO_RECONF_REM_LINKS: (u16) A bitmask of the links requested
* to be removed from the MLO association.
*
* @NL80211_ATTR_EPCS: Flag attribute indicating that EPCS is enabled for a
* station interface.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -3438,6 +3446,7 @@ enum nl80211_attrs {
NL80211_ATTR_SUPPORTED_SELECTORS,
NL80211_ATTR_MLO_RECONF_REM_LINKS,
NL80211_ATTR_EPCS,
/* add attributes here, update the policy in nl80211.c */

View File

@ -849,6 +849,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
NLA_POLICY_VALIDATE_FN(NLA_BINARY, validate_supported_selectors,
NL80211_MAX_SUPP_SELECTORS),
[NL80211_ATTR_MLO_RECONF_REM_LINKS] = { .type = NLA_U16 },
[NL80211_ATTR_EPCS] = { .type = NLA_FLAG },
};
/* policy for the key attributes */
@ -16537,6 +16538,26 @@ out:
return err;
}
static int
nl80211_epcs_cfg(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
struct wireless_dev *wdev = dev->ieee80211_ptr;
bool val;
if (wdev->iftype != NL80211_IFTYPE_STATION &&
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
return -EOPNOTSUPP;
if (!wdev->connected)
return -ENOLINK;
val = nla_get_flag(info->attrs[NL80211_ATTR_EPCS]);
return rdev_set_epcs(rdev, dev, val);
}
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@ -17735,6 +17756,12 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
},
{
.cmd = NL80211_CMD_EPCS_CFG,
.doit = nl80211_epcs_cfg,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP),
},
};
static struct genl_family nl80211_fam __ro_after_init = {
@ -20480,6 +20507,39 @@ void cfg80211_schedule_channels_check(struct wireless_dev *wdev)
}
EXPORT_SYMBOL(cfg80211_schedule_channels_check);
void cfg80211_epcs_changed(struct net_device *netdev, bool enabled)
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
struct sk_buff *msg;
void *hdr;
trace_cfg80211_epcs_changed(wdev, enabled);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return;
hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_EPCS_CFG);
if (!hdr) {
nlmsg_free(msg);
return;
}
if (enabled && nla_put_flag(msg, NL80211_ATTR_EPCS))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
NL80211_MCGRP_MLME, GFP_KERNEL);
return;
nla_put_failure:
nlmsg_free(msg);
}
EXPORT_SYMBOL(cfg80211_epcs_changed);
/* initialisation/exit functions */
int __init nl80211_init(void)

View File

@ -1566,4 +1566,19 @@ rdev_assoc_ml_reconf(struct cfg80211_registered_device *rdev,
return ret;
}
static inline int
rdev_set_epcs(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool val)
{
struct wiphy *wiphy = &rdev->wiphy;
int ret = -EOPNOTSUPP;
trace_rdev_set_epcs(wiphy, dev, val);
if (rdev->ops->set_epcs)
ret = rdev->ops->set_epcs(wiphy, dev, val);
trace_rdev_return_int(wiphy, ret);
return ret;
}
#endif /* __CFG80211_RDEV_OPS */

View File

@ -3049,6 +3049,24 @@ TRACE_EVENT(rdev_set_ttlm,
WIPHY_PR_ARG, NETDEV_PR_ARG)
);
TRACE_EVENT(rdev_set_epcs,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
bool val),
TP_ARGS(wiphy, netdev, val),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
__field(bool, val)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
__entry->val = val;
),
TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", config=%u",
WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->val)
);
/*************************************************************
* cfg80211 exported functions traces *
*************************************************************/
@ -4148,6 +4166,22 @@ TRACE_EVENT(rdev_assoc_ml_reconf,
WIPHY_PR_ARG, NETDEV_PR_ARG,
__entry->add_links, __entry->rem_links)
);
TRACE_EVENT(cfg80211_epcs_changed,
TP_PROTO(struct wireless_dev *wdev, bool enabled),
TP_ARGS(wdev, enabled),
TP_STRUCT__entry(
WDEV_ENTRY
__field(u32, enabled)
),
TP_fast_assign(
WDEV_ASSIGN;
__entry->enabled = enabled;
),
TP_printk(WDEV_PR_FMT ", enabled=%u",
WDEV_PR_ARG, __entry->enabled)
);
#endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH