1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2024 - 2025 Intel Corporation
4 */
5 #include <net/cfg80211.h>
6 #include <net/mac80211.h>
7
8 #include "mld.h"
9 #include "roc.h"
10 #include "hcmd.h"
11 #include "iface.h"
12 #include "sta.h"
13 #include "mlo.h"
14
15 #include "fw/api/context.h"
16 #include "fw/api/time-event.h"
17
18 #define AUX_ROC_MAX_DELAY MSEC_TO_TU(200)
19
20 static void
iwl_mld_vif_iter_emlsr_block_roc(void * data,u8 * mac,struct ieee80211_vif * vif)21 iwl_mld_vif_iter_emlsr_block_roc(void *data, u8 *mac, struct ieee80211_vif *vif)
22 {
23 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
24 int *result = data;
25 int ret;
26
27 ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
28 IWL_MLD_EMLSR_BLOCKED_ROC,
29 iwl_mld_get_primary_link(vif));
30 if (ret)
31 *result = ret;
32 }
33
iwl_mld_start_roc(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_channel * channel,int duration,enum ieee80211_roc_type type)34 int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
35 struct ieee80211_channel *channel, int duration,
36 enum ieee80211_roc_type type)
37 {
38 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
39 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
40 struct iwl_mld_int_sta *aux_sta;
41 struct iwl_roc_req cmd = {
42 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
43 };
44 u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
45 WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
46 u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
47 enum iwl_roc_activity activity;
48 int ret = 0;
49
50 lockdep_assert_wiphy(mld->wiphy);
51
52 ieee80211_iterate_active_interfaces_mtx(mld->hw,
53 IEEE80211_IFACE_ITER_NORMAL,
54 iwl_mld_vif_iter_emlsr_block_roc,
55 &ret);
56 if (ret)
57 return ret;
58
59 /* TODO: task=Hotspot 2.0 */
60 if (vif->type != NL80211_IFTYPE_P2P_DEVICE) {
61 IWL_ERR(mld, "NOT SUPPORTED: ROC on vif->type %d\n",
62 vif->type);
63
64 return -EOPNOTSUPP;
65 }
66
67 switch (type) {
68 case IEEE80211_ROC_TYPE_NORMAL:
69 activity = ROC_ACTIVITY_P2P_DISC;
70 break;
71 case IEEE80211_ROC_TYPE_MGMT_TX:
72 activity = ROC_ACTIVITY_P2P_NEG;
73 break;
74 default:
75 WARN_ONCE(1, "Got an invalid P2P ROC type\n");
76 return -EINVAL;
77 }
78
79 if (WARN_ON(mld_vif->roc_activity != ROC_NUM_ACTIVITIES))
80 return -EBUSY;
81
82 /* No MLO on P2P device */
83 aux_sta = &mld_vif->deflink.aux_sta;
84
85 ret = iwl_mld_add_aux_sta(mld, aux_sta);
86 if (ret)
87 return ret;
88
89 cmd.activity = cpu_to_le32(activity);
90 cmd.sta_id = cpu_to_le32(aux_sta->sta_id);
91 cmd.channel_info.channel = cpu_to_le32(channel->hw_value);
92 cmd.channel_info.band = iwl_mld_nl80211_band_to_fw(channel->band);
93 cmd.channel_info.width = IWL_PHY_CHANNEL_MODE20;
94 /* TODO: task=Hotspot 2.0, revisit those parameters when we add an ROC
95 * on the BSS vif
96 */
97 cmd.max_delay = cpu_to_le32(AUX_ROC_MAX_DELAY);
98 cmd.duration = cpu_to_le32(MSEC_TO_TU(duration));
99
100 memcpy(cmd.node_addr, vif->addr, ETH_ALEN);
101
102 ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
103 &cmd, cmd_len);
104 if (ret) {
105 IWL_ERR(mld, "Couldn't send the ROC_CMD\n");
106 return ret;
107 }
108 mld_vif->roc_activity = activity;
109
110 return 0;
111 }
112
113 static void
iwl_mld_vif_iter_emlsr_unblock_roc(void * data,u8 * mac,struct ieee80211_vif * vif)114 iwl_mld_vif_iter_emlsr_unblock_roc(void *data, u8 *mac,
115 struct ieee80211_vif *vif)
116 {
117 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
118
119 iwl_mld_unblock_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_BLOCKED_ROC);
120 }
121
iwl_mld_destroy_roc(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mld_vif * mld_vif)122 static void iwl_mld_destroy_roc(struct iwl_mld *mld,
123 struct ieee80211_vif *vif,
124 struct iwl_mld_vif *mld_vif)
125 {
126 mld_vif->roc_activity = ROC_NUM_ACTIVITIES;
127
128 ieee80211_iterate_active_interfaces_mtx(mld->hw,
129 IEEE80211_IFACE_ITER_NORMAL,
130 iwl_mld_vif_iter_emlsr_unblock_roc,
131 NULL);
132
133 /* wait until every tx has seen that roc_activity has been reset */
134 synchronize_net();
135 /* from here, no new tx will be added
136 * we can flush the Tx on the queues
137 */
138
139 iwl_mld_flush_link_sta_txqs(mld, mld_vif->deflink.aux_sta.sta_id);
140
141 iwl_mld_remove_aux_sta(mld, vif, &vif->bss_conf);
142 }
143
iwl_mld_cancel_roc(struct ieee80211_hw * hw,struct ieee80211_vif * vif)144 int iwl_mld_cancel_roc(struct ieee80211_hw *hw,
145 struct ieee80211_vif *vif)
146 {
147 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
148 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
149 struct iwl_roc_req cmd = {
150 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
151 };
152 u8 ver = iwl_fw_lookup_cmd_ver(mld->fw,
153 WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
154 u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd);
155 int ret;
156
157 lockdep_assert_wiphy(mld->wiphy);
158
159 /* TODO: task=Hotspot 2.0 */
160 if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE))
161 return -EOPNOTSUPP;
162
163 /* No roc activity running it's probably already done */
164 if (mld_vif->roc_activity == ROC_NUM_ACTIVITIES)
165 return 0;
166
167 cmd.activity = cpu_to_le32(mld_vif->roc_activity);
168
169 ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD),
170 &cmd, cmd_len);
171 if (ret)
172 IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n");
173
174 /* We may have raced with the firmware expiring the ROC instance at
175 * this very moment. In that case, we can have a notification in the
176 * async processing queue. However, none can arrive _after_ this as
177 * ROC_CMD was sent synchronously, i.e. we waited for a response and
178 * the firmware cannot refer to this ROC after the response. Thus,
179 * if we just cancel the notification (if there's one) we'll be at a
180 * clean state for any possible next ROC.
181 */
182 iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_ROC,
183 mld_vif->roc_activity);
184
185 iwl_mld_destroy_roc(mld, vif, mld_vif);
186
187 return 0;
188 }
189
iwl_mld_handle_roc_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)190 void iwl_mld_handle_roc_notif(struct iwl_mld *mld,
191 struct iwl_rx_packet *pkt)
192 {
193 const struct iwl_roc_notif *notif = (void *)pkt->data;
194 u32 activity = le32_to_cpu(notif->activity);
195 /* TODO: task=Hotspot 2.0 - roc can run on BSS */
196 struct ieee80211_vif *vif = mld->p2p_device_vif;
197 struct iwl_mld_vif *mld_vif;
198
199 if (WARN_ON(!vif))
200 return;
201
202 mld_vif = iwl_mld_vif_from_mac80211(vif);
203 /* It is possible that the ROC was canceled
204 * but the notification was already fired.
205 */
206 if (mld_vif->roc_activity != activity)
207 return;
208
209 if (le32_to_cpu(notif->success) &&
210 le32_to_cpu(notif->started)) {
211 /* We had a successful start */
212 ieee80211_ready_on_channel(mld->hw);
213 } else {
214 /* ROC was not successful, tell the firmware to remove it */
215 if (le32_to_cpu(notif->started))
216 iwl_mld_cancel_roc(mld->hw, vif);
217 else
218 iwl_mld_destroy_roc(mld, vif, mld_vif);
219 /* we need to let know mac80211 about end OR
220 * an unsuccessful start
221 */
222 ieee80211_remain_on_channel_expired(mld->hw);
223 }
224 }
225