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