mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-21 06:50:25 +00:00
223 lines
6 KiB
C
223 lines
6 KiB
C
![]() |
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||
|
/*
|
||
|
* Copyright (C) 2024 Intel Corporation
|
||
|
*/
|
||
|
#include "session-protect.h"
|
||
|
#include "fw/api/time-event.h"
|
||
|
#include "fw/api/context.h"
|
||
|
#include "iface.h"
|
||
|
#include <net/mac80211.h>
|
||
|
|
||
|
void iwl_mld_handle_session_prot_notif(struct iwl_mld *mld,
|
||
|
struct iwl_rx_packet *pkt)
|
||
|
{
|
||
|
struct iwl_session_prot_notif *notif = (void *)pkt->data;
|
||
|
int fw_link_id = le32_to_cpu(notif->mac_link_id);
|
||
|
struct ieee80211_bss_conf *link_conf =
|
||
|
iwl_mld_fw_id_to_link_conf(mld, fw_link_id);
|
||
|
struct ieee80211_vif *vif;
|
||
|
struct iwl_mld_vif *mld_vif;
|
||
|
struct iwl_mld_session_protect *session_protect;
|
||
|
|
||
|
if (WARN_ON(!link_conf))
|
||
|
return;
|
||
|
|
||
|
vif = link_conf->vif;
|
||
|
mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||
|
session_protect = &mld_vif->session_protect;
|
||
|
|
||
|
if (!le32_to_cpu(notif->status)) {
|
||
|
memset(session_protect, 0, sizeof(*session_protect));
|
||
|
} else if (le32_to_cpu(notif->start)) {
|
||
|
/* End_jiffies indicates an active session */
|
||
|
session_protect->session_requested = false;
|
||
|
session_protect->end_jiffies =
|
||
|
TU_TO_EXP_TIME(session_protect->duration);
|
||
|
/* !session_protect->end_jiffies means inactive session */
|
||
|
if (!session_protect->end_jiffies)
|
||
|
session_protect->end_jiffies = 1;
|
||
|
} else {
|
||
|
memset(session_protect, 0, sizeof(*session_protect));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int _iwl_mld_schedule_session_protection(struct iwl_mld *mld,
|
||
|
struct ieee80211_vif *vif,
|
||
|
u32 duration, u32 min_duration,
|
||
|
int link_id)
|
||
|
{
|
||
|
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||
|
struct iwl_mld_link *link =
|
||
|
iwl_mld_link_dereference_check(mld_vif, link_id);
|
||
|
struct iwl_mld_session_protect *session_protect =
|
||
|
&mld_vif->session_protect;
|
||
|
struct iwl_session_prot_cmd cmd = {
|
||
|
.id_and_color = cpu_to_le32(link->fw_id),
|
||
|
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
||
|
.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),
|
||
|
.duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
|
||
|
};
|
||
|
int ret;
|
||
|
|
||
|
lockdep_assert_wiphy(mld->wiphy);
|
||
|
|
||
|
WARN(hweight16(vif->active_links) > 1,
|
||
|
"Session protection isn't allowed with more than one active link");
|
||
|
|
||
|
if (session_protect->end_jiffies &&
|
||
|
time_after(session_protect->end_jiffies,
|
||
|
TU_TO_EXP_TIME(min_duration))) {
|
||
|
IWL_DEBUG_TE(mld, "We have ample in the current session: %u\n",
|
||
|
jiffies_to_msecs(session_protect->end_jiffies -
|
||
|
jiffies));
|
||
|
return -EALREADY;
|
||
|
}
|
||
|
|
||
|
IWL_DEBUG_TE(mld, "Add a new session protection, duration %d TU\n",
|
||
|
le32_to_cpu(cmd.duration_tu));
|
||
|
|
||
|
ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP,
|
||
|
SESSION_PROTECTION_CMD), &cmd);
|
||
|
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
/* end_jiffies will be updated when handling session_prot_notif */
|
||
|
session_protect->end_jiffies = 0;
|
||
|
session_protect->duration = duration;
|
||
|
session_protect->session_requested = true;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void iwl_mld_schedule_session_protection(struct iwl_mld *mld,
|
||
|
struct ieee80211_vif *vif,
|
||
|
u32 duration, u32 min_duration,
|
||
|
int link_id)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
ret = _iwl_mld_schedule_session_protection(mld, vif, duration,
|
||
|
min_duration, link_id);
|
||
|
if (ret && ret != -EALREADY)
|
||
|
IWL_ERR(mld,
|
||
|
"Couldn't send the SESSION_PROTECTION_CMD (%d)\n",
|
||
|
ret);
|
||
|
}
|
||
|
|
||
|
struct iwl_mld_session_start_data {
|
||
|
struct iwl_mld *mld;
|
||
|
struct ieee80211_bss_conf *link_conf;
|
||
|
bool success;
|
||
|
};
|
||
|
|
||
|
static bool iwl_mld_session_start_fn(struct iwl_notif_wait_data *notif_wait,
|
||
|
struct iwl_rx_packet *pkt, void *_data)
|
||
|
{
|
||
|
struct iwl_session_prot_notif *notif = (void *)pkt->data;
|
||
|
unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
|
||
|
struct iwl_mld_session_start_data *data = _data;
|
||
|
struct ieee80211_bss_conf *link_conf;
|
||
|
struct iwl_mld *mld = data->mld;
|
||
|
int fw_link_id;
|
||
|
|
||
|
if (IWL_FW_CHECK(mld, pkt_len < sizeof(*notif),
|
||
|
"short session prot notif (%d)\n",
|
||
|
pkt_len))
|
||
|
return false;
|
||
|
|
||
|
fw_link_id = le32_to_cpu(notif->mac_link_id);
|
||
|
link_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id);
|
||
|
|
||
|
if (link_conf != data->link_conf)
|
||
|
return false;
|
||
|
|
||
|
if (!le32_to_cpu(notif->status))
|
||
|
return true;
|
||
|
|
||
|
if (notif->start) {
|
||
|
data->success = true;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int iwl_mld_start_session_protection(struct iwl_mld *mld,
|
||
|
struct ieee80211_vif *vif,
|
||
|
u32 duration, u32 min_duration,
|
||
|
int link_id, unsigned long timeout)
|
||
|
{
|
||
|
static const u16 start_notif[] = { SESSION_PROTECTION_NOTIF };
|
||
|
struct iwl_notification_wait start_wait;
|
||
|
struct iwl_mld_session_start_data data = {
|
||
|
.mld = mld,
|
||
|
.link_conf = wiphy_dereference(mld->wiphy,
|
||
|
vif->link_conf[link_id]),
|
||
|
};
|
||
|
int ret;
|
||
|
|
||
|
if (WARN_ON(!data.link_conf))
|
||
|
return -EINVAL;
|
||
|
|
||
|
iwl_init_notification_wait(&mld->notif_wait, &start_wait,
|
||
|
start_notif, ARRAY_SIZE(start_notif),
|
||
|
iwl_mld_session_start_fn, &data);
|
||
|
|
||
|
ret = _iwl_mld_schedule_session_protection(mld, vif, duration,
|
||
|
min_duration, link_id);
|
||
|
|
||
|
if (ret) {
|
||
|
iwl_remove_notification(&mld->notif_wait, &start_wait);
|
||
|
return ret == -EALREADY ? 0 : ret;
|
||
|
}
|
||
|
|
||
|
ret = iwl_wait_notification(&mld->notif_wait, &start_wait, timeout);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
return data.success ? 0 : -EIO;
|
||
|
}
|
||
|
|
||
|
int iwl_mld_cancel_session_protection(struct iwl_mld *mld,
|
||
|
struct ieee80211_vif *vif,
|
||
|
int link_id)
|
||
|
{
|
||
|
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||
|
struct iwl_mld_link *link =
|
||
|
iwl_mld_link_dereference_check(mld_vif, link_id);
|
||
|
struct iwl_mld_session_protect *session_protect =
|
||
|
&mld_vif->session_protect;
|
||
|
struct iwl_session_prot_cmd cmd = {
|
||
|
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
|
||
|
.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),
|
||
|
};
|
||
|
int ret;
|
||
|
|
||
|
lockdep_assert_wiphy(mld->wiphy);
|
||
|
|
||
|
/* If there isn't an active session or a requested one for this
|
||
|
* link do nothing
|
||
|
*/
|
||
|
if (!session_protect->session_requested &&
|
||
|
!session_protect->end_jiffies)
|
||
|
return 0;
|
||
|
|
||
|
if (WARN_ON(!link))
|
||
|
return -EINVAL;
|
||
|
|
||
|
cmd.id_and_color = cpu_to_le32(link->fw_id);
|
||
|
|
||
|
ret = iwl_mld_send_cmd_pdu(mld,
|
||
|
WIDE_ID(MAC_CONF_GROUP,
|
||
|
SESSION_PROTECTION_CMD), &cmd);
|
||
|
if (ret) {
|
||
|
IWL_ERR(mld,
|
||
|
"Couldn't send the SESSION_PROTECTION_CMD\n");
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
memset(session_protect, 0, sizeof(*session_protect));
|
||
|
|
||
|
return 0;
|
||
|
}
|