diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 159a6b0c3..b6f2f82c5 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -3632,6 +3632,16 @@ struct wpa_driver_ops { */ int (*set_default_scan_ies)(void *priv, const u8 *ies, size_t ies_len); + /** + * set_tdls_mode - Set TDLS trigger mode to the host driver + * @priv: Private driver interface data + * @tdls_external_control: Represents if TDLS external trigger control + * mode is enabled/disabled. + * + * This optional callback can be used to configure the TDLS external + * trigger control mode to the host driver. + */ + int (*set_tdls_mode)(void *priv, int tdls_external_control); }; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 4dc1cecb5..75c4271a5 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -9325,6 +9325,56 @@ static int nl80211_p2p_lo_stop(void *priv) return send_and_recv_msgs(drv, msg, NULL, NULL); } + +static int nl80211_set_tdls_mode(void *priv, int tdls_external_control) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *params; + int ret; + u32 tdls_mode; + + wpa_printf(MSG_DEBUG, + "nl80211: Set TDKS mode: tdls_external_control=%d", + tdls_external_control); + + if (tdls_external_control == 1) + tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL; + else + tdls_mode = QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT; + + if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS)) + goto fail; + + params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!params) + goto fail; + + if (nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE, + tdls_mode)) + goto fail; + + nla_nest_end(msg, params); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; + if (ret) { + wpa_printf(MSG_ERROR, + "nl80211: Set TDLS mode failed: ret=%d (%s)", + ret, strerror(-ret)); + goto fail; + } + return 0; +fail: + nlmsg_free(msg); + return -1; +} + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -9568,6 +9618,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .p2p_lo_start = nl80211_p2p_lo_start, .p2p_lo_stop = nl80211_p2p_lo_stop, .set_default_scan_ies = nl80211_set_default_scan_ies, + .set_tdls_mode = nl80211_set_tdls_mode, #endif /* CONFIG_DRIVER_NL80211_QCA */ .configure_data_frame_filters = nl80211_configure_data_frame_filters, .get_ext_capab = nl80211_get_ext_capab, diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index a929a7d06..a75494374 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -532,6 +532,8 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s, #endif /* CONFIG_MBO */ } else if (os_strcasecmp(cmd, "lci") == 0) { ret = wpas_ctrl_iface_set_lci(wpa_s, value); + } else if (os_strcasecmp(cmd, "tdls_trigger_control") == 0) { + ret = wpa_drv_set_tdls_mode(wpa_s, atoi(value)); } else { value[-1] = '='; ret = wpa_config_process_global(wpa_s->conf, cmd, -1); diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 5d5dcf0b0..f8efddcc9 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -968,4 +968,13 @@ static inline int wpa_drv_set_default_scan_ies(struct wpa_supplicant *wpa_s, return wpa_s->driver->set_default_scan_ies(wpa_s->drv_priv, ies, len); } +static inline int wpa_drv_set_tdls_mode(struct wpa_supplicant *wpa_s, + int tdls_external_control) +{ + if (!wpa_s->driver->set_tdls_mode) + return -1; + return wpa_s->driver->set_tdls_mode(wpa_s->drv_priv, + tdls_external_control); +} + #endif /* DRIVER_I_H */