Currently, the proximity detection (PD) interface type has no start/stop commands defined, preventing user space from controlling PD operations through the nl80211 interface. Add NL80211_CMD_START_PD and NL80211_CMD_STOP_PD commands to allow user space to start and stop a PD interface. Add the corresponding start_pd and stop_pd operations to cfg80211_ops and ieee80211_ops, along with nl80211 command handlers, rdev wrappers, and tracing support. Validate that drivers advertising PD interface support implement the required operations. Handle PD interface teardown during device unregistration and when the interface leaves the network. Signed-off-by: Peddolla Harshavardhan Reddy --- include/net/cfg80211.h | 5 ++++ include/uapi/linux/nl80211.h | 9 ++++++ net/wireless/core.c | 32 ++++++++++++++++++++- net/wireless/core.h | 2 ++ net/wireless/nl80211.c | 54 ++++++++++++++++++++++++++++++++++++ net/wireless/rdev-ops.h | 19 +++++++++++++ net/wireless/trace.h | 20 +++++++++++++ 7 files changed, 140 insertions(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 73cfe1a14c01..099a2ff9af58 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -4900,6 +4900,9 @@ struct mgmt_frame_regs { * links by calling cfg80211_mlo_reconf_add_done(). When calling * cfg80211_mlo_reconf_add_done() the bss pointer must be given for each * link for which MLO reconfiguration 'add' operation was requested. + * + * @start_pd: Start the PD interface. + * @stop_pd: Stop the PD interface. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); @@ -5271,6 +5274,8 @@ struct cfg80211_ops { struct cfg80211_ml_reconf_req *req); int (*set_epcs)(struct wiphy *wiphy, struct net_device *dev, bool val); + int (*start_pd)(struct wiphy *wiphy, struct wireless_dev *wdev); + void (*stop_pd)(struct wiphy *wiphy, struct wireless_dev *wdev); }; /* diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index b1f0e72ec953..55a882535e2b 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -1369,6 +1369,12 @@ * %NL80211_ATTR_INCUMBENT_SIGNAL_INTERFERENCE_BITMAP. The current channel * definition is also sent. * + * @NL80211_CMD_START_PD: Start PD operation, identified by its + * %NL80211_ATTR_WDEV interface. This interface must have been previously + * created with %NL80211_CMD_NEW_INTERFACE. + * @NL80211_CMD_STOP_PD: Stop the PD operation, identified by + * its %NL80211_ATTR_WDEV interface. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1634,6 +1640,9 @@ enum nl80211_commands { NL80211_CMD_INCUMBENT_SIGNAL_DETECT, + NL80211_CMD_START_PD, + NL80211_CMD_STOP_PD, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ diff --git a/net/wireless/core.c b/net/wireless/core.c index 67a603129c42..7bab8c4fb873 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -270,6 +270,25 @@ void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, rdev->opencount--; } +void cfg80211_stop_pd(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + lockdep_assert_held(&rdev->wiphy.mtx); + + if (WARN_ON(wdev->iftype != NL80211_IFTYPE_PD)) + return; + + if (!wdev_running(wdev)) + return; + + cfg80211_pmsr_wdev_down(wdev); + + rdev_stop_pd(rdev, wdev); + wdev->is_running = false; + + rdev->opencount--; +} + void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) { struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); @@ -294,6 +313,9 @@ void cfg80211_shutdown_all_interfaces(struct wiphy *wiphy) case NL80211_IFTYPE_NAN: cfg80211_stop_nan(rdev, wdev); break; + case NL80211_IFTYPE_PD: + cfg80211_stop_pd(rdev, wdev); + break; default: break; } @@ -760,6 +782,9 @@ int wiphy_register(struct wiphy *wiphy) !rdev->ops->add_nan_func || !rdev->ops->del_nan_func || !(wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))))) return -EINVAL; + if (WARN_ON((wiphy->interface_modes & BIT(NL80211_IFTYPE_PD)) && + (!rdev->ops->start_pd || !rdev->ops->stop_pd))) + return -EINVAL; if (WARN_ON(wiphy->interface_modes & BIT(NL80211_IFTYPE_WDS))) return -EINVAL; @@ -1309,6 +1334,9 @@ static void _cfg80211_unregister_wdev(struct wireless_dev *wdev, case NL80211_IFTYPE_NAN: cfg80211_stop_nan(rdev, wdev); break; + case NL80211_IFTYPE_PD: + cfg80211_stop_pd(rdev, wdev); + break; default: break; } @@ -1418,9 +1446,11 @@ void cfg80211_leave(struct cfg80211_registered_device *rdev, case NL80211_IFTYPE_NAN: cfg80211_stop_nan(rdev, wdev); break; + case NL80211_IFTYPE_PD: + cfg80211_stop_pd(rdev, wdev); + break; case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_PD: /* nothing to do */ break; case NL80211_IFTYPE_UNSPECIFIED: diff --git a/net/wireless/core.h b/net/wireless/core.h index 6cace846d7a3..f631b6997988 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -550,6 +550,8 @@ void cfg80211_stop_p2p_device(struct cfg80211_registered_device *rdev, void cfg80211_stop_nan(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev); +void cfg80211_stop_pd(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev); struct cfg80211_internal_bss * cfg80211_bss_update(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 293fdd07ac7a..0ae96063c032 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -16296,6 +16296,46 @@ static int nl80211_nan_change_config(struct sk_buff *skb, return rdev_nan_change_conf(rdev, wdev, &conf, changed); } +static int nl80211_start_pd(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev = info->user_ptr[1]; + int err; + + if (wdev->iftype != NL80211_IFTYPE_PD) + return -EOPNOTSUPP; + + if (wdev_running(wdev)) + return -EEXIST; + + if (rfkill_blocked(rdev->wiphy.rfkill)) + return -ERFKILL; + + if (!rdev->ops->start_pd) + return -EOPNOTSUPP; + + err = rdev_start_pd(rdev, wdev); + if (err) + return err; + wdev->is_running = true; + rdev->opencount++; + + return 0; +} + +static int nl80211_stop_pd(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev = info->user_ptr[1]; + + if (wdev->iftype != NL80211_IFTYPE_PD) + return -EOPNOTSUPP; + + cfg80211_stop_pd(rdev, wdev); + + return 0; +} + void cfg80211_nan_match(struct wireless_dev *wdev, struct cfg80211_nan_match_params *match, gfp_t gfp) { @@ -18977,6 +19017,20 @@ static const struct genl_small_ops nl80211_small_ops[] = { .flags = GENL_ADMIN_PERM, .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP), }, + { + .cmd = NL80211_CMD_START_PD, + .doit = nl80211_start_pd, + .flags = GENL_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV | + NL80211_FLAG_NEED_RTNL), + }, + { + .cmd = NL80211_CMD_STOP_PD, + .doit = nl80211_stop_pd, + .flags = GENL_ADMIN_PERM, + .internal_flags = IFLAGS(NL80211_FLAG_NEED_WDEV_UP | + NL80211_FLAG_NEED_RTNL), + }, { .cmd = NL80211_CMD_SET_MCAST_RATE, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index 3c0fff3cb5ac..921566fa802d 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -1061,6 +1061,25 @@ rdev_nan_change_conf(struct cfg80211_registered_device *rdev, return ret; } +static inline int rdev_start_pd(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + int ret; + + trace_rdev_start_pd(&rdev->wiphy, wdev); + ret = rdev->ops->start_pd(&rdev->wiphy, wdev); + trace_rdev_return_int(&rdev->wiphy, ret); + return ret; +} + +static inline void rdev_stop_pd(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev) +{ + trace_rdev_stop_pd(&rdev->wiphy, wdev); + rdev->ops->stop_pd(&rdev->wiphy, wdev); + trace_rdev_return_void(&rdev->wiphy); +} + static inline int rdev_set_mac_acl(struct cfg80211_registered_device *rdev, struct net_device *dev, struct cfg80211_acl_data *params) diff --git a/net/wireless/trace.h b/net/wireless/trace.h index 56718e250d31..978c019c01b4 100644 --- a/net/wireless/trace.h +++ b/net/wireless/trace.h @@ -2375,6 +2375,26 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_nan, TP_ARGS(wiphy, wdev) ); +TRACE_EVENT(rdev_start_pd, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev), + TP_STRUCT__entry( + WIPHY_ENTRY + WDEV_ENTRY + ), + TP_fast_assign( + WIPHY_ASSIGN; + WDEV_ASSIGN; + ), + TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, + WIPHY_PR_ARG, WDEV_PR_ARG) +); + +DEFINE_EVENT(wiphy_wdev_evt, rdev_stop_pd, + TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev), + TP_ARGS(wiphy, wdev) +); + TRACE_EVENT(rdev_add_nan_func, TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev, const struct cfg80211_nan_func *func), -- 2.34.1