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 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 34 struct iwl_mld_roc_iter_data { 35 enum iwl_roc_activity activity; 36 struct ieee80211_vif *vif; 37 bool found; 38 }; 39 40 static void iwl_mld_find_roc_vif_iter(void *data, u8 *mac, 41 struct ieee80211_vif *vif) 42 { 43 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 44 struct iwl_mld_roc_iter_data *roc_data = data; 45 46 if (mld_vif->roc_activity != roc_data->activity) 47 return; 48 49 /* The FW supports one ROC of each type simultaneously */ 50 if (WARN_ON(roc_data->found)) { 51 roc_data->vif = NULL; 52 return; 53 } 54 55 roc_data->found = true; 56 roc_data->vif = vif; 57 } 58 59 static struct ieee80211_vif * 60 iwl_mld_find_roc_vif(struct iwl_mld *mld, enum iwl_roc_activity activity) 61 { 62 struct iwl_mld_roc_iter_data roc_data = { 63 .activity = activity, 64 .found = false, 65 }; 66 67 ieee80211_iterate_active_interfaces_mtx(mld->hw, 68 IEEE80211_IFACE_ITER_NORMAL, 69 iwl_mld_find_roc_vif_iter, 70 &roc_data); 71 72 return roc_data.vif; 73 } 74 75 int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 76 struct ieee80211_channel *channel, int duration, 77 enum ieee80211_roc_type type) 78 { 79 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); 80 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 81 struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta; 82 struct iwl_roc_req cmd = { 83 .action = cpu_to_le32(FW_CTXT_ACTION_ADD), 84 }; 85 enum iwl_roc_activity activity; 86 int ret = 0; 87 88 lockdep_assert_wiphy(mld->wiphy); 89 90 if (vif->type != NL80211_IFTYPE_P2P_DEVICE && 91 vif->type != NL80211_IFTYPE_STATION) { 92 IWL_ERR(mld, "NOT SUPPORTED: ROC on vif->type %d\n", 93 vif->type); 94 95 return -EOPNOTSUPP; 96 } 97 98 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { 99 switch (type) { 100 case IEEE80211_ROC_TYPE_NORMAL: 101 activity = ROC_ACTIVITY_P2P_DISC; 102 break; 103 case IEEE80211_ROC_TYPE_MGMT_TX: 104 activity = ROC_ACTIVITY_P2P_NEG; 105 break; 106 default: 107 WARN_ONCE(1, "Got an invalid P2P ROC type\n"); 108 return -EINVAL; 109 } 110 } else { 111 activity = ROC_ACTIVITY_HOTSPOT; 112 } 113 114 /* The FW supports one ROC of each type simultaneously */ 115 if (WARN_ON(iwl_mld_find_roc_vif(mld, activity))) 116 return -EBUSY; 117 118 ieee80211_iterate_active_interfaces_mtx(mld->hw, 119 IEEE80211_IFACE_ITER_NORMAL, 120 iwl_mld_vif_iter_emlsr_block_roc, 121 &ret); 122 if (ret) 123 return ret; 124 125 ret = iwl_mld_add_aux_sta(mld, aux_sta); 126 if (ret) 127 return ret; 128 129 cmd.activity = cpu_to_le32(activity); 130 cmd.sta_id = cpu_to_le32(aux_sta->sta_id); 131 cmd.channel_info.channel = cpu_to_le32(channel->hw_value); 132 cmd.channel_info.band = iwl_mld_nl80211_band_to_fw(channel->band); 133 cmd.channel_info.width = IWL_PHY_CHANNEL_MODE20; 134 cmd.max_delay = cpu_to_le32(AUX_ROC_MAX_DELAY); 135 cmd.duration = cpu_to_le32(MSEC_TO_TU(duration)); 136 137 memcpy(cmd.node_addr, vif->addr, ETH_ALEN); 138 139 ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 140 &cmd); 141 if (ret) { 142 IWL_ERR(mld, "Couldn't send the ROC_CMD\n"); 143 return ret; 144 } 145 146 mld_vif->roc_activity = activity; 147 148 return 0; 149 } 150 151 static void 152 iwl_mld_vif_iter_emlsr_unblock_roc(void *data, u8 *mac, 153 struct ieee80211_vif *vif) 154 { 155 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 156 157 iwl_mld_unblock_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_BLOCKED_ROC); 158 } 159 160 static void iwl_mld_destroy_roc(struct iwl_mld *mld, 161 struct ieee80211_vif *vif, 162 struct iwl_mld_vif *mld_vif) 163 { 164 mld_vif->roc_activity = ROC_NUM_ACTIVITIES; 165 166 ieee80211_iterate_active_interfaces_mtx(mld->hw, 167 IEEE80211_IFACE_ITER_NORMAL, 168 iwl_mld_vif_iter_emlsr_unblock_roc, 169 NULL); 170 171 /* wait until every tx has seen that roc_activity has been reset */ 172 synchronize_net(); 173 /* from here, no new tx will be added 174 * we can flush the Tx on the queues 175 */ 176 177 iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id); 178 179 iwl_mld_remove_aux_sta(mld, vif); 180 } 181 182 int iwl_mld_cancel_roc(struct ieee80211_hw *hw, 183 struct ieee80211_vif *vif) 184 { 185 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); 186 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 187 struct iwl_roc_req cmd = { 188 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), 189 }; 190 int ret; 191 192 lockdep_assert_wiphy(mld->wiphy); 193 194 if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE && 195 vif->type != NL80211_IFTYPE_STATION)) 196 return -EOPNOTSUPP; 197 198 /* No roc activity running it's probably already done */ 199 if (mld_vif->roc_activity == ROC_NUM_ACTIVITIES) 200 return 0; 201 202 cmd.activity = cpu_to_le32(mld_vif->roc_activity); 203 204 ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 205 &cmd); 206 if (ret) 207 IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n"); 208 209 /* We may have raced with the firmware expiring the ROC instance at 210 * this very moment. In that case, we can have a notification in the 211 * async processing queue. However, none can arrive _after_ this as 212 * ROC_CMD was sent synchronously, i.e. we waited for a response and 213 * the firmware cannot refer to this ROC after the response. Thus, 214 * if we just cancel the notification (if there's one) we'll be at a 215 * clean state for any possible next ROC. 216 */ 217 iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_ROC, 218 mld_vif->roc_activity); 219 220 iwl_mld_destroy_roc(mld, vif, mld_vif); 221 222 return 0; 223 } 224 225 void iwl_mld_handle_roc_notif(struct iwl_mld *mld, 226 struct iwl_rx_packet *pkt) 227 { 228 const struct iwl_roc_notif *notif = (void *)pkt->data; 229 u32 activity = le32_to_cpu(notif->activity); 230 struct iwl_mld_vif *mld_vif; 231 struct ieee80211_vif *vif; 232 233 vif = iwl_mld_find_roc_vif(mld, activity); 234 if (WARN_ON(!vif)) 235 return; 236 237 mld_vif = iwl_mld_vif_from_mac80211(vif); 238 /* It is possible that the ROC was canceled 239 * but the notification was already fired. 240 */ 241 if (mld_vif->roc_activity != activity) 242 return; 243 244 if (le32_to_cpu(notif->success) && 245 le32_to_cpu(notif->started)) { 246 /* We had a successful start */ 247 ieee80211_ready_on_channel(mld->hw); 248 } else { 249 /* ROC was not successful, tell the firmware to remove it */ 250 if (le32_to_cpu(notif->started)) 251 iwl_mld_cancel_roc(mld->hw, vif); 252 else 253 iwl_mld_destroy_roc(mld, vif, mld_vif); 254 /* we need to let know mac80211 about end OR 255 * an unsuccessful start 256 */ 257 ieee80211_remain_on_channel_expired(mld->hw); 258 } 259 } 260