From: Nick Hainke Date: Sun, 6 Nov 2022 15:48:32 +0000 (+0100) Subject: mac80211: subsys: add tags to upstreamed patches X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=2426dbb73402599d43c4c16146bd031a81c0bbc7;p=openwrt%2Fstaging%2Fblocktrron.git mac80211: subsys: add tags to upstreamed patches Some patches were already upstreamed. Signed-off-by: Nick Hainke --- diff --git a/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch b/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch deleted file mode 100644 index 159aad564b..0000000000 --- a/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch +++ /dev/null @@ -1,62 +0,0 @@ -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 -@@ -2950,6 +2950,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/303-v5.16-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch b/package/kernel/mac80211/patches/subsys/303-v5.16-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch new file mode 100644 index 0000000000..159aad564b --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/303-v5.16-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 +@@ -2950,6 +2950,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/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch b/package/kernel/mac80211/patches/subsys/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch deleted file mode 100644 index c43cd3acb9..0000000000 --- a/package/kernel/mac80211/patches/subsys/306-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch +++ /dev/null @@ -1,60 +0,0 @@ -From: Felix Fietkau -Date: Tue, 14 Dec 2021 17:53:12 +0100 -Subject: [PATCH] mac80211: use coarse boottime for airtime fairness code - -The time values used by the airtime fairness code only need to be accurate -enough to cover station activity detection. -Using ktime_get_coarse_boottime_ns instead of ktime_get_boottime_ns will -drop the accuracy down to jiffies intervals, but at the same time saves -a lot of CPU cycles in a hot path - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3820,7 +3820,7 @@ struct ieee80211_txq *ieee80211_next_txq - { - struct ieee80211_local *local = hw_to_local(hw); - struct airtime_sched_info *air_sched; -- u64 now = ktime_get_boottime_ns(); -+ u64 now = ktime_get_coarse_boottime_ns(); - struct ieee80211_txq *ret = NULL; - struct airtime_info *air_info; - struct txq_info *txqi = NULL; -@@ -3947,7 +3947,7 @@ void ieee80211_update_airtime_weight(str - u64 weight_sum = 0; - - if (unlikely(!now)) -- now = ktime_get_boottime_ns(); -+ now = ktime_get_coarse_boottime_ns(); - - lockdep_assert_held(&air_sched->lock); - -@@ -3973,7 +3973,7 @@ void ieee80211_schedule_txq(struct ieee8 - 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(); -+ u64 now = ktime_get_coarse_boottime_ns(); - struct airtime_info *air_info; - u8 ac = txq->ac; - bool was_active; -@@ -4031,7 +4031,7 @@ static void __ieee80211_unschedule_txq(s - - if (!purge) - airtime_set_active(air_sched, air_info, -- ktime_get_boottime_ns()); -+ ktime_get_coarse_boottime_ns()); - - rb_erase_cached(&txqi->schedule_order, - &air_sched->active_txqs); -@@ -4119,7 +4119,7 @@ bool ieee80211_txq_may_transmit(struct i - if (RB_EMPTY_NODE(&txqi->schedule_order)) - goto out; - -- now = ktime_get_boottime_ns(); -+ now = ktime_get_coarse_boottime_ns(); - - /* Like in ieee80211_next_txq(), make sure the first station in the - * scheduling order is eligible for transmission to avoid starvation. diff --git a/package/kernel/mac80211/patches/subsys/306-v5.17-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch b/package/kernel/mac80211/patches/subsys/306-v5.17-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch new file mode 100644 index 0000000000..c43cd3acb9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/306-v5.17-mac80211-use-coarse-boottime-for-airtime-fairness-co.patch @@ -0,0 +1,60 @@ +From: Felix Fietkau +Date: Tue, 14 Dec 2021 17:53:12 +0100 +Subject: [PATCH] mac80211: use coarse boottime for airtime fairness code + +The time values used by the airtime fairness code only need to be accurate +enough to cover station activity detection. +Using ktime_get_coarse_boottime_ns instead of ktime_get_boottime_ns will +drop the accuracy down to jiffies intervals, but at the same time saves +a lot of CPU cycles in a hot path + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3820,7 +3820,7 @@ struct ieee80211_txq *ieee80211_next_txq + { + struct ieee80211_local *local = hw_to_local(hw); + struct airtime_sched_info *air_sched; +- u64 now = ktime_get_boottime_ns(); ++ u64 now = ktime_get_coarse_boottime_ns(); + struct ieee80211_txq *ret = NULL; + struct airtime_info *air_info; + struct txq_info *txqi = NULL; +@@ -3947,7 +3947,7 @@ void ieee80211_update_airtime_weight(str + u64 weight_sum = 0; + + if (unlikely(!now)) +- now = ktime_get_boottime_ns(); ++ now = ktime_get_coarse_boottime_ns(); + + lockdep_assert_held(&air_sched->lock); + +@@ -3973,7 +3973,7 @@ void ieee80211_schedule_txq(struct ieee8 + 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(); ++ u64 now = ktime_get_coarse_boottime_ns(); + struct airtime_info *air_info; + u8 ac = txq->ac; + bool was_active; +@@ -4031,7 +4031,7 @@ static void __ieee80211_unschedule_txq(s + + if (!purge) + airtime_set_active(air_sched, air_info, +- ktime_get_boottime_ns()); ++ ktime_get_coarse_boottime_ns()); + + rb_erase_cached(&txqi->schedule_order, + &air_sched->active_txqs); +@@ -4119,7 +4119,7 @@ bool ieee80211_txq_may_transmit(struct i + if (RB_EMPTY_NODE(&txqi->schedule_order)) + goto out; + +- now = ktime_get_boottime_ns(); ++ now = ktime_get_coarse_boottime_ns(); + + /* Like in ieee80211_next_txq(), make sure the first station in the + * scheduling order is eligible for transmission to avoid starvation. diff --git a/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch deleted file mode 100644 index a9a6182ab2..0000000000 --- a/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch +++ /dev/null @@ -1,178 +0,0 @@ -From: Felix Fietkau -Date: Fri, 12 Nov 2021 12:22:23 +0100 -Subject: [PATCH] mac80211: add support for .ndo_fill_forward_path - -This allows drivers to provide a destination device + info for flow offload -Only supported in combination with 802.3 encap offload - -Signed-off-by: Felix Fietkau -Tested-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name -Signed-off-by: Johannes Berg ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -3937,6 +3937,8 @@ struct ieee80211_prep_tx_info { - * twt structure. - * @twt_teardown_request: Update the hw with TWT teardown request received - * from the peer. -+ * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to -+ * resolve a path for hardware flow offloading - */ - struct ieee80211_ops { - void (*tx)(struct ieee80211_hw *hw, -@@ -4265,6 +4267,13 @@ struct ieee80211_ops { - struct ieee80211_twt_setup *twt); - void (*twt_teardown_request)(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, u8 flowid); -+#if LINUX_VERSION_IS_GEQ(5,10,0) -+ int (*net_fill_forward_path)(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta, -+ struct net_device_path_ctx *ctx, -+ struct net_device_path *path); -+#endif - }; - - /** ---- a/net/mac80211/driver-ops.h -+++ b/net/mac80211/driver-ops.h -@@ -1486,4 +1486,28 @@ static inline void drv_twt_teardown_requ - trace_drv_return_void(local); - } - -+#if LINUX_VERSION_IS_GEQ(5,10,0) -+static inline int drv_net_fill_forward_path(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_sta *sta, -+ struct net_device_path_ctx *ctx, -+ struct net_device_path *path) -+{ -+ int ret = -EOPNOTSUPP; -+ -+ sdata = get_bss_sdata(sdata); -+ if (!check_sdata_in_driver(sdata)) -+ return -EIO; -+ -+ trace_drv_net_fill_forward_path(local, sdata, sta); -+ if (local->ops->net_fill_forward_path) -+ ret = local->ops->net_fill_forward_path(&local->hw, -+ &sdata->vif, sta, -+ ctx, path); -+ trace_drv_return_int(local, ret); -+ -+ return ret; -+} -+#endif -+ - #endif /* __MAC80211_DRIVER_OPS */ ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1489,7 +1489,7 @@ struct ieee80211_local { - }; - - static inline struct ieee80211_sub_if_data * --IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) -+IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev) - { - return netdev_priv(dev); - } ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -822,6 +822,66 @@ static const struct net_device_ops ieee8 - - }; - -+#if LINUX_VERSION_IS_GEQ(5,10,0) -+static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx, -+ struct net_device_path *path) -+{ -+ struct ieee80211_sub_if_data *sdata; -+ struct ieee80211_local *local; -+ struct sta_info *sta; -+ int ret = -ENOENT; -+ -+ sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev); -+ local = sdata->local; -+ -+ if (!local->ops->net_fill_forward_path) -+ return -EOPNOTSUPP; -+ -+ rcu_read_lock(); -+ switch (sdata->vif.type) { -+ case NL80211_IFTYPE_AP_VLAN: -+ sta = rcu_dereference(sdata->u.vlan.sta); -+ if (sta) -+ break; -+ if (sdata->wdev.use_4addr) -+ goto out; -+ if (is_multicast_ether_addr(ctx->daddr)) -+ goto out; -+ sta = sta_info_get_bss(sdata, ctx->daddr); -+ break; -+ case NL80211_IFTYPE_AP: -+ if (is_multicast_ether_addr(ctx->daddr)) -+ goto out; -+ sta = sta_info_get(sdata, ctx->daddr); -+ break; -+ case NL80211_IFTYPE_STATION: -+ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { -+ sta = sta_info_get(sdata, ctx->daddr); -+ if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { -+ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) -+ goto out; -+ -+ break; -+ } -+ } -+ -+ sta = sta_info_get(sdata, sdata->u.mgd.bssid); -+ break; -+ default: -+ goto out; -+ } -+ -+ if (!sta) -+ goto out; -+ -+ ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path); -+out: -+ rcu_read_unlock(); -+ -+ return ret; -+} -+#endif -+ - static const struct net_device_ops ieee80211_dataif_8023_ops = { - #if LINUX_VERSION_IS_LESS(4,10,0) - .ndo_change_mtu = __change_mtu, -@@ -839,7 +899,9 @@ static const struct net_device_ops ieee8 - #else - .ndo_get_stats64 = bp_ieee80211_get_stats64, - #endif -- -+#if LINUX_VERSION_IS_GEQ(5,10,0) -+ .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, -+#endif - }; - - static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) ---- a/net/mac80211/trace.h -+++ b/net/mac80211/trace.h -@@ -2892,6 +2892,15 @@ TRACE_EVENT(drv_twt_teardown_request, - ) - ); - -+#if LINUX_VERSION_IS_GEQ(5,10,0) -+DEFINE_EVENT(sta_event, drv_net_fill_forward_path, -+ TP_PROTO(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct ieee80211_sta *sta), -+ TP_ARGS(local, sdata, sta) -+); -+#endif -+ - #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ - - #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/308-v5.17-mac80211-add-support-for-.ndo_fill_forward_path.patch b/package/kernel/mac80211/patches/subsys/308-v5.17-mac80211-add-support-for-.ndo_fill_forward_path.patch new file mode 100644 index 0000000000..a9a6182ab2 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/308-v5.17-mac80211-add-support-for-.ndo_fill_forward_path.patch @@ -0,0 +1,178 @@ +From: Felix Fietkau +Date: Fri, 12 Nov 2021 12:22:23 +0100 +Subject: [PATCH] mac80211: add support for .ndo_fill_forward_path + +This allows drivers to provide a destination device + info for flow offload +Only supported in combination with 802.3 encap offload + +Signed-off-by: Felix Fietkau +Tested-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,6 +3937,8 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. ++ * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to ++ * resolve a path for hardware flow offloading + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, +@@ -4265,6 +4267,13 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++ int (*net_fill_forward_path)(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, ++ struct net_device_path_ctx *ctx, ++ struct net_device_path *path); ++#endif + }; + + /** +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1486,4 +1486,28 @@ static inline void drv_twt_teardown_requ + trace_drv_return_void(local); + } + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++static inline int drv_net_fill_forward_path(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ struct net_device_path_ctx *ctx, ++ struct net_device_path *path) ++{ ++ int ret = -EOPNOTSUPP; ++ ++ sdata = get_bss_sdata(sdata); ++ if (!check_sdata_in_driver(sdata)) ++ return -EIO; ++ ++ trace_drv_net_fill_forward_path(local, sdata, sta); ++ if (local->ops->net_fill_forward_path) ++ ret = local->ops->net_fill_forward_path(&local->hw, ++ &sdata->vif, sta, ++ ctx, path); ++ trace_drv_return_int(local, ret); ++ ++ return ret; ++} ++#endif ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1489,7 +1489,7 @@ struct ieee80211_local { + }; + + static inline struct ieee80211_sub_if_data * +-IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) ++IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev) + { + return netdev_priv(dev); + } +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -822,6 +822,66 @@ static const struct net_device_ops ieee8 + + }; + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx, ++ struct net_device_path *path) ++{ ++ struct ieee80211_sub_if_data *sdata; ++ struct ieee80211_local *local; ++ struct sta_info *sta; ++ int ret = -ENOENT; ++ ++ sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev); ++ local = sdata->local; ++ ++ if (!local->ops->net_fill_forward_path) ++ return -EOPNOTSUPP; ++ ++ rcu_read_lock(); ++ switch (sdata->vif.type) { ++ case NL80211_IFTYPE_AP_VLAN: ++ sta = rcu_dereference(sdata->u.vlan.sta); ++ if (sta) ++ break; ++ if (sdata->wdev.use_4addr) ++ goto out; ++ if (is_multicast_ether_addr(ctx->daddr)) ++ goto out; ++ sta = sta_info_get_bss(sdata, ctx->daddr); ++ break; ++ case NL80211_IFTYPE_AP: ++ if (is_multicast_ether_addr(ctx->daddr)) ++ goto out; ++ sta = sta_info_get(sdata, ctx->daddr); ++ break; ++ case NL80211_IFTYPE_STATION: ++ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) { ++ sta = sta_info_get(sdata, ctx->daddr); ++ if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { ++ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) ++ goto out; ++ ++ break; ++ } ++ } ++ ++ sta = sta_info_get(sdata, sdata->u.mgd.bssid); ++ break; ++ default: ++ goto out; ++ } ++ ++ if (!sta) ++ goto out; ++ ++ ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path); ++out: ++ rcu_read_unlock(); ++ ++ return ret; ++} ++#endif ++ + static const struct net_device_ops ieee80211_dataif_8023_ops = { + #if LINUX_VERSION_IS_LESS(4,10,0) + .ndo_change_mtu = __change_mtu, +@@ -839,7 +899,9 @@ static const struct net_device_ops ieee8 + #else + .ndo_get_stats64 = bp_ieee80211_get_stats64, + #endif +- ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++ .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path, ++#endif + }; + + static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2892,6 +2892,15 @@ TRACE_EVENT(drv_twt_teardown_request, + ) + ); + ++#if LINUX_VERSION_IS_GEQ(5,10,0) ++DEFINE_EVENT(sta_event, drv_net_fill_forward_path, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta), ++ TP_ARGS(local, sdata, sta) ++); ++#endif ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch b/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch deleted file mode 100644 index 18b1951f6e..0000000000 --- a/package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch +++ /dev/null @@ -1,262 +0,0 @@ -From: Aloka Dixit -Date: Tue, 5 Oct 2021 21:09:36 -0700 -Subject: [PATCH] mac80211: split beacon retrieval functions - -Split __ieee80211_beacon_get() into a separate function for AP mode -ieee80211_beacon_get_ap(). -Also, move the code common to all modes (AP, adhoc and mesh) to -a separate function ieee80211_beacon_get_finish(). - -Signed-off-by: Aloka Dixit -Link: https://lore.kernel.org/r/20211006040938.9531-2-alokad@codeaurora.org -Signed-off-by: Johannes Berg ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -4987,6 +4987,115 @@ static int ieee80211_beacon_protect(stru - return 0; - } - -+static void -+ieee80211_beacon_get_finish(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_mutable_offsets *offs, -+ struct beacon_data *beacon, -+ struct sk_buff *skb, -+ struct ieee80211_chanctx_conf *chanctx_conf, -+ u16 csa_off_base) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); -+ struct ieee80211_tx_info *info; -+ enum nl80211_band band; -+ struct ieee80211_tx_rate_control txrc; -+ -+ /* CSA offsets */ -+ if (offs && beacon) { -+ u16 i; -+ -+ for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { -+ u16 csa_off = beacon->cntdwn_counter_offsets[i]; -+ -+ if (!csa_off) -+ continue; -+ -+ offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; -+ } -+ } -+ -+ band = chanctx_conf->def.chan->band; -+ info = IEEE80211_SKB_CB(skb); -+ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; -+ info->flags |= IEEE80211_TX_CTL_NO_ACK; -+ info->band = band; -+ -+ memset(&txrc, 0, sizeof(txrc)); -+ txrc.hw = hw; -+ txrc.sband = local->hw.wiphy->bands[band]; -+ txrc.bss_conf = &sdata->vif.bss_conf; -+ txrc.skb = skb; -+ txrc.reported_rate.idx = -1; -+ if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) -+ txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; -+ else -+ txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; -+ txrc.bss = true; -+ rate_control_get_rate(sdata, NULL, &txrc); -+ -+ info->control.vif = vif; -+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | -+ IEEE80211_TX_CTL_ASSIGN_SEQ | -+ IEEE80211_TX_CTL_FIRST_FRAGMENT; -+} -+ -+static struct sk_buff * -+ieee80211_beacon_get_ap(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_mutable_offsets *offs, -+ bool is_template, -+ struct beacon_data *beacon, -+ struct ieee80211_chanctx_conf *chanctx_conf) -+{ -+ struct ieee80211_local *local = hw_to_local(hw); -+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); -+ struct ieee80211_if_ap *ap = &sdata->u.ap; -+ struct sk_buff *skb = NULL; -+ u16 csa_off_base = 0; -+ -+ if (beacon->cntdwn_counter_offsets[0]) { -+ if (!is_template) -+ ieee80211_beacon_update_cntdwn(vif); -+ -+ ieee80211_set_beacon_cntdwn(sdata, beacon); -+ } -+ -+ /* headroom, head length, -+ * tail length and maximum TIM length -+ */ -+ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + -+ beacon->tail_len + 256 + -+ local->hw.extra_beacon_tailroom); -+ if (!skb) -+ return NULL; -+ -+ skb_reserve(skb, local->tx_headroom); -+ skb_put_data(skb, beacon->head, beacon->head_len); -+ -+ ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); -+ -+ 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; -+ } -+ -+ if (beacon->tail) -+ skb_put_data(skb, beacon->tail, beacon->tail_len); -+ -+ if (ieee80211_beacon_protect(skb, local, sdata) < 0) -+ return NULL; -+ -+ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, -+ csa_off_base); -+ return skb; -+} -+ - static struct sk_buff * - __ieee80211_beacon_get(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, -@@ -4996,12 +5105,8 @@ __ieee80211_beacon_get(struct ieee80211_ - struct ieee80211_local *local = hw_to_local(hw); - struct beacon_data *beacon = NULL; - struct sk_buff *skb = NULL; -- struct ieee80211_tx_info *info; - struct ieee80211_sub_if_data *sdata = NULL; -- enum nl80211_band band; -- struct ieee80211_tx_rate_control txrc; - struct ieee80211_chanctx_conf *chanctx_conf; -- int csa_off_base = 0; - - rcu_read_lock(); - -@@ -5018,48 +5123,11 @@ __ieee80211_beacon_get(struct ieee80211_ - struct ieee80211_if_ap *ap = &sdata->u.ap; - - beacon = rcu_dereference(ap->beacon); -- if (beacon) { -- if (beacon->cntdwn_counter_offsets[0]) { -- if (!is_template) -- ieee80211_beacon_update_cntdwn(vif); -- -- ieee80211_set_beacon_cntdwn(sdata, beacon); -- } -- -- /* -- * headroom, head length, -- * tail length and maximum TIM length -- */ -- skb = dev_alloc_skb(local->tx_headroom + -- beacon->head_len + -- beacon->tail_len + 256 + -- local->hw.extra_beacon_tailroom); -- if (!skb) -- goto out; -- -- skb_reserve(skb, local->tx_headroom); -- skb_put_data(skb, beacon->head, beacon->head_len); -- -- ieee80211_beacon_add_tim(sdata, &ap->ps, skb, -- is_template); -- -- 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; -- } -- -- if (beacon->tail) -- skb_put_data(skb, beacon->tail, -- beacon->tail_len); -- -- if (ieee80211_beacon_protect(skb, local, sdata) < 0) -- goto out; -- } else -+ if (!beacon) - goto out; -+ -+ skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, -+ beacon, chanctx_conf); - } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - struct ieee80211_hdr *hdr; -@@ -5085,6 +5153,9 @@ __ieee80211_beacon_get(struct ieee80211_ - hdr = (struct ieee80211_hdr *) skb->data; - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_BEACON); -+ -+ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, -+ chanctx_conf, 0); - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { - struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - -@@ -5124,51 +5195,13 @@ __ieee80211_beacon_get(struct ieee80211_ - } - - skb_put_data(skb, beacon->tail, beacon->tail_len); -+ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, -+ chanctx_conf, 0); - } else { - WARN_ON(1); - goto out; - } - -- /* CSA offsets */ -- if (offs && beacon) { -- int i; -- -- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { -- u16 csa_off = beacon->cntdwn_counter_offsets[i]; -- -- if (!csa_off) -- continue; -- -- offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; -- } -- } -- -- band = chanctx_conf->def.chan->band; -- -- info = IEEE80211_SKB_CB(skb); -- -- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; -- info->flags |= IEEE80211_TX_CTL_NO_ACK; -- info->band = band; -- -- memset(&txrc, 0, sizeof(txrc)); -- txrc.hw = hw; -- txrc.sband = local->hw.wiphy->bands[band]; -- txrc.bss_conf = &sdata->vif.bss_conf; -- txrc.skb = skb; -- txrc.reported_rate.idx = -1; -- if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) -- txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; -- else -- txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; -- txrc.bss = true; -- rate_control_get_rate(sdata, NULL, &txrc); -- -- info->control.vif = vif; -- -- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | -- IEEE80211_TX_CTL_ASSIGN_SEQ | -- IEEE80211_TX_CTL_FIRST_FRAGMENT; - out: - rcu_read_unlock(); - return skb; diff --git a/package/kernel/mac80211/patches/subsys/312-v5.16-mac80211-split-beacon-retrieval-functions.patch b/package/kernel/mac80211/patches/subsys/312-v5.16-mac80211-split-beacon-retrieval-functions.patch new file mode 100644 index 0000000000..18b1951f6e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/312-v5.16-mac80211-split-beacon-retrieval-functions.patch @@ -0,0 +1,262 @@ +From: Aloka Dixit +Date: Tue, 5 Oct 2021 21:09:36 -0700 +Subject: [PATCH] mac80211: split beacon retrieval functions + +Split __ieee80211_beacon_get() into a separate function for AP mode +ieee80211_beacon_get_ap(). +Also, move the code common to all modes (AP, adhoc and mesh) to +a separate function ieee80211_beacon_get_finish(). + +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20211006040938.9531-2-alokad@codeaurora.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4987,6 +4987,115 @@ static int ieee80211_beacon_protect(stru + return 0; + } + ++static void ++ieee80211_beacon_get_finish(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ struct beacon_data *beacon, ++ struct sk_buff *skb, ++ struct ieee80211_chanctx_conf *chanctx_conf, ++ u16 csa_off_base) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_tx_info *info; ++ enum nl80211_band band; ++ struct ieee80211_tx_rate_control txrc; ++ ++ /* CSA offsets */ ++ if (offs && beacon) { ++ u16 i; ++ ++ for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { ++ u16 csa_off = beacon->cntdwn_counter_offsets[i]; ++ ++ if (!csa_off) ++ continue; ++ ++ offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; ++ } ++ } ++ ++ band = chanctx_conf->def.chan->band; ++ info = IEEE80211_SKB_CB(skb); ++ info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ++ info->flags |= IEEE80211_TX_CTL_NO_ACK; ++ info->band = band; ++ ++ memset(&txrc, 0, sizeof(txrc)); ++ txrc.hw = hw; ++ txrc.sband = local->hw.wiphy->bands[band]; ++ txrc.bss_conf = &sdata->vif.bss_conf; ++ txrc.skb = skb; ++ txrc.reported_rate.idx = -1; ++ if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) ++ txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; ++ else ++ txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; ++ txrc.bss = true; ++ rate_control_get_rate(sdata, NULL, &txrc); ++ ++ info->control.vif = vif; ++ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | ++ IEEE80211_TX_CTL_ASSIGN_SEQ | ++ IEEE80211_TX_CTL_FIRST_FRAGMENT; ++} ++ ++static struct sk_buff * ++ieee80211_beacon_get_ap(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_mutable_offsets *offs, ++ bool is_template, ++ struct beacon_data *beacon, ++ struct ieee80211_chanctx_conf *chanctx_conf) ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_if_ap *ap = &sdata->u.ap; ++ struct sk_buff *skb = NULL; ++ u16 csa_off_base = 0; ++ ++ if (beacon->cntdwn_counter_offsets[0]) { ++ if (!is_template) ++ ieee80211_beacon_update_cntdwn(vif); ++ ++ ieee80211_set_beacon_cntdwn(sdata, beacon); ++ } ++ ++ /* headroom, head length, ++ * tail length and maximum TIM length ++ */ ++ skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + ++ beacon->tail_len + 256 + ++ local->hw.extra_beacon_tailroom); ++ if (!skb) ++ return NULL; ++ ++ skb_reserve(skb, local->tx_headroom); ++ skb_put_data(skb, beacon->head, beacon->head_len); ++ ++ ieee80211_beacon_add_tim(sdata, &ap->ps, skb, is_template); ++ ++ 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; ++ } ++ ++ if (beacon->tail) ++ skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ++ if (ieee80211_beacon_protect(skb, local, sdata) < 0) ++ return NULL; ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, chanctx_conf, ++ csa_off_base); ++ return skb; ++} ++ + static struct sk_buff * + __ieee80211_beacon_get(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -4996,12 +5105,8 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_local *local = hw_to_local(hw); + struct beacon_data *beacon = NULL; + struct sk_buff *skb = NULL; +- struct ieee80211_tx_info *info; + struct ieee80211_sub_if_data *sdata = NULL; +- enum nl80211_band band; +- struct ieee80211_tx_rate_control txrc; + struct ieee80211_chanctx_conf *chanctx_conf; +- int csa_off_base = 0; + + rcu_read_lock(); + +@@ -5018,48 +5123,11 @@ __ieee80211_beacon_get(struct ieee80211_ + struct ieee80211_if_ap *ap = &sdata->u.ap; + + beacon = rcu_dereference(ap->beacon); +- if (beacon) { +- if (beacon->cntdwn_counter_offsets[0]) { +- if (!is_template) +- ieee80211_beacon_update_cntdwn(vif); +- +- ieee80211_set_beacon_cntdwn(sdata, beacon); +- } +- +- /* +- * headroom, head length, +- * tail length and maximum TIM length +- */ +- skb = dev_alloc_skb(local->tx_headroom + +- beacon->head_len + +- beacon->tail_len + 256 + +- local->hw.extra_beacon_tailroom); +- if (!skb) +- goto out; +- +- skb_reserve(skb, local->tx_headroom); +- skb_put_data(skb, beacon->head, beacon->head_len); +- +- ieee80211_beacon_add_tim(sdata, &ap->ps, skb, +- is_template); +- +- 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; +- } +- +- if (beacon->tail) +- skb_put_data(skb, beacon->tail, +- beacon->tail_len); +- +- if (ieee80211_beacon_protect(skb, local, sdata) < 0) +- goto out; +- } else ++ if (!beacon) + goto out; ++ ++ skb = ieee80211_beacon_get_ap(hw, vif, offs, is_template, ++ beacon, chanctx_conf); + } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; + struct ieee80211_hdr *hdr; +@@ -5085,6 +5153,9 @@ __ieee80211_beacon_get(struct ieee80211_ + hdr = (struct ieee80211_hdr *) skb->data; + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_BEACON); ++ ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + +@@ -5124,51 +5195,13 @@ __ieee80211_beacon_get(struct ieee80211_ + } + + skb_put_data(skb, beacon->tail, beacon->tail_len); ++ ieee80211_beacon_get_finish(hw, vif, offs, beacon, skb, ++ chanctx_conf, 0); + } else { + WARN_ON(1); + goto out; + } + +- /* CSA offsets */ +- if (offs && beacon) { +- int i; +- +- for (i = 0; i < IEEE80211_MAX_CNTDWN_COUNTERS_NUM; i++) { +- u16 csa_off = beacon->cntdwn_counter_offsets[i]; +- +- if (!csa_off) +- continue; +- +- offs->cntdwn_counter_offs[i] = csa_off_base + csa_off; +- } +- } +- +- band = chanctx_conf->def.chan->band; +- +- info = IEEE80211_SKB_CB(skb); +- +- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +- info->flags |= IEEE80211_TX_CTL_NO_ACK; +- info->band = band; +- +- memset(&txrc, 0, sizeof(txrc)); +- txrc.hw = hw; +- txrc.sband = local->hw.wiphy->bands[band]; +- txrc.bss_conf = &sdata->vif.bss_conf; +- txrc.skb = skb; +- txrc.reported_rate.idx = -1; +- if (sdata->beacon_rate_set && sdata->beacon_rateidx_mask[band]) +- txrc.rate_idx_mask = sdata->beacon_rateidx_mask[band]; +- else +- txrc.rate_idx_mask = sdata->rc_rateidx_mask[band]; +- txrc.bss = true; +- rate_control_get_rate(sdata, NULL, &txrc); +- +- info->control.vif = vif; +- +- info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT | +- IEEE80211_TX_CTL_ASSIGN_SEQ | +- IEEE80211_TX_CTL_FIRST_FRAGMENT; + out: + rcu_read_unlock(); + return skb; diff --git a/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch deleted file mode 100644 index 429886d701..0000000000 --- a/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch +++ /dev/null @@ -1,493 +0,0 @@ -From: John Crispin -Date: Wed, 15 Sep 2021 19:54:34 -0700 -Subject: [PATCH] nl80211: MBSSID and EMA support in AP mode - -Add new attributes to configure support for multiple BSSID -and advanced multi-BSSID advertisements (EMA) in AP mode. - -- NL80211_ATTR_MBSSID_CONFIG used for per interface configuration. -- NL80211_ATTR_MBSSID_ELEMS used to MBSSID elements for beacons. - -Memory for the elements is allocated dynamically. This change frees -the memory in existing functions which call nl80211_parse_beacon(), -a comment is added to indicate the new references to do the same. - -Signed-off-by: John Crispin -Co-developed-by: Aloka Dixit -Signed-off-by: Aloka Dixit -Link: https://lore.kernel.org/r/20210916025437.29138-2-alokad@codeaurora.org -[don't leave ERR_PTR hanging around] -Signed-off-by: Johannes Berg ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -1046,6 +1046,36 @@ struct cfg80211_crypto_settings { - }; - - /** -+ * struct cfg80211_mbssid_config - AP settings for multi bssid -+ * -+ * @tx_wdev: pointer to the transmitted interface in the MBSSID set -+ * @index: index of this AP in the multi bssid group. -+ * @ema: set to true if the beacons should be sent out in EMA mode. -+ */ -+struct cfg80211_mbssid_config { -+ struct wireless_dev *tx_wdev; -+ u8 index; -+ bool ema; -+}; -+ -+/** -+ * struct cfg80211_mbssid_elems - Multiple BSSID elements -+ * -+ * @cnt: Number of elements in array %elems. -+ * -+ * @elem: Array of multiple BSSID element(s) to be added into Beacon frames. -+ * @elem.data: Data for multiple BSSID elements. -+ * @elem.len: Length of data. -+ */ -+struct cfg80211_mbssid_elems { -+ u8 cnt; -+ struct { -+ const u8 *data; -+ size_t len; -+ } elem[]; -+}; -+ -+/** - * struct cfg80211_beacon_data - beacon data - * @head: head portion of beacon (before TIM IE) - * or %NULL if not changed -@@ -1063,6 +1093,7 @@ struct cfg80211_crypto_settings { - * @assocresp_ies_len: length of assocresp_ies in octets - * @probe_resp_len: length of probe response template (@probe_resp) - * @probe_resp: probe response template (AP mode only) -+ * @mbssid_ies: multiple BSSID elements - * @ftm_responder: enable FTM responder functionality; -1 for no change - * (which also implies no change in LCI/civic location data) - * @lci: Measurement Report element content, starting with Measurement Token -@@ -1080,6 +1111,7 @@ struct cfg80211_beacon_data { - const u8 *probe_resp; - const u8 *lci; - const u8 *civicloc; -+ struct cfg80211_mbssid_elems *mbssid_ies; - s8 ftm_responder; - - size_t head_len, tail_len; -@@ -1194,6 +1226,7 @@ enum cfg80211_ap_settings_flags { - * @he_oper: HE operation IE (or %NULL if HE isn't enabled) - * @fils_discovery: FILS discovery transmission parameters - * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters -+ * @mbssid_config: AP settings for multiple bssid - */ - struct cfg80211_ap_settings { - struct cfg80211_chan_def chandef; -@@ -1226,6 +1259,7 @@ struct cfg80211_ap_settings { - struct cfg80211_he_bss_color he_bss_color; - struct cfg80211_fils_discovery fils_discovery; - struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; -+ struct cfg80211_mbssid_config mbssid_config; - }; - - /** -@@ -4986,6 +5020,13 @@ struct wiphy_iftype_akm_suites { - * %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes - * @sar_capa: SAR control capabilities - * @rfkill: a pointer to the rfkill structure -+ * -+ * @mbssid_max_interfaces: maximum number of interfaces supported by the driver -+ * in a multiple BSSID set. This field must be set to a non-zero value -+ * by the driver to advertise MBSSID support. -+ * @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by -+ * the driver. Setting this field to a non-zero value indicates that the -+ * driver supports enhanced multi-BSSID advertisements (EMA AP). - */ - struct wiphy { - struct mutex mtx; -@@ -5133,6 +5174,9 @@ struct wiphy { - - struct rfkill *rfkill; - -+ u8 mbssid_max_interfaces; -+ u8 ema_max_profile_periodicity; -+ - char priv[] __aligned(NETDEV_ALIGN); - }; - ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -337,7 +337,10 @@ - * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes - * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from - * userspace to request deletion of a virtual interface, then requires -- * attribute %NL80211_ATTR_IFINDEX. -+ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are -+ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, -+ * and if this command is used for the transmitting interface, then all -+ * the non-transmitting interfaces are deleted as well. - * - * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified - * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. -@@ -2593,6 +2596,18 @@ 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_MBSSID_CONFIG: Nested attribute for multiple BSSID -+ * advertisements (MBSSID) parameters in AP mode. -+ * Kernel uses this attribute to indicate the driver's support for MBSSID -+ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. -+ * Userspace should use this attribute to configure per interface MBSSID -+ * parameters. -+ * See &enum nl80211_mbssid_config_attributes for details. -+ * -+ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. -+ * Mandatory parameter for the transmitting interface to enable MBSSID. -+ * Optional for the non-transmitting interfaces. -+ * - * @NUM_NL80211_ATTR: total number of nl80211_attrs available - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3096,6 +3111,9 @@ enum nl80211_attrs { - NL80211_ATTR_COLOR_CHANGE_COLOR, - NL80211_ATTR_COLOR_CHANGE_ELEMS, - -+ NL80211_ATTR_MBSSID_CONFIG, -+ NL80211_ATTR_MBSSID_ELEMS, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, -@@ -7349,4 +7367,60 @@ enum nl80211_sar_specs_attrs { - NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, - }; - -+/** -+ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced -+ * multi-BSSID advertisements (EMA) in AP mode. -+ * Kernel uses some of these attributes to advertise driver's support for -+ * MBSSID and EMA. -+ * Remaining attributes should be used by the userspace to configure the -+ * features. -+ * -+ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid -+ * -+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise -+ * the maximum number of MBSSID interfaces supported by the driver. -+ * Driver should indicate MBSSID support by setting -+ * wiphy->mbssid_max_interfaces to a value more than or equal to 2. -+ * -+ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel -+ * to advertise the maximum profile periodicity supported by the driver -+ * if EMA is enabled. Driver should indicate EMA support to the userspace -+ * by setting wiphy->mbssid_max_ema_profile_periodicity to -+ * a non-zero value. -+ * -+ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of -+ * this BSS (u8) in the multiple BSSID set. -+ * Value must be set to 0 for the transmitting interface and non-zero for -+ * all non-transmitting interfaces. The userspace will be responsible -+ * for using unique indices for the interfaces. -+ * Range: 0 to wiphy->mbssid_max_interfaces-1. -+ * -+ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for -+ * a non-transmitted profile which provides the interface index (u32) of -+ * the transmitted profile. The value must match one of the interface -+ * indices advertised by the kernel. Optional if the interface being set up -+ * is the transmitting one, however, if provided then the value must match -+ * the interface index of the same. -+ * -+ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. -+ * Setting this flag is permitted only if the driver advertises EMA support -+ * by setting wiphy->mbssid_max_ema_profile_periodicity to non-zero. -+ * -+ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal -+ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute -+ */ -+enum nl80211_mbssid_config_attributes { -+ __NL80211_MBSSID_CONFIG_ATTR_INVALID, -+ -+ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, -+ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, -+ NL80211_MBSSID_CONFIG_ATTR_INDEX, -+ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, -+ NL80211_MBSSID_CONFIG_ATTR_EMA, -+ -+ /* keep last */ -+ __NL80211_MBSSID_CONFIG_ATTR_LAST, -+ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, -+}; -+ - #endif /* __LINUX_NL80211_H */ ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -442,6 +442,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = { - [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), - }; - -+static const struct nla_policy -+nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { -+ [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2), -+ [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] = -+ NLA_POLICY_MIN(NLA_U8, 1), -+ [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 }, -+ [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 }, -+ [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, -+}; -+ - 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 }, -@@ -788,6 +798,9 @@ 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_MBSSID_CONFIG] = -+ NLA_POLICY_NESTED(nl80211_mbssid_config_policy), -+ [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, - }; - - /* policy for the key attributes */ -@@ -2236,6 +2249,35 @@ fail: - return -ENOBUFS; - } - -+static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) -+{ -+ struct nlattr *config; -+ -+ if (!wiphy->mbssid_max_interfaces) -+ return 0; -+ -+ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); -+ if (!config) -+ return -ENOBUFS; -+ -+ if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, -+ wiphy->mbssid_max_interfaces)) -+ goto fail; -+ -+ if (wiphy->ema_max_profile_periodicity && -+ nla_put_u8(msg, -+ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, -+ wiphy->ema_max_profile_periodicity)) -+ goto fail; -+ -+ nla_nest_end(msg, config); -+ return 0; -+ -+fail: -+ nla_nest_cancel(msg, config); -+ return -ENOBUFS; -+} -+ - struct nl80211_dump_wiphy_state { - s64 filter_wiphy; - long start; -@@ -2821,6 +2863,9 @@ static int nl80211_send_wiphy(struct cfg - if (nl80211_put_sar_specs(rdev, msg)) - goto nla_put_failure; - -+ if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) -+ goto nla_put_failure; -+ - /* done */ - state->split_start = 0; - break; -@@ -5020,6 +5065,96 @@ static int validate_beacon_tx_rate(struc - return 0; - } - -+static int nl80211_parse_mbssid_config(struct wiphy *wiphy, -+ struct net_device *dev, -+ struct nlattr *attrs, -+ struct cfg80211_mbssid_config *config, -+ u8 num_elems) -+{ -+ struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; -+ -+ if (!wiphy->mbssid_max_interfaces) -+ return -EOPNOTSUPP; -+ -+ if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL, -+ NULL) || -+ !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]) -+ return -EINVAL; -+ -+ config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]); -+ if (config->ema) { -+ if (!wiphy->ema_max_profile_periodicity) -+ return -EOPNOTSUPP; -+ -+ if (num_elems > wiphy->ema_max_profile_periodicity) -+ return -EINVAL; -+ } -+ -+ config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]); -+ if (config->index >= wiphy->mbssid_max_interfaces || -+ (!config->index && !num_elems)) -+ return -EINVAL; -+ -+ if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) { -+ u32 tx_ifindex = -+ nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]); -+ -+ if ((!config->index && tx_ifindex != dev->ifindex) || -+ (config->index && tx_ifindex == dev->ifindex)) -+ return -EINVAL; -+ -+ if (tx_ifindex != dev->ifindex) { -+ struct net_device *tx_netdev = -+ dev_get_by_index(wiphy_net(wiphy), tx_ifindex); -+ -+ if (!tx_netdev || !tx_netdev->ieee80211_ptr || -+ tx_netdev->ieee80211_ptr->wiphy != wiphy || -+ tx_netdev->ieee80211_ptr->iftype != -+ NL80211_IFTYPE_AP) { -+ dev_put(tx_netdev); -+ return -EINVAL; -+ } -+ -+ config->tx_wdev = tx_netdev->ieee80211_ptr; -+ } else { -+ config->tx_wdev = dev->ieee80211_ptr; -+ } -+ } else if (!config->index) { -+ config->tx_wdev = dev->ieee80211_ptr; -+ } else { -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static struct cfg80211_mbssid_elems * -+nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) -+{ -+ struct nlattr *nl_elems; -+ struct cfg80211_mbssid_elems *elems; -+ int rem_elems; -+ u8 i = 0, num_elems = 0; -+ -+ if (!wiphy->mbssid_max_interfaces) -+ return ERR_PTR(-EINVAL); -+ -+ nla_for_each_nested(nl_elems, attrs, rem_elems) -+ num_elems++; -+ -+ elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); -+ if (!elems) -+ return ERR_PTR(-ENOMEM); -+ -+ nla_for_each_nested(nl_elems, attrs, rem_elems) { -+ elems->elem[i].data = nla_data(nl_elems); -+ elems->elem[i].len = nla_len(nl_elems); -+ i++; -+ } -+ elems->cnt = num_elems; -+ return elems; -+} -+ - static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, - struct nlattr *attrs[], - struct cfg80211_beacon_data *bcn) -@@ -5100,6 +5235,17 @@ static int nl80211_parse_beacon(struct c - bcn->ftm_responder = -1; - } - -+ if (attrs[NL80211_ATTR_MBSSID_ELEMS]) { -+ struct cfg80211_mbssid_elems *mbssid = -+ nl80211_parse_mbssid_elems(&rdev->wiphy, -+ attrs[NL80211_ATTR_MBSSID_ELEMS]); -+ -+ if (IS_ERR(mbssid)) -+ return PTR_ERR(mbssid); -+ -+ bcn->mbssid_ies = mbssid; -+ } -+ - return 0; - } - -@@ -5556,6 +5702,17 @@ static int nl80211_start_ap(struct sk_bu - goto out; - } - -+ if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) { -+ err = nl80211_parse_mbssid_config(&rdev->wiphy, dev, -+ info->attrs[NL80211_ATTR_MBSSID_CONFIG], -+ ¶ms.mbssid_config, -+ params.beacon.mbssid_ies ? -+ params.beacon.mbssid_ies->cnt : -+ 0); -+ if (err) -+ goto out; -+ } -+ - nl80211_calculate_ap_params(¶ms); - - if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) -@@ -5577,6 +5734,11 @@ static int nl80211_start_ap(struct sk_bu - - out: - kfree(params.acl); -+ kfree(params.beacon.mbssid_ies); -+ if (params.mbssid_config.tx_wdev && -+ params.mbssid_config.tx_wdev->netdev && -+ params.mbssid_config.tx_wdev->netdev != dev) -+ dev_put(params.mbssid_config.tx_wdev->netdev); - - return err; - } -@@ -5601,12 +5763,14 @@ static int nl80211_set_beacon(struct sk_ - - err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); - if (err) -- return err; -+ goto out; - - wdev_lock(wdev); - err = rdev_change_beacon(rdev, dev, ¶ms); - wdev_unlock(wdev); - -+out: -+ kfree(params.mbssid_ies); - return err; - } - -@@ -9283,12 +9447,14 @@ static int nl80211_channel_switch(struct - - err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after); - if (err) -- return err; -+ goto free; - - csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs), - GFP_KERNEL); -- if (!csa_attrs) -- return -ENOMEM; -+ if (!csa_attrs) { -+ err = -ENOMEM; -+ goto free; -+ } - - err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX, - info->attrs[NL80211_ATTR_CSA_IES], -@@ -9407,6 +9573,8 @@ skip_beacons: - wdev_unlock(wdev); - - free: -+ kfree(params.beacon_after.mbssid_ies); -+ kfree(params.beacon_csa.mbssid_ies); - kfree(csa_attrs); - return err; - } -@@ -14959,6 +15127,8 @@ static int nl80211_color_change(struct s - wdev_unlock(wdev); - - out: -+ kfree(params.beacon_next.mbssid_ies); -+ kfree(params.beacon_color_change.mbssid_ies); - kfree(tb); - return err; - } diff --git a/package/kernel/mac80211/patches/subsys/313-v5.16-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/313-v5.16-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch new file mode 100644 index 0000000000..429886d701 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/313-v5.16-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch @@ -0,0 +1,493 @@ +From: John Crispin +Date: Wed, 15 Sep 2021 19:54:34 -0700 +Subject: [PATCH] nl80211: MBSSID and EMA support in AP mode + +Add new attributes to configure support for multiple BSSID +and advanced multi-BSSID advertisements (EMA) in AP mode. + +- NL80211_ATTR_MBSSID_CONFIG used for per interface configuration. +- NL80211_ATTR_MBSSID_ELEMS used to MBSSID elements for beacons. + +Memory for the elements is allocated dynamically. This change frees +the memory in existing functions which call nl80211_parse_beacon(), +a comment is added to indicate the new references to do the same. + +Signed-off-by: John Crispin +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20210916025437.29138-2-alokad@codeaurora.org +[don't leave ERR_PTR hanging around] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1046,6 +1046,36 @@ struct cfg80211_crypto_settings { + }; + + /** ++ * struct cfg80211_mbssid_config - AP settings for multi bssid ++ * ++ * @tx_wdev: pointer to the transmitted interface in the MBSSID set ++ * @index: index of this AP in the multi bssid group. ++ * @ema: set to true if the beacons should be sent out in EMA mode. ++ */ ++struct cfg80211_mbssid_config { ++ struct wireless_dev *tx_wdev; ++ u8 index; ++ bool ema; ++}; ++ ++/** ++ * struct cfg80211_mbssid_elems - Multiple BSSID elements ++ * ++ * @cnt: Number of elements in array %elems. ++ * ++ * @elem: Array of multiple BSSID element(s) to be added into Beacon frames. ++ * @elem.data: Data for multiple BSSID elements. ++ * @elem.len: Length of data. ++ */ ++struct cfg80211_mbssid_elems { ++ u8 cnt; ++ struct { ++ const u8 *data; ++ size_t len; ++ } elem[]; ++}; ++ ++/** + * struct cfg80211_beacon_data - beacon data + * @head: head portion of beacon (before TIM IE) + * or %NULL if not changed +@@ -1063,6 +1093,7 @@ struct cfg80211_crypto_settings { + * @assocresp_ies_len: length of assocresp_ies in octets + * @probe_resp_len: length of probe response template (@probe_resp) + * @probe_resp: probe response template (AP mode only) ++ * @mbssid_ies: multiple BSSID elements + * @ftm_responder: enable FTM responder functionality; -1 for no change + * (which also implies no change in LCI/civic location data) + * @lci: Measurement Report element content, starting with Measurement Token +@@ -1080,6 +1111,7 @@ struct cfg80211_beacon_data { + const u8 *probe_resp; + const u8 *lci; + const u8 *civicloc; ++ struct cfg80211_mbssid_elems *mbssid_ies; + s8 ftm_responder; + + size_t head_len, tail_len; +@@ -1194,6 +1226,7 @@ enum cfg80211_ap_settings_flags { + * @he_oper: HE operation IE (or %NULL if HE isn't enabled) + * @fils_discovery: FILS discovery transmission parameters + * @unsol_bcast_probe_resp: Unsolicited broadcast probe response parameters ++ * @mbssid_config: AP settings for multiple bssid + */ + struct cfg80211_ap_settings { + struct cfg80211_chan_def chandef; +@@ -1226,6 +1259,7 @@ struct cfg80211_ap_settings { + struct cfg80211_he_bss_color he_bss_color; + struct cfg80211_fils_discovery fils_discovery; + struct cfg80211_unsol_bcast_probe_resp unsol_bcast_probe_resp; ++ struct cfg80211_mbssid_config mbssid_config; + }; + + /** +@@ -4986,6 +5020,13 @@ struct wiphy_iftype_akm_suites { + * %NL80211_TID_CONFIG_ATTR_RETRY_LONG attributes + * @sar_capa: SAR control capabilities + * @rfkill: a pointer to the rfkill structure ++ * ++ * @mbssid_max_interfaces: maximum number of interfaces supported by the driver ++ * in a multiple BSSID set. This field must be set to a non-zero value ++ * by the driver to advertise MBSSID support. ++ * @mbssid_max_ema_profile_periodicity: maximum profile periodicity supported by ++ * the driver. Setting this field to a non-zero value indicates that the ++ * driver supports enhanced multi-BSSID advertisements (EMA AP). + */ + struct wiphy { + struct mutex mtx; +@@ -5133,6 +5174,9 @@ struct wiphy { + + struct rfkill *rfkill; + ++ u8 mbssid_max_interfaces; ++ u8 ema_max_profile_periodicity; ++ + char priv[] __aligned(NETDEV_ALIGN); + }; + +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -337,7 +337,10 @@ + * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes + * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from + * userspace to request deletion of a virtual interface, then requires +- * attribute %NL80211_ATTR_IFINDEX. ++ * attribute %NL80211_ATTR_IFINDEX. If multiple BSSID advertisements are ++ * enabled using %NL80211_ATTR_MBSSID_CONFIG, %NL80211_ATTR_MBSSID_ELEMS, ++ * and if this command is used for the transmitting interface, then all ++ * the non-transmitting interfaces are deleted as well. + * + * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified + * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC. +@@ -2593,6 +2596,18 @@ 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_MBSSID_CONFIG: Nested attribute for multiple BSSID ++ * advertisements (MBSSID) parameters in AP mode. ++ * Kernel uses this attribute to indicate the driver's support for MBSSID ++ * and enhanced multi-BSSID advertisements (EMA AP) to the userspace. ++ * Userspace should use this attribute to configure per interface MBSSID ++ * parameters. ++ * See &enum nl80211_mbssid_config_attributes for details. ++ * ++ * @NL80211_ATTR_MBSSID_ELEMS: Nested parameter to pass multiple BSSID elements. ++ * Mandatory parameter for the transmitting interface to enable MBSSID. ++ * Optional for the non-transmitting interfaces. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3096,6 +3111,9 @@ enum nl80211_attrs { + NL80211_ATTR_COLOR_CHANGE_COLOR, + NL80211_ATTR_COLOR_CHANGE_ELEMS, + ++ NL80211_ATTR_MBSSID_CONFIG, ++ NL80211_ATTR_MBSSID_ELEMS, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -7349,4 +7367,60 @@ enum nl80211_sar_specs_attrs { + NL80211_SAR_ATTR_SPECS_MAX = __NL80211_SAR_ATTR_SPECS_LAST - 1, + }; + ++/** ++ * enum nl80211_mbssid_config_attributes - multiple BSSID (MBSSID) and enhanced ++ * multi-BSSID advertisements (EMA) in AP mode. ++ * Kernel uses some of these attributes to advertise driver's support for ++ * MBSSID and EMA. ++ * Remaining attributes should be used by the userspace to configure the ++ * features. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_INVALID: Invalid ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES: Used by the kernel to advertise ++ * the maximum number of MBSSID interfaces supported by the driver. ++ * Driver should indicate MBSSID support by setting ++ * wiphy->mbssid_max_interfaces to a value more than or equal to 2. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY: Used by the kernel ++ * to advertise the maximum profile periodicity supported by the driver ++ * if EMA is enabled. Driver should indicate EMA support to the userspace ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to ++ * a non-zero value. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_INDEX: Mandatory parameter to pass the index of ++ * this BSS (u8) in the multiple BSSID set. ++ * Value must be set to 0 for the transmitting interface and non-zero for ++ * all non-transmitting interfaces. The userspace will be responsible ++ * for using unique indices for the interfaces. ++ * Range: 0 to wiphy->mbssid_max_interfaces-1. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX: Mandatory parameter for ++ * a non-transmitted profile which provides the interface index (u32) of ++ * the transmitted profile. The value must match one of the interface ++ * indices advertised by the kernel. Optional if the interface being set up ++ * is the transmitting one, however, if provided then the value must match ++ * the interface index of the same. ++ * ++ * @NL80211_MBSSID_CONFIG_ATTR_EMA: Flag used to enable EMA AP feature. ++ * Setting this flag is permitted only if the driver advertises EMA support ++ * by setting wiphy->mbssid_max_ema_profile_periodicity to non-zero. ++ * ++ * @__NL80211_MBSSID_CONFIG_ATTR_LAST: Internal ++ * @NL80211_MBSSID_CONFIG_ATTR_MAX: highest attribute ++ */ ++enum nl80211_mbssid_config_attributes { ++ __NL80211_MBSSID_CONFIG_ATTR_INVALID, ++ ++ NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ NL80211_MBSSID_CONFIG_ATTR_INDEX, ++ NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX, ++ NL80211_MBSSID_CONFIG_ATTR_EMA, ++ ++ /* keep last */ ++ __NL80211_MBSSID_CONFIG_ATTR_LAST, ++ NL80211_MBSSID_CONFIG_ATTR_MAX = __NL80211_MBSSID_CONFIG_ATTR_LAST - 1, ++}; ++ + #endif /* __LINUX_NL80211_H */ +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -442,6 +442,16 @@ sar_policy[NL80211_SAR_ATTR_MAX + 1] = { + [NL80211_SAR_ATTR_SPECS] = NLA_POLICY_NESTED_ARRAY(sar_specs_policy), + }; + ++static const struct nla_policy ++nl80211_mbssid_config_policy[NL80211_MBSSID_CONFIG_ATTR_MAX + 1] = { ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES] = NLA_POLICY_MIN(NLA_U8, 2), ++ [NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY] = ++ NLA_POLICY_MIN(NLA_U8, 1), ++ [NL80211_MBSSID_CONFIG_ATTR_INDEX] = { .type = NLA_U8 }, ++ [NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX] = { .type = NLA_U32 }, ++ [NL80211_MBSSID_CONFIG_ATTR_EMA] = { .type = NLA_FLAG }, ++}; ++ + 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 }, +@@ -788,6 +798,9 @@ 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_MBSSID_CONFIG] = ++ NLA_POLICY_NESTED(nl80211_mbssid_config_policy), ++ [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, + }; + + /* policy for the key attributes */ +@@ -2236,6 +2249,35 @@ fail: + return -ENOBUFS; + } + ++static int nl80211_put_mbssid_support(struct wiphy *wiphy, struct sk_buff *msg) ++{ ++ struct nlattr *config; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return 0; ++ ++ config = nla_nest_start(msg, NL80211_ATTR_MBSSID_CONFIG); ++ if (!config) ++ return -ENOBUFS; ++ ++ if (nla_put_u8(msg, NL80211_MBSSID_CONFIG_ATTR_MAX_INTERFACES, ++ wiphy->mbssid_max_interfaces)) ++ goto fail; ++ ++ if (wiphy->ema_max_profile_periodicity && ++ nla_put_u8(msg, ++ NL80211_MBSSID_CONFIG_ATTR_MAX_EMA_PROFILE_PERIODICITY, ++ wiphy->ema_max_profile_periodicity)) ++ goto fail; ++ ++ nla_nest_end(msg, config); ++ return 0; ++ ++fail: ++ nla_nest_cancel(msg, config); ++ return -ENOBUFS; ++} ++ + struct nl80211_dump_wiphy_state { + s64 filter_wiphy; + long start; +@@ -2821,6 +2863,9 @@ static int nl80211_send_wiphy(struct cfg + if (nl80211_put_sar_specs(rdev, msg)) + goto nla_put_failure; + ++ if (nl80211_put_mbssid_support(&rdev->wiphy, msg)) ++ goto nla_put_failure; ++ + /* done */ + state->split_start = 0; + break; +@@ -5020,6 +5065,96 @@ static int validate_beacon_tx_rate(struc + return 0; + } + ++static int nl80211_parse_mbssid_config(struct wiphy *wiphy, ++ struct net_device *dev, ++ struct nlattr *attrs, ++ struct cfg80211_mbssid_config *config, ++ u8 num_elems) ++{ ++ struct nlattr *tb[NL80211_MBSSID_CONFIG_ATTR_MAX + 1]; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return -EOPNOTSUPP; ++ ++ if (nla_parse_nested(tb, NL80211_MBSSID_CONFIG_ATTR_MAX, attrs, NULL, ++ NULL) || ++ !tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]) ++ return -EINVAL; ++ ++ config->ema = nla_get_flag(tb[NL80211_MBSSID_CONFIG_ATTR_EMA]); ++ if (config->ema) { ++ if (!wiphy->ema_max_profile_periodicity) ++ return -EOPNOTSUPP; ++ ++ if (num_elems > wiphy->ema_max_profile_periodicity) ++ return -EINVAL; ++ } ++ ++ config->index = nla_get_u8(tb[NL80211_MBSSID_CONFIG_ATTR_INDEX]); ++ if (config->index >= wiphy->mbssid_max_interfaces || ++ (!config->index && !num_elems)) ++ return -EINVAL; ++ ++ if (tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]) { ++ u32 tx_ifindex = ++ nla_get_u32(tb[NL80211_MBSSID_CONFIG_ATTR_TX_IFINDEX]); ++ ++ if ((!config->index && tx_ifindex != dev->ifindex) || ++ (config->index && tx_ifindex == dev->ifindex)) ++ return -EINVAL; ++ ++ if (tx_ifindex != dev->ifindex) { ++ struct net_device *tx_netdev = ++ dev_get_by_index(wiphy_net(wiphy), tx_ifindex); ++ ++ if (!tx_netdev || !tx_netdev->ieee80211_ptr || ++ tx_netdev->ieee80211_ptr->wiphy != wiphy || ++ tx_netdev->ieee80211_ptr->iftype != ++ NL80211_IFTYPE_AP) { ++ dev_put(tx_netdev); ++ return -EINVAL; ++ } ++ ++ config->tx_wdev = tx_netdev->ieee80211_ptr; ++ } else { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } ++ } else if (!config->index) { ++ config->tx_wdev = dev->ieee80211_ptr; ++ } else { ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static struct cfg80211_mbssid_elems * ++nl80211_parse_mbssid_elems(struct wiphy *wiphy, struct nlattr *attrs) ++{ ++ struct nlattr *nl_elems; ++ struct cfg80211_mbssid_elems *elems; ++ int rem_elems; ++ u8 i = 0, num_elems = 0; ++ ++ if (!wiphy->mbssid_max_interfaces) ++ return ERR_PTR(-EINVAL); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) ++ num_elems++; ++ ++ elems = kzalloc(struct_size(elems, elem, num_elems), GFP_KERNEL); ++ if (!elems) ++ return ERR_PTR(-ENOMEM); ++ ++ nla_for_each_nested(nl_elems, attrs, rem_elems) { ++ elems->elem[i].data = nla_data(nl_elems); ++ elems->elem[i].len = nla_len(nl_elems); ++ i++; ++ } ++ elems->cnt = num_elems; ++ return elems; ++} ++ + static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev, + struct nlattr *attrs[], + struct cfg80211_beacon_data *bcn) +@@ -5100,6 +5235,17 @@ static int nl80211_parse_beacon(struct c + bcn->ftm_responder = -1; + } + ++ if (attrs[NL80211_ATTR_MBSSID_ELEMS]) { ++ struct cfg80211_mbssid_elems *mbssid = ++ nl80211_parse_mbssid_elems(&rdev->wiphy, ++ attrs[NL80211_ATTR_MBSSID_ELEMS]); ++ ++ if (IS_ERR(mbssid)) ++ return PTR_ERR(mbssid); ++ ++ bcn->mbssid_ies = mbssid; ++ } ++ + return 0; + } + +@@ -5556,6 +5702,17 @@ static int nl80211_start_ap(struct sk_bu + goto out; + } + ++ if (info->attrs[NL80211_ATTR_MBSSID_CONFIG]) { ++ err = nl80211_parse_mbssid_config(&rdev->wiphy, dev, ++ info->attrs[NL80211_ATTR_MBSSID_CONFIG], ++ ¶ms.mbssid_config, ++ params.beacon.mbssid_ies ? ++ params.beacon.mbssid_ies->cnt : ++ 0); ++ if (err) ++ goto out; ++ } ++ + nl80211_calculate_ap_params(¶ms); + + if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT]) +@@ -5577,6 +5734,11 @@ static int nl80211_start_ap(struct sk_bu + + out: + kfree(params.acl); ++ kfree(params.beacon.mbssid_ies); ++ if (params.mbssid_config.tx_wdev && ++ params.mbssid_config.tx_wdev->netdev && ++ params.mbssid_config.tx_wdev->netdev != dev) ++ dev_put(params.mbssid_config.tx_wdev->netdev); + + return err; + } +@@ -5601,12 +5763,14 @@ static int nl80211_set_beacon(struct sk_ + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms); + if (err) +- return err; ++ goto out; + + wdev_lock(wdev); + err = rdev_change_beacon(rdev, dev, ¶ms); + wdev_unlock(wdev); + ++out: ++ kfree(params.mbssid_ies); + return err; + } + +@@ -9283,12 +9447,14 @@ static int nl80211_channel_switch(struct + + err = nl80211_parse_beacon(rdev, info->attrs, ¶ms.beacon_after); + if (err) +- return err; ++ goto free; + + csa_attrs = kcalloc(NL80211_ATTR_MAX + 1, sizeof(*csa_attrs), + GFP_KERNEL); +- if (!csa_attrs) +- return -ENOMEM; ++ if (!csa_attrs) { ++ err = -ENOMEM; ++ goto free; ++ } + + err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX, + info->attrs[NL80211_ATTR_CSA_IES], +@@ -9407,6 +9573,8 @@ skip_beacons: + wdev_unlock(wdev); + + free: ++ kfree(params.beacon_after.mbssid_ies); ++ kfree(params.beacon_csa.mbssid_ies); + kfree(csa_attrs); + return err; + } +@@ -14959,6 +15127,8 @@ static int nl80211_color_change(struct s + wdev_unlock(wdev); + + out: ++ kfree(params.beacon_next.mbssid_ies); ++ kfree(params.beacon_color_change.mbssid_ies); + kfree(tb); + return err; + } diff --git a/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch b/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch deleted file mode 100644 index 2038ee69db..0000000000 --- a/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch +++ /dev/null @@ -1,378 +0,0 @@ -From: Lorenzo Bianconi -Date: Sat, 23 Oct 2021 11:10:50 +0200 -Subject: [PATCH] cfg80211: implement APIs for dedicated radar detection HW - -If a dedicated (off-channel) radar detection hardware (chain) -is available in the hardware/driver, allow this to be used by -calling the NL80211_CMD_RADAR_DETECT command with a new flag -attribute requesting off-channel radar detection is used. - -Offchannel CAC (channel availability check) avoids the CAC -downtime when switching to a radar channel or when turning on -the AP. - -Drivers advertise support for this using the new feature flag -NL80211_EXT_FEATURE_RADAR_OFFCHAN. - -Tested-by: Evelyn Tsai -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/7468e291ef5d05d692c1738d25b8f778d8ea5c3f.1634979655.git.lorenzo@kernel.org -Link: https://lore.kernel.org/r/1e60e60fef00e14401adae81c3d49f3e5f307537.1634979655.git.lorenzo@kernel.org -Link: https://lore.kernel.org/r/85fa50f57fc3adb2934c8d9ca0be30394de6b7e8.1634979655.git.lorenzo@kernel.org -Link: https://lore.kernel.org/r/4b6c08671ad59aae0ac46fc94c02f31b1610eb72.1634979655.git.lorenzo@kernel.org -Link: https://lore.kernel.org/r/241849ccaf2c228873c6f8495bf87b19159ba458.1634979655.git.lorenzo@kernel.org -[remove offchan_mutex, fix cfg80211_stop_offchan_radar_detection(), - remove gfp_t argument, fix documentation, fix tracing] -Signed-off-by: Johannes Berg ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -4057,6 +4057,15 @@ struct mgmt_frame_regs { - * @set_sar_specs: Update the SAR (TX power) settings. - * - * @color_change: Initiate a color change. -+ * -+ * @set_radar_offchan: Configure dedicated offchannel chain available for -+ * radar/CAC detection on some hw. This chain can't be used to transmit -+ * or receive frames and it is bounded to a running wdev. -+ * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * switching to a different channel during CAC detection on the selected -+ * radar channel. -+ * The caller is expected to set chandef pointer to NULL in order to -+ * disable offchannel CAC/radar detection. - */ - struct cfg80211_ops { - int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); -@@ -4387,6 +4396,8 @@ struct cfg80211_ops { - int (*color_change)(struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_color_change_settings *params); -+ int (*set_radar_offchan)(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef); - }; - - /* -@@ -7608,6 +7619,20 @@ void cfg80211_cac_event(struct net_devic - const struct cfg80211_chan_def *chandef, - enum nl80211_radar_event event, gfp_t gfp); - -+/** -+ * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event -+ * @wiphy: the wiphy -+ * @chandef: chandef for the current channel -+ * @event: type of event -+ * -+ * This function is called when a Channel Availability Check (CAC) is finished, -+ * started or aborted by a offchannel dedicated chain. -+ * -+ * Note that this acquires the wiphy lock. -+ */ -+void cfg80211_offchan_cac_event(struct wiphy *wiphy, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event); - - /** - * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -2608,6 +2608,13 @@ enum nl80211_commands { - * Mandatory parameter for the transmitting interface to enable MBSSID. - * Optional for the non-transmitting interfaces. - * -+ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for -+ * radar/CAC detection on some hw. This chain can't be used to transmit -+ * or receive frames and it is bounded to a running wdev. -+ * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * switching on a different channel during CAC detection on the selected -+ * radar channel. -+ * - * @NUM_NL80211_ATTR: total number of nl80211_attrs available - * @NL80211_ATTR_MAX: highest attribute number currently defined - * @__NL80211_ATTR_AFTER_LAST: internal use -@@ -3114,6 +3121,8 @@ enum nl80211_attrs { - NL80211_ATTR_MBSSID_CONFIG, - NL80211_ATTR_MBSSID_ELEMS, - -+ NL80211_ATTR_RADAR_OFFCHAN, -+ - /* add attributes here, update the policy in nl80211.c */ - - __NL80211_ATTR_AFTER_LAST, -@@ -6013,6 +6022,9 @@ enum nl80211_feature_flags { - * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision - * detection and change announcemnts. - * -+ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC -+ * detection. -+ * - * @NUM_NL80211_EXT_FEATURES: number of extended features. - * @MAX_NL80211_EXT_FEATURES: highest extended feature index. - */ -@@ -6078,6 +6090,7 @@ enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_SECURE_RTT, - NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, - NL80211_EXT_FEATURE_BSS_COLOR, -+ NL80211_EXT_FEATURE_RADAR_OFFCHAN, - - /* add new features before the definition below */ - NUM_NL80211_EXT_FEATURES, ---- a/net/wireless/core.c -+++ b/net/wireless/core.c -@@ -543,6 +543,7 @@ use_default_name: - INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); - INIT_WORK(&rdev->conn_work, cfg80211_conn_work); - INIT_WORK(&rdev->event_work, cfg80211_event_work); -+ INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); - - init_waitqueue_head(&rdev->dev_wait); - -@@ -1205,6 +1206,8 @@ void __cfg80211_leave(struct cfg80211_re - - cfg80211_pmsr_wdev_down(wdev); - -+ cfg80211_stop_offchan_radar_detection(wdev); -+ - switch (wdev->iftype) { - case NL80211_IFTYPE_ADHOC: - __cfg80211_leave_ibss(rdev, dev, true); ---- a/net/wireless/core.h -+++ b/net/wireless/core.h -@@ -84,6 +84,10 @@ struct cfg80211_registered_device { - - struct delayed_work dfs_update_channels_wk; - -+ struct wireless_dev *offchan_radar_wdev; -+ struct cfg80211_chan_def offchan_radar_chandef; -+ struct delayed_work offchan_cac_work; -+ - /* netlink port which started critical protocol (0 means not started) */ - u32 crit_proto_nlportid; - -@@ -491,6 +495,15 @@ cfg80211_chandef_dfs_cac_time(struct wip - - void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); - -+int -+cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ struct cfg80211_chan_def *chandef); -+ -+void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); -+ -+void cfg80211_offchan_cac_work(struct work_struct *work); -+ - bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan); - ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -970,3 +970,116 @@ void cfg80211_cac_event(struct net_devic - nl80211_radar_notify(rdev, chandef, event, netdev, gfp); - } - EXPORT_SYMBOL(cfg80211_cac_event); -+ -+void cfg80211_offchan_cac_work(struct work_struct *work) -+{ -+ struct delayed_work *delayed_work = to_delayed_work(work); -+ struct cfg80211_registered_device *rdev; -+ -+ rdev = container_of(delayed_work, struct cfg80211_registered_device, -+ offchan_cac_work); -+ cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, -+ NL80211_RADAR_CAC_FINISHED); -+} -+ -+static void -+__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event) -+{ -+ struct wiphy *wiphy = &rdev->wiphy; -+ struct net_device *netdev; -+ -+ lockdep_assert_wiphy(&rdev->wiphy); -+ -+ if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) -+ return; -+ -+ switch (event) { -+ case NL80211_RADAR_CAC_FINISHED: -+ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); -+ memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); -+ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); -+ cfg80211_sched_dfs_chan_update(rdev); -+ wdev = rdev->offchan_radar_wdev; -+ rdev->offchan_radar_wdev = NULL; -+ break; -+ case NL80211_RADAR_CAC_ABORTED: -+ cancel_delayed_work(&rdev->offchan_cac_work); -+ wdev = rdev->offchan_radar_wdev; -+ rdev->offchan_radar_wdev = NULL; -+ break; -+ case NL80211_RADAR_CAC_STARTED: -+ WARN_ON(!wdev); -+ rdev->offchan_radar_wdev = wdev; -+ break; -+ default: -+ return; -+ } -+ -+ netdev = wdev ? wdev->netdev : NULL; -+ nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); -+} -+ -+void cfg80211_offchan_cac_event(struct wiphy *wiphy, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event) -+{ -+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); -+ -+ wiphy_lock(wiphy); -+ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); -+ wiphy_unlock(wiphy); -+} -+EXPORT_SYMBOL(cfg80211_offchan_cac_event); -+ -+int -+cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ struct cfg80211_chan_def *chandef) -+{ -+ unsigned int cac_time_ms; -+ int err; -+ -+ lockdep_assert_wiphy(&rdev->wiphy); -+ -+ if (!wiphy_ext_feature_isset(&rdev->wiphy, -+ NL80211_EXT_FEATURE_RADAR_OFFCHAN)) -+ return -EOPNOTSUPP; -+ -+ if (rdev->offchan_radar_wdev) -+ return -EBUSY; -+ -+ err = rdev_set_radar_offchan(rdev, chandef); -+ if (err) -+ return err; -+ -+ cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef); -+ if (!cac_time_ms) -+ cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; -+ -+ rdev->offchan_radar_chandef = *chandef; -+ __cfg80211_offchan_cac_event(rdev, wdev, chandef, -+ NL80211_RADAR_CAC_STARTED); -+ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, -+ msecs_to_jiffies(cac_time_ms)); -+ -+ return 0; -+} -+ -+void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) -+{ -+ struct wiphy *wiphy = wdev->wiphy; -+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); -+ -+ lockdep_assert_wiphy(wiphy); -+ -+ if (wdev != rdev->offchan_radar_wdev) -+ return; -+ -+ rdev_set_radar_offchan(rdev, NULL); -+ -+ __cfg80211_offchan_cac_event(rdev, NULL, NULL, -+ NL80211_RADAR_CAC_ABORTED); -+} ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -801,6 +801,7 @@ static const struct nla_policy nl80211_p - [NL80211_ATTR_MBSSID_CONFIG] = - NLA_POLICY_NESTED(nl80211_mbssid_config_policy), - [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, -+ [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, - }; - - /* policy for the key attributes */ -@@ -9287,12 +9288,6 @@ static int nl80211_start_radar_detection - if (err) - return err; - -- if (netif_carrier_ok(dev)) -- return -EBUSY; -- -- if (wdev->cac_started) -- return -EBUSY; -- - err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); - if (err < 0) - return err; -@@ -9303,6 +9298,16 @@ static int nl80211_start_radar_detection - if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) - return -EINVAL; - -+ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) -+ return cfg80211_start_offchan_radar_detection(rdev, wdev, -+ &chandef); -+ -+ if (netif_carrier_ok(dev)) -+ return -EBUSY; -+ -+ if (wdev->cac_started) -+ return -EBUSY; -+ - /* CAC start is offloaded to HW and can't be started manually */ - if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) - return -EOPNOTSUPP; ---- a/net/wireless/rdev-ops.h -+++ b/net/wireless/rdev-ops.h -@@ -1381,4 +1381,21 @@ static inline int rdev_color_change(stru - return ret; - } - -+static inline int -+rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, -+ struct cfg80211_chan_def *chandef) -+{ -+ struct wiphy *wiphy = &rdev->wiphy; -+ int ret; -+ -+ if (!rdev->ops->set_radar_offchan) -+ return -EOPNOTSUPP; -+ -+ trace_rdev_set_radar_offchan(wiphy, chandef); -+ ret = rdev->ops->set_radar_offchan(wiphy, chandef); -+ trace_rdev_return_int(wiphy, ret); -+ -+ return ret; -+} -+ - #endif /* __CFG80211_RDEV_OPS */ ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -3643,6 +3643,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, - __entry->color_bitmap) - ); - -+TRACE_EVENT(rdev_set_radar_offchan, -+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), -+ -+ TP_ARGS(wiphy, chandef), -+ -+ TP_STRUCT__entry( -+ WIPHY_ENTRY -+ CHAN_DEF_ENTRY -+ ), -+ -+ TP_fast_assign( -+ WIPHY_ASSIGN; -+ CHAN_DEF_ASSIGN(chandef) -+ ), -+ -+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, -+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG) -+); -+ - #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ - - #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/314-v5.17-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch b/package/kernel/mac80211/patches/subsys/314-v5.17-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch new file mode 100644 index 0000000000..2038ee69db --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/314-v5.17-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch @@ -0,0 +1,378 @@ +From: Lorenzo Bianconi +Date: Sat, 23 Oct 2021 11:10:50 +0200 +Subject: [PATCH] cfg80211: implement APIs for dedicated radar detection HW + +If a dedicated (off-channel) radar detection hardware (chain) +is available in the hardware/driver, allow this to be used by +calling the NL80211_CMD_RADAR_DETECT command with a new flag +attribute requesting off-channel radar detection is used. + +Offchannel CAC (channel availability check) avoids the CAC +downtime when switching to a radar channel or when turning on +the AP. + +Drivers advertise support for this using the new feature flag +NL80211_EXT_FEATURE_RADAR_OFFCHAN. + +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/7468e291ef5d05d692c1738d25b8f778d8ea5c3f.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/1e60e60fef00e14401adae81c3d49f3e5f307537.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/85fa50f57fc3adb2934c8d9ca0be30394de6b7e8.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/4b6c08671ad59aae0ac46fc94c02f31b1610eb72.1634979655.git.lorenzo@kernel.org +Link: https://lore.kernel.org/r/241849ccaf2c228873c6f8495bf87b19159ba458.1634979655.git.lorenzo@kernel.org +[remove offchan_mutex, fix cfg80211_stop_offchan_radar_detection(), + remove gfp_t argument, fix documentation, fix tracing] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -4057,6 +4057,15 @@ struct mgmt_frame_regs { + * @set_sar_specs: Update the SAR (TX power) settings. + * + * @color_change: Initiate a color change. ++ * ++ * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching to a different channel during CAC detection on the selected ++ * radar channel. ++ * The caller is expected to set chandef pointer to NULL in order to ++ * disable offchannel CAC/radar detection. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4387,6 +4396,8 @@ struct cfg80211_ops { + int (*color_change)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_color_change_settings *params); ++ int (*set_radar_offchan)(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef); + }; + + /* +@@ -7608,6 +7619,20 @@ void cfg80211_cac_event(struct net_devic + const struct cfg80211_chan_def *chandef, + enum nl80211_radar_event event, gfp_t gfp); + ++/** ++ * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event ++ * @wiphy: the wiphy ++ * @chandef: chandef for the current channel ++ * @event: type of event ++ * ++ * This function is called when a Channel Availability Check (CAC) is finished, ++ * started or aborted by a offchannel dedicated chain. ++ * ++ * Note that this acquires the wiphy lock. ++ */ ++void cfg80211_offchan_cac_event(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2608,6 +2608,13 @@ enum nl80211_commands { + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * ++ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching on a different channel during CAC detection on the selected ++ * radar channel. ++ * + * @NUM_NL80211_ATTR: total number of nl80211_attrs available + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use +@@ -3114,6 +3121,8 @@ enum nl80211_attrs { + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + ++ NL80211_ATTR_RADAR_OFFCHAN, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -6013,6 +6022,9 @@ enum nl80211_feature_flags { + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * ++ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC ++ * detection. ++ * + * @NUM_NL80211_EXT_FEATURES: number of extended features. + * @MAX_NL80211_EXT_FEATURES: highest extended feature index. + */ +@@ -6078,6 +6090,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,6 +543,7 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); ++ INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1205,6 +1206,8 @@ void __cfg80211_leave(struct cfg80211_re + + cfg80211_pmsr_wdev_down(wdev); + ++ cfg80211_stop_offchan_radar_detection(wdev); ++ + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + __cfg80211_leave_ibss(rdev, dev, true); +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -84,6 +84,10 @@ struct cfg80211_registered_device { + + struct delayed_work dfs_update_channels_wk; + ++ struct wireless_dev *offchan_radar_wdev; ++ struct cfg80211_chan_def offchan_radar_chandef; ++ struct delayed_work offchan_cac_work; ++ + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; + +@@ -491,6 +495,15 @@ cfg80211_chandef_dfs_cac_time(struct wip + + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + ++int ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef); ++ ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); ++ ++void cfg80211_offchan_cac_work(struct work_struct *work); ++ + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -970,3 +970,116 @@ void cfg80211_cac_event(struct net_devic + nl80211_radar_notify(rdev, chandef, event, netdev, gfp); + } + EXPORT_SYMBOL(cfg80211_cac_event); ++ ++void cfg80211_offchan_cac_work(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(delayed_work, struct cfg80211_registered_device, ++ offchan_cac_work); ++ cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); ++} ++ ++static void ++__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ struct wiphy *wiphy = &rdev->wiphy; ++ struct net_device *netdev; ++ ++ lockdep_assert_wiphy(&rdev->wiphy); ++ ++ if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) ++ return; ++ ++ switch (event) { ++ case NL80211_RADAR_CAC_FINISHED: ++ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE); ++ memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); ++ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); ++ cfg80211_sched_dfs_chan_update(rdev); ++ wdev = rdev->offchan_radar_wdev; ++ rdev->offchan_radar_wdev = NULL; ++ break; ++ case NL80211_RADAR_CAC_ABORTED: ++ cancel_delayed_work(&rdev->offchan_cac_work); ++ wdev = rdev->offchan_radar_wdev; ++ rdev->offchan_radar_wdev = NULL; ++ break; ++ case NL80211_RADAR_CAC_STARTED: ++ WARN_ON(!wdev); ++ rdev->offchan_radar_wdev = wdev; ++ break; ++ default: ++ return; ++ } ++ ++ netdev = wdev ? wdev->netdev : NULL; ++ nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); ++} ++ ++void cfg80211_offchan_cac_event(struct wiphy *wiphy, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ wiphy_lock(wiphy); ++ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ wiphy_unlock(wiphy); ++} ++EXPORT_SYMBOL(cfg80211_offchan_cac_event); ++ ++int ++cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef) ++{ ++ unsigned int cac_time_ms; ++ int err; ++ ++ lockdep_assert_wiphy(&rdev->wiphy); ++ ++ if (!wiphy_ext_feature_isset(&rdev->wiphy, ++ NL80211_EXT_FEATURE_RADAR_OFFCHAN)) ++ return -EOPNOTSUPP; ++ ++ if (rdev->offchan_radar_wdev) ++ return -EBUSY; ++ ++ err = rdev_set_radar_offchan(rdev, chandef); ++ if (err) ++ return err; ++ ++ cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, chandef); ++ if (!cac_time_ms) ++ cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; ++ ++ rdev->offchan_radar_chandef = *chandef; ++ __cfg80211_offchan_cac_event(rdev, wdev, chandef, ++ NL80211_RADAR_CAC_STARTED); ++ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, ++ msecs_to_jiffies(cac_time_ms)); ++ ++ return 0; ++} ++ ++void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) ++{ ++ struct wiphy *wiphy = wdev->wiphy; ++ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); ++ ++ lockdep_assert_wiphy(wiphy); ++ ++ if (wdev != rdev->offchan_radar_wdev) ++ return; ++ ++ rdev_set_radar_offchan(rdev, NULL); ++ ++ __cfg80211_offchan_cac_event(rdev, NULL, NULL, ++ NL80211_RADAR_CAC_ABORTED); ++} +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -801,6 +801,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_MBSSID_CONFIG] = + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, ++ [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, + }; + + /* policy for the key attributes */ +@@ -9287,12 +9288,6 @@ static int nl80211_start_radar_detection + if (err) + return err; + +- if (netif_carrier_ok(dev)) +- return -EBUSY; +- +- if (wdev->cac_started) +- return -EBUSY; +- + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); + if (err < 0) + return err; +@@ -9303,6 +9298,16 @@ static int nl80211_start_radar_detection + if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) + return -EINVAL; + ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) ++ return cfg80211_start_offchan_radar_detection(rdev, wdev, ++ &chandef); ++ ++ if (netif_carrier_ok(dev)) ++ return -EBUSY; ++ ++ if (wdev->cac_started) ++ return -EBUSY; ++ + /* CAC start is offloaded to HW and can't be started manually */ + if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) + return -EOPNOTSUPP; +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1381,4 +1381,21 @@ static inline int rdev_color_change(stru + return ret; + } + ++static inline int ++rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct wiphy *wiphy = &rdev->wiphy; ++ int ret; ++ ++ if (!rdev->ops->set_radar_offchan) ++ return -EOPNOTSUPP; ++ ++ trace_rdev_set_radar_offchan(wiphy, chandef); ++ ret = rdev->ops->set_radar_offchan(wiphy, chandef); ++ trace_rdev_return_int(wiphy, ret); ++ ++ return ret; ++} ++ + #endif /* __CFG80211_RDEV_OPS */ +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3643,6 +3643,25 @@ TRACE_EVENT(cfg80211_bss_color_notify, + __entry->color_bitmap) + ); + ++TRACE_EVENT(rdev_set_radar_offchan, ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), ++ ++ TP_ARGS(wiphy, chandef), ++ ++ TP_STRUCT__entry( ++ WIPHY_ENTRY ++ CHAN_DEF_ENTRY ++ ), ++ ++ TP_fast_assign( ++ WIPHY_ASSIGN; ++ CHAN_DEF_ASSIGN(chandef) ++ ), ++ ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ++); ++ + #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch b/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch deleted file mode 100644 index b1a1d2c894..0000000000 --- a/package/kernel/mac80211/patches/subsys/315-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch +++ /dev/null @@ -1,183 +0,0 @@ -From: Lorenzo Bianconi -Date: Wed, 27 Oct 2021 11:03:42 +0200 -Subject: [PATCH] cfg80211: move offchan_cac_event to a dedicated work - -In order to make cfg80211_offchan_cac_abort() (renamed from -cfg80211_offchan_cac_event) callable in other contexts and -without so much locking restrictions, make it trigger a new -work instead of operating directly. - -Do some other renames while at it to clarify. - -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/6145c3d0f30400a568023f67981981d24c7c6133.1635325205.git.lorenzo@kernel.org -[rewrite commit log] -Signed-off-by: Johannes Berg ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -7620,19 +7620,13 @@ void cfg80211_cac_event(struct net_devic - enum nl80211_radar_event event, gfp_t gfp); - - /** -- * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event -+ * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event - * @wiphy: the wiphy -- * @chandef: chandef for the current channel -- * @event: type of event - * -- * This function is called when a Channel Availability Check (CAC) is finished, -- * started or aborted by a offchannel dedicated chain. -- * -- * Note that this acquires the wiphy lock. -+ * This function is called by the driver when a Channel Availability Check -+ * (CAC) is aborted by a offchannel dedicated chain. - */ --void cfg80211_offchan_cac_event(struct wiphy *wiphy, -- const struct cfg80211_chan_def *chandef, -- enum nl80211_radar_event event); -+void cfg80211_offchan_cac_abort(struct wiphy *wiphy); - - /** - * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying ---- a/net/wireless/core.c -+++ b/net/wireless/core.c -@@ -543,7 +543,9 @@ use_default_name: - INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); - INIT_WORK(&rdev->conn_work, cfg80211_conn_work); - INIT_WORK(&rdev->event_work, cfg80211_event_work); -- INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); -+ INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); -+ INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, -+ cfg80211_offchan_cac_done_wk); - - init_waitqueue_head(&rdev->dev_wait); - -@@ -1053,11 +1055,13 @@ void wiphy_unregister(struct wiphy *wiph - cancel_work_sync(&rdev->conn_work); - flush_work(&rdev->event_work); - cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); -+ cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); - flush_work(&rdev->destroy_work); - flush_work(&rdev->sched_scan_stop_wk); - flush_work(&rdev->propagate_radar_detect_wk); - flush_work(&rdev->propagate_cac_done_wk); - flush_work(&rdev->mgmt_registrations_update_wk); -+ flush_work(&rdev->offchan_cac_abort_wk); - - #ifdef CONFIG_PM - if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) ---- a/net/wireless/core.h -+++ b/net/wireless/core.h -@@ -86,7 +86,8 @@ struct cfg80211_registered_device { - - struct wireless_dev *offchan_radar_wdev; - struct cfg80211_chan_def offchan_radar_chandef; -- struct delayed_work offchan_cac_work; -+ struct delayed_work offchan_cac_done_wk; -+ struct work_struct offchan_cac_abort_wk; - - /* netlink port which started critical protocol (0 means not started) */ - u32 crit_proto_nlportid; -@@ -502,7 +503,9 @@ cfg80211_start_offchan_radar_detection(s - - void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); - --void cfg80211_offchan_cac_work(struct work_struct *work); -+void cfg80211_offchan_cac_done_wk(struct work_struct *work); -+ -+void cfg80211_offchan_cac_abort_wk(struct work_struct *work); - - bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan); ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -971,17 +971,6 @@ void cfg80211_cac_event(struct net_devic - } - EXPORT_SYMBOL(cfg80211_cac_event); - --void cfg80211_offchan_cac_work(struct work_struct *work) --{ -- struct delayed_work *delayed_work = to_delayed_work(work); -- struct cfg80211_registered_device *rdev; -- -- rdev = container_of(delayed_work, struct cfg80211_registered_device, -- offchan_cac_work); -- cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, -- NL80211_RADAR_CAC_FINISHED); --} -- - static void - __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, -@@ -1006,7 +995,7 @@ __cfg80211_offchan_cac_event(struct cfg8 - rdev->offchan_radar_wdev = NULL; - break; - case NL80211_RADAR_CAC_ABORTED: -- cancel_delayed_work(&rdev->offchan_cac_work); -+ cancel_delayed_work(&rdev->offchan_cac_done_wk); - wdev = rdev->offchan_radar_wdev; - rdev->offchan_radar_wdev = NULL; - break; -@@ -1022,17 +1011,44 @@ __cfg80211_offchan_cac_event(struct cfg8 - nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); - } - --void cfg80211_offchan_cac_event(struct wiphy *wiphy, -- const struct cfg80211_chan_def *chandef, -- enum nl80211_radar_event event) -+static void -+cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event) -+{ -+ wiphy_lock(&rdev->wiphy); -+ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); -+ wiphy_unlock(&rdev->wiphy); -+} -+ -+void cfg80211_offchan_cac_done_wk(struct work_struct *work) -+{ -+ struct delayed_work *delayed_work = to_delayed_work(work); -+ struct cfg80211_registered_device *rdev; -+ -+ rdev = container_of(delayed_work, struct cfg80211_registered_device, -+ offchan_cac_done_wk); -+ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, -+ NL80211_RADAR_CAC_FINISHED); -+} -+ -+void cfg80211_offchan_cac_abort_wk(struct work_struct *work) -+{ -+ struct cfg80211_registered_device *rdev; -+ -+ rdev = container_of(work, struct cfg80211_registered_device, -+ offchan_cac_abort_wk); -+ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, -+ NL80211_RADAR_CAC_ABORTED); -+} -+ -+void cfg80211_offchan_cac_abort(struct wiphy *wiphy) - { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - -- wiphy_lock(wiphy); -- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); -- wiphy_unlock(wiphy); -+ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); - } --EXPORT_SYMBOL(cfg80211_offchan_cac_event); -+EXPORT_SYMBOL(cfg80211_offchan_cac_abort); - - int - cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, -@@ -1062,7 +1078,7 @@ cfg80211_start_offchan_radar_detection(s - rdev->offchan_radar_chandef = *chandef; - __cfg80211_offchan_cac_event(rdev, wdev, chandef, - NL80211_RADAR_CAC_STARTED); -- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, -+ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, - msecs_to_jiffies(cac_time_ms)); - - return 0; diff --git a/package/kernel/mac80211/patches/subsys/315-v5.17-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch b/package/kernel/mac80211/patches/subsys/315-v5.17-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch new file mode 100644 index 0000000000..b1a1d2c894 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/315-v5.17-cfg80211-move-offchan_cac_event-to-a-dedicated-work.patch @@ -0,0 +1,183 @@ +From: Lorenzo Bianconi +Date: Wed, 27 Oct 2021 11:03:42 +0200 +Subject: [PATCH] cfg80211: move offchan_cac_event to a dedicated work + +In order to make cfg80211_offchan_cac_abort() (renamed from +cfg80211_offchan_cac_event) callable in other contexts and +without so much locking restrictions, make it trigger a new +work instead of operating directly. + +Do some other renames while at it to clarify. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/6145c3d0f30400a568023f67981981d24c7c6133.1635325205.git.lorenzo@kernel.org +[rewrite commit log] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -7620,19 +7620,13 @@ void cfg80211_cac_event(struct net_devic + enum nl80211_radar_event event, gfp_t gfp); + + /** +- * cfg80211_offchan_cac_event - Channel Availability Check (CAC) offchan event ++ * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event + * @wiphy: the wiphy +- * @chandef: chandef for the current channel +- * @event: type of event + * +- * This function is called when a Channel Availability Check (CAC) is finished, +- * started or aborted by a offchannel dedicated chain. +- * +- * Note that this acquires the wiphy lock. ++ * This function is called by the driver when a Channel Availability Check ++ * (CAC) is aborted by a offchannel dedicated chain. + */ +-void cfg80211_offchan_cac_event(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event); ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,7 +543,9 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); +- INIT_DELAYED_WORK(&rdev->offchan_cac_work, cfg80211_offchan_cac_work); ++ INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); ++ INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, ++ cfg80211_offchan_cac_done_wk); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1053,11 +1055,13 @@ void wiphy_unregister(struct wiphy *wiph + cancel_work_sync(&rdev->conn_work); + flush_work(&rdev->event_work); + cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); ++ cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); + flush_work(&rdev->destroy_work); + flush_work(&rdev->sched_scan_stop_wk); + flush_work(&rdev->propagate_radar_detect_wk); + flush_work(&rdev->propagate_cac_done_wk); + flush_work(&rdev->mgmt_registrations_update_wk); ++ flush_work(&rdev->offchan_cac_abort_wk); + + #ifdef CONFIG_PM + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -86,7 +86,8 @@ struct cfg80211_registered_device { + + struct wireless_dev *offchan_radar_wdev; + struct cfg80211_chan_def offchan_radar_chandef; +- struct delayed_work offchan_cac_work; ++ struct delayed_work offchan_cac_done_wk; ++ struct work_struct offchan_cac_abort_wk; + + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; +@@ -502,7 +503,9 @@ cfg80211_start_offchan_radar_detection(s + + void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); + +-void cfg80211_offchan_cac_work(struct work_struct *work); ++void cfg80211_offchan_cac_done_wk(struct work_struct *work); ++ ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work); + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -971,17 +971,6 @@ void cfg80211_cac_event(struct net_devic + } + EXPORT_SYMBOL(cfg80211_cac_event); + +-void cfg80211_offchan_cac_work(struct work_struct *work) +-{ +- struct delayed_work *delayed_work = to_delayed_work(work); +- struct cfg80211_registered_device *rdev; +- +- rdev = container_of(delayed_work, struct cfg80211_registered_device, +- offchan_cac_work); +- cfg80211_offchan_cac_event(&rdev->wiphy, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_FINISHED); +-} +- + static void + __cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, +@@ -1006,7 +995,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: +- cancel_delayed_work(&rdev->offchan_cac_work); ++ cancel_delayed_work(&rdev->offchan_cac_done_wk); + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; +@@ -1022,17 +1011,44 @@ __cfg80211_offchan_cac_event(struct cfg8 + nl80211_radar_notify(rdev, chandef, event, netdev, GFP_KERNEL); + } + +-void cfg80211_offchan_cac_event(struct wiphy *wiphy, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++static void ++cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) ++{ ++ wiphy_lock(&rdev->wiphy); ++ __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ wiphy_unlock(&rdev->wiphy); ++} ++ ++void cfg80211_offchan_cac_done_wk(struct work_struct *work) ++{ ++ struct delayed_work *delayed_work = to_delayed_work(work); ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(delayed_work, struct cfg80211_registered_device, ++ offchan_cac_done_wk); ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); ++} ++ ++void cfg80211_offchan_cac_abort_wk(struct work_struct *work) ++{ ++ struct cfg80211_registered_device *rdev; ++ ++ rdev = container_of(work, struct cfg80211_registered_device, ++ offchan_cac_abort_wk); ++ cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); ++} ++ ++void cfg80211_offchan_cac_abort(struct wiphy *wiphy) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- wiphy_lock(wiphy); +- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); +- wiphy_unlock(wiphy); ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); + } +-EXPORT_SYMBOL(cfg80211_offchan_cac_event); ++EXPORT_SYMBOL(cfg80211_offchan_cac_abort); + + int + cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +@@ -1062,7 +1078,7 @@ cfg80211_start_offchan_radar_detection(s + rdev->offchan_radar_chandef = *chandef; + __cfg80211_offchan_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); +- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_work, ++ queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, + msecs_to_jiffies(cac_time_ms)); + + return 0; diff --git a/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch deleted file mode 100644 index 362bb885d7..0000000000 --- a/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch +++ /dev/null @@ -1,99 +0,0 @@ -From: Lorenzo Bianconi -Date: Wed, 3 Nov 2021 18:02:35 +0100 -Subject: [PATCH] cfg80211: fix possible NULL pointer dereference in - cfg80211_stop_offchan_radar_detection - -Fix the following NULL pointer dereference in -cfg80211_stop_offchan_radar_detection routine that occurs when hostapd -is stopped during the CAC on offchannel chain: - -Sat Jan 1 0[ 779.567851] ESR = 0x96000005 -0:12:50 2000 dae[ 779.572346] EC = 0x25: DABT (current EL), IL = 32 bits -mon.debug hostap[ 779.578984] SET = 0, FnV = 0 -d: hostapd_inter[ 779.583445] EA = 0, S1PTW = 0 -face_deinit_free[ 779.587936] Data abort info: -: num_bss=1 conf[ 779.592224] ISV = 0, ISS = 0x00000005 -->num_bss=1 -Sat[ 779.597403] CM = 0, WnR = 0 - Jan 1 00:12:50[ 779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000 - 2000 daemon.deb[ 779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 -ug hostapd: host[ 779.619657] Internal error: Oops: 96000005 [#1] SMP -[ 779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0 -[ 779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT) -[ 779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--) -[ 779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211] -[ 779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211] -[ 779.800731] sp : ffffffc01204b7e0 -[ 779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00 -[ 779.809340] x27: 0000000000000000 x26: ffffffc008cb3050 -[ 779.814644] x25: 0000000000000000 x24: 0000000000000002 -[ 779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0 -[ 779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00 -[ 779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0 -[ 779.835860] x17: 00000000ffffffff x16: 0000000000000000 -[ 779.841164] x15: 0000000040d59200 x14: 00000000000019c0 -[ 779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6 -[ 779.851771] x11: 0000000000000141 x10: 0000000000000820 -[ 779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038 -[ 779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038 -[ 779.867683] x5 : 0000000000000e90 x4 : 0000000000000038 -[ 779.872987] x3 : 0000000000000002 x2 : 0000000000000004 -[ 779.878291] x1 : 0000000000000000 x0 : 0000000000000000 -[ 779.883594] Call trace: -[ 779.886039] cfg80211_chandef_valid+0x10/0x490 [cfg80211] -[ 779.891434] cfg80211_check_station_change+0x3190/0x3950 [cfg80211] -[ 779.897697] nl80211_radar_notify+0x138/0x19c [cfg80211] -[ 779.903005] cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211] -[ 779.909616] __cfg80211_leave+0x2c/0x190 [cfg80211] -[ 779.914490] cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211] -[ 779.920404] raw_notifier_call_chain+0x50/0x70 -[ 779.924841] call_netdevice_notifiers_info+0x54/0xa0 -[ 779.929796] __dev_close_many+0x40/0x100 -[ 779.933712] __dev_change_flags+0x98/0x190 -[ 779.937800] dev_change_flags+0x20/0x60 -[ 779.941628] devinet_ioctl+0x534/0x6d0 -[ 779.945370] inet_ioctl+0x1bc/0x230 -[ 779.948849] sock_do_ioctl+0x44/0x200 -[ 779.952502] sock_ioctl+0x268/0x4c0 -[ 779.955985] __arm64_sys_ioctl+0xac/0xd0 -[ 779.959900] el0_svc_common.constprop.0+0x60/0x110 -[ 779.964682] do_el0_svc+0x1c/0x24 -[ 779.967990] el0_svc+0x10/0x1c -[ 779.971036] el0_sync_handler+0x9c/0x120 -[ 779.974950] el0_sync+0x148/0x180 -[ 779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000) -[ 779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]--- -[ 779.996400] Kernel panic - not syncing: Oops: Fatal exception -[ 780.002139] SMP: stopping secondary CPUs -[ 780.006057] Kernel Offset: disabled -[ 780.009537] CPU features: 0x0000002,04002004 -[ 780.013796] Memory Limit: none - -Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW") -Reported-by: Evelyn Tsai -Tested-by: Evelyn Tsai -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg8 - - lockdep_assert_wiphy(&rdev->wiphy); - -+ if (!cfg80211_chandef_valid(chandef)) -+ return; -+ - if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) - return; - -@@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detecti - - rdev_set_radar_offchan(rdev, NULL); - -- __cfg80211_offchan_cac_event(rdev, NULL, NULL, -+ __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_ABORTED); - } diff --git a/package/kernel/mac80211/patches/subsys/316-v5.17-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch b/package/kernel/mac80211/patches/subsys/316-v5.17-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch new file mode 100644 index 0000000000..362bb885d7 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/316-v5.17-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch @@ -0,0 +1,99 @@ +From: Lorenzo Bianconi +Date: Wed, 3 Nov 2021 18:02:35 +0100 +Subject: [PATCH] cfg80211: fix possible NULL pointer dereference in + cfg80211_stop_offchan_radar_detection + +Fix the following NULL pointer dereference in +cfg80211_stop_offchan_radar_detection routine that occurs when hostapd +is stopped during the CAC on offchannel chain: + +Sat Jan 1 0[ 779.567851] ESR = 0x96000005 +0:12:50 2000 dae[ 779.572346] EC = 0x25: DABT (current EL), IL = 32 bits +mon.debug hostap[ 779.578984] SET = 0, FnV = 0 +d: hostapd_inter[ 779.583445] EA = 0, S1PTW = 0 +face_deinit_free[ 779.587936] Data abort info: +: num_bss=1 conf[ 779.592224] ISV = 0, ISS = 0x00000005 +->num_bss=1 +Sat[ 779.597403] CM = 0, WnR = 0 + Jan 1 00:12:50[ 779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000 + 2000 daemon.deb[ 779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000 +ug hostapd: host[ 779.619657] Internal error: Oops: 96000005 [#1] SMP +[ 779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0 +[ 779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT) +[ 779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--) +[ 779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211] +[ 779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211] +[ 779.800731] sp : ffffffc01204b7e0 +[ 779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00 +[ 779.809340] x27: 0000000000000000 x26: ffffffc008cb3050 +[ 779.814644] x25: 0000000000000000 x24: 0000000000000002 +[ 779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0 +[ 779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00 +[ 779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0 +[ 779.835860] x17: 00000000ffffffff x16: 0000000000000000 +[ 779.841164] x15: 0000000040d59200 x14: 00000000000019c0 +[ 779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6 +[ 779.851771] x11: 0000000000000141 x10: 0000000000000820 +[ 779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038 +[ 779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038 +[ 779.867683] x5 : 0000000000000e90 x4 : 0000000000000038 +[ 779.872987] x3 : 0000000000000002 x2 : 0000000000000004 +[ 779.878291] x1 : 0000000000000000 x0 : 0000000000000000 +[ 779.883594] Call trace: +[ 779.886039] cfg80211_chandef_valid+0x10/0x490 [cfg80211] +[ 779.891434] cfg80211_check_station_change+0x3190/0x3950 [cfg80211] +[ 779.897697] nl80211_radar_notify+0x138/0x19c [cfg80211] +[ 779.903005] cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211] +[ 779.909616] __cfg80211_leave+0x2c/0x190 [cfg80211] +[ 779.914490] cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211] +[ 779.920404] raw_notifier_call_chain+0x50/0x70 +[ 779.924841] call_netdevice_notifiers_info+0x54/0xa0 +[ 779.929796] __dev_close_many+0x40/0x100 +[ 779.933712] __dev_change_flags+0x98/0x190 +[ 779.937800] dev_change_flags+0x20/0x60 +[ 779.941628] devinet_ioctl+0x534/0x6d0 +[ 779.945370] inet_ioctl+0x1bc/0x230 +[ 779.948849] sock_do_ioctl+0x44/0x200 +[ 779.952502] sock_ioctl+0x268/0x4c0 +[ 779.955985] __arm64_sys_ioctl+0xac/0xd0 +[ 779.959900] el0_svc_common.constprop.0+0x60/0x110 +[ 779.964682] do_el0_svc+0x1c/0x24 +[ 779.967990] el0_svc+0x10/0x1c +[ 779.971036] el0_sync_handler+0x9c/0x120 +[ 779.974950] el0_sync+0x148/0x180 +[ 779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000) +[ 779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]--- +[ 779.996400] Kernel panic - not syncing: Oops: Fatal exception +[ 780.002139] SMP: stopping secondary CPUs +[ 780.006057] Kernel Offset: disabled +[ 780.009537] CPU features: 0x0000002,04002004 +[ 780.013796] Memory Limit: none + +Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW") +Reported-by: Evelyn Tsai +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg8 + + lockdep_assert_wiphy(&rdev->wiphy); + ++ if (!cfg80211_chandef_valid(chandef)) ++ return; ++ + if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) + return; + +@@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detecti + + rdev_set_radar_offchan(rdev, NULL); + +- __cfg80211_offchan_cac_event(rdev, NULL, NULL, ++ __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_ABORTED); + } diff --git a/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch deleted file mode 100644 index df7afefb34..0000000000 --- a/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch +++ /dev/null @@ -1,136 +0,0 @@ -From: Lorenzo Bianconi -Date: Tue, 16 Nov 2021 12:41:52 +0100 -Subject: [PATCH] cfg80211: schedule offchan_cac_abort_wk in - cfg80211_radar_event - -If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event -routine adding offchan parameter to cfg80211_radar_event signature. -Rename cfg80211_radar_event in __cfg80211_radar_event and introduce -the two following inline helpers: -- cfg80211_radar_event -- cfg80211_offchan_radar_event -Doing so the drv will not need to run cfg80211_offchan_cac_abort() after -radar detection on the offchannel chain. - -Tested-by: Owen Peng -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -7580,15 +7580,33 @@ void cfg80211_cqm_txe_notify(struct net_ - void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); - - /** -- * cfg80211_radar_event - radar detection event -+ * __cfg80211_radar_event - radar detection event - * @wiphy: the wiphy - * @chandef: chandef for the current channel -+ * @offchan: the radar has been detected on the offchannel chain - * @gfp: context flags - * - * This function is called when a radar is detected on the current chanenl. - */ --void cfg80211_radar_event(struct wiphy *wiphy, -- struct cfg80211_chan_def *chandef, gfp_t gfp); -+void __cfg80211_radar_event(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef, -+ bool offchan, gfp_t gfp); -+ -+static inline void -+cfg80211_radar_event(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef, -+ gfp_t gfp) -+{ -+ __cfg80211_radar_event(wiphy, chandef, false, gfp); -+} -+ -+static inline void -+cfg80211_offchan_radar_event(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef, -+ gfp_t gfp) -+{ -+ __cfg80211_radar_event(wiphy, chandef, true, gfp); -+} - - /** - * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(s - } - - --void cfg80211_radar_event(struct wiphy *wiphy, -- struct cfg80211_chan_def *chandef, -- gfp_t gfp) -+void __cfg80211_radar_event(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef, -+ bool offchan, gfp_t gfp) - { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - -- trace_cfg80211_radar_event(wiphy, chandef); -+ trace_cfg80211_radar_event(wiphy, chandef, offchan); - - /* only set the chandef supplied channel to unavailable, in - * case the radar is detected on only one of multiple channels -@@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy * - */ - cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); - -+ if (offchan) -+ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); -+ - cfg80211_sched_dfs_chan_update(rdev); - - nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); -@@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy * - memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); - queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); - } --EXPORT_SYMBOL(cfg80211_radar_event); -+EXPORT_SYMBOL(__cfg80211_radar_event); - - void cfg80211_cac_event(struct net_device *netdev, - const struct cfg80211_chan_def *chandef, -@@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg8 - rdev->offchan_radar_wdev = NULL; - break; - case NL80211_RADAR_CAC_ABORTED: -- cancel_delayed_work(&rdev->offchan_cac_done_wk); -+ if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) -+ return; - wdev = rdev->offchan_radar_wdev; - rdev->offchan_radar_wdev = NULL; - break; ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_n - ); - - TRACE_EVENT(cfg80211_radar_event, -- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), -- TP_ARGS(wiphy, chandef), -+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, -+ bool offchan), -+ TP_ARGS(wiphy, chandef, offchan), - TP_STRUCT__entry( - WIPHY_ENTRY - CHAN_DEF_ENTRY -+ __field(bool, offchan) - ), - TP_fast_assign( - WIPHY_ASSIGN; - CHAN_DEF_ASSIGN(chandef); -+ __entry->offchan = offchan; - ), -- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, -- WIPHY_PR_ARG, CHAN_DEF_PR_ARG) -+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d", -+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan) - ); - - TRACE_EVENT(cfg80211_cac_event, diff --git a/package/kernel/mac80211/patches/subsys/317-v5.17-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch b/package/kernel/mac80211/patches/subsys/317-v5.17-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch new file mode 100644 index 0000000000..df7afefb34 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/317-v5.17-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch @@ -0,0 +1,136 @@ +From: Lorenzo Bianconi +Date: Tue, 16 Nov 2021 12:41:52 +0100 +Subject: [PATCH] cfg80211: schedule offchan_cac_abort_wk in + cfg80211_radar_event + +If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event +routine adding offchan parameter to cfg80211_radar_event signature. +Rename cfg80211_radar_event in __cfg80211_radar_event and introduce +the two following inline helpers: +- cfg80211_radar_event +- cfg80211_offchan_radar_event +Doing so the drv will not need to run cfg80211_offchan_cac_abort() after +radar detection on the offchannel chain. + +Tested-by: Owen Peng +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -7580,15 +7580,33 @@ void cfg80211_cqm_txe_notify(struct net_ + void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp); + + /** +- * cfg80211_radar_event - radar detection event ++ * __cfg80211_radar_event - radar detection event + * @wiphy: the wiphy + * @chandef: chandef for the current channel ++ * @offchan: the radar has been detected on the offchannel chain + * @gfp: context flags + * + * This function is called when a radar is detected on the current chanenl. + */ +-void cfg80211_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, gfp_t gfp); ++void __cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ bool offchan, gfp_t gfp); ++ ++static inline void ++cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) ++{ ++ __cfg80211_radar_event(wiphy, chandef, false, gfp); ++} ++ ++static inline void ++cfg80211_offchan_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) ++{ ++ __cfg80211_radar_event(wiphy, chandef, true, gfp); ++} + + /** + * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(s + } + + +-void cfg80211_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, +- gfp_t gfp) ++void __cfg80211_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ bool offchan, gfp_t gfp) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- trace_cfg80211_radar_event(wiphy, chandef); ++ trace_cfg80211_radar_event(wiphy, chandef, offchan); + + /* only set the chandef supplied channel to unavailable, in + * case the radar is detected on only one of multiple channels +@@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy * + */ + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + ++ if (offchan) ++ queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ + cfg80211_sched_dfs_chan_update(rdev); + + nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp); +@@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy * + memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def)); + queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk); + } +-EXPORT_SYMBOL(cfg80211_radar_event); ++EXPORT_SYMBOL(__cfg80211_radar_event); + + void cfg80211_cac_event(struct net_device *netdev, + const struct cfg80211_chan_def *chandef, +@@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg8 + rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: +- cancel_delayed_work(&rdev->offchan_cac_done_wk); ++ if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) ++ return; + wdev = rdev->offchan_radar_wdev; + rdev->offchan_radar_wdev = NULL; + break; +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_n + ); + + TRACE_EVENT(cfg80211_radar_event, +- TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), +- TP_ARGS(wiphy, chandef), ++ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef, ++ bool offchan), ++ TP_ARGS(wiphy, chandef, offchan), + TP_STRUCT__entry( + WIPHY_ENTRY + CHAN_DEF_ENTRY ++ __field(bool, offchan) + ), + TP_fast_assign( + WIPHY_ASSIGN; + CHAN_DEF_ASSIGN(chandef); ++ __entry->offchan = offchan; + ), +- TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT, +- WIPHY_PR_ARG, CHAN_DEF_PR_ARG) ++ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d", ++ WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan) + ); + + TRACE_EVENT(cfg80211_cac_event, diff --git a/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch deleted file mode 100644 index a1b6e3c80d..0000000000 --- a/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch +++ /dev/null @@ -1,220 +0,0 @@ -From: Lorenzo Bianconi -Date: Tue, 16 Nov 2021 15:03:36 +0100 -Subject: [PATCH] cfg80211: allow continuous radar monitoring on offchannel - chain - -Allow continuous radar detection on the offchannel chain in order -to switch to the monitored channel whenever the underlying driver -reports a radar pattern on the main channel. - -Tested-by: Owen Peng -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/net/wireless/chan.c -+++ b/net/wireless/chan.c -@@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan( - return false; - } - -+static bool -+cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, -+ struct ieee80211_channel *channel) -+{ -+ if (!rdev->offchan_radar_wdev) -+ return false; -+ -+ if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) -+ return false; -+ -+ return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); -+} -+ - bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan) - { -@@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct - - if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) - return true; -+ -+ if (cfg80211_offchan_chain_is_active(rdev, chan)) -+ return true; - } - - return false; ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 - if (!cfg80211_chandef_valid(chandef)) - return; - -- if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) -+ if (!rdev->offchan_radar_wdev) - return; - - switch (event) { -@@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg8 - queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); - cfg80211_sched_dfs_chan_update(rdev); - wdev = rdev->offchan_radar_wdev; -- rdev->offchan_radar_wdev = NULL; - break; - case NL80211_RADAR_CAC_ABORTED: - if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) - return; - wdev = rdev->offchan_radar_wdev; -- rdev->offchan_radar_wdev = NULL; - break; - case NL80211_RADAR_CAC_STARTED: -- WARN_ON(!wdev); -- rdev->offchan_radar_wdev = wdev; - break; - default: - return; -@@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg802 - enum nl80211_radar_event event) - { - wiphy_lock(&rdev->wiphy); -- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); -+ __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, -+ chandef, event); - wiphy_unlock(&rdev->wiphy); - } - -@@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(s - NL80211_EXT_FEATURE_RADAR_OFFCHAN)) - return -EOPNOTSUPP; - -- if (rdev->offchan_radar_wdev) -+ /* Offchannel chain already locked by another wdev */ -+ if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) -+ return -EBUSY; -+ -+ /* CAC already in progress on the offchannel chain */ -+ if (rdev->offchan_radar_wdev == wdev && -+ delayed_work_pending(&rdev->offchan_cac_done_wk)) - return -EBUSY; - - err = rdev_set_radar_offchan(rdev, chandef); -@@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(s - cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; - - rdev->offchan_radar_chandef = *chandef; -+ rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ -+ - __cfg80211_offchan_cac_event(rdev, wdev, chandef, - NL80211_RADAR_CAC_STARTED); - queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, -@@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detecti - return; - - rdev_set_radar_offchan(rdev, NULL); -+ rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ - - __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, - NL80211_RADAR_CAC_ABORTED); ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -9278,42 +9278,60 @@ static int nl80211_start_radar_detection - struct cfg80211_chan_def chandef; - enum nl80211_dfs_regions dfs_region; - unsigned int cac_time_ms; -- int err; -+ int err = -EINVAL; -+ -+ flush_delayed_work(&rdev->dfs_update_channels_wk); -+ -+ wiphy_lock(wiphy); - - dfs_region = reg_get_dfs_region(wiphy); - if (dfs_region == NL80211_DFS_UNSET) -- return -EINVAL; -+ goto unlock; - - err = nl80211_parse_chandef(rdev, info, &chandef); - if (err) -- return err; -+ goto unlock; - - err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); - if (err < 0) -- return err; -+ goto unlock; - -- if (err == 0) -- return -EINVAL; -+ if (err == 0) { -+ err = -EINVAL; -+ goto unlock; -+ } - -- if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) -- return -EINVAL; -+ if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) { -+ err = -EINVAL; -+ goto unlock; -+ } - -- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) -- return cfg80211_start_offchan_radar_detection(rdev, wdev, -- &chandef); -+ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { -+ err = cfg80211_start_offchan_radar_detection(rdev, wdev, -+ &chandef); -+ goto unlock; -+ } - -- if (netif_carrier_ok(dev)) -- return -EBUSY; -+ if (netif_carrier_ok(dev)) { -+ err = -EBUSY; -+ goto unlock; -+ } - -- if (wdev->cac_started) -- return -EBUSY; -+ if (wdev->cac_started) { -+ err = -EBUSY; -+ goto unlock; -+ } - - /* CAC start is offloaded to HW and can't be started manually */ -- if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) -- return -EOPNOTSUPP; -+ if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) { -+ err = -EOPNOTSUPP; -+ goto unlock; -+ } - -- if (!rdev->ops->start_radar_detection) -- return -EOPNOTSUPP; -+ if (!rdev->ops->start_radar_detection) { -+ err = -EOPNOTSUPP; -+ goto unlock; -+ } - - cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); - if (WARN_ON(!cac_time_ms)) -@@ -9326,6 +9344,9 @@ static int nl80211_start_radar_detection - wdev->cac_start_time = jiffies; - wdev->cac_time_ms = cac_time_ms; - } -+unlock: -+ wiphy_unlock(wiphy); -+ - return err; - } - -@@ -15961,7 +15982,8 @@ static const struct genl_small_ops nl802 - .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, - .doit = nl80211_start_radar_detection, - .flags = GENL_UNS_ADMIN_PERM, -- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP, -+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | -+ NL80211_FLAG_NO_WIPHY_MTX, - }, - { - .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, diff --git a/package/kernel/mac80211/patches/subsys/318-v5.17-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch b/package/kernel/mac80211/patches/subsys/318-v5.17-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch new file mode 100644 index 0000000000..a1b6e3c80d --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/318-v5.17-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch @@ -0,0 +1,220 @@ +From: Lorenzo Bianconi +Date: Tue, 16 Nov 2021 15:03:36 +0100 +Subject: [PATCH] cfg80211: allow continuous radar monitoring on offchannel + chain + +Allow continuous radar detection on the offchannel chain in order +to switch to the monitored channel whenever the underlying driver +reports a radar pattern on the main channel. + +Tested-by: Owen Peng +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan( + return false; + } + ++static bool ++cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, ++ struct ieee80211_channel *channel) ++{ ++ if (!rdev->offchan_radar_wdev) ++ return false; ++ ++ if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) ++ return false; ++ ++ return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); ++} ++ + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan) + { +@@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct + + if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan)) + return true; ++ ++ if (cfg80211_offchan_chain_is_active(rdev, chan)) ++ return true; + } + + return false; +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + if (!cfg80211_chandef_valid(chandef)) + return; + +- if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev) ++ if (!rdev->offchan_radar_wdev) + return; + + switch (event) { +@@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg8 + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); + cfg80211_sched_dfs_chan_update(rdev); + wdev = rdev->offchan_radar_wdev; +- rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_ABORTED: + if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) + return; + wdev = rdev->offchan_radar_wdev; +- rdev->offchan_radar_wdev = NULL; + break; + case NL80211_RADAR_CAC_STARTED: +- WARN_ON(!wdev); +- rdev->offchan_radar_wdev = wdev; + break; + default: + return; +@@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg802 + enum nl80211_radar_event event) + { + wiphy_lock(&rdev->wiphy); +- __cfg80211_offchan_cac_event(rdev, NULL, chandef, event); ++ __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, ++ chandef, event); + wiphy_unlock(&rdev->wiphy); + } + +@@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(s + NL80211_EXT_FEATURE_RADAR_OFFCHAN)) + return -EOPNOTSUPP; + +- if (rdev->offchan_radar_wdev) ++ /* Offchannel chain already locked by another wdev */ ++ if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) ++ return -EBUSY; ++ ++ /* CAC already in progress on the offchannel chain */ ++ if (rdev->offchan_radar_wdev == wdev && ++ delayed_work_pending(&rdev->offchan_cac_done_wk)) + return -EBUSY; + + err = rdev_set_radar_offchan(rdev, chandef); +@@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(s + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + + rdev->offchan_radar_chandef = *chandef; ++ rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ ++ + __cfg80211_offchan_cac_event(rdev, wdev, chandef, + NL80211_RADAR_CAC_STARTED); + queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, +@@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detecti + return; + + rdev_set_radar_offchan(rdev, NULL); ++ rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ + + __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, + NL80211_RADAR_CAC_ABORTED); +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -9278,42 +9278,60 @@ static int nl80211_start_radar_detection + struct cfg80211_chan_def chandef; + enum nl80211_dfs_regions dfs_region; + unsigned int cac_time_ms; +- int err; ++ int err = -EINVAL; ++ ++ flush_delayed_work(&rdev->dfs_update_channels_wk); ++ ++ wiphy_lock(wiphy); + + dfs_region = reg_get_dfs_region(wiphy); + if (dfs_region == NL80211_DFS_UNSET) +- return -EINVAL; ++ goto unlock; + + err = nl80211_parse_chandef(rdev, info, &chandef); + if (err) +- return err; ++ goto unlock; + + err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype); + if (err < 0) +- return err; ++ goto unlock; + +- if (err == 0) +- return -EINVAL; ++ if (err == 0) { ++ err = -EINVAL; ++ goto unlock; ++ } + +- if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) +- return -EINVAL; ++ if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) { ++ err = -EINVAL; ++ goto unlock; ++ } + +- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) +- return cfg80211_start_offchan_radar_detection(rdev, wdev, +- &chandef); ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { ++ err = cfg80211_start_offchan_radar_detection(rdev, wdev, ++ &chandef); ++ goto unlock; ++ } + +- if (netif_carrier_ok(dev)) +- return -EBUSY; ++ if (netif_carrier_ok(dev)) { ++ err = -EBUSY; ++ goto unlock; ++ } + +- if (wdev->cac_started) +- return -EBUSY; ++ if (wdev->cac_started) { ++ err = -EBUSY; ++ goto unlock; ++ } + + /* CAC start is offloaded to HW and can't be started manually */ +- if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) +- return -EOPNOTSUPP; ++ if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) { ++ err = -EOPNOTSUPP; ++ goto unlock; ++ } + +- if (!rdev->ops->start_radar_detection) +- return -EOPNOTSUPP; ++ if (!rdev->ops->start_radar_detection) { ++ err = -EOPNOTSUPP; ++ goto unlock; ++ } + + cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef); + if (WARN_ON(!cac_time_ms)) +@@ -9326,6 +9344,9 @@ static int nl80211_start_radar_detection + wdev->cac_start_time = jiffies; + wdev->cac_time_ms = cac_time_ms; + } ++unlock: ++ wiphy_unlock(wiphy); ++ + return err; + } + +@@ -15961,7 +15982,8 @@ static const struct genl_small_ops nl802 + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .doit = nl80211_start_radar_detection, + .flags = GENL_UNS_ADMIN_PERM, +- .internal_flags = NL80211_FLAG_NEED_NETDEV_UP, ++ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | ++ NL80211_FLAG_NO_WIPHY_MTX, + }, + { + .cmd = NL80211_CMD_GET_PROTOCOL_FEATURES, diff --git a/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch deleted file mode 100644 index eb80afbccb..0000000000 --- a/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch +++ /dev/null @@ -1,67 +0,0 @@ -From: Lorenzo Bianconi -Date: Sat, 23 Oct 2021 11:10:51 +0200 -Subject: [PATCH] mac80211: introduce set_radar_offchan callback - -Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops -in order to configure a dedicated offchannel chain available on some hw -(e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime. - -Tested-by: Evelyn Tsai -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -3937,6 +3937,14 @@ struct ieee80211_prep_tx_info { - * twt structure. - * @twt_teardown_request: Update the hw with TWT teardown request received - * from the peer. -+ * @set_radar_offchan: Configure dedicated offchannel chain available for -+ * radar/CAC detection on some hw. This chain can't be used to transmit -+ * or receive frames and it is bounded to a running wdev. -+ * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * switching to a different channel during CAC detection on the selected -+ * radar channel. -+ * The caller is expected to set chandef pointer to NULL in order to -+ * disable offchannel CAC/radar detection. - * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to - * resolve a path for hardware flow offloading - */ -@@ -4267,6 +4275,8 @@ struct ieee80211_ops { - struct ieee80211_twt_setup *twt); - void (*twt_teardown_request)(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, u8 flowid); -+ int (*set_radar_offchan)(struct ieee80211_hw *hw, -+ struct cfg80211_chan_def *chandef); - #if LINUX_VERSION_IS_GEQ(5,10,0) - int (*net_fill_forward_path)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -4344,6 +4344,18 @@ out: - return err; - } - -+static int -+ieee80211_set_radar_offchan(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef) -+{ -+ struct ieee80211_local *local = wiphy_priv(wiphy); -+ -+ if (!local->ops->set_radar_offchan) -+ return -EOPNOTSUPP; -+ -+ return local->ops->set_radar_offchan(&local->hw, chandef); -+} -+ - const struct cfg80211_ops mac80211_config_ops = { - .add_virtual_intf = ieee80211_add_iface, - .del_virtual_intf = ieee80211_del_iface, -@@ -4448,4 +4460,5 @@ const struct cfg80211_ops mac80211_confi - .reset_tid_config = ieee80211_reset_tid_config, - .set_sar_specs = ieee80211_set_sar_specs, - .color_change = ieee80211_color_change, -+ .set_radar_offchan = ieee80211_set_radar_offchan, - }; diff --git a/package/kernel/mac80211/patches/subsys/319-v5.17-mac80211-introduce-set_radar_offchan-callback.patch b/package/kernel/mac80211/patches/subsys/319-v5.17-mac80211-introduce-set_radar_offchan-callback.patch new file mode 100644 index 0000000000..eb80afbccb --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/319-v5.17-mac80211-introduce-set_radar_offchan-callback.patch @@ -0,0 +1,67 @@ +From: Lorenzo Bianconi +Date: Sat, 23 Oct 2021 11:10:51 +0200 +Subject: [PATCH] mac80211: introduce set_radar_offchan callback + +Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops +in order to configure a dedicated offchannel chain available on some hw +(e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime. + +Tested-by: Evelyn Tsai +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,6 +3937,14 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. ++ * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * radar/CAC detection on some hw. This chain can't be used to transmit ++ * or receive frames and it is bounded to a running wdev. ++ * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * switching to a different channel during CAC detection on the selected ++ * radar channel. ++ * The caller is expected to set chandef pointer to NULL in order to ++ * disable offchannel CAC/radar detection. + * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to + * resolve a path for hardware flow offloading + */ +@@ -4267,6 +4275,8 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); ++ int (*set_radar_offchan)(struct ieee80211_hw *hw, ++ struct cfg80211_chan_def *chandef); + #if LINUX_VERSION_IS_GEQ(5,10,0) + int (*net_fill_forward_path)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4344,6 +4344,18 @@ out: + return err; + } + ++static int ++ieee80211_set_radar_offchan(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) ++{ ++ struct ieee80211_local *local = wiphy_priv(wiphy); ++ ++ if (!local->ops->set_radar_offchan) ++ return -EOPNOTSUPP; ++ ++ return local->ops->set_radar_offchan(&local->hw, chandef); ++} ++ + const struct cfg80211_ops mac80211_config_ops = { + .add_virtual_intf = ieee80211_add_iface, + .del_virtual_intf = ieee80211_del_iface, +@@ -4448,4 +4460,5 @@ const struct cfg80211_ops mac80211_confi + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, + .color_change = ieee80211_color_change, ++ .set_radar_offchan = ieee80211_set_radar_offchan, + }; diff --git a/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch deleted file mode 100644 index 483b87cd88..0000000000 --- a/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch +++ /dev/null @@ -1,532 +0,0 @@ -From: Lorenzo Bianconi -Date: Mon, 29 Nov 2021 14:11:24 +0100 -Subject: [PATCH] cfg80211: rename offchannel_chain structs to background_chain - to avoid confusion with ETSI standard - -ETSI standard defines "Offchannel CAC" as: -"Off-Channel CAC is performed by a number of non-continuous checks -spread over a period in time. This period, which is required to -determine the presence of radar signals, is defined as the Off-Channel -CAC Time.. -Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time -4 hours..". -mac80211 implementation refers to a dedicated hw chain used for continuous -radar monitoring. Rename offchannel_* references to background_* in -order to avoid confusion with ETSI standard. - -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/include/net/cfg80211.h -+++ b/include/net/cfg80211.h -@@ -4058,14 +4058,14 @@ struct mgmt_frame_regs { - * - * @color_change: Initiate a color change. - * -- * @set_radar_offchan: Configure dedicated offchannel chain available for -+ * @set_radar_background: Configure dedicated offchannel chain available for - * radar/CAC detection on some hw. This chain can't be used to transmit - * or receive frames and it is bounded to a running wdev. -- * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * Background radar/CAC detection allows to avoid the CAC downtime - * switching to a different channel during CAC detection on the selected - * radar channel. - * The caller is expected to set chandef pointer to NULL in order to -- * disable offchannel CAC/radar detection. -+ * disable background CAC/radar detection. - */ - struct cfg80211_ops { - int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); -@@ -4396,8 +4396,8 @@ struct cfg80211_ops { - int (*color_change)(struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_color_change_settings *params); -- int (*set_radar_offchan)(struct wiphy *wiphy, -- struct cfg80211_chan_def *chandef); -+ int (*set_radar_background)(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef); - }; - - /* -@@ -7601,9 +7601,9 @@ cfg80211_radar_event(struct wiphy *wiphy - } - - static inline void --cfg80211_offchan_radar_event(struct wiphy *wiphy, -- struct cfg80211_chan_def *chandef, -- gfp_t gfp) -+cfg80211_background_radar_event(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef, -+ gfp_t gfp) - { - __cfg80211_radar_event(wiphy, chandef, true, gfp); - } -@@ -7638,13 +7638,13 @@ void cfg80211_cac_event(struct net_devic - enum nl80211_radar_event event, gfp_t gfp); - - /** -- * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event -+ * cfg80211_background_cac_abort - Channel Availability Check offchan abort event - * @wiphy: the wiphy - * - * This function is called by the driver when a Channel Availability Check - * (CAC) is aborted by a offchannel dedicated chain. - */ --void cfg80211_offchan_cac_abort(struct wiphy *wiphy); -+void cfg80211_background_cac_abort(struct wiphy *wiphy); - - /** - * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -3937,14 +3937,14 @@ struct ieee80211_prep_tx_info { - * twt structure. - * @twt_teardown_request: Update the hw with TWT teardown request received - * from the peer. -- * @set_radar_offchan: Configure dedicated offchannel chain available for -+ * @set_radar_background: Configure dedicated offchannel chain available for - * radar/CAC detection on some hw. This chain can't be used to transmit - * or receive frames and it is bounded to a running wdev. -- * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * Background radar/CAC detection allows to avoid the CAC downtime - * switching to a different channel during CAC detection on the selected - * radar channel. - * The caller is expected to set chandef pointer to NULL in order to -- * disable offchannel CAC/radar detection. -+ * disable background CAC/radar detection. - * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to - * resolve a path for hardware flow offloading - */ -@@ -4275,8 +4275,8 @@ struct ieee80211_ops { - struct ieee80211_twt_setup *twt); - void (*twt_teardown_request)(struct ieee80211_hw *hw, - struct ieee80211_sta *sta, u8 flowid); -- int (*set_radar_offchan)(struct ieee80211_hw *hw, -- struct cfg80211_chan_def *chandef); -+ int (*set_radar_background)(struct ieee80211_hw *hw, -+ struct cfg80211_chan_def *chandef); - #if LINUX_VERSION_IS_GEQ(5,10,0) - int (*net_fill_forward_path)(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, ---- a/include/uapi/linux/nl80211.h -+++ b/include/uapi/linux/nl80211.h -@@ -2608,10 +2608,10 @@ enum nl80211_commands { - * Mandatory parameter for the transmitting interface to enable MBSSID. - * Optional for the non-transmitting interfaces. - * -- * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for -- * radar/CAC detection on some hw. This chain can't be used to transmit -- * or receive frames and it is bounded to a running wdev. -- * Offchannel radar/CAC detection allows to avoid the CAC downtime -+ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain -+ * available for radar/CAC detection on some hw. This chain can't be used -+ * to transmit or receive frames and it is bounded to a running wdev. -+ * Background radar/CAC detection allows to avoid the CAC downtime - * switching on a different channel during CAC detection on the selected - * radar channel. - * -@@ -3121,7 +3121,7 @@ enum nl80211_attrs { - NL80211_ATTR_MBSSID_CONFIG, - NL80211_ATTR_MBSSID_ELEMS, - -- NL80211_ATTR_RADAR_OFFCHAN, -+ NL80211_ATTR_RADAR_BACKGROUND, - - /* add attributes here, update the policy in nl80211.c */ - -@@ -6022,7 +6022,7 @@ enum nl80211_feature_flags { - * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision - * detection and change announcemnts. - * -- * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC -+ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC - * detection. - * - * @NUM_NL80211_EXT_FEATURES: number of extended features. -@@ -6090,7 +6090,7 @@ enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_SECURE_RTT, - NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, - NL80211_EXT_FEATURE_BSS_COLOR, -- NL80211_EXT_FEATURE_RADAR_OFFCHAN, -+ NL80211_EXT_FEATURE_RADAR_BACKGROUND, - - /* add new features before the definition below */ - NUM_NL80211_EXT_FEATURES, ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -4345,15 +4345,15 @@ out: - } - - static int --ieee80211_set_radar_offchan(struct wiphy *wiphy, -- struct cfg80211_chan_def *chandef) -+ieee80211_set_radar_background(struct wiphy *wiphy, -+ struct cfg80211_chan_def *chandef) - { - struct ieee80211_local *local = wiphy_priv(wiphy); - -- if (!local->ops->set_radar_offchan) -+ if (!local->ops->set_radar_background) - return -EOPNOTSUPP; - -- return local->ops->set_radar_offchan(&local->hw, chandef); -+ return local->ops->set_radar_background(&local->hw, chandef); - } - - const struct cfg80211_ops mac80211_config_ops = { -@@ -4460,5 +4460,5 @@ const struct cfg80211_ops mac80211_confi - .reset_tid_config = ieee80211_reset_tid_config, - .set_sar_specs = ieee80211_set_sar_specs, - .color_change = ieee80211_color_change, -- .set_radar_offchan = ieee80211_set_radar_offchan, -+ .set_radar_background = ieee80211_set_radar_background, - }; ---- a/net/wireless/chan.c -+++ b/net/wireless/chan.c -@@ -716,13 +716,13 @@ static bool - cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, - struct ieee80211_channel *channel) - { -- if (!rdev->offchan_radar_wdev) -+ if (!rdev->background_radar_wdev) - return false; - -- if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) -+ if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) - return false; - -- return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); -+ return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); - } - - bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, ---- a/net/wireless/core.c -+++ b/net/wireless/core.c -@@ -543,9 +543,10 @@ use_default_name: - INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); - INIT_WORK(&rdev->conn_work, cfg80211_conn_work); - INIT_WORK(&rdev->event_work, cfg80211_event_work); -- INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); -- INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, -- cfg80211_offchan_cac_done_wk); -+ INIT_WORK(&rdev->background_cac_abort_wk, -+ cfg80211_background_cac_abort_wk); -+ INIT_DELAYED_WORK(&rdev->background_cac_done_wk, -+ cfg80211_background_cac_done_wk); - - init_waitqueue_head(&rdev->dev_wait); - -@@ -1055,13 +1056,13 @@ void wiphy_unregister(struct wiphy *wiph - cancel_work_sync(&rdev->conn_work); - flush_work(&rdev->event_work); - cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); -- cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); -+ cancel_delayed_work_sync(&rdev->background_cac_done_wk); - flush_work(&rdev->destroy_work); - flush_work(&rdev->sched_scan_stop_wk); - flush_work(&rdev->propagate_radar_detect_wk); - flush_work(&rdev->propagate_cac_done_wk); - flush_work(&rdev->mgmt_registrations_update_wk); -- flush_work(&rdev->offchan_cac_abort_wk); -+ flush_work(&rdev->background_cac_abort_wk); - - #ifdef CONFIG_PM - if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) -@@ -1210,7 +1211,7 @@ void __cfg80211_leave(struct cfg80211_re - - cfg80211_pmsr_wdev_down(wdev); - -- cfg80211_stop_offchan_radar_detection(wdev); -+ cfg80211_stop_background_radar_detection(wdev); - - switch (wdev->iftype) { - case NL80211_IFTYPE_ADHOC: ---- a/net/wireless/core.h -+++ b/net/wireless/core.h -@@ -84,10 +84,10 @@ struct cfg80211_registered_device { - - struct delayed_work dfs_update_channels_wk; - -- struct wireless_dev *offchan_radar_wdev; -- struct cfg80211_chan_def offchan_radar_chandef; -- struct delayed_work offchan_cac_done_wk; -- struct work_struct offchan_cac_abort_wk; -+ struct wireless_dev *background_radar_wdev; -+ struct cfg80211_chan_def background_radar_chandef; -+ struct delayed_work background_cac_done_wk; -+ struct work_struct background_cac_abort_wk; - - /* netlink port which started critical protocol (0 means not started) */ - u32 crit_proto_nlportid; -@@ -497,15 +497,15 @@ cfg80211_chandef_dfs_cac_time(struct wip - void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); - - int --cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev, -- struct cfg80211_chan_def *chandef); -+cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ struct cfg80211_chan_def *chandef); - --void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); -+void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev); - --void cfg80211_offchan_cac_done_wk(struct work_struct *work); -+void cfg80211_background_cac_done_wk(struct work_struct *work); - --void cfg80211_offchan_cac_abort_wk(struct work_struct *work); -+void cfg80211_background_cac_abort_wk(struct work_struct *work); - - bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan); ---- a/net/wireless/mlme.c -+++ b/net/wireless/mlme.c -@@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy - cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); - - if (offchan) -- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); -+ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); - - cfg80211_sched_dfs_chan_update(rdev); - -@@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_devic - EXPORT_SYMBOL(cfg80211_cac_event); - - static void --__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev, -- const struct cfg80211_chan_def *chandef, -- enum nl80211_radar_event event) -+__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event) - { - struct wiphy *wiphy = &rdev->wiphy; - struct net_device *netdev; -@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 - if (!cfg80211_chandef_valid(chandef)) - return; - -- if (!rdev->offchan_radar_wdev) -+ if (!rdev->background_radar_wdev) - return; - - switch (event) { -@@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg8 - memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); - queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); - cfg80211_sched_dfs_chan_update(rdev); -- wdev = rdev->offchan_radar_wdev; -+ wdev = rdev->background_radar_wdev; - break; - case NL80211_RADAR_CAC_ABORTED: -- if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) -+ if (!cancel_delayed_work(&rdev->background_cac_done_wk)) - return; -- wdev = rdev->offchan_radar_wdev; -+ wdev = rdev->background_radar_wdev; - break; - case NL80211_RADAR_CAC_STARTED: - break; -@@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg8 - } - - static void --cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, -- const struct cfg80211_chan_def *chandef, -- enum nl80211_radar_event event) -+cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, -+ const struct cfg80211_chan_def *chandef, -+ enum nl80211_radar_event event) - { - wiphy_lock(&rdev->wiphy); -- __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, -- chandef, event); -+ __cfg80211_background_cac_event(rdev, rdev->background_radar_wdev, -+ chandef, event); - wiphy_unlock(&rdev->wiphy); - } - --void cfg80211_offchan_cac_done_wk(struct work_struct *work) -+void cfg80211_background_cac_done_wk(struct work_struct *work) - { - struct delayed_work *delayed_work = to_delayed_work(work); - struct cfg80211_registered_device *rdev; - - rdev = container_of(delayed_work, struct cfg80211_registered_device, -- offchan_cac_done_wk); -- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, -- NL80211_RADAR_CAC_FINISHED); -+ background_cac_done_wk); -+ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, -+ NL80211_RADAR_CAC_FINISHED); - } - --void cfg80211_offchan_cac_abort_wk(struct work_struct *work) -+void cfg80211_background_cac_abort_wk(struct work_struct *work) - { - struct cfg80211_registered_device *rdev; - - rdev = container_of(work, struct cfg80211_registered_device, -- offchan_cac_abort_wk); -- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, -- NL80211_RADAR_CAC_ABORTED); -+ background_cac_abort_wk); -+ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, -+ NL80211_RADAR_CAC_ABORTED); - } - --void cfg80211_offchan_cac_abort(struct wiphy *wiphy) -+void cfg80211_background_cac_abort(struct wiphy *wiphy) - { - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - -- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); -+ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); - } --EXPORT_SYMBOL(cfg80211_offchan_cac_abort); -+EXPORT_SYMBOL(cfg80211_background_cac_abort); - - int --cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, -- struct wireless_dev *wdev, -- struct cfg80211_chan_def *chandef) -+cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, -+ struct wireless_dev *wdev, -+ struct cfg80211_chan_def *chandef) - { - unsigned int cac_time_ms; - int err; -@@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(s - lockdep_assert_wiphy(&rdev->wiphy); - - if (!wiphy_ext_feature_isset(&rdev->wiphy, -- NL80211_EXT_FEATURE_RADAR_OFFCHAN)) -+ NL80211_EXT_FEATURE_RADAR_BACKGROUND)) - return -EOPNOTSUPP; - - /* Offchannel chain already locked by another wdev */ -- if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) -+ if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev) - return -EBUSY; - - /* CAC already in progress on the offchannel chain */ -- if (rdev->offchan_radar_wdev == wdev && -- delayed_work_pending(&rdev->offchan_cac_done_wk)) -+ if (rdev->background_radar_wdev == wdev && -+ delayed_work_pending(&rdev->background_cac_done_wk)) - return -EBUSY; - -- err = rdev_set_radar_offchan(rdev, chandef); -+ err = rdev_set_radar_background(rdev, chandef); - if (err) - return err; - -@@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(s - if (!cac_time_ms) - cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; - -- rdev->offchan_radar_chandef = *chandef; -- rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ -+ rdev->background_radar_chandef = *chandef; -+ rdev->background_radar_wdev = wdev; /* Get offchain ownership */ - -- __cfg80211_offchan_cac_event(rdev, wdev, chandef, -- NL80211_RADAR_CAC_STARTED); -- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, -+ __cfg80211_background_cac_event(rdev, wdev, chandef, -+ NL80211_RADAR_CAC_STARTED); -+ queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk, - msecs_to_jiffies(cac_time_ms)); - - return 0; - } - --void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) -+void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev) - { - struct wiphy *wiphy = wdev->wiphy; - struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); - - lockdep_assert_wiphy(wiphy); - -- if (wdev != rdev->offchan_radar_wdev) -+ if (wdev != rdev->background_radar_wdev) - return; - -- rdev_set_radar_offchan(rdev, NULL); -- rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ -+ rdev_set_radar_background(rdev, NULL); -+ rdev->background_radar_wdev = NULL; /* Release offchain ownership */ - -- __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, -- NL80211_RADAR_CAC_ABORTED); -+ __cfg80211_background_cac_event(rdev, wdev, -+ &rdev->background_radar_chandef, -+ NL80211_RADAR_CAC_ABORTED); - } ---- a/net/wireless/nl80211.c -+++ b/net/wireless/nl80211.c -@@ -801,7 +801,7 @@ static const struct nla_policy nl80211_p - [NL80211_ATTR_MBSSID_CONFIG] = - NLA_POLICY_NESTED(nl80211_mbssid_config_policy), - [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, -- [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, -+ [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, - }; - - /* policy for the key attributes */ -@@ -9306,9 +9306,9 @@ static int nl80211_start_radar_detection - goto unlock; - } - -- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { -- err = cfg80211_start_offchan_radar_detection(rdev, wdev, -- &chandef); -+ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) { -+ err = cfg80211_start_background_radar_detection(rdev, wdev, -+ &chandef); - goto unlock; - } - ---- a/net/wireless/rdev-ops.h -+++ b/net/wireless/rdev-ops.h -@@ -1382,17 +1382,17 @@ static inline int rdev_color_change(stru - } - - static inline int --rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, -- struct cfg80211_chan_def *chandef) -+rdev_set_radar_background(struct cfg80211_registered_device *rdev, -+ struct cfg80211_chan_def *chandef) - { - struct wiphy *wiphy = &rdev->wiphy; - int ret; - -- if (!rdev->ops->set_radar_offchan) -+ if (!rdev->ops->set_radar_background) - return -EOPNOTSUPP; - -- trace_rdev_set_radar_offchan(wiphy, chandef); -- ret = rdev->ops->set_radar_offchan(wiphy, chandef); -+ trace_rdev_set_radar_background(wiphy, chandef); -+ ret = rdev->ops->set_radar_background(wiphy, chandef); - trace_rdev_return_int(wiphy, ret); - - return ret; ---- a/net/wireless/trace.h -+++ b/net/wireless/trace.h -@@ -3646,7 +3646,7 @@ TRACE_EVENT(cfg80211_bss_color_notify, - __entry->color_bitmap) - ); - --TRACE_EVENT(rdev_set_radar_offchan, -+TRACE_EVENT(rdev_set_radar_background, - TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), - - TP_ARGS(wiphy, chandef), diff --git a/package/kernel/mac80211/patches/subsys/320-v5.17-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch b/package/kernel/mac80211/patches/subsys/320-v5.17-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch new file mode 100644 index 0000000000..483b87cd88 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/320-v5.17-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch @@ -0,0 +1,532 @@ +From: Lorenzo Bianconi +Date: Mon, 29 Nov 2021 14:11:24 +0100 +Subject: [PATCH] cfg80211: rename offchannel_chain structs to background_chain + to avoid confusion with ETSI standard + +ETSI standard defines "Offchannel CAC" as: +"Off-Channel CAC is performed by a number of non-continuous checks +spread over a period in time. This period, which is required to +determine the presence of radar signals, is defined as the Off-Channel +CAC Time.. +Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time +4 hours..". +mac80211 implementation refers to a dedicated hw chain used for continuous +radar monitoring. Rename offchannel_* references to background_* in +order to avoid confusion with ETSI standard. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -4058,14 +4058,14 @@ struct mgmt_frame_regs { + * + * @color_change: Initiate a color change. + * +- * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * @set_radar_background: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to +- * disable offchannel CAC/radar detection. ++ * disable background CAC/radar detection. + */ + struct cfg80211_ops { + int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); +@@ -4396,8 +4396,8 @@ struct cfg80211_ops { + int (*color_change)(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_color_change_settings *params); +- int (*set_radar_offchan)(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef); ++ int (*set_radar_background)(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef); + }; + + /* +@@ -7601,9 +7601,9 @@ cfg80211_radar_event(struct wiphy *wiphy + } + + static inline void +-cfg80211_offchan_radar_event(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef, +- gfp_t gfp) ++cfg80211_background_radar_event(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef, ++ gfp_t gfp) + { + __cfg80211_radar_event(wiphy, chandef, true, gfp); + } +@@ -7638,13 +7638,13 @@ void cfg80211_cac_event(struct net_devic + enum nl80211_radar_event event, gfp_t gfp); + + /** +- * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event ++ * cfg80211_background_cac_abort - Channel Availability Check offchan abort event + * @wiphy: the wiphy + * + * This function is called by the driver when a Channel Availability Check + * (CAC) is aborted by a offchannel dedicated chain. + */ +-void cfg80211_offchan_cac_abort(struct wiphy *wiphy); ++void cfg80211_background_cac_abort(struct wiphy *wiphy); + + /** + * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3937,14 +3937,14 @@ struct ieee80211_prep_tx_info { + * twt structure. + * @twt_teardown_request: Update the hw with TWT teardown request received + * from the peer. +- * @set_radar_offchan: Configure dedicated offchannel chain available for ++ * @set_radar_background: Configure dedicated offchannel chain available for + * radar/CAC detection on some hw. This chain can't be used to transmit + * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching to a different channel during CAC detection on the selected + * radar channel. + * The caller is expected to set chandef pointer to NULL in order to +- * disable offchannel CAC/radar detection. ++ * disable background CAC/radar detection. + * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to + * resolve a path for hardware flow offloading + */ +@@ -4275,8 +4275,8 @@ struct ieee80211_ops { + struct ieee80211_twt_setup *twt); + void (*twt_teardown_request)(struct ieee80211_hw *hw, + struct ieee80211_sta *sta, u8 flowid); +- int (*set_radar_offchan)(struct ieee80211_hw *hw, +- struct cfg80211_chan_def *chandef); ++ int (*set_radar_background)(struct ieee80211_hw *hw, ++ struct cfg80211_chan_def *chandef); + #if LINUX_VERSION_IS_GEQ(5,10,0) + int (*net_fill_forward_path)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +--- a/include/uapi/linux/nl80211.h ++++ b/include/uapi/linux/nl80211.h +@@ -2608,10 +2608,10 @@ enum nl80211_commands { + * Mandatory parameter for the transmitting interface to enable MBSSID. + * Optional for the non-transmitting interfaces. + * +- * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for +- * radar/CAC detection on some hw. This chain can't be used to transmit +- * or receive frames and it is bounded to a running wdev. +- * Offchannel radar/CAC detection allows to avoid the CAC downtime ++ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain ++ * available for radar/CAC detection on some hw. This chain can't be used ++ * to transmit or receive frames and it is bounded to a running wdev. ++ * Background radar/CAC detection allows to avoid the CAC downtime + * switching on a different channel during CAC detection on the selected + * radar channel. + * +@@ -3121,7 +3121,7 @@ enum nl80211_attrs { + NL80211_ATTR_MBSSID_CONFIG, + NL80211_ATTR_MBSSID_ELEMS, + +- NL80211_ATTR_RADAR_OFFCHAN, ++ NL80211_ATTR_RADAR_BACKGROUND, + + /* add attributes here, update the policy in nl80211.c */ + +@@ -6022,7 +6022,7 @@ enum nl80211_feature_flags { + * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision + * detection and change announcemnts. + * +- * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC ++ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC + * detection. + * + * @NUM_NL80211_EXT_FEATURES: number of extended features. +@@ -6090,7 +6090,7 @@ enum nl80211_ext_feature_index { + NL80211_EXT_FEATURE_SECURE_RTT, + NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE, + NL80211_EXT_FEATURE_BSS_COLOR, +- NL80211_EXT_FEATURE_RADAR_OFFCHAN, ++ NL80211_EXT_FEATURE_RADAR_BACKGROUND, + + /* add new features before the definition below */ + NUM_NL80211_EXT_FEATURES, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -4345,15 +4345,15 @@ out: + } + + static int +-ieee80211_set_radar_offchan(struct wiphy *wiphy, +- struct cfg80211_chan_def *chandef) ++ieee80211_set_radar_background(struct wiphy *wiphy, ++ struct cfg80211_chan_def *chandef) + { + struct ieee80211_local *local = wiphy_priv(wiphy); + +- if (!local->ops->set_radar_offchan) ++ if (!local->ops->set_radar_background) + return -EOPNOTSUPP; + +- return local->ops->set_radar_offchan(&local->hw, chandef); ++ return local->ops->set_radar_background(&local->hw, chandef); + } + + const struct cfg80211_ops mac80211_config_ops = { +@@ -4460,5 +4460,5 @@ const struct cfg80211_ops mac80211_confi + .reset_tid_config = ieee80211_reset_tid_config, + .set_sar_specs = ieee80211_set_sar_specs, + .color_change = ieee80211_color_change, +- .set_radar_offchan = ieee80211_set_radar_offchan, ++ .set_radar_background = ieee80211_set_radar_background, + }; +--- a/net/wireless/chan.c ++++ b/net/wireless/chan.c +@@ -716,13 +716,13 @@ static bool + cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev, + struct ieee80211_channel *channel) + { +- if (!rdev->offchan_radar_wdev) ++ if (!rdev->background_radar_wdev) + return false; + +- if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef)) ++ if (!cfg80211_chandef_valid(&rdev->background_radar_chandef)) + return false; + +- return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel); ++ return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel); + } + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, +--- a/net/wireless/core.c ++++ b/net/wireless/core.c +@@ -543,9 +543,10 @@ use_default_name: + INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work); + INIT_WORK(&rdev->conn_work, cfg80211_conn_work); + INIT_WORK(&rdev->event_work, cfg80211_event_work); +- INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk); +- INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk, +- cfg80211_offchan_cac_done_wk); ++ INIT_WORK(&rdev->background_cac_abort_wk, ++ cfg80211_background_cac_abort_wk); ++ INIT_DELAYED_WORK(&rdev->background_cac_done_wk, ++ cfg80211_background_cac_done_wk); + + init_waitqueue_head(&rdev->dev_wait); + +@@ -1055,13 +1056,13 @@ void wiphy_unregister(struct wiphy *wiph + cancel_work_sync(&rdev->conn_work); + flush_work(&rdev->event_work); + cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); +- cancel_delayed_work_sync(&rdev->offchan_cac_done_wk); ++ cancel_delayed_work_sync(&rdev->background_cac_done_wk); + flush_work(&rdev->destroy_work); + flush_work(&rdev->sched_scan_stop_wk); + flush_work(&rdev->propagate_radar_detect_wk); + flush_work(&rdev->propagate_cac_done_wk); + flush_work(&rdev->mgmt_registrations_update_wk); +- flush_work(&rdev->offchan_cac_abort_wk); ++ flush_work(&rdev->background_cac_abort_wk); + + #ifdef CONFIG_PM + if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) +@@ -1210,7 +1211,7 @@ void __cfg80211_leave(struct cfg80211_re + + cfg80211_pmsr_wdev_down(wdev); + +- cfg80211_stop_offchan_radar_detection(wdev); ++ cfg80211_stop_background_radar_detection(wdev); + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: +--- a/net/wireless/core.h ++++ b/net/wireless/core.h +@@ -84,10 +84,10 @@ struct cfg80211_registered_device { + + struct delayed_work dfs_update_channels_wk; + +- struct wireless_dev *offchan_radar_wdev; +- struct cfg80211_chan_def offchan_radar_chandef; +- struct delayed_work offchan_cac_done_wk; +- struct work_struct offchan_cac_abort_wk; ++ struct wireless_dev *background_radar_wdev; ++ struct cfg80211_chan_def background_radar_chandef; ++ struct delayed_work background_cac_done_wk; ++ struct work_struct background_cac_abort_wk; + + /* netlink port which started critical protocol (0 means not started) */ + u32 crit_proto_nlportid; +@@ -497,15 +497,15 @@ cfg80211_chandef_dfs_cac_time(struct wip + void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev); + + int +-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- struct cfg80211_chan_def *chandef); ++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef); + +-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev); ++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev); + +-void cfg80211_offchan_cac_done_wk(struct work_struct *work); ++void cfg80211_background_cac_done_wk(struct work_struct *work); + +-void cfg80211_offchan_cac_abort_wk(struct work_struct *work); ++void cfg80211_background_cac_abort_wk(struct work_struct *work); + + bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan); +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy + cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE); + + if (offchan) +- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); + + cfg80211_sched_dfs_chan_update(rdev); + +@@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_devic + EXPORT_SYMBOL(cfg80211_cac_event); + + static void +-__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) + { + struct wiphy *wiphy = &rdev->wiphy; + struct net_device *netdev; +@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8 + if (!cfg80211_chandef_valid(chandef)) + return; + +- if (!rdev->offchan_radar_wdev) ++ if (!rdev->background_radar_wdev) + return; + + switch (event) { +@@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg8 + memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef)); + queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk); + cfg80211_sched_dfs_chan_update(rdev); +- wdev = rdev->offchan_radar_wdev; ++ wdev = rdev->background_radar_wdev; + break; + case NL80211_RADAR_CAC_ABORTED: +- if (!cancel_delayed_work(&rdev->offchan_cac_done_wk)) ++ if (!cancel_delayed_work(&rdev->background_cac_done_wk)) + return; +- wdev = rdev->offchan_radar_wdev; ++ wdev = rdev->background_radar_wdev; + break; + case NL80211_RADAR_CAC_STARTED: + break; +@@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg8 + } + + static void +-cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev, +- const struct cfg80211_chan_def *chandef, +- enum nl80211_radar_event event) ++cfg80211_background_cac_event(struct cfg80211_registered_device *rdev, ++ const struct cfg80211_chan_def *chandef, ++ enum nl80211_radar_event event) + { + wiphy_lock(&rdev->wiphy); +- __cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev, +- chandef, event); ++ __cfg80211_background_cac_event(rdev, rdev->background_radar_wdev, ++ chandef, event); + wiphy_unlock(&rdev->wiphy); + } + +-void cfg80211_offchan_cac_done_wk(struct work_struct *work) ++void cfg80211_background_cac_done_wk(struct work_struct *work) + { + struct delayed_work *delayed_work = to_delayed_work(work); + struct cfg80211_registered_device *rdev; + + rdev = container_of(delayed_work, struct cfg80211_registered_device, +- offchan_cac_done_wk); +- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_FINISHED); ++ background_cac_done_wk); ++ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_FINISHED); + } + +-void cfg80211_offchan_cac_abort_wk(struct work_struct *work) ++void cfg80211_background_cac_abort_wk(struct work_struct *work) + { + struct cfg80211_registered_device *rdev; + + rdev = container_of(work, struct cfg80211_registered_device, +- offchan_cac_abort_wk); +- cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_ABORTED); ++ background_cac_abort_wk); ++ cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); + } + +-void cfg80211_offchan_cac_abort(struct wiphy *wiphy) ++void cfg80211_background_cac_abort(struct wiphy *wiphy) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + +- queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk); ++ queue_work(cfg80211_wq, &rdev->background_cac_abort_wk); + } +-EXPORT_SYMBOL(cfg80211_offchan_cac_abort); ++EXPORT_SYMBOL(cfg80211_background_cac_abort); + + int +-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev, +- struct wireless_dev *wdev, +- struct cfg80211_chan_def *chandef) ++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev, ++ struct wireless_dev *wdev, ++ struct cfg80211_chan_def *chandef) + { + unsigned int cac_time_ms; + int err; +@@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(s + lockdep_assert_wiphy(&rdev->wiphy); + + if (!wiphy_ext_feature_isset(&rdev->wiphy, +- NL80211_EXT_FEATURE_RADAR_OFFCHAN)) ++ NL80211_EXT_FEATURE_RADAR_BACKGROUND)) + return -EOPNOTSUPP; + + /* Offchannel chain already locked by another wdev */ +- if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev) ++ if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev) + return -EBUSY; + + /* CAC already in progress on the offchannel chain */ +- if (rdev->offchan_radar_wdev == wdev && +- delayed_work_pending(&rdev->offchan_cac_done_wk)) ++ if (rdev->background_radar_wdev == wdev && ++ delayed_work_pending(&rdev->background_cac_done_wk)) + return -EBUSY; + +- err = rdev_set_radar_offchan(rdev, chandef); ++ err = rdev_set_radar_background(rdev, chandef); + if (err) + return err; + +@@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(s + if (!cac_time_ms) + cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS; + +- rdev->offchan_radar_chandef = *chandef; +- rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */ ++ rdev->background_radar_chandef = *chandef; ++ rdev->background_radar_wdev = wdev; /* Get offchain ownership */ + +- __cfg80211_offchan_cac_event(rdev, wdev, chandef, +- NL80211_RADAR_CAC_STARTED); +- queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk, ++ __cfg80211_background_cac_event(rdev, wdev, chandef, ++ NL80211_RADAR_CAC_STARTED); ++ queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk, + msecs_to_jiffies(cac_time_ms)); + + return 0; + } + +-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev) ++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev) + { + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy); + + lockdep_assert_wiphy(wiphy); + +- if (wdev != rdev->offchan_radar_wdev) ++ if (wdev != rdev->background_radar_wdev) + return; + +- rdev_set_radar_offchan(rdev, NULL); +- rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */ ++ rdev_set_radar_background(rdev, NULL); ++ rdev->background_radar_wdev = NULL; /* Release offchain ownership */ + +- __cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef, +- NL80211_RADAR_CAC_ABORTED); ++ __cfg80211_background_cac_event(rdev, wdev, ++ &rdev->background_radar_chandef, ++ NL80211_RADAR_CAC_ABORTED); + } +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -801,7 +801,7 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_MBSSID_CONFIG] = + NLA_POLICY_NESTED(nl80211_mbssid_config_policy), + [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED }, +- [NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG }, ++ [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG }, + }; + + /* policy for the key attributes */ +@@ -9306,9 +9306,9 @@ static int nl80211_start_radar_detection + goto unlock; + } + +- if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) { +- err = cfg80211_start_offchan_radar_detection(rdev, wdev, +- &chandef); ++ if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) { ++ err = cfg80211_start_background_radar_detection(rdev, wdev, ++ &chandef); + goto unlock; + } + +--- a/net/wireless/rdev-ops.h ++++ b/net/wireless/rdev-ops.h +@@ -1382,17 +1382,17 @@ static inline int rdev_color_change(stru + } + + static inline int +-rdev_set_radar_offchan(struct cfg80211_registered_device *rdev, +- struct cfg80211_chan_def *chandef) ++rdev_set_radar_background(struct cfg80211_registered_device *rdev, ++ struct cfg80211_chan_def *chandef) + { + struct wiphy *wiphy = &rdev->wiphy; + int ret; + +- if (!rdev->ops->set_radar_offchan) ++ if (!rdev->ops->set_radar_background) + return -EOPNOTSUPP; + +- trace_rdev_set_radar_offchan(wiphy, chandef); +- ret = rdev->ops->set_radar_offchan(wiphy, chandef); ++ trace_rdev_set_radar_background(wiphy, chandef); ++ ret = rdev->ops->set_radar_background(wiphy, chandef); + trace_rdev_return_int(wiphy, ret); + + return ret; +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -3646,7 +3646,7 @@ TRACE_EVENT(cfg80211_bss_color_notify, + __entry->color_bitmap) + ); + +-TRACE_EVENT(rdev_set_radar_offchan, ++TRACE_EVENT(rdev_set_radar_background, + TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef), + + TP_ARGS(wiphy, chandef), diff --git a/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch deleted file mode 100644 index a135e3d1b5..0000000000 --- a/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch +++ /dev/null @@ -1,144 +0,0 @@ -From: John Crispin -Date: Wed, 15 Sep 2021 19:54:35 -0700 -Subject: [PATCH] mac80211: MBSSID support in interface handling - -Configure multiple BSSID and enhanced multi-BSSID advertisement (EMA) -parameters in mac80211 for AP mode. - -For each interface, 'mbssid_tx_vif' points to the transmitting interface of -the MBSSID set. The pointer is set to NULL if MBSSID is disabled. - -Function ieee80211_stop() is modified to always bring down all the -non-transmitting interfaces first and the transmitting interface last. - -Signed-off-by: John Crispin -Co-developed-by: Aloka Dixit -Signed-off-by: Aloka Dixit -Link: https://lore.kernel.org/r/20210916025437.29138-3-alokad@codeaurora.org -[slightly change logic to be more obvious] -Signed-off-by: Johannes Berg ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -1719,6 +1719,7 @@ enum ieee80211_offload_flags { - * 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. -+ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled. - */ - struct ieee80211_vif { - enum nl80211_iftype type; -@@ -1750,6 +1751,8 @@ struct ieee80211_vif { - bool color_change_active; - u8 color_change_color; - -+ struct ieee80211_vif *mbssid_tx_vif; -+ - /* must be last */ - u8 drv_priv[] __aligned(sizeof(void *)); - }; ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -112,6 +112,36 @@ static int ieee80211_set_mon_options(str - return 0; - } - -+static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata, -+ struct cfg80211_mbssid_config params) -+{ -+ struct ieee80211_sub_if_data *tx_sdata; -+ -+ sdata->vif.mbssid_tx_vif = NULL; -+ sdata->vif.bss_conf.bssid_index = 0; -+ sdata->vif.bss_conf.nontransmitted = false; -+ sdata->vif.bss_conf.ema_ap = false; -+ -+ if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev) -+ return -EINVAL; -+ -+ tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev); -+ if (!tx_sdata) -+ return -EINVAL; -+ -+ if (tx_sdata == sdata) { -+ sdata->vif.mbssid_tx_vif = &sdata->vif; -+ } else { -+ sdata->vif.mbssid_tx_vif = &tx_sdata->vif; -+ sdata->vif.bss_conf.nontransmitted = true; -+ sdata->vif.bss_conf.bssid_index = params.index; -+ } -+ if (params.ema) -+ sdata->vif.bss_conf.ema_ap = true; -+ -+ return 0; -+} -+ - static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, - const char *name, - unsigned char name_assign_type, -@@ -1107,6 +1137,14 @@ static int ieee80211_start_ap(struct wip - changed |= BSS_CHANGED_HE_BSS_COLOR; - } - -+ if (sdata->vif.type == NL80211_IFTYPE_AP && -+ params->mbssid_config.tx_wdev) { -+ err = ieee80211_set_ap_mbssid_options(sdata, -+ params->mbssid_config); -+ if (err) -+ return err; -+ } -+ - mutex_lock(&local->mtx); - err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, - IEEE80211_CHANCTX_SHARED); ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct iee - ieee80211_add_virtual_monitor(local); - } - -+static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) -+{ -+ struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata; -+ struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif; -+ -+ if (!tx_vif) -+ return; -+ -+ tx_sdata = vif_to_sdata(tx_vif); -+ sdata->vif.mbssid_tx_vif = NULL; -+ -+ list_for_each_entry_safe(non_tx_sdata, tmp_sdata, -+ &tx_sdata->local->interfaces, list) { -+ if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata && -+ non_tx_sdata->vif.mbssid_tx_vif == tx_vif && -+ ieee80211_sdata_running(non_tx_sdata)) { -+ non_tx_sdata->vif.mbssid_tx_vif = NULL; -+ dev_close(non_tx_sdata->wdev.netdev); -+ } -+ } -+ -+ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) { -+ tx_sdata->vif.mbssid_tx_vif = NULL; -+ dev_close(tx_sdata->wdev.netdev); -+ } -+} -+ - static int ieee80211_stop(struct net_device *dev) - { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - -- /* close all dependent VLAN interfaces before locking wiphy */ -+ /* close dependent VLAN and MBSSID interfaces before locking wiphy */ - if (sdata->vif.type == NL80211_IFTYPE_AP) { - struct ieee80211_sub_if_data *vlan, *tmpsdata; - - list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, - u.vlan.list) - dev_close(vlan->dev); -+ -+ ieee80211_stop_mbssid(sdata); - } - - wiphy_lock(sdata->local->hw.wiphy); diff --git a/package/kernel/mac80211/patches/subsys/323-v5.16-mac80211-MBSSID-support-in-interface-handling.patch b/package/kernel/mac80211/patches/subsys/323-v5.16-mac80211-MBSSID-support-in-interface-handling.patch new file mode 100644 index 0000000000..a135e3d1b5 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/323-v5.16-mac80211-MBSSID-support-in-interface-handling.patch @@ -0,0 +1,144 @@ +From: John Crispin +Date: Wed, 15 Sep 2021 19:54:35 -0700 +Subject: [PATCH] mac80211: MBSSID support in interface handling + +Configure multiple BSSID and enhanced multi-BSSID advertisement (EMA) +parameters in mac80211 for AP mode. + +For each interface, 'mbssid_tx_vif' points to the transmitting interface of +the MBSSID set. The pointer is set to NULL if MBSSID is disabled. + +Function ieee80211_stop() is modified to always bring down all the +non-transmitting interfaces first and the transmitting interface last. + +Signed-off-by: John Crispin +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Link: https://lore.kernel.org/r/20210916025437.29138-3-alokad@codeaurora.org +[slightly change logic to be more obvious] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1719,6 +1719,7 @@ enum ieee80211_offload_flags { + * 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. ++ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled. + */ + struct ieee80211_vif { + enum nl80211_iftype type; +@@ -1750,6 +1751,8 @@ struct ieee80211_vif { + bool color_change_active; + u8 color_change_color; + ++ struct ieee80211_vif *mbssid_tx_vif; ++ + /* must be last */ + u8 drv_priv[] __aligned(sizeof(void *)); + }; +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -112,6 +112,36 @@ static int ieee80211_set_mon_options(str + return 0; + } + ++static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata, ++ struct cfg80211_mbssid_config params) ++{ ++ struct ieee80211_sub_if_data *tx_sdata; ++ ++ sdata->vif.mbssid_tx_vif = NULL; ++ sdata->vif.bss_conf.bssid_index = 0; ++ sdata->vif.bss_conf.nontransmitted = false; ++ sdata->vif.bss_conf.ema_ap = false; ++ ++ if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev) ++ return -EINVAL; ++ ++ tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev); ++ if (!tx_sdata) ++ return -EINVAL; ++ ++ if (tx_sdata == sdata) { ++ sdata->vif.mbssid_tx_vif = &sdata->vif; ++ } else { ++ sdata->vif.mbssid_tx_vif = &tx_sdata->vif; ++ sdata->vif.bss_conf.nontransmitted = true; ++ sdata->vif.bss_conf.bssid_index = params.index; ++ } ++ if (params.ema) ++ sdata->vif.bss_conf.ema_ap = true; ++ ++ return 0; ++} ++ + static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, +@@ -1107,6 +1137,14 @@ static int ieee80211_start_ap(struct wip + changed |= BSS_CHANGED_HE_BSS_COLOR; + } + ++ if (sdata->vif.type == NL80211_IFTYPE_AP && ++ params->mbssid_config.tx_wdev) { ++ err = ieee80211_set_ap_mbssid_options(sdata, ++ params->mbssid_config); ++ if (err) ++ return err; ++ } ++ + mutex_lock(&local->mtx); + err = ieee80211_vif_use_channel(sdata, ¶ms->chandef, + IEEE80211_CHANCTX_SHARED); +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct iee + ieee80211_add_virtual_monitor(local); + } + ++static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata; ++ struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif; ++ ++ if (!tx_vif) ++ return; ++ ++ tx_sdata = vif_to_sdata(tx_vif); ++ sdata->vif.mbssid_tx_vif = NULL; ++ ++ list_for_each_entry_safe(non_tx_sdata, tmp_sdata, ++ &tx_sdata->local->interfaces, list) { ++ if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata && ++ non_tx_sdata->vif.mbssid_tx_vif == tx_vif && ++ ieee80211_sdata_running(non_tx_sdata)) { ++ non_tx_sdata->vif.mbssid_tx_vif = NULL; ++ dev_close(non_tx_sdata->wdev.netdev); ++ } ++ } ++ ++ if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) { ++ tx_sdata->vif.mbssid_tx_vif = NULL; ++ dev_close(tx_sdata->wdev.netdev); ++ } ++} ++ + static int ieee80211_stop(struct net_device *dev) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + +- /* close all dependent VLAN interfaces before locking wiphy */ ++ /* close dependent VLAN and MBSSID interfaces before locking wiphy */ + if (sdata->vif.type == NL80211_IFTYPE_AP) { + struct ieee80211_sub_if_data *vlan, *tmpsdata; + + list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans, + u.vlan.list) + dev_close(vlan->dev); ++ ++ ieee80211_stop_mbssid(sdata); + } + + wiphy_lock(sdata->local->hw.wiphy); diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch deleted file mode 100644 index e2b05719db..0000000000 --- a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch +++ /dev/null @@ -1,326 +0,0 @@ -From: Lorenzo Bianconi -Date: Thu, 24 Feb 2022 12:54:58 +0100 -Subject: [PATCH] mac80211: MBSSID beacon handling in AP mode - -Add new fields in struct beacon_data to store all MBSSID elements. -Generate a beacon template which includes all MBSSID elements. -Move CSA offset to reflect the MBSSID element length. - -Co-developed-by: Aloka Dixit -Signed-off-by: Aloka Dixit -Co-developed-by: John Crispin -Signed-off-by: John Crispin -Signed-off-by: Lorenzo Bianconi -Tested-by: Money Wang -Link: https://lore.kernel.org/r/5322db3c303f431adaf191ab31c45e151dde5465.1645702516.git.lorenzo@kernel.org -[small cleanups] -Signed-off-by: Johannes Berg ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -4938,12 +4938,14 @@ void ieee80211_report_low_ack(struct iee - * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets - * to countdown counters. This array can contain zero values which - * should be ignored. -+ * @mbssid_off: position of the multiple bssid element - */ - struct ieee80211_mutable_offsets { - u16 tim_offset; - u16 tim_length; - - u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; -+ u16 mbssid_off; - }; - - /** ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -989,11 +989,29 @@ static int ieee80211_set_ftm_responder_p - return 0; - } - -+static int -+ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst, -+ struct cfg80211_mbssid_elems *src) -+{ -+ int i, offset = 0; -+ -+ for (i = 0; i < src->cnt; i++) { -+ memcpy(pos + offset, src->elem[i].data, src->elem[i].len); -+ dst->elem[i].len = src->elem[i].len; -+ dst->elem[i].data = pos + offset; -+ offset += dst->elem[i].len; -+ } -+ dst->cnt = src->cnt; -+ -+ return offset; -+} -+ - 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_color_change_settings *cca) - { -+ struct cfg80211_mbssid_elems *mbssid = NULL; - struct beacon_data *new, *old; - int new_head_len, new_tail_len; - int size, err; -@@ -1021,6 +1039,17 @@ static int ieee80211_assign_beacon(struc - - size = sizeof(*new) + new_head_len + new_tail_len; - -+ /* new or old multiple BSSID elements? */ -+ if (params->mbssid_ies) { -+ mbssid = params->mbssid_ies; -+ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); -+ size += ieee80211_get_mbssid_beacon_len(mbssid); -+ } else if (old && old->mbssid_ies) { -+ mbssid = old->mbssid_ies; -+ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); -+ size += ieee80211_get_mbssid_beacon_len(mbssid); -+ } -+ - new = kzalloc(size, GFP_KERNEL); - if (!new) - return -ENOMEM; -@@ -1029,12 +1058,20 @@ static int ieee80211_assign_beacon(struc - - /* - * pointers go into the block we allocated, -- * memory is | beacon_data | head | tail | -+ * memory is | beacon_data | head | tail | mbssid_ies - */ - new->head = ((u8 *) new) + sizeof(*new); - new->tail = new->head + new_head_len; - new->head_len = new_head_len; - new->tail_len = new_tail_len; -+ /* copy in optional mbssid_ies */ -+ if (mbssid) { -+ u8 *pos = new->tail + new->tail_len; -+ -+ new->mbssid_ies = (void *)pos; -+ pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); -+ ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); -+ } - - if (csa) { - new->cntdwn_current_counter = csa->count; -@@ -1332,8 +1369,11 @@ static int ieee80211_stop_ap(struct wiph - - mutex_unlock(&local->mtx); - -- kfree(sdata->u.ap.next_beacon); -- sdata->u.ap.next_beacon = NULL; -+ if (sdata->u.ap.next_beacon) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; -+ } - - /* turn off carrier for this interface and dependent VLANs */ - list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) -@@ -3126,12 +3166,24 @@ cfg80211_beacon_dup(struct cfg80211_beac - - len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len + - beacon->proberesp_ies_len + beacon->assocresp_ies_len + -- beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len; -+ beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len + -+ ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); - - new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL); - if (!new_beacon) - return NULL; - -+ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) { -+ new_beacon->mbssid_ies = -+ kzalloc(struct_size(new_beacon->mbssid_ies, -+ elem, beacon->mbssid_ies->cnt), -+ GFP_KERNEL); -+ if (!new_beacon->mbssid_ies) { -+ kfree(new_beacon); -+ return NULL; -+ } -+ } -+ - pos = (u8 *)(new_beacon + 1); - if (beacon->head_len) { - new_beacon->head_len = beacon->head_len; -@@ -3169,6 +3221,10 @@ cfg80211_beacon_dup(struct cfg80211_beac - memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); - pos += beacon->probe_resp_len; - } -+ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) -+ pos += ieee80211_copy_mbssid_beacon(pos, -+ new_beacon->mbssid_ies, -+ beacon->mbssid_ies); - - /* might copy -1, meaning no changes requested */ - new_beacon->ftm_responder = beacon->ftm_responder; -@@ -3206,8 +3262,11 @@ static int ieee80211_set_after_csa_beaco - case NL80211_IFTYPE_AP: - err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, - NULL, NULL); -- kfree(sdata->u.ap.next_beacon); -- sdata->u.ap.next_beacon = NULL; -+ if (sdata->u.ap.next_beacon) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; -+ } - - if (err < 0) - return err; -@@ -3362,8 +3421,12 @@ static int ieee80211_set_csa_beacon(stru - if ((params->n_counter_offsets_beacon > - IEEE80211_MAX_CNTDWN_COUNTERS_NUM) || - (params->n_counter_offsets_presp > -- IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) -+ IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; - return -EINVAL; -+ } - - csa.counter_offsets_beacon = params->counter_offsets_beacon; - csa.counter_offsets_presp = params->counter_offsets_presp; -@@ -3373,7 +3436,9 @@ static int ieee80211_set_csa_beacon(stru - - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); - if (err < 0) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); - kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; - return err; - } - *changed |= err; -@@ -3463,8 +3528,11 @@ static int ieee80211_set_csa_beacon(stru - 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; -+ if (sdata->u.ap.next_beacon) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; -+ } - - cfg80211_color_change_aborted_notify(sdata->dev); - } -@@ -4202,8 +4270,11 @@ ieee80211_set_after_color_change_beacon( - - 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 (sdata->u.ap.next_beacon) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; -+ } - - if (ret < 0) - return ret; -@@ -4246,7 +4317,11 @@ ieee80211_set_color_change_beacon(struct - err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, - NULL, &color_change); - if (err < 0) { -- kfree(sdata->u.ap.next_beacon); -+ if (sdata->u.ap.next_beacon) { -+ kfree(sdata->u.ap.next_beacon->mbssid_ies); -+ kfree(sdata->u.ap.next_beacon); -+ sdata->u.ap.next_beacon = NULL; -+ } - return err; - } - *changed |= err; ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -261,6 +261,7 @@ struct beacon_data { - struct ieee80211_meshconf_ie *meshconf; - u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; - u8 cntdwn_current_counter; -+ struct cfg80211_mbssid_elems *mbssid_ies; - struct rcu_head rcu_head; - }; - -@@ -1082,6 +1083,20 @@ ieee80211_vif_get_shift(struct ieee80211 - return shift; - } - -+static inline int -+ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems) -+{ -+ int i, len = 0; -+ -+ if (!elems) -+ return 0; -+ -+ for (i = 0; i < elems->cnt; i++) -+ len += elems->elem[i].len; -+ -+ return len; -+} -+ - enum { - IEEE80211_RX_MSG = 1, - IEEE80211_TX_STATUS_MSG = 2, ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -5041,6 +5041,19 @@ ieee80211_beacon_get_finish(struct ieee8 - IEEE80211_TX_CTL_FIRST_FRAGMENT; - } - -+static void -+ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon) -+{ -+ int i; -+ -+ if (!beacon->mbssid_ies) -+ return; -+ -+ for (i = 0; i < beacon->mbssid_ies->cnt; i++) -+ skb_put_data(skb, beacon->mbssid_ies->elem[i].data, -+ beacon->mbssid_ies->elem[i].len); -+} -+ - static struct sk_buff * - ieee80211_beacon_get_ap(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, -@@ -5054,6 +5067,7 @@ ieee80211_beacon_get_ap(struct ieee80211 - struct ieee80211_if_ap *ap = &sdata->u.ap; - struct sk_buff *skb = NULL; - u16 csa_off_base = 0; -+ int mbssid_len; - - if (beacon->cntdwn_counter_offsets[0]) { - if (!is_template) -@@ -5063,11 +5077,12 @@ ieee80211_beacon_get_ap(struct ieee80211 - } - - /* headroom, head length, -- * tail length and maximum TIM length -+ * tail length, maximum TIM length and multiple BSSID length - */ -+ mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); - skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + - beacon->tail_len + 256 + -- local->hw.extra_beacon_tailroom); -+ local->hw.extra_beacon_tailroom + mbssid_len); - if (!skb) - return NULL; - -@@ -5081,6 +5096,11 @@ ieee80211_beacon_get_ap(struct ieee80211 - offs->tim_length = skb->len - beacon->head_len; - offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; - -+ if (mbssid_len) { -+ ieee80211_beacon_add_mbssid(skb, beacon); -+ offs->mbssid_off = skb->len - mbssid_len; -+ } -+ - /* for AP the csa offsets are from tail */ - csa_off_base = skb->len; - } diff --git a/package/kernel/mac80211/patches/subsys/324-v5.18-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-v5.18-mac80211-MBSSID-beacon-handling-in-AP-mode.patch new file mode 100644 index 0000000000..e2b05719db --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/324-v5.18-mac80211-MBSSID-beacon-handling-in-AP-mode.patch @@ -0,0 +1,326 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Feb 2022 12:54:58 +0100 +Subject: [PATCH] mac80211: MBSSID beacon handling in AP mode + +Add new fields in struct beacon_data to store all MBSSID elements. +Generate a beacon template which includes all MBSSID elements. +Move CSA offset to reflect the MBSSID element length. + +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Co-developed-by: John Crispin +Signed-off-by: John Crispin +Signed-off-by: Lorenzo Bianconi +Tested-by: Money Wang +Link: https://lore.kernel.org/r/5322db3c303f431adaf191ab31c45e151dde5465.1645702516.git.lorenzo@kernel.org +[small cleanups] +Signed-off-by: Johannes Berg +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -4938,12 +4938,14 @@ void ieee80211_report_low_ack(struct iee + * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets + * to countdown counters. This array can contain zero values which + * should be ignored. ++ * @mbssid_off: position of the multiple bssid element + */ + struct ieee80211_mutable_offsets { + u16 tim_offset; + u16 tim_length; + + u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; ++ u16 mbssid_off; + }; + + /** +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -989,11 +989,29 @@ static int ieee80211_set_ftm_responder_p + return 0; + } + ++static int ++ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst, ++ struct cfg80211_mbssid_elems *src) ++{ ++ int i, offset = 0; ++ ++ for (i = 0; i < src->cnt; i++) { ++ memcpy(pos + offset, src->elem[i].data, src->elem[i].len); ++ dst->elem[i].len = src->elem[i].len; ++ dst->elem[i].data = pos + offset; ++ offset += dst->elem[i].len; ++ } ++ dst->cnt = src->cnt; ++ ++ return offset; ++} ++ + 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_color_change_settings *cca) + { ++ struct cfg80211_mbssid_elems *mbssid = NULL; + struct beacon_data *new, *old; + int new_head_len, new_tail_len; + int size, err; +@@ -1021,6 +1039,17 @@ static int ieee80211_assign_beacon(struc + + size = sizeof(*new) + new_head_len + new_tail_len; + ++ /* new or old multiple BSSID elements? */ ++ if (params->mbssid_ies) { ++ mbssid = params->mbssid_ies; ++ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ size += ieee80211_get_mbssid_beacon_len(mbssid); ++ } else if (old && old->mbssid_ies) { ++ mbssid = old->mbssid_ies; ++ size += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ size += ieee80211_get_mbssid_beacon_len(mbssid); ++ } ++ + new = kzalloc(size, GFP_KERNEL); + if (!new) + return -ENOMEM; +@@ -1029,12 +1058,20 @@ static int ieee80211_assign_beacon(struc + + /* + * pointers go into the block we allocated, +- * memory is | beacon_data | head | tail | ++ * memory is | beacon_data | head | tail | mbssid_ies + */ + new->head = ((u8 *) new) + sizeof(*new); + new->tail = new->head + new_head_len; + new->head_len = new_head_len; + new->tail_len = new_tail_len; ++ /* copy in optional mbssid_ies */ ++ if (mbssid) { ++ u8 *pos = new->tail + new->tail_len; ++ ++ new->mbssid_ies = (void *)pos; ++ pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); ++ ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); ++ } + + if (csa) { + new->cntdwn_current_counter = csa->count; +@@ -1332,8 +1369,11 @@ static int ieee80211_stop_ap(struct wiph + + mutex_unlock(&local->mtx); + +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + /* turn off carrier for this interface and dependent VLANs */ + list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) +@@ -3126,12 +3166,24 @@ cfg80211_beacon_dup(struct cfg80211_beac + + len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len + + beacon->proberesp_ies_len + beacon->assocresp_ies_len + +- beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len; ++ beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len + ++ ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); + + new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL); + if (!new_beacon) + return NULL; + ++ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) { ++ new_beacon->mbssid_ies = ++ kzalloc(struct_size(new_beacon->mbssid_ies, ++ elem, beacon->mbssid_ies->cnt), ++ GFP_KERNEL); ++ if (!new_beacon->mbssid_ies) { ++ kfree(new_beacon); ++ return NULL; ++ } ++ } ++ + pos = (u8 *)(new_beacon + 1); + if (beacon->head_len) { + new_beacon->head_len = beacon->head_len; +@@ -3169,6 +3221,10 @@ cfg80211_beacon_dup(struct cfg80211_beac + memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); + pos += beacon->probe_resp_len; + } ++ if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) ++ pos += ieee80211_copy_mbssid_beacon(pos, ++ new_beacon->mbssid_ies, ++ beacon->mbssid_ies); + + /* might copy -1, meaning no changes requested */ + new_beacon->ftm_responder = beacon->ftm_responder; +@@ -3206,8 +3262,11 @@ static int ieee80211_set_after_csa_beaco + case NL80211_IFTYPE_AP: + err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon, + NULL, NULL); +- kfree(sdata->u.ap.next_beacon); +- sdata->u.ap.next_beacon = NULL; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + if (err < 0) + return err; +@@ -3362,8 +3421,12 @@ static int ieee80211_set_csa_beacon(stru + if ((params->n_counter_offsets_beacon > + IEEE80211_MAX_CNTDWN_COUNTERS_NUM) || + (params->n_counter_offsets_presp > +- IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) ++ IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; + return -EINVAL; ++ } + + csa.counter_offsets_beacon = params->counter_offsets_beacon; + csa.counter_offsets_presp = params->counter_offsets_presp; +@@ -3373,7 +3436,9 @@ static int ieee80211_set_csa_beacon(stru + + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_csa, &csa, NULL); + if (err < 0) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); + kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; + return err; + } + *changed |= err; +@@ -3463,8 +3528,11 @@ static int ieee80211_set_csa_beacon(stru + 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; ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + cfg80211_color_change_aborted_notify(sdata->dev); + } +@@ -4202,8 +4270,11 @@ ieee80211_set_after_color_change_beacon( + + 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 (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + + if (ret < 0) + return ret; +@@ -4246,7 +4317,11 @@ ieee80211_set_color_change_beacon(struct + err = ieee80211_assign_beacon(sdata, ¶ms->beacon_color_change, + NULL, &color_change); + if (err < 0) { +- kfree(sdata->u.ap.next_beacon); ++ if (sdata->u.ap.next_beacon) { ++ kfree(sdata->u.ap.next_beacon->mbssid_ies); ++ kfree(sdata->u.ap.next_beacon); ++ sdata->u.ap.next_beacon = NULL; ++ } + return err; + } + *changed |= err; +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -261,6 +261,7 @@ struct beacon_data { + struct ieee80211_meshconf_ie *meshconf; + u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM]; + u8 cntdwn_current_counter; ++ struct cfg80211_mbssid_elems *mbssid_ies; + struct rcu_head rcu_head; + }; + +@@ -1082,6 +1083,20 @@ ieee80211_vif_get_shift(struct ieee80211 + return shift; + } + ++static inline int ++ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems) ++{ ++ int i, len = 0; ++ ++ if (!elems) ++ return 0; ++ ++ for (i = 0; i < elems->cnt; i++) ++ len += elems->elem[i].len; ++ ++ return len; ++} ++ + enum { + IEEE80211_RX_MSG = 1, + IEEE80211_TX_STATUS_MSG = 2, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -5041,6 +5041,19 @@ ieee80211_beacon_get_finish(struct ieee8 + IEEE80211_TX_CTL_FIRST_FRAGMENT; + } + ++static void ++ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon) ++{ ++ int i; ++ ++ if (!beacon->mbssid_ies) ++ return; ++ ++ for (i = 0; i < beacon->mbssid_ies->cnt; i++) ++ skb_put_data(skb, beacon->mbssid_ies->elem[i].data, ++ beacon->mbssid_ies->elem[i].len); ++} ++ + static struct sk_buff * + ieee80211_beacon_get_ap(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, +@@ -5054,6 +5067,7 @@ ieee80211_beacon_get_ap(struct ieee80211 + struct ieee80211_if_ap *ap = &sdata->u.ap; + struct sk_buff *skb = NULL; + u16 csa_off_base = 0; ++ int mbssid_len; + + if (beacon->cntdwn_counter_offsets[0]) { + if (!is_template) +@@ -5063,11 +5077,12 @@ ieee80211_beacon_get_ap(struct ieee80211 + } + + /* headroom, head length, +- * tail length and maximum TIM length ++ * tail length, maximum TIM length and multiple BSSID length + */ ++ mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies); + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + + beacon->tail_len + 256 + +- local->hw.extra_beacon_tailroom); ++ local->hw.extra_beacon_tailroom + mbssid_len); + if (!skb) + return NULL; + +@@ -5081,6 +5096,11 @@ ieee80211_beacon_get_ap(struct ieee80211 + offs->tim_length = skb->len - beacon->head_len; + offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0]; + ++ if (mbssid_len) { ++ ieee80211_beacon_add_mbssid(skb, beacon); ++ offs->mbssid_off = skb->len - mbssid_len; ++ } ++ + /* for AP the csa offsets are from tail */ + csa_off_base = skb->len; + } diff --git a/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch deleted file mode 100644 index 38b0de180e..0000000000 --- a/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: John Crispin -Date: Thu, 24 Feb 2022 12:54:59 +0100 -Subject: [PATCH] mac80211: MBSSID channel switch - -Trigger ieee80211_csa_finish() on the non-transmitting interfaces -when channel switch concludes on the transmitting interface. - -Co-developed-by: Lorenzo Bianconi -Signed-off-by: Lorenzo Bianconi -Co-developed-by: Aloka Dixit -Signed-off-by: Aloka Dixit -Signed-off-by: John Crispin -Link: https://lore.kernel.org/r/6fde4d7f9fa387494f46a7aa4a584478dcda06f1.1645702516.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -3247,9 +3247,31 @@ cfg80211_beacon_dup(struct cfg80211_beac - void ieee80211_csa_finish(struct ieee80211_vif *vif) - { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); -+ struct ieee80211_local *local = sdata->local; - -- ieee80211_queue_work(&sdata->local->hw, -- &sdata->csa_finalize_work); -+ rcu_read_lock(); -+ -+ if (vif->mbssid_tx_vif == vif) { -+ /* Trigger ieee80211_csa_finish() on the non-transmitting -+ * interfaces when channel switch is received on -+ * transmitting interface -+ */ -+ struct ieee80211_sub_if_data *iter; -+ -+ list_for_each_entry_rcu(iter, &local->interfaces, list) { -+ if (!ieee80211_sdata_running(iter)) -+ continue; -+ -+ if (iter == sdata || iter->vif.mbssid_tx_vif != vif) -+ continue; -+ -+ ieee80211_queue_work(&iter->local->hw, -+ &iter->csa_finalize_work); -+ } -+ } -+ ieee80211_queue_work(&local->hw, &sdata->csa_finalize_work); -+ -+ rcu_read_unlock(); - } - EXPORT_SYMBOL(ieee80211_csa_finish); - diff --git a/package/kernel/mac80211/patches/subsys/325-v5.18-mac80211-MBSSID-channel-switch.patch b/package/kernel/mac80211/patches/subsys/325-v5.18-mac80211-MBSSID-channel-switch.patch new file mode 100644 index 0000000000..38b0de180e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/325-v5.18-mac80211-MBSSID-channel-switch.patch @@ -0,0 +1,52 @@ +From: John Crispin +Date: Thu, 24 Feb 2022 12:54:59 +0100 +Subject: [PATCH] mac80211: MBSSID channel switch + +Trigger ieee80211_csa_finish() on the non-transmitting interfaces +when channel switch concludes on the transmitting interface. + +Co-developed-by: Lorenzo Bianconi +Signed-off-by: Lorenzo Bianconi +Co-developed-by: Aloka Dixit +Signed-off-by: Aloka Dixit +Signed-off-by: John Crispin +Link: https://lore.kernel.org/r/6fde4d7f9fa387494f46a7aa4a584478dcda06f1.1645702516.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -3247,9 +3247,31 @@ cfg80211_beacon_dup(struct cfg80211_beac + void ieee80211_csa_finish(struct ieee80211_vif *vif) + { + struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_local *local = sdata->local; + +- ieee80211_queue_work(&sdata->local->hw, +- &sdata->csa_finalize_work); ++ rcu_read_lock(); ++ ++ if (vif->mbssid_tx_vif == vif) { ++ /* Trigger ieee80211_csa_finish() on the non-transmitting ++ * interfaces when channel switch is received on ++ * transmitting interface ++ */ ++ struct ieee80211_sub_if_data *iter; ++ ++ list_for_each_entry_rcu(iter, &local->interfaces, list) { ++ if (!ieee80211_sdata_running(iter)) ++ continue; ++ ++ if (iter == sdata || iter->vif.mbssid_tx_vif != vif) ++ continue; ++ ++ ieee80211_queue_work(&iter->local->hw, ++ &iter->csa_finalize_work); ++ } ++ } ++ ieee80211_queue_work(&local->hw, &sdata->csa_finalize_work); ++ ++ rcu_read_unlock(); + } + EXPORT_SYMBOL(ieee80211_csa_finish); + diff --git a/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch deleted file mode 100644 index 1955568607..0000000000 --- a/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Lorenzo Bianconi -Date: Thu, 24 Feb 2022 12:55:00 +0100 -Subject: [PATCH] mac80211: update bssid_indicator in - ieee80211_assign_beacon - -Update bssid_indicator in ieee80211_bss_conf according to the -number of bssid in the set. - -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/f92317e002fca9933f05a445fcefb4f53291d601.1645702516.git.lorenzo@kernel.org -Signed-off-by: Johannes Berg ---- - ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -1071,6 +1071,9 @@ static int ieee80211_assign_beacon(struc - new->mbssid_ies = (void *)pos; - pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); - ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); -+ /* update bssid_indicator */ -+ sdata->vif.bss_conf.bssid_indicator = -+ ilog2(__roundup_pow_of_two(mbssid->cnt + 1)); - } - - if (csa) { diff --git a/package/kernel/mac80211/patches/subsys/326-v5.18-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch b/package/kernel/mac80211/patches/subsys/326-v5.18-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch new file mode 100644 index 0000000000..1955568607 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/326-v5.18-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch @@ -0,0 +1,25 @@ +From: Lorenzo Bianconi +Date: Thu, 24 Feb 2022 12:55:00 +0100 +Subject: [PATCH] mac80211: update bssid_indicator in + ieee80211_assign_beacon + +Update bssid_indicator in ieee80211_bss_conf according to the +number of bssid in the set. + +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/f92317e002fca9933f05a445fcefb4f53291d601.1645702516.git.lorenzo@kernel.org +Signed-off-by: Johannes Berg +--- + +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1071,6 +1071,9 @@ static int ieee80211_assign_beacon(struc + new->mbssid_ies = (void *)pos; + pos += struct_size(new->mbssid_ies, elem, mbssid->cnt); + ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid); ++ /* update bssid_indicator */ ++ sdata->vif.bss_conf.bssid_indicator = ++ ilog2(__roundup_pow_of_two(mbssid->cnt + 1)); + } + + if (csa) { diff --git a/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch b/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch deleted file mode 100644 index f0150ddef0..0000000000 --- a/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch +++ /dev/null @@ -1,38 +0,0 @@ -From: Felix Fietkau -Date: Sat, 26 Mar 2022 23:58:35 +0100 -Subject: [PATCH] mac80211: do not wake queues on a vif that is being stopped - -When a vif is being removed and sdata->bss is cleared, __ieee80211_wake_txqs -can still be called on it, which crashes as soon as sdata->bss is being -dereferenced. -To fix this properly, check for SDATA_STATE_RUNNING before waking queues, -and take the fq lock when setting it (to ensure that __ieee80211_wake_txqs -observes the change when running on a different CPU - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct iee - bool cancel_scan; - struct cfg80211_nan_func *func; - -+ spin_lock_bh(&local->fq.lock); - clear_bit(SDATA_STATE_RUNNING, &sdata->state); -+ spin_unlock_bh(&local->fq.lock); - - cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; - if (cancel_scan) ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct - local_bh_disable(); - spin_lock(&fq->lock); - -+ if (!test_bit(SDATA_STATE_RUNNING, &sdata->state)) -+ goto out; -+ - if (sdata->vif.type == NL80211_IFTYPE_AP) - ps = &sdata->bss->ps; - diff --git a/package/kernel/mac80211/patches/subsys/328-v5.19-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch b/package/kernel/mac80211/patches/subsys/328-v5.19-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch new file mode 100644 index 0000000000..f0150ddef0 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/328-v5.19-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch @@ -0,0 +1,38 @@ +From: Felix Fietkau +Date: Sat, 26 Mar 2022 23:58:35 +0100 +Subject: [PATCH] mac80211: do not wake queues on a vif that is being stopped + +When a vif is being removed and sdata->bss is cleared, __ieee80211_wake_txqs +can still be called on it, which crashes as soon as sdata->bss is being +dereferenced. +To fix this properly, check for SDATA_STATE_RUNNING before waking queues, +and take the fq lock when setting it (to ensure that __ieee80211_wake_txqs +observes the change when running on a different CPU + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct iee + bool cancel_scan; + struct cfg80211_nan_func *func; + ++ spin_lock_bh(&local->fq.lock); + clear_bit(SDATA_STATE_RUNNING, &sdata->state); ++ spin_unlock_bh(&local->fq.lock); + + cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; + if (cancel_scan) +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct + local_bh_disable(); + spin_lock(&fq->lock); + ++ if (!test_bit(SDATA_STATE_RUNNING, &sdata->state)) ++ goto out; ++ + if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->bss->ps; + diff --git a/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch deleted file mode 100644 index e59036f5a2..0000000000 --- a/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch +++ /dev/null @@ -1,1249 +0,0 @@ -From: Felix Fietkau -Date: Sun, 19 Jun 2022 23:13:05 +0200 -Subject: [PATCH] mac80211: switch airtime fairness back to deficit round-robin - scheduling - -This reverts commits 6a789ba679d652587532cec2a0e0274fda172f3b and -2433647bc8d983a543e7d31b41ca2de1c7e2c198. - -The virtual time scheduler code has a number of issues: -- queues slowed down by hardware/firmware powersave handling were not properly - handled. -- on ath10k in push-pull mode, tx queues that the driver tries to pull from - were starved, causing excessive latency -- delay between tx enqueue and reported airtime use were causing excessively - bursty tx behavior - -The bursty behavior may also be present on the round-robin scheduler, but there -it is much easier to fix without introducing additional regressions - -Signed-off-by: Felix Fietkau ---- - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -6666,6 +6666,9 @@ 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 - * -@@ -6678,7 +6681,11 @@ static inline void ieee80211_txq_schedul - * The driver may call this function if it has buffered packets for - * this TXQ internally. - */ --void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); -+static inline void -+ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) -+{ -+ __ieee80211_schedule_txq(hw, txq, true); -+} - - /** - * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() -@@ -6690,8 +6697,12 @@ void ieee80211_schedule_txq(struct ieee8 - * The driver may set force=true if it has buffered packets for this TXQ - * internally. - */ --void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, -- bool force); -+static inline void -+ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, -+ bool force) -+{ -+ __ieee80211_schedule_txq(hw, txq, force); -+} - - /** - * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit ---- a/net/mac80211/cfg.c -+++ b/net/mac80211/cfg.c -@@ -1554,38 +1554,6 @@ 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) -@@ -1773,8 +1741,7 @@ static int sta_apply_parameters(struct i - sta_apply_mesh_params(local, sta, params); - - if (params->airtime_weight) -- sta_apply_airtime_params(local, sta, params); -- -+ sta->airtime_weight = params->airtime_weight; - - /* 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->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); -+ 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]); - 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->airtime[ac].aql_txq_limit_low; -- q_limit_high_old = local->airtime[ac].aql_txq_limit_high; -+ q_limit_low_old = local->aql_txq_limit_low[ac]; -+ q_limit_high_old = local->aql_txq_limit_high[ac]; - -- local->airtime[ac].aql_txq_limit_low = q_limit_low; -- local->airtime[ac].aql_txq_limit_high = q_limit_high; -+ local->aql_txq_limit_low[ac] = q_limit_low; -+ local->aql_txq_limit_high[ac] = q_limit_high; - - mutex_lock(&local->sta_mtx); - list_for_each_entry(sta, &local->sta_list, list) { -@@ -382,46 +382,6 @@ 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) -@@ -672,11 +632,7 @@ void debugfs_hw_add(struct ieee80211_loc - if (local->ops->wake_tx_queue) - DEBUGFS_ADD_MODE(aqm, 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_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 -@@ -512,34 +512,6 @@ 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 */ -@@ -685,10 +657,8 @@ 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; -- u64 v_t[IEEE80211_NUM_ACS]; -+ s64 deficit[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->airtime[ac].lock); -+ spin_lock_bh(&local->active_txq_lock[ac]); - rx_airtime += sta->airtime[ac].rx_airtime; - tx_airtime += sta->airtime[ac].tx_airtime; -- v_t[ac] = sta->airtime[ac].v_t; -- spin_unlock_bh(&local->airtime[ac].lock); -+ deficit[ac] = sta->airtime[ac].deficit; -+ spin_unlock_bh(&local->active_txq_lock[ac]); - } - - p += scnprintf(p, bufsz + buf - p, - "RX: %llu us\nTX: %llu us\nWeight: %u\n" -- "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]); -+ "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]); - - 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->airtime[ac].lock); -+ spin_lock_bh(&local->active_txq_lock[ac]); - sta->airtime[ac].rx_airtime = 0; - sta->airtime[ac].tx_airtime = 0; -- sta->airtime[ac].v_t = 0; -- spin_unlock_bh(&local->airtime[ac].lock); -+ sta->airtime[ac].deficit = sta->airtime_weight; -+ spin_unlock_bh(&local->active_txq_lock[ac]); - } - - 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->airtime[ac].lock); -+ spin_lock_bh(&local->active_txq_lock[ac]); - q_limit_l[ac] = sta->airtime[ac].aql_limit_low; - q_limit_h[ac] = sta->airtime[ac].aql_limit_high; -- spin_unlock_bh(&local->airtime[ac].lock); -+ spin_unlock_bh(&local->active_txq_lock[ac]); - q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); - } - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -862,16 +862,20 @@ 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 -- * @schedule_order: used with ieee80211_local->active_txqs - * @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 - */ - struct txq_info { - struct fq_tin tin; - struct codel_vars def_cvars; - struct codel_stats cstats; -- struct rb_node schedule_order; -+ -+ u16 schedule_round; -+ struct list_head schedule_order; - - struct sk_buff_head frags; -+ - unsigned long flags; - - /* keep last! */ -@@ -948,8 +952,6 @@ 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; -@@ -1184,44 +1186,6 @@ 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 { -@@ -1235,8 +1199,13 @@ struct ieee80211_local { - struct codel_params cparams; - - /* protects active_txqs and txqi->schedule_order */ -- struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; -+ spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; -+ struct list_head active_txqs[IEEE80211_NUM_ACS]; -+ u16 schedule_round[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; - -@@ -1660,125 +1629,6 @@ 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) || -@@ -2024,14 +1874,6 @@ 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 -@@ -2192,9 +2192,6 @@ 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 -@@ -707,13 +707,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - spin_lock_init(&local->queue_stop_reason_lock); - - for (i = 0; i < IEEE80211_NUM_ACS; 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 = -+ 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] = - IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; - } - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -1583,8 +1583,12 @@ 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); - -- ieee80211_unschedule_txq(&local->hw, txq, false); -+ 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]); - - 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,11 +426,15 @@ 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]); -- init_airtime_info(&sta->airtime[i], &local->airtime[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]; - } - - for (i = 0; i < IEEE80211_NUM_TIDS; i++) -@@ -1889,59 +1893,24 @@ void ieee80211_sta_set_buffered(struct i - } - EXPORT_SYMBOL(ieee80211_sta_set_buffered); - --void ieee80211_register_airtime(struct ieee80211_txq *txq, -- u32 tx_airtime, u32 rx_airtime) -+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, -+ u32 tx_airtime, u32 rx_airtime) - { -- 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; -+ 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); - u32 airtime = 0; - -- air_sched = &local->airtime[txq->ac]; -- air_info = to_airtime_info(txq); -- -- if (local->airtime_flags & AIRTIME_USE_TX) -+ if (sta->local->airtime_flags & AIRTIME_USE_TX) - airtime += tx_airtime; -- if (local->airtime_flags & AIRTIME_USE_RX) -+ if (sta->local->airtime_flags & AIRTIME_USE_RX) - airtime += rx_airtime; - -- /* 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); -+ 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]); - } - EXPORT_SYMBOL(ieee80211_sta_register_airtime); - -@@ -2385,7 +2354,7 @@ void sta_set_sinfo(struct sta_info *sta, - } - - if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { -- sinfo->airtime_weight = sta->airtime[0].weight; -+ sinfo->airtime_weight = sta->airtime_weight; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); - } - ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -135,25 +135,18 @@ 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; -- u64 v_t; -- u64 last_scheduled; -- struct list_head list; -+ s64 deficit; - 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; - -@@ -523,6 +516,7 @@ 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 -@@ -653,6 +647,7 @@ 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 -@@ -983,25 +983,6 @@ 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,7 +18,6 @@ - #include - #include - #include --#include - #include - #include - #include -@@ -1480,7 +1479,7 @@ void ieee80211_txq_init(struct ieee80211 - codel_vars_init(&txqi->def_cvars); - codel_stats_init(&txqi->cstats); - __skb_queue_head_init(&txqi->frags); -- RB_CLEAR_NODE(&txqi->schedule_order); -+ INIT_LIST_HEAD(&txqi->schedule_order); - - txqi->txq.vif = &sdata->vif; - -@@ -1524,7 +1523,9 @@ void ieee80211_txq_purge(struct ieee8021 - ieee80211_purge_tx_queue(&local->hw, &txqi->frags); - spin_unlock_bh(&fq->lock); - -- ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); -+ 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]); - } - - void ieee80211_txq_set_params(struct ieee80211_local *local) -@@ -3819,259 +3820,102 @@ 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_coarse_boottime_ns(); - struct ieee80211_txq *ret = NULL; -- struct airtime_info *air_info; -- struct txq_info *txqi = NULL; -- struct rb_node *node; -- bool first = false; -+ struct txq_info *txqi = NULL, *head = NULL; -+ bool found_eligible_txq = false; - -- air_sched = &local->airtime[ac]; -- spin_lock_bh(&air_sched->lock); -+ spin_lock_bh(&local->active_txq_lock[ac]); - -- 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; -- -- 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))) -+ begin: -+ txqi = list_first_entry_or_null(&local->active_txqs[ac], -+ struct txq_info, -+ schedule_order); -+ if (!txqi) - goto out; - -- if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { -- first = false; -- goto begin; -- } -- -- 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); -- --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 (new_air->v_t <= old_air->v_t) { -- new = &parent->rb_left; -- } else { -- new = &parent->rb_right; -- leftmost = false; -- } -+ if (txqi == head) { -+ if (!found_eligible_txq) -+ goto out; -+ else -+ found_eligible_txq = false; - } - -- 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]; -+ if (!head) -+ head = txqi; - -- 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; -+ 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; - -- /* 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 (aql_check) -+ found_eligible_txq = true; - -- 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 (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; - } -- -- 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_coarse_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_coarse_boottime_ns(); -- struct airtime_info *air_info; -- u8 ac = txq->ac; -- bool was_active; - -- 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)) -+ if (txqi->schedule_round == local->schedule_round[ac]) - goto out; - -- /* 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); -+ list_del_init(&txqi->schedule_order); -+ txqi->schedule_round = local->schedule_round[ac]; -+ ret = &txqi->txq; - - out: -- spin_unlock_bh(&air_sched->lock); --} --EXPORT_SYMBOL(ieee80211_schedule_txq); -- --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; -- -- air_sched = &local->airtime[txq->ac]; -- air_info = to_airtime_info(&txqi->txq); -- -- lockdep_assert_held(&air_sched->lock); -- -- if (purge) { -- list_del_init(&air_info->list); -- ieee80211_update_airtime_weight(local, air_sched, 0, true); -- } -- -- 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_coarse_boottime_ns()); -- -- rb_erase_cached(&txqi->schedule_order, -- &air_sched->active_txqs); -- RB_CLEAR_NODE(&txqi->schedule_order); -+ spin_unlock_bh(&local->active_txq_lock[ac]); -+ return ret; - } -+EXPORT_SYMBOL(ieee80211_next_txq); - --void ieee80211_unschedule_txq(struct ieee80211_hw *hw, -+void __ieee80211_schedule_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) -+ 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); -+ spin_lock_bh(&local->active_txq_lock[txq->ac]); - -- if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && -- !txq_has_queue(txq)) -- __ieee80211_unschedule_txq(hw, txq, false); -+ 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]); -+ } - -- spin_unlock_bh(&local->airtime[txq->ac].lock); -+ spin_unlock_bh(&local->active_txq_lock[txq->ac]); - } --EXPORT_SYMBOL(ieee80211_return_txq); -+EXPORT_SYMBOL(__ieee80211_schedule_txq); - - DEFINE_STATIC_KEY_FALSE(aql_disable); - - bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - { -- struct airtime_info *air_info = to_airtime_info(txq); -+ struct sta_info *sta; - struct ieee80211_local *local = hw_to_local(hw); - - if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) -@@ -4086,12 +3930,15 @@ bool ieee80211_txq_airtime_check(struct - if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) - return true; - -- if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) -+ 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) - return true; - - if (atomic_read(&local->aql_total_pending_airtime) < - local->aql_threshold && -- atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) -+ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < -+ sta->airtime[txq->ac].aql_limit_high) - return true; - - return false; -@@ -4101,59 +3948,60 @@ 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 airtime_sched_info *air_sched; -- struct airtime_info *air_info; -- struct rb_node *node = NULL; -- bool ret = false; -- u64 now; -- -+ struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); -+ struct sta_info *sta; -+ u8 ac = txq->ac; - -- if (!ieee80211_txq_airtime_check(hw, txq)) -- return false; -+ spin_lock_bh(&local->active_txq_lock[ac]); - -- air_sched = &local->airtime[txq->ac]; -- spin_lock_bh(&air_sched->lock); -+ if (!txqi->txq.sta) -+ goto out; - -- if (RB_EMPTY_NODE(&txqi->schedule_order)) -+ if (list_empty(&txqi->schedule_order)) - goto out; - -- now = ktime_get_coarse_boottime_ns(); -+ list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], -+ schedule_order) { -+ if (iter == txqi) -+ break; - -- /* 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); -+ 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]); - } - -- air_info = to_airtime_info(&txqi->txq); -- if (air_info->v_t <= air_sched->v_t) { -- air_sched->last_schedule_activity = now; -- ret = true; -- } -+ 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]); - -+ return false; - out: -- spin_unlock_bh(&air_sched->lock); -- return ret; -+ if (!list_empty(&txqi->schedule_order)) -+ list_del_init(&txqi->schedule_order); -+ spin_unlock_bh(&local->active_txq_lock[ac]); -+ -+ return true; - } - 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(&air_sched->lock); -- air_sched->schedule_pos = NULL; -- spin_unlock_bh(&air_sched->lock); -+ spin_lock_bh(&local->active_txq_lock[ac]); -+ local->schedule_round[ac]++; -+ spin_unlock_bh(&local->active_txq_lock[ac]); - } - EXPORT_SYMBOL(ieee80211_txq_schedule_start); - diff --git a/package/kernel/mac80211/patches/subsys/330-v6.0-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch b/package/kernel/mac80211/patches/subsys/330-v6.0-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch new file mode 100644 index 0000000000..e59036f5a2 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/330-v6.0-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch @@ -0,0 +1,1249 @@ +From: Felix Fietkau +Date: Sun, 19 Jun 2022 23:13:05 +0200 +Subject: [PATCH] mac80211: switch airtime fairness back to deficit round-robin + scheduling + +This reverts commits 6a789ba679d652587532cec2a0e0274fda172f3b and +2433647bc8d983a543e7d31b41ca2de1c7e2c198. + +The virtual time scheduler code has a number of issues: +- queues slowed down by hardware/firmware powersave handling were not properly + handled. +- on ath10k in push-pull mode, tx queues that the driver tries to pull from + were starved, causing excessive latency +- delay between tx enqueue and reported airtime use were causing excessively + bursty tx behavior + +The bursty behavior may also be present on the round-robin scheduler, but there +it is much easier to fix without introducing additional regressions + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -6666,6 +6666,9 @@ 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 + * +@@ -6678,7 +6681,11 @@ static inline void ieee80211_txq_schedul + * The driver may call this function if it has buffered packets for + * this TXQ internally. + */ +-void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq); ++static inline void ++ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq) ++{ ++ __ieee80211_schedule_txq(hw, txq, true); ++} + + /** + * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq() +@@ -6690,8 +6697,12 @@ void ieee80211_schedule_txq(struct ieee8 + * The driver may set force=true if it has buffered packets for this TXQ + * internally. + */ +-void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, +- bool force); ++static inline void ++ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq, ++ bool force) ++{ ++ __ieee80211_schedule_txq(hw, txq, force); ++} + + /** + * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1554,38 +1554,6 @@ 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) +@@ -1773,8 +1741,7 @@ static int sta_apply_parameters(struct i + sta_apply_mesh_params(local, sta, params); + + if (params->airtime_weight) +- sta_apply_airtime_params(local, sta, params); +- ++ sta->airtime_weight = params->airtime_weight; + + /* 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->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); ++ 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]); + 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->airtime[ac].aql_txq_limit_low; +- q_limit_high_old = local->airtime[ac].aql_txq_limit_high; ++ q_limit_low_old = local->aql_txq_limit_low[ac]; ++ q_limit_high_old = local->aql_txq_limit_high[ac]; + +- local->airtime[ac].aql_txq_limit_low = q_limit_low; +- local->airtime[ac].aql_txq_limit_high = q_limit_high; ++ local->aql_txq_limit_low[ac] = q_limit_low; ++ local->aql_txq_limit_high[ac] = q_limit_high; + + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, &local->sta_list, list) { +@@ -382,46 +382,6 @@ 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) +@@ -672,11 +632,7 @@ void debugfs_hw_add(struct ieee80211_loc + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 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_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 +@@ -512,34 +512,6 @@ 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 */ +@@ -685,10 +657,8 @@ 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; +- u64 v_t[IEEE80211_NUM_ACS]; ++ s64 deficit[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->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + rx_airtime += sta->airtime[ac].rx_airtime; + tx_airtime += sta->airtime[ac].tx_airtime; +- v_t[ac] = sta->airtime[ac].v_t; +- spin_unlock_bh(&local->airtime[ac].lock); ++ deficit[ac] = sta->airtime[ac].deficit; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + + p += scnprintf(p, bufsz + buf - p, + "RX: %llu us\nTX: %llu us\nWeight: %u\n" +- "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]); ++ "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]); + + 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->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + sta->airtime[ac].rx_airtime = 0; + sta->airtime[ac].tx_airtime = 0; +- sta->airtime[ac].v_t = 0; +- spin_unlock_bh(&local->airtime[ac].lock); ++ sta->airtime[ac].deficit = sta->airtime_weight; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + + 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->airtime[ac].lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + q_limit_l[ac] = sta->airtime[ac].aql_limit_low; + q_limit_h[ac] = sta->airtime[ac].aql_limit_high; +- spin_unlock_bh(&local->airtime[ac].lock); ++ spin_unlock_bh(&local->active_txq_lock[ac]); + q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); + } + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -862,16 +862,20 @@ 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 +- * @schedule_order: used with ieee80211_local->active_txqs + * @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 + */ + struct txq_info { + struct fq_tin tin; + struct codel_vars def_cvars; + struct codel_stats cstats; +- struct rb_node schedule_order; ++ ++ u16 schedule_round; ++ struct list_head schedule_order; + + struct sk_buff_head frags; ++ + unsigned long flags; + + /* keep last! */ +@@ -948,8 +952,6 @@ 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; +@@ -1184,44 +1186,6 @@ 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 { +@@ -1235,8 +1199,13 @@ struct ieee80211_local { + struct codel_params cparams; + + /* protects active_txqs and txqi->schedule_order */ +- struct airtime_sched_info airtime[IEEE80211_NUM_ACS]; ++ spinlock_t active_txq_lock[IEEE80211_NUM_ACS]; ++ struct list_head active_txqs[IEEE80211_NUM_ACS]; ++ u16 schedule_round[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; + +@@ -1660,125 +1629,6 @@ 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) || +@@ -2024,14 +1874,6 @@ 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 +@@ -2192,9 +2192,6 @@ 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 +@@ -707,13 +707,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + spin_lock_init(&local->queue_stop_reason_lock); + + for (i = 0; i < IEEE80211_NUM_ACS; 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 = ++ 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] = + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1583,8 +1583,12 @@ 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); + +- ieee80211_unschedule_txq(&local->hw, txq, false); ++ 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]); + + 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,11 +426,15 @@ 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]); +- init_airtime_info(&sta->airtime[i], &local->airtime[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]; + } + + for (i = 0; i < IEEE80211_NUM_TIDS; i++) +@@ -1889,59 +1893,24 @@ void ieee80211_sta_set_buffered(struct i + } + EXPORT_SYMBOL(ieee80211_sta_set_buffered); + +-void ieee80211_register_airtime(struct ieee80211_txq *txq, +- u32 tx_airtime, u32 rx_airtime) ++void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, ++ u32 tx_airtime, u32 rx_airtime) + { +- 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; ++ 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); + u32 airtime = 0; + +- air_sched = &local->airtime[txq->ac]; +- air_info = to_airtime_info(txq); +- +- if (local->airtime_flags & AIRTIME_USE_TX) ++ if (sta->local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; +- if (local->airtime_flags & AIRTIME_USE_RX) ++ if (sta->local->airtime_flags & AIRTIME_USE_RX) + airtime += rx_airtime; + +- /* 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); ++ 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]); + } + EXPORT_SYMBOL(ieee80211_sta_register_airtime); + +@@ -2385,7 +2354,7 @@ void sta_set_sinfo(struct sta_info *sta, + } + + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) { +- sinfo->airtime_weight = sta->airtime[0].weight; ++ sinfo->airtime_weight = sta->airtime_weight; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT); + } + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -135,25 +135,18 @@ 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; +- u64 v_t; +- u64 last_scheduled; +- struct list_head list; ++ s64 deficit; + 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; + +@@ -523,6 +516,7 @@ 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 +@@ -653,6 +647,7 @@ 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 +@@ -983,25 +983,6 @@ 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,7 +18,6 @@ + #include + #include + #include +-#include + #include + #include + #include +@@ -1480,7 +1479,7 @@ void ieee80211_txq_init(struct ieee80211 + codel_vars_init(&txqi->def_cvars); + codel_stats_init(&txqi->cstats); + __skb_queue_head_init(&txqi->frags); +- RB_CLEAR_NODE(&txqi->schedule_order); ++ INIT_LIST_HEAD(&txqi->schedule_order); + + txqi->txq.vif = &sdata->vif; + +@@ -1524,7 +1523,9 @@ void ieee80211_txq_purge(struct ieee8021 + ieee80211_purge_tx_queue(&local->hw, &txqi->frags); + spin_unlock_bh(&fq->lock); + +- ieee80211_unschedule_txq(&local->hw, &txqi->txq, true); ++ 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]); + } + + void ieee80211_txq_set_params(struct ieee80211_local *local) +@@ -3819,259 +3820,102 @@ 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_coarse_boottime_ns(); + struct ieee80211_txq *ret = NULL; +- struct airtime_info *air_info; +- struct txq_info *txqi = NULL; +- struct rb_node *node; +- bool first = false; ++ struct txq_info *txqi = NULL, *head = NULL; ++ bool found_eligible_txq = false; + +- air_sched = &local->airtime[ac]; +- spin_lock_bh(&air_sched->lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); + +- 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; +- +- 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))) ++ begin: ++ txqi = list_first_entry_or_null(&local->active_txqs[ac], ++ struct txq_info, ++ schedule_order); ++ if (!txqi) + goto out; + +- if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) { +- first = false; +- goto begin; +- } +- +- 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); +- +-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 (new_air->v_t <= old_air->v_t) { +- new = &parent->rb_left; +- } else { +- new = &parent->rb_right; +- leftmost = false; +- } ++ if (txqi == head) { ++ if (!found_eligible_txq) ++ goto out; ++ else ++ found_eligible_txq = false; + } + +- 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]; ++ if (!head) ++ head = txqi; + +- 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; ++ 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; + +- /* 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 (aql_check) ++ found_eligible_txq = true; + +- 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 (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; + } +- +- 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_coarse_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_coarse_boottime_ns(); +- struct airtime_info *air_info; +- u8 ac = txq->ac; +- bool was_active; + +- 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)) ++ if (txqi->schedule_round == local->schedule_round[ac]) + goto out; + +- /* 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); ++ list_del_init(&txqi->schedule_order); ++ txqi->schedule_round = local->schedule_round[ac]; ++ ret = &txqi->txq; + + out: +- spin_unlock_bh(&air_sched->lock); +-} +-EXPORT_SYMBOL(ieee80211_schedule_txq); +- +-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; +- +- air_sched = &local->airtime[txq->ac]; +- air_info = to_airtime_info(&txqi->txq); +- +- lockdep_assert_held(&air_sched->lock); +- +- if (purge) { +- list_del_init(&air_info->list); +- ieee80211_update_airtime_weight(local, air_sched, 0, true); +- } +- +- 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_coarse_boottime_ns()); +- +- rb_erase_cached(&txqi->schedule_order, +- &air_sched->active_txqs); +- RB_CLEAR_NODE(&txqi->schedule_order); ++ spin_unlock_bh(&local->active_txq_lock[ac]); ++ return ret; + } ++EXPORT_SYMBOL(ieee80211_next_txq); + +-void ieee80211_unschedule_txq(struct ieee80211_hw *hw, ++void __ieee80211_schedule_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) ++ 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); ++ spin_lock_bh(&local->active_txq_lock[txq->ac]); + +- if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force && +- !txq_has_queue(txq)) +- __ieee80211_unschedule_txq(hw, txq, false); ++ 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]); ++ } + +- spin_unlock_bh(&local->airtime[txq->ac].lock); ++ spin_unlock_bh(&local->active_txq_lock[txq->ac]); + } +-EXPORT_SYMBOL(ieee80211_return_txq); ++EXPORT_SYMBOL(__ieee80211_schedule_txq); + + DEFINE_STATIC_KEY_FALSE(aql_disable); + + bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +- struct airtime_info *air_info = to_airtime_info(txq); ++ struct sta_info *sta; + struct ieee80211_local *local = hw_to_local(hw); + + if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) +@@ -4086,12 +3930,15 @@ bool ieee80211_txq_airtime_check(struct + if (unlikely(txq->tid == IEEE80211_NUM_TIDS)) + return true; + +- if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low) ++ 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) + return true; + + if (atomic_read(&local->aql_total_pending_airtime) < + local->aql_threshold && +- atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high) ++ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < ++ sta->airtime[txq->ac].aql_limit_high) + return true; + + return false; +@@ -4101,59 +3948,60 @@ 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 airtime_sched_info *air_sched; +- struct airtime_info *air_info; +- struct rb_node *node = NULL; +- bool ret = false; +- u64 now; +- ++ struct txq_info *iter, *tmp, *txqi = to_txq_info(txq); ++ struct sta_info *sta; ++ u8 ac = txq->ac; + +- if (!ieee80211_txq_airtime_check(hw, txq)) +- return false; ++ spin_lock_bh(&local->active_txq_lock[ac]); + +- air_sched = &local->airtime[txq->ac]; +- spin_lock_bh(&air_sched->lock); ++ if (!txqi->txq.sta) ++ goto out; + +- if (RB_EMPTY_NODE(&txqi->schedule_order)) ++ if (list_empty(&txqi->schedule_order)) + goto out; + +- now = ktime_get_coarse_boottime_ns(); ++ list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], ++ schedule_order) { ++ if (iter == txqi) ++ break; + +- /* 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); ++ 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]); + } + +- air_info = to_airtime_info(&txqi->txq); +- if (air_info->v_t <= air_sched->v_t) { +- air_sched->last_schedule_activity = now; +- ret = true; +- } ++ 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]); + ++ return false; + out: +- spin_unlock_bh(&air_sched->lock); +- return ret; ++ if (!list_empty(&txqi->schedule_order)) ++ list_del_init(&txqi->schedule_order); ++ spin_unlock_bh(&local->active_txq_lock[ac]); ++ ++ return true; + } + 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(&air_sched->lock); +- air_sched->schedule_pos = NULL; +- spin_unlock_bh(&air_sched->lock); ++ spin_lock_bh(&local->active_txq_lock[ac]); ++ local->schedule_round[ac]++; ++ spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_txq_schedule_start); + diff --git a/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch b/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch deleted file mode 100644 index c006d3762a..0000000000 --- a/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch +++ /dev/null @@ -1,52 +0,0 @@ -From: Felix Fietkau -Date: Mon, 20 Jun 2022 14:53:04 +0200 -Subject: [PATCH] mac80211: make sta airtime deficit field s32 instead of - s64 - -32 bit is more than enough range for the airtime deficit - -Signed-off-by: Felix Fietkau ---- - ---- 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]; -+ s32 deficit[IEEE80211_NUM_ACS]; - ssize_t rv; - int ac; - -@@ -219,7 +219,7 @@ static ssize_t sta_airtime_read(struct f - - 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", -+ "Deficit: VO: %d us VI: %d us BE: %d us BK: %d us\n", - rx_airtime, tx_airtime, sta->airtime_weight, - deficit[0], deficit[1], deficit[2], deficit[3]); - ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -138,7 +138,7 @@ enum ieee80211_agg_stop_reason { - struct airtime_info { - u64 rx_airtime; - u64 tx_airtime; -- s64 deficit; -+ s32 deficit; - atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ - u32 aql_limit_low; - u32 aql_limit_high; ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3847,7 +3847,7 @@ struct ieee80211_txq *ieee80211_next_txq - 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; -+ s32 deficit = sta->airtime[txqi->txq.ac].deficit; - - if (aql_check) - found_eligible_txq = true; diff --git a/package/kernel/mac80211/patches/subsys/331-v6.0-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch b/package/kernel/mac80211/patches/subsys/331-v6.0-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch new file mode 100644 index 0000000000..c006d3762a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/331-v6.0-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch @@ -0,0 +1,52 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 14:53:04 +0200 +Subject: [PATCH] mac80211: make sta airtime deficit field s32 instead of + s64 + +32 bit is more than enough range for the airtime deficit + +Signed-off-by: Felix Fietkau +--- + +--- 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]; ++ s32 deficit[IEEE80211_NUM_ACS]; + ssize_t rv; + int ac; + +@@ -219,7 +219,7 @@ static ssize_t sta_airtime_read(struct f + + 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", ++ "Deficit: VO: %d us VI: %d us BE: %d us BK: %d us\n", + rx_airtime, tx_airtime, sta->airtime_weight, + deficit[0], deficit[1], deficit[2], deficit[3]); + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -138,7 +138,7 @@ enum ieee80211_agg_stop_reason { + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; +- s64 deficit; ++ s32 deficit; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; + u32 aql_limit_high; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3847,7 +3847,7 @@ struct ieee80211_txq *ieee80211_next_txq + 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; ++ s32 deficit = sta->airtime[txqi->txq.ac].deficit; + + if (aql_check) + found_eligible_txq = true; diff --git a/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch b/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch deleted file mode 100644 index c214294603..0000000000 --- a/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch +++ /dev/null @@ -1,48 +0,0 @@ -From: Felix Fietkau -Date: Mon, 20 Jun 2022 14:59:09 +0200 -Subject: [PATCH] mac80211: consider aql_tx_pending when checking airtime - deficit - -When queueing packets for a station, deficit only gets added once the packets -have been transmitted, which could be much later. During that time, a lot of -temporary unfairness could happen, which could lead to bursty behavior. -Fix this by subtracting the aql_tx_pending when checking the deficit in tx -scheduling. - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3817,6 +3817,13 @@ out: - } - EXPORT_SYMBOL(ieee80211_tx_dequeue); - -+static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac) -+{ -+ struct airtime_info *air_info = &sta->airtime[ac]; -+ -+ return air_info->deficit - atomic_read(&air_info->aql_tx_pending); -+} -+ - struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) - { - struct ieee80211_local *local = hw_to_local(hw); -@@ -3847,7 +3854,7 @@ struct ieee80211_txq *ieee80211_next_txq - struct sta_info *sta = container_of(txqi->txq.sta, - struct sta_info, sta); - bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); -- s32 deficit = sta->airtime[txqi->txq.ac].deficit; -+ s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac); - - if (aql_check) - found_eligible_txq = true; -@@ -3972,7 +3979,7 @@ bool ieee80211_txq_may_transmit(struct i - continue; - } - sta = container_of(iter->txq.sta, struct sta_info, sta); -- if (sta->airtime[ac].deficit < 0) -+ if (ieee80211_sta_deficit(sta, ac) < 0) - sta->airtime[ac].deficit += sta->airtime_weight; - list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); - } diff --git a/package/kernel/mac80211/patches/subsys/332-v6.0-mac80211-consider-aql_tx_pending-when-checking-airti.patch b/package/kernel/mac80211/patches/subsys/332-v6.0-mac80211-consider-aql_tx_pending-when-checking-airti.patch new file mode 100644 index 0000000000..c214294603 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/332-v6.0-mac80211-consider-aql_tx_pending-when-checking-airti.patch @@ -0,0 +1,48 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 14:59:09 +0200 +Subject: [PATCH] mac80211: consider aql_tx_pending when checking airtime + deficit + +When queueing packets for a station, deficit only gets added once the packets +have been transmitted, which could be much later. During that time, a lot of +temporary unfairness could happen, which could lead to bursty behavior. +Fix this by subtracting the aql_tx_pending when checking the deficit in tx +scheduling. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3817,6 +3817,13 @@ out: + } + EXPORT_SYMBOL(ieee80211_tx_dequeue); + ++static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac) ++{ ++ struct airtime_info *air_info = &sta->airtime[ac]; ++ ++ return air_info->deficit - atomic_read(&air_info->aql_tx_pending); ++} ++ + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +@@ -3847,7 +3854,7 @@ struct ieee80211_txq *ieee80211_next_txq + struct sta_info *sta = container_of(txqi->txq.sta, + struct sta_info, sta); + bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); +- s32 deficit = sta->airtime[txqi->txq.ac].deficit; ++ s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac); + + if (aql_check) + found_eligible_txq = true; +@@ -3972,7 +3979,7 @@ bool ieee80211_txq_may_transmit(struct i + continue; + } + sta = container_of(iter->txq.sta, struct sta_info, sta); +- if (sta->airtime[ac].deficit < 0) ++ if (ieee80211_sta_deficit(sta, ac) < 0) + sta->airtime[ac].deficit += sta->airtime_weight; + list_move_tail(&iter->schedule_order, &local->active_txqs[ac]); + } diff --git a/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch b/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch deleted file mode 100644 index 317e4f0653..0000000000 --- a/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch +++ /dev/null @@ -1,118 +0,0 @@ -From: Felix Fietkau -Date: Mon, 20 Jun 2022 20:52:50 +0200 -Subject: [PATCH] mac80211: keep recently active tx queues in scheduling - list - -This allows proper deficit accounting to ensure that they don't carry their -deficit until the next time they become active - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -83,6 +83,13 @@ extern const u8 ieee80211_ac_to_qos_mask - - #define IEEE80211_MAX_NAN_INSTANCE_ID 255 - -+ -+/* -+ * Keep a station's queues on the active list for deficit accounting purposes -+ * if it was active or queued during the last 100ms -+ */ -+#define AIRTIME_ACTIVE_DURATION (HZ / 10) -+ - struct ieee80211_bss { - u32 device_ts_beacon, device_ts_presp; - ---- a/net/mac80211/sta_info.h -+++ b/net/mac80211/sta_info.h -@@ -138,6 +138,7 @@ enum ieee80211_agg_stop_reason { - struct airtime_info { - u64 rx_airtime; - u64 tx_airtime; -+ u32 last_active; - s32 deficit; - atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ - u32 aql_limit_low; ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3824,6 +3824,36 @@ static inline s32 ieee80211_sta_deficit( - return air_info->deficit - atomic_read(&air_info->aql_tx_pending); - } - -+static void -+ieee80211_txq_set_active(struct txq_info *txqi) -+{ -+ struct sta_info *sta; -+ -+ if (!txqi->txq.sta) -+ return; -+ -+ sta = container_of(txqi->txq.sta, struct sta_info, sta); -+ sta->airtime[txqi->txq.ac].last_active = (u32)jiffies; -+} -+ -+static bool -+ieee80211_txq_keep_active(struct txq_info *txqi) -+{ -+ struct sta_info *sta; -+ u32 diff; -+ -+ if (!txqi->txq.sta) -+ return false; -+ -+ sta = container_of(txqi->txq.sta, struct sta_info, sta); -+ if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0) -+ return false; -+ -+ diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active; -+ -+ return diff <= AIRTIME_ACTIVE_DURATION; -+} -+ - struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) - { - struct ieee80211_local *local = hw_to_local(hw); -@@ -3870,7 +3900,6 @@ struct ieee80211_txq *ieee80211_next_txq - } - } - -- - if (txqi->schedule_round == local->schedule_round[ac]) - goto out; - -@@ -3890,12 +3919,13 @@ void __ieee80211_schedule_txq(struct iee - { - struct ieee80211_local *local = hw_to_local(hw); - struct txq_info *txqi = to_txq_info(txq); -+ bool has_queue; - - spin_lock_bh(&local->active_txq_lock[txq->ac]); - -+ has_queue = force || txq_has_queue(txq); - if (list_empty(&txqi->schedule_order) && -- (force || !skb_queue_empty(&txqi->frags) || -- txqi->tin.backlog_packets)) { -+ (has_queue || ieee80211_txq_keep_active(txqi))) { - /* 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 -@@ -3903,7 +3933,7 @@ void __ieee80211_schedule_txq(struct iee - * get immediately moved to the back of the list on the next - * call to ieee80211_next_txq(). - */ -- if (txqi->txq.sta && local->airtime_flags && -+ if (txqi->txq.sta && local->airtime_flags && has_queue && - wiphy_ext_feature_isset(local->hw.wiphy, - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) - list_add(&txqi->schedule_order, -@@ -3911,6 +3941,8 @@ void __ieee80211_schedule_txq(struct iee - else - list_add_tail(&txqi->schedule_order, - &local->active_txqs[txq->ac]); -+ if (has_queue) -+ ieee80211_txq_set_active(txqi); - } - - spin_unlock_bh(&local->active_txq_lock[txq->ac]); diff --git a/package/kernel/mac80211/patches/subsys/333-v6.0-mac80211-keep-recently-active-tx-queues-in-schedulin.patch b/package/kernel/mac80211/patches/subsys/333-v6.0-mac80211-keep-recently-active-tx-queues-in-schedulin.patch new file mode 100644 index 0000000000..317e4f0653 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/333-v6.0-mac80211-keep-recently-active-tx-queues-in-schedulin.patch @@ -0,0 +1,118 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 20:52:50 +0200 +Subject: [PATCH] mac80211: keep recently active tx queues in scheduling + list + +This allows proper deficit accounting to ensure that they don't carry their +deficit until the next time they become active + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -83,6 +83,13 @@ extern const u8 ieee80211_ac_to_qos_mask + + #define IEEE80211_MAX_NAN_INSTANCE_ID 255 + ++ ++/* ++ * Keep a station's queues on the active list for deficit accounting purposes ++ * if it was active or queued during the last 100ms ++ */ ++#define AIRTIME_ACTIVE_DURATION (HZ / 10) ++ + struct ieee80211_bss { + u32 device_ts_beacon, device_ts_presp; + +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -138,6 +138,7 @@ enum ieee80211_agg_stop_reason { + struct airtime_info { + u64 rx_airtime; + u64 tx_airtime; ++ u32 last_active; + s32 deficit; + atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ + u32 aql_limit_low; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3824,6 +3824,36 @@ static inline s32 ieee80211_sta_deficit( + return air_info->deficit - atomic_read(&air_info->aql_tx_pending); + } + ++static void ++ieee80211_txq_set_active(struct txq_info *txqi) ++{ ++ struct sta_info *sta; ++ ++ if (!txqi->txq.sta) ++ return; ++ ++ sta = container_of(txqi->txq.sta, struct sta_info, sta); ++ sta->airtime[txqi->txq.ac].last_active = (u32)jiffies; ++} ++ ++static bool ++ieee80211_txq_keep_active(struct txq_info *txqi) ++{ ++ struct sta_info *sta; ++ u32 diff; ++ ++ if (!txqi->txq.sta) ++ return false; ++ ++ sta = container_of(txqi->txq.sta, struct sta_info, sta); ++ if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0) ++ return false; ++ ++ diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active; ++ ++ return diff <= AIRTIME_ACTIVE_DURATION; ++} ++ + struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) + { + struct ieee80211_local *local = hw_to_local(hw); +@@ -3870,7 +3900,6 @@ struct ieee80211_txq *ieee80211_next_txq + } + } + +- + if (txqi->schedule_round == local->schedule_round[ac]) + goto out; + +@@ -3890,12 +3919,13 @@ void __ieee80211_schedule_txq(struct iee + { + struct ieee80211_local *local = hw_to_local(hw); + struct txq_info *txqi = to_txq_info(txq); ++ bool has_queue; + + spin_lock_bh(&local->active_txq_lock[txq->ac]); + ++ has_queue = force || txq_has_queue(txq); + if (list_empty(&txqi->schedule_order) && +- (force || !skb_queue_empty(&txqi->frags) || +- txqi->tin.backlog_packets)) { ++ (has_queue || ieee80211_txq_keep_active(txqi))) { + /* 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 +@@ -3903,7 +3933,7 @@ void __ieee80211_schedule_txq(struct iee + * get immediately moved to the back of the list on the next + * call to ieee80211_next_txq(). + */ +- if (txqi->txq.sta && local->airtime_flags && ++ if (txqi->txq.sta && local->airtime_flags && has_queue && + wiphy_ext_feature_isset(local->hw.wiphy, + NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) + list_add(&txqi->schedule_order, +@@ -3911,6 +3941,8 @@ void __ieee80211_schedule_txq(struct iee + else + list_add_tail(&txqi->schedule_order, + &local->active_txqs[txq->ac]); ++ if (has_queue) ++ ieee80211_txq_set_active(txqi); + } + + spin_unlock_bh(&local->active_txq_lock[txq->ac]); diff --git a/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch deleted file mode 100644 index fb6fd6eac6..0000000000 --- a/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch +++ /dev/null @@ -1,131 +0,0 @@ -From: Felix Fietkau -Date: Mon, 20 Jun 2022 21:26:34 +0200 -Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness - -In order to maintain fairness, the amount of queueing needs to be limited -beyond the simple per-station AQL budget, otherwise the driver can simply -repeatedly do scheduling rounds until all queues that have not used their -AQL budget become eligble. - -To be conservative, use the high AQL limit for the first txq and add half -of the low AQL for each subsequent queue. - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/ieee80211_i.h -+++ b/net/mac80211/ieee80211_i.h -@@ -1215,6 +1215,7 @@ struct ieee80211_local { - u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; - u32 aql_threshold; - atomic_t aql_total_pending_airtime; -+ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS]; - - const struct ieee80211_ops *ops; - ---- a/net/mac80211/main.c -+++ b/net/mac80211/main.c -@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ - local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; - local->aql_txq_limit_high[i] = - IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; -+ atomic_set(&local->aql_ac_pending_airtime[i], 0); - } - - local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim - &sta->airtime[ac].aql_tx_pending); - - atomic_add(tx_airtime, &local->aql_total_pending_airtime); -+ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]); - return; - } - -@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim - tx_pending, 0); - } - -+ atomic_sub(tx_airtime, &local->aql_total_pending_airtime); - tx_pending = atomic_sub_return(tx_airtime, -- &local->aql_total_pending_airtime); -+ &local->aql_ac_pending_airtime[ac]); - if (WARN_ONCE(tx_pending < 0, - "Device %s AC %d pending airtime underflow: %u, %u", - wiphy_name(local->hw.wiphy), ac, tx_pending, -- tx_airtime)) -- atomic_cmpxchg(&local->aql_total_pending_airtime, -+ tx_airtime)) { -+ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac], - tx_pending, 0); -+ atomic_sub(tx_pending, &local->aql_total_pending_airtime); -+ } - } - - int sta_info_move_state(struct sta_info *sta, ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq - - spin_lock_bh(&local->active_txq_lock[ac]); - -+ if (!local->schedule_round[ac]) -+ goto out; -+ - begin: - txqi = list_first_entry_or_null(&local->active_txqs[ac], - struct txq_info, -@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct - } - EXPORT_SYMBOL(ieee80211_txq_airtime_check); - -+static bool -+ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac) -+{ -+ unsigned int num_txq = 0; -+ struct txq_info *txq; -+ u32 aql_limit; -+ -+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) -+ return true; -+ -+ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order) -+ num_txq++; -+ -+ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 + -+ local->aql_txq_limit_high[ac]; -+ -+ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit; -+} -+ - bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) - { -@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i - if (list_empty(&txqi->schedule_order)) - goto out; - -+ if (!ieee80211_txq_schedule_airtime_check(local, ac)) -+ goto out; -+ - list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], - schedule_order) { - if (iter == txqi) -@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct - struct ieee80211_local *local = hw_to_local(hw); - - spin_lock_bh(&local->active_txq_lock[ac]); -- local->schedule_round[ac]++; -+ -+ if (ieee80211_txq_schedule_airtime_check(local, ac)) { -+ local->schedule_round[ac]++; -+ if (!local->schedule_round[ac]) -+ local->schedule_round[ac]++; -+ } else { -+ local->schedule_round[ac] = 0; -+ } -+ - spin_unlock_bh(&local->active_txq_lock[ac]); - } - EXPORT_SYMBOL(ieee80211_txq_schedule_start); diff --git a/package/kernel/mac80211/patches/subsys/334-v6.0-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch b/package/kernel/mac80211/patches/subsys/334-v6.0-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch new file mode 100644 index 0000000000..fb6fd6eac6 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/334-v6.0-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch @@ -0,0 +1,131 @@ +From: Felix Fietkau +Date: Mon, 20 Jun 2022 21:26:34 +0200 +Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness + +In order to maintain fairness, the amount of queueing needs to be limited +beyond the simple per-station AQL budget, otherwise the driver can simply +repeatedly do scheduling rounds until all queues that have not used their +AQL budget become eligble. + +To be conservative, use the high AQL limit for the first txq and add half +of the low AQL for each subsequent queue. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -1215,6 +1215,7 @@ struct ieee80211_local { + u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; + u32 aql_threshold; + atomic_t aql_total_pending_airtime; ++ atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS]; + + const struct ieee80211_ops *ops; + +--- a/net/mac80211/main.c ++++ b/net/mac80211/main.c +@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_ + local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; + local->aql_txq_limit_high[i] = + IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; ++ atomic_set(&local->aql_ac_pending_airtime[i], 0); + } + + local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim + &sta->airtime[ac].aql_tx_pending); + + atomic_add(tx_airtime, &local->aql_total_pending_airtime); ++ atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]); + return; + } + +@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim + tx_pending, 0); + } + ++ atomic_sub(tx_airtime, &local->aql_total_pending_airtime); + tx_pending = atomic_sub_return(tx_airtime, +- &local->aql_total_pending_airtime); ++ &local->aql_ac_pending_airtime[ac]); + if (WARN_ONCE(tx_pending < 0, + "Device %s AC %d pending airtime underflow: %u, %u", + wiphy_name(local->hw.wiphy), ac, tx_pending, +- tx_airtime)) +- atomic_cmpxchg(&local->aql_total_pending_airtime, ++ tx_airtime)) { ++ atomic_cmpxchg(&local->aql_ac_pending_airtime[ac], + tx_pending, 0); ++ atomic_sub(tx_pending, &local->aql_total_pending_airtime); ++ } + } + + int sta_info_move_state(struct sta_info *sta, +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq + + spin_lock_bh(&local->active_txq_lock[ac]); + ++ if (!local->schedule_round[ac]) ++ goto out; ++ + begin: + txqi = list_first_entry_or_null(&local->active_txqs[ac], + struct txq_info, +@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct + } + EXPORT_SYMBOL(ieee80211_txq_airtime_check); + ++static bool ++ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac) ++{ ++ unsigned int num_txq = 0; ++ struct txq_info *txq; ++ u32 aql_limit; ++ ++ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) ++ return true; ++ ++ list_for_each_entry(txq, &local->active_txqs[ac], schedule_order) ++ num_txq++; ++ ++ aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 + ++ local->aql_txq_limit_high[ac]; ++ ++ return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit; ++} ++ + bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, + struct ieee80211_txq *txq) + { +@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i + if (list_empty(&txqi->schedule_order)) + goto out; + ++ if (!ieee80211_txq_schedule_airtime_check(local, ac)) ++ goto out; ++ + list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac], + schedule_order) { + if (iter == txqi) +@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct + struct ieee80211_local *local = hw_to_local(hw); + + spin_lock_bh(&local->active_txq_lock[ac]); +- local->schedule_round[ac]++; ++ ++ if (ieee80211_txq_schedule_airtime_check(local, ac)) { ++ local->schedule_round[ac]++; ++ if (!local->schedule_round[ac]) ++ local->schedule_round[ac]++; ++ } else { ++ local->schedule_round[ac] = 0; ++ } ++ + spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_txq_schedule_start); diff --git a/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch b/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch deleted file mode 100644 index df45a520fa..0000000000 --- a/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch +++ /dev/null @@ -1,58 +0,0 @@ -From: Felix Fietkau -Date: Sat, 25 Jun 2022 21:25:40 +0200 -Subject: [PATCH] mac80211: add debugfs file to display per-phy AQL pending - airtime - -Now that the global pending airtime is more relevant for airtime fairness, -it makes sense to make it accessible via debugfs for debugging - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -201,6 +201,36 @@ static const struct file_operations airt - .llseek = default_llseek, - }; - -+static ssize_t aql_pending_read(struct file *file, -+ char __user *user_buf, -+ size_t count, loff_t *ppos) -+{ -+ struct ieee80211_local *local = file->private_data; -+ char buf[400]; -+ int len = 0; -+ -+ len = scnprintf(buf, sizeof(buf), -+ "AC AQL pending\n" -+ "VO %u us\n" -+ "VI %u us\n" -+ "BE %u us\n" -+ "BK %u us\n" -+ "total %u us\n", -+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]), -+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]), -+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]), -+ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]), -+ atomic_read(&local->aql_total_pending_airtime)); -+ return simple_read_from_buffer(user_buf, count, ppos, -+ buf, len); -+} -+ -+static const struct file_operations aql_pending_ops = { -+ .read = aql_pending_read, -+ .open = simple_open, -+ .llseek = default_llseek, -+}; -+ - static ssize_t aql_txq_limit_read(struct file *file, - char __user *user_buf, - size_t count, -@@ -628,6 +658,7 @@ void debugfs_hw_add(struct ieee80211_loc - DEBUGFS_ADD(hw_conf); - DEBUGFS_ADD_MODE(force_tx_status, 0600); - DEBUGFS_ADD_MODE(aql_enable, 0600); -+ DEBUGFS_ADD(aql_pending); - - if (local->ops->wake_tx_queue) - DEBUGFS_ADD_MODE(aqm, 0600); diff --git a/package/kernel/mac80211/patches/subsys/335-v6.0-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch b/package/kernel/mac80211/patches/subsys/335-v6.0-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch new file mode 100644 index 0000000000..df45a520fa --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/335-v6.0-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch @@ -0,0 +1,58 @@ +From: Felix Fietkau +Date: Sat, 25 Jun 2022 21:25:40 +0200 +Subject: [PATCH] mac80211: add debugfs file to display per-phy AQL pending + airtime + +Now that the global pending airtime is more relevant for airtime fairness, +it makes sense to make it accessible via debugfs for debugging + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -201,6 +201,36 @@ static const struct file_operations airt + .llseek = default_llseek, + }; + ++static ssize_t aql_pending_read(struct file *file, ++ char __user *user_buf, ++ size_t count, loff_t *ppos) ++{ ++ struct ieee80211_local *local = file->private_data; ++ char buf[400]; ++ int len = 0; ++ ++ len = scnprintf(buf, sizeof(buf), ++ "AC AQL pending\n" ++ "VO %u us\n" ++ "VI %u us\n" ++ "BE %u us\n" ++ "BK %u us\n" ++ "total %u us\n", ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]), ++ atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]), ++ atomic_read(&local->aql_total_pending_airtime)); ++ return simple_read_from_buffer(user_buf, count, ppos, ++ buf, len); ++} ++ ++static const struct file_operations aql_pending_ops = { ++ .read = aql_pending_read, ++ .open = simple_open, ++ .llseek = default_llseek, ++}; ++ + static ssize_t aql_txq_limit_read(struct file *file, + char __user *user_buf, + size_t count, +@@ -628,6 +658,7 @@ void debugfs_hw_add(struct ieee80211_loc + DEBUGFS_ADD(hw_conf); + DEBUGFS_ADD_MODE(force_tx_status, 0600); + DEBUGFS_ADD_MODE(aql_enable, 0600); ++ DEBUGFS_ADD(aql_pending); + + if (local->ops->wake_tx_queue) + DEBUGFS_ADD_MODE(aqm, 0600); diff --git a/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch b/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch deleted file mode 100644 index 35f07c1a97..0000000000 --- a/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch +++ /dev/null @@ -1,36 +0,0 @@ -From: Felix Fietkau -Date: Sat, 25 Jun 2022 23:10:19 +0200 -Subject: [PATCH] mac80211: only accumulate airtime deficit for active - clients - -When a client does not generate any local tx activity, accumulating airtime -deficit for the round-robin scheduler can be harmful. If this goes on for too -long, the deficit could grow quite large, which might cause unreasonable -initial latency once the client becomes active - -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -1900,6 +1900,7 @@ void ieee80211_sta_register_airtime(stru - struct ieee80211_local *local = sta->sdata->local; - u8 ac = ieee80211_ac_from_tid(tid); - u32 airtime = 0; -+ u32 diff; - - if (sta->local->airtime_flags & AIRTIME_USE_TX) - airtime += tx_airtime; -@@ -1909,7 +1910,11 @@ void ieee80211_sta_register_airtime(stru - 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; -+ -+ diff = (u32)jiffies - sta->airtime[ac].last_active; -+ if (diff <= AIRTIME_ACTIVE_DURATION) -+ sta->airtime[ac].deficit -= airtime; -+ - spin_unlock_bh(&local->active_txq_lock[ac]); - } - EXPORT_SYMBOL(ieee80211_sta_register_airtime); diff --git a/package/kernel/mac80211/patches/subsys/336-v6.0-mac80211-only-accumulate-airtime-deficit-for-active-.patch b/package/kernel/mac80211/patches/subsys/336-v6.0-mac80211-only-accumulate-airtime-deficit-for-active-.patch new file mode 100644 index 0000000000..35f07c1a97 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/336-v6.0-mac80211-only-accumulate-airtime-deficit-for-active-.patch @@ -0,0 +1,36 @@ +From: Felix Fietkau +Date: Sat, 25 Jun 2022 23:10:19 +0200 +Subject: [PATCH] mac80211: only accumulate airtime deficit for active + clients + +When a client does not generate any local tx activity, accumulating airtime +deficit for the round-robin scheduler can be harmful. If this goes on for too +long, the deficit could grow quite large, which might cause unreasonable +initial latency once the client becomes active + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -1900,6 +1900,7 @@ void ieee80211_sta_register_airtime(stru + struct ieee80211_local *local = sta->sdata->local; + u8 ac = ieee80211_ac_from_tid(tid); + u32 airtime = 0; ++ u32 diff; + + if (sta->local->airtime_flags & AIRTIME_USE_TX) + airtime += tx_airtime; +@@ -1909,7 +1910,11 @@ void ieee80211_sta_register_airtime(stru + 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; ++ ++ diff = (u32)jiffies - sta->airtime[ac].last_active; ++ if (diff <= AIRTIME_ACTIVE_DURATION) ++ sta->airtime[ac].deficit -= airtime; ++ + spin_unlock_bh(&local->active_txq_lock[ac]); + } + EXPORT_SYMBOL(ieee80211_sta_register_airtime); diff --git a/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch b/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch deleted file mode 100644 index 43c3e75d65..0000000000 --- a/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch +++ /dev/null @@ -1,30 +0,0 @@ -From: Felix Fietkau -Date: Wed, 13 Jul 2022 07:32:26 +0200 -Subject: [PATCH] mac80211: exclude multicast packets from AQL pending airtime - -In AP mode, multicast traffic is handled very differently from normal traffic, -especially if at least one client is in powersave mode. -This means that multicast packets can be buffered a lot longer than normal -unicast packets, and can eat up the AQL budget very quickly because of the low -data rate. -Along with the recent change to maintain a global PHY AQL limit, this can lead -to significant latency spikes for unicast traffic. - -Since queueing multicast to hardware is currently not constrained by AQL limits -anyway, let's just exclude it from the AQL pending airtime calculation entirely. - -Fixes: 8e4bac067105 ("wifi: mac80211: add a per-PHY AQL limit to improve fairness") -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/tx.c -+++ b/net/mac80211/tx.c -@@ -3792,7 +3792,7 @@ begin: - encap_out: - IEEE80211_SKB_CB(skb)->control.vif = vif; - -- if (vif && -+ if (tx.sta && - wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { - bool ampdu = txq->ac != IEEE80211_AC_VO; - u32 airtime; diff --git a/package/kernel/mac80211/patches/subsys/339-v6.0-mac80211-exclude-multicast-packets-from-AQL-pending-.patch b/package/kernel/mac80211/patches/subsys/339-v6.0-mac80211-exclude-multicast-packets-from-AQL-pending-.patch new file mode 100644 index 0000000000..43c3e75d65 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/339-v6.0-mac80211-exclude-multicast-packets-from-AQL-pending-.patch @@ -0,0 +1,30 @@ +From: Felix Fietkau +Date: Wed, 13 Jul 2022 07:32:26 +0200 +Subject: [PATCH] mac80211: exclude multicast packets from AQL pending airtime + +In AP mode, multicast traffic is handled very differently from normal traffic, +especially if at least one client is in powersave mode. +This means that multicast packets can be buffered a lot longer than normal +unicast packets, and can eat up the AQL budget very quickly because of the low +data rate. +Along with the recent change to maintain a global PHY AQL limit, this can lead +to significant latency spikes for unicast traffic. + +Since queueing multicast to hardware is currently not constrained by AQL limits +anyway, let's just exclude it from the AQL pending airtime calculation entirely. + +Fixes: 8e4bac067105 ("wifi: mac80211: add a per-PHY AQL limit to improve fairness") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -3792,7 +3792,7 @@ begin: + encap_out: + IEEE80211_SKB_CB(skb)->control.vif = vif; + +- if (vif && ++ if (tx.sta && + wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { + bool ampdu = txq->ac != IEEE80211_AC_VO; + u32 airtime; diff --git a/package/kernel/mac80211/patches/subsys/340-v5.19-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch b/package/kernel/mac80211/patches/subsys/340-v5.19-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch new file mode 100644 index 0000000000..82243f1d98 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/340-v5.19-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch @@ -0,0 +1,46 @@ +From aa40d5a43526cca9439a2b45fcfdcd016594dece Mon Sep 17 00:00:00 2001 +From: Tetsuo Handa +Date: Sun, 17 Jul 2022 21:21:52 +0900 +Subject: [PATCH] wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +lockdep complains use of uninitialized spinlock at ieee80211_do_stop() [1], +for commit f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif +that is being stopped") guards clear_bit() using fq.lock even before +fq_init() from ieee80211_txq_setup_flows() initializes this spinlock. + +According to discussion [2], Toke was not happy with expanding usage of +fq.lock. Since __ieee80211_wake_txqs() is called under RCU read lock, we +can instead use synchronize_rcu() for flushing ieee80211_wake_txqs(). + +Link: https://syzkaller.appspot.com/bug?extid=eceab52db7c4b961e9d6 [1] +Link: https://lkml.kernel.org/r/874k0zowh2.fsf@toke.dk [2] +Reported-by: syzbot +Signed-off-by: Tetsuo Handa +Fixes: f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif that is being stopped") +Tested-by: syzbot +Acked-by: Toke Høiland-Jørgensen +Signed-off-by: Kalle Valo +Link: https://lore.kernel.org/r/9cc9b81d-75a3-3925-b612-9d0ad3cab82b@I-love.SAKURA.ne.jp +[ pick up commit 3598cb6e1862 ("wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop()") from -next] +Link: https://lore.kernel.org/all/87o7xcq6qt.fsf@kernel.org/ +Signed-off-by: Jakub Kicinski +--- + net/mac80211/iface.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -377,9 +377,8 @@ static void ieee80211_do_stop(struct iee + bool cancel_scan; + struct cfg80211_nan_func *func; + +- spin_lock_bh(&local->fq.lock); + clear_bit(SDATA_STATE_RUNNING, &sdata->state); +- spin_unlock_bh(&local->fq.lock); ++ synchronize_rcu(); /* flush _ieee80211_wake_txqs() */ + + cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; + if (cancel_scan) diff --git a/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch b/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch deleted file mode 100644 index 82243f1d98..0000000000 --- a/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch +++ /dev/null @@ -1,46 +0,0 @@ -From aa40d5a43526cca9439a2b45fcfdcd016594dece Mon Sep 17 00:00:00 2001 -From: Tetsuo Handa -Date: Sun, 17 Jul 2022 21:21:52 +0900 -Subject: [PATCH] wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop() -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -lockdep complains use of uninitialized spinlock at ieee80211_do_stop() [1], -for commit f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif -that is being stopped") guards clear_bit() using fq.lock even before -fq_init() from ieee80211_txq_setup_flows() initializes this spinlock. - -According to discussion [2], Toke was not happy with expanding usage of -fq.lock. Since __ieee80211_wake_txqs() is called under RCU read lock, we -can instead use synchronize_rcu() for flushing ieee80211_wake_txqs(). - -Link: https://syzkaller.appspot.com/bug?extid=eceab52db7c4b961e9d6 [1] -Link: https://lkml.kernel.org/r/874k0zowh2.fsf@toke.dk [2] -Reported-by: syzbot -Signed-off-by: Tetsuo Handa -Fixes: f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif that is being stopped") -Tested-by: syzbot -Acked-by: Toke Høiland-Jørgensen -Signed-off-by: Kalle Valo -Link: https://lore.kernel.org/r/9cc9b81d-75a3-3925-b612-9d0ad3cab82b@I-love.SAKURA.ne.jp -[ pick up commit 3598cb6e1862 ("wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop()") from -next] -Link: https://lore.kernel.org/all/87o7xcq6qt.fsf@kernel.org/ -Signed-off-by: Jakub Kicinski ---- - net/mac80211/iface.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - ---- a/net/mac80211/iface.c -+++ b/net/mac80211/iface.c -@@ -377,9 +377,8 @@ static void ieee80211_do_stop(struct iee - bool cancel_scan; - struct cfg80211_nan_func *func; - -- spin_lock_bh(&local->fq.lock); - clear_bit(SDATA_STATE_RUNNING, &sdata->state); -- spin_unlock_bh(&local->fq.lock); -+ synchronize_rcu(); /* flush _ieee80211_wake_txqs() */ - - cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata; - if (cancel_scan) diff --git a/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch b/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch deleted file mode 100644 index 8c56acbf88..0000000000 --- a/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch +++ /dev/null @@ -1,40 +0,0 @@ -From: Alexander Wetzel -Date: Thu, 15 Sep 2022 14:41:20 +0200 -Subject: [PATCH] mac80211: Fix deadlock: Don't start TX while holding - fq->lock - -ieee80211_txq_purge() calls fq_tin_reset() and -ieee80211_purge_tx_queue(); Both are then calling -ieee80211_free_txskb(). Which can decide to TX the skb again. - -There are at least two ways to get a deadlock: - -1) When we have a TDLS teardown packet queued in either tin or frags - ieee80211_tdls_td_tx_handle() will call ieee80211_subif_start_xmit() - while we still hold fq->lock. ieee80211_txq_enqueue() will thus - deadlock. - -2) A variant of the above happens if aggregation is up and running: - In that case ieee80211_iface_work() will deadlock with the original - task: The original tasks already holds fq->lock and tries to get - sta->lock after kicking off ieee80211_iface_work(). But the worker - can get sta->lock prior to the original task and will then spin for - fq->lock. - -Avoid these deadlocks by not sending out any skbs when called via -ieee80211_free_txskb(). - -Signed-off-by: Alexander Wetzel ---- - ---- a/net/mac80211/status.c -+++ b/net/mac80211/status.c -@@ -698,7 +698,7 @@ static void ieee80211_report_used_skb(st - - if (!sdata) { - skb->dev = NULL; -- } else { -+ } else if (!dropped) { - unsigned int hdr_size = - ieee80211_hdrlen(hdr->frame_control); - diff --git a/package/kernel/mac80211/patches/subsys/341-v6.0-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch b/package/kernel/mac80211/patches/subsys/341-v6.0-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch new file mode 100644 index 0000000000..8c56acbf88 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/341-v6.0-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch @@ -0,0 +1,40 @@ +From: Alexander Wetzel +Date: Thu, 15 Sep 2022 14:41:20 +0200 +Subject: [PATCH] mac80211: Fix deadlock: Don't start TX while holding + fq->lock + +ieee80211_txq_purge() calls fq_tin_reset() and +ieee80211_purge_tx_queue(); Both are then calling +ieee80211_free_txskb(). Which can decide to TX the skb again. + +There are at least two ways to get a deadlock: + +1) When we have a TDLS teardown packet queued in either tin or frags + ieee80211_tdls_td_tx_handle() will call ieee80211_subif_start_xmit() + while we still hold fq->lock. ieee80211_txq_enqueue() will thus + deadlock. + +2) A variant of the above happens if aggregation is up and running: + In that case ieee80211_iface_work() will deadlock with the original + task: The original tasks already holds fq->lock and tries to get + sta->lock after kicking off ieee80211_iface_work(). But the worker + can get sta->lock prior to the original task and will then spin for + fq->lock. + +Avoid these deadlocks by not sending out any skbs when called via +ieee80211_free_txskb(). + +Signed-off-by: Alexander Wetzel +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -698,7 +698,7 @@ static void ieee80211_report_used_skb(st + + if (!sdata) { + skb->dev = NULL; +- } else { ++ } else if (!dropped) { + unsigned int hdr_size = + ieee80211_hdrlen(hdr->frame_control); + diff --git a/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch b/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch deleted file mode 100644 index 4310329319..0000000000 --- a/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch +++ /dev/null @@ -1,47 +0,0 @@ -From: Alexander Wetzel -Date: Thu, 15 Sep 2022 15:09:46 +0200 -Subject: [PATCH] mac80211: Ensure vif queues are operational after start - -Make sure local->queue_stop_reasons and vif.txqs_stopped stay in sync. - -When a new vif is created the queues may end up in an inconsistent state -and be inoperable: -Communication not using iTXQ will work, allowing to e.g. complete the -association. But the 4-way handshake will time out. The sta will not -send out any skbs queued in iTXQs. - -All normal attempts to start the queues will fail when reaching this -state. -local->queue_stop_reasons will have marked all queues as operational but -vif.txqs_stopped will still be set, creating an inconsistent internal -state. - -In reality this seems to be race between the mac80211 function -ieee80211_do_open() setting SDATA_STATE_RUNNING and the wake_txqs_tasklet: -Depending on the driver and the timing the queues may end up to be -operational or not. - -Cc: stable@vger.kernel.org -Fixes: f856373e2f31 ("wifi: mac80211: do not wake queues on a vif that is being stopped") -Signed-off-by: Alexander Wetzel ---- - ---- a/net/mac80211/util.c -+++ b/net/mac80211/util.c -@@ -301,14 +301,14 @@ static void __ieee80211_wake_txqs(struct - local_bh_disable(); - spin_lock(&fq->lock); - -+ sdata->vif.txqs_stopped[ac] = false; -+ - if (!test_bit(SDATA_STATE_RUNNING, &sdata->state)) - goto out; - - if (sdata->vif.type == NL80211_IFTYPE_AP) - ps = &sdata->bss->ps; - -- sdata->vif.txqs_stopped[ac] = false; -- - list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sdata != sta->sdata) - continue; diff --git a/package/kernel/mac80211/patches/subsys/342-v6.0-mac80211-Ensure-vif-queues-are-operational-after-sta.patch b/package/kernel/mac80211/patches/subsys/342-v6.0-mac80211-Ensure-vif-queues-are-operational-after-sta.patch new file mode 100644 index 0000000000..4310329319 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/342-v6.0-mac80211-Ensure-vif-queues-are-operational-after-sta.patch @@ -0,0 +1,47 @@ +From: Alexander Wetzel +Date: Thu, 15 Sep 2022 15:09:46 +0200 +Subject: [PATCH] mac80211: Ensure vif queues are operational after start + +Make sure local->queue_stop_reasons and vif.txqs_stopped stay in sync. + +When a new vif is created the queues may end up in an inconsistent state +and be inoperable: +Communication not using iTXQ will work, allowing to e.g. complete the +association. But the 4-way handshake will time out. The sta will not +send out any skbs queued in iTXQs. + +All normal attempts to start the queues will fail when reaching this +state. +local->queue_stop_reasons will have marked all queues as operational but +vif.txqs_stopped will still be set, creating an inconsistent internal +state. + +In reality this seems to be race between the mac80211 function +ieee80211_do_open() setting SDATA_STATE_RUNNING and the wake_txqs_tasklet: +Depending on the driver and the timing the queues may end up to be +operational or not. + +Cc: stable@vger.kernel.org +Fixes: f856373e2f31 ("wifi: mac80211: do not wake queues on a vif that is being stopped") +Signed-off-by: Alexander Wetzel +--- + +--- a/net/mac80211/util.c ++++ b/net/mac80211/util.c +@@ -301,14 +301,14 @@ static void __ieee80211_wake_txqs(struct + local_bh_disable(); + spin_lock(&fq->lock); + ++ sdata->vif.txqs_stopped[ac] = false; ++ + if (!test_bit(SDATA_STATE_RUNNING, &sdata->state)) + goto out; + + if (sdata->vif.type == NL80211_IFTYPE_AP) + ps = &sdata->bss->ps; + +- sdata->vif.txqs_stopped[ac] = false; +- + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sdata != sta->sdata) + continue; diff --git a/package/kernel/mac80211/patches/subsys/343-v6.1-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch b/package/kernel/mac80211/patches/subsys/343-v6.1-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch new file mode 100644 index 0000000000..0246785475 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/343-v6.1-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch @@ -0,0 +1,37 @@ +From: Felix Fietkau +Date: Wed, 28 Sep 2022 13:50:34 +0200 +Subject: [PATCH] wifi: mac80211: fix decap offload for stations on AP_VLAN + interfaces + +Since AP_VLAN interfaces are not passed to the driver, check offload_flags +on the bss vif instead. + +Reported-by: Howard Hsu +Fixes: 80a915ec4427 ("mac80211: add rx decapsulation offload support") +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -4267,6 +4267,7 @@ void ieee80211_check_fast_rx(struct sta_ + .vif_type = sdata->vif.type, + .control_port_protocol = sdata->control_port_protocol, + }, *old, *new = NULL; ++ u32 offload_flags; + bool set_offload = false; + bool assign = false; + bool offload; +@@ -4382,10 +4383,10 @@ void ieee80211_check_fast_rx(struct sta_ + if (assign) + new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); + +- offload = assign && +- (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED); ++ offload_flags = get_bss_sdata(sdata)->vif.offload_flags; ++ offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED; + +- if (offload) ++ if (assign && offload) + set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); + else + set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); diff --git a/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch b/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch deleted file mode 100644 index 0246785475..0000000000 --- a/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch +++ /dev/null @@ -1,37 +0,0 @@ -From: Felix Fietkau -Date: Wed, 28 Sep 2022 13:50:34 +0200 -Subject: [PATCH] wifi: mac80211: fix decap offload for stations on AP_VLAN - interfaces - -Since AP_VLAN interfaces are not passed to the driver, check offload_flags -on the bss vif instead. - -Reported-by: Howard Hsu -Fixes: 80a915ec4427 ("mac80211: add rx decapsulation offload support") -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -4267,6 +4267,7 @@ void ieee80211_check_fast_rx(struct sta_ - .vif_type = sdata->vif.type, - .control_port_protocol = sdata->control_port_protocol, - }, *old, *new = NULL; -+ u32 offload_flags; - bool set_offload = false; - bool assign = false; - bool offload; -@@ -4382,10 +4383,10 @@ void ieee80211_check_fast_rx(struct sta_ - if (assign) - new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); - -- offload = assign && -- (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED); -+ offload_flags = get_bss_sdata(sdata)->vif.offload_flags; -+ offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED; - -- if (offload) -+ if (assign && offload) - set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); - else - set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); diff --git a/package/kernel/mac80211/patches/subsys/344-v6.1-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch b/package/kernel/mac80211/patches/subsys/344-v6.1-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch new file mode 100644 index 0000000000..161c7d6c8f --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/344-v6.1-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch @@ -0,0 +1,99 @@ +From: Felix Fietkau +Date: Fri, 7 Oct 2022 10:54:47 +0200 +Subject: [PATCH] wifi: cfg80211: fix ieee80211_data_to_8023_exthdr + handling of small packets + +STP topology change notification packets only have a payload of 7 bytes, +so they get dropped due to the skb->len < hdrlen + 8 check. +Fix this by removing skb->len based checks and instead check the return code +on the skb_copy_bits calls. + +Fixes: 2d1c304cb2d5 ("cfg80211: add function for 802.3 conversion with separate output buffer") +Reported-by: Chad Monroe +Signed-off-by: Felix Fietkau +--- + +--- a/net/wireless/util.c ++++ b/net/wireless/util.c +@@ -557,7 +557,7 @@ int ieee80211_data_to_8023_exthdr(struct + return -1; + + hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset; +- if (skb->len < hdrlen + 8) ++ if (skb->len < hdrlen) + return -1; + + /* convert IEEE 802.11 header + possible LLC headers into Ethernet +@@ -572,8 +572,9 @@ int ieee80211_data_to_8023_exthdr(struct + memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); + memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN); + +- if (iftype == NL80211_IFTYPE_MESH_POINT) +- skb_copy_bits(skb, hdrlen, &mesh_flags, 1); ++ if (iftype == NL80211_IFTYPE_MESH_POINT && ++ skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0) ++ return -1; + + mesh_flags &= MESH_FLAGS_AE; + +@@ -593,11 +594,12 @@ int ieee80211_data_to_8023_exthdr(struct + if (iftype == NL80211_IFTYPE_MESH_POINT) { + if (mesh_flags == MESH_FLAGS_AE_A4) + return -1; +- if (mesh_flags == MESH_FLAGS_AE_A5_A6) { +- skb_copy_bits(skb, hdrlen + +- offsetof(struct ieee80211s_hdr, eaddr1), +- tmp.h_dest, 2 * ETH_ALEN); +- } ++ if (mesh_flags == MESH_FLAGS_AE_A5_A6 && ++ skb_copy_bits(skb, hdrlen + ++ offsetof(struct ieee80211s_hdr, eaddr1), ++ tmp.h_dest, 2 * ETH_ALEN) < 0) ++ return -1; ++ + hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); + } + break; +@@ -611,10 +613,11 @@ int ieee80211_data_to_8023_exthdr(struct + if (iftype == NL80211_IFTYPE_MESH_POINT) { + if (mesh_flags == MESH_FLAGS_AE_A5_A6) + return -1; +- if (mesh_flags == MESH_FLAGS_AE_A4) +- skb_copy_bits(skb, hdrlen + +- offsetof(struct ieee80211s_hdr, eaddr1), +- tmp.h_source, ETH_ALEN); ++ if (mesh_flags == MESH_FLAGS_AE_A4 && ++ skb_copy_bits(skb, hdrlen + ++ offsetof(struct ieee80211s_hdr, eaddr1), ++ tmp.h_source, ETH_ALEN) < 0) ++ return -1; + hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); + } + break; +@@ -626,18 +629,18 @@ int ieee80211_data_to_8023_exthdr(struct + break; + } + +- skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); +- tmp.h_proto = payload.proto; +- +- if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && +- tmp.h_proto != htons(ETH_P_AARP) && +- tmp.h_proto != htons(ETH_P_IPX)) || +- ether_addr_equal(payload.hdr, bridge_tunnel_header))) ++ if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 && ++ ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && ++ payload.proto != htons(ETH_P_AARP) && ++ payload.proto != htons(ETH_P_IPX)) || ++ ether_addr_equal(payload.hdr, bridge_tunnel_header)))) { + /* remove RFC1042 or Bridge-Tunnel encapsulation and + * replace EtherType */ + hdrlen += ETH_ALEN + 2; +- else ++ tmp.h_proto = payload.proto; ++ } else { + tmp.h_proto = htons(skb->len - hdrlen); ++ } + + pskb_pull(skb, hdrlen); + diff --git a/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch b/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch deleted file mode 100644 index 161c7d6c8f..0000000000 --- a/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch +++ /dev/null @@ -1,99 +0,0 @@ -From: Felix Fietkau -Date: Fri, 7 Oct 2022 10:54:47 +0200 -Subject: [PATCH] wifi: cfg80211: fix ieee80211_data_to_8023_exthdr - handling of small packets - -STP topology change notification packets only have a payload of 7 bytes, -so they get dropped due to the skb->len < hdrlen + 8 check. -Fix this by removing skb->len based checks and instead check the return code -on the skb_copy_bits calls. - -Fixes: 2d1c304cb2d5 ("cfg80211: add function for 802.3 conversion with separate output buffer") -Reported-by: Chad Monroe -Signed-off-by: Felix Fietkau ---- - ---- a/net/wireless/util.c -+++ b/net/wireless/util.c -@@ -557,7 +557,7 @@ int ieee80211_data_to_8023_exthdr(struct - return -1; - - hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset; -- if (skb->len < hdrlen + 8) -+ if (skb->len < hdrlen) - return -1; - - /* convert IEEE 802.11 header + possible LLC headers into Ethernet -@@ -572,8 +572,9 @@ int ieee80211_data_to_8023_exthdr(struct - memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); - memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN); - -- if (iftype == NL80211_IFTYPE_MESH_POINT) -- skb_copy_bits(skb, hdrlen, &mesh_flags, 1); -+ if (iftype == NL80211_IFTYPE_MESH_POINT && -+ skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0) -+ return -1; - - mesh_flags &= MESH_FLAGS_AE; - -@@ -593,11 +594,12 @@ int ieee80211_data_to_8023_exthdr(struct - if (iftype == NL80211_IFTYPE_MESH_POINT) { - if (mesh_flags == MESH_FLAGS_AE_A4) - return -1; -- if (mesh_flags == MESH_FLAGS_AE_A5_A6) { -- skb_copy_bits(skb, hdrlen + -- offsetof(struct ieee80211s_hdr, eaddr1), -- tmp.h_dest, 2 * ETH_ALEN); -- } -+ if (mesh_flags == MESH_FLAGS_AE_A5_A6 && -+ skb_copy_bits(skb, hdrlen + -+ offsetof(struct ieee80211s_hdr, eaddr1), -+ tmp.h_dest, 2 * ETH_ALEN) < 0) -+ return -1; -+ - hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); - } - break; -@@ -611,10 +613,11 @@ int ieee80211_data_to_8023_exthdr(struct - if (iftype == NL80211_IFTYPE_MESH_POINT) { - if (mesh_flags == MESH_FLAGS_AE_A5_A6) - return -1; -- if (mesh_flags == MESH_FLAGS_AE_A4) -- skb_copy_bits(skb, hdrlen + -- offsetof(struct ieee80211s_hdr, eaddr1), -- tmp.h_source, ETH_ALEN); -+ if (mesh_flags == MESH_FLAGS_AE_A4 && -+ skb_copy_bits(skb, hdrlen + -+ offsetof(struct ieee80211s_hdr, eaddr1), -+ tmp.h_source, ETH_ALEN) < 0) -+ return -1; - hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); - } - break; -@@ -626,18 +629,18 @@ int ieee80211_data_to_8023_exthdr(struct - break; - } - -- skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); -- tmp.h_proto = payload.proto; -- -- if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && -- tmp.h_proto != htons(ETH_P_AARP) && -- tmp.h_proto != htons(ETH_P_IPX)) || -- ether_addr_equal(payload.hdr, bridge_tunnel_header))) -+ if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 && -+ ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) && -+ payload.proto != htons(ETH_P_AARP) && -+ payload.proto != htons(ETH_P_IPX)) || -+ ether_addr_equal(payload.hdr, bridge_tunnel_header)))) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - hdrlen += ETH_ALEN + 2; -- else -+ tmp.h_proto = payload.proto; -+ } else { - tmp.h_proto = htons(skb->len - hdrlen); -+ } - - pskb_pull(skb, hdrlen); - diff --git a/package/kernel/mac80211/patches/subsys/345-v6.1-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch b/package/kernel/mac80211/patches/subsys/345-v6.1-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch new file mode 100644 index 0000000000..23047f68c9 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/345-v6.1-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Fri, 7 Oct 2022 10:58:26 +0200 +Subject: [PATCH] wifi: mac80211: do not drop packets smaller than the + LLC-SNAP header on fast-rx + +Since STP TCN frames are only 7 bytes, the pskb_may_pull call returns an error. +Instead of dropping those packets, bump them back to the slow path for proper +processing. + +Fixes: 49ddf8e6e234 ("mac80211: add fast-rx path") +Reported-by: Chad Monroe +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -4603,7 +4603,7 @@ static bool ieee80211_invoke_fast_rx(str + + if (!(status->rx_flags & IEEE80211_RX_AMSDU)) { + if (!pskb_may_pull(skb, snap_offs + sizeof(*payload))) +- goto drop; ++ return false; + + payload = (void *)(skb->data + snap_offs); + diff --git a/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch b/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch deleted file mode 100644 index 23047f68c9..0000000000 --- a/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Felix Fietkau -Date: Fri, 7 Oct 2022 10:58:26 +0200 -Subject: [PATCH] wifi: mac80211: do not drop packets smaller than the - LLC-SNAP header on fast-rx - -Since STP TCN frames are only 7 bytes, the pskb_may_pull call returns an error. -Instead of dropping those packets, bump them back to the slow path for proper -processing. - -Fixes: 49ddf8e6e234 ("mac80211: add fast-rx path") -Reported-by: Chad Monroe -Signed-off-by: Felix Fietkau ---- - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -4603,7 +4603,7 @@ static bool ieee80211_invoke_fast_rx(str - - if (!(status->rx_flags & IEEE80211_RX_AMSDU)) { - if (!pskb_may_pull(skb, snap_offs + sizeof(*payload))) -- goto drop; -+ return false; - - payload = (void *)(skb->data + snap_offs); - diff --git a/package/kernel/mac80211/patches/subsys/363-bss-color-collision.patch b/package/kernel/mac80211/patches/subsys/363-bss-color-collision.patch deleted file mode 100644 index edee4b3ee0..0000000000 --- a/package/kernel/mac80211/patches/subsys/363-bss-color-collision.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 6d945a33f2b0aa24fc210dadaa0af3e8218e7002 Mon Sep 17 00:00:00 2001 -From: Lorenzo Bianconi -Date: Fri, 25 Mar 2022 11:42:41 +0100 -Subject: [PATCH] mac80211: introduce BSS color collision detection - -Add ieee80211_rx_check_bss_color_collision routine in order to introduce -BSS color collision detection in mac80211 if it is not supported in HW/FW -(e.g. for mt7915 chipset). -Add IEEE80211_HW_DETECTS_COLOR_COLLISION flag to let the driver notify -BSS color collision detection is supported in HW/FW. Set this for ath11k -which apparently didn't need this code. - -Tested-by: Peter Chiu -Co-developed-by: Ryder Lee -Signed-off-by: Ryder Lee -Signed-off-by: Lorenzo Bianconi -Link: https://lore.kernel.org/r/a05eeeb1841a84560dc5aaec77894fcb69a54f27.1648204871.git.lorenzo@kernel.org -[clarify commit message a bit, move flag to mac80211] -Signed-off-by: Johannes Berg ---- - drivers/net/wireless/ath/ath11k/mac.c | 5 ++- - include/net/mac80211.h | 4 +++ - net/mac80211/debugfs.c | 1 + - net/mac80211/rx.c | 46 +++++++++++++++++++++++++++ - 4 files changed, 55 insertions(+), 1 deletion(-) - ---- a/include/net/mac80211.h -+++ b/include/net/mac80211.h -@@ -2418,6 +2418,9 @@ struct ieee80211_txq { - * usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to - * the stack. - * -+ * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color -+ * collision detection and doesn't need it in software. -+ * - * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays - */ - enum ieee80211_hw_flags { -@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags { - IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, - IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, - IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP, -+ IEEE80211_HW_DETECTS_COLOR_COLLISION, - - /* keep last, obviously */ - NUM_IEEE80211_HW_FLAGS ---- a/net/mac80211/debugfs.c -+++ b/net/mac80211/debugfs.c -@@ -494,6 +494,7 @@ static const char *hw_flag_names[] = { - FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), - FLAG(SUPPORTS_RX_DECAP_OFFLOAD), - FLAG(SUPPORTS_CONC_MON_RX_DECAP), -+ FLAG(DETECTS_COLOR_COLLISION), - #undef FLAG - }; - ---- a/net/mac80211/rx.c -+++ b/net/mac80211/rx.c -@@ -3182,6 +3182,49 @@ static void ieee80211_process_sa_query_r - ieee80211_tx_skb(sdata, skb); - } - -+static void -+ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) -+{ -+ struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; -+ const struct element *ie; -+ size_t baselen; -+ -+ if (!wiphy_ext_feature_isset(rx->local->hw.wiphy, -+ NL80211_EXT_FEATURE_BSS_COLOR)) -+ return; -+ -+ if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) -+ return; -+ -+ if (rx->sdata->vif.csa_active) -+ return; -+ -+ baselen = mgmt->u.beacon.variable - rx->skb->data; -+ if (baselen > rx->skb->len) -+ return; -+ -+ ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, -+ mgmt->u.beacon.variable, -+ rx->skb->len - baselen); -+ if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) && -+ ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) { -+ struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf; -+ const struct ieee80211_he_operation *he_oper; -+ u8 color; -+ -+ he_oper = (void *)(ie->data + 1); -+ if (le32_get_bits(he_oper->he_oper_params, -+ IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED)) -+ return; -+ -+ color = le32_get_bits(he_oper->he_oper_params, -+ IEEE80211_HE_OPERATION_BSS_COLOR_MASK); -+ if (color == bss_conf->he_bss_color.color) -+ ieeee80211_obss_color_collision_notify(&rx->sdata->vif, -+ BIT_ULL(color)); -+ } -+} -+ - static ieee80211_rx_result debug_noinline - ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) - { -@@ -3207,6 +3250,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802 - !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { - int sig = 0; - -+ /* sw bss color collision detection */ -+ ieee80211_rx_check_bss_color_collision(rx); -+ - if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && - !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) - sig = status->signal; diff --git a/package/kernel/mac80211/patches/subsys/363-v5.19-bss-color-collision.patch b/package/kernel/mac80211/patches/subsys/363-v5.19-bss-color-collision.patch new file mode 100644 index 0000000000..edee4b3ee0 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/363-v5.19-bss-color-collision.patch @@ -0,0 +1,118 @@ +From 6d945a33f2b0aa24fc210dadaa0af3e8218e7002 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi +Date: Fri, 25 Mar 2022 11:42:41 +0100 +Subject: [PATCH] mac80211: introduce BSS color collision detection + +Add ieee80211_rx_check_bss_color_collision routine in order to introduce +BSS color collision detection in mac80211 if it is not supported in HW/FW +(e.g. for mt7915 chipset). +Add IEEE80211_HW_DETECTS_COLOR_COLLISION flag to let the driver notify +BSS color collision detection is supported in HW/FW. Set this for ath11k +which apparently didn't need this code. + +Tested-by: Peter Chiu +Co-developed-by: Ryder Lee +Signed-off-by: Ryder Lee +Signed-off-by: Lorenzo Bianconi +Link: https://lore.kernel.org/r/a05eeeb1841a84560dc5aaec77894fcb69a54f27.1648204871.git.lorenzo@kernel.org +[clarify commit message a bit, move flag to mac80211] +Signed-off-by: Johannes Berg +--- + drivers/net/wireless/ath/ath11k/mac.c | 5 ++- + include/net/mac80211.h | 4 +++ + net/mac80211/debugfs.c | 1 + + net/mac80211/rx.c | 46 +++++++++++++++++++++++++++ + 4 files changed, 55 insertions(+), 1 deletion(-) + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -2418,6 +2418,9 @@ struct ieee80211_txq { + * usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to + * the stack. + * ++ * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color ++ * collision detection and doesn't need it in software. ++ * + * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays + */ + enum ieee80211_hw_flags { +@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags { + IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, + IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, + IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP, ++ IEEE80211_HW_DETECTS_COLOR_COLLISION, + + /* keep last, obviously */ + NUM_IEEE80211_HW_FLAGS +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -494,6 +494,7 @@ static const char *hw_flag_names[] = { + FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), + FLAG(SUPPORTS_RX_DECAP_OFFLOAD), + FLAG(SUPPORTS_CONC_MON_RX_DECAP), ++ FLAG(DETECTS_COLOR_COLLISION), + #undef FLAG + }; + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -3182,6 +3182,49 @@ static void ieee80211_process_sa_query_r + ieee80211_tx_skb(sdata, skb); + } + ++static void ++ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx) ++{ ++ struct ieee80211_mgmt *mgmt = (void *)rx->skb->data; ++ const struct element *ie; ++ size_t baselen; ++ ++ if (!wiphy_ext_feature_isset(rx->local->hw.wiphy, ++ NL80211_EXT_FEATURE_BSS_COLOR)) ++ return; ++ ++ if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION)) ++ return; ++ ++ if (rx->sdata->vif.csa_active) ++ return; ++ ++ baselen = mgmt->u.beacon.variable - rx->skb->data; ++ if (baselen > rx->skb->len) ++ return; ++ ++ ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ++ mgmt->u.beacon.variable, ++ rx->skb->len - baselen); ++ if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) && ++ ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) { ++ struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf; ++ const struct ieee80211_he_operation *he_oper; ++ u8 color; ++ ++ he_oper = (void *)(ie->data + 1); ++ if (le32_get_bits(he_oper->he_oper_params, ++ IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED)) ++ return; ++ ++ color = le32_get_bits(he_oper->he_oper_params, ++ IEEE80211_HE_OPERATION_BSS_COLOR_MASK); ++ if (color == bss_conf->he_bss_color.color) ++ ieeee80211_obss_color_collision_notify(&rx->sdata->vif, ++ BIT_ULL(color)); ++ } ++} ++ + static ieee80211_rx_result debug_noinline + ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx) + { +@@ -3207,6 +3250,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802 + !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) { + int sig = 0; + ++ /* sw bss color collision detection */ ++ ieee80211_rx_check_bss_color_collision(rx); ++ + if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) && + !(status->flag & RX_FLAG_NO_SIGNAL_VAL)) + sig = status->signal;