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