Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

wifi: wfx: allow to send frames during ROC

Until now, all the traffic was blocked during scan operation. However,
scan operation is going to be used to implement Remain On Channel (ROC).
In this case, special frames (marked with IEEE80211_TX_CTL_TX_OFFCHAN)
must be sent during the operation.

These frames need to be sent on the virtual interface #2. Until now,
this interface was only used by the device for internal purpose. But
since API 3.9, it can be used to send data during scan operation (we
hijack the scan process to implement ROC).

Thus, we need to change a bit the way we match the frames with the
interface.

Fortunately, the frames received during the scan are marked with the
correct interface number. So there is no change to do on this part.

Signed-off-by: Jérôme Pouiller <jerome.pouiller@silabs.com>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20231004172843.195332-8-jerome.pouiller@silabs.com

authored by

Jérôme Pouiller and committed by
Kalle Valo
f7385a20 04106ec5

+62 -15
+28 -8
drivers/net/wireless/silabs/wfx/data_tx.c
··· 226 226 return req; 227 227 } 228 228 229 + struct wfx_vif *wfx_skb_wvif(struct wfx_dev *wdev, struct sk_buff *skb) 230 + { 231 + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); 232 + struct wfx_hif_msg *hif = (struct wfx_hif_msg *)skb->data; 233 + 234 + if (tx_priv->vif_id != hif->interface && hif->interface != 2) { 235 + dev_err(wdev->dev, "corrupted skb"); 236 + return wdev_to_wvif(wdev, hif->interface); 237 + } 238 + return wdev_to_wvif(wdev, tx_priv->vif_id); 239 + } 240 + 229 241 static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, 230 242 struct ieee80211_hdr *hdr) 231 243 { ··· 364 352 /* Fill tx_priv */ 365 353 tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data; 366 354 tx_priv->icv_size = wfx_tx_get_icv_len(hw_key); 355 + tx_priv->vif_id = wvif->id; 367 356 368 357 /* Fill hif_msg */ 369 358 WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); ··· 375 362 hif_msg = (struct wfx_hif_msg *)skb->data; 376 363 hif_msg->len = cpu_to_le16(skb->len); 377 364 hif_msg->id = HIF_REQ_ID_TX; 378 - hif_msg->interface = wvif->id; 365 + if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) 366 + hif_msg->interface = 2; 367 + else 368 + hif_msg->interface = wvif->id; 379 369 if (skb->len > le16_to_cpu(wvif->wdev->hw_caps.size_inp_ch_buf)) { 380 370 dev_warn(wvif->wdev->dev, 381 371 "requested frame size (%d) is larger than maximum supported (%d)\n", ··· 399 383 req->fc_offset = offset; 400 384 /* Queue index are inverted between firmware and Linux */ 401 385 req->queue_id = 3 - queue_id; 402 - req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); 403 - req->retry_policy_index = wfx_tx_get_retry_policy_id(wvif, tx_info); 404 - req->frame_format = wfx_tx_get_frame_format(tx_info); 386 + if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 387 + req->peer_sta_id = HIF_LINK_ID_NOT_ASSOCIATED; 388 + req->retry_policy_index = HIF_TX_RETRY_POLICY_INVALID; 389 + req->frame_format = HIF_FRAME_FORMAT_NON_HT; 390 + } else { 391 + req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); 392 + req->retry_policy_index = wfx_tx_get_retry_policy_id(wvif, tx_info); 393 + req->frame_format = wfx_tx_get_frame_format(tx_info); 394 + } 405 395 if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI) 406 396 req->short_gi = 1; 407 397 if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ··· 523 501 } 524 502 tx_info = IEEE80211_SKB_CB(skb); 525 503 tx_priv = wfx_skb_tx_priv(skb); 526 - wvif = wdev_to_wvif(wdev, ((struct wfx_hif_msg *)skb->data)->interface); 504 + wvif = wfx_skb_wvif(wdev, skb); 527 505 WARN_ON(!wvif); 528 506 if (!wvif) 529 507 return; ··· 585 563 struct wfx_dev *wdev = hw->priv; 586 564 struct sk_buff_head dropped; 587 565 struct wfx_vif *wvif; 588 - struct wfx_hif_msg *hif; 589 566 struct sk_buff *skb; 590 567 591 568 skb_queue_head_init(&dropped); ··· 600 579 if (wdev->chip_frozen) 601 580 wfx_pending_drop(wdev, &dropped); 602 581 while ((skb = skb_dequeue(&dropped)) != NULL) { 603 - hif = (struct wfx_hif_msg *)skb->data; 604 - wvif = wdev_to_wvif(wdev, hif->interface); 582 + wvif = wfx_skb_wvif(wdev, skb); 605 583 ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); 606 584 wfx_skb_dtor(wvif, skb); 607 585 }
+2
drivers/net/wireless/silabs/wfx/data_tx.h
··· 36 36 struct wfx_tx_priv { 37 37 ktime_t xmit_timestamp; 38 38 unsigned char icv_size; 39 + unsigned char vif_id; 39 40 }; 40 41 41 42 void wfx_tx_policy_init(struct wfx_vif *wvif); ··· 48 47 49 48 struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb); 50 49 struct wfx_hif_req_tx *wfx_skb_txreq(struct sk_buff *skb); 50 + struct wfx_vif *wfx_skb_wvif(struct wfx_dev *wdev, struct sk_buff *skb); 51 51 52 52 #endif
+31 -7
drivers/net/wireless/silabs/wfx/queue.c
··· 68 68 for (i = 0; i < IEEE80211_NUM_ACS; ++i) { 69 69 skb_queue_head_init(&wvif->tx_queue[i].normal); 70 70 skb_queue_head_init(&wvif->tx_queue[i].cab); 71 + skb_queue_head_init(&wvif->tx_queue[i].offchan); 71 72 wvif->tx_queue[i].priority = priorities[i]; 72 73 } 73 74 } 74 75 75 76 bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue) 76 77 { 77 - return skb_queue_empty_lockless(&queue->normal) && skb_queue_empty_lockless(&queue->cab); 78 + return skb_queue_empty_lockless(&queue->normal) && 79 + skb_queue_empty_lockless(&queue->cab) && 80 + skb_queue_empty_lockless(&queue->offchan); 78 81 } 79 82 80 83 void wfx_tx_queues_check_empty(struct wfx_vif *wvif) ··· 106 103 void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, 107 104 struct sk_buff_head *dropped) 108 105 { 109 - __wfx_tx_queue_drop(wvif, &queue->cab, dropped); 110 106 __wfx_tx_queue_drop(wvif, &queue->normal, dropped); 107 + __wfx_tx_queue_drop(wvif, &queue->cab, dropped); 108 + __wfx_tx_queue_drop(wvif, &queue->offchan, dropped); 111 109 wake_up(&wvif->wdev->tx_dequeue); 112 110 } 113 111 ··· 117 113 struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; 118 114 struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 119 115 120 - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) 116 + if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) 117 + skb_queue_tail(&queue->offchan, skb); 118 + else if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) 121 119 skb_queue_tail(&queue->cab, skb); 122 120 else 123 121 skb_queue_tail(&queue->normal, skb); ··· 129 123 { 130 124 struct wfx_queue *queue; 131 125 struct wfx_vif *wvif; 132 - struct wfx_hif_msg *hif; 133 126 struct sk_buff *skb; 134 127 135 128 WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device", __func__); 136 129 while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) { 137 - hif = (struct wfx_hif_msg *)skb->data; 138 - wvif = wdev_to_wvif(wdev, hif->interface); 130 + wvif = wfx_skb_wvif(wdev, skb); 139 131 if (wvif) { 140 132 queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; 141 133 WARN_ON(skb_get_queue_mapping(skb) > 3); ··· 159 155 if (req->packet_id != packet_id) 160 156 continue; 161 157 spin_unlock_bh(&wdev->tx_pending.lock); 162 - wvif = wdev_to_wvif(wdev, hif->interface); 158 + wvif = wfx_skb_wvif(wdev, skb); 163 159 if (wvif) { 164 160 queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; 165 161 WARN_ON(skb_get_queue_mapping(skb) > 3); ··· 249 245 num_queues++; 250 246 } 251 247 } 248 + 249 + wvif = NULL; 250 + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { 251 + for (i = 0; i < num_queues; i++) { 252 + skb = skb_dequeue(&queues[i]->offchan); 253 + if (!skb) 254 + continue; 255 + hif = (struct wfx_hif_msg *)skb->data; 256 + /* Offchan frames are assigned to a special interface. 257 + * The only interface allowed to send data during scan. 258 + */ 259 + WARN_ON(hif->interface != 2); 260 + atomic_inc(&queues[i]->pending_frames); 261 + trace_queues_stats(wdev, queues[i]); 262 + return skb; 263 + } 264 + } 265 + 266 + if (mutex_is_locked(&wdev->scan_lock)) 267 + return NULL; 252 268 253 269 wvif = NULL; 254 270 while ((wvif = wvif_iterate(wdev, wvif)) != NULL) {
+1
drivers/net/wireless/silabs/wfx/queue.h
··· 17 17 struct wfx_queue { 18 18 struct sk_buff_head normal; 19 19 struct sk_buff_head cab; /* Content After (DTIM) Beacon */ 20 + struct sk_buff_head offchan; 20 21 atomic_t pending_frames; 21 22 int priority; 22 23 };