diff options
Diffstat (limited to 'sys/contrib/dev/iwlwifi/mld/session-protect.c')
| -rw-r--r-- | sys/contrib/dev/iwlwifi/mld/session-protect.c | 222 | 
1 files changed, 222 insertions, 0 deletions
| diff --git a/sys/contrib/dev/iwlwifi/mld/session-protect.c b/sys/contrib/dev/iwlwifi/mld/session-protect.c new file mode 100644 index 000000000000..dbb5615dc3f6 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/mld/session-protect.c @@ -0,0 +1,222 @@ +// 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; +} | 
