File Index
Files and directories
Sign in
FILE

session-protect.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mld/session-protect.c C
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2024 Intel Corporation
  4 */
  5#include "session-protect.h"
  6#include "fw/api/time-event.h"
  7#include "fw/api/context.h"
  8#include "iface.h"
  9#include <net/mac80211.h>
 10
 11void iwl_mld_handle_session_prot_notif(struct iwl_mld *mld,
 12				       struct iwl_rx_packet *pkt)
 13{
 14	struct iwl_session_prot_notif *notif = (void *)pkt->data;
 15	int fw_link_id = le32_to_cpu(notif->mac_link_id);
 16	struct ieee80211_bss_conf *link_conf =
 17		iwl_mld_fw_id_to_link_conf(mld, fw_link_id);
 18	struct ieee80211_vif *vif;
 19	struct iwl_mld_vif *mld_vif;
 20	struct iwl_mld_session_protect *session_protect;
 21
 22	if (WARN_ON(!link_conf))
 23		return;
 24
 25	vif = link_conf->vif;
 26	mld_vif = iwl_mld_vif_from_mac80211(vif);
 27	session_protect = &mld_vif->session_protect;
 28
 29	if (!le32_to_cpu(notif->status)) {
 30		memset(session_protect, 0, sizeof(*session_protect));
 31	} else if (le32_to_cpu(notif->start)) {
 32		/* End_jiffies indicates an active session */
 33		session_protect->session_requested = false;
 34		session_protect->end_jiffies =
 35			TU_TO_EXP_TIME(session_protect->duration);
 36		/* !session_protect->end_jiffies means inactive session */
 37		if (!session_protect->end_jiffies)
 38			session_protect->end_jiffies = 1;
 39	} else {
 40		memset(session_protect, 0, sizeof(*session_protect));
 41	}
 42}
 43
 44static int _iwl_mld_schedule_session_protection(struct iwl_mld *mld,
 45						struct ieee80211_vif *vif,
 46						u32 duration, u32 min_duration,
 47						int link_id)
 48{
 49	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
 50	struct iwl_mld_link *link =
 51		iwl_mld_link_dereference_check(mld_vif, link_id);
 52	struct iwl_mld_session_protect *session_protect =
 53		&mld_vif->session_protect;
 54	struct iwl_session_prot_cmd cmd = {
 55		.id_and_color = cpu_to_le32(link->fw_id),
 56		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
 57		.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),
 58		.duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
 59	};
 60	int ret;
 61
 62	lockdep_assert_wiphy(mld->wiphy);
 63
 64	WARN(hweight16(vif->active_links) > 1,
 65	     "Session protection isn't allowed with more than one active link");
 66
 67	if (session_protect->end_jiffies &&
 68	    time_after(session_protect->end_jiffies,
 69		       TU_TO_EXP_TIME(min_duration))) {
 70		IWL_DEBUG_TE(mld, "We have ample in the current session: %u\n",
 71			     jiffies_to_msecs(session_protect->end_jiffies -
 72					      jiffies));
 73		return -EALREADY;
 74	}
 75
 76	IWL_DEBUG_TE(mld, "Add a new session protection, duration %d TU\n",
 77		     le32_to_cpu(cmd.duration_tu));
 78
 79	ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP,
 80						SESSION_PROTECTION_CMD), &cmd);
 81
 82	if (ret)
 83		return ret;
 84
 85	/* end_jiffies will be updated when handling session_prot_notif */
 86	session_protect->end_jiffies = 0;
 87	session_protect->duration = duration;
 88	session_protect->session_requested = true;
 89
 90	return 0;
 91}
 92
 93void iwl_mld_schedule_session_protection(struct iwl_mld *mld,
 94					 struct ieee80211_vif *vif,
 95					 u32 duration, u32 min_duration,
 96					 int link_id)
 97{
 98	int ret;
 99
100	ret = _iwl_mld_schedule_session_protection(mld, vif, duration,
101						   min_duration, link_id);
102	if (ret && ret != -EALREADY)
103		IWL_ERR(mld,
104			"Couldn't send the SESSION_PROTECTION_CMD (%d)\n",
105			ret);
106}
107
108struct iwl_mld_session_start_data {
109	struct iwl_mld *mld;
110	struct ieee80211_bss_conf *link_conf;
111	bool success;
112};
113
114static bool iwl_mld_session_start_fn(struct iwl_notif_wait_data *notif_wait,
115				     struct iwl_rx_packet *pkt, void *_data)
116{
117	struct iwl_session_prot_notif *notif = (void *)pkt->data;
118	unsigned int pkt_len = iwl_rx_packet_payload_len(pkt);
119	struct iwl_mld_session_start_data *data = _data;
120	struct ieee80211_bss_conf *link_conf;
121	struct iwl_mld *mld = data->mld;
122	int fw_link_id;
123
124	if (IWL_FW_CHECK(mld, pkt_len < sizeof(*notif),
125			 "short session prot notif (%d)\n",
126			 pkt_len))
127		return false;
128
129	fw_link_id = le32_to_cpu(notif->mac_link_id);
130	link_conf = iwl_mld_fw_id_to_link_conf(mld, fw_link_id);
131
132	if (link_conf != data->link_conf)
133		return false;
134
135	if (!le32_to_cpu(notif->status))
136		return true;
137
138	if (notif->start) {
139		data->success = true;
140		return true;
141	}
142
143	return false;
144}
145
146int iwl_mld_start_session_protection(struct iwl_mld *mld,
147				     struct ieee80211_vif *vif,
148				     u32 duration, u32 min_duration,
149				     int link_id, unsigned long timeout)
150{
151	static const u16 start_notif[] = { SESSION_PROTECTION_NOTIF };
152	struct iwl_notification_wait start_wait;
153	struct iwl_mld_session_start_data data = {
154		.mld = mld,
155		.link_conf = wiphy_dereference(mld->wiphy,
156					       vif->link_conf[link_id]),
157	};
158	int ret;
159
160	if (WARN_ON(!data.link_conf))
161		return -EINVAL;
162
163	iwl_init_notification_wait(&mld->notif_wait, &start_wait,
164				   start_notif, ARRAY_SIZE(start_notif),
165				   iwl_mld_session_start_fn, &data);
166
167	ret = _iwl_mld_schedule_session_protection(mld, vif, duration,
168						   min_duration, link_id);
169
170	if (ret) {
171		iwl_remove_notification(&mld->notif_wait, &start_wait);
172		return ret == -EALREADY ? 0 : ret;
173	}
174
175	ret = iwl_wait_notification(&mld->notif_wait, &start_wait, timeout);
176	if (ret)
177		return ret;
178	return data.success ? 0 : -EIO;
179}
180
181int iwl_mld_cancel_session_protection(struct iwl_mld *mld,
182				      struct ieee80211_vif *vif,
183				      int link_id)
184{
185	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
186	struct iwl_mld_link *link =
187		iwl_mld_link_dereference_check(mld_vif, link_id);
188	struct iwl_mld_session_protect *session_protect =
189		&mld_vif->session_protect;
190	struct iwl_session_prot_cmd cmd = {
191		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
192		.conf_id = cpu_to_le32(SESSION_PROTECT_CONF_ASSOC),
193	};
194	int ret;
195
196	lockdep_assert_wiphy(mld->wiphy);
197
198	/* If there isn't an active session or a requested one for this
199	 * link do nothing
200	 */
201	if (!session_protect->session_requested &&
202	    !session_protect->end_jiffies)
203		return 0;
204
205	if (WARN_ON(!link))
206		return -EINVAL;
207
208	cmd.id_and_color = cpu_to_le32(link->fw_id);
209
210	ret = iwl_mld_send_cmd_pdu(mld,
211				   WIDE_ID(MAC_CONF_GROUP,
212					   SESSION_PROTECTION_CMD), &cmd);
213	if (ret) {
214		IWL_ERR(mld,
215			"Couldn't send the SESSION_PROTECTION_CMD\n");
216		return ret;
217	}
218
219	memset(session_protect, 0, sizeof(*session_protect));
220
221	return 0;
222}
~/ Read-only file preview.