diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile index 4e84f929a3..d8268f158e 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=mac80211 PKG_VERSION:=5.10.68-1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.10.68/ PKG_HASH:=bba161b0084590c677a84b80993709e388a3c478f29ed0c475d4fce1b9162968 diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh index 1e275a0028..8b3a37c81c 100644 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh @@ -26,7 +26,6 @@ drv_mac80211_init_device_config() { hostapd_common_add_device_config config_add_string path phy 'macaddr:macaddr' - config_add_string hwmode config_add_string tx_burst config_add_string distance config_add_int beacon_int chanbw frag rts @@ -44,11 +43,26 @@ drv_mac80211_init_device_config() { su_beamformee \ mu_beamformer \ mu_beamformee \ + he_su_beamformer \ + he_su_beamformee \ + he_mu_beamformer \ vht_txop_ps \ htc_vht \ rx_antenna_pattern \ - tx_antenna_pattern - config_add_int vht_max_a_mpdu_len_exp vht_max_mpdu vht_link_adapt vht160 rx_stbc tx_stbc + tx_antenna_pattern \ + he_spr_sr_control \ + he_twt_required + config_add_int \ + beamformer_antennas \ + beamformee_antennas \ + vht_max_a_mpdu_len_exp \ + vht_max_mpdu \ + vht_link_adapt \ + vht160 \ + rx_stbc \ + tx_stbc \ + he_bss_color \ + he_spr_non_srg_obss_pd_max_offset config_add_boolean \ ldpc \ greenfield \ @@ -96,6 +110,23 @@ mac80211_add_capabilities() { export -n -- "$__var=$__out" } +mac80211_add_he_capabilities() { + local __out= oifs + + oifs="$IFS" + IFS=: + for capab in "$@"; do + set -- $capab + [ "$(($4))" -gt 0 ] || continue + [ "$(((0x$2) & $3))" -gt 0 ] || { + eval "$1=0" + continue + } + append base_cfg "$1=1" "$N" + done + IFS="$oifs" +} + mac80211_hostapd_setup_base() { local phy="$1" @@ -119,6 +150,9 @@ mac80211_hostapd_setup_base() { [ "$noscan" -gt 0 ] && hostapd_noscan=1 [ "$tx_burst" = 0 ] && tx_burst= + chan_ofs=0 + [ "$band" = "6g" ] && chan_ofs=1 + ieee80211n=1 ht_capab= case "$htmode" in @@ -126,7 +160,7 @@ mac80211_hostapd_setup_base() { HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160) case "$hwmode" in a) - case "$(( ($channel / 4) % 2 ))" in + case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in 1) ht_capab="[HT40+]";; 0) ht_capab="[HT40-]";; esac @@ -200,7 +234,7 @@ mac80211_hostapd_setup_base() { case "$htmode" in VHT20|HE20) enable_ac=1;; VHT40|HE40) - case "$(( ($channel / 4) % 2 ))" in + case "$(( (($channel / 4) + $chan_ofs) % 2 ))" in 1) idx=$(($channel + 2));; 0) idx=$(($channel - 2));; esac @@ -208,7 +242,7 @@ mac80211_hostapd_setup_base() { vht_center_seg0=$idx ;; VHT80|HE80) - case "$(( ($channel / 4) % 4 ))" in + case "$(( (($channel / 4) + $chan_ofs) % 4 ))" in 1) idx=$(($channel + 6));; 2) idx=$(($channel + 2));; 3) idx=$(($channel - 2));; @@ -219,15 +253,35 @@ mac80211_hostapd_setup_base() { vht_center_seg0=$idx ;; VHT160|HE160) - case "$channel" in - 36|40|44|48|52|56|60|64) idx=50;; - 100|104|108|112|116|120|124|128) idx=114;; - esac + if [ "$band" = "6g" ]; then + case "$channel" in + 1|5|9|13|17|21|25|29) idx=15;; + 33|37|41|45|49|53|57|61) idx=47;; + 65|69|73|77|81|85|89|93) idx=79;; + 97|101|105|109|113|117|121|125) idx=111;; + 129|133|137|141|145|149|153|157) idx=143;; + 161|165|169|173|177|181|185|189) idx=175;; + 193|197|201|205|209|213|217|221) idx=207;; + esac + else + case "$channel" in + 36|40|44|48|52|56|60|64) idx=50;; + 100|104|108|112|116|120|124|128) idx=114;; + esac + fi enable_ac=1 vht_oper_chwidth=2 vht_center_seg0=$idx ;; esac + [ "$band" = "6g" ] && { + op_class= + case "$htmode" in + HE20) op_class=131;; + HE*) op_class=$((132 + $vht_oper_chwidth)) + esac + [ -n "$op_class" ] && append base_cfg "op_class=$op_class" "$N" + } [ "$hwmode" = "a" ] || enable_ac=0 if [ "$enable_ac" != "0" -o "$vendor_vht" = "1" ]; then @@ -242,6 +296,8 @@ mac80211_hostapd_setup_base() { mu_beamformee:1 \ vht_txop_ps:1 \ htc_vht:1 \ + beamformee_antennas:4 \ + beamformer_antennas:4 \ rx_antenna_pattern:1 \ tx_antenna_pattern:1 \ vht_max_a_mpdu_len_exp:7 \ @@ -282,6 +338,18 @@ mac80211_hostapd_setup_base() { RX-STBC-123:0x700:0x300:1 \ RX-STBC-1234:0x700:0x400:1 \ + [ "$(($vht_cap & 0x800))" -gt 0 -a "$su_beamformer" -gt 0 ] && { + cap_ant="$(( ( ($vht_cap >> 16) & 3 ) + 1 ))" + [ "$cap_ant" -gt "$beamformer_antennas" ] && cap_ant="$beamformer_antennas" + [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[SOUNDING-DIMENSION-$cap_ant]" + } + + [ "$(($vht_cap & 0x1000))" -gt 0 -a "$su_beamformee" -gt 0 ] && { + cap_ant="$(( ( ($vht_cap >> 13) & 3 ) + 1 ))" + [ "$cap_ant" -gt "$beamformee_antennas" ] && cap_ant="$beamformee_antennas" + [ "$cap_ant" -gt 1 ] && vht_capab="$vht_capab[BF-ANTENNA-$cap_ant]" + } + # supported Channel widths vht160_hw=0 [ "$(($vht_cap & 12))" -eq 4 -a 1 -le "$vht160" ] && \ @@ -337,16 +405,62 @@ mac80211_hostapd_setup_base() { esac if [ "$enable_ax" != "0" ]; then + json_get_vars \ + he_su_beamformer:1 \ + he_su_beamformee:0 \ + he_mu_beamformer:1 \ + he_twt_required:0 \ + he_spr_sr_control:0 \ + he_spr_non_srg_obss_pd_max_offset:1 \ + he_bss_color + + he_phy_cap=$(iw phy "$phy" info | awk -F "[()]" '/HE PHY Capabilities/ { print $2 }' | head -1) + he_phy_cap=${he_phy_cap:2} + he_mac_cap=$(iw phy "$phy" info | awk -F "[()]" '/HE MAC Capabilities/ { print $2 }' | head -1) + he_mac_cap=${he_mac_cap:2} + append base_cfg "ieee80211ax=1" "$N" + [ -n "$he_bss_color" ] && append base_cfg "he_bss_color=$he_bss_color" "$N" [ "$hwmode" = "a" ] && { append base_cfg "he_oper_chwidth=$vht_oper_chwidth" "$N" append base_cfg "he_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N" } + + mac80211_add_he_capabilities \ + he_su_beamformer:${he_phy_cap:6:2}:0x80:$he_su_beamformer \ + he_su_beamformee:${he_phy_cap:8:2}:0x1:$he_su_beamformee \ + he_mu_beamformer:${he_phy_cap:8:2}:0x2:$he_mu_beamformer \ + he_spr_sr_control:${he_phy_cap:14:2}:0x1:$he_spr_sr_control \ + he_twt_required:${he_mac_cap:0:2}:0x6:$he_twt_required + + [ "$he_spr_sr_control" -gt 0 ] && append base_cfg "he_spr_non_srg_obss_pd_max_offset=$he_spr_non_srg_obss_pd_max_offset" "$N" + append base_cfg "he_default_pe_duration=4" "$N" append base_cfg "he_rts_threshold=1023" "$N" - append base_cfg "he_su_beamformer=1" "$N" - append base_cfg "he_su_beamformee=1" "$N" - append base_cfg "he_mu_beamformer=1" "$N" + append base_cfg "he_mu_edca_qos_info_param_count=0" "$N" + append base_cfg "he_mu_edca_qos_info_q_ack=0" "$N" + append base_cfg "he_mu_edca_qos_info_queue_request=0" "$N" + append base_cfg "he_mu_edca_qos_info_txop_request=0" "$N" + append base_cfg "he_mu_edca_ac_be_aifsn=8" "$N" + append base_cfg "he_mu_edca_ac_be_aci=0" "$N" + append base_cfg "he_mu_edca_ac_be_ecwmin=9" "$N" + append base_cfg "he_mu_edca_ac_be_ecwmax=10" "$N" + append base_cfg "he_mu_edca_ac_be_timer=255" "$N" + append base_cfg "he_mu_edca_ac_bk_aifsn=15" "$N" + append base_cfg "he_mu_edca_ac_bk_aci=1" "$N" + append base_cfg "he_mu_edca_ac_bk_ecwmin=9" "$N" + append base_cfg "he_mu_edca_ac_bk_ecwmax=10" "$N" + append base_cfg "he_mu_edca_ac_bk_timer=255" "$N" + append base_cfg "he_mu_edca_ac_vi_ecwmin=5" "$N" + append base_cfg "he_mu_edca_ac_vi_ecwmax=7" "$N" + append base_cfg "he_mu_edca_ac_vi_aifsn=5" "$N" + append base_cfg "he_mu_edca_ac_vi_aci=2" "$N" + append base_cfg "he_mu_edca_ac_vi_timer=255" "$N" + append base_cfg "he_mu_edca_ac_vo_aifsn=5" "$N" + append base_cfg "he_mu_edca_ac_vo_aci=3" "$N" + append base_cfg "he_mu_edca_ac_vo_ecwmin=5" "$N" + append base_cfg "he_mu_edca_ac_vo_ecwmax=7" "$N" + append base_cfg "he_mu_edca_ac_vo_timer=255" "$N" fi hostapd_prepare_device_config "$hostapd_conf_file" nl80211 @@ -528,7 +642,7 @@ mac80211_iw_interface_add() { rc="$?" } - [ "$rc" != 0 ] && wireless_setup_failed INTERFACE_CREATION_FAILED + [ "$rc" != 0 ] && echo "Failed to create interface $ifname" return $rc } @@ -689,14 +803,8 @@ mac80211_prepare_iw_htmode() { case "$htmode" in VHT20|HT20) iw_htmode=HT20;; HT40*|VHT40|VHT160) - case "$hwmode" in - a) - case "$(( ($channel / 4) % 2 ))" in - 1) iw_htmode="HT40+" ;; - 0) iw_htmode="HT40-";; - esac - ;; - *) + case "$band" in + 2g) case "$htmode" in HT40+) iw_htmode="HT40+";; HT40-) iw_htmode="HT40-";; @@ -709,6 +817,12 @@ mac80211_prepare_iw_htmode() { ;; esac ;; + *) + case "$(( ($channel / 4) % 2 ))" in + 1) iw_htmode="HT40+" ;; + 0) iw_htmode="HT40-";; + esac + ;; esac [ "$auto_channel" -gt 0 ] && iw_htmode="HT40+" ;; @@ -763,6 +877,7 @@ mac80211_setup_adhoc() { mcval= [ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" + iw dev "$ifname" set type ibss iw dev "$ifname" ibss join "$ssid" $freq $iw_htmode fixed-freq $bssid \ beacon-interval $beacon_int \ ${brstr:+basic-rates $brstr} \ @@ -818,7 +933,6 @@ mac80211_setup_vif() { mesh) wireless_vif_parse_encryption [ -z "$htmode" ] && htmode="NOHT"; - freq="$(get_freq "$phy" "$channel")" if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then mac80211_setup_supplicant $vif_enable || failed=1 else @@ -832,7 +946,6 @@ mac80211_setup_vif() { adhoc) wireless_vif_parse_encryption if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then - freq="$(get_freq "$phy" "$channel")" mac80211_setup_supplicant_noctl $vif_enable || failed=1 else mac80211_setup_adhoc $vif_enable @@ -849,10 +962,30 @@ mac80211_setup_vif() { get_freq() { local phy="$1" - local chan="$2" - iw "$phy" info | grep -E -m1 "(\* ${chan:-....} MHz${chan:+|\\[$chan\\]})" | grep MHz | awk '{print $2}' + local channel="$2" + local band="$3" + + case "$band" in + 2g) band="1:";; + 5g) band="2:";; + 60g) band="3:";; + 6g) band="4:";; + esac + + iw "$phy" info | awk -v band="$band" -v channel="[$channel]" ' + +$1 ~ /Band/ { + band_match = band == $2 } +band_match && $3 == "MHz" && $4 == channel { + print $2 + exit +} +' +} + + chan_is_dfs() { local phy="$1" local chan="$2" @@ -933,7 +1066,7 @@ drv_mac80211_setup() { done # convert channel to frequency - [ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")" + [ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel" "$band")" [ -n "$country" ] && { iw reg get | grep -q "^country $country:" || { diff --git a/package/kernel/mac80211/files/lib/wifi/mac80211.sh b/package/kernel/mac80211/files/lib/wifi/mac80211.sh index e8a6136e16..7e2d41daa2 100644 --- a/package/kernel/mac80211/files/lib/wifi/mac80211.sh +++ b/package/kernel/mac80211/files/lib/wifi/mac80211.sh @@ -57,6 +57,85 @@ check_mac80211_device() { [ "$phy" = "$dev" ] && found=1 } + +__get_band_defaults() { + local phy="$1" + + ( iw phy "$phy" info; echo ) | awk ' +BEGIN { + bands = "" +} + +($1 == "Band" || $1 == "") && band { + if (channel) { + mode="NOHT" + if (ht) mode="HT20" + if (vht && band != "1:") mode="VHT80" + if (he) mode="HE80" + if (he && band == "1:") mode="HE20" + sub("\\[", "", channel) + sub("\\]", "", channel) + bands = bands band channel ":" mode " " + } + band="" +} + +$1 == "Band" { + band = $2 + channel = "" + vht = "" + ht = "" + he = "" +} + +$0 ~ "Capabilities:" { + ht=1 +} + +$0 ~ "VHT Capabilities" { + vht=1 +} + +$0 ~ "HE Iftypes" { + he=1 +} + +$1 == "*" && $3 == "MHz" && $0 !~ /disabled/ && band && !channel { + channel = $4 +} + +END { + print bands +}' +} + +get_band_defaults() { + local phy="$1" + + for c in $(__get_band_defaults "$phy"); do + local band="${c%%:*}" + c="${c#*:}" + local chan="${c%%:*}" + c="${c#*:}" + local mode="${c%%:*}" + + case "$band" in + 1) band=2g;; + 2) band=5g;; + 3) band=60g;; + 4) band=6g;; + *) band="";; + esac + + [ -n "$band" ] || continue + [ -n "$mode_band" -a "$band" = "6g" ] && return + + mode_band="$band" + channel="$chan" + htmode="$mode" + done +} + detect_mac80211() { devidx=0 config_load wireless @@ -75,26 +154,12 @@ detect_mac80211() { config_foreach check_mac80211_device wifi-device [ "$found" -gt 0 ] && continue - mode_band="g" - channel="11" + mode_band="" + channel="" htmode="" ht_capab="" - iw phy "$dev" info | grep -q 'Capabilities:' && htmode=HT20 - - iw phy "$dev" info | grep -q '\* 5... MHz \[' && { - mode_band="a" - channel=$(iw phy "$dev" info | grep '\* 5... MHz \[' | grep '(disabled)' -v -m 1 | sed 's/[^[]*\[\|\].*//g') - iw phy "$dev" info | grep -q 'VHT Capabilities' && htmode="VHT80" - } - - iw phy "$dev" info | grep -q '\* 5.... MHz \[' && { - mode_band="ad" - channel=$(iw phy "$dev" info | grep '\* 5.... MHz \[' | grep '(disabled)' -v -m 1 | sed 's/[^[]*\[\|\|\].*//g') - iw phy "$dev" info | grep -q 'Capabilities:' && htmode="HT20" - } - - [ -n "$htmode" ] && ht_capab="set wireless.radio${devidx}.htmode=$htmode" + get_band_defaults "$dev" path="$(mac80211_phy_to_path "$dev")" if [ -n "$path" ]; then @@ -106,10 +171,10 @@ detect_mac80211() { uci -q batch <<-EOF set wireless.radio${devidx}=wifi-device set wireless.radio${devidx}.type=mac80211 - set wireless.radio${devidx}.channel=${channel} - set wireless.radio${devidx}.hwmode=11${mode_band} ${dev_id} - ${ht_capab} + set wireless.radio${devidx}.channel=${channel} + set wireless.radio${devidx}.band=${mode_band} + set wireless.radio${devidx}.htmode=$htmode set wireless.radio${devidx}.disabled=0 set wireless.default_radio${devidx}=wifi-iface diff --git a/package/kernel/mac80211/patches/subsys/305-mac80211-fix-regression-in-SSN-handling-of-addba-tx.patch b/package/kernel/mac80211/patches/subsys/305-mac80211-fix-regression-in-SSN-handling-of-addba-tx.patch new file mode 100644 index 0000000000..6ffdffc562 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/305-mac80211-fix-regression-in-SSN-handling-of-addba-tx.patch @@ -0,0 +1,44 @@ +From: Felix Fietkau +Date: Wed, 24 Nov 2021 10:30:41 +0100 +Subject: [PATCH] mac80211: fix regression in SSN handling of addba tx + +Some drivers that do their own sequence number allocation (e.g. ath9k) rely +on being able to modify params->ssn on starting tx ampdu sessions. +This was broken by a change that modified it to use sta->tid_seq[tid] instead. + +Cc: stable@vger.kernel.org +Fixes: 31d8bb4e07f8 ("mac80211: agg-tx: refactor sending addba") +Reported-by: Eneas U de Queiroz +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/agg-tx.c ++++ b/net/mac80211/agg-tx.c +@@ -480,8 +480,7 @@ static void ieee80211_send_addba_with_ti + + /* send AddBA request */ + ieee80211_send_addba_request(sdata, sta->sta.addr, tid, +- tid_tx->dialog_token, +- sta->tid_seq[tid] >> 4, ++ tid_tx->dialog_token, tid_tx->ssn, + buf_size, tid_tx->timeout); + + WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state)); +@@ -523,6 +522,7 @@ void ieee80211_tx_ba_session_handle_star + + params.ssn = sta->tid_seq[tid] >> 4; + ret = drv_ampdu_action(local, sdata, ¶ms); ++ tid_tx->ssn = params.ssn; + if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) { + return; + } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) { +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -190,6 +190,7 @@ struct tid_ampdu_tx { + u8 stop_initiator; + bool tx_stop; + u16 buf_size; ++ u16 ssn; + + u16 failed_bar_ssn; + bool bar_pending; diff --git a/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch b/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch new file mode 100644 index 0000000000..c8cac93354 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch @@ -0,0 +1,62 @@ +From: Xing Song +Date: Tue, 23 Nov 2021 11:31:23 +0800 +Subject: [PATCH] mac80211: set up the fwd_skb->dev for mesh forwarding + +Mesh forwarding requires that the fwd_skb->dev is set up for TX handling, +otherwise the following warning will be generated, so set it up for the +pending frames. + +[ 72.835674 ] WARNING: CPU: 0 PID: 1193 at __skb_flow_dissect+0x284/0x1298 +[ 72.842379 ] Modules linked in: ksmbd pppoe ppp_async l2tp_ppp ... +[ 72.962020 ] CPU: 0 PID: 1193 Comm: kworker/u5:1 Tainted: P S 5.4.137 #0 +[ 72.969938 ] Hardware name: MT7622_MT7531 RFB (DT) +[ 72.974659 ] Workqueue: napi_workq napi_workfn +[ 72.979025 ] pstate: 60000005 (nZCv daif -PAN -UAO) +[ 72.983822 ] pc : __skb_flow_dissect+0x284/0x1298 +[ 72.988444 ] lr : __skb_flow_dissect+0x54/0x1298 +[ 72.992977 ] sp : ffffffc010c738c0 +[ 72.996293 ] x29: ffffffc010c738c0 x28: 0000000000000000 +[ 73.001615 ] x27: 000000000000ffc2 x26: ffffff800c2eb818 +[ 73.006937 ] x25: ffffffc010a987c8 x24: 00000000000000ce +[ 73.012259 ] x23: ffffffc010c73a28 x22: ffffffc010a99c60 +[ 73.017581 ] x21: 000000000000ffc2 x20: ffffff80094da800 +[ 73.022903 ] x19: 0000000000000000 x18: 0000000000000014 +[ 73.028226 ] x17: 00000000084d16af x16: 00000000d1fc0bab +[ 73.033548 ] x15: 00000000715f6034 x14: 000000009dbdd301 +[ 73.038870 ] x13: 00000000ea4dcbc3 x12: 0000000000000040 +[ 73.044192 ] x11: 000000000eb00ff0 x10: 0000000000000000 +[ 73.049513 ] x9 : 000000000eb00073 x8 : 0000000000000088 +[ 73.054834 ] x7 : 0000000000000000 x6 : 0000000000000001 +[ 73.060155 ] x5 : 0000000000000000 x4 : 0000000000000000 +[ 73.065476 ] x3 : ffffffc010a98000 x2 : 0000000000000000 +[ 73.070797 ] x1 : 0000000000000000 x0 : 0000000000000000 +[ 73.076120 ] Call trace: +[ 73.078572 ] __skb_flow_dissect+0x284/0x1298 +[ 73.082846 ] __skb_get_hash+0x7c/0x228 +[ 73.086629 ] ieee80211_txq_may_transmit+0x7fc/0x17b8 [mac80211] +[ 73.092564 ] ieee80211_tx_prepare_skb+0x20c/0x268 [mac80211] +[ 73.098238 ] ieee80211_tx_pending+0x144/0x330 [mac80211] +[ 73.103560 ] tasklet_action_common.isra.16+0xb4/0x158 +[ 73.108618 ] tasklet_action+0x2c/0x38 +[ 73.112286 ] __do_softirq+0x168/0x3b0 +[ 73.115954 ] do_softirq.part.15+0x88/0x98 +[ 73.119969 ] __local_bh_enable_ip+0xb0/0xb8 +[ 73.124156 ] napi_workfn+0x58/0x90 +[ 73.127565 ] process_one_work+0x20c/0x478 +[ 73.131579 ] worker_thread+0x50/0x4f0 +[ 73.135249 ] kthread+0x124/0x128 +[ 73.138484 ] ret_from_fork+0x10/0x1c + +Signed-off-by: Xing Song +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2940,6 +2940,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 + if (!fwd_skb) + goto out; + ++ fwd_skb->dev = sdata->dev; + fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data; + fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); + info = IEEE80211_SKB_CB(fwd_skb); diff --git a/package/kernel/mac80211/patches/subsys/307-mac80211-do-not-access-the-IV-when-it-was-stripped.patch b/package/kernel/mac80211/patches/subsys/307-mac80211-do-not-access-the-IV-when-it-was-stripped.patch new file mode 100644 index 0000000000..b50499d58a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/307-mac80211-do-not-access-the-IV-when-it-was-stripped.patch @@ -0,0 +1,26 @@ +From: Xing Song +Date: Mon, 1 Nov 2021 10:46:57 +0800 +Subject: [PATCH] mac80211: do not access the IV when it was stripped + +ieee80211_get_keyid() will return false value if IV has been stripped, +such as return 0 for IP/ARP frames due to LLC header, and return -EINVAL +for disassociation frames due to its length... etc. Don't try to access +it if it's not present. + +Signed-off-by: Xing Song +Link: https://lore.kernel.org/r/20211101024657.143026-1-xing.song@mediatek.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1945,7 +1945,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_ + int keyid = rx->sta->ptk_idx; + sta_ptk = rcu_dereference(rx->sta->ptk[keyid]); + +- if (ieee80211_has_protected(fc)) { ++ if (ieee80211_has_protected(fc) && ++ !(status->flag & RX_FLAG_IV_STRIPPED)) { + cs = rx->sta->cipher_scheme; + keyid = ieee80211_get_keyid(rx->skb, cs); + diff --git a/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch b/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch index 49af25eb1d..518bc582ae 100644 --- a/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch +++ b/package/kernel/mac80211/patches/subsys/315-mac80211-add-rx-decapsulation-offload-support.patch @@ -183,7 +183,7 @@ Signed-off-by: Felix Fietkau enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c -@@ -4195,7 +4195,9 @@ void ieee80211_check_fast_rx(struct sta_ +@@ -4197,7 +4197,9 @@ void ieee80211_check_fast_rx(struct sta_ .vif_type = sdata->vif.type, .control_port_protocol = sdata->control_port_protocol, }, *old, *new = NULL; @@ -193,7 +193,7 @@ Signed-off-by: Felix Fietkau /* use sparse to check that we don't return without updating */ __acquire(check_fast_rx); -@@ -4308,6 +4310,17 @@ void ieee80211_check_fast_rx(struct sta_ +@@ -4310,6 +4312,17 @@ void ieee80211_check_fast_rx(struct sta_ if (assign) new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); @@ -211,7 +211,7 @@ Signed-off-by: Felix Fietkau spin_lock_bh(&sta->lock); old = rcu_dereference_protected(sta->fast_rx, true); rcu_assign_pointer(sta->fast_rx, new); -@@ -4354,6 +4367,108 @@ void ieee80211_check_fast_rx_iface(struc +@@ -4356,6 +4369,108 @@ void ieee80211_check_fast_rx_iface(struc mutex_unlock(&local->sta_mtx); } @@ -320,7 +320,7 @@ Signed-off-by: Felix Fietkau static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, struct ieee80211_fast_rx *fast_rx) { -@@ -4374,9 +4489,6 @@ static bool ieee80211_invoke_fast_rx(str +@@ -4376,9 +4491,6 @@ static bool ieee80211_invoke_fast_rx(str } addrs __aligned(2); struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; @@ -330,7 +330,7 @@ Signed-off-by: Felix Fietkau /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write * to a common data structure; drivers can implement that per queue * but we don't have that information in mac80211 -@@ -4450,32 +4562,6 @@ static bool ieee80211_invoke_fast_rx(str +@@ -4452,32 +4564,6 @@ static bool ieee80211_invoke_fast_rx(str pskb_trim(skb, skb->len - fast_rx->icv_len)) goto drop; @@ -363,7 +363,7 @@ Signed-off-by: Felix Fietkau if (rx->key && !ieee80211_has_protected(hdr->frame_control)) goto drop; -@@ -4487,12 +4573,6 @@ static bool ieee80211_invoke_fast_rx(str +@@ -4489,12 +4575,6 @@ static bool ieee80211_invoke_fast_rx(str return true; } @@ -376,7 +376,7 @@ Signed-off-by: Felix Fietkau /* do the header conversion - first grab the addresses */ ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs); ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs); -@@ -4501,62 +4581,14 @@ static bool ieee80211_invoke_fast_rx(str +@@ -4503,62 +4583,14 @@ static bool ieee80211_invoke_fast_rx(str /* push the addresses in front */ memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); @@ -443,7 +443,7 @@ Signed-off-by: Felix Fietkau stats->dropped++; return true; } -@@ -4610,6 +4642,47 @@ static bool ieee80211_prepare_and_rx_han +@@ -4612,6 +4644,47 @@ static bool ieee80211_prepare_and_rx_han return true; } @@ -491,7 +491,7 @@ Signed-off-by: Felix Fietkau /* * This is the actual Rx frames handler. as it belongs to Rx path it must * be called with rcu_read_lock protection. -@@ -4847,15 +4920,20 @@ void ieee80211_rx_list(struct ieee80211_ +@@ -4849,15 +4922,20 @@ void ieee80211_rx_list(struct ieee80211_ * if it was previously present. * Also, frames with less than 16 bytes are dropped. */ diff --git a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch index 78aff4a930..5d390990cd 100644 --- a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch +++ b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch @@ -7,24 +7,6 @@ The software rate control cannot deal with encap offload, so fix it. Signed-off-by: Ryder Lee --- ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -2024,6 +2024,15 @@ static inline void ieee80211_tx_skb(stru - ieee80211_tx_skb_tid(sdata, skb, 7); - } - -+static inline bool ieee80211_is_tx_data(struct sk_buff *skb) -+{ -+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ -+ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || -+ ieee80211_is_data(hdr->frame_control); -+} -+ - u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action, - struct ieee802_11_elems *elems, - u64 filter, u32 crc, u8 *transmitter_bssid, --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie @@ -117,3 +99,28 @@ Signed-off-by: Ryder Lee if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { struct sta_info *sta = container_of(txq->sta, struct sta_info, +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6733,4 +6733,22 @@ struct sk_buff *ieee80211_get_fils_disco + struct sk_buff * + ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); ++ ++/** ++ * ieee80211_is_tx_data - check if frame is a data frame ++ * ++ * The function is used to check if a frame is a data frame. Frames with ++ * hardware encapsulation enabled are data frames. ++ * ++ * @skb: the frame to be transmitted. ++ */ ++static inline bool ieee80211_is_tx_data(struct sk_buff *skb) ++{ ++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_hdr *hdr = (void *) skb->data; ++ ++ return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP || ++ ieee80211_is_data(hdr->frame_control); ++} ++ + #endif /* MAC80211_H */ diff --git a/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch new file mode 100644 index 0000000000..073782188a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/380-mac80211-introduce-aql_enable-node-in-debugfs.patch @@ -0,0 +1,111 @@ +From: Lorenzo Bianconi +Date: Sat, 9 Jan 2021 18:57:51 +0100 +Subject: [PATCH] mac80211: introduce aql_enable node in debugfs + +Introduce aql_enable node in debugfs in order to enable/disable aql. +This is useful for debugging purpose. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/e7a934d5d84e4796c4f97ea5de4e66c824296b07.1610214851.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -281,6 +281,56 @@ static const struct file_operations aql_ + .llseek = default_llseek, + }; + ++static ssize_t aql_enable_read(struct file *file, char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ char buf[3]; ++ int len; ++ ++ len = scnprintf(buf, sizeof(buf), "%d\n", ++ !static_key_false(&aql_disable.key)); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, buf, len); ++} ++ ++static ssize_t aql_enable_write(struct file *file, const char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ bool aql_disabled = static_key_false(&aql_disable.key); ++ char buf[3]; ++ size_t len; ++ ++ if (count > sizeof(buf)) ++ return -EINVAL; ++ ++ if (copy_from_user(buf, user_buf, count)) ++ return -EFAULT; ++ ++ buf[sizeof(buf) - 1] = '\0'; ++ len = strlen(buf); ++ if (len > 0 && buf[len - 1] == '\n') ++ buf[len - 1] = 0; ++ ++ if (buf[0] == '0' && buf[1] == '\0') { ++ if (!aql_disabled) ++ static_branch_inc(&aql_disable); ++ } else if (buf[0] == '1' && buf[1] == '\0') { ++ if (aql_disabled) ++ static_branch_dec(&aql_disable); ++ } else { ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++static const struct file_operations aql_enable_ops = { ++ .write = aql_enable_write, ++ .read = aql_enable_read, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ + static ssize_t force_tx_status_read(struct file *file, + char __user *user_buf, + size_t count, +@@ -569,6 +619,7 @@ void debugfs_hw_add(struct ieee80211_loc + DEBUGFS_ADD(power); + DEBUGFS_ADD(hw_conf); + DEBUGFS_ADD_MODE(force_tx_status, 0600); ++ DEBUGFS_ADD_MODE(aql_enable, 0600); + + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 0600); +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1140,6 +1140,8 @@ enum mac80211_scan_state { + SCAN_ABORT, + }; + ++DECLARE_STATIC_KEY_FALSE(aql_disable); ++ + struct ieee80211_local { + /* embed the driver visible part. + * don't cast (use the static inlines below), but we keep +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3909,6 +3909,8 @@ void __ieee80211_schedule_txq(struct iee + } + EXPORT_SYMBOL(__ieee80211_schedule_txq); + ++DEFINE_STATIC_KEY_FALSE(aql_disable); ++ + bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +@@ -3918,6 +3920,9 @@ bool ieee80211_txq_airtime_check(struct + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) + return true; + ++ if (static_branch_unlikely(&aql_disable)) ++ return true; ++ + if (!txq->sta) + return true; + diff --git a/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch b/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch new file mode 100644 index 0000000000..708ad6f460 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch @@ -0,0 +1,39 @@ +From: Johannes Berg +Date: Fri, 18 Jun 2021 13:41:44 +0300 +Subject: [PATCH] mac80211: rearrange struct txq_info for fewer holes + +We can slightly decrease the size of struct txq_info by +rearranging some fields for fewer holes, so do that. + +Signed-off-by: Johannes Berg +Signed-off-by: Luca Coelho +Link: https://lore.kernel.org/r/iwlwifi.20210618133832.1bf019a1fe2e.Ib54622b8d6dc1a9a7dc484e573c073119450538b@changeid +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -5,7 +5,7 @@ + * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2010 Johannes Berg + * Copyright 2013-2015 Intel Mobile Communications GmbH +- * Copyright (C) 2018-2020 Intel Corporation ++ * Copyright (C) 2018-2021 Intel Corporation + */ + + #ifndef IEEE80211_I_H +@@ -848,9 +848,12 @@ struct txq_info { + struct fq_tin tin; + struct codel_vars def_cvars; + struct codel_stats cstats; +- struct sk_buff_head frags; +- struct list_head schedule_order; ++ + u16 schedule_round; ++ struct list_head schedule_order; ++ ++ struct sk_buff_head frags; ++ + unsigned long flags; + + /* keep last! */ diff --git a/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch b/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch new file mode 100644 index 0000000000..8b3d743b2f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch @@ -0,0 +1,1277 @@ +From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= +Date: Wed, 23 Jun 2021 15:47:55 +0200 +Subject: [PATCH] mac80211: Switch to a virtual time-based airtime scheduler +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This switches the airtime scheduler in mac80211 to use a virtual +time-based scheduler instead of the round-robin scheduler used before. +This has a couple of advantages: + +- No need to sync up the round-robin scheduler in firmware/hardware with + the round-robin airtime scheduler. + +- If several stations are eligible for transmission we can schedule both + of them; no need to hard-block the scheduling rotation until the head + of the queue has used up its quantum. + +- The check of whether a station is eligible for transmission becomes + simpler (in ieee80211_txq_may_transmit()). + +The drawback is that scheduling becomes slightly more expensive, as we +need to maintain an rbtree of TXQs sorted by virtual time. This means +that ieee80211_register_airtime() becomes O(logN) in the number of +currently scheduled TXQs because it can change the order of the +scheduled stations. We mitigate this overhead by only resorting when a +station changes position in the tree, and hopefully N rarely grows too +big (it's only TXQs currently backlogged, not all associated stations), +so it shouldn't be too big of an issue. + +To prevent divisions in the fast path, we maintain both station sums and +pre-computed reciprocals of the sums. This turns the fast-path operation +into a multiplication, with divisions only happening as the number of +active stations change (to re-compute the current sum of all active +station weights). To prevent this re-computation of the reciprocal from +happening too frequently, we use a time-based notion of station +activity, instead of updating the weight every time a station gets +scheduled or de-scheduled. As queues can oscillate between empty and +occupied quite frequently, this can significantly cut down on the number +of re-computations. It also has the added benefit of making the station +airtime calculation independent on whether the queue happened to have +drained at the time an airtime value was accounted. + +Co-developed-by: Yibo Zhao +Signed-off-by: Yibo Zhao +Signed-off-by: Toke Høiland-Jørgensen +Link: https://lore.kernel.org/r/20210623134755.235545-1-toke@redhat.com +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6557,9 +6557,6 @@ static inline void ieee80211_txq_schedul + { + } + +-void __ieee80211_schedule_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq, bool force); +- + /** + * ieee80211_schedule_txq - schedule a TXQ for transmission + * +@@ -6572,11 +6569,7 @@ void __ieee80211_schedule_txq(struct iee + * The driver may call this function if it has buffered packets for + * this TXQ internally. + */ +-static inline void +-ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) +-{ +- __ieee80211_schedule_txq(hw, txq, true); +-} ++void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); + + /** + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() +@@ -6588,12 +6581,8 @@ ieee80211_schedule_txq(struct ieee80211_ + * The driver may set force=true if it has buffered packets for this TXQ + * internally. + */ +-static inline void +-ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, +- bool force) +-{ +- __ieee80211_schedule_txq(hw, txq, force); +-} ++void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, ++ bool force); + + /** + * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1461,6 +1461,38 @@ static void sta_apply_mesh_params(struct + #endif + } + ++static void sta_apply_airtime_params(struct ieee80211_local *local, ++ struct sta_info *sta, ++ struct station_parameters *params) ++{ ++ u8 ac; ++ ++ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { ++ struct airtime_sched_info *air_sched = &local->airtime[ac]; ++ struct airtime_info *air_info = &sta->airtime[ac]; ++ struct txq_info *txqi; ++ u8 tid; ++ ++ spin_lock_bh(&air_sched->lock); ++ for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) { ++ if (air_info->weight == params->airtime_weight || ++ !sta->sta.txq[tid] || ++ ac != ieee80211_ac_from_tid(tid)) ++ continue; ++ ++ airtime_weight_set(air_info, params->airtime_weight); ++ ++ txqi = to_txq_info(sta->sta.txq[tid]); ++ if (RB_EMPTY_NODE(&txqi->schedule_order)) ++ continue; ++ ++ ieee80211_update_airtime_weight(local, air_sched, ++ 0, true); ++ } ++ spin_unlock_bh(&air_sched->lock); ++ } ++} ++ + static int sta_apply_parameters(struct ieee80211_local *local, + struct sta_info *sta, + struct station_parameters *params) +@@ -1648,7 +1680,8 @@ static int sta_apply_parameters(struct i + sta_apply_mesh_params(local, sta, params); + + if (params->airtime_weight) +- sta->airtime_weight = params->airtime_weight; ++ sta_apply_airtime_params(local, sta, params); ++ + + /* set the STA state after all sta info from usermode has been set */ + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) || +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct + "VI %u %u\n" + "BE %u %u\n" + "BK %u %u\n", +- local->aql_txq_limit_low[IEEE80211_AC_VO], +- local->aql_txq_limit_high[IEEE80211_AC_VO], +- local->aql_txq_limit_low[IEEE80211_AC_VI], +- local->aql_txq_limit_high[IEEE80211_AC_VI], +- local->aql_txq_limit_low[IEEE80211_AC_BE], +- local->aql_txq_limit_high[IEEE80211_AC_BE], +- local->aql_txq_limit_low[IEEE80211_AC_BK], +- local->aql_txq_limit_high[IEEE80211_AC_BK]); ++ local->airtime[IEEE80211_AC_VO].aql_txq_limit_low, ++ local->airtime[IEEE80211_AC_VO].aql_txq_limit_high, ++ local->airtime[IEEE80211_AC_VI].aql_txq_limit_low, ++ local->airtime[IEEE80211_AC_VI].aql_txq_limit_high, ++ local->airtime[IEEE80211_AC_BE].aql_txq_limit_low, ++ local->airtime[IEEE80211_AC_BE].aql_txq_limit_high, ++ local->airtime[IEEE80211_AC_BK].aql_txq_limit_low, ++ local->airtime[IEEE80211_AC_BK].aql_txq_limit_high); + return simple_read_from_buffer(user_buf, count, ppos, + buf, len); + } +@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc + if (ac >= IEEE80211_NUM_ACS) + return -EINVAL; + +- q_limit_low_old = local->aql_txq_limit_low[ac]; +- q_limit_high_old = local->aql_txq_limit_high[ac]; ++ q_limit_low_old = local->airtime[ac].aql_txq_limit_low; ++ q_limit_high_old = local->airtime[ac].aql_txq_limit_high; + +- local->aql_txq_limit_low[ac] = q_limit_low; +- local->aql_txq_limit_high[ac] = q_limit_high; ++ local->airtime[ac].aql_txq_limit_low = q_limit_low; ++ local->airtime[ac].aql_txq_limit_high = q_limit_high; + + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { +@@ -382,6 +382,46 @@ static const struct file_operations forc + .llseek = default_llseek, + }; + ++static ssize_t airtime_read(struct file *file, ++ char __user *user_buf, ++ size_t count, ++ loff_t *ppos) ++{ ++ struct ieee80211_local *local = file->private_data; ++ char buf[200]; ++ u64 v_t[IEEE80211_NUM_ACS]; ++ u64 wt[IEEE80211_NUM_ACS]; ++ int len = 0, ac; ++ ++ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { ++ spin_lock_bh(&local->airtime[ac].lock); ++ v_t[ac] = local->airtime[ac].v_t; ++ wt[ac] = local->airtime[ac].weight_sum; ++ spin_unlock_bh(&local->airtime[ac].lock); ++ } ++ len = scnprintf(buf, sizeof(buf), ++ "\tVO VI BE BK\n" ++ "Virt-t\t%-10llu %-10llu %-10llu %-10llu\n" ++ "Weight\t%-10llu %-10llu %-10llu %-10llu\n", ++ v_t[0], ++ v_t[1], ++ v_t[2], ++ v_t[3], ++ wt[0], ++ wt[1], ++ wt[2], ++ wt[3]); ++ ++ return simple_read_from_buffer(user_buf, count, ppos, ++ buf, len); ++} ++ ++static const struct file_operations airtime_ops = { ++ .read = airtime_read, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ + #ifdef CONFIG_PM + static ssize_t reset_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +@@ -624,7 +664,11 @@ void debugfs_hw_add(struct ieee80211_loc + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 0600); + +- DEBUGFS_ADD_MODE(airtime_flags, 0600); ++ if (wiphy_ext_feature_isset(local->hw.wiphy, ++ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { ++ DEBUGFS_ADD_MODE(airtime, 0600); ++ DEBUGFS_ADD_MODE(airtime_flags, 0600); ++ } + + DEBUGFS_ADD(aql_txq_limit); + debugfs_create_u32("aql_threshold", 0600, +--- a/net/mac80211/debugfs_netdev.c ++++ b/net/mac80211/debugfs_netdev.c +@@ -513,6 +513,34 @@ static ssize_t ieee80211_if_fmt_aqm( + } + IEEE80211_IF_FILE_R(aqm); + ++static ssize_t ieee80211_if_fmt_airtime( ++ const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_txq *txq = sdata->vif.txq; ++ struct airtime_info *air_info; ++ int len; ++ ++ if (!txq) ++ return 0; ++ ++ spin_lock_bh(&local->airtime[txq->ac].lock); ++ air_info = to_airtime_info(txq); ++ len = scnprintf(buf, ++ buflen, ++ "RX: %llu us\nTX: %llu us\nWeight: %u\n" ++ "Virt-T: %lld us\n", ++ air_info->rx_airtime, ++ air_info->tx_airtime, ++ air_info->weight, ++ air_info->v_t); ++ spin_unlock_bh(&local->airtime[txq->ac].lock); ++ ++ return len; ++} ++ ++IEEE80211_IF_FILE_R(airtime); ++ + IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX); + + /* IBSS attributes */ +@@ -661,8 +689,10 @@ static void add_common_files(struct ieee + + if (sdata->local->ops->wake_tx_queue && + sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE && +- sdata->vif.type != NL80211_IFTYPE_NAN) ++ sdata->vif.type != NL80211_IFTYPE_NAN) { + DEBUGFS_ADD(aqm); ++ DEBUGFS_ADD(airtime); ++ } + } + + static void add_sta_files(struct ieee80211_sub_if_data *sdata) +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f + size_t bufsz = 400; + char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; + u64 rx_airtime = 0, tx_airtime = 0; +- s64 deficit[IEEE80211_NUM_ACS]; ++ u64 v_t[IEEE80211_NUM_ACS]; + ssize_t rv; + int ac; + +@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f + return -ENOMEM; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->active_txq_lock[ac]); ++ spin_lock_bh(&local->airtime[ac].lock); + rx_airtime += sta->airtime[ac].rx_airtime; + tx_airtime += sta->airtime[ac].tx_airtime; +- deficit[ac] = sta->airtime[ac].deficit; +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ v_t[ac] = sta->airtime[ac].v_t; ++ spin_unlock_bh(&local->airtime[ac].lock); + } + + p += scnprintf(p, bufsz + buf - p, + "RX: %llu us\nTX: %llu us\nWeight: %u\n" +- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", +- rx_airtime, tx_airtime, sta->airtime_weight, +- deficit[0], deficit[1], deficit[2], deficit[3]); ++ "Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n", ++ rx_airtime, tx_airtime, sta->airtime[0].weight, ++ v_t[0], v_t[1], v_t[2], v_t[3]); + + rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); + kfree(buf); +@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct + int ac; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->active_txq_lock[ac]); ++ spin_lock_bh(&local->airtime[ac].lock); + sta->airtime[ac].rx_airtime = 0; + sta->airtime[ac].tx_airtime = 0; +- sta->airtime[ac].deficit = sta->airtime_weight; +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ sta->airtime[ac].v_t = 0; ++ spin_unlock_bh(&local->airtime[ac].lock); + } + + return count; +@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file + return -ENOMEM; + + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { +- spin_lock_bh(&local->active_txq_lock[ac]); ++ spin_lock_bh(&local->airtime[ac].lock); + q_limit_l[ac] = sta->airtime[ac].aql_limit_low; + q_limit_h[ac] = sta->airtime[ac].aql_limit_high; +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ spin_unlock_bh(&local->airtime[ac].lock); + q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); + } + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -840,20 +840,16 @@ enum txq_info_flags { + * @def_flow: used as a fallback flow when a packet destined to @tin hashes to + * a fq_flow which is already owned by a different tin + * @def_cvars: codel vars for @def_flow +- * @frags: used to keep fragments created after dequeue + * @schedule_order: used with ieee80211_local->active_txqs +- * @schedule_round: counter to prevent infinite loops on TXQ scheduling ++ * @frags: used to keep fragments created after dequeue + */ + struct txq_info { + struct fq_tin tin; + struct codel_vars def_cvars; + struct codel_stats cstats; +- +- u16 schedule_round; +- struct list_head schedule_order; ++ struct rb_node schedule_order; + + struct sk_buff_head frags; +- + unsigned long flags; + + /* keep last! */ +@@ -930,6 +926,8 @@ struct ieee80211_sub_if_data { + struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS]; + struct mac80211_qos_map __rcu *qos_map; + ++ struct airtime_info airtime[IEEE80211_NUM_ACS]; ++ + struct work_struct csa_finalize_work; + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; +@@ -1143,6 +1141,44 @@ enum mac80211_scan_state { + SCAN_ABORT, + }; + ++/** ++ * struct airtime_sched_info - state used for airtime scheduling and AQL ++ * ++ * @lock: spinlock that protects all the fields in this struct ++ * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time ++ * @schedule_pos: the current position maintained while a driver walks the tree ++ * with ieee80211_next_txq() ++ * @active_list: list of struct airtime_info structs that were active within ++ * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute ++ * weight_sum ++ * @last_weight_update: used for rate limiting walking active_list ++ * @last_schedule_time: tracks the last time a transmission was scheduled; used ++ * for catching up v_t if no stations are eligible for ++ * transmission. ++ * @v_t: global virtual time; queues with v_t < this are eligible for ++ * transmission ++ * @weight_sum: total sum of all active stations used for dividing airtime ++ * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast ++ * path - see comment above ++ * IEEE80211_RECIPROCAL_DIVISOR_64) ++ * @aql_txq_limit_low: AQL limit when total outstanding airtime ++ * is < IEEE80211_AQL_THRESHOLD ++ * @aql_txq_limit_high: AQL limit when total outstanding airtime ++ * is > IEEE80211_AQL_THRESHOLD ++ */ ++struct airtime_sched_info { ++ spinlock_t lock; ++ struct rb_root_cached active_txqs; ++ struct rb_node *schedule_pos; ++ struct list_head active_list; ++ u64 last_weight_update; ++ u64 last_schedule_activity; ++ u64 v_t; ++ u64 weight_sum; ++ u64 weight_sum_reciprocal; ++ u32 aql_txq_limit_low; ++ u32 aql_txq_limit_high; ++}; + DECLARE_STATIC_KEY_FALSE(aql_disable); + + struct ieee80211_local { +@@ -1156,13 +1192,8 @@ struct ieee80211_local { + struct codel_params cparams; + + /* protects active_txqs and txqi->schedule_order */ +- spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; +- struct list_head active_txqs[IEEE80211_NUM_ACS]; +- u16 schedule_round[IEEE80211_NUM_ACS]; +- ++ struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; + u16 airtime_flags; +- u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; +- u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; + u32 aql_threshold; + atomic_t aql_total_pending_airtime; + +@@ -1581,6 +1612,125 @@ static inline bool txq_has_queue(struct + return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets); + } + ++static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq) ++{ ++ struct ieee80211_sub_if_data *sdata; ++ struct sta_info *sta; ++ ++ if (txq->sta) { ++ sta = container_of(txq->sta, struct sta_info, sta); ++ return &sta->airtime[txq->ac]; ++ } ++ ++ sdata = vif_to_sdata(txq->vif); ++ return &sdata->airtime[txq->ac]; ++} ++ ++/* To avoid divisions in the fast path, we keep pre-computed reciprocals for ++ * airtime weight calculations. There are two different weights to keep track ++ * of: The per-station weight and the sum of weights per phy. ++ * ++ * For the per-station weights (kept in airtime_info below), we use 32-bit ++ * reciprocals with a devisor of 2^19. This lets us keep the multiplications and ++ * divisions for the station weights as 32-bit operations at the cost of a bit ++ * of rounding error for high weights; but the choice of divisor keeps rounding ++ * errors <10% for weights <2^15, assuming no more than 8ms of airtime is ++ * reported at a time. ++ * ++ * For the per-phy sum of weights the values can get higher, so we use 64-bit ++ * operations for those with a 32-bit divisor, which should avoid any ++ * significant rounding errors. ++ */ ++#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL ++#define IEEE80211_RECIPROCAL_SHIFT_64 32 ++#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U ++#define IEEE80211_RECIPROCAL_SHIFT_32 19 ++ ++static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight) ++{ ++ if (air_info->weight == weight) ++ return; ++ ++ air_info->weight = weight; ++ if (weight) { ++ air_info->weight_reciprocal = ++ IEEE80211_RECIPROCAL_DIVISOR_32 / weight; ++ } else { ++ air_info->weight_reciprocal = 0; ++ } ++} ++ ++static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched, ++ int weight_sum) ++{ ++ if (air_sched->weight_sum == weight_sum) ++ return; ++ ++ air_sched->weight_sum = weight_sum; ++ if (air_sched->weight_sum) { ++ air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64; ++ do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum); ++ } else { ++ air_sched->weight_sum_reciprocal = 0; ++ } ++} ++ ++/* A problem when trying to enforce airtime fairness is that we want to divide ++ * the airtime between the currently *active* stations. However, basing this on ++ * the instantaneous queue state of stations doesn't work, as queues tend to ++ * oscillate very quickly between empty and occupied, leading to the scheduler ++ * thinking only a single station is active when deciding whether to allow ++ * transmission (and thus not throttling correctly). ++ * ++ * To fix this we use a timer-based notion of activity: a station is considered ++ * active if it has been scheduled within the last 100 ms; we keep a separate ++ * list of all the stations considered active in this manner, and lazily update ++ * the total weight of active stations from this list (filtering the stations in ++ * the list by their 'last active' time). ++ * ++ * We add one additional safeguard to guard against stations that manage to get ++ * scheduled every 100 ms but don't transmit a lot of data, and thus don't use ++ * up any airtime. Such stations would be able to get priority for an extended ++ * period of time if they do start transmitting at full capacity again, and so ++ * we add an explicit maximum for how far behind a station is allowed to fall in ++ * the virtual airtime domain. This limit is set to a relatively high value of ++ * 20 ms because the main mechanism for catching up idle stations is the active ++ * state as described above; i.e., the hard limit should only be hit in ++ * pathological cases. ++ */ ++#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC) ++#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */ ++ ++static inline bool airtime_is_active(struct airtime_info *air_info, u64 now) ++{ ++ return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION; ++} ++ ++static inline void airtime_set_active(struct airtime_sched_info *air_sched, ++ struct airtime_info *air_info, u64 now) ++{ ++ air_info->last_scheduled = now; ++ air_sched->last_schedule_activity = now; ++ list_move_tail(&air_info->list, &air_sched->active_list); ++} ++ ++static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched, ++ u64 v_t, u64 now) ++{ ++ air_sched->v_t = v_t; ++ return true; ++} ++ ++static inline void init_airtime_info(struct airtime_info *air_info, ++ struct airtime_sched_info *air_sched) ++{ ++ atomic_set(&air_info->aql_tx_pending, 0); ++ air_info->aql_limit_low = air_sched->aql_txq_limit_low; ++ air_info->aql_limit_high = air_sched->aql_txq_limit_high; ++ airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT); ++ INIT_LIST_HEAD(&air_info->list); ++} ++ + static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) + { + return ether_addr_equal(raddr, addr) || +@@ -1821,6 +1971,14 @@ int ieee80211_tx_control_port(struct wip + u64 *cookie); + int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, + const u8 *buf, size_t len); ++void ieee80211_resort_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq); ++void ieee80211_unschedule_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq, ++ bool purge); ++void ieee80211_update_airtime_weight(struct ieee80211_local *local, ++ struct airtime_sched_info *air_sched, ++ u64 now, bool force); + + /* HT */ + void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -2088,6 +2088,9 @@ int ieee80211_if_add(struct ieee80211_lo + } + } + ++ for (i = 0; i < IEEE80211_NUM_ACS; i++) ++ init_airtime_info(&sdata->airtime[i], &local->airtime[i]); ++ + ieee80211_set_default_queues(sdata); + + sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -693,10 +693,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + spin_lock_init(&local->queue_stop_reason_lock); + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { +- INIT_LIST_HEAD(&local->active_txqs[i]); +- spin_lock_init(&local->active_txq_lock[i]); +- local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; +- local->aql_txq_limit_high[i] = ++ struct airtime_sched_info *air_sched = &local->airtime[i]; ++ ++ air_sched->active_txqs = RB_ROOT_CACHED; ++ INIT_LIST_HEAD(&air_sched->active_list); ++ spin_lock_init(&air_sched->lock); ++ air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; ++ air_sched->aql_txq_limit_high = + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1573,12 +1573,8 @@ static void sta_ps_start(struct sta_info + + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { + struct ieee80211_txq *txq = sta->sta.txq[tid]; +- struct txq_info *txqi = to_txq_info(txq); + +- spin_lock(&local->active_txq_lock[txq->ac]); +- if (!list_empty(&txqi->schedule_order)) +- list_del_init(&txqi->schedule_order); +- spin_unlock(&local->active_txq_lock[txq->ac]); ++ ieee80211_unschedule_txq(&local->hw, txq, false); + + if (txq_has_queue(txq)) + set_bit(tid, &sta->txq_buffered_tids); +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -426,15 +426,11 @@ struct sta_info *sta_info_alloc(struct i + if (sta_prepare_rate_control(local, sta, gfp)) + goto free_txq; + +- sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + skb_queue_head_init(&sta->ps_tx_buf[i]); + skb_queue_head_init(&sta->tx_filtered[i]); +- sta->airtime[i].deficit = sta->airtime_weight; +- atomic_set(&sta->airtime[i].aql_tx_pending, 0); +- sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; +- sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; ++ init_airtime_info(&sta->airtime[i], &local->airtime[i]); + } + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) +@@ -1893,24 +1889,59 @@ void ieee80211_sta_set_buffered(struct i + } + EXPORT_SYMBOL(ieee80211_sta_set_buffered); + +-void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, +- u32 tx_airtime, u32 rx_airtime) ++void ieee80211_register_airtime(struct ieee80211_txq *txq, ++ u32 tx_airtime, u32 rx_airtime) + { +- struct sta_info *sta = container_of(pubsta, struct sta_info, sta); +- struct ieee80211_local *local = sta->sdata->local; +- u8 ac = ieee80211_ac_from_tid(tid); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif); ++ struct ieee80211_local *local = sdata->local; ++ u64 weight_sum, weight_sum_reciprocal; ++ struct airtime_sched_info *air_sched; ++ struct airtime_info *air_info; + u32 airtime = 0; + +- if (sta->local->airtime_flags & AIRTIME_USE_TX) ++ air_sched = &local->airtime[txq->ac]; ++ air_info = to_airtime_info(txq); ++ ++ if (local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; +- if (sta->local->airtime_flags & AIRTIME_USE_RX) ++ if (local->airtime_flags & AIRTIME_USE_RX) + airtime += rx_airtime; + +- spin_lock_bh(&local->active_txq_lock[ac]); +- sta->airtime[ac].tx_airtime += tx_airtime; +- sta->airtime[ac].rx_airtime += rx_airtime; +- sta->airtime[ac].deficit -= airtime; +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ /* Weights scale so the unit weight is 256 */ ++ airtime <<= 8; ++ ++ spin_lock_bh(&air_sched->lock); ++ ++ air_info->tx_airtime += tx_airtime; ++ air_info->rx_airtime += rx_airtime; ++ ++ if (air_sched->weight_sum) { ++ weight_sum = air_sched->weight_sum; ++ weight_sum_reciprocal = air_sched->weight_sum_reciprocal; ++ } else { ++ weight_sum = air_info->weight; ++ weight_sum_reciprocal = air_info->weight_reciprocal; ++ } ++ ++ /* Round the calculation of global vt */ ++ air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) * ++ weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64; ++ air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) * ++ air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32; ++ ieee80211_resort_txq(&local->hw, txq); ++ ++ spin_unlock_bh(&air_sched->lock); ++} ++ ++void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, ++ u32 tx_airtime, u32 rx_airtime) ++{ ++ struct ieee80211_txq *txq = pubsta->txq[tid]; ++ ++ if (!txq) ++ return; ++ ++ ieee80211_register_airtime(txq, tx_airtime, rx_airtime); + } + EXPORT_SYMBOL(ieee80211_sta_register_airtime); + +@@ -2354,7 +2385,7 @@ void sta_set_sinfo(struct sta_info *sta, + } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { +- sinfo->airtime_weight = sta->airtime_weight; ++ sinfo->airtime_weight = sta->airtime[0].weight; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); + } + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -135,18 +135,25 @@ enum ieee80211_agg_stop_reason { + #define AIRTIME_USE_TX BIT(0) + #define AIRTIME_USE_RX BIT(1) + ++ + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; +- s64 deficit; ++ u64 v_t; ++ u64 last_scheduled; ++ struct list_head list; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; + u32 aql_limit_high; ++ u32 weight_reciprocal; ++ u16 weight; + }; + + void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, + struct sta_info *sta, u8 ac, + u16 tx_airtime, bool tx_completed); ++void ieee80211_register_airtime(struct ieee80211_txq *txq, ++ u32 tx_airtime, u32 rx_airtime); + + struct sta_info; + +@@ -516,7 +523,6 @@ struct ieee80211_fragment_cache { + * @tid_seq: per-TID sequence numbers for sending to this STA + * @airtime: per-AC struct airtime_info describing airtime statistics for this + * station +- * @airtime_weight: station weight for airtime fairness calculation purposes + * @ampdu_mlme: A-MPDU state machine state + * @mesh: mesh STA information + * @debugfs_dir: debug filesystem directory dentry +@@ -647,7 +653,6 @@ struct sta_info { + u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; + + struct airtime_info airtime[IEEE80211_NUM_ACS]; +- u16 airtime_weight; + + /* + * Aggregation information, locked with lock. +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -972,6 +972,25 @@ static void __ieee80211_tx_status(struct + if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) + ieee80211_frame_acked(sta, skb); + ++ } else if (wiphy_ext_feature_isset(local->hw.wiphy, ++ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) { ++ struct ieee80211_sub_if_data *sdata; ++ struct ieee80211_txq *txq; ++ u32 airtime; ++ ++ /* Account airtime to multicast queue */ ++ sdata = ieee80211_sdata_from_skb(local, skb); ++ ++ if (sdata && (txq = sdata->vif.txq)) { ++ airtime = info->status.tx_time ?: ++ ieee80211_calc_expected_tx_airtime(hw, ++ &sdata->vif, ++ NULL, ++ skb->len, ++ false); ++ ++ ieee80211_register_airtime(txq, airtime, 0); ++ } + } + + /* SNMP counters +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1489,7 +1490,7 @@ void ieee80211_txq_init(struct ieee80211 + codel_vars_init(&txqi->def_cvars); + codel_stats_init(&txqi->cstats); + __skb_queue_head_init(&txqi->frags); +- INIT_LIST_HEAD(&txqi->schedule_order); ++ RB_CLEAR_NODE(&txqi->schedule_order); + + txqi->txq.vif = &sdata->vif; + +@@ -1533,9 +1534,7 @@ void ieee80211_txq_purge(struct ieee8021 + ieee80211_purge_tx_queue(&local->hw, &txqi->frags); + spin_unlock_bh(&fq->lock); + +- spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]); +- list_del_init(&txqi->schedule_order); +- spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]); ++ ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); + } + + void ieee80211_txq_set_params(struct ieee80211_local *local) +@@ -3819,102 +3818,259 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue); + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); ++ struct airtime_sched_info *air_sched; ++ u64 now = ktime_get_boottime_ns(); + struct ieee80211_txq *ret = NULL; +- struct txq_info *txqi = NULL, *head = NULL; +- bool found_eligible_txq = false; ++ struct airtime_info *air_info; ++ struct txq_info *txqi = NULL; ++ struct rb_node *node; ++ bool first = false; + +- spin_lock_bh(&local->active_txq_lock[ac]); ++ air_sched = &local->airtime[ac]; ++ spin_lock_bh(&air_sched->lock); + +- begin: +- txqi = list_first_entry_or_null(&local->active_txqs[ac], +- struct txq_info, +- schedule_order); +- if (!txqi) ++ node = air_sched->schedule_pos; ++ ++begin: ++ if (!node) { ++ node = rb_first_cached(&air_sched->active_txqs); ++ first = true; ++ } else { ++ node = rb_next(node); ++ } ++ ++ if (!node) + goto out; + +- if (txqi == head) { +- if (!found_eligible_txq) +- goto out; +- else +- found_eligible_txq = false; ++ txqi = container_of(node, struct txq_info, schedule_order); ++ air_info = to_airtime_info(&txqi->txq); ++ ++ if (air_info->v_t > air_sched->v_t && ++ (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now))) ++ goto out; ++ ++ if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { ++ first = false; ++ goto begin; + } + +- if (!head) +- head = txqi; ++ air_sched->schedule_pos = node; ++ air_sched->last_schedule_activity = now; ++ ret = &txqi->txq; ++out: ++ spin_unlock_bh(&air_sched->lock); ++ return ret; ++} ++EXPORT_SYMBOL(ieee80211_next_txq); + +- if (txqi->txq.sta) { +- struct sta_info *sta = container_of(txqi->txq.sta, +- struct sta_info, sta); +- bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); +- s64 deficit = sta->airtime[txqi->txq.ac].deficit; ++static void __ieee80211_insert_txq(struct rb_root_cached *root, ++ struct txq_info *txqi) ++{ ++ struct rb_node **new = &root->rb_root.rb_node; ++ struct airtime_info *old_air, *new_air; ++ struct rb_node *parent = NULL; ++ struct txq_info *__txqi; ++ bool leftmost = true; ++ ++ while (*new) { ++ parent = *new; ++ __txqi = rb_entry(parent, struct txq_info, schedule_order); ++ old_air = to_airtime_info(&__txqi->txq); ++ new_air = to_airtime_info(&txqi->txq); + +- if (aql_check) +- found_eligible_txq = true; ++ if (new_air->v_t <= old_air->v_t) { ++ new = &parent->rb_left; ++ } else { ++ new = &parent->rb_right; ++ leftmost = false; ++ } ++ } + +- if (deficit < 0) +- sta->airtime[txqi->txq.ac].deficit += +- sta->airtime_weight; +- +- if (deficit < 0 || !aql_check) { +- list_move_tail(&txqi->schedule_order, +- &local->active_txqs[txqi->txq.ac]); +- goto begin; ++ rb_link_node(&txqi->schedule_order, parent, new); ++ rb_insert_color_cached(&txqi->schedule_order, root, leftmost); ++} ++ ++void ieee80211_resort_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq) ++{ ++ struct airtime_info *air_info = to_airtime_info(txq); ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct txq_info *txqi = to_txq_info(txq); ++ struct airtime_sched_info *air_sched; ++ ++ air_sched = &local->airtime[txq->ac]; ++ ++ lockdep_assert_held(&air_sched->lock); ++ ++ if (!RB_EMPTY_NODE(&txqi->schedule_order)) { ++ struct airtime_info *a_prev = NULL, *a_next = NULL; ++ struct txq_info *t_prev, *t_next; ++ struct rb_node *n_prev, *n_next; ++ ++ /* Erasing a node can cause an expensive rebalancing operation, ++ * so we check the previous and next nodes first and only remove ++ * and re-insert if the current node is not already in the ++ * correct position. ++ */ ++ if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) { ++ t_prev = container_of(n_prev, struct txq_info, ++ schedule_order); ++ a_prev = to_airtime_info(&t_prev->txq); ++ } ++ ++ if ((n_next = rb_next(&txqi->schedule_order)) != NULL) { ++ t_next = container_of(n_next, struct txq_info, ++ schedule_order); ++ a_next = to_airtime_info(&t_next->txq); + } ++ ++ if ((!a_prev || a_prev->v_t <= air_info->v_t) && ++ (!a_next || a_next->v_t > air_info->v_t)) ++ return; ++ ++ if (air_sched->schedule_pos == &txqi->schedule_order) ++ air_sched->schedule_pos = n_prev; ++ ++ rb_erase_cached(&txqi->schedule_order, ++ &air_sched->active_txqs); ++ RB_CLEAR_NODE(&txqi->schedule_order); ++ __ieee80211_insert_txq(&air_sched->active_txqs, txqi); + } ++} ++ ++void ieee80211_update_airtime_weight(struct ieee80211_local *local, ++ struct airtime_sched_info *air_sched, ++ u64 now, bool force) ++{ ++ struct airtime_info *air_info, *tmp; ++ u64 weight_sum = 0; ++ ++ if (unlikely(!now)) ++ now = ktime_get_boottime_ns(); ++ ++ lockdep_assert_held(&air_sched->lock); ++ ++ if (!force && (air_sched->last_weight_update < ++ now - AIRTIME_ACTIVE_DURATION)) ++ return; ++ ++ list_for_each_entry_safe(air_info, tmp, ++ &air_sched->active_list, list) { ++ if (airtime_is_active(air_info, now)) ++ weight_sum += air_info->weight; ++ else ++ list_del_init(&air_info->list); ++ } ++ airtime_weight_sum_set(air_sched, weight_sum); ++ air_sched->last_weight_update = now; ++} + ++void ieee80211_schedule_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq) ++ __acquires(txq_lock) __releases(txq_lock) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct txq_info *txqi = to_txq_info(txq); ++ struct airtime_sched_info *air_sched; ++ u64 now = ktime_get_boottime_ns(); ++ struct airtime_info *air_info; ++ u8 ac = txq->ac; ++ bool was_active; + +- if (txqi->schedule_round == local->schedule_round[ac]) ++ air_sched = &local->airtime[ac]; ++ air_info = to_airtime_info(txq); ++ ++ spin_lock_bh(&air_sched->lock); ++ was_active = airtime_is_active(air_info, now); ++ airtime_set_active(air_sched, air_info, now); ++ ++ if (!RB_EMPTY_NODE(&txqi->schedule_order)) + goto out; + +- list_del_init(&txqi->schedule_order); +- txqi->schedule_round = local->schedule_round[ac]; +- ret = &txqi->txq; ++ /* If the station has been inactive for a while, catch up its v_t so it ++ * doesn't get indefinite priority; see comment above the definition of ++ * AIRTIME_MAX_BEHIND. ++ */ ++ if ((!was_active && air_info->v_t < air_sched->v_t) || ++ air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND) ++ air_info->v_t = air_sched->v_t; ++ ++ ieee80211_update_airtime_weight(local, air_sched, now, !was_active); ++ __ieee80211_insert_txq(&air_sched->active_txqs, txqi); + + out: +- spin_unlock_bh(&local->active_txq_lock[ac]); +- return ret; ++ spin_unlock_bh(&air_sched->lock); + } +-EXPORT_SYMBOL(ieee80211_next_txq); ++EXPORT_SYMBOL(ieee80211_schedule_txq); + +-void __ieee80211_schedule_txq(struct ieee80211_hw *hw, +- struct ieee80211_txq *txq, +- bool force) ++static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq, ++ bool purge) + { + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); ++ struct airtime_sched_info *air_sched; ++ struct airtime_info *air_info; + +- spin_lock_bh(&local->active_txq_lock[txq->ac]); ++ air_sched = &local->airtime[txq->ac]; ++ air_info = to_airtime_info(&txqi->txq); + +- if (list_empty(&txqi->schedule_order) && +- (force || !skb_queue_empty(&txqi->frags) || +- txqi->tin.backlog_packets)) { +- /* If airtime accounting is active, always enqueue STAs at the +- * head of the list to ensure that they only get moved to the +- * back by the airtime DRR scheduler once they have a negative +- * deficit. A station that already has a negative deficit will +- * get immediately moved to the back of the list on the next +- * call to ieee80211_next_txq(). +- */ +- if (txqi->txq.sta && local->airtime_flags && +- wiphy_ext_feature_isset(local->hw.wiphy, +- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) +- list_add(&txqi->schedule_order, +- &local->active_txqs[txq->ac]); +- else +- list_add_tail(&txqi->schedule_order, +- &local->active_txqs[txq->ac]); ++ lockdep_assert_held(&air_sched->lock); ++ ++ if (purge) { ++ list_del_init(&air_info->list); ++ ieee80211_update_airtime_weight(local, air_sched, 0, true); + } + +- spin_unlock_bh(&local->active_txq_lock[txq->ac]); ++ if (RB_EMPTY_NODE(&txqi->schedule_order)) ++ return; ++ ++ if (air_sched->schedule_pos == &txqi->schedule_order) ++ air_sched->schedule_pos = rb_prev(&txqi->schedule_order); ++ ++ if (!purge) ++ airtime_set_active(air_sched, air_info, ++ ktime_get_boottime_ns()); ++ ++ rb_erase_cached(&txqi->schedule_order, ++ &air_sched->active_txqs); ++ RB_CLEAR_NODE(&txqi->schedule_order); ++} ++ ++void ieee80211_unschedule_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq, ++ bool purge) ++ __acquires(txq_lock) __releases(txq_lock) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ ++ spin_lock_bh(&local->airtime[txq->ac].lock); ++ __ieee80211_unschedule_txq(hw, txq, purge); ++ spin_unlock_bh(&local->airtime[txq->ac].lock); ++} ++ ++void ieee80211_return_txq(struct ieee80211_hw *hw, ++ struct ieee80211_txq *txq, bool force) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct txq_info *txqi = to_txq_info(txq); ++ ++ spin_lock_bh(&local->airtime[txq->ac].lock); ++ ++ if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && ++ !txq_has_queue(txq)) ++ __ieee80211_unschedule_txq(hw, txq, false); ++ ++ spin_unlock_bh(&local->airtime[txq->ac].lock); + } +-EXPORT_SYMBOL(__ieee80211_schedule_txq); ++EXPORT_SYMBOL(ieee80211_return_txq); + + DEFINE_STATIC_KEY_FALSE(aql_disable); + + bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +- struct sta_info *sta; ++ struct airtime_info *air_info = to_airtime_info(txq); + struct ieee80211_local *local = hw_to_local(hw); + + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) +@@ -3929,15 +4085,12 @@ bool ieee80211_txq_airtime_check(struct + if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) + return true; + +- sta = container_of(txq->sta, struct sta_info, sta); +- if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < +- sta->airtime[txq->ac].aql_limit_low) ++ if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) + return true; + + if (atomic_read(&local->aql_total_pending_airtime) < + local->aql_threshold && +- atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < +- sta->airtime[txq->ac].aql_limit_high) ++ atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) + return true; + + return false; +@@ -3947,60 +4100,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec + bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { ++ struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq); + struct ieee80211_local *local = hw_to_local(hw); +- struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); +- struct sta_info *sta; +- u8 ac = txq->ac; ++ struct airtime_sched_info *air_sched; ++ struct airtime_info *air_info; ++ struct rb_node *node = NULL; ++ bool ret = false; ++ u64 now; + +- spin_lock_bh(&local->active_txq_lock[ac]); + +- if (!txqi->txq.sta) +- goto out; ++ if (!ieee80211_txq_airtime_check(hw, txq)) ++ return false; ++ ++ air_sched = &local->airtime[txq->ac]; ++ spin_lock_bh(&air_sched->lock); + +- if (list_empty(&txqi->schedule_order)) ++ if (RB_EMPTY_NODE(&txqi->schedule_order)) + goto out; + +- list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], +- schedule_order) { +- if (iter == txqi) +- break; ++ now = ktime_get_boottime_ns(); + +- if (!iter->txq.sta) { +- list_move_tail(&iter->schedule_order, +- &local->active_txqs[ac]); +- continue; +- } +- sta = container_of(iter->txq.sta, struct sta_info, sta); +- if (sta->airtime[ac].deficit < 0) +- sta->airtime[ac].deficit += sta->airtime_weight; +- list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); ++ /* Like in ieee80211_next_txq(), make sure the first station in the ++ * scheduling order is eligible for transmission to avoid starvation. ++ */ ++ node = rb_first_cached(&air_sched->active_txqs); ++ if (node) { ++ first_txqi = container_of(node, struct txq_info, ++ schedule_order); ++ air_info = to_airtime_info(&first_txqi->txq); ++ ++ if (air_sched->v_t < air_info->v_t) ++ airtime_catchup_v_t(air_sched, air_info->v_t, now); + } + +- sta = container_of(txqi->txq.sta, struct sta_info, sta); +- if (sta->airtime[ac].deficit >= 0) +- goto out; +- +- sta->airtime[ac].deficit += sta->airtime_weight; +- list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]); +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ air_info = to_airtime_info(&txqi->txq); ++ if (air_info->v_t <= air_sched->v_t) { ++ air_sched->last_schedule_activity = now; ++ ret = true; ++ } + +- return false; + out: +- if (!list_empty(&txqi->schedule_order)) +- list_del_init(&txqi->schedule_order); +- spin_unlock_bh(&local->active_txq_lock[ac]); +- +- return true; ++ spin_unlock_bh(&air_sched->lock); ++ return ret; + } + EXPORT_SYMBOL(ieee80211_txq_may_transmit); + + void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); ++ struct airtime_sched_info *air_sched = &local->airtime[ac]; + +- spin_lock_bh(&local->active_txq_lock[ac]); +- local->schedule_round[ac]++; +- spin_unlock_bh(&local->active_txq_lock[ac]); ++ spin_lock_bh(&air_sched->lock); ++ air_sched->schedule_pos = NULL; ++ spin_unlock_bh(&air_sched->lock); + } + EXPORT_SYMBOL(ieee80211_txq_schedule_start); + diff --git a/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch b/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch new file mode 100644 index 0000000000..a47e29794c --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/384-nl80211-add-common-API-to-configure-SAR-power-limita.patch @@ -0,0 +1,398 @@ +From: Carl Huang +Date: Thu, 3 Dec 2020 05:37:26 -0500 +Subject: [PATCH] nl80211: add common API to configure SAR power limitations + +NL80211_CMD_SET_SAR_SPECS is added to configure SAR from +user space. NL80211_ATTR_SAR_SPEC is used to pass the SAR +power specification when used with NL80211_CMD_SET_SAR_SPECS. + +Wireless driver needs to register SAR type, supported frequency +ranges to wiphy, so user space can query it. The index in +frequency range is used to specify which sub band the power +limitation applies to. The SAR type is for compatibility, so later +other SAR mechanism can be implemented without breaking the user +space SAR applications. + +Normal process is user space queries the SAR capability, and +gets the index of supported frequency ranges and associates the +power limitation with this index and sends to kernel. + +Here is an example of message send to kernel: +8c 00 00 00 08 00 01 00 00 00 00 00 38 00 2b 81 +08 00 01 00 00 00 00 00 2c 00 02 80 14 00 00 80 +08 00 02 00 00 00 00 00 08 00 01 00 38 00 00 00 +14 00 01 80 08 00 02 00 01 00 00 00 08 00 01 00 +48 00 00 00 + +NL80211_CMD_SET_SAR_SPECS: 0x8c +NL80211_ATTR_WIPHY: 0x01(phy idx is 0) +NL80211_ATTR_SAR_SPEC: 0x812b (NLA_NESTED) +NL80211_SAR_ATTR_TYPE: 0x00 (NL80211_SAR_TYPE_POWER) +NL80211_SAR_ATTR_SPECS: 0x8002 (NLA_NESTED) +freq range 0 power: 0x38 in 0.25dbm unit (14dbm) +freq range 1 power: 0x48 in 0.25dbm unit (18dbm) + +Signed-off-by: Carl Huang +Reviewed-by: Brian Norris +Reviewed-by: Abhishek Kumar +Link: https://lore.kernel.org/r/20201203103728.3034-2-cjhuang@codeaurora.org +[minor edits, NLA parse cleanups] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1737,6 +1737,54 @@ struct station_info { + u8 connected_to_as; + }; + ++/** ++ * struct cfg80211_sar_sub_specs - sub specs limit ++ * @power: power limitation in 0.25dbm ++ * @freq_range_index: index the power limitation applies to ++ */ ++struct cfg80211_sar_sub_specs { ++ s32 power; ++ u32 freq_range_index; ++}; ++ ++/** ++ * struct cfg80211_sar_specs - sar limit specs ++ * @type: it's set with power in 0.25dbm or other types ++ * @num_sub_specs: number of sar sub specs ++ * @sub_specs: memory to hold the sar sub specs ++ */ ++struct cfg80211_sar_specs { ++ enum nl80211_sar_type type; ++ u32 num_sub_specs; ++ struct cfg80211_sar_sub_specs sub_specs[]; ++}; ++ ++ ++/** ++ * @struct cfg80211_sar_chan_ranges - sar frequency ranges ++ * @start_freq: start range edge frequency ++ * @end_freq: end range edge frequency ++ */ ++struct cfg80211_sar_freq_ranges { ++ u32 start_freq; ++ u32 end_freq; ++}; ++ ++/** ++ * struct cfg80211_sar_capa - sar limit capability ++ * @type: it's set via power in 0.25dbm or other types ++ * @num_freq_ranges: number of frequency ranges ++ * @freq_ranges: memory to hold the freq ranges. ++ * ++ * Note: WLAN driver may append new ranges or split an existing ++ * range to small ones and then append them. ++ */ ++struct cfg80211_sar_capa { ++ enum nl80211_sar_type type; ++ u32 num_freq_ranges; ++ const struct cfg80211_sar_freq_ranges *freq_ranges; ++}; ++ + #if IS_ENABLED(CPTCFG_CFG80211) + /** + * cfg80211_get_station - retrieve information about a given station +@@ -4259,6 +4307,8 @@ struct cfg80211_ops { + struct cfg80211_tid_config *tid_conf); + int (*reset_tid_config)(struct wiphy *wiphy, struct net_device *dev, + const u8 *peer, u8 tids); ++ int (*set_sar_specs)(struct wiphy *wiphy, ++ struct cfg80211_sar_specs *sar); + }; + + /* +@@ -5030,6 +5080,8 @@ struct wiphy { + + u8 max_data_retry_count; + ++ const struct cfg80211_sar_capa *sar_capa; ++ + char priv[] __aligned(NETDEV_ALIGN); + }; + +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -405,6 +405,18 @@ nl80211_unsol_bcast_probe_resp_policy[NL + .len = IEEE80211_MAX_DATA_LEN } + }; + ++static const struct nla_policy ++sar_specs_policy[NL80211_SAR_ATTR_SPECS_MAX + 1] = { ++ [NL80211_SAR_ATTR_SPECS_POWER] = { .type = NLA_S32 }, ++ [NL80211_SAR_ATTR_SPECS_RANGE_INDEX] = {.type = NLA_U32 }, ++}; ++ ++static const struct nla_policy ++sar_policy[NL80211_SAR_ATTR_MAX + 1] = { ++ [NL80211_SAR_ATTR_TYPE] = NLA_POLICY_MAX(NLA_U32, NUM_NL80211_SAR_TYPE), ++ [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), ++}; ++ + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + [0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD }, + [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, +@@ -739,6 +751,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_SAE_PWE] = + NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK, + NL80211_SAE_PWE_BOTH), ++ [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), + [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, + }; + +@@ -2117,6 +2130,56 @@ fail: + return -ENOBUFS; + } + ++static int ++nl80211_put_sar_specs(struct cfg80211_registered_device *rdev, ++ struct sk_buff *msg) ++{ ++ struct nlattr *sar_capa, *specs, *sub_freq_range; ++ u8 num_freq_ranges; ++ int i; ++ ++ if (!rdev->wiphy.sar_capa) ++ return 0; ++ ++ num_freq_ranges = rdev->wiphy.sar_capa->num_freq_ranges; ++ ++ sar_capa = nla_nest_start(msg, NL80211_ATTR_SAR_SPEC); ++ if (!sar_capa) ++ return -ENOSPC; ++ ++ if (nla_put_u32(msg, NL80211_SAR_ATTR_TYPE, rdev->wiphy.sar_capa->type)) ++ goto fail; ++ ++ specs = nla_nest_start(msg, NL80211_SAR_ATTR_SPECS); ++ if (!specs) ++ goto fail; ++ ++ /* report supported freq_ranges */ ++ for (i = 0; i < num_freq_ranges; i++) { ++ sub_freq_range = nla_nest_start(msg, i + 1); ++ if (!sub_freq_range) ++ goto fail; ++ ++ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_START_FREQ, ++ rdev->wiphy.sar_capa->freq_ranges[i].start_freq)) ++ goto fail; ++ ++ if (nla_put_u32(msg, NL80211_SAR_ATTR_SPECS_END_FREQ, ++ rdev->wiphy.sar_capa->freq_ranges[i].end_freq)) ++ goto fail; ++ ++ nla_nest_end(msg, sub_freq_range); ++ } ++ ++ nla_nest_end(msg, specs); ++ nla_nest_end(msg, sar_capa); ++ ++ return 0; ++fail: ++ nla_nest_cancel(msg, sar_capa); ++ return -ENOBUFS; ++} ++ + struct nl80211_dump_wiphy_state { + s64 filter_wiphy; + long start; +@@ -2366,6 +2429,8 @@ static int nl80211_send_wiphy(struct cfg + CMD(set_multicast_to_unicast, SET_MULTICAST_TO_UNICAST); + CMD(update_connect_params, UPDATE_CONNECT_PARAMS); + CMD(update_ft_ies, UPDATE_FT_IES); ++ if (rdev->wiphy.sar_capa) ++ CMD(set_sar_specs, SET_SAR_SPECS); + } + #undef CMD + +@@ -2691,6 +2756,11 @@ static int nl80211_send_wiphy(struct cfg + + if (nl80211_put_tid_config_support(rdev, msg)) + goto nla_put_failure; ++ state->split_start++; ++ break; ++ case 16: ++ if (nl80211_put_sar_specs(rdev, msg)) ++ goto nla_put_failure; + + /* done */ + state->split_start = 0; +@@ -14712,6 +14782,111 @@ static void nl80211_post_doit(__genl_con + } + } + ++static int nl80211_set_sar_sub_specs(struct cfg80211_registered_device *rdev, ++ struct cfg80211_sar_specs *sar_specs, ++ struct nlattr *spec[], int index) ++{ ++ u32 range_index, i; ++ ++ if (!sar_specs || !spec) ++ return -EINVAL; ++ ++ if (!spec[NL80211_SAR_ATTR_SPECS_POWER] || ++ !spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]) ++ return -EINVAL; ++ ++ range_index = nla_get_u32(spec[NL80211_SAR_ATTR_SPECS_RANGE_INDEX]); ++ ++ /* check if range_index exceeds num_freq_ranges */ ++ if (range_index >= rdev->wiphy.sar_capa->num_freq_ranges) ++ return -EINVAL; ++ ++ /* check if range_index duplicates */ ++ for (i = 0; i < index; i++) { ++ if (sar_specs->sub_specs[i].freq_range_index == range_index) ++ return -EINVAL; ++ } ++ ++ sar_specs->sub_specs[index].power = ++ nla_get_s32(spec[NL80211_SAR_ATTR_SPECS_POWER]); ++ ++ sar_specs->sub_specs[index].freq_range_index = range_index; ++ ++ return 0; ++} ++ ++static int nl80211_set_sar_specs(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct cfg80211_registered_device *rdev = info->user_ptr[0]; ++ struct nlattr *spec[NL80211_SAR_ATTR_SPECS_MAX + 1]; ++ struct nlattr *tb[NL80211_SAR_ATTR_MAX + 1]; ++ struct cfg80211_sar_specs *sar_spec; ++ enum nl80211_sar_type type; ++ struct nlattr *spec_list; ++ u32 specs; ++ int rem, err; ++ ++ if (!rdev->wiphy.sar_capa || !rdev->ops->set_sar_specs) ++ return -EOPNOTSUPP; ++ ++ if (!info->attrs[NL80211_ATTR_SAR_SPEC]) ++ return -EINVAL; ++ ++ nla_parse_nested(tb, NL80211_SAR_ATTR_MAX, ++ info->attrs[NL80211_ATTR_SAR_SPEC], ++ NULL, NULL); ++ ++ if (!tb[NL80211_SAR_ATTR_TYPE] || !tb[NL80211_SAR_ATTR_SPECS]) ++ return -EINVAL; ++ ++ type = nla_get_u32(tb[NL80211_SAR_ATTR_TYPE]); ++ if (type != rdev->wiphy.sar_capa->type) ++ return -EINVAL; ++ ++ specs = 0; ++ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) ++ specs++; ++ ++ if (specs > rdev->wiphy.sar_capa->num_freq_ranges) ++ return -EINVAL; ++ ++ sar_spec = kzalloc(sizeof(*sar_spec) + ++ specs * sizeof(struct cfg80211_sar_sub_specs), ++ GFP_KERNEL); ++ if (!sar_spec) ++ return -ENOMEM; ++ ++ sar_spec->type = type; ++ specs = 0; ++ nla_for_each_nested(spec_list, tb[NL80211_SAR_ATTR_SPECS], rem) { ++ nla_parse_nested(spec, NL80211_SAR_ATTR_SPECS_MAX, ++ spec_list, NULL, NULL); ++ ++ switch (type) { ++ case NL80211_SAR_TYPE_POWER: ++ if (nl80211_set_sar_sub_specs(rdev, sar_spec, ++ spec, specs)) { ++ err = -EINVAL; ++ goto error; ++ } ++ break; ++ default: ++ err = -EINVAL; ++ goto error; ++ } ++ specs++; ++ } ++ ++ sar_spec->num_sub_specs = specs; ++ ++ rdev->cur_cmd_info = info; ++ err = rdev_set_sar_specs(rdev, sar_spec); ++ rdev->cur_cmd_info = NULL; ++error: ++ kfree(sar_spec); ++ return err; ++} ++ + static __genl_const struct genl_ops nl80211_ops[] = { + { + .cmd = NL80211_CMD_GET_WIPHY, +@@ -15575,6 +15750,14 @@ static const struct genl_small_ops nl802 + .internal_flags = NL80211_FLAG_NEED_NETDEV | + NL80211_FLAG_NEED_RTNL, + }, ++ { ++ .cmd = NL80211_CMD_SET_SAR_SPECS, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = nl80211_set_sar_specs, ++ .flags = GENL_UNS_ADMIN_PERM, ++ .internal_flags = NL80211_FLAG_NEED_WIPHY | ++ NL80211_FLAG_NEED_RTNL, ++ }, + }; + + static struct genl_family nl80211_fam __genl_ro_after_init = { +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1356,4 +1356,16 @@ static inline int rdev_reset_tid_config( + return ret; + } + ++static inline int rdev_set_sar_specs(struct cfg80211_registered_device *rdev, ++ struct cfg80211_sar_specs *sar) ++{ ++ int ret; ++ ++ trace_rdev_set_sar_specs(&rdev->wiphy, sar); ++ ret = rdev->ops->set_sar_specs(&rdev->wiphy, sar); ++ trace_rdev_return_int(&rdev->wiphy, ret); ++ ++ return ret; ++} ++ + #endif /* __CFG80211_RDEV_OPS */ +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3551,6 +3551,25 @@ TRACE_EVENT(rdev_reset_tid_config, + TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", tids: 0x%x", + WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->tids) + ); ++ ++TRACE_EVENT(rdev_set_sar_specs, ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_sar_specs *sar), ++ TP_ARGS(wiphy, sar), ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ __field(u16, type) ++ __field(u16, num) ++ ), ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ __entry->type = sar->type; ++ __entry->num = sar->num_sub_specs; ++ ++ ), ++ TP_printk(WIPHY_PR_FMT ", Set type:%d, num_specs:%d", ++ WIPHY_PR_ARG, __entry->type, __entry->num) ++); ++ + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch b/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch new file mode 100644 index 0000000000..c351bc812a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/385-mac80211-add-ieee80211_set_sar_specs.patch @@ -0,0 +1,51 @@ +From: Carl Huang +Date: Thu, 3 Dec 2020 05:37:27 -0500 +Subject: [PATCH] mac80211: add ieee80211_set_sar_specs + +This change registers ieee80211_set_sar_specs to +mac80211_config_ops, so cfg80211 can call it. + +Signed-off-by: Carl Huang +Reviewed-by: Brian Norris +Reviewed-by: Abhishek Kumar +Link: https://lore.kernel.org/r/20201203103728.3034-3-cjhuang@codeaurora.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4207,6 +4207,8 @@ struct ieee80211_ops { + struct ieee80211_vif *vif); + void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled); ++ int (*set_sar_specs)(struct ieee80211_hw *hw, ++ const struct cfg80211_sar_specs *sar); + void (*sta_set_decap_offload)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled); +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4136,6 +4136,17 @@ static int ieee80211_reset_tid_config(st + return ret; + } + ++static int ieee80211_set_sar_specs(struct wiphy *wiphy, ++ struct cfg80211_sar_specs *sar) ++{ ++ struct ieee80211_local *local = wiphy_priv(wiphy); ++ ++ if (!local->ops->set_sar_specs) ++ return -EOPNOTSUPP; ++ ++ return local->ops->set_sar_specs(&local->hw, sar); ++} ++ + const struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, +@@ -4239,4 +4250,5 @@ const struct cfg80211_ops mac80211_confi + .probe_mesh_link = ieee80211_probe_mesh_link, + .set_tid_config = ieee80211_set_tid_config, + .reset_tid_config = ieee80211_reset_tid_config, ++ .set_sar_specs = ieee80211_set_sar_specs, + }; diff --git a/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch b/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch new file mode 100644 index 0000000000..c2cc16cd48 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch @@ -0,0 +1,26 @@ +From: Ryder Lee +Date: Fri, 18 Jun 2021 04:38:59 +0800 +Subject: [PATCH] mac80211: check per vif offload_flags in Tx path + +offload_flags has been introduced to indicate encap status of each interface. +An interface can encap offload at runtime, or if it has some extra limitations +it can simply override the flags, so it's more flexible to check offload_flags +in Tx path. + +Signed-off-by: Ryder Lee +Link: https://lore.kernel.org/r/177785418cf407808bf3a44760302d0647076990.1623961575.git.ryder.lee@mediatek.com +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3331,6 +3331,9 @@ static bool ieee80211_amsdu_aggregate(st + if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) + return false; + ++ if (sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) ++ return false; ++ + if (skb_is_gso(skb)) + return false; + diff --git a/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch new file mode 100644 index 0000000000..36b705de12 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch @@ -0,0 +1,485 @@ +From: John Crispin +Date: Fri, 2 Jul 2021 19:44:07 +0200 +Subject: [PATCH] nl80211: add support for BSS coloring + +This patch adds support for BSS color collisions to the wireless subsystem. +Add the required functionality to nl80211 that will notify about color +collisions, triggering the color change and notifying when it is completed. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/500b3582aec8fe2c42ef46f3117b148cb7cbceb5.1625247619.git.lorenzo@kernel.org +[remove unnecessary NULL initialisation] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1252,6 +1252,27 @@ struct cfg80211_csa_settings { + #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 + + /** ++ * struct cfg80211_color_change_settings - color change settings ++ * ++ * Used for bss color change ++ * ++ * @beacon_color_change: beacon data while performing the color countdown ++ * @counter_offsets_beacon: offsets of the counters within the beacon (tail) ++ * @counter_offsets_presp: offsets of the counters within the probe response ++ * @beacon_next: beacon data to be used after the color change ++ * @count: number of beacons until the color change ++ * @color: the color used after the change ++ */ ++struct cfg80211_color_change_settings { ++ struct cfg80211_beacon_data beacon_color_change; ++ u16 counter_offset_beacon; ++ u16 counter_offset_presp; ++ struct cfg80211_beacon_data beacon_next; ++ u8 count; ++ u8 color; ++}; ++ ++/** + * struct iface_combination_params - input parameters for interface combinations + * + * Used to pass interface combination parameters +@@ -3979,6 +4000,8 @@ struct mgmt_frame_regs { + * This callback may sleep. + * @reset_tid_config: Reset TID specific configuration for the peer, for the + * given TIDs. This callback may sleep. ++ * ++ * @color_change: Initiate a color change. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4309,6 +4332,9 @@ struct cfg80211_ops { + const u8 *peer, u8 tids); + int (*set_sar_specs)(struct wiphy *wiphy, + struct cfg80211_sar_specs *sar); ++ int (*color_change)(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct cfg80211_color_change_settings *params); + }; + + /* +@@ -8094,4 +8120,70 @@ void cfg80211_update_owe_info_event(stru + */ + void cfg80211_bss_flush(struct wiphy *wiphy); + ++/** ++ * cfg80211_bss_color_notify - notify about bss color event ++ * @dev: network device ++ * @gfp: allocation flags ++ * @cmd: the actual event we want to notify ++ * @count: the number of TBTTs until the color change happens ++ * @color_bitmap: representations of the colors that the local BSS is aware of ++ */ ++int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, ++ enum nl80211_commands cmd, u8 count, ++ u64 color_bitmap); ++ ++/** ++ * cfg80211_obss_color_collision_notify - notify about bss color collision ++ * @dev: network device ++ * @color_bitmap: representations of the colors that the local BSS is aware of ++ */ ++static inline int cfg80211_obss_color_collision_notify(struct net_device *dev, ++ u64 color_bitmap) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ 0, color_bitmap); ++} ++ ++/** ++ * cfg80211_color_change_started_notify - notify color change start ++ * @dev: the device on which the color is switched ++ * @count: the number of TBTTs until the color change happens ++ * ++ * Inform the userspace about the color change that has started. ++ */ ++static inline int cfg80211_color_change_started_notify(struct net_device *dev, ++ u8 count) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ count, 0); ++} ++ ++/** ++ * cfg80211_color_change_aborted_notify - notify color change abort ++ * @dev: the device on which the color is switched ++ * ++ * Inform the userspace about the color change that has aborted. ++ */ ++static inline int cfg80211_color_change_aborted_notify(struct net_device *dev) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ 0, 0); ++} ++ ++/** ++ * cfg80211_color_change_notify - notify color change completion ++ * @dev: the device on which the color was switched ++ * ++ * Inform the userspace about the color change that has completed. ++ */ ++static inline int cfg80211_color_change_notify(struct net_device *dev) ++{ ++ return cfg80211_bss_color_notify(dev, GFP_KERNEL, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ 0, 0); ++} ++ + #endif /* __NET_CFG80211_H */ +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -1185,6 +1185,21 @@ + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. + * ++ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever ++ * mac80211/drv detects a bss color collision. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that ++ * userspace wants to change the BSS color. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has ++ * started ++ * ++ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has ++ * been aborted ++ * ++ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change ++ * has completed ++ * + * @NL80211_CMD_MAX: highest used command number + * @__NL80211_CMD_AFTER_LAST: internal use + */ +@@ -1417,6 +1432,14 @@ enum nl80211_commands { + + NL80211_CMD_SET_SAR_SPECS, + ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ ++ NL80211_CMD_COLOR_CHANGE_REQUEST, ++ ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, ++ + /* add new commands above here */ + + /* used to define NL80211_CMD_MAX below */ +@@ -2560,6 +2583,16 @@ enum nl80211_commands { + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * ++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the ++ * %NL80211_CMD_OBSS_COLOR_COLLISION event. ++ * ++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's ++ * until the color switch event. ++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are ++ * switching to ++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE ++ * information for the time while performing a color switch. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3057,6 +3090,12 @@ enum nl80211_attrs { + + NL80211_ATTR_DISABLE_HE, + ++ NL80211_ATTR_OBSS_COLOR_BITMAP, ++ ++ NL80211_ATTR_COLOR_CHANGE_COUNT, ++ NL80211_ATTR_COLOR_CHANGE_COLOR, ++ NL80211_ATTR_COLOR_CHANGE_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -5950,6 +5989,9 @@ enum nl80211_feature_flags { + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. + * ++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision ++ * detection and change announcemnts. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6014,6 +6056,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_LTF, + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, ++ NL80211_EXT_FEATURE_BSS_COLOR, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -753,6 +753,10 @@ static const struct nla_policy nl80211_p + NL80211_SAE_PWE_BOTH), + [NL80211_ATTR_SAR_SPEC] = NLA_POLICY_NESTED(sar_policy), + [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, ++ [NL80211_ATTR_OBSS_COLOR_BITMAP] = { .type = NLA_U64 }, ++ [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, ++ [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, ++ [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), + }; + + /* policy for the key attributes */ +@@ -14677,6 +14681,106 @@ bad_tid_conf: + return ret; + } + ++static int nl80211_color_change(struct sk_buff *skb, struct genl_info *info) ++{ ++ struct cfg80211_registered_device *rdev = info->user_ptr[0]; ++ struct cfg80211_color_change_settings params = {}; ++ struct net_device *dev = info->user_ptr[1]; ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct nlattr **tb; ++ u16 offset; ++ int err; ++ ++ if (!rdev->ops->color_change) ++ return -EOPNOTSUPP; ++ ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR)) ++ return -EOPNOTSUPP; ++ ++ if (wdev->iftype != NL80211_IFTYPE_AP) ++ return -EOPNOTSUPP; ++ ++ if (!info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT] || ++ !info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR] || ++ !info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS]) ++ return -EINVAL; ++ ++ params.count = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COUNT]); ++ params.color = nla_get_u8(info->attrs[NL80211_ATTR_COLOR_CHANGE_COLOR]); ++ ++ err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_next); ++ if (err) ++ return err; ++ ++ tb = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*tb), GFP_KERNEL); ++ if (!tb) ++ return -ENOMEM; ++ ++ err = nla_parse_nested(tb, NL80211_ATTR_MAX, ++ info->attrs[NL80211_ATTR_COLOR_CHANGE_ELEMS], ++ nl80211_policy, info->extack); ++ if (err) ++ goto out; ++ ++ err = nl80211_parse_beacon(rdev, tb, ¶ms.beacon_color_change); ++ if (err) ++ goto out; ++ ++ if (!tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]) != sizeof(u16)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_BEACON]); ++ if (offset >= params.beacon_color_change.tail_len) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (params.beacon_color_change.tail[offset] != params.count) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ params.counter_offset_beacon = offset; ++ ++ if (tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) { ++ if (nla_len(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]) != ++ sizeof(u16)) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ offset = nla_get_u16(tb[NL80211_ATTR_CNTDWN_OFFS_PRESP]); ++ if (offset >= params.beacon_color_change.probe_resp_len) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ if (params.beacon_color_change.probe_resp[offset] != ++ params.count) { ++ err = -EINVAL; ++ goto out; ++ } ++ ++ params.counter_offset_presp = offset; ++ } ++ ++ wdev_lock(wdev); ++ err = rdev_color_change(rdev, dev, ¶ms); ++ wdev_unlock(wdev); ++ ++out: ++ kfree(tb); ++ return err; ++} ++ + #define NL80211_FLAG_NEED_WIPHY 0x01 + #define NL80211_FLAG_NEED_NETDEV 0x02 + #define NL80211_FLAG_NEED_RTNL 0x04 +@@ -15758,6 +15862,14 @@ static const struct genl_small_ops nl802 + .internal_flags = NL80211_FLAG_NEED_WIPHY | + NL80211_FLAG_NEED_RTNL, + }, ++ { ++ .cmd = NL80211_CMD_COLOR_CHANGE_REQUEST, ++ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, ++ .doit = nl80211_color_change, ++ .flags = GENL_UNS_ADMIN_PERM, ++ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | ++ NL80211_FLAG_NEED_RTNL, ++ }, + }; + + static struct genl_family nl80211_fam __genl_ro_after_init = { +@@ -17384,6 +17496,51 @@ void cfg80211_ch_switch_started_notify(s + } + EXPORT_SYMBOL(cfg80211_ch_switch_started_notify); + ++int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp, ++ enum nl80211_commands cmd, u8 count, ++ u64 color_bitmap) ++{ ++ struct wireless_dev *wdev = dev->ieee80211_ptr; ++ struct wiphy *wiphy = wdev->wiphy; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ struct sk_buff *msg; ++ void *hdr; ++ ++ ASSERT_WDEV_LOCK(wdev); ++ ++ trace_cfg80211_bss_color_notify(dev, cmd, count, color_bitmap); ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); ++ if (!msg) ++ return -ENOMEM; ++ ++ hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); ++ if (!hdr) ++ goto nla_put_failure; ++ ++ if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex)) ++ goto nla_put_failure; ++ ++ if (cmd == NL80211_CMD_COLOR_CHANGE_STARTED && ++ nla_put_u32(msg, NL80211_ATTR_COLOR_CHANGE_COUNT, count)) ++ goto nla_put_failure; ++ ++ if (cmd == NL80211_CMD_OBSS_COLOR_COLLISION && ++ nla_put_u64_64bit(msg, NL80211_ATTR_OBSS_COLOR_BITMAP, ++ color_bitmap, NL80211_ATTR_PAD)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ ++ return genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), ++ msg, 0, NL80211_MCGRP_MLME, gfp); ++ ++nla_put_failure: ++ nlmsg_free(msg); ++ return -EINVAL; ++} ++EXPORT_SYMBOL(cfg80211_bss_color_notify); ++ + void + nl80211_radar_notify(struct cfg80211_registered_device *rdev, + const struct cfg80211_chan_def *chandef, +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1368,4 +1368,17 @@ static inline int rdev_set_sar_specs(str + return ret; + } + ++static inline int rdev_color_change(struct cfg80211_registered_device *rdev, ++ struct net_device *dev, ++ struct cfg80211_color_change_settings *params) ++{ ++ int ret; ++ ++ trace_rdev_color_change(&rdev->wiphy, dev, params); ++ ret = rdev->ops->color_change(&rdev->wiphy, dev, params); ++ trace_rdev_return_int(&rdev->wiphy, ret); ++ ++ return ret; ++} ++ + #endif /* __CFG80211_RDEV_OPS */ +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3570,6 +3570,52 @@ TRACE_EVENT(rdev_set_sar_specs, + WIPHY_PR_ARG, __entry->type, __entry->num) + ); + ++TRACE_EVENT(rdev_color_change, ++ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, ++ struct cfg80211_color_change_settings *params), ++ TP_ARGS(wiphy, netdev, params), ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ NETDEV_ENTRY ++ __field(u8, count) ++ __field(u16, bcn_ofs) ++ __field(u16, pres_ofs) ++ ), ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ NETDEV_ASSIGN; ++ __entry->count = params->count; ++ __entry->bcn_ofs = params->counter_offset_beacon; ++ __entry->pres_ofs = params->counter_offset_presp; ++ ), ++ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ++ ", count: %u", ++ WIPHY_PR_ARG, NETDEV_PR_ARG, ++ __entry->count) ++); ++ ++TRACE_EVENT(cfg80211_bss_color_notify, ++ TP_PROTO(struct net_device *netdev, ++ enum nl80211_commands cmd, ++ u8 count, u64 color_bitmap), ++ TP_ARGS(netdev, cmd, count, color_bitmap), ++ TP_STRUCT__entry( ++ NETDEV_ENTRY ++ __field(enum nl80211_bss_scan_width, cmd) ++ __field(u8, count) ++ __field(u64, color_bitmap) ++ ), ++ TP_fast_assign( ++ NETDEV_ASSIGN; ++ __entry->cmd = cmd; ++ __entry->count = count; ++ __entry->color_bitmap = color_bitmap; ++ ), ++ TP_printk(NETDEV_PR_FMT ", cmd: %x, count: %u, bitmap: %llx", ++ NETDEV_PR_ARG, __entry->cmd, __entry->count, ++ __entry->color_bitmap) ++); ++ + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch new file mode 100644 index 0000000000..0a3118545f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch @@ -0,0 +1,524 @@ +From: John Crispin +Date: Fri, 2 Jul 2021 19:44:08 +0200 +Subject: [PATCH] mac80211: add support for BSS color change + +The color change announcement is very similar to how CSA works where +we have an IE that includes a counter. When the counter hits 0, the new +color is applied via an updated beacon. + +This patch makes the CSA counter functionality reusable, rather than +implementing it again. This also allows for future reuse incase support +for other counter IEs gets added. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/057c1e67b82bee561ea44ce6a45a8462d3da6995.1625247619.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1710,6 +1710,10 @@ enum ieee80211_offload_flags { + * protected by fq->lock. + * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see + * &enum ieee80211_offload_flags. ++ * @color_change_active: marks whether a color change is ongoing. Internally it is ++ * write-protected by sdata_lock and local->mtx so holding either is fine ++ * for read access. ++ * @color_change_color: the bss color that will be used after the change. + */ + struct ieee80211_vif { + enum nl80211_iftype type; +@@ -1738,6 +1742,9 @@ struct ieee80211_vif { + + bool txqs_stopped[IEEE80211_NUM_ACS]; + ++ bool color_change_active; ++ u8 color_change_color; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +@@ -4982,6 +4989,16 @@ void ieee80211_csa_finish(struct ieee802 + bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif); + + /** ++ * ieee80211_color_change_finish - notify mac80211 about color change ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * ++ * After a color change announcement was scheduled and the counter in this ++ * announcement hits 1, this function must be called by the driver to ++ * notify mac80211 that the color can be changed ++ */ ++void ieee80211_color_change_finish(struct ieee80211_vif *vif); ++ ++/** + * ieee80211_proberesp_get - retrieve a Probe Response template + * @hw: pointer obtained from ieee80211_alloc_hw(). + * @vif: &struct ieee80211_vif pointer from the add_interface callback. +@@ -6726,6 +6743,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp + struct ieee80211_vif *vif); + + /** ++ * ieeee80211_obss_color_collision_notify - notify userland about a BSS color ++ * collision. ++ * ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is ++ * aware of. ++ */ ++void ++ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, ++ u64 color_bitmap); ++ ++/** + * ieee80211_is_tx_data - check if frame is a data frame + * + * The function is used to check if a frame is a data frame. Frames with +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -827,9 +827,11 @@ static int ieee80211_set_monitor_channel + return ret; + } + +-static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, +- const u8 *resp, size_t resp_len, +- const struct ieee80211_csa_settings *csa) ++static int ++ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata, ++ const u8 *resp, size_t resp_len, ++ const struct ieee80211_csa_settings *csa, ++ const struct ieee80211_color_change_settings *cca) + { + struct probe_resp *new, *old; + +@@ -849,6 +851,8 @@ static int ieee80211_set_probe_resp(stru + memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_presp, + csa->n_counter_offsets_presp * + sizeof(new->cntdwn_counter_offsets[0])); ++ else if (cca) ++ new->cntdwn_counter_offsets[0] = cca->counter_offset_presp; + + rcu_assign_pointer(sdata->u.ap.probe_resp, new); + if (old) +@@ -954,7 +958,8 @@ static int ieee80211_set_ftm_responder_p + + static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata, + struct cfg80211_beacon_data *params, +- const struct ieee80211_csa_settings *csa) ++ const struct ieee80211_csa_settings *csa, ++ const struct ieee80211_color_change_settings *cca) + { + struct beacon_data *new, *old; + int new_head_len, new_tail_len; +@@ -1003,6 +1008,9 @@ static int ieee80211_assign_beacon(struc + memcpy(new->cntdwn_counter_offsets, csa->counter_offsets_beacon, + csa->n_counter_offsets_beacon * + sizeof(new->cntdwn_counter_offsets[0])); ++ } else if (cca) { ++ new->cntdwn_current_counter = cca->count; ++ new->cntdwn_counter_offsets[0] = cca->counter_offset_beacon; + } + + /* copy in head */ +@@ -1019,7 +1027,7 @@ static int ieee80211_assign_beacon(struc + memcpy(new->tail, old->tail, new_tail_len); + + err = ieee80211_set_probe_resp(sdata, params->probe_resp, +- params->probe_resp_len, csa); ++ params->probe_resp_len, csa, cca); + if (err < 0) { + kfree(new); + return err; +@@ -1176,7 +1184,7 @@ static int ieee80211_start_ap(struct wip + if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) + sdata->vif.bss_conf.beacon_tx_rate = params->beacon_rate; + +- err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL); ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon, NULL, NULL); + if (err < 0) + goto error; + changed |= err; +@@ -1231,17 +1239,17 @@ static int ieee80211_change_beacon(struc + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata_assert_lock(sdata); + +- /* don't allow changing the beacon while CSA is in place - offset ++ /* don't allow changing the beacon while a countdown is in place - offset + * of channel switch counter may change + */ +- if (sdata->vif.csa_active) ++ if (sdata->vif.csa_active || sdata->vif.color_change_active) + return -EBUSY; + + old = sdata_dereference(sdata->u.ap.beacon, sdata); + if (!old) + return -ENOENT; + +- err = ieee80211_assign_beacon(sdata, params, NULL); ++ err = ieee80211_assign_beacon(sdata, params, NULL, NULL); + if (err < 0) + return err; + ieee80211_bss_info_change_notify(sdata, err); +@@ -3174,7 +3182,7 @@ static int ieee80211_set_after_csa_beaco + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, +- NULL); ++ NULL, NULL); + kfree(sdata->u.ap.next_beacon); + sdata->u.ap.next_beacon = NULL; + +@@ -3340,7 +3348,7 @@ static int ieee80211_set_csa_beacon(stru + csa.n_counter_offsets_presp = params->n_counter_offsets_presp; + csa.count = params->count; + +- err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa); ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); + if (err < 0) { + kfree(sdata->u.ap.next_beacon); + return err; +@@ -3428,6 +3436,15 @@ static int ieee80211_set_csa_beacon(stru + return 0; + } + ++static void ieee80211_color_change_abort(struct ieee80211_sub_if_data *sdata) ++{ ++ sdata->vif.color_change_active = false; ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ ++ cfg80211_color_change_aborted_notify(sdata->dev); ++} ++ + static int + __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params) +@@ -3496,6 +3513,10 @@ __ieee80211_channel_switch(struct wiphy + goto out; + } + ++ /* if there is a color change in progress, abort it */ ++ if (sdata->vif.color_change_active) ++ ieee80211_color_change_abort(sdata); ++ + err = ieee80211_set_csa_beacon(sdata, params, &changed); + if (err) { + ieee80211_vif_unreserve_chanctx(sdata); +@@ -4147,6 +4168,196 @@ static int ieee80211_set_sar_specs(struc + return local->ops->set_sar_specs(&local->hw, sar); + } + ++static int ++ieee80211_set_after_color_change_beacon(struct ieee80211_sub_if_data *sdata, ++ u32 *changed) ++{ ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP: { ++ int ret; ++ ++ ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, ++ NULL, NULL); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ ++ if (ret < 0) ++ return ret; ++ ++ *changed |= ret; ++ break; ++ } ++ default: ++ WARN_ON_ONCE(1); ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int ++ieee80211_set_color_change_beacon(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_color_change_settings *params, ++ u32 *changed) ++{ ++ struct ieee80211_color_change_settings color_change = {}; ++ int err; ++ ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP: ++ sdata->u.ap.next_beacon = ++ cfg80211_beacon_dup(¶ms->beacon_next); ++ if (!sdata->u.ap.next_beacon) ++ return -ENOMEM; ++ ++ if (params->count <= 1) ++ break; ++ ++ color_change.counter_offset_beacon = ++ params->counter_offset_beacon; ++ color_change.counter_offset_presp = ++ params->counter_offset_presp; ++ color_change.count = params->count; ++ ++ err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, ++ NULL, &color_change); ++ if (err < 0) { ++ kfree(sdata->u.ap.next_beacon); ++ return err; ++ } ++ *changed |= err; ++ break; ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static void ++ieee80211_color_change_bss_config_notify(struct ieee80211_sub_if_data *sdata, ++ u8 color, int enable, u32 changed) ++{ ++ sdata->vif.bss_conf.he_bss_color.color = color; ++ sdata->vif.bss_conf.he_bss_color.enabled = enable; ++ changed |= BSS_CHANGED_HE_BSS_COLOR; ++ ++ ieee80211_bss_info_change_notify(sdata, changed); ++} ++ ++static int ieee80211_color_change_finalize(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_local *local = sdata->local; ++ u32 changed = 0; ++ int err; ++ ++ sdata_assert_lock(sdata); ++ lockdep_assert_held(&local->mtx); ++ ++ sdata->vif.color_change_active = false; ++ ++ err = ieee80211_set_after_color_change_beacon(sdata, &changed); ++ if (err) { ++ cfg80211_color_change_aborted_notify(sdata->dev); ++ return err; ++ } ++ ++ ieee80211_color_change_bss_config_notify(sdata, ++ sdata->vif.color_change_color, ++ 1, changed); ++ cfg80211_color_change_notify(sdata->dev); ++ ++ return 0; ++} ++ ++void ieee80211_color_change_finalize_work(struct work_struct *work) ++{ ++ struct ieee80211_sub_if_data *sdata = ++ container_of(work, struct ieee80211_sub_if_data, ++ color_change_finalize_work); ++ struct ieee80211_local *local = sdata->local; ++ ++ sdata_lock(sdata); ++ mutex_lock(&local->mtx); ++ ++ /* AP might have been stopped while waiting for the lock. */ ++ if (!sdata->vif.color_change_active) ++ goto unlock; ++ ++ if (!ieee80211_sdata_running(sdata)) ++ goto unlock; ++ ++ ieee80211_color_change_finalize(sdata); ++ ++unlock: ++ mutex_unlock(&local->mtx); ++ sdata_unlock(sdata); ++} ++ ++void ieee80211_color_change_finish(struct ieee80211_vif *vif) ++{ ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ ++ ieee80211_queue_work(&sdata->local->hw, ++ &sdata->color_change_finalize_work); ++} ++EXPORT_SYMBOL_GPL(ieee80211_color_change_finish); ++ ++void ++ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif, ++ u64 color_bitmap) ++{ ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ ++ if (sdata->vif.color_change_active || sdata->vif.csa_active) ++ return; ++ ++ cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap); ++} ++EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify); ++ ++static int ++ieee80211_color_change(struct wiphy *wiphy, struct net_device *dev, ++ struct cfg80211_color_change_settings *params) ++{ ++ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ieee80211_local *local = sdata->local; ++ u32 changed = 0; ++ int err; ++ ++ sdata_assert_lock(sdata); ++ ++ mutex_lock(&local->mtx); ++ ++ /* don't allow another color change if one is already active or if csa ++ * is active ++ */ ++ if (sdata->vif.color_change_active || sdata->vif.csa_active) { ++ err = -EBUSY; ++ goto out; ++ } ++ ++ err = ieee80211_set_color_change_beacon(sdata, params, &changed); ++ if (err) ++ goto out; ++ ++ sdata->vif.color_change_active = true; ++ sdata->vif.color_change_color = params->color; ++ ++ cfg80211_color_change_started_notify(sdata->dev, params->count); ++ ++ if (changed) ++ ieee80211_color_change_bss_config_notify(sdata, 0, 0, changed); ++ else ++ /* if the beacon didn't change, we can finalize immediately */ ++ ieee80211_color_change_finalize(sdata); ++ ++out: ++ mutex_unlock(&local->mtx); ++ ++ return err; ++} ++ + const struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, +@@ -4251,4 +4462,5 @@ const struct cfg80211_ops mac80211_confi + .set_tid_config = ieee80211_set_tid_config, + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, ++ .color_change = ieee80211_color_change, + }; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -248,6 +248,12 @@ struct ieee80211_csa_settings { + u8 count; + }; + ++struct ieee80211_color_change_settings { ++ u16 counter_offset_beacon; ++ u16 counter_offset_presp; ++ u8 count; ++}; ++ + struct beacon_data { + u8 *head, *tail; + int head_len, tail_len; +@@ -932,6 +938,8 @@ struct ieee80211_sub_if_data { + bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */ + struct cfg80211_chan_def csa_chandef; + ++ struct work_struct color_change_finalize_work; ++ + struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */ + struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */ + +@@ -1900,6 +1908,9 @@ void ieee80211_csa_finalize_work(struct + int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_csa_settings *params); + ++/* color change handling */ ++void ieee80211_color_change_finalize_work(struct work_struct *work); ++ + /* interface handling */ + #define MAC80211_SUPPORTED_FEATURES_TX (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ + NETIF_F_HW_CSUM | NETIF_F_SG | \ +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -465,6 +465,7 @@ static void ieee80211_do_stop(struct iee + sdata_unlock(sdata); + + cancel_work_sync(&sdata->csa_finalize_work); ++ cancel_work_sync(&sdata->color_change_finalize_work); + + cancel_delayed_work_sync(&sdata->dfs_cac_timer_work); + +@@ -1639,6 +1640,7 @@ static void ieee80211_setup_sdata(struct + INIT_WORK(&sdata->work, ieee80211_iface_work); + INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); + INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); ++ INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work); + INIT_LIST_HEAD(&sdata->assigned_chanctx_list); + INIT_LIST_HEAD(&sdata->reserved_chanctx_list); + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4790,11 +4790,11 @@ static int ieee80211_beacon_add_tim(stru + static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, + struct beacon_data *beacon) + { ++ u8 *beacon_data, count, max_count = 1; + struct probe_resp *resp; +- u8 *beacon_data; + size_t beacon_data_len; ++ u16 *bcn_offsets; + int i; +- u8 count = beacon->cntdwn_current_counter; + + switch (sdata->vif.type) { + case NL80211_IFTYPE_AP: +@@ -4814,21 +4814,27 @@ static void ieee80211_set_beacon_cntdwn( + } + + rcu_read_lock(); +- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; ++i) { +- resp = rcu_dereference(sdata->u.ap.probe_resp); ++ resp = rcu_dereference(sdata->u.ap.probe_resp); + +- if (beacon->cntdwn_counter_offsets[i]) { +- if (WARN_ON_ONCE(beacon->cntdwn_counter_offsets[i] >= +- beacon_data_len)) { ++ bcn_offsets = beacon->cntdwn_counter_offsets; ++ count = beacon->cntdwn_current_counter; ++ if (sdata->vif.csa_active) ++ max_count = IEEE80211_MAX_CNTDWN_COUNTERS_NUM; ++ ++ for (i = 0; i < max_count; ++i) { ++ if (bcn_offsets[i]) { ++ if (WARN_ON_ONCE(bcn_offsets[i] >= beacon_data_len)) { + rcu_read_unlock(); + return; + } +- +- beacon_data[beacon->cntdwn_counter_offsets[i]] = count; ++ beacon_data[bcn_offsets[i]] = count; + } + +- if (sdata->vif.type == NL80211_IFTYPE_AP && resp) +- resp->data[resp->cntdwn_counter_offsets[i]] = count; ++ if (sdata->vif.type == NL80211_IFTYPE_AP && resp) { ++ u16 *resp_offsets = resp->cntdwn_counter_offsets; ++ ++ resp->data[resp_offsets[i]] = count; ++ } + } + rcu_read_unlock(); + } +@@ -5038,6 +5044,7 @@ __ieee80211_beacon_get(struct ieee80211_ + if (offs) { + offs->tim_offset = beacon->head_len; + offs->tim_length = skb->len - beacon->head_len; ++ offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; + + /* for AP the csa offsets are from tail */ + csa_off_base = skb->len; diff --git a/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch new file mode 100644 index 0000000000..369619938e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch @@ -0,0 +1,112 @@ +From: Lorenzo Bianconi +Date: Mon, 23 Aug 2021 20:02:38 +0200 +Subject: [PATCH] ieee80211: add TWT element definitions + +Introduce TWT definitions and TWT Information element structure +in ieee80211.h + +Tested-by: Peter Chiu +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/71d8b581fe4b5abc5b92f8d77ac2de3e2f7591b6.1629741512.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -1088,6 +1088,48 @@ struct ieee80211_ext { + } u; + } __packed __aligned(2); + ++#define IEEE80211_TWT_CONTROL_NDP BIT(0) ++#define IEEE80211_TWT_CONTROL_RESP_MODE BIT(1) ++#define IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST BIT(3) ++#define IEEE80211_TWT_CONTROL_RX_DISABLED BIT(4) ++#define IEEE80211_TWT_CONTROL_WAKE_DUR_UNIT BIT(5) ++ ++#define IEEE80211_TWT_REQTYPE_REQUEST BIT(0) ++#define IEEE80211_TWT_REQTYPE_SETUP_CMD GENMASK(3, 1) ++#define IEEE80211_TWT_REQTYPE_TRIGGER BIT(4) ++#define IEEE80211_TWT_REQTYPE_IMPLICIT BIT(5) ++#define IEEE80211_TWT_REQTYPE_FLOWTYPE BIT(6) ++#define IEEE80211_TWT_REQTYPE_FLOWID GENMASK(9, 7) ++#define IEEE80211_TWT_REQTYPE_WAKE_INT_EXP GENMASK(14, 10) ++#define IEEE80211_TWT_REQTYPE_PROTECTION BIT(15) ++ ++enum ieee80211_twt_setup_cmd { ++ TWT_SETUP_CMD_REQUEST, ++ TWT_SETUP_CMD_SUGGEST, ++ TWT_SETUP_CMD_DEMAND, ++ TWT_SETUP_CMD_GROUPING, ++ TWT_SETUP_CMD_ACCEPT, ++ TWT_SETUP_CMD_ALTERNATE, ++ TWT_SETUP_CMD_DICTATE, ++ TWT_SETUP_CMD_REJECT, ++}; ++ ++struct ieee80211_twt_params { ++ __le16 req_type; ++ __le64 twt; ++ u8 min_twt_dur; ++ __le16 mantissa; ++ u8 channel; ++} __packed; ++ ++struct ieee80211_twt_setup { ++ u8 dialog_token; ++ u8 element_id; ++ u8 length; ++ u8 control; ++ u8 params[]; ++} __packed; ++ + struct ieee80211_mgmt { + __le16 frame_control; + __le16 duration; +@@ -1252,6 +1294,10 @@ struct ieee80211_mgmt { + __le16 toa_error; + u8 variable[0]; + } __packed ftm; ++ struct { ++ u8 action_code; ++ u8 variable[]; ++ } __packed s1g; + } u; + } __packed action; + } u; +@@ -2880,6 +2926,7 @@ enum ieee80211_eid { + WLAN_EID_AID_RESPONSE = 211, + WLAN_EID_S1G_BCN_COMPAT = 213, + WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214, ++ WLAN_EID_S1G_TWT = 216, + WLAN_EID_S1G_CAPABILITIES = 217, + WLAN_EID_VENDOR_SPECIFIC = 221, + WLAN_EID_QOS_PARAMETER = 222, +@@ -2948,6 +2995,7 @@ enum ieee80211_category { + WLAN_CATEGORY_FST = 18, + WLAN_CATEGORY_UNPROT_DMG = 20, + WLAN_CATEGORY_VHT = 21, ++ WLAN_CATEGORY_S1G = 22, + WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, + WLAN_CATEGORY_VENDOR_SPECIFIC = 127, + }; +@@ -3021,6 +3069,20 @@ enum ieee80211_key_len { + WLAN_KEY_LEN_BIP_GMAC_256 = 32, + }; + ++enum ieee80211_s1g_actioncode { ++ WLAN_S1G_AID_SWITCH_REQUEST, ++ WLAN_S1G_AID_SWITCH_RESPONSE, ++ WLAN_S1G_SYNC_CONTROL, ++ WLAN_S1G_STA_INFO_ANNOUNCE, ++ WLAN_S1G_EDCA_PARAM_SET, ++ WLAN_S1G_EL_OPERATION, ++ WLAN_S1G_TWT_SETUP, ++ WLAN_S1G_TWT_TEARDOWN, ++ WLAN_S1G_SECT_GROUP_ID_LIST, ++ WLAN_S1G_SECT_ID_FEEDBACK, ++ WLAN_S1G_TWT_INFORMATION = 11, ++}; ++ + #define IEEE80211_WEP_IV_LEN 4 + #define IEEE80211_WEP_ICV_LEN 4 + #define IEEE80211_CCMP_HDR_LEN 8 diff --git a/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch new file mode 100644 index 0000000000..c32861a78f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch @@ -0,0 +1,576 @@ +From: Lorenzo Bianconi +Date: Mon, 23 Aug 2021 20:02:39 +0200 +Subject: [PATCH] mac80211: introduce individual TWT support in AP mode + +Introduce TWT action frames parsing support to mac80211. +Currently just individual TWT agreement are support in AP mode. +Whenever the AP receives a TWT action frame from an associated client, +after performing sanity checks, it will notify the underlay driver with +requested parameters in order to check if they are supported and if there +is enough room for a new agreement. The driver is expected to set the +agreement result and report it to mac80211. + +Drivers supporting this have two new callbacks: + - add_twt_setup (mandatory) + - twt_teardown_request (optional) + +mac80211 will send an action frame reply according to the result +reported by the driver. + +Tested-by: Peter Chiu +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/257512f2e22ba42b9f2624942a128dd8f141de4b.1629741512.git.lorenzo@kernel.org +[use le16p_replace_bits(), minor cleanups, use (void *) casts, + fix to use ieee80211_get_he_iftype_cap() correctly] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4219,6 +4219,11 @@ struct ieee80211_ops { + void (*sta_set_decap_offload)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled); ++ void (*add_twt_setup)(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, ++ struct ieee80211_twt_setup *twt); ++ void (*twt_teardown_request)(struct ieee80211_hw *hw, ++ struct ieee80211_sta *sta, u8 flowid); + }; + + /** +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1429,4 +1429,40 @@ static inline void drv_sta_set_decap_off + trace_drv_return_void(local); + } + ++static inline void drv_add_twt_setup(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ struct ieee80211_twt_setup *twt) ++{ ++ struct ieee80211_twt_params *twt_agrt; ++ ++ might_sleep(); ++ ++ if (!check_sdata_in_driver(sdata)) ++ return; ++ ++ twt_agrt = (void *)twt->params; ++ ++ trace_drv_add_twt_setup(local, sta, twt, twt_agrt); ++ local->ops->add_twt_setup(&local->hw, sta, twt); ++ trace_drv_return_void(local); ++} ++ ++static inline void drv_twt_teardown_request(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ u8 flowid) ++{ ++ might_sleep(); ++ if (!check_sdata_in_driver(sdata)) ++ return; ++ ++ if (!local->ops->twt_teardown_request) ++ return; ++ ++ trace_drv_twt_teardown_request(local, sta, flowid); ++ local->ops->twt_teardown_request(&local->hw, sta, flowid); ++ trace_drv_return_void(local); ++} ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -954,6 +954,7 @@ struct ieee80211_sub_if_data { + + struct work_struct work; + struct sk_buff_head skb_queue; ++ struct sk_buff_head status_queue; + + u8 needed_rx_chains; + enum ieee80211_smps_mode smps_mode; +@@ -2093,6 +2094,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie + + /* S1G */ + void ieee80211_s1g_sta_rate_init(struct sta_info *sta); ++bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb); ++void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb); ++void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb); + + /* Spectrum management */ + void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata, +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -563,6 +563,7 @@ static void ieee80211_do_stop(struct iee + */ + ieee80211_free_keys(sdata, true); + skb_queue_purge(&sdata->skb_queue); ++ skb_queue_purge(&sdata->status_queue); + } + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); +@@ -1070,6 +1071,7 @@ int ieee80211_add_virtual_monitor(struct + } + + skb_queue_head_init(&sdata->skb_queue); ++ skb_queue_head_init(&sdata->status_queue); + INIT_WORK(&sdata->work, ieee80211_iface_work); + + return 0; +@@ -1442,6 +1444,24 @@ static void ieee80211_if_setup_no_queue( + #endif + } + ++static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)skb->data; ++ ++ if (ieee80211_is_action(mgmt->frame_control) && ++ mgmt->u.action.category == WLAN_CATEGORY_S1G) { ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_TEARDOWN: ++ case WLAN_S1G_TWT_SETUP: ++ ieee80211_s1g_status_twt_action(sdata, skb); ++ break; ++ default: ++ break; ++ } ++ } ++} ++ + static void ieee80211_iface_work(struct work_struct *work) + { + struct ieee80211_sub_if_data *sdata = +@@ -1519,6 +1539,16 @@ static void ieee80211_iface_work(struct + WARN_ON(1); + break; + } ++ } else if (ieee80211_is_action(mgmt->frame_control) && ++ mgmt->u.action.category == WLAN_CATEGORY_S1G) { ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_TEARDOWN: ++ case WLAN_S1G_TWT_SETUP: ++ ieee80211_s1g_rx_twt_action(sdata, skb); ++ break; ++ default: ++ break; ++ } + } else if (ieee80211_is_ext(mgmt->frame_control)) { + if (sdata->vif.type == NL80211_IFTYPE_STATION) + ieee80211_sta_rx_queued_ext(sdata, skb); +@@ -1574,6 +1604,12 @@ static void ieee80211_iface_work(struct + kfree_skb(skb); + } + ++ /* process status queue */ ++ while ((skb = skb_dequeue(&sdata->status_queue))) { ++ ieee80211_iface_process_status(sdata, skb); ++ kfree_skb(skb); ++ } ++ + /* then other type-dependent work */ + switch (sdata->vif.type) { + case NL80211_IFTYPE_STATION: +@@ -1637,6 +1673,7 @@ static void ieee80211_setup_sdata(struct + } + + skb_queue_head_init(&sdata->skb_queue); ++ skb_queue_head_init(&sdata->status_queue); + INIT_WORK(&sdata->work, ieee80211_iface_work); + INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work); + INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work); +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3210,6 +3210,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802 + return RX_CONTINUE; + } + ++static bool ++ieee80211_process_rx_twt_action(struct ieee80211_rx_data *rx) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)rx->skb->data; ++ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); ++ struct ieee80211_sub_if_data *sdata = rx->sdata; ++ const struct ieee80211_sta_he_cap *hecap; ++ struct ieee80211_supported_band *sband; ++ ++ /* TWT actions are only supported in AP for the moment */ ++ if (sdata->vif.type != NL80211_IFTYPE_AP) ++ return false; ++ ++ if (!rx->local->ops->add_twt_setup) ++ return false; ++ ++ sband = rx->local->hw.wiphy->bands[status->band]; ++ hecap = ieee80211_get_he_iftype_cap(sband, ++ ieee80211_vif_type_p2p(&sdata->vif)); ++ if (!hecap) ++ return false; ++ ++ if (!(hecap->he_cap_elem.mac_cap_info[0] & ++ IEEE80211_HE_MAC_CAP0_TWT_RES)) ++ return false; ++ ++ if (!rx->sta) ++ return false; ++ ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_SETUP: { ++ struct ieee80211_twt_setup *twt; ++ ++ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + ++ 1 + /* action code */ ++ sizeof(struct ieee80211_twt_setup) + ++ 2 /* TWT req_type agrt */) ++ break; ++ ++ twt = (void *)mgmt->u.action.u.s1g.variable; ++ if (twt->element_id != WLAN_EID_S1G_TWT) ++ break; ++ ++ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + ++ 4 + /* action code + token + tlv */ ++ twt->length) ++ break; ++ ++ return true; /* queue the frame */ ++ } ++ case WLAN_S1G_TWT_TEARDOWN: ++ if (rx->skb->len < IEEE80211_MIN_ACTION_SIZE + 2) ++ break; ++ ++ return true; /* queue the frame */ ++ default: ++ break; ++ } ++ ++ return false; ++} ++ + static ieee80211_rx_result debug_noinline + ieee80211_rx_h_action(struct ieee80211_rx_data *rx) + { +@@ -3489,6 +3551,17 @@ ieee80211_rx_h_action(struct ieee80211_r + !mesh_path_sel_is_hwmp(sdata)) + break; + goto queue; ++ case WLAN_CATEGORY_S1G: ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_SETUP: ++ case WLAN_S1G_TWT_TEARDOWN: ++ if (ieee80211_process_rx_twt_action(rx)) ++ goto queue; ++ break; ++ default: ++ break; ++ } ++ break; + } + + return RX_CONTINUE; +--- a/net/mac80211/s1g.c ++++ b/net/mac80211/s1g.c +@@ -6,6 +6,7 @@ + #include + #include + #include "ieee80211_i.h" ++#include "driver-ops.h" + + void ieee80211_s1g_sta_rate_init(struct sta_info *sta) + { +@@ -14,3 +15,182 @@ void ieee80211_s1g_sta_rate_init(struct + sta->rx_stats.last_rate = + STA_STATS_FIELD(TYPE, STA_STATS_RATE_TYPE_S1G); + } ++ ++bool ieee80211_s1g_is_twt_setup(struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ ++ if (likely(!ieee80211_is_action(mgmt->frame_control))) ++ return false; ++ ++ if (likely(mgmt->u.action.category != WLAN_CATEGORY_S1G)) ++ return false; ++ ++ return mgmt->u.action.u.s1g.action_code == WLAN_S1G_TWT_SETUP; ++} ++ ++static void ++ieee80211_s1g_send_twt_setup(struct ieee80211_sub_if_data *sdata, const u8 *da, ++ const u8 *bssid, struct ieee80211_twt_setup *twt) ++{ ++ int len = IEEE80211_MIN_ACTION_SIZE + 4 + twt->length; ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_mgmt *mgmt; ++ struct sk_buff *skb; ++ ++ skb = dev_alloc_skb(local->hw.extra_tx_headroom + len); ++ if (!skb) ++ return; ++ ++ skb_reserve(skb, local->hw.extra_tx_headroom); ++ mgmt = skb_put_zero(skb, len); ++ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | ++ IEEE80211_STYPE_ACTION); ++ memcpy(mgmt->da, da, ETH_ALEN); ++ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); ++ memcpy(mgmt->bssid, bssid, ETH_ALEN); ++ ++ mgmt->u.action.category = WLAN_CATEGORY_S1G; ++ mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_SETUP; ++ memcpy(mgmt->u.action.u.s1g.variable, twt, 3 + twt->length); ++ ++ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | ++ IEEE80211_TX_INTFL_MLME_CONN_TX | ++ IEEE80211_TX_CTL_REQ_TX_STATUS; ++ ieee80211_tx_skb(sdata, skb); ++} ++ ++static void ++ieee80211_s1g_send_twt_teardown(struct ieee80211_sub_if_data *sdata, ++ const u8 *da, const u8 *bssid, u8 flowid) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_mgmt *mgmt; ++ struct sk_buff *skb; ++ u8 *id; ++ ++ skb = dev_alloc_skb(local->hw.extra_tx_headroom + ++ IEEE80211_MIN_ACTION_SIZE + 2); ++ if (!skb) ++ return; ++ ++ skb_reserve(skb, local->hw.extra_tx_headroom); ++ mgmt = skb_put_zero(skb, IEEE80211_MIN_ACTION_SIZE + 2); ++ mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | ++ IEEE80211_STYPE_ACTION); ++ memcpy(mgmt->da, da, ETH_ALEN); ++ memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); ++ memcpy(mgmt->bssid, bssid, ETH_ALEN); ++ ++ mgmt->u.action.category = WLAN_CATEGORY_S1G; ++ mgmt->u.action.u.s1g.action_code = WLAN_S1G_TWT_TEARDOWN; ++ id = (u8 *)mgmt->u.action.u.s1g.variable; ++ *id = flowid; ++ ++ IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | ++ IEEE80211_TX_CTL_REQ_TX_STATUS; ++ ieee80211_tx_skb(sdata, skb); ++} ++ ++static void ++ieee80211_s1g_rx_twt_setup(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)skb->data; ++ struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable; ++ struct ieee80211_twt_params *twt_agrt = (void *)twt->params; ++ ++ twt_agrt->req_type &= cpu_to_le16(~IEEE80211_TWT_REQTYPE_REQUEST); ++ ++ /* broadcast TWT not supported yet */ ++ if (twt->control & IEEE80211_TWT_CONTROL_NEG_TYPE_BROADCAST) { ++ le16p_replace_bits(&twt_agrt->req_type, ++ TWT_SETUP_CMD_REJECT, ++ IEEE80211_TWT_REQTYPE_SETUP_CMD); ++ goto out; ++ } ++ ++ drv_add_twt_setup(sdata->local, sdata, &sta->sta, twt); ++out: ++ ieee80211_s1g_send_twt_setup(sdata, mgmt->sa, sdata->vif.addr, twt); ++} ++ ++static void ++ieee80211_s1g_rx_twt_teardown(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ ++ drv_twt_teardown_request(sdata->local, sdata, &sta->sta, ++ mgmt->u.action.u.s1g.variable[0]); ++} ++ ++static void ++ieee80211_s1g_tx_twt_setup_fail(struct ieee80211_sub_if_data *sdata, ++ struct sta_info *sta, struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ struct ieee80211_twt_setup *twt = (void *)mgmt->u.action.u.s1g.variable; ++ struct ieee80211_twt_params *twt_agrt = (void *)twt->params; ++ u8 flowid = le16_get_bits(twt_agrt->req_type, ++ IEEE80211_TWT_REQTYPE_FLOWID); ++ ++ drv_twt_teardown_request(sdata->local, sdata, &sta->sta, flowid); ++ ++ ieee80211_s1g_send_twt_teardown(sdata, mgmt->sa, sdata->vif.addr, ++ flowid); ++} ++ ++void ieee80211_s1g_rx_twt_action(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ struct ieee80211_local *local = sdata->local; ++ struct sta_info *sta; ++ ++ mutex_lock(&local->sta_mtx); ++ ++ sta = sta_info_get_bss(sdata, mgmt->sa); ++ if (!sta) ++ goto out; ++ ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_SETUP: ++ ieee80211_s1g_rx_twt_setup(sdata, sta, skb); ++ break; ++ case WLAN_S1G_TWT_TEARDOWN: ++ ieee80211_s1g_rx_twt_teardown(sdata, sta, skb); ++ break; ++ default: ++ break; ++ } ++ ++out: ++ mutex_unlock(&local->sta_mtx); ++} ++ ++void ieee80211_s1g_status_twt_action(struct ieee80211_sub_if_data *sdata, ++ struct sk_buff *skb) ++{ ++ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; ++ struct ieee80211_local *local = sdata->local; ++ struct sta_info *sta; ++ ++ mutex_lock(&local->sta_mtx); ++ ++ sta = sta_info_get_bss(sdata, mgmt->da); ++ if (!sta) ++ goto out; ++ ++ switch (mgmt->u.action.u.s1g.action_code) { ++ case WLAN_S1G_TWT_SETUP: ++ /* process failed twt setup frames */ ++ ieee80211_s1g_tx_twt_setup_fail(sdata, sta, skb); ++ break; ++ default: ++ break; ++ } ++ ++out: ++ mutex_unlock(&local->sta_mtx); ++} +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -705,13 +705,26 @@ static void ieee80211_report_used_skb(st + /* Check to see if packet is a TDLS teardown packet */ + if (ieee80211_is_data(hdr->frame_control) && + (ieee80211_get_tdls_action(skb, hdr_size) == +- WLAN_TDLS_TEARDOWN)) ++ WLAN_TDLS_TEARDOWN)) { + ieee80211_tdls_td_tx_handle(local, sdata, skb, + info->flags); +- else ++ } else if (ieee80211_s1g_is_twt_setup(skb)) { ++ if (!acked) { ++ struct sk_buff *qskb; ++ ++ qskb = skb_clone(skb, GFP_ATOMIC); ++ if (qskb) { ++ skb_queue_tail(&sdata->status_queue, ++ qskb); ++ ieee80211_queue_work(&local->hw, ++ &sdata->work); ++ } ++ } ++ } else { + ieee80211_mgd_conn_tx_status(sdata, + hdr->frame_control, + acked); ++ } + } + + rcu_read_unlock(); +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2804,6 +2804,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d + TP_ARGS(local, sdata, sta, enabled) + ); + ++TRACE_EVENT(drv_add_twt_setup, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sta *sta, ++ struct ieee80211_twt_setup *twt, ++ struct ieee80211_twt_params *twt_agrt), ++ ++ TP_ARGS(local, sta, twt, twt_agrt), ++ ++ TP_STRUCT__entry( ++ LOCAL_ENTRY ++ STA_ENTRY ++ __field(u8, dialog_token) ++ __field(u8, control) ++ __field(__le16, req_type) ++ __field(__le64, twt) ++ __field(u8, duration) ++ __field(__le16, mantissa) ++ __field(u8, channel) ++ ), ++ ++ TP_fast_assign( ++ LOCAL_ASSIGN; ++ STA_ASSIGN; ++ __entry->dialog_token = twt->dialog_token; ++ __entry->control = twt->control; ++ __entry->req_type = twt_agrt->req_type; ++ __entry->twt = twt_agrt->twt; ++ __entry->duration = twt_agrt->min_twt_dur; ++ __entry->mantissa = twt_agrt->mantissa; ++ __entry->channel = twt_agrt->channel; ++ ), ++ ++ TP_printk( ++ LOCAL_PR_FMT STA_PR_FMT ++ " token:%d control:0x%02x req_type:0x%04x" ++ " twt:%llu duration:%d mantissa:%d channel:%d", ++ LOCAL_PR_ARG, STA_PR_ARG, __entry->dialog_token, ++ __entry->control, le16_to_cpu(__entry->req_type), ++ le64_to_cpu(__entry->twt), __entry->duration, ++ le16_to_cpu(__entry->mantissa), __entry->channel ++ ) ++); ++ ++TRACE_EVENT(drv_twt_teardown_request, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sta *sta, u8 flowid), ++ ++ TP_ARGS(local, sta, flowid), ++ ++ TP_STRUCT__entry( ++ LOCAL_ENTRY ++ STA_ENTRY ++ __field(u8, flowid) ++ ), ++ ++ TP_fast_assign( ++ LOCAL_ASSIGN; ++ STA_ASSIGN; ++ __entry->flowid = flowid; ++ ), ++ ++ TP_printk( ++ LOCAL_PR_FMT STA_PR_FMT " flowid:%d", ++ LOCAL_PR_ARG, STA_PR_ARG, __entry->flowid ++ ) ++); ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/391-wireless-align-some-HE-capabilities-with-the-spec.patch b/package/kernel/mac80211/patches/subsys/391-wireless-align-some-HE-capabilities-with-the-spec.patch new file mode 100644 index 0000000000..eb32c49890 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/391-wireless-align-some-HE-capabilities-with-the-spec.patch @@ -0,0 +1,196 @@ +From: Johannes Berg +Date: Fri, 9 Apr 2021 12:40:17 +0300 +Subject: [PATCH] wireless: align some HE capabilities with the spec + +Some names were changed, align that with the spec as of +802.11ax-D6.1. + +Signed-off-by: Luca Coelho +Link: https://lore.kernel.org/r/iwlwifi.20210409123755.b1e5fbab0d8c.I3eb6076cb0714ec6aec6b8f9dee613ce4a05d825@changeid +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3627,7 +3627,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee + IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->mac_cap_info[4] &= ~m; + +- m = IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION | ++ m = IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION | + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | + IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING | + IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; +@@ -3637,7 +3637,7 @@ ath11k_mac_filter_he_cap_mesh(struct iee + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + he_cap_elem->phy_cap_info[2] &= ~m; + +- m = IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA | ++ m = IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK; + he_cap_elem->phy_cap_info[3] &= ~m; +@@ -3649,13 +3649,13 @@ ath11k_mac_filter_he_cap_mesh(struct iee + he_cap_elem->phy_cap_info[5] &= ~m; + + m = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | +- IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | ++ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; + he_cap_elem->phy_cap_info[6] &= ~m; + +- m = IEEE80211_HE_PHY_CAP7_SRP_BASED_SR | +- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | ++ m = IEEE80211_HE_PHY_CAP7_PSR_BASED_SR | ++ IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; + he_cap_elem->phy_cap_info[7] &= ~m; +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -307,8 +307,8 @@ mt7915_set_stream_he_txbf_caps(struct ie + IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; + elem->phy_cap_info[5] &= ~c; + +- c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | +- IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB; ++ c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | ++ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; + elem->phy_cap_info[6] &= ~c; + + elem->phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_MAX_NC_MASK; +@@ -348,8 +348,8 @@ mt7915_set_stream_he_txbf_caps(struct ie + c = (nss - 1) | (max_t(int, mcs->tx_mcs_160, 1) << 3); + elem->phy_cap_info[5] |= c; + +- c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB | +- IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB; ++ c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB | ++ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB; + elem->phy_cap_info[6] |= c; + } + +@@ -484,7 +484,7 @@ mt7915_init_he_caps(struct mt7915_phy *p + IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE | + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT; + he_cap_elem->phy_cap_info[7] |= +- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | ++ IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI; + he_cap_elem->phy_cap_info[8] |= + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -2065,7 +2065,7 @@ int ieee80211_get_vht_max_nss(struct iee + #define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 + #define IEEE80211_HE_MAC_CAP4_QTP 0x02 + #define IEEE80211_HE_MAC_CAP4_BQR 0x04 +-#define IEEE80211_HE_MAC_CAP4_SRP_RESP 0x08 ++#define IEEE80211_HE_MAC_CAP4_PSR_RESP 0x08 + #define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 + #define IEEE80211_HE_MAC_CAP4_OPS 0x20 + #define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40 +@@ -2076,7 +2076,7 @@ int ieee80211_get_vht_max_nss(struct iee + + #define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 0x01 + #define IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B41 0x02 +-#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION 0x04 ++#define IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECTIVE_TRANSMISSION 0x04 + #define IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU 0x08 + #define IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX 0x10 + #define IEEE80211_HE_MAC_CAP5_HE_DYNAMIC_SM_PS 0x20 +@@ -2134,7 +2134,7 @@ int ieee80211_get_vht_max_nss(struct iee + #define IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK 0x18 + #define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_1 0x00 + #define IEEE80211_HE_PHY_CAP3_DCM_MAX_RX_NSS_2 0x20 +-#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40 ++#define IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU 0x40 + #define IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER 0x80 + + #define IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE 0x01 +@@ -2181,15 +2181,15 @@ int ieee80211_get_vht_max_nss(struct iee + + #define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_42_SU 0x01 + #define IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU 0x02 +-#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB 0x04 +-#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB 0x08 ++#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB 0x04 ++#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB 0x08 + #define IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB 0x10 + #define IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE 0x20 + #define IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO 0x40 + #define IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT 0x80 + +-#define IEEE80211_HE_PHY_CAP7_SRP_BASED_SR 0x01 +-#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR 0x02 ++#define IEEE80211_HE_PHY_CAP7_PSR_BASED_SR 0x01 ++#define IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP 0x02 + #define IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI 0x04 + #define IEEE80211_HE_PHY_CAP7_MAX_NC_1 0x08 + #define IEEE80211_HE_PHY_CAP7_MAX_NC_2 0x10 +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -732,15 +732,15 @@ static ssize_t sta_he_capa_read(struct f + PFLAG(MAC, 4, BSRP_BQRP_A_MPDU_AGG, "BSRP-BQRP-A-MPDU-AGG"); + PFLAG(MAC, 4, QTP, "QTP"); + PFLAG(MAC, 4, BQR, "BQR"); +- PFLAG(MAC, 4, SRP_RESP, "SRP-RESP"); ++ PFLAG(MAC, 4, PSR_RESP, "PSR-RESP"); + PFLAG(MAC, 4, NDP_FB_REP, "NDP-FB-REP"); + PFLAG(MAC, 4, OPS, "OPS"); + PFLAG(MAC, 4, AMDSU_IN_AMPDU, "AMSDU-IN-AMPDU"); + + PRINT("MULTI-TID-AGG-TX-QOS-%d", ((cap[5] << 1) | (cap[4] >> 7)) & 0x7); + +- PFLAG(MAC, 5, SUBCHAN_SELECVITE_TRANSMISSION, +- "SUBCHAN-SELECVITE-TRANSMISSION"); ++ PFLAG(MAC, 5, SUBCHAN_SELECTIVE_TRANSMISSION, ++ "SUBCHAN-SELECTIVE-TRANSMISSION"); + PFLAG(MAC, 5, UL_2x996_TONE_RU, "UL-2x996-TONE-RU"); + PFLAG(MAC, 5, OM_CTRL_UL_MU_DATA_DIS_RX, "OM-CTRL-UL-MU-DATA-DIS-RX"); + PFLAG(MAC, 5, HE_DYNAMIC_SM_PS, "HE-DYNAMIC-SM-PS"); +@@ -832,8 +832,8 @@ static ssize_t sta_he_capa_read(struct f + + PFLAG(PHY, 3, DCM_MAX_RX_NSS_1, "DCM-MAX-RX-NSS-1"); + PFLAG(PHY, 3, DCM_MAX_RX_NSS_2, "DCM-MAX-RX-NSS-2"); +- PFLAG(PHY, 3, RX_HE_MU_PPDU_FROM_NON_AP_STA, +- "RX-HE-MU-PPDU-FROM-NON-AP-STA"); ++ PFLAG(PHY, 3, RX_PARTIAL_BW_SU_IN_20MHZ_MU, ++ "RX-PARTIAL-BW-SU-IN-20MHZ-MU"); + PFLAG(PHY, 3, SU_BEAMFORMER, "SU-BEAMFORMER"); + + PFLAG(PHY, 4, SU_BEAMFORMEE, "SU-BEAMFORMEE"); +@@ -853,16 +853,17 @@ static ssize_t sta_he_capa_read(struct f + + PFLAG(PHY, 6, CODEBOOK_SIZE_42_SU, "CODEBOOK-SIZE-42-SU"); + PFLAG(PHY, 6, CODEBOOK_SIZE_75_MU, "CODEBOOK-SIZE-75-MU"); +- PFLAG(PHY, 6, TRIG_SU_BEAMFORMER_FB, "TRIG-SU-BEAMFORMER-FB"); +- PFLAG(PHY, 6, TRIG_MU_BEAMFORMER_FB, "TRIG-MU-BEAMFORMER-FB"); ++ PFLAG(PHY, 6, TRIG_SU_BEAMFORMING_FB, "TRIG-SU-BEAMFORMING-FB"); ++ PFLAG(PHY, 6, TRIG_MU_BEAMFORMING_PARTIAL_BW_FB, ++ "MU-BEAMFORMING-PARTIAL-BW-FB"); + PFLAG(PHY, 6, TRIG_CQI_FB, "TRIG-CQI-FB"); + PFLAG(PHY, 6, PARTIAL_BW_EXT_RANGE, "PARTIAL-BW-EXT-RANGE"); + PFLAG(PHY, 6, PARTIAL_BANDWIDTH_DL_MUMIMO, + "PARTIAL-BANDWIDTH-DL-MUMIMO"); + PFLAG(PHY, 6, PPE_THRESHOLD_PRESENT, "PPE-THRESHOLD-PRESENT"); + +- PFLAG(PHY, 7, SRP_BASED_SR, "SRP-BASED-SR"); +- PFLAG(PHY, 7, POWER_BOOST_FACTOR_AR, "POWER-BOOST-FACTOR-AR"); ++ PFLAG(PHY, 7, PSR_BASED_SR, "PSR-BASED-SR"); ++ PFLAG(PHY, 7, POWER_BOOST_FACTOR_SUPP, "POWER-BOOST-FACTOR-SUPP"); + PFLAG(PHY, 7, HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, + "HE-SU-MU-PPDU-4XLTF-AND-08-US-GI"); + PFLAG_RANGE(PHY, 7, MAX_NC, 0, 1, 1, "MAX-NC-%d"); +--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +@@ -631,7 +631,7 @@ static struct ieee80211_sband_iftype_dat + .phy_cap_info[6] = + IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT, + .phy_cap_info[7] = +- IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | ++ IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | + IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP7_MAX_NC_1, + .phy_cap_info[8] = diff --git a/package/kernel/mac80211/patches/subsys/392-wireless-fix-spelling-of-A-MSDU-in-HE-capabilities.patch b/package/kernel/mac80211/patches/subsys/392-wireless-fix-spelling-of-A-MSDU-in-HE-capabilities.patch new file mode 100644 index 0000000000..0bd01126f7 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/392-wireless-fix-spelling-of-A-MSDU-in-HE-capabilities.patch @@ -0,0 +1,113 @@ +From: Johannes Berg +Date: Fri, 9 Apr 2021 12:40:24 +0300 +Subject: [PATCH] wireless: fix spelling of A-MSDU in HE capabilities + +In the HE capabilities, spell A-MSDU correctly, not "A-MDSU". + +Signed-off-by: Luca Coelho +Link: https://lore.kernel.org/r/iwlwifi.20210409123755.9e6ff1af1181.If6868bc6902ccd9a95c74c78f716c4b41473ef14@changeid +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +@@ -598,7 +598,7 @@ static struct ieee80211_sband_iftype_dat + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, + .mac_cap_info[4] = +- IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU | ++ IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_MULTI_TID_AGG_TX_QOS_B40 | +@@ -682,7 +682,7 @@ static struct ieee80211_sband_iftype_dat + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, + .mac_cap_info[4] = +- IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, ++ IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .mac_cap_info[5] = + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU, + .phy_cap_info[0] = +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -427,7 +427,7 @@ mt7915_init_he_caps(struct mt7915_phy *p + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; + he_cap_elem->mac_cap_info[4] = +- IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU; ++ IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; + + if (band == NL80211_BAND_2GHZ) + he_cap_elem->phy_cap_info[0] = +--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +@@ -1353,7 +1353,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *sk + if (elem->mac_cap_info[3] & IEEE80211_HE_MAC_CAP3_OMI_CONTROL) + cap |= STA_REC_HE_CAP_OM; + +- if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU) ++ if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU) + cap |= STA_REC_HE_CAP_AMSDU_IN_AMPDU; + + if (elem->mac_cap_info[4] & IEEE80211_HE_MAC_CAP4_BQR) +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -2068,7 +2068,7 @@ int ieee80211_get_vht_max_nss(struct iee + #define IEEE80211_HE_MAC_CAP4_PSR_RESP 0x08 + #define IEEE80211_HE_MAC_CAP4_NDP_FB_REP 0x10 + #define IEEE80211_HE_MAC_CAP4_OPS 0x20 +-#define IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU 0x40 ++#define IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU 0x40 + /* Multi TID agg TX is split between byte #4 and #5 + * The value is a combination of B39,B40,B41 + */ +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -735,7 +735,7 @@ static ssize_t sta_he_capa_read(struct f + PFLAG(MAC, 4, PSR_RESP, "PSR-RESP"); + PFLAG(MAC, 4, NDP_FB_REP, "NDP-FB-REP"); + PFLAG(MAC, 4, OPS, "OPS"); +- PFLAG(MAC, 4, AMDSU_IN_AMPDU, "AMSDU-IN-AMPDU"); ++ PFLAG(MAC, 4, AMSDU_IN_AMPDU, "AMSDU-IN-AMPDU"); + + PRINT("MULTI-TID-AGG-TX-QOS-%d", ((cap[5] << 1) | (cap[4] >> 7)) & 0x7); + +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -2748,7 +2748,7 @@ static const struct ieee80211_sband_ifty + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, +- .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, ++ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | +@@ -2792,7 +2792,7 @@ static const struct ieee80211_sband_ifty + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, +- .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, ++ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | + IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A | +@@ -2838,7 +2838,7 @@ static const struct ieee80211_sband_ifty + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, +- .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, ++ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | +@@ -2886,7 +2886,7 @@ static const struct ieee80211_sband_ifty + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | + IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, +- .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMDSU_IN_AMPDU, ++ .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G | diff --git a/package/kernel/mac80211/patches/subsys/393-wireless-align-HE-capabilities-A-MPDU-Length-Exponen.patch b/package/kernel/mac80211/patches/subsys/393-wireless-align-HE-capabilities-A-MPDU-Length-Exponen.patch new file mode 100644 index 0000000000..42b71df9d1 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/393-wireless-align-HE-capabilities-A-MPDU-Length-Exponen.patch @@ -0,0 +1,148 @@ +From: Johannes Berg +Date: Fri, 9 Apr 2021 12:40:20 +0300 +Subject: [PATCH] wireless: align HE capabilities A-MPDU Length Exponent + Extension + +The A-MPDU length exponent extension is defined differently in +802.11ax D6.1, align with that. + +Signed-off-by: Luca Coelho +Link: https://lore.kernel.org/r/iwlwifi.20210409123755.c2a257d3e2df.I3455245d388c52c61dace7e7958dbed7e807cfb6@changeid +Signed-off-by: Johannes Berg +--- + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -1290,9 +1290,8 @@ static void ath11k_peer_assoc_h_he(struc + * request, then use MAX_AMPDU_LEN_FACTOR as 16 to calculate max_ampdu + * length. + */ +- ampdu_factor = (he_cap->he_cap_elem.mac_cap_info[3] & +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) >> +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_SHIFT; ++ ampdu_factor = u8_get_bits(he_cap->he_cap_elem.mac_cap_info[3], ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK); + + if (ampdu_factor) { + if (sta->vht_cap.vht_supported) +--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c ++++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +@@ -596,7 +596,7 @@ static struct ieee80211_sband_iftype_dat + IEEE80211_HE_MAC_CAP2_32BIT_BA_BITMAP, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU | + IEEE80211_HE_MAC_CAP4_MULTI_TID_AGG_TX_QOS_B39, +@@ -680,7 +680,7 @@ static struct ieee80211_sband_iftype_dat + IEEE80211_HE_MAC_CAP2_BSR, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2, + .mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .mac_cap_info[5] = +--- a/drivers/net/wireless/mac80211_hwsim.c ++++ b/drivers/net/wireless/mac80211_hwsim.c +@@ -2747,7 +2747,7 @@ static const struct ieee80211_sband_ifty + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, + .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | +@@ -2791,7 +2791,7 @@ static const struct ieee80211_sband_ifty + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, + .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[1] = + IEEE80211_HE_PHY_CAP1_PREAMBLE_PUNC_RX_MASK | +@@ -2837,7 +2837,7 @@ static const struct ieee80211_sband_ifty + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, + .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | +@@ -2885,7 +2885,7 @@ static const struct ieee80211_sband_ifty + IEEE80211_HE_MAC_CAP2_ACK_EN, + .mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2, ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3, + .mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU, + .phy_cap_info[0] = + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | +--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c ++++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c +@@ -425,7 +425,7 @@ mt7915_init_he_caps(struct mt7915_phy *p + IEEE80211_HE_MAC_CAP0_HTC_HE; + he_cap_elem->mac_cap_info[3] = + IEEE80211_HE_MAC_CAP3_OMI_CONTROL | +- IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED; ++ IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3; + he_cap_elem->mac_cap_info[4] = + IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU; + +--- a/include/linux/ieee80211.h ++++ b/include/linux/ieee80211.h +@@ -2051,17 +2051,15 @@ int ieee80211_get_vht_max_nss(struct iee + * A-MDPU Length Exponent field in the HT capabilities, VHT capabilities and the + * same field in the HE capabilities. + */ +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT 0x00 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1 0x08 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2 0x10 +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED 0x18 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_0 0x00 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1 0x08 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2 0x10 ++#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3 0x18 + #define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK 0x18 + #define IEEE80211_HE_MAC_CAP3_AMSDU_FRAG 0x20 + #define IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED 0x40 + #define IEEE80211_HE_MAC_CAP3_RX_CTRL_FRAME_TO_MULTIBSS 0x80 + +-#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_SHIFT 3 +- + #define IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG 0x01 + #define IEEE80211_HE_MAC_CAP4_QTP 0x02 + #define IEEE80211_HE_MAC_CAP4_BQR 0x04 +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -711,17 +711,17 @@ static ssize_t sta_he_capa_read(struct f + PFLAG(MAC, 3, OFDMA_RA, "OFDMA-RA"); + + switch (cap[3] & IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK) { +- case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_USE_VHT: +- PRINT("MAX-AMPDU-LEN-EXP-USE-VHT"); ++ case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_0: ++ PRINT("MAX-AMPDU-LEN-EXP-USE-EXT-0"); + break; +- case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_1: +- PRINT("MAX-AMPDU-LEN-EXP-VHT-1"); ++ case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_1: ++ PRINT("MAX-AMPDU-LEN-EXP-VHT-EXT-1"); + break; +- case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_VHT_2: +- PRINT("MAX-AMPDU-LEN-EXP-VHT-2"); ++ case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_2: ++ PRINT("MAX-AMPDU-LEN-EXP-VHT-EXT-2"); + break; +- case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_RESERVED: +- PRINT("MAX-AMPDU-LEN-EXP-RESERVED"); ++ case IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3: ++ PRINT("MAX-AMPDU-LEN-EXP-VHT-EXT-3"); + break; + } + diff --git a/package/kernel/mac80211/patches/subsys/394-mac80211-fix-rate-control-for-retransmitted-frames.patch b/package/kernel/mac80211/patches/subsys/394-mac80211-fix-rate-control-for-retransmitted-frames.patch new file mode 100644 index 0000000000..cd91a925f3 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/394-mac80211-fix-rate-control-for-retransmitted-frames.patch @@ -0,0 +1,35 @@ +From: Felix Fietkau +Date: Mon, 22 Nov 2021 21:39:38 +0100 +Subject: [PATCH] mac80211: fix rate control for retransmitted frames + +Since retransmission clears info->control, rate control needs to be called +again, otherwise the driver might crash due to invalid rates. + +Cc: stable@vger.kernel.org # 5.14+ +Reported-by: Aaro Koskinen +Reported-by: Robert W +Fixes: 03c3911d2d67 ("mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -1835,15 +1835,15 @@ static int invoke_tx_handlers_late(struc + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + ieee80211_tx_result res = TX_CONTINUE; + ++ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) ++ CALL_TXH(ieee80211_tx_h_rate_ctrl); ++ + if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { + __skb_queue_tail(&tx->skbs, tx->skb); + tx->skb = NULL; + goto txh_done; + } + +- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) +- CALL_TXH(ieee80211_tx_h_rate_ctrl); +- + CALL_TXH(ieee80211_tx_h_michael_mic_add); + CALL_TXH(ieee80211_tx_h_sequence); + CALL_TXH(ieee80211_tx_h_fragment); diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch index 406c3a2ee3..6f13f64208 100644 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch @@ -1,6 +1,6 @@ --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -3745,6 +3745,7 @@ struct mgmt_frame_regs { +@@ -3814,6 +3814,7 @@ struct mgmt_frame_regs { * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful @@ -8,7 +8,7 @@ * * @set_wds_peer: set the WDS peer for a WDS interface * -@@ -4067,6 +4068,7 @@ struct cfg80211_ops { +@@ -4138,6 +4139,7 @@ struct cfg80211_ops { enum nl80211_tx_power_setting type, int mbm); int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); @@ -36,9 +36,9 @@ u8 ps_dtim_period; --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -2560,6 +2560,9 @@ enum nl80211_commands { - * disassoc events to indicate that an immediate reconnect to the AP - * is desired. +@@ -2593,6 +2593,9 @@ enum nl80211_commands { + * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE + * information for the time while performing a color switch. * + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce + * transmit power to stay within regulatory limits. u32, dBi. @@ -46,9 +46,9 @@ * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3057,6 +3060,8 @@ enum nl80211_attrs { - - NL80211_ATTR_DISABLE_HE, +@@ -3096,6 +3099,8 @@ enum nl80211_attrs { + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + @@ -57,7 +57,7 @@ __NL80211_ATTR_AFTER_LAST, --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2728,6 +2728,19 @@ static int ieee80211_get_tx_power(struct +@@ -2769,6 +2769,19 @@ static int ieee80211_get_tx_power(struct return 0; } @@ -77,7 +77,7 @@ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, const u8 *addr) { -@@ -4158,6 +4171,7 @@ const struct cfg80211_ops mac80211_confi +@@ -4413,6 +4426,7 @@ const struct cfg80211_ops mac80211_confi .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, @@ -87,7 +87,7 @@ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -1390,6 +1390,7 @@ struct ieee80211_local { +@@ -1435,6 +1435,7 @@ struct ieee80211_local { int dynamic_ps_forced_timeout; int user_power_level; /* in dBm, for all interfaces */ @@ -129,15 +129,15 @@ local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -740,6 +740,7 @@ static const struct nla_policy nl80211_p - NLA_POLICY_RANGE(NLA_U8, NL80211_SAE_PWE_HUNT_AND_PECK, - NL80211_SAE_PWE_BOTH), - [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, +@@ -757,6 +757,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 }, + [NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy), + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, }; /* policy for the key attributes */ -@@ -3248,6 +3249,20 @@ static int nl80211_set_wiphy(struct sk_b +@@ -3322,6 +3323,20 @@ static int nl80211_set_wiphy(struct sk_b if (result) return result; } diff --git a/package/kernel/mt76/Makefile b/package/kernel/mt76/Makefile index e4051d8347..e947f1a2f3 100644 --- a/package/kernel/mt76/Makefile +++ b/package/kernel/mt76/Makefile @@ -8,11 +8,12 @@ PKG_LICENSE_FILES:= PKG_SOURCE_URL:=https://github.com/openwrt/mt76 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2021-06-06 -PKG_SOURCE_VERSION:=22b690334c0f49b11534cc2e331c9d5e17c4a0bc -PKG_MIRROR_HASH:=ff5e563935919d2e40c1e7254ef3bc06f7ecc5e69f8ddd12903e8f5de942d630 +PKG_SOURCE_DATE:=2021-11-23 +PKG_SOURCE_VERSION:=99225b985cbcab4707589f1fa313436f4bf1e368 +PKG_MIRROR_HASH:=6444c7d49d778c7621b03f0f201ce41f6dc9ac00dedb29c66478360b4fd60492 PKG_MAINTAINER:=Felix Fietkau +PKG_USE_NINJA:=0 PKG_BUILD_PARALLEL:=1 PKG_CONFIG_DEPENDS += \ @@ -151,6 +152,14 @@ define KernelPackage/mt76-connac FILES:= $(PKG_BUILD_DIR)/mt76-connac-lib.ko endef +define KernelPackage/mt76-sdio + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7615/MT79xx SDIO driver common code + HIDDEN:=1 + DEPENDS+=+kmod-mt76-core +kmod-mmc + FILES:= $(PKG_BUILD_DIR)/mt76-sdio.ko +endef + define KernelPackage/mt7615-common $(KernelPackage/mt76-default) TITLE:=MediaTek MT7615 wireless driver common code @@ -195,9 +204,8 @@ endef define KernelPackage/mt7663s $(KernelPackage/mt76-default) TITLE:=MediaTek MT7663s wireless driver - DEPENDS+=+kmod-mmc +kmod-mt7615-common +kmod-mt7663-usb-sdio + DEPENDS+=+kmod-mt76-sdio +kmod-mt7615-common +kmod-mt7663-usb-sdio FILES:= \ - $(PKG_BUILD_DIR)/mt76-sdio.ko \ $(PKG_BUILD_DIR)/mt7615/mt7663s.ko AUTOLOAD:=$(call AutoProbe,mt7663s) endef @@ -218,10 +226,25 @@ define KernelPackage/mt7915e AUTOLOAD:=$(call AutoProbe,mt7915e) endef +define KernelPackage/mt7921-common + TITLE:=MediaTek MT7615 wireless driver common code + HIDDEN:=1 + DEPENDS+=@PCI_SUPPORT +kmod-mt76-core +kmod-mt76-connac + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921-common.ko +endef + +define KernelPackage/mt7921s + $(KernelPackage/mt76-default) + TITLE:=MediaTek MT7921s wireless driver + DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-mt76-sdio +kmod-mt7921-common + FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921s.ko + AUTOLOAD:=$(call AutoProbe,mt7921s) +endef + define KernelPackage/mt7921e $(KernelPackage/mt76-default) TITLE:=MediaTek MT7921e wireless driver - DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac + DEPENDS+=@PCI_SUPPORT +kmod-mt76-connac +kmod-mt7921-common FILES:= $(PKG_BUILD_DIR)/mt7921/mt7921e.ko AUTOLOAD:=$(call AutoProbe,mt7921e) endef @@ -287,6 +310,9 @@ endif ifdef CONFIG_PACKAGE_kmod-mt76-connac PKG_MAKE_FLAGS += CONFIG_MT76_CONNAC_LIB=m endif +ifdef CONFIG_PACKAGE_kmod-mt76-sdio + PKG_MAKE_FLAGS += CONFIG_MT76_SDIO=m +endif ifdef CONFIG_PACKAGE_kmod-mt7615-common PKG_MAKE_FLAGS += CONFIG_MT7615_COMMON=m endif @@ -301,7 +327,6 @@ ifdef CONFIG_PACKAGE_kmod-mt7663-usb-sdio PKG_MAKE_FLAGS += CONFIG_MT7663_USB_SDIO_COMMON=m endif ifdef CONFIG_PACKAGE_kmod-mt7663s - PKG_MAKE_FLAGS += CONFIG_MT76_SDIO=m PKG_MAKE_FLAGS += CONFIG_MT7663S=m endif ifdef CONFIG_PACKAGE_kmod-mt7663u @@ -310,6 +335,12 @@ endif ifdef CONFIG_PACKAGE_kmod-mt7915e PKG_MAKE_FLAGS += CONFIG_MT7915E=m endif +ifdef CONFIG_PACKAGE_kmod-mt7921-common + PKG_MAKE_FLAGS += CONFIG_MT7921_COMMON=m +endif +ifdef CONFIG_PACKAGE_kmod-mt7921s + PKG_MAKE_FLAGS += CONFIG_MT7921S=m +endif ifdef CONFIG_PACKAGE_kmod-mt7921e PKG_MAKE_FLAGS += CONFIG_MT7921E=m endif @@ -432,6 +463,7 @@ $(eval $(call KernelPackage,mt76x2u)) $(eval $(call KernelPackage,mt76x2)) $(eval $(call KernelPackage,mt7603)) $(eval $(call KernelPackage,mt76-connac)) +$(eval $(call KernelPackage,mt76-sdio)) $(eval $(call KernelPackage,mt7615-common)) $(eval $(call KernelPackage,mt7615-firmware)) $(eval $(call KernelPackage,mt7615e)) @@ -441,6 +473,8 @@ $(eval $(call KernelPackage,mt7663-usb-sdio)) $(eval $(call KernelPackage,mt7663u)) $(eval $(call KernelPackage,mt7663s)) $(eval $(call KernelPackage,mt7915e)) +$(eval $(call KernelPackage,mt7921-common)) +$(eval $(call KernelPackage,mt7921s)) $(eval $(call KernelPackage,mt7921e)) $(eval $(call KernelPackage,mt76)) $(eval $(call BuildPackage,mt76-test)) diff --git a/package/kernel/mt76/patches/100-Revert-of-net-pass-the-dst-buffer-to-of_get_mac_addr.patch b/package/kernel/mt76/patches/100-Revert-of-net-pass-the-dst-buffer-to-of_get_mac_addr.patch new file mode 100644 index 0000000000..24b1240548 --- /dev/null +++ b/package/kernel/mt76/patches/100-Revert-of-net-pass-the-dst-buffer-to-of_get_mac_addr.patch @@ -0,0 +1,26 @@ +From: Felix Fietkau +Date: Tue, 23 Nov 2021 17:01:45 +0100 +Subject: [PATCH] Revert "of: net: pass the dst buffer to of_get_mac_address()" + +This reverts commit 4932c5d80153c336c77dbe8d7af9f8fdd879d01f. +--- + +--- a/eeprom.c ++++ b/eeprom.c +@@ -105,9 +105,15 @@ mt76_eeprom_override(struct mt76_phy *ph + { + struct mt76_dev *dev = phy->dev; + ++#ifdef CONFIG_OF + struct device_node *np = dev->dev->of_node; ++ const u8 *mac = NULL; + +- of_get_mac_address(np, phy->macaddr); ++ if (np) ++ mac = of_get_mac_address(np); ++ if (!IS_ERR_OR_NULL(mac)) ++ ether_addr_copy(phy->macaddr, mac); ++#endif + + if (!is_valid_ether_addr(phy->macaddr)) { + eth_random_addr(phy->macaddr); diff --git a/package/network/config/netifd/Makefile b/package/network/config/netifd/Makefile index f9aea470cd..cd4f8f423d 100644 --- a/package/network/config/netifd/Makefile +++ b/package/network/config/netifd/Makefile @@ -5,9 +5,9 @@ PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git -PKG_SOURCE_DATE:=2021-11-27 -PKG_SOURCE_VERSION:=a68e80513abb73cc76b94b5d70d0813344fa7cd7 -PKG_MIRROR_HASH:=4f2eff7a0bd4e9b278d220a4361e8948b582feab59eeedcc5eb120678aa72d0d +PKG_SOURCE_DATE:=2021-10-30 +PKG_SOURCE_VERSION:=8f82742ca4f47f459284f3a07323d04da72ea5f6 +PKG_MIRROR_HASH:=5e519bb1aec9bb30782213f32f19f12e874c909e42826618dd4332ded816d2fe PKG_MAINTAINER:=Felix Fietkau PKG_LICENSE:=GPL-2.0 diff --git a/package/network/services/hostapd/Makefile b/package/network/services/hostapd/Makefile index 67ea89c339..783c10d587 100644 --- a/package/network/services/hostapd/Makefile +++ b/package/network/services/hostapd/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=hostapd -PKG_RELEASE:=35 +PKG_RELEASE:=37 PKG_SOURCE_URL:=http://w1.fi/hostap.git PKG_SOURCE_PROTO:=git diff --git a/package/network/services/hostapd/files/hostapd-basic.config b/package/network/services/hostapd/files/hostapd-basic.config index 947e2fa200..33c38192b1 100644 --- a/package/network/services/hostapd/files/hostapd-basic.config +++ b/package/network/services/hostapd/files/hostapd-basic.config @@ -384,7 +384,7 @@ CONFIG_TLS=internal #CONFIG_OWE=y # Airtime policy support -#CONFIG_AIRTIME_POLICY=y +CONFIG_AIRTIME_POLICY=y # Override default value for the wpa_disable_eapol_key_retries configuration # parameter. See that parameter in hostapd.conf for more details. diff --git a/package/network/services/hostapd/files/hostapd.sh b/package/network/services/hostapd/files/hostapd.sh index 0887fe2737..6961acc0e1 100644 --- a/package/network/services/hostapd/files/hostapd.sh +++ b/package/network/services/hostapd/files/hostapd.sh @@ -91,6 +91,7 @@ hostapd_add_log_config() { hostapd_common_add_device_config() { config_add_array basic_rate config_add_array supported_rates + config_add_string beacon_rate config_add_string country country3 config_add_boolean country_ie doth @@ -100,6 +101,7 @@ hostapd_common_add_device_config() { config_add_boolean legacy_rates config_add_int cell_density config_add_boolean vendor_vht + config_add_int rts_threshold config_add_string acs_chan_bias config_add_array hostapd_options @@ -116,7 +118,8 @@ hostapd_prepare_device_config() { local base_cfg= json_get_vars country country3 country_ie beacon_int:100 dtim_period:2 doth require_mode legacy_rates \ - acs_chan_bias local_pwr_constraint spectrum_mgmt_required airtime_mode cell_density vendor_vht + acs_chan_bias local_pwr_constraint spectrum_mgmt_required airtime_mode cell_density vendor_vht \ + rts_threshold beacon_rate hostapd_set_log_options base_cfg @@ -209,9 +212,11 @@ hostapd_prepare_device_config() { hostapd_add_rate brlist "$br" done + [ -n "$beacon_rate" ] && append base_cfg "beacon_rate=$beacon_rate" "$N" [ -n "$rlist" ] && append base_cfg "supported_rates=$rlist" "$N" [ -n "$brlist" ] && append base_cfg "basic_rates=$brlist" "$N" append base_cfg "beacon_int=$beacon_int" "$N" + [ -n "$rts_threshold" ] && append base_cfg "rts_threshold=$rts_threshold" "$N" append base_cfg "dtim_period=$dtim_period" "$N" [ "$airtime_mode" -gt 0 ] && append base_cfg "airtime_mode=$airtime_mode" "$N" @@ -271,7 +276,7 @@ hostapd_common_add_bss_config() { config_add_array domain_match domain_match2 domain_suffix_match domain_suffix_match2 config_add_string ieee80211w_mgmt_cipher - config_add_int dynamic_vlan vlan_naming + config_add_int dynamic_vlan vlan_naming vlan_no_bridge config_add_string vlan_tagged_interface vlan_bridge config_add_string vlan_file @@ -289,6 +294,7 @@ hostapd_common_add_bss_config() { config_add_boolean wnm_sleep_mode wnm_sleep_mode_no_keys bss_transition config_add_int time_advertisement config_add_string time_zone + config_add_string vendor_elements config_add_boolean ieee80211k rrm_neighbor_report rrm_beacon_report @@ -321,7 +327,7 @@ hostapd_common_add_bss_config() { config_add_int iw_ipaddr_type_availability iw_gas_address3 config_add_string iw_hessid iw_network_auth_type iw_qos_map_set config_add_array iw_roaming_consortium iw_domain_name iw_anqp_3gpp_cell_net iw_nai_realm - config_add_array iw_anqp_elem + config_add_array iw_anqp_elem iw_venue_name iw_venue_url config_add_boolean hs20 disable_dgaf osen config_add_int anqp_domain_id @@ -332,12 +338,21 @@ hostapd_common_add_bss_config() { config_add_array hs20_conn_capab config_add_string osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp + config_add_string hs20_t_c_server_url + config_add_array airtime_sta_weight config_add_int airtime_bss_weight airtime_bss_limit config_add_boolean multicast_to_unicast per_sta_vif config_add_array hostapd_bss_options + + config_add_boolean request_cui + config_add_array radius_auth_req_attr + config_add_array radius_acct_req_attr + + config_add_int eap_server + config_add_string eap_user_file ca_cert server_cert private_key private_key_passwd server_id } hostapd_set_vlan_file() { @@ -401,10 +416,22 @@ append_iw_nai_realm() { [ -n "$1" ] && append bss_conf "nai_realm=$1" "$N" } +append_iw_venue_name() { + append bss_conf "venue_name=$1" "$N" +} + +append_iw_venue_url() { + append bss_conf "venue_url=$1" "$N" +} + append_hs20_oper_friendly_name() { append bss_conf "hs20_oper_friendly_name=$1" "$N" } +append_osu_provider_friendly_name() { + append bss_conf "osu_friendly_name=$1" "$N" +} + append_osu_provider_service_desc() { append bss_conf "osu_service_desc=$1" "$N" } @@ -452,6 +479,7 @@ append_osu_provider() { append bss_conf "osu_method_list=$osu_method_list" "$N" config_list_foreach "$1" osu_service_desc append_osu_provider_service_desc + config_list_foreach "$1" osu_friendly_name append_osu_friendly_name config_list_foreach "$1" osu_icon append_osu_icon append bss_conf "$N" @@ -461,6 +489,14 @@ append_hs20_conn_capab() { [ -n "$1" ] && append bss_conf "hs20_conn_capab=$1" "$N" } +append_radius_acct_req_attr() { + append bss_conf "radius_acct_req_attr=$1" "$N" +} + +append_radius_auth_req_attr() { + append bss_conf "radius_auth_req_attr=$1" "$N" +} + append_airtime_sta_weight() { [ -n "$1" ] && append bss_conf "airtime_sta_weight=$1" "$N" } @@ -487,7 +523,9 @@ hostapd_set_bss_options() { bss_load_update_period chan_util_avg_period sae_require_mfp \ multi_ap multi_ap_backhaul_ssid multi_ap_backhaul_key skip_inactivity_poll \ airtime_bss_weight airtime_bss_limit airtime_sta_weight \ - multicast_to_unicast per_sta_vif + multicast_to_unicast per_sta_vif \ + eap_server eap_user_file ca_cert server_cert private_key private_key_passwd server_id \ + vendor_elements set_default isolate 0 set_default maxassoc 0 @@ -508,6 +546,7 @@ hostapd_set_bss_options() { set_default multi_ap 0 set_default airtime_bss_weight 0 set_default airtime_bss_limit 0 + set_default eap_server 0 append bss_conf "ctrl_interface=/var/run/hostapd" if [ "$isolate" -gt 0 ]; then @@ -534,6 +573,7 @@ hostapd_set_bss_options() { append bss_conf "uapsd_advertisement_enabled=$uapsd" "$N" append bss_conf "utf8_ssid=$utf8_ssid" "$N" append bss_conf "multi_ap=$multi_ap" "$N" + [ -n "$vendor_elements" ] && append bss_conf "vendor_elements=$vendor_elements" "$N" [ "$tdls_prohibit" -gt 0 ] && append bss_conf "tdls_prohibit=$tdls_prohibit" "$N" @@ -552,6 +592,7 @@ hostapd_set_bss_options() { append bss_conf "acct_server_shared_secret=$acct_secret" "$N" [ -n "$acct_interval" ] && \ append bss_conf "radius_acct_interim_interval=$acct_interval" "$N" + json_for_each_item append_radius_acct_req_attr radius_acct_req_attr } case "$auth_type" in @@ -606,7 +647,7 @@ hostapd_set_bss_options() { auth_server auth_secret auth_port \ dae_client dae_secret dae_port \ ownip radius_client_addr \ - eap_reauth_period + eap_reauth_period request_cui # radius can provide VLAN ID for clients vlan_possible=1 @@ -618,18 +659,22 @@ hostapd_set_bss_options() { set_default auth_port 1812 set_default dae_port 3799 + set_default request_cui 0 + [ "$eap_server" -eq 0 ] && { + append bss_conf "auth_server_addr=$auth_server" "$N" + append bss_conf "auth_server_port=$auth_port" "$N" + append bss_conf "auth_server_shared_secret=$auth_secret" "$N" + } - append bss_conf "auth_server_addr=$auth_server" "$N" - append bss_conf "auth_server_port=$auth_port" "$N" - append bss_conf "auth_server_shared_secret=$auth_secret" "$N" - + [ "$request_cui" -gt 0 ] && append bss_conf "radius_request_cui=$request_cui" "$N" [ -n "$eap_reauth_period" ] && append bss_conf "eap_reauth_period=$eap_reauth_period" "$N" [ -n "$dae_client" -a -n "$dae_secret" ] && { append bss_conf "radius_das_port=$dae_port" "$N" append bss_conf "radius_das_client=$dae_client $dae_secret" "$N" } + json_for_each_item append_radius_auth_req_attr radius_auth_req_attr [ -n "$ownip" ] && append bss_conf "own_ip_addr=$ownip" "$N" [ -n "$radius_client_addr" ] && append bss_conf "radius_client_addr=$radius_client_addr" "$N" @@ -701,7 +746,8 @@ hostapd_set_bss_options() { } append bss_conf "ssid=$ssid" "$N" - [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge" "$N" + [ -n "$network_bridge" ] && append bss_conf "bridge=$network_bridge${N}wds_bridge=" "$N" + [ -n "$network_ifname" ] && append bss_conf "snoop_iface=$network_ifname" "$N" [ -n "$iapp_interface" ] && { local ifname network_get_device ifname "$iapp_interface" || ifname="$iapp_interface" @@ -742,7 +788,7 @@ hostapd_set_bss_options() { append bss_conf "ftm_responder=1" "$N" [ "$stationary_ap" -eq "1" ] && append bss_conf "stationary_ap=1" "$N" [ -n "$lci" ] && append bss_conf "lci=$lci" "$N" - [ -n "$civic" ] && append bss_conf "lci=$civic" "$N" + [ -n "$civic" ] && append bss_conf "civic=$civic" "$N" } fi @@ -766,6 +812,7 @@ hostapd_set_bss_options() { ;; esac + [ -n "$network_ifname" ] && append bss_conf "ft_iface=$network_ifname" "$N" append bss_conf "mobility_domain=$mobility_domain" "$N" append bss_conf "ft_psk_generate_local=$ft_psk_generate_local" "$N" append bss_conf "ft_over_ds=$ft_over_ds" "$N" @@ -780,6 +827,13 @@ hostapd_set_bss_options() { set_default r0_key_lifetime 10000 set_default pmk_r1_push 0 + [ -n "$r0kh" -a -n "$r1kh" ] || { + key=`echo -n "$mobility_domain/$auth_secret" | md5sum | awk '{print $1}'` + + set_default r0kh "ff:ff:ff:ff:ff:ff,*,$key" + set_default r1kh "00:00:00:00:00:00,00:00:00:00:00:00,$key" + } + [ -n "$r1_key_holder" ] && append bss_conf "r1_key_holder=$r1_key_holder" "$N" append bss_conf "r0_key_lifetime=$r0_key_lifetime" "$N" append bss_conf "pmk_r1_push=$pmk_r1_push" "$N" @@ -865,13 +919,17 @@ hostapd_set_bss_options() { } [ -n "$vlan_possible" -a -n "$dynamic_vlan" ] && { - json_get_vars vlan_naming vlan_tagged_interface vlan_bridge vlan_file + json_get_vars vlan_naming vlan_tagged_interface vlan_bridge vlan_file vlan_no_bridge set_default vlan_naming 1 [ -z "$vlan_file" ] && set_default vlan_file /var/run/hostapd-$ifname.vlan append bss_conf "dynamic_vlan=$dynamic_vlan" "$N" append bss_conf "vlan_naming=$vlan_naming" "$N" - [ -n "$vlan_bridge" ] && \ + if [ -n "$vlan_bridge" ]; then append bss_conf "vlan_bridge=$vlan_bridge" "$N" + else + set_default vlan_no_bridge 1 + fi + append bss_conf "vlan_no_bridge=$vlan_no_bridge" "$N" [ -n "$vlan_tagged_interface" ] && \ append bss_conf "vlan_tagged_interface=$vlan_tagged_interface" "$N" [ -n "$vlan_file" ] && { @@ -884,6 +942,7 @@ hostapd_set_bss_options() { json_get_vars iw_hessid iw_venue_group iw_venue_type iw_network_auth_type json_get_vars iw_roaming_consortium iw_domain_name iw_anqp_3gpp_cell_net iw_nai_realm json_get_vars iw_anqp_elem iw_qos_map_set iw_ipaddr_type_availability iw_gas_address3 + json_get_vars iw_venue_name iw_venue_url set_default iw_enabled 0 if [ "$iw_enabled" = "1" ]; then @@ -907,11 +966,12 @@ hostapd_set_bss_options() { [ -n "$iw_network_auth_type" ] && \ append bss_conf "network_auth_type=$iw_network_auth_type" "$N" [ -n "$iw_gas_address3" ] && append bss_conf "gas_address3=$iw_gas_address3" "$N" - [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N" json_for_each_item append_iw_roaming_consortium iw_roaming_consortium json_for_each_item append_iw_anqp_elem iw_anqp_elem json_for_each_item append_iw_nai_realm iw_nai_realm + json_for_each_item append_iw_venue_name iw_venue_name + json_for_each_item append_iw_venue_url iw_venue_url iw_domain_name_conf= json_for_each_item append_iw_domain_name iw_domain_name @@ -924,11 +984,19 @@ hostapd_set_bss_options() { append bss_conf "anqp_3gpp_cell_net=$iw_anqp_3gpp_cell_net_conf" "$N" fi + set_default iw_qos_map_set 0,0,2,16,1,1,255,255,18,22,24,38,40,40,44,46,48,56 + case "$iw_qos_map_set" in + *,*);; + *) iw_qos_map_set="";; + esac + [ -n "$iw_qos_map_set" ] && append bss_conf "qos_map_set=$iw_qos_map_set" "$N" local hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \ - osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp + osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \ + hs20_t_c_server_url json_get_vars hs20 disable_dgaf osen anqp_domain_id hs20_deauth_req_timeout \ - osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp + osu_ssid hs20_wan_metrics hs20_operating_class hs20_t_c_filename hs20_t_c_timestamp \ + hs20_t_c_server_url set_default hs20 0 set_default disable_dgaf $hs20 @@ -947,12 +1015,23 @@ hostapd_set_bss_options() { [ -n "$hs20_operating_class" ] && append bss_conf "hs20_operating_class=$hs20_operating_class" "$N" [ -n "$hs20_t_c_filename" ] && append bss_conf "hs20_t_c_filename=$hs20_t_c_filename" "$N" [ -n "$hs20_t_c_timestamp" ] && append bss_conf "hs20_t_c_timestamp=$hs20_t_c_timestamp" "$N" - json_for_each_item append_hs20_conn_capab hs20_conn_capab + [ -n "$hs20_t_c_server_url" ] && append bss_conf "hs20_t_c_server_url=$hs20_t_c_server_url" "$N" json_for_each_item append_hs20_oper_friendly_name hs20_oper_friendly_name + json_for_each_item append_hs20_conn_capab hs20_conn_capab json_for_each_item append_osu_provider osu_provider json_for_each_item append_operator_icon operator_icon fi + if [ "$eap_server" = "1" ]; then + append bss_conf "eap_server=1" "$N" + [ -n "$eap_user_file" ] && append bss_conf "eap_user_file=$eap_user_file" "$N" + [ -n "$ca_cert" ] && append bss_conf "ca_cert=$ca_cert" "$N" + [ -n "$server_cert" ] && append bss_conf "server_cert=$server_cert" "$N" + [ -n "$private_key" ] && append bss_conf "private_key=$private_key" "$N" + [ -n "$private_key_passwd" ] && append bss_conf "private_key_passwd=$private_key_passwd" "$N" + [ -n "$server_id" ] && append bss_conf "server_id=$server_id" "$N" + fi + set_default multicast_to_unicast 0 if [ "$multicast_to_unicast" -gt 0 ]; then append bss_conf "multicast_to_unicast=$multicast_to_unicast" "$N" @@ -1081,16 +1160,16 @@ wpa_supplicant_set_fixed_freq() { append network_data "frequency=$freq" "$N$T" case "$htmode" in NOHT) append network_data "disable_ht=1" "$N$T";; - HT20|VHT20) append network_data "disable_ht40=1" "$N$T";; - HT40*|VHT40*|VHT80*|VHT160*) append network_data "ht40=1" "$N$T";; + HE20|HT20|VHT20) append network_data "disable_ht40=1" "$N$T";; + HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160) append network_data "ht40=1" "$N$T";; esac case "$htmode" in VHT*) append network_data "vht=1" "$N$T";; esac case "$htmode" in - VHT80) append network_data "max_oper_chwidth=1" "$N$T";; - VHT160) append network_data "max_oper_chwidth=2" "$N$T";; - VHT20|VHT40) append network_data "max_oper_chwidth=0" "$N$T";; + HE80|VHT80) append network_data "max_oper_chwidth=1" "$N$T";; + HE160|VHT160) append network_data "max_oper_chwidth=2" "$N$T";; + HE20|HE40|VHT20|VHT40) append network_data "max_oper_chwidth=0" "$N$T";; *) append network_data "disable_vht=1" "$N$T";; esac } diff --git a/package/network/services/hostapd/patches/020-ignore-4addr-mode-enabling-error.patch b/package/network/services/hostapd/patches/020-ignore-4addr-mode-enabling-error.patch index 3431ac0949..f6751829a5 100644 --- a/package/network/services/hostapd/patches/020-ignore-4addr-mode-enabling-error.patch +++ b/package/network/services/hostapd/patches/020-ignore-4addr-mode-enabling-error.patch @@ -18,8 +18,6 @@ Signed-off-by: Jouni Malinen src/drivers/driver_nl80211.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) -diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c -index 72189da24..011a15e68 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -617,6 +617,7 @@ struct wiphy_idx_data { @@ -30,7 +28,7 @@ index 72189da24..011a15e68 100644 }; -@@ -639,6 +640,9 @@ static int netdev_info_handler(struct nl_msg *msg, void *arg) +@@ -639,6 +640,9 @@ static int netdev_info_handler(struct nl os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); @@ -40,7 +38,7 @@ index 72189da24..011a15e68 100644 return NL_SKIP; } -@@ -691,6 +695,20 @@ static int nl80211_get_macaddr(struct i802_bss *bss) +@@ -691,6 +695,20 @@ static int nl80211_get_macaddr(struct i8 } @@ -61,7 +59,7 @@ index 72189da24..011a15e68 100644 static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv, struct nl80211_wiphy_data *w) { -@@ -11482,6 +11500,11 @@ static int nl80211_set_4addr_mode(void *priv, const char *bridge_ifname, +@@ -11508,6 +11526,11 @@ static int nl80211_set_4addr_mode(void * ret = send_and_recv_msgs(drv, msg, NULL, NULL); msg = NULL; @@ -73,6 +71,3 @@ index 72189da24..011a15e68 100644 if (!ret) { if (bridge_ifname[0] && val && i802_check_bridge(drv, bss, bridge_ifname, bss->ifname) < 0) --- -2.29.2 - diff --git a/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch new file mode 100644 index 0000000000..9ff9b2398d --- /dev/null +++ b/package/network/services/hostapd/patches/023-ndisc_snoop-call-dl_list_del-before-freeing-ipv6-add.patch @@ -0,0 +1,19 @@ +From: Felix Fietkau +Date: Wed, 28 Jul 2021 05:43:29 +0200 +Subject: [PATCH] ndisc_snoop: call dl_list_del before freeing ipv6 addresses + +Fixes a segmentation fault on sta disconnect + +Signed-off-by: Felix Fietkau +--- + +--- a/src/ap/ndisc_snoop.c ++++ b/src/ap/ndisc_snoop.c +@@ -61,6 +61,7 @@ void sta_ip6addr_del(struct hostapd_data + dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr, + list) { + hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr); ++ dl_list_del(&ip6addr->list); + os_free(ip6addr); + } + } diff --git a/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch new file mode 100644 index 0000000000..f65362fe96 --- /dev/null +++ b/package/network/services/hostapd/patches/030-driver_nl80211-rewrite-neigh-code-to-not-depend-on-l.patch @@ -0,0 +1,275 @@ +From: Felix Fietkau +Date: Wed, 28 Jul 2021 05:49:46 +0200 +Subject: [PATCH] driver_nl80211: rewrite neigh code to not depend on + libnl3-route + +Removes an unnecessary dependency and also makes the code smaller + +Signed-off-by: Felix Fietkau +--- + +--- a/src/drivers/driver_nl80211.c ++++ b/src/drivers/driver_nl80211.c +@@ -16,9 +16,6 @@ + #include + #include + #include +-#ifdef CONFIG_LIBNL3_ROUTE +-#include +-#endif /* CONFIG_LIBNL3_ROUTE */ + #include + #include + #include +@@ -4965,26 +4962,29 @@ fail: + + static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_addr; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->ifindex, ++ .ndm_family = AF_BRIDGE, ++ }; ++ struct nl_msg *msg; + int err; + +- rn = rtnl_neigh_alloc(); +- if (!rn) ++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); ++ if (!msg) + return; + +- rtnl_neigh_set_family(rn, AF_BRIDGE); +- rtnl_neigh_set_ifindex(rn, bss->ifindex); +- nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN); +- if (!nl_addr) { +- rtnl_neigh_put(rn); +- return; +- } +- rtnl_neigh_set_lladdr(rn, nl_addr); ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) ++ goto errout; ++ ++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr)) ++ goto errout; ++ ++ if (nl_send_auto_complete(drv->rtnl_sk, msg) < 0) ++ goto errout; + +- err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); ++ err = nl_wait_for_ack(drv->rtnl_sk); + if (err < 0) { + wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for " + MACSTR " ifindex=%d failed: %s", MAC2STR(addr), +@@ -4994,9 +4994,8 @@ static void rtnl_neigh_delete_fdb_entry( + MACSTR, MAC2STR(addr)); + } + +- nl_addr_put(nl_addr); +- rtnl_neigh_put(rn); +-#endif /* CONFIG_LIBNL3_ROUTE */ ++errout: ++ nlmsg_free(msg); + } + + +@@ -7337,7 +7336,6 @@ static void *i802_init(struct hostapd_da + (params->num_bridge == 0 || !params->bridge[0])) + add_ifidx(drv, br_ifindex, drv->ifindex); + +-#ifdef CONFIG_LIBNL3_ROUTE + if (bss->added_if_into_bridge || bss->already_in_bridge) { + int err; + +@@ -7354,7 +7352,6 @@ static void *i802_init(struct hostapd_da + goto failed; + } + } +-#endif /* CONFIG_LIBNL3_ROUTE */ + + if (drv->capa.flags2 & WPA_DRIVER_FLAGS2_CONTROL_PORT_RX) { + wpa_printf(MSG_DEBUG, +@@ -10238,13 +10235,14 @@ static int wpa_driver_br_add_ip_neigh(vo + const u8 *ipaddr, int prefixlen, + const u8 *addr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_ipaddr = NULL; +- struct nl_addr *nl_lladdr = NULL; +- int family, addrsize; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->br_ifindex, ++ }; ++ struct nl_msg *msg; ++ int addrsize; + int res; + + if (!ipaddr || prefixlen == 0 || !addr) +@@ -10263,85 +10261,66 @@ static int wpa_driver_br_add_ip_neigh(vo + } + + if (version == 4) { +- family = AF_INET; ++ nhdr.ndm_family = AF_INET; + addrsize = 4; + } else if (version == 6) { +- family = AF_INET6; ++ nhdr.ndm_family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; + } + +- rn = rtnl_neigh_alloc(); +- if (rn == NULL) ++ msg = nlmsg_alloc_simple(RTM_NEWNEIGH, NLM_F_CREATE); ++ if (!msg) + return -ENOMEM; + +- /* set the destination ip address for neigh */ +- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); +- if (nl_ipaddr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); +- res = -ENOMEM; ++ res = -ENOMEM; ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) + goto errout; +- } +- nl_addr_set_prefixlen(nl_ipaddr, prefixlen); +- res = rtnl_neigh_set_dst(rn, nl_ipaddr); +- if (res) { +- wpa_printf(MSG_DEBUG, +- "nl80211: neigh set destination addr failed"); ++ ++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr)) + goto errout; +- } + +- /* set the corresponding lladdr for neigh */ +- nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN); +- if (nl_lladdr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed"); +- res = -ENOMEM; ++ if (nla_put(msg, NDA_LLADDR, ETH_ALEN, (void *)addr)) + goto errout; +- } +- rtnl_neigh_set_lladdr(rn, nl_lladdr); + +- rtnl_neigh_set_ifindex(rn, bss->br_ifindex); +- rtnl_neigh_set_state(rn, NUD_PERMANENT); ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto errout; + +- res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE); ++ res = nl_wait_for_ack(drv->rtnl_sk); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Adding bridge ip neigh failed: %s", + nl_geterror(res)); + } + errout: +- if (nl_lladdr) +- nl_addr_put(nl_lladdr); +- if (nl_ipaddr) +- nl_addr_put(nl_ipaddr); +- if (rn) +- rtnl_neigh_put(rn); ++ nlmsg_free(msg); + return res; +-#else /* CONFIG_LIBNL3_ROUTE */ +- return -1; +-#endif /* CONFIG_LIBNL3_ROUTE */ + } + + + static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version, + const u8 *ipaddr) + { +-#ifdef CONFIG_LIBNL3_ROUTE + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; +- struct rtnl_neigh *rn; +- struct nl_addr *nl_ipaddr; +- int family, addrsize; ++ struct ndmsg nhdr = { ++ .ndm_state = NUD_PERMANENT, ++ .ndm_ifindex = bss->br_ifindex, ++ }; ++ struct nl_msg *msg; ++ int addrsize; + int res; + + if (!ipaddr) + return -EINVAL; + + if (version == 4) { +- family = AF_INET; ++ nhdr.ndm_family = AF_INET; + addrsize = 4; + } else if (version == 6) { +- family = AF_INET6; ++ nhdr.ndm_family = AF_INET6; + addrsize = 16; + } else { + return -EINVAL; +@@ -10359,41 +10338,30 @@ static int wpa_driver_br_delete_ip_neigh + return -1; + } + +- rn = rtnl_neigh_alloc(); +- if (rn == NULL) ++ msg = nlmsg_alloc_simple(RTM_DELNEIGH, NLM_F_CREATE); ++ if (!msg) + return -ENOMEM; + +- /* set the destination ip address for neigh */ +- nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize); +- if (nl_ipaddr == NULL) { +- wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed"); +- res = -ENOMEM; ++ res = -ENOMEM; ++ if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0) + goto errout; +- } +- res = rtnl_neigh_set_dst(rn, nl_ipaddr); +- if (res) { +- wpa_printf(MSG_DEBUG, +- "nl80211: neigh set destination addr failed"); ++ ++ if (nla_put(msg, NDA_DST, addrsize, (void *)ipaddr)) + goto errout; +- } + +- rtnl_neigh_set_ifindex(rn, bss->br_ifindex); ++ res = nl_send_auto_complete(drv->rtnl_sk, msg); ++ if (res < 0) ++ goto errout; + +- res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); ++ res = nl_wait_for_ack(drv->rtnl_sk); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Deleting bridge ip neigh failed: %s", + nl_geterror(res)); + } + errout: +- if (nl_ipaddr) +- nl_addr_put(nl_ipaddr); +- if (rn) +- rtnl_neigh_put(rn); ++ nlmsg_free(msg); + return res; +-#else /* CONFIG_LIBNL3_ROUTE */ +- return -1; +-#endif /* CONFIG_LIBNL3_ROUTE */ + } + + diff --git a/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch new file mode 100644 index 0000000000..55dd980cd7 --- /dev/null +++ b/package/network/services/hostapd/patches/040-mesh-allow-processing-authentication-frames-in-block.patch @@ -0,0 +1,34 @@ +From: Felix Fietkau +Date: Mon, 18 Feb 2019 12:57:11 +0100 +Subject: [PATCH] mesh: allow processing authentication frames in blocked state + +If authentication fails repeatedly e.g. because of a weak signal, the link +can end up in blocked state. If one of the nodes tries to establish a link +again before it is unblocked on the other side, it will block the link to +that other side. The same happens on the other side when it unblocks the +link. In that scenario, the link never recovers on its own. + +To fix this, allow restarting authentication even if the link is in blocked +state, but don't initiate the attempt until the blocked period is over. + +Signed-off-by: Felix Fietkau +--- + +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -2527,15 +2527,6 @@ static void handle_auth(struct hostapd_d + seq_ctrl); + return; + } +-#ifdef CONFIG_MESH +- if ((hapd->conf->mesh & MESH_ENABLED) && +- sta->plink_state == PLINK_BLOCKED) { +- wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR +- " is blocked - drop Authentication frame", +- MAC2STR(mgmt->sa)); +- return; +- } +-#endif /* CONFIG_MESH */ + } else { + #ifdef CONFIG_MESH + if (hapd->conf->mesh & MESH_ENABLED) { diff --git a/package/network/services/hostapd/patches/050-mesh-make-forwarding-configurable.patch b/package/network/services/hostapd/patches/050-mesh-make-forwarding-configurable.patch index 0ecb9ba078..4d64ec8287 100644 --- a/package/network/services/hostapd/patches/050-mesh-make-forwarding-configurable.patch +++ b/package/network/services/hostapd/patches/050-mesh-make-forwarding-configurable.patch @@ -59,7 +59,7 @@ Signed-off-by: Daniel Golle --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -10023,6 +10023,9 @@ static int nl80211_put_mesh_config(struc +@@ -10038,6 +10038,9 @@ static int nl80211_put_mesh_config(struc if (((params->flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) && nla_put_u8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, params->auto_plinks)) || diff --git a/package/network/services/hostapd/patches/110-notify-mgmt-frames.patch b/package/network/services/hostapd/patches/110-notify-mgmt-frames.patch index 9e187253d4..c3a66a7115 100644 --- a/package/network/services/hostapd/patches/110-notify-mgmt-frames.patch +++ b/package/network/services/hostapd/patches/110-notify-mgmt-frames.patch @@ -63,7 +63,7 @@ Signed-off-by: Raphaël Mélotte --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c -@@ -4878,6 +4878,28 @@ static int handle_action(struct hostapd_ +@@ -4869,6 +4869,28 @@ static int handle_action(struct hostapd_ return 1; } @@ -92,7 +92,7 @@ Signed-off-by: Raphaël Mélotte /** * ieee802_11_mgmt - process incoming IEEE 802.11 management frames -@@ -4969,6 +4991,9 @@ int ieee802_11_mgmt(struct hostapd_data +@@ -4960,6 +4982,9 @@ int ieee802_11_mgmt(struct hostapd_data if (hapd->iconf->track_sta_max_num) sta_track_add(hapd->iface, mgmt->sa, ssi_signal); diff --git a/package/network/services/hostapd/patches/200-multicall.patch b/package/network/services/hostapd/patches/200-multicall.patch index 4f3e3decfe..9119a24c55 100644 --- a/package/network/services/hostapd/patches/200-multicall.patch +++ b/package/network/services/hostapd/patches/200-multicall.patch @@ -231,7 +231,7 @@ os_memset(&global, 0, sizeof(global)); --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c -@@ -4581,8 +4581,8 @@ static void wpas_event_unprot_beacon(str +@@ -4579,8 +4579,8 @@ static void wpas_event_unprot_beacon(str } @@ -242,7 +242,7 @@ { struct wpa_supplicant *wpa_s = ctx; int resched; -@@ -5400,7 +5400,7 @@ void wpa_supplicant_event(void *ctx, enu +@@ -5398,7 +5398,7 @@ void wpa_supplicant_event(void *ctx, enu } diff --git a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch index 9e2551ce60..ccd8589728 100644 --- a/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch +++ b/package/network/services/hostapd/patches/330-nl80211_fix_set_freq.patch @@ -1,6 +1,6 @@ --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -4646,7 +4646,7 @@ static int nl80211_set_channel(struct i8 +@@ -4661,7 +4661,7 @@ static int nl80211_set_channel(struct i8 freq->freq, freq->ht_enabled, freq->vht_enabled, freq->he_enabled, freq->bandwidth, freq->center_freq1, freq->center_freq2); diff --git a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch index a2a03c04f7..076950fe35 100644 --- a/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch +++ b/package/network/services/hostapd/patches/350-nl80211_del_beacon_bss.patch @@ -1,6 +1,6 @@ --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -2788,10 +2788,15 @@ static int wpa_driver_nl80211_del_beacon +@@ -2803,10 +2803,15 @@ static int wpa_driver_nl80211_del_beacon struct nl_msg *msg; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -18,7 +18,7 @@ return send_and_recv_msgs(drv, msg, NULL, NULL); } -@@ -5261,7 +5266,7 @@ static void nl80211_teardown_ap(struct i +@@ -5278,7 +5283,7 @@ static void nl80211_teardown_ap(struct i nl80211_mgmt_unsubscribe(bss, "AP teardown"); nl80211_put_wiphy_data_ap(bss); @@ -27,7 +27,7 @@ } -@@ -7679,8 +7684,6 @@ static int wpa_driver_nl80211_if_remove( +@@ -7694,8 +7699,6 @@ static int wpa_driver_nl80211_if_remove( } else { wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context"); nl80211_teardown_ap(bss); @@ -36,7 +36,7 @@ nl80211_destroy_bss(bss); if (!bss->added_if) i802_set_iface_flags(bss, 0); -@@ -8074,7 +8077,6 @@ static int wpa_driver_nl80211_deinit_ap( +@@ -8089,7 +8092,6 @@ static int wpa_driver_nl80211_deinit_ap( if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(bss); @@ -44,7 +44,7 @@ /* * If the P2P GO interface was dynamically added, then it is -@@ -8094,7 +8096,6 @@ static int wpa_driver_nl80211_stop_ap(vo +@@ -8109,7 +8111,6 @@ static int wpa_driver_nl80211_stop_ap(vo if (!is_ap_interface(drv->nlmode)) return -1; wpa_driver_nl80211_del_beacon(bss); diff --git a/package/network/services/hostapd/patches/370-ap_sta_support.patch b/package/network/services/hostapd/patches/370-ap_sta_support.patch index a7a646d2d1..1c5f72ddc0 100644 --- a/package/network/services/hostapd/patches/370-ap_sta_support.patch +++ b/package/network/services/hostapd/patches/370-ap_sta_support.patch @@ -274,7 +274,7 @@ if (ieee802_11_build_ap_params(hapd, ¶ms) < 0) --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c -@@ -4581,6 +4581,60 @@ static void wpas_event_unprot_beacon(str +@@ -4579,6 +4579,60 @@ static void wpas_event_unprot_beacon(str } @@ -335,7 +335,7 @@ void supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { -@@ -4883,8 +4937,10 @@ void supplicant_event(void *ctx, enum wp +@@ -4881,8 +4935,10 @@ void supplicant_event(void *ctx, enum wp channel_width_to_string(data->ch_switch.ch_width), data->ch_switch.cf1, data->ch_switch.cf2); diff --git a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch index 61d2089bc8..b5dec991d0 100644 --- a/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch +++ b/package/network/services/hostapd/patches/461-driver_nl80211-use-new-parameters-during-ibss-join.patch @@ -10,7 +10,7 @@ Signed-hostap: Antonio Quartulli --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -5584,7 +5584,7 @@ static int wpa_driver_nl80211_ibss(struc +@@ -5601,7 +5601,7 @@ static int wpa_driver_nl80211_ibss(struc struct wpa_driver_associate_params *params) { struct nl_msg *msg; @@ -19,7 +19,7 @@ Signed-hostap: Antonio Quartulli int count = 0; wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); -@@ -5611,6 +5611,37 @@ retry: +@@ -5628,6 +5628,37 @@ retry: nl80211_put_beacon_int(msg, params->beacon_int)) goto fail; diff --git a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch index 33ef097e75..7e21da263d 100644 --- a/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch +++ b/package/network/services/hostapd/patches/463-add-mcast_rate-to-11s.patch @@ -29,7 +29,7 @@ Tested-by: Simon Wunderlich struct wpa_driver_set_key_params { --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -10043,6 +10043,18 @@ static int nl80211_put_mesh_id(struct nl +@@ -10058,6 +10058,18 @@ static int nl80211_put_mesh_id(struct nl } @@ -48,7 +48,7 @@ Tested-by: Simon Wunderlich static int nl80211_put_mesh_config(struct nl_msg *msg, struct wpa_driver_mesh_bss_params *params) { -@@ -10104,6 +10116,7 @@ static int nl80211_join_mesh(struct i802 +@@ -10119,6 +10131,7 @@ static int nl80211_join_mesh(struct i802 nl80211_put_basic_rates(msg, params->basic_rates) || nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) || nl80211_put_beacon_int(msg, params->beacon_int) || diff --git a/package/network/services/hostapd/patches/600-ubus_support.patch b/package/network/services/hostapd/patches/600-ubus_support.patch index 938840755a..53f521e649 100644 --- a/package/network/services/hostapd/patches/600-ubus_support.patch +++ b/package/network/services/hostapd/patches/600-ubus_support.patch @@ -126,7 +126,7 @@ if (res == HOSTAPD_ACL_PENDING) return; -@@ -4166,7 +4178,7 @@ static void handle_assoc(struct hostapd_ +@@ -4157,7 +4169,7 @@ static void handle_assoc(struct hostapd_ int resp = WLAN_STATUS_SUCCESS; u16 reply_res; const u8 *pos; @@ -135,7 +135,7 @@ struct sta_info *sta; u8 *tmp = NULL; #ifdef CONFIG_FILS -@@ -4379,6 +4391,11 @@ static void handle_assoc(struct hostapd_ +@@ -4370,6 +4382,11 @@ static void handle_assoc(struct hostapd_ left = res; } #endif /* CONFIG_FILS */ @@ -147,9 +147,9 @@ /* followed by SSID and Supported rates; and HT capabilities if 802.11n * is used */ -@@ -4543,6 +4560,14 @@ static void handle_assoc(struct hostapd_ - pos, left, rssi, omit_rsnxe); - os_free(tmp); +@@ -4468,6 +4485,14 @@ static void handle_assoc(struct hostapd_ + } + #endif /* CONFIG_FILS */ + ubus_resp = hostapd_ubus_handle_event(hapd, &req); + if (ubus_resp) { @@ -159,10 +159,10 @@ + goto fail; + } + + fail: + /* - * Remove the station in case tranmission of a success response fails - * (the STA was added associated to the driver) or if the station was -@@ -4570,6 +4595,7 @@ static void handle_disassoc(struct hosta +@@ -4561,6 +4586,7 @@ static void handle_disassoc(struct hosta wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.disassoc.reason_code)); @@ -170,7 +170,7 @@ sta = ap_get_sta(hapd, mgmt->sa); if (sta == NULL) { -@@ -4636,6 +4662,8 @@ static void handle_deauth(struct hostapd +@@ -4627,6 +4653,8 @@ static void handle_deauth(struct hostapd " reason_code=%d", MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code)); @@ -235,22 +235,22 @@ wpabuf_free(sta->p2p_ie); --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c -@@ -424,6 +424,7 @@ void ap_handle_timer(void *eloop_ctx, vo +@@ -423,6 +423,7 @@ void ap_handle_timer(void *eloop_ctx, vo + hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "deauthenticated due to " "local deauth request"); - ap_free_sta(hapd, sta); + hostapd_ubus_notify(hapd, "local-deauth", sta->addr); + ap_free_sta(hapd, sta); return; } - -@@ -579,6 +580,7 @@ skip_poll: +@@ -578,6 +579,7 @@ skip_poll: + mlme_deauthenticate_indication( hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID); - ap_free_sta(hapd, sta); + hostapd_ubus_notify(hapd, "inactive-deauth", sta->addr); + ap_free_sta(hapd, sta); break; } - } @@ -1294,6 +1296,7 @@ void ap_sta_set_authorized(struct hostap buf, ip_addr, keyid_buf); } else { diff --git a/package/network/services/hostapd/patches/700-wifi-reload.patch b/package/network/services/hostapd/patches/700-wifi-reload.patch index d5520d0b77..ceb92265dd 100644 --- a/package/network/services/hostapd/patches/700-wifi-reload.patch +++ b/package/network/services/hostapd/patches/700-wifi-reload.patch @@ -174,7 +174,7 @@ hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface, --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c -@@ -4493,6 +4493,9 @@ static int wpa_driver_nl80211_set_ap(voi +@@ -4508,6 +4508,9 @@ static int wpa_driver_nl80211_set_ap(voi if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)", ret, strerror(-ret)); diff --git a/package/network/services/hostapd/patches/710-vlan_no_bridge.patch b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch new file mode 100644 index 0000000000..7de4e2c1d4 --- /dev/null +++ b/package/network/services/hostapd/patches/710-vlan_no_bridge.patch @@ -0,0 +1,33 @@ +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -115,6 +115,7 @@ struct hostapd_ssid { + #define DYNAMIC_VLAN_OPTIONAL 1 + #define DYNAMIC_VLAN_REQUIRED 2 + int dynamic_vlan; ++ int vlan_no_bridge; + #define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0 + #define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1 + #define DYNAMIC_VLAN_NAMING_END 2 +--- a/src/ap/vlan_full.c ++++ b/src/ap/vlan_full.c +@@ -466,6 +466,9 @@ void vlan_newlink(const char *ifname, st + + wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname); + ++ if (hapd->conf->ssid.vlan_no_bridge) ++ return; ++ + for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) { + if (vlan->configured || + os_strcmp(ifname, vlan->ifname) != 0) +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -3400,6 +3400,8 @@ static int hostapd_config_fill(struct ho + #ifndef CONFIG_NO_VLAN + } else if (os_strcmp(buf, "dynamic_vlan") == 0) { + bss->ssid.dynamic_vlan = atoi(pos); ++ } else if (os_strcmp(buf, "vlan_no_bridge") == 0) { ++ bss->ssid.vlan_no_bridge = atoi(pos); + } else if (os_strcmp(buf, "per_sta_vif") == 0) { + bss->ssid.per_sta_vif = atoi(pos); + } else if (os_strcmp(buf, "vlan_file") == 0) { diff --git a/package/network/services/hostapd/patches/711-wds_bridge_force.patch b/package/network/services/hostapd/patches/711-wds_bridge_force.patch new file mode 100644 index 0000000000..01507b6d36 --- /dev/null +++ b/package/network/services/hostapd/patches/711-wds_bridge_force.patch @@ -0,0 +1,22 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2405,6 +2405,8 @@ static int hostapd_config_fill(struct ho + sizeof(conf->bss[0]->iface)); + } else if (os_strcmp(buf, "bridge") == 0) { + os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); ++ if (!bss->wds_bridge[0]) ++ os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); + } else if (os_strcmp(buf, "vlan_bridge") == 0) { + os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); + } else if (os_strcmp(buf, "wds_bridge") == 0) { +--- a/src/ap/ap_drv_ops.c ++++ b/src/ap/ap_drv_ops.c +@@ -340,8 +340,6 @@ int hostapd_set_wds_sta(struct hostapd_d + return -1; + if (hapd->conf->wds_bridge[0]) + bridge = hapd->conf->wds_bridge; +- else if (hapd->conf->bridge[0]) +- bridge = hapd->conf->bridge; + return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val, + bridge, ifname_wds); + } diff --git a/package/network/services/hostapd/patches/730-ft_iface.patch b/package/network/services/hostapd/patches/730-ft_iface.patch new file mode 100644 index 0000000000..c1adf1ffcf --- /dev/null +++ b/package/network/services/hostapd/patches/730-ft_iface.patch @@ -0,0 +1,38 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -3069,6 +3069,8 @@ static int hostapd_config_fill(struct ho + wpa_printf(MSG_INFO, + "Line %d: Obsolete peerkey parameter ignored", line); + #ifdef CONFIG_IEEE80211R_AP ++ } else if (os_strcmp(buf, "ft_iface") == 0) { ++ os_strlcpy(bss->ft_iface, pos, sizeof(bss->ft_iface)); + } else if (os_strcmp(buf, "mobility_domain") == 0) { + if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN || + hexstr2bin(pos, bss->mobility_domain, +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -284,6 +284,7 @@ struct airtime_sta_weight { + struct hostapd_bss_config { + char iface[IFNAMSIZ + 1]; + char bridge[IFNAMSIZ + 1]; ++ char ft_iface[IFNAMSIZ + 1]; + char vlan_bridge[IFNAMSIZ + 1]; + char wds_bridge[IFNAMSIZ + 1]; + +--- a/src/ap/wpa_auth_glue.c ++++ b/src/ap/wpa_auth_glue.c +@@ -1511,8 +1511,12 @@ int hostapd_setup_wpa(struct hostapd_dat + wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt)) { + const char *ft_iface; + +- ft_iface = hapd->conf->bridge[0] ? hapd->conf->bridge : +- hapd->conf->iface; ++ if (hapd->conf->ft_iface[0]) ++ ft_iface = hapd->conf->ft_iface; ++ else if (hapd->conf->bridge[0]) ++ ft_iface = hapd->conf->bridge; ++ else ++ ft_iface = hapd->conf->iface; + hapd->l2 = l2_packet_init(ft_iface, NULL, ETH_P_RRB, + hostapd_rrb_receive, hapd, 1); + if (!hapd->l2) { diff --git a/package/network/services/hostapd/patches/740-snoop_iface.patch b/package/network/services/hostapd/patches/740-snoop_iface.patch new file mode 100644 index 0000000000..15aaf4b8e4 --- /dev/null +++ b/package/network/services/hostapd/patches/740-snoop_iface.patch @@ -0,0 +1,66 @@ +--- a/src/ap/ap_config.h ++++ b/src/ap/ap_config.h +@@ -285,6 +285,7 @@ struct hostapd_bss_config { + char iface[IFNAMSIZ + 1]; + char bridge[IFNAMSIZ + 1]; + char ft_iface[IFNAMSIZ + 1]; ++ char snoop_iface[IFNAMSIZ + 1]; + char vlan_bridge[IFNAMSIZ + 1]; + char wds_bridge[IFNAMSIZ + 1]; + +--- a/src/ap/x_snoop.c ++++ b/src/ap/x_snoop.c +@@ -31,14 +31,16 @@ int x_snoop_init(struct hostapd_data *ha + return -1; + } + +- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, + 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable hairpin_mode on the bridge port"); + return -1; + } + +- if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable proxyarp on the bridge port"); + return -1; +@@ -52,7 +54,8 @@ int x_snoop_init(struct hostapd_data *ha + } + + #ifdef CONFIG_IPV6 +- if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { ++ if (!conf->snoop_iface[0] && ++ hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to enable multicast snooping on the bridge"); + return -1; +@@ -71,8 +74,12 @@ x_snoop_get_l2_packet(struct hostapd_dat + { + struct hostapd_bss_config *conf = hapd->conf; + struct l2_packet_data *l2; ++ const char *ifname = conf->bridge; + +- l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1); ++ if (conf->snoop_iface[0]) ++ ifname = conf->snoop_iface; ++ ++ l2 = l2_packet_init(ifname, NULL, ETH_P_ALL, handler, hapd, 1); + if (l2 == NULL) { + wpa_printf(MSG_DEBUG, + "x_snoop: Failed to initialize L2 packet processing %s", +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -2407,6 +2407,8 @@ static int hostapd_config_fill(struct ho + os_strlcpy(bss->bridge, pos, sizeof(bss->bridge)); + if (!bss->wds_bridge[0]) + os_strlcpy(bss->wds_bridge, pos, sizeof(bss->wds_bridge)); ++ } else if (os_strcmp(buf, "snoop_iface") == 0) { ++ os_strlcpy(bss->snoop_iface, pos, sizeof(bss->snoop_iface)); + } else if (os_strcmp(buf, "vlan_bridge") == 0) { + os_strlcpy(bss->vlan_bridge, pos, sizeof(bss->vlan_bridge)); + } else if (os_strcmp(buf, "wds_bridge") == 0) { diff --git a/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch new file mode 100644 index 0000000000..94f4a2b297 --- /dev/null +++ b/package/network/services/hostapd/patches/750-qos_map_set_without_interworking.patch @@ -0,0 +1,112 @@ +--- a/hostapd/config_file.c ++++ b/hostapd/config_file.c +@@ -1711,6 +1711,8 @@ static int parse_anqp_elem(struct hostap + return 0; + } + ++#endif /* CONFIG_INTERWORKING */ ++ + + static int parse_qos_map_set(struct hostapd_bss_config *bss, + char *buf, int line) +@@ -1752,8 +1754,6 @@ static int parse_qos_map_set(struct host + return 0; + } + +-#endif /* CONFIG_INTERWORKING */ +- + + #ifdef CONFIG_HS20 + static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf, +@@ -4050,10 +4050,10 @@ static int hostapd_config_fill(struct ho + bss->gas_frag_limit = val; + } else if (os_strcmp(buf, "gas_comeback_delay") == 0) { + bss->gas_comeback_delay = atoi(pos); ++#endif /* CONFIG_INTERWORKING */ + } else if (os_strcmp(buf, "qos_map_set") == 0) { + if (parse_qos_map_set(bss, pos, line) < 0) + return 1; +-#endif /* CONFIG_INTERWORKING */ + #ifdef CONFIG_RADIUS_TEST + } else if (os_strcmp(buf, "dump_msk_file") == 0) { + os_free(bss->dump_msk_file); +--- a/src/ap/hostapd.c ++++ b/src/ap/hostapd.c +@@ -1386,6 +1386,7 @@ static int hostapd_setup_bss(struct host + wpa_printf(MSG_ERROR, "GAS server initialization failed"); + return -1; + } ++#endif /* CONFIG_INTERWORKING */ + + if (conf->qos_map_set_len && + hostapd_drv_set_qos_map(hapd, conf->qos_map_set, +@@ -1393,7 +1394,6 @@ static int hostapd_setup_bss(struct host + wpa_printf(MSG_ERROR, "Failed to initialize QoS Map"); + return -1; + } +-#endif /* CONFIG_INTERWORKING */ + + if (conf->bss_load_update_period && bss_load_update_init(hapd)) { + wpa_printf(MSG_ERROR, "BSS Load initialization failed"); +--- a/src/ap/drv_callbacks.c ++++ b/src/ap/drv_callbacks.c +@@ -245,12 +245,10 @@ int hostapd_notif_assoc(struct hostapd_d + } + #endif /* NEED_AP_MLME */ + +-#ifdef CONFIG_INTERWORKING + if (elems.ext_capab && elems.ext_capab_len > 4) { + if (elems.ext_capab[4] & 0x01) + sta->qos_map_enabled = 1; + } +-#endif /* CONFIG_INTERWORKING */ + + #ifdef CONFIG_HS20 + wpabuf_free(sta->hs20_ie); +--- a/src/ap/ieee802_11.c ++++ b/src/ap/ieee802_11.c +@@ -2875,13 +2875,11 @@ static u16 copy_supp_rates(struct hostap + static u16 check_ext_capab(struct hostapd_data *hapd, struct sta_info *sta, + const u8 *ext_capab_ie, size_t ext_capab_ie_len) + { +-#ifdef CONFIG_INTERWORKING + /* check for QoS Map support */ + if (ext_capab_ie_len >= 5) { + if (ext_capab_ie[4] & 0x01) + sta->qos_map_enabled = 1; + } +-#endif /* CONFIG_INTERWORKING */ + + if (ext_capab_ie_len > 0) { + sta->ecsa_supported = !!(ext_capab_ie[0] & BIT(2)); +--- a/wpa_supplicant/events.c ++++ b/wpa_supplicant/events.c +@@ -2500,8 +2500,6 @@ void wnm_bss_keep_alive_deinit(struct wp + } + + +-#ifdef CONFIG_INTERWORKING +- + static int wpas_qos_map_set(struct wpa_supplicant *wpa_s, const u8 *qos_map, + size_t len) + { +@@ -2534,8 +2532,6 @@ static void interworking_process_assoc_r + } + } + +-#endif /* CONFIG_INTERWORKING */ +- + + static void multi_ap_process_assoc_resp(struct wpa_supplicant *wpa_s, + const u8 *ies, size_t ies_len) +@@ -2669,10 +2665,8 @@ static int wpa_supplicant_event_associnf + wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); + #endif /* CONFIG_WNM */ +-#ifdef CONFIG_INTERWORKING + interworking_process_assoc_resp(wpa_s, data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len); +-#endif /* CONFIG_INTERWORKING */ + if (wpa_s->hw_capab == CAPAB_VHT && + get_ie(data->assoc_info.resp_ies, + data->assoc_info.resp_ies_len, WLAN_EID_VHT_CAP)) diff --git a/package/network/services/hostapd/patches/802-wolfssl-init-RNG-with-ECC-key.patch b/package/network/services/hostapd/patches/802-wolfssl-init-RNG-with-ECC-key.patch index 89d111e991..84fc1c9351 100644 --- a/package/network/services/hostapd/patches/802-wolfssl-init-RNG-with-ECC-key.patch +++ b/package/network/services/hostapd/patches/802-wolfssl-init-RNG-with-ECC-key.patch @@ -14,11 +14,9 @@ Signed-off-by: David Bauer src/crypto/crypto_wolfssl.c | 4 ++++ 1 file changed, 4 insertions(+) -diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c -index 2e4bf8962..ed2528159 100644 --- a/src/crypto/crypto_wolfssl.c +++ b/src/crypto/crypto_wolfssl.c -@@ -1303,6 +1303,7 @@ int ecc_projective_add_point(ecc_point *P, ecc_point *Q, ecc_point *R, +@@ -1303,6 +1303,7 @@ int ecc_projective_add_point(ecc_point * struct crypto_ec { ecc_key key; @@ -26,7 +24,7 @@ index 2e4bf8962..ed2528159 100644 mp_int a; mp_int prime; mp_int order; -@@ -1357,6 +1358,8 @@ struct crypto_ec * crypto_ec_init(int group) +@@ -1357,6 +1358,8 @@ struct crypto_ec * crypto_ec_init(int gr return NULL; if (wc_ecc_init(&e->key) != 0 || @@ -35,7 +33,7 @@ index 2e4bf8962..ed2528159 100644 wc_ecc_set_curve(&e->key, 0, curve_id) != 0 || mp_init(&e->a) != MP_OKAY || mp_init(&e->prime) != MP_OKAY || -@@ -1388,6 +1391,7 @@ void crypto_ec_deinit(struct crypto_ec* e) +@@ -1388,6 +1391,7 @@ void crypto_ec_deinit(struct crypto_ec* mp_clear(&e->order); mp_clear(&e->prime); mp_clear(&e->a); @@ -43,6 +41,3 @@ index 2e4bf8962..ed2528159 100644 wc_ecc_free(&e->key); os_free(e); } --- -2.31.1 - diff --git a/package/network/utils/iw/patches/001-nl80211_h_sync.patch b/package/network/utils/iw/patches/001-nl80211_h_sync.patch index 1d6ea0fae0..2f724b61ff 100644 --- a/package/network/utils/iw/patches/001-nl80211_h_sync.patch +++ b/package/network/utils/iw/patches/001-nl80211_h_sync.patch @@ -20,27 +20,50 @@ * * @NL80211_CMD_SET_MULTICAST_TO_UNICAST: Configure if this AP should perform * multicast to unicast conversion. When enabled, all multicast packets -@@ -1177,6 +1181,10 @@ +@@ -1177,6 +1181,25 @@ * includes the contents of the frame. %NL80211_ATTR_ACK flag is included * if the recipient acknowledged the frame. * + * @NL80211_CMD_SET_SAR_SPECS: SAR power limitation configuration is + * passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to + * specify the wiphy index to be applied to. ++ * ++ * @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever ++ * mac80211/drv detects a bss color collision. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that ++ * userspace wants to change the BSS color. ++ * ++ * @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has ++ * started ++ * ++ * @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has ++ * been aborted ++ * ++ * @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change ++ * has completed + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ -@@ -1407,6 +1415,8 @@ enum nl80211_commands { +@@ -1407,6 +1430,16 @@ enum nl80211_commands { NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, + NL80211_CMD_SET_SAR_SPECS, ++ ++ NL80211_CMD_OBSS_COLOR_COLLISION, ++ ++ NL80211_CMD_COLOR_CHANGE_REQUEST, ++ ++ NL80211_CMD_COLOR_CHANGE_STARTED, ++ NL80211_CMD_COLOR_CHANGE_ABORTED, ++ NL80211_CMD_COLOR_CHANGE_COMPLETED, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ -@@ -1750,8 +1760,9 @@ enum nl80211_commands { +@@ -1750,8 +1783,9 @@ enum nl80211_commands { * specify just a single bitrate, which is to be used for the beacon. * The driver must also specify support for this with the extended * features NL80211_EXT_FEATURE_BEACON_RATE_LEGACY, @@ -52,7 +75,7 @@ * * @NL80211_ATTR_FRAME_MATCH: A binary attribute which typically must contain * at least one byte, currently used with @NL80211_CMD_REGISTER_FRAME. -@@ -1955,8 +1966,15 @@ enum nl80211_commands { +@@ -1955,8 +1989,15 @@ enum nl80211_commands { * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire * probe-response frame. The DA field in the 802.11 header is zero-ed out, * to be filled by the FW. @@ -70,7 +93,7 @@ * @NL80211_ATTR_HT_CAPABILITY_MASK: Specify which bits of the * ATTR_HT_CAPABILITY to which attention should be paid. * Currently, only mac80211 NICs support this feature. -@@ -2077,7 +2095,8 @@ enum nl80211_commands { +@@ -2077,7 +2118,8 @@ enum nl80211_commands { * until the channel switch event. * @NL80211_ATTR_CH_SWITCH_BLOCK_TX: flag attribute specifying that transmission * must be blocked on the current channel (before the channel switch @@ -80,7 +103,7 @@ * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information * for the time while performing a channel switch. * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel -@@ -2527,6 +2546,23 @@ enum nl80211_commands { +@@ -2527,6 +2569,33 @@ enum nl80211_commands { * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. * @@ -98,13 +121,23 @@ + * disassoc events to indicate that an immediate reconnect to the AP + * is desired. + * ++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the ++ * %NL80211_CMD_OBSS_COLOR_COLLISION event. ++ * ++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's ++ * until the color switch event. ++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are ++ * switching to ++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE ++ * information for the time while performing a color switch. ++ * + * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce + * transmit power to stay within regulatory limits. u32, dBi. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3016,6 +3052,16 @@ enum nl80211_attrs { +@@ -3016,6 +3085,22 @@ enum nl80211_attrs { NL80211_ATTR_S1G_CAPABILITY, NL80211_ATTR_S1G_CAPABILITY_MASK, @@ -116,12 +149,18 @@ + + NL80211_ATTR_DISABLE_HE, + ++ NL80211_ATTR_OBSS_COLOR_BITMAP, ++ ++ NL80211_ATTR_COLOR_CHANGE_COUNT, ++ NL80211_ATTR_COLOR_CHANGE_COLOR, ++ NL80211_ATTR_COLOR_CHANGE_ELEMS, ++ + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, -@@ -5896,6 +5942,19 @@ enum nl80211_feature_flags { +@@ -5896,6 +5981,22 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports * unsolicited broadcast probe response transmission * @@ -137,11 +176,14 @@ + * @NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE: Device supports management + * frame protection for all management frames exchanged during the + * negotiation and range measurement procedure. ++ * ++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision ++ * detection and change announcemnts. + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ -@@ -5956,6 +6015,10 @@ enum nl80211_ext_feature_index { +@@ -5956,6 +6057,11 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_SAE_OFFLOAD_AP, NL80211_EXT_FEATURE_FILS_DISCOVERY, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, @@ -149,10 +191,11 @@ + NL80211_EXT_FEATURE_SECURE_LTF, + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, ++ NL80211_EXT_FEATURE_BSS_COLOR, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, -@@ -6253,11 +6316,13 @@ struct nl80211_vendor_cmd_info { +@@ -6253,11 +6359,13 @@ struct nl80211_vendor_cmd_info { * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable. * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable. * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable. @@ -166,7 +209,7 @@ }; /** -@@ -6849,6 +6914,9 @@ enum nl80211_peer_measurement_ftm_capa { +@@ -6849,6 +6957,9 @@ enum nl80211_peer_measurement_ftm_capa { * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based * ranging will be used. @@ -176,7 +219,7 @@ * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number -@@ -6867,6 +6935,7 @@ enum nl80211_peer_measurement_ftm_req { +@@ -6867,6 +6978,7 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, @@ -184,7 +227,7 @@ /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, -@@ -7124,4 +7193,115 @@ enum nl80211_unsol_bcast_probe_resp_attr +@@ -7124,4 +7236,115 @@ enum nl80211_unsol_bcast_probe_resp_attr NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX = __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1 }; diff --git a/package/network/utils/iw/patches/200-reduce_size.patch b/package/network/utils/iw/patches/200-reduce_size.patch index 83e11405cb..c50a4a4d38 100644 --- a/package/network/utils/iw/patches/200-reduce_size.patch +++ b/package/network/utils/iw/patches/200-reduce_size.patch @@ -187,23 +187,29 @@ }; static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data, -@@ -2326,6 +2331,7 @@ void print_ies(unsigned char *ie, int ie - ieprinters[ie[0]].flags & BIT(ptype)) { - print_ie(&ieprinters[ie[0]], - ie[0], ie[1], ie + 2, &ie_buffer); +@@ -2080,8 +2085,10 @@ static void print_wifi_wps(const uint8_t + + static const struct ie_print wifiprinters[] = { + [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), }, +#ifdef IW_FULL - } else if (ie[0] == 221 /* vendor */) { - print_vendor(ie[1], ie + 2, unknown, ptype); - } else if (ie[0] == 255 /* extension */) { -@@ -2337,6 +2343,7 @@ void print_ies(unsigned char *ie, int ie - for (i=0; i= 4 && memcmp(data, wfa_oui, 3) == 0) { + if (data[3] < ARRAY_SIZE(wfa_printers) && + wfa_printers[data[3]].name && +@@ -2377,6 +2388,7 @@ static void print_capa_non_dmg(__u16 cap printf(" ESS"); if (capa & WLAN_CAPABILITY_IBSS) printf(" IBSS"); @@ -211,7 +217,7 @@ if (capa & WLAN_CAPABILITY_CF_POLLABLE) printf(" CfPollable"); if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST) -@@ -2405,6 +2413,7 @@ static void print_capa_non_dmg(__u16 cap +@@ -2405,6 +2417,7 @@ static void print_capa_non_dmg(__u16 cap printf(" DelayedBACK"); if (capa & WLAN_CAPABILITY_IMM_BACK) printf(" ImmediateBACK"); @@ -219,7 +225,7 @@ } static int print_bss_handler(struct nl_msg *msg, void *arg) -@@ -2489,8 +2498,10 @@ static int print_bss_handler(struct nl_m +@@ -2489,8 +2502,10 @@ static int print_bss_handler(struct nl_m if (bss[NL80211_BSS_FREQUENCY]) { int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]); printf("\tfreq: %d\n", freq); @@ -230,7 +236,7 @@ } if (bss[NL80211_BSS_BEACON_INTERVAL]) printf("\tbeacon interval: %d TUs\n", -@@ -2684,6 +2695,7 @@ static int handle_stop_sched_scan(struct +@@ -2684,6 +2699,7 @@ static int handle_stop_sched_scan(struct return 0; } @@ -238,7 +244,7 @@ COMMAND(scan, sched_start, SCHED_SCAN_OPTIONS, NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan, -@@ -2694,3 +2706,4 @@ COMMAND(scan, sched_start, +@@ -2694,3 +2710,4 @@ COMMAND(scan, sched_start, COMMAND(scan, sched_stop, "", NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan, "Stop an ongoing scheduled scan.");