wil6210: off channel transmit management frames in AP mode
Currently wil6210 ignores the channel field in the cfg80211_mgmt_tx_params struct for wil_cfg80211_ops mgmt_tx operation and sends all management frames on the serving channel. Add support for off-channel transmission of management frames (WIPHY_FLAG_OFFCHAN_TX) in AP mode. This is useful in enterprise APs for sending custom probe request frames. Signed-off-by: Ahmad Masri <amasri@codeaurora.org> Signed-off-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
This commit is contained in:
parent
6a363e8aa3
commit
b698e2dfc2
@ -1090,18 +1090,51 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
int rc;
|
||||
bool tx_status;
|
||||
|
||||
/* Note, currently we do not support the "wait" parameter, user-space
|
||||
* must call remain_on_channel before mgmt_tx or listen on a channel
|
||||
* another way (AP/PCP or connected station)
|
||||
* in addition we need to check if specified "chan" argument is
|
||||
* different from currently "listened" channel and fail if it is.
|
||||
wil_dbg_misc(wil, "mgmt_tx: channel %d offchan %d, wait %d\n",
|
||||
params->chan ? params->chan->hw_value : -1,
|
||||
params->offchan,
|
||||
params->wait);
|
||||
|
||||
/* Note, currently we support the "wait" parameter only on AP mode.
|
||||
* In other modes, user-space must call remain_on_channel before
|
||||
* mgmt_tx or listen on a channel other than active one.
|
||||
*/
|
||||
|
||||
rc = wmi_mgmt_tx(vif, buf, len);
|
||||
tx_status = (rc == 0);
|
||||
if (params->chan && params->chan->hw_value == 0) {
|
||||
wil_err(wil, "invalid channel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wdev->iftype != NL80211_IFTYPE_AP) {
|
||||
wil_dbg_misc(wil,
|
||||
"send WMI_SW_TX_REQ_CMDID on non-AP interfaces\n");
|
||||
rc = wmi_mgmt_tx(vif, buf, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!params->chan || params->chan->hw_value == vif->channel) {
|
||||
wil_dbg_misc(wil,
|
||||
"send WMI_SW_TX_REQ_CMDID for on-channel\n");
|
||||
rc = wmi_mgmt_tx(vif, buf, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (params->offchan == 0) {
|
||||
wil_err(wil,
|
||||
"invalid channel params: current %d requested %d, off-channel not allowed\n",
|
||||
vif->channel, params->chan->hw_value);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* use the wmi_mgmt_tx_ext only on AP mode and off-channel */
|
||||
rc = wmi_mgmt_tx_ext(vif, buf, len, params->chan->hw_value,
|
||||
params->wait);
|
||||
|
||||
out:
|
||||
tx_status = (rc == 0);
|
||||
cfg80211_mgmt_tx_status(wdev, cookie ? *cookie : 0, buf, len,
|
||||
tx_status, GFP_KERNEL);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1130,6 +1130,9 @@ void wil_refresh_fw_capabilities(struct wil6210_priv *wil)
|
||||
wiphy->max_sched_scan_plans = WMI_MAX_PLANS_NUM;
|
||||
}
|
||||
|
||||
if (test_bit(WMI_FW_CAPABILITY_TX_REQ_EXT, wil->fw_capabilities))
|
||||
wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX;
|
||||
|
||||
if (wil->platform_ops.set_features) {
|
||||
features = (test_bit(WMI_FW_CAPABILITY_REF_CLOCK_CONTROL,
|
||||
wil->fw_capabilities) &&
|
||||
|
@ -1350,6 +1350,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil,
|
||||
struct cfg80211_sched_scan_request *request);
|
||||
int wmi_stop_sched_scan(struct wil6210_priv *wil);
|
||||
int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len);
|
||||
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
|
||||
u8 channel, u16 duration_ms);
|
||||
|
||||
int reverse_memcmp(const void *cs, const void *ct, size_t count);
|
||||
|
||||
|
@ -466,6 +466,8 @@ static const char *cmdid2name(u16 cmdid)
|
||||
return "WMI_CFG_DEF_RX_OFFLOAD_CMD";
|
||||
case WMI_LINK_STATS_CMDID:
|
||||
return "WMI_LINK_STATS_CMD";
|
||||
case WMI_SW_TX_REQ_EXT_CMDID:
|
||||
return "WMI_SW_TX_REQ_EXT_CMDID";
|
||||
default:
|
||||
return "Untracked CMD";
|
||||
}
|
||||
@ -3114,6 +3116,60 @@ int wmi_mgmt_tx(struct wil6210_vif *vif, const u8 *buf, size_t len)
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wmi_mgmt_tx_ext(struct wil6210_vif *vif, const u8 *buf, size_t len,
|
||||
u8 channel, u16 duration_ms)
|
||||
{
|
||||
size_t total;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct ieee80211_mgmt *mgmt_frame = (void *)buf;
|
||||
struct wmi_sw_tx_req_ext_cmd *cmd;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_sw_tx_complete_event evt;
|
||||
} __packed evt = {
|
||||
.evt = {.status = WMI_FW_STATUS_FAILURE},
|
||||
};
|
||||
int rc;
|
||||
|
||||
wil_dbg_wmi(wil, "mgmt_tx_ext mid %d channel %d duration %d\n",
|
||||
vif->mid, channel, duration_ms);
|
||||
wil_hex_dump_wmi("mgmt_tx_ext frame ", DUMP_PREFIX_OFFSET, 16, 1, buf,
|
||||
len, true);
|
||||
|
||||
if (len < sizeof(struct ieee80211_hdr_3addr)) {
|
||||
wil_err(wil, "short frame. len %zu\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
total = sizeof(*cmd) + len;
|
||||
if (total < len) {
|
||||
wil_err(wil, "mgmt_tx_ext invalid len %zu\n", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd = kzalloc(total, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(cmd->dst_mac, mgmt_frame->da, WMI_MAC_LEN);
|
||||
cmd->len = cpu_to_le16(len);
|
||||
memcpy(cmd->payload, buf, len);
|
||||
cmd->channel = channel - 1;
|
||||
cmd->duration_ms = cpu_to_le16(duration_ms);
|
||||
|
||||
rc = wmi_call(wil, WMI_SW_TX_REQ_EXT_CMDID, vif->mid, cmd, total,
|
||||
WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
|
||||
if (!rc && evt.evt.status != WMI_FW_STATUS_SUCCESS) {
|
||||
wil_err(wil, "mgmt_tx_ext failed with status %d\n",
|
||||
evt.evt.status);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_wmi_tx_sring_cfg(struct wil6210_priv *wil, int ring_id)
|
||||
{
|
||||
int rc;
|
||||
|
Loading…
Reference in New Issue
Block a user