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

Configure Feed

Select the types of activity you want to include in your feed.

wifi: mac80211: add support for NDP ADDBA/DELBA for S1G

S1G defines use of NDP Block Ack (BA) for aggregation, requiring negotiation
of NDP ADDBA/DELBA action frames. If the S1G recipient supports HT-immediate
block ack, the sender must send an NDP ADDBA Request indicating it expects
only NDP BlockAck frames for the agreement.

Introduce support for NDP ADDBA and DELBA exchange in mac80211. The
implementation negotiates the BA mechanism during setup based on station
capabilities and driver support (IEEE80211_HW_SUPPORTS_NDP_BLOCKACK).
If negotiation fails due to mismatched expectations, a rejection with status code
WLAN_STATUS_REJECTED_NDP_BLOCK_ACK_SUGGESTED is returned as per IEEE 802.11-2024.

Trace sample:

IEEE 802.11 Wireless Management
Fixed parameters
Category code: Block Ack (3)
Action code: NDP ADDBA Request (0x80)
Dialog token: 0x01
Block Ack Parameters: 0x1003, A-MSDUs, Block Ack Policy
.... .... .... ...1 = A-MSDUs: Permitted in QoS Data MPDUs
.... .... .... ..1. = Block Ack Policy: Immediate Block Ack
.... .... ..00 00.. = Traffic Identifier: 0x0
0001 0000 00.. .... = Number of Buffers (1 Buffer = 2304 Bytes): 64
Block Ack Timeout: 0x0000
Block Ack Starting Sequence Control (SSC): 0x0010
.... .... .... 0000 = Fragment: 0
0000 0000 0001 .... = Starting Sequence Number: 1

IEEE 802.11 Wireless Management
Fixed parameters
Category code: Block Ack (3)
Action code: NDP ADDBA Response (0x81)
Dialog token: 0x02
Status code: BlockAck negotiation refused because, due to buffer constraints and other unspecified reasons, the recipient prefers to generate only NDP BlockAck frames (0x006d)
Block Ack Parameters: 0x1002, Block Ack Policy
.... .... .... ...0 = A-MSDUs: Not Permitted
.... .... .... ..1. = Block Ack Policy: Immediate Block Ack
.... .... ..00 00.. = Traffic Identifier: 0x0
0001 0000 00.. .... = Number of Buffers (1 Buffer = 2304 Bytes): 64
Block Ack Timeout: 0x0000

Signed-off-by: Ria Thomas <ria.thomas@morsemicro.com>
Link: https://patch.msgid.link/20260305091304.310990-1-ria.thomas@morsemicro.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Ria Thomas and committed by
Johannes Berg
98acd4c1 9aa84d5c

+72 -13
+3
include/linux/ieee80211-ht.h
··· 281 281 WLAN_ACTION_ADDBA_REQ = 0, 282 282 WLAN_ACTION_ADDBA_RESP = 1, 283 283 WLAN_ACTION_DELBA = 2, 284 + WLAN_ACTION_NDP_ADDBA_REQ = 128, 285 + WLAN_ACTION_NDP_ADDBA_RESP = 129, 286 + WLAN_ACTION_NDP_DELBA = 130, 284 287 }; 285 288 286 289 /* BACK (block-ack) parties */
+2
include/linux/ieee80211.h
··· 1482 1482 WLAN_STATUS_REJECT_DSE_BAND = 96, 1483 1483 WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, 1484 1484 WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, 1485 + /* 802.11ah */ 1486 + WLAN_STATUS_REJECTED_NDP_BLOCK_ACK_SUGGESTED = 109, 1485 1487 /* 802.11ai */ 1486 1488 WLAN_STATUS_FILS_AUTHENTICATION_FAILURE = 112, 1487 1489 WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER = 113,
+4
include/net/mac80211.h
··· 2913 2913 * HW flag so drivers can opt in according to their own control, e.g. in 2914 2914 * testing. 2915 2915 * 2916 + * @IEEE80211_HW_SUPPORTS_NDP_BLOCKACK: HW can transmit/receive S1G NDP 2917 + * BlockAck frames. 2918 + * 2916 2919 * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays 2917 2920 */ 2918 2921 enum ieee80211_hw_flags { ··· 2976 2973 IEEE80211_HW_DISALLOW_PUNCTURING, 2977 2974 IEEE80211_HW_HANDLES_QUIET_CSA, 2978 2975 IEEE80211_HW_STRICT, 2976 + IEEE80211_HW_SUPPORTS_NDP_BLOCKACK, 2979 2977 2980 2978 /* keep last, obviously */ 2981 2979 NUM_IEEE80211_HW_FLAGS
+21 -3
net/mac80211/agg-rx.c
··· 94 94 /* check if this is a self generated aggregation halt */ 95 95 if (initiator == WLAN_BACK_RECIPIENT && tx) 96 96 ieee80211_send_delba(sta->sdata, sta->sta.addr, 97 - tid, WLAN_BACK_RECIPIENT, reason); 97 + tid, WLAN_BACK_RECIPIENT, reason, 98 + ieee80211_s1g_use_ndp_ba(sta->sdata, sta)); 98 99 99 100 /* 100 101 * return here in case tid_rx is not assigned - which will happen if ··· 241 240 struct sk_buff *skb; 242 241 struct ieee80211_mgmt *mgmt; 243 242 bool amsdu = ieee80211_hw_check(&local->hw, SUPPORTS_AMSDU_IN_AMPDU); 243 + bool use_ndp = ieee80211_s1g_use_ndp_ba(sdata, sta); 244 244 u16 capab; 245 245 246 246 skb = dev_alloc_skb(sizeof(*mgmt) + ··· 255 253 256 254 skb_put(skb, 2 + sizeof(mgmt->u.action.addba_resp)); 257 255 mgmt->u.action.category = WLAN_CATEGORY_BACK; 258 - mgmt->u.action.action_code = WLAN_ACTION_ADDBA_RESP; 256 + mgmt->u.action.action_code = use_ndp ? 257 + WLAN_ACTION_NDP_ADDBA_RESP : WLAN_ACTION_ADDBA_RESP; 259 258 260 259 mgmt->u.action.addba_resp.dialog_token = dialog_token; 261 260 ··· 279 276 u8 dialog_token, u16 timeout, 280 277 u16 start_seq_num, u16 ba_policy, u16 tid, 281 278 u16 buf_size, bool tx, bool auto_seq, 279 + bool req_ndp, 282 280 const u8 addba_ext_data) 283 281 { 284 282 struct ieee80211_local *local = sta->sdata->local; ··· 301 297 if (tid >= IEEE80211_FIRST_TSPEC_TSID) { 302 298 ht_dbg(sta->sdata, 303 299 "STA %pM requests BA session on unsupported tid %d\n", 300 + sta->sta.addr, tid); 301 + goto end; 302 + } 303 + 304 + if (tx && ieee80211_s1g_use_ndp_ba(sta->sdata, sta) && !req_ndp) { 305 + /* 306 + * According to IEEE 802.11-2024: Inform S1G originator 307 + * ADDBA rejected as NDP BlockAck is preferred 308 + */ 309 + status = WLAN_STATUS_REJECTED_NDP_BLOCK_ACK_SUGGESTED; 310 + ht_dbg(sta->sdata, 311 + "Rejecting AddBA Req from %pM tid %u - require NDP BlockAck\n", 304 312 sta->sta.addr, tid); 305 313 goto end; 306 314 } ··· 490 474 struct ieee80211_mgmt *mgmt, 491 475 size_t len) 492 476 { 477 + bool req_ndp = mgmt->u.action.action_code == WLAN_ACTION_NDP_ADDBA_REQ; 493 478 u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num; 494 479 u8 dialog_token, addba_ext_data; 495 480 ··· 515 498 516 499 __ieee80211_start_rx_ba_session(sta, dialog_token, timeout, 517 500 start_seq_num, ba_policy, tid, 518 - buf_size, true, false, addba_ext_data); 501 + buf_size, true, false, 502 + req_ndp, addba_ext_data); 519 503 } 520 504 521 505 void ieee80211_manage_rx_ba_offl(struct ieee80211_vif *vif,
+9 -4
net/mac80211/agg-tx.c
··· 60 60 61 61 static void ieee80211_send_addba_request(struct sta_info *sta, u16 tid, 62 62 u8 dialog_token, u16 start_seq_num, 63 - u16 agg_size, u16 timeout) 63 + u16 agg_size, u16 timeout, bool ndp) 64 64 { 65 65 struct ieee80211_sub_if_data *sdata = sta->sdata; 66 66 struct ieee80211_local *local = sdata->local; ··· 80 80 skb_put(skb, 2 + sizeof(mgmt->u.action.addba_req)); 81 81 82 82 mgmt->u.action.category = WLAN_CATEGORY_BACK; 83 - mgmt->u.action.action_code = WLAN_ACTION_ADDBA_REQ; 83 + mgmt->u.action.action_code = ndp ? 84 + WLAN_ACTION_NDP_ADDBA_REQ : WLAN_ACTION_ADDBA_REQ; 84 85 85 86 mgmt->u.action.addba_req.dialog_token = dialog_token; 86 87 capab = IEEE80211_ADDBA_PARAM_AMSDU_MASK; ··· 485 484 486 485 /* send AddBA request */ 487 486 ieee80211_send_addba_request(sta, tid, tid_tx->dialog_token, 488 - tid_tx->ssn, buf_size, tid_tx->timeout); 487 + tid_tx->ssn, buf_size, tid_tx->timeout, 488 + tid_tx->ndp); 489 489 490 490 WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)); 491 491 } ··· 523 521 */ 524 522 synchronize_net(); 525 523 524 + tid_tx->ndp = ieee80211_s1g_use_ndp_ba(sdata, sta); 526 525 params.ssn = sta->tid_seq[tid] >> 4; 527 526 ret = drv_ampdu_action(local, sdata, &params); 528 527 tid_tx->ssn = params.ssn; ··· 943 940 944 941 if (send_delba) 945 942 ieee80211_send_delba(sdata, sta->sta.addr, tid, 946 - WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); 943 + WLAN_BACK_INITIATOR, 944 + WLAN_REASON_QSTA_NOT_USE, 945 + tid_tx->ndp); 947 946 } 948 947 949 948 void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
+1
net/mac80211/debugfs.c
··· 490 490 FLAG(DISALLOW_PUNCTURING), 491 491 FLAG(HANDLES_QUIET_CSA), 492 492 FLAG(STRICT), 493 + FLAG(SUPPORTS_NDP_BLOCKACK), 493 494 #undef FLAG 494 495 }; 495 496
+5 -3
net/mac80211/ht.c
··· 379 379 sta->ampdu_mlme.tid_rx_manage_offl)) 380 380 __ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, 381 381 IEEE80211_MAX_AMPDU_BUF_HT, 382 - false, true, 0); 382 + false, true, false, 0); 383 383 384 384 if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS, 385 385 sta->ampdu_mlme.tid_rx_manage_offl)) ··· 455 455 456 456 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, 457 457 const u8 *da, u16 tid, 458 - u16 initiator, u16 reason_code) 458 + u16 initiator, u16 reason_code, 459 + bool use_ndp) 459 460 { 460 461 struct ieee80211_local *local = sdata->local; 461 462 struct sk_buff *skb; ··· 474 473 skb_put(skb, 2 + sizeof(mgmt->u.action.delba)); 475 474 476 475 mgmt->u.action.category = WLAN_CATEGORY_BACK; 477 - mgmt->u.action.action_code = WLAN_ACTION_DELBA; 476 + mgmt->u.action.action_code = use_ndp ? 477 + WLAN_ACTION_NDP_DELBA : WLAN_ACTION_DELBA; 478 478 params = (u16)(initiator << 11); /* bit 11 initiator */ 479 479 params |= (u16)(tid << 12); /* bit 15:12 TID number */ 480 480
+5 -1
net/mac80211/ieee80211_i.h
··· 2190 2190 struct link_sta_info *link_sta); 2191 2191 void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata, 2192 2192 const u8 *da, u16 tid, 2193 - u16 initiator, u16 reason_code); 2193 + u16 initiator, u16 reason_code, 2194 + bool use_ndp); 2194 2195 int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata, 2195 2196 enum ieee80211_smps_mode smps, const u8 *da, 2196 2197 const u8 *bssid, int link_id); ··· 2207 2206 u8 dialog_token, u16 timeout, 2208 2207 u16 start_seq_num, u16 ba_policy, u16 tid, 2209 2208 u16 buf_size, bool tx, bool auto_seq, 2209 + bool req_ndp, 2210 2210 const u8 addba_ext_data); 2211 2211 void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, 2212 2212 enum ieee80211_agg_stop_reason reason); ··· 2333 2331 void ieee80211_s1g_cap_to_sta_s1g_cap(struct ieee80211_sub_if_data *sdata, 2334 2332 const struct ieee80211_s1g_cap *s1g_cap_ie, 2335 2333 struct link_sta_info *link_sta); 2334 + bool ieee80211_s1g_use_ndp_ba(const struct ieee80211_sub_if_data *sdata, 2335 + const struct sta_info *sta); 2336 2336 2337 2337 /* Spectrum management */ 2338 2338 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
+3
net/mac80211/iface.c
··· 1581 1581 if (sta) { 1582 1582 switch (mgmt->u.action.action_code) { 1583 1583 case WLAN_ACTION_ADDBA_REQ: 1584 + case WLAN_ACTION_NDP_ADDBA_REQ: 1584 1585 ieee80211_process_addba_request(local, sta, 1585 1586 mgmt, len); 1586 1587 break; 1587 1588 case WLAN_ACTION_ADDBA_RESP: 1589 + case WLAN_ACTION_NDP_ADDBA_RESP: 1588 1590 ieee80211_process_addba_resp(local, sta, 1589 1591 mgmt, len); 1590 1592 break; 1591 1593 case WLAN_ACTION_DELBA: 1594 + case WLAN_ACTION_NDP_DELBA: 1592 1595 ieee80211_process_delba(sdata, sta, 1593 1596 mgmt, len); 1594 1597 break;
+9 -2
net/mac80211/rx.c
··· 1475 1475 !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) 1476 1476 ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, 1477 1477 WLAN_BACK_RECIPIENT, 1478 - WLAN_REASON_QSTA_REQUIRE_SETUP); 1478 + WLAN_REASON_QSTA_REQUIRE_SETUP, 1479 + ieee80211_s1g_use_ndp_ba(rx->sdata, 1480 + rx->sta)); 1479 1481 goto dont_reorder; 1480 1482 } 1481 1483 ··· 3374 3372 !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) 3375 3373 ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, 3376 3374 WLAN_BACK_RECIPIENT, 3377 - WLAN_REASON_QSTA_REQUIRE_SETUP); 3375 + WLAN_REASON_QSTA_REQUIRE_SETUP, 3376 + ieee80211_s1g_use_ndp_ba(rx->sdata, 3377 + rx->sta)); 3378 3378 3379 3379 tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); 3380 3380 if (!tid_agg_rx) ··· 3757 3753 3758 3754 switch (mgmt->u.action.action_code) { 3759 3755 case WLAN_ACTION_ADDBA_REQ: 3756 + case WLAN_ACTION_NDP_ADDBA_REQ: 3760 3757 if (len < IEEE80211_MIN_ACTION_SIZE(addba_req)) 3761 3758 goto invalid; 3762 3759 break; 3763 3760 case WLAN_ACTION_ADDBA_RESP: 3761 + case WLAN_ACTION_NDP_ADDBA_RESP: 3764 3762 if (len < IEEE80211_MIN_ACTION_SIZE(addba_resp)) 3765 3763 goto invalid; 3766 3764 break; 3767 3765 case WLAN_ACTION_DELBA: 3766 + case WLAN_ACTION_NDP_DELBA: 3768 3767 if (len < IEEE80211_MIN_ACTION_SIZE(delba)) 3769 3768 goto invalid; 3770 3769 break;
+8
net/mac80211/s1g.c
··· 220 220 221 221 ieee80211_sta_recalc_aggregates(&link_sta->sta->sta); 222 222 } 223 + 224 + bool ieee80211_s1g_use_ndp_ba(const struct ieee80211_sub_if_data *sdata, 225 + const struct sta_info *sta) 226 + { 227 + return sdata->vif.cfg.s1g && 228 + ieee80211_hw_check(&sdata->local->hw, SUPPORTS_NDP_BLOCKACK) && 229 + (sta && sta->sta.deflink.s1g_cap.s1g); 230 + }
+2
net/mac80211/sta_info.h
··· 171 171 * @bar_pending: BAR needs to be re-sent 172 172 * @amsdu: support A-MSDU within A-MDPU 173 173 * @ssn: starting sequence number of the session 174 + * @ndp: this session is using NDP Block ACKs 174 175 * 175 176 * This structure's lifetime is managed by RCU, assignments to 176 177 * the array holding it must hold the aggregation mutex. ··· 200 199 u16 failed_bar_ssn; 201 200 bool bar_pending; 202 201 bool amsdu; 202 + bool ndp; 203 203 u8 tid; 204 204 }; 205 205