diff --git a/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch b/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch new file mode 100644 index 00000000000..22697718f88 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch @@ -0,0 +1,651 @@ +From: Felix Fietkau +Date: Thu, 13 Aug 2020 15:37:11 +0200 +Subject: [PATCH] mac80211: rework tx encapsulation offload API + +The current API (which lets the driver turn on/off per vif directly) has a +number of limitations: +- it does not deal with AP_VLAN +- conditions for enabling (no tkip, no monitor) are only checked at + add_interface time +- no way to indicate 4-addr support + +In order to address this, store offload flags in struct ieee80211_vif +(easy to extend for decap offload later). mac80211 initially sets the enable +flag, but gives the driver a chance to modify it before its settings are +applied. In addition to the .add_interface op, a .update_vif_offload op is +introduced, which can be used for runtime changes. + +If a driver can't disable encap offload at runtime, or if it has some extra +limitations, it can simply override the flags within those ops. + +Support for encap offload with 4-address mode interfaces can be enabled +by setting a flag from .add_interface or .update_vif_offload. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -4150,6 +4150,35 @@ static int ath11k_set_he_mu_sounding_mod + return ret; + } + ++static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif) ++{ ++ struct ath11k *ar = hw->priv; ++ struct ath11k_base *ab = ar->ab; ++ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); ++ u32 param_id, param_value; ++ int ret; ++ ++ param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE; ++ if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET || ++ (vif->type != NL80211_IFTYPE_STATION && ++ vif->type != NL80211_IFTYPE_AP)) ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ ++ if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) ++ param_value = ATH11K_HW_TXRX_ETHERNET; ++ else ++ param_value = ATH11K_HW_TXRX_NATIVE_WIFI; ++ ++ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, ++ param_id, param_value); ++ if (ret) { ++ ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n", ++ arvif->vdev_id, ret); ++ vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ } ++} ++ + static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) + { +@@ -4159,7 +4188,6 @@ static int ath11k_mac_op_add_interface(s + struct vdev_create_params vdev_param = {0}; + struct peer_create_params peer_param; + u32 param_id, param_value; +- int hw_encap = 0; + u16 nss; + int i; + int ret; +@@ -4253,30 +4281,7 @@ static int ath11k_mac_op_add_interface(s + list_add(&arvif->list, &ar->arvifs); + spin_unlock_bh(&ar->data_lock); + +- param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE; +- if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET) +- switch (vif->type) { +- case NL80211_IFTYPE_STATION: +- case NL80211_IFTYPE_AP_VLAN: +- case NL80211_IFTYPE_AP: +- hw_encap = 1; +- break; +- default: +- break; +- } +- +- if (ieee80211_set_hw_80211_encap(vif, hw_encap)) +- param_value = ATH11K_HW_TXRX_ETHERNET; +- else +- param_value = ATH11K_HW_TXRX_NATIVE_WIFI; +- +- ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +- param_id, param_value); +- if (ret) { +- ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n", +- arvif->vdev_id, ret); +- goto err_vdev_del; +- } ++ ath11k_mac_op_update_vif_offload(hw, vif); + + nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1; + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, +@@ -5599,6 +5604,7 @@ static const struct ieee80211_ops ath11k + .reconfig_complete = ath11k_mac_op_reconfig_complete, + .add_interface = ath11k_mac_op_add_interface, + .remove_interface = ath11k_mac_op_remove_interface, ++ .update_vif_offload = ath11k_mac_op_update_vif_offload, + .config = ath11k_mac_op_config, + .bss_info_changed = ath11k_mac_op_bss_info_changed, + .configure_filter = ath11k_mac_op_configure_filter, +@@ -5852,6 +5858,7 @@ static int __ath11k_mac_register(struct + ieee80211_hw_set(ar->hw, QUEUE_CONTROL); + ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG); + ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK); ++ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD); + if (ht_cap & WMI_HT_CAP_ENABLED) { + ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION); + ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW); +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1603,6 +1603,21 @@ enum ieee80211_vif_flags { + IEEE80211_VIF_GET_NOA_UPDATE = BIT(3), + }; + ++ ++/** ++ * enum ieee80211_offload_flags - virtual interface offload flags ++ * ++ * @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled ++ * The driver supports sending frames passed as 802.3 frames by mac80211. ++ * It must also support sending 802.11 packets for the same interface. ++ * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload ++ */ ++ ++enum ieee80211_offload_flags { ++ IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0), ++ IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), ++}; ++ + /** + * struct ieee80211_vif - per-interface data + * +@@ -1623,6 +1638,11 @@ enum ieee80211_vif_flags { + * these need to be set (or cleared) when the interface is added + * or, if supported by the driver, the interface type is changed + * at runtime, mac80211 will never touch this field ++ * @offloaad_flags: hardware offload capabilities/flags for this interface. ++ * These are initialized by mac80211 before calling .add_interface, ++ * .change_interface or .update_vif_offload and updated by the driver ++ * within these ops, based on supported features or runtime change ++ * restrictions. + * @hw_queue: hardware queue for each AC + * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only + * @chanctx_conf: The channel context this interface is assigned to, or %NULL +@@ -1659,6 +1679,7 @@ struct ieee80211_vif { + struct ieee80211_chanctx_conf __rcu *chanctx_conf; + + u32 driver_flags; ++ u32 offload_flags; + + #ifdef CPTCFG_MAC80211_DEBUGFS + struct dentry *debugfs_dir; +@@ -2325,6 +2346,9 @@ struct ieee80211_txq { + * aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx + * A-MPDU sessions active while rekeying with Extended Key ID. + * ++ * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation ++ * offload ++ * + * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays + */ + enum ieee80211_hw_flags { +@@ -2377,6 +2401,7 @@ enum ieee80211_hw_flags { + IEEE80211_HW_SUPPORTS_MULTI_BSSID, + IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, + IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT, ++ IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, + + /* keep last, obviously */ + NUM_IEEE80211_HW_FLAGS +@@ -3811,6 +3836,8 @@ enum ieee80211_reconfig_type { + * @set_tid_config: Apply TID specific configurations. This callback may sleep. + * @reset_tid_config: Reset TID specific configuration for the peer. + * This callback may sleep. ++ * @update_vif_config: Update virtual interface offload flags ++ * This callback may sleep. + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, +@@ -4122,6 +4149,8 @@ struct ieee80211_ops { + int (*reset_tid_config)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u8 tids); ++ void (*update_vif_offload)(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif); + }; + + /** +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -504,6 +504,7 @@ static int ieee80211_del_key(struct wiph + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + struct ieee80211_key *key = NULL; ++ bool recalc_offload = false; + int ret; + + mutex_lock(&local->sta_mtx); +@@ -528,6 +529,7 @@ static int ieee80211_del_key(struct wiph + goto out_unlock; + } + ++ recalc_offload = key->conf.cipher == WLAN_CIPHER_SUITE_TKIP; + ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION); + + ret = 0; +@@ -535,6 +537,9 @@ static int ieee80211_del_key(struct wiph + mutex_unlock(&local->key_mtx); + mutex_unlock(&local->sta_mtx); + ++ if (recalc_offload) ++ ieee80211_recalc_offload(local); ++ + return ret; + } + +--- a/net/mac80211/debugfs.c ++++ b/net/mac80211/debugfs.c +@@ -408,6 +408,7 @@ static const char *hw_flag_names[] = { + FLAG(SUPPORTS_MULTI_BSSID), + FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), + FLAG(AMPDU_KEYBORDER_SUPPORT), ++ FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), + #undef FLAG + }; + +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1385,4 +1385,19 @@ static inline int drv_reset_tid_config(s + + return ret; + } ++ ++static inline void drv_update_vif_offload(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata) ++{ ++ might_sleep(); ++ check_sdata_in_driver(sdata); ++ ++ if (!local->ops->update_vif_offload) ++ return; ++ ++ trace_drv_update_vif_offload(local, sdata); ++ local->ops->update_vif_offload(&local->hw, &sdata->vif); ++ trace_drv_return_void(local); ++} ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -990,8 +990,6 @@ struct ieee80211_sub_if_data { + } debugfs; + #endif + +- bool hw_80211_encap; +- + /* must be last, dynamically sized area in this! */ + struct ieee80211_vif vif; + }; +@@ -1769,6 +1767,7 @@ void ieee80211_del_virtual_monitor(struc + bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata); + void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata, + bool update_bss); ++void ieee80211_recalc_offload(struct ieee80211_local *local); + + static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) + { +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -43,6 +43,7 @@ + */ + + static void ieee80211_iface_work(struct work_struct *work); ++static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata); + + bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata) + { +@@ -348,6 +349,99 @@ static int ieee80211_check_queues(struct + return 0; + } + ++static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype) ++{ ++ switch (iftype) { ++ case NL80211_IFTYPE_AP: ++ case NL80211_IFTYPE_P2P_GO: ++ case NL80211_IFTYPE_P2P_CLIENT: ++ case NL80211_IFTYPE_STATION: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_key *key; ++ u32 flags; ++ ++ flags = sdata->vif.offload_flags; ++ ++ if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && ++ ieee80211_iftype_supports_encap_offload(sdata->vif.type)) { ++ flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ mutex_lock(&local->key_mtx); ++ list_for_each_entry(key, &sdata->key_list, list) { ++ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) ++ continue; ++ if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP || ++ !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) ++ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ } ++ mutex_unlock(&local->key_mtx); ++ ++ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && ++ local->hw.wiphy->frag_threshold != (u32)-1) ++ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ ++ if (local->monitors) ++ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ } else { ++ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ } ++ ++ if (sdata->vif.offload_flags == flags) ++ return false; ++ ++ sdata->vif.offload_flags = flags; ++ return true; ++} ++ ++ ++static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_sub_if_data *vsdata; ++ ++ if (ieee80211_set_sdata_offload_flags(sdata)) { ++ drv_update_vif_offload(local, sdata); ++ ieee80211_set_vif_encap_ops(sdata); ++ } ++ ++ list_for_each_entry(vsdata, &local->interfaces, list) { ++ if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN || ++ vsdata->bss != &sdata->u.ap) ++ continue; ++ ++ ieee80211_set_vif_encap_ops(vsdata); ++ } ++} ++ ++void ieee80211_recalc_offload(struct ieee80211_local *local) ++{ ++ struct ieee80211_sub_if_data *sdata; ++ ++ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD)) ++ return; ++ ++ mutex_lock(&local->iflist_mtx); ++ ++ list_for_each_entry(sdata, &local->interfaces, list) { ++ if (!ieee80211_sdata_running(sdata)) ++ continue; ++ ++ ieee80211_recalc_sdata_offload(sdata); ++ } ++ ++ mutex_unlock(&local->iflist_mtx); ++} ++ + void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, + const int offset) + { +@@ -587,6 +681,7 @@ int ieee80211_do_open(struct wireless_de + if (rtnl_dereference(sdata->bss->beacon)) { + ieee80211_vif_vlan_copy_chanctx(sdata); + netif_carrier_on(dev); ++ ieee80211_set_vif_encap_ops(sdata); + } else { + netif_carrier_off(dev); + } +@@ -616,6 +711,7 @@ int ieee80211_do_open(struct wireless_de + + ieee80211_adjust_monitor_flags(sdata, 1); + ieee80211_configure_filter(local); ++ ieee80211_recalc_offload(local); + mutex_lock(&local->mtx); + ieee80211_recalc_idle(local); + mutex_unlock(&local->mtx); +@@ -625,10 +721,13 @@ int ieee80211_do_open(struct wireless_de + default: + if (coming_up) { + ieee80211_del_virtual_monitor(local); ++ ieee80211_set_sdata_offload_flags(sdata); + + res = drv_add_interface(local, sdata); + if (res) + goto err_stop; ++ ++ ieee80211_set_vif_encap_ops(sdata); + res = ieee80211_check_queues(sdata, + ieee80211_vif_type_p2p(&sdata->vif)); + if (res) +@@ -1286,61 +1385,6 @@ static const struct net_device_ops ieee8 + + }; + +-static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata, +- bool enable) +-{ +- sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops : +- &ieee80211_dataif_ops; +- sdata->hw_80211_encap = enable; +-} +- +-bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable) +-{ +- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); +- struct ieee80211_local *local = sdata->local; +- struct ieee80211_sub_if_data *iter; +- struct ieee80211_key *key; +- +- mutex_lock(&local->iflist_mtx); +- list_for_each_entry(iter, &local->interfaces, list) { +- struct ieee80211_sub_if_data *disable = NULL; +- +- if (vif->type == NL80211_IFTYPE_MONITOR) { +- disable = iter; +- __ieee80211_set_hw_80211_encap(iter, false); +- } else if (iter->vif.type == NL80211_IFTYPE_MONITOR) { +- disable = sdata; +- enable = false; +- } +- if (disable) +- sdata_dbg(disable, +- "disable hw 80211 encap due to mon co-exist\n"); +- } +- mutex_unlock(&local->iflist_mtx); +- +- if (enable == sdata->hw_80211_encap) +- return enable; +- +- if (!sdata->dev) +- return false; +- +- if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && +- (local->hw.wiphy->frag_threshold != (u32)-1)) +- enable = false; +- +- mutex_lock(&sdata->local->key_mtx); +- list_for_each_entry(key, &sdata->key_list, list) { +- if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP) +- enable = false; +- } +- mutex_unlock(&sdata->local->key_mtx); +- +- __ieee80211_set_hw_80211_encap(sdata, enable); +- +- return enable; +-} +-EXPORT_SYMBOL(ieee80211_set_hw_80211_encap); +- + static void ieee80211_if_free(struct net_device *dev) + { + free_percpu(netdev_tstats(dev)); +@@ -1371,6 +1415,51 @@ static void ieee80211_if_setup_no_queue( + #endif + } + ++static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata) ++{ ++ struct ieee80211_local *local = sdata->local; ++ struct ieee80211_sub_if_data *bss = sdata; ++ struct ieee80211_key *key; ++ bool enabled; ++ ++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { ++ if (!sdata->bss) ++ return; ++ ++ bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); ++ } ++ ++ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) || ++ !ieee80211_iftype_supports_encap_offload(bss->vif.type)) ++ return; ++ ++ enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; ++ if (sdata->wdev.use_4addr && ++ !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR)) ++ enabled = false; ++ ++ /* ++ * Encapsulation offload cannot be used with software crypto, and a per-VLAN ++ * key may have been set ++ */ ++ if (enabled && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { ++ mutex_lock(&local->key_mtx); ++ list_for_each_entry(key, &sdata->key_list, list) { ++ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) ++ continue; ++ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) ++ enabled = false; ++ } ++ mutex_unlock(&local->key_mtx); ++ } ++ ++ sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops : ++ &ieee80211_dataif_ops; ++} ++ + static void ieee80211_iface_work(struct work_struct *work) + { + struct ieee80211_sub_if_data *sdata = +@@ -1553,7 +1642,6 @@ static void ieee80211_setup_sdata(struct + sdata->vif.bss_conf.txpower = INT_MIN; /* unset */ + + sdata->noack_map = 0; +- sdata->hw_80211_encap = false; + + /* only monitor/p2p-device differ */ + if (sdata->dev) { +@@ -1688,6 +1776,7 @@ static int ieee80211_runtime_change_ifty + + ieee80211_teardown_sdata(sdata); + ++ ieee80211_set_sdata_offload_flags(sdata); + ret = drv_change_interface(local, sdata, internal_type, p2p); + if (ret) + type = ieee80211_vif_type_p2p(&sdata->vif); +@@ -1700,6 +1789,7 @@ static int ieee80211_runtime_change_ifty + ieee80211_check_queues(sdata, type); + + ieee80211_setup_sdata(sdata, type); ++ ieee80211_set_vif_encap_ops(sdata); + + err = ieee80211_do_open(&sdata->wdev, false); + WARN(err, "type change: do_open returned %d", err); +--- a/net/mac80211/key.c ++++ b/net/mac80211/key.c +@@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel + } + } + +- /* TKIP countermeasures don't work in encap offload mode */ +- if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP && +- sdata->hw_80211_encap) { +- sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n"); +- return -EINVAL; +- } +- + ret = drv_set_key(key->local, SET_KEY, sdata, + sta ? &sta->sta : NULL, &key->conf); + +@@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: +- /* We cannot do software crypto of data frames with +- * encapsulation offload enabled. However for 802.11w to +- * function properly we need cmac/gmac keys. +- */ +- if (sdata->hw_80211_encap) +- return -EINVAL; +- /* Fall through */ +- + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: +@@ -824,6 +809,7 @@ int ieee80211_key_link(struct ieee80211_ + */ + bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION; + int ret = -EOPNOTSUPP; ++ bool recalc_offload = false; + + mutex_lock(&sdata->local->key_mtx); + +@@ -864,11 +850,15 @@ int ieee80211_key_link(struct ieee80211_ + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; ++ recalc_offload = !old_key && key->conf.cipher == WLAN_CIPHER_SUITE_TKIP; + + increment_tailroom_need_count(sdata); + + ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key); + ++ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) ++ recalc_offload = true; ++ + if (!ret) { + ieee80211_debugfs_key_add(key); + ieee80211_key_destroy(old_key, delay_tailroom); +@@ -879,6 +869,9 @@ int ieee80211_key_link(struct ieee80211_ + out: + mutex_unlock(&sdata->local->key_mtx); + ++ if (recalc_offload) ++ ieee80211_recalc_offload(sdata->local); ++ + return ret; + } + +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2733,6 +2733,12 @@ TRACE_EVENT(drv_get_ftm_responder_stats, + ) + ); + ++DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata), ++ TP_ARGS(local, sdata) ++); ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4270,11 +4270,6 @@ netdev_tx_t ieee80211_subif_start_xmit_8 + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sta_info *sta; + +- if (WARN_ON(!sdata->hw_80211_encap)) { +- kfree_skb(skb); +- return NETDEV_TX_OK; +- } +- + if (unlikely(skb->len < ETH_HLEN)) { + kfree_skb(skb); + return NETDEV_TX_OK; diff --git a/package/kernel/mac80211/patches/subsys/315-mac80211-reduce-duplication-in-tx-status-functions.patch b/package/kernel/mac80211/patches/subsys/315-mac80211-reduce-duplication-in-tx-status-functions.patch new file mode 100644 index 00000000000..8b664d6895a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/315-mac80211-reduce-duplication-in-tx-status-functions.patch @@ -0,0 +1,197 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:16:59 +0200 +Subject: [PATCH] mac80211: reduce duplication in tx status functions + +Move redundant functionality from __ieee80211_tx_status into +ieee80211_tx_status_ext. Preparation for unifying with the 802.3 tx status +codepath. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -184,18 +184,6 @@ static void ieee80211_frame_acked(struct + struct ieee80211_mgmt *mgmt = (void *) skb->data; + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; +- struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); +- +- if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { +- sta->status_stats.last_ack = jiffies; +- if (txinfo->status.is_valid_ack_signal) { +- sta->status_stats.last_ack_signal = +- (s8)txinfo->status.ack_signal; +- sta->status_stats.ack_signal_filled = true; +- ewma_avg_signal_add(&sta->status_stats.avg_ack_signal, +- -txinfo->status.ack_signal); +- } +- } + + if (ieee80211_is_data_qos(mgmt->frame_control)) { + struct ieee80211_hdr *hdr = (void *) skb->data; +@@ -899,7 +887,8 @@ void ieee80211_tx_monitor(struct ieee802 + } + + static void __ieee80211_tx_status(struct ieee80211_hw *hw, +- struct ieee80211_tx_status *status) ++ struct ieee80211_tx_status *status, ++ int rates_idx, int retry_count) + { + struct sk_buff *skb = status->skb; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; +@@ -908,8 +897,6 @@ static void __ieee80211_tx_status(struct + struct sta_info *sta; + __le16 fc; + struct ieee80211_supported_band *sband; +- int retry_count; +- int rates_idx; + bool send_to_cooked; + bool acked; + bool noack_success; +@@ -918,8 +905,6 @@ static void __ieee80211_tx_status(struct + int tid = IEEE80211_NUM_TIDS; + u16 tx_time_est; + +- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); +- + sband = local->hw.wiphy->bands[info->band]; + fc = hdr->frame_control; + +@@ -996,24 +981,14 @@ static void __ieee80211_tx_status(struct + if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + ieee80211_handle_filtered_frame(local, sta, skb); + return; +- } else { ++ } else if (ieee80211_is_data_present(fc)) { + if (!acked && !noack_success) +- sta->status_stats.retry_failed++; +- sta->status_stats.retry_count += retry_count; +- +- if (ieee80211_is_data_present(fc)) { +- if (!acked && !noack_success) +- sta->status_stats.msdu_failed[tid]++; ++ sta->status_stats.msdu_failed[tid]++; + +- sta->status_stats.msdu_retries[tid] += +- retry_count; +- } ++ sta->status_stats.msdu_retries[tid] += ++ retry_count; + } + +- rate_control_tx_status(local, sband, status); +- if (ieee80211_vif_is_mesh(&sta->sdata->vif)) +- ieee80211s_update_metric(local, sta, status); +- + if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked) + ieee80211_frame_acked(sta, skb); + +@@ -1038,20 +1013,6 @@ static void __ieee80211_tx_status(struct + true); + ieee80211_info_set_tx_time_est(info, 0); + } +- +- if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { +- if (acked) { +- if (sta->status_stats.lost_packets) +- sta->status_stats.lost_packets = 0; +- +- /* Track when last TDLS packet was ACKed */ +- sta->status_stats.last_pkt_time = jiffies; +- } else if (noack_success) { +- /* nothing to do here, do not account as lost */ +- } else { +- ieee80211_lost_packet(sta, info); +- } +- } + } + + /* SNMP counters +@@ -1135,7 +1096,7 @@ void ieee80211_tx_status(struct ieee8021 + if (sta) + status.sta = &sta->sta; + +- __ieee80211_tx_status(hw, &status); ++ ieee80211_tx_status_ext(hw, &status); + rcu_read_unlock(); + } + EXPORT_SYMBOL(ieee80211_tx_status); +@@ -1148,7 +1109,7 @@ void ieee80211_tx_status_ext(struct ieee + struct ieee80211_sta *pubsta = status->sta; + struct ieee80211_supported_band *sband; + struct sta_info *sta; +- int retry_count; ++ int rates_idx, retry_count; + bool acked, noack_success; + + if (pubsta) { +@@ -1158,13 +1119,7 @@ void ieee80211_tx_status_ext(struct ieee + sta->tx_stats.last_rate_info = *status->rate; + } + +- if (status->skb) +- return __ieee80211_tx_status(hw, status); +- +- if (!status->sta) +- return; +- +- ieee80211_tx_get_rates(hw, info, &retry_count); ++ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); + + sband = hw->wiphy->bands[info->band]; + +@@ -1176,20 +1131,30 @@ void ieee80211_tx_status_ext(struct ieee + sta->status_stats.retry_failed++; + sta->status_stats.retry_count += retry_count; + +- if (acked) { +- sta->status_stats.last_ack = jiffies; ++ if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { ++ if (acked) { ++ sta->status_stats.last_ack = jiffies; + +- if (sta->status_stats.lost_packets) +- sta->status_stats.lost_packets = 0; ++ if (sta->status_stats.lost_packets) ++ sta->status_stats.lost_packets = 0; + +- /* Track when last packet was ACKed */ +- sta->status_stats.last_pkt_time = jiffies; +- } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { +- return; +- } else if (noack_success) { +- /* nothing to do here, do not account as lost */ +- } else { +- ieee80211_lost_packet(sta, info); ++ /* Track when last packet was ACKed */ ++ sta->status_stats.last_pkt_time = jiffies; ++ ++ if (info->status.is_valid_ack_signal) { ++ sta->status_stats.last_ack_signal = ++ (s8)info->status.ack_signal; ++ sta->status_stats.ack_signal_filled = true; ++ ewma_avg_signal_add(&sta->status_stats.avg_ack_signal, ++ -info->status.ack_signal); ++ } ++ } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { ++ return; ++ } else if (noack_success) { ++ /* nothing to do here, do not account as lost */ ++ } else { ++ ieee80211_lost_packet(sta, info); ++ } + } + + rate_control_tx_status(local, sband, status); +@@ -1197,6 +1162,10 @@ void ieee80211_tx_status_ext(struct ieee + ieee80211s_update_metric(local, sta, status); + } + ++ if (status->skb) ++ return __ieee80211_tx_status(hw, status, rates_idx, ++ retry_count); ++ + if (acked || noack_success) { + I802_DEBUG_INC(local->dot11TransmittedFrameCount); + if (!pubsta) diff --git a/package/kernel/mac80211/patches/subsys/316-mac80211-remove-tx-status-call-to-ieee80211_sta_regi.patch b/package/kernel/mac80211/patches/subsys/316-mac80211-remove-tx-status-call-to-ieee80211_sta_regi.patch new file mode 100644 index 00000000000..168d6458a52 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/316-mac80211-remove-tx-status-call-to-ieee80211_sta_regi.patch @@ -0,0 +1,26 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:29:12 +0200 +Subject: [PATCH] mac80211: remove tx status call to + ieee80211_sta_register_airtime + +All drivers using airtime fairness are calling ieee80211_sta_register_airtime +directly + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -997,12 +997,6 @@ static void __ieee80211_tx_status(struct + ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, + acked, info->status.tx_time); + +- if (info->status.tx_time && +- wiphy_ext_feature_isset(local->hw.wiphy, +- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) +- ieee80211_sta_register_airtime(&sta->sta, tid, +- info->status.tx_time, 0); +- + if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) { + /* Do this here to avoid the expensive lookup of the sta + * in ieee80211_report_used_skb(). diff --git a/package/kernel/mac80211/patches/subsys/317-mac80211-optimize-station-connection-monitor.patch b/package/kernel/mac80211/patches/subsys/317-mac80211-optimize-station-connection-monitor.patch new file mode 100644 index 00000000000..ed9efb2b0d4 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/317-mac80211-optimize-station-connection-monitor.patch @@ -0,0 +1,174 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:29:56 +0200 +Subject: [PATCH] mac80211: optimize station connection monitor + +Calling mod_timer for every rx/tx packet can be quite expensive. +Instead of constantly updating the timer, we can simply let it run out +and check the timestamp of the last ACK or rx packet to re-arm it. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/ieee80211_i.h ++++ b/net/mac80211/ieee80211_i.h +@@ -2045,8 +2045,6 @@ void ieee80211_dynamic_ps_timer(struct t + void ieee80211_send_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + bool powersave); +-void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, +- struct ieee80211_hdr *hdr); + void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata, + struct ieee80211_hdr *hdr, bool ack, u16 tx_time); + +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2432,23 +2432,6 @@ static void ieee80211_set_disassoc(struc + sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM; + } + +-void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata, +- struct ieee80211_hdr *hdr) +-{ +- /* +- * We can postpone the mgd.timer whenever receiving unicast frames +- * from AP because we know that the connection is working both ways +- * at that time. But multicast frames (and hence also beacons) must +- * be ignored here, because we need to trigger the timer during +- * data idle periods for sending the periodic probe request to the +- * AP we're connected to. +- */ +- if (is_multicast_ether_addr(hdr->addr1)) +- return; +- +- ieee80211_sta_reset_conn_monitor(sdata); +-} +- + static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata) + { + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; +@@ -2521,21 +2504,13 @@ void ieee80211_sta_tx_notify(struct ieee + { + ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time); + +- if (!ieee80211_is_data(hdr->frame_control)) +- return; +- +- if (ieee80211_is_any_nullfunc(hdr->frame_control) && +- sdata->u.mgd.probe_send_count > 0) { +- if (ack) +- ieee80211_sta_reset_conn_monitor(sdata); +- else +- sdata->u.mgd.nullfunc_failed = true; +- ieee80211_queue_work(&sdata->local->hw, &sdata->work); ++ if (!ieee80211_is_any_nullfunc(hdr->frame_control) || ++ !sdata->u.mgd.probe_send_count) + return; +- } + +- if (ack) +- ieee80211_sta_reset_conn_monitor(sdata); ++ if (!ack) ++ sdata->u.mgd.nullfunc_failed = true; ++ ieee80211_queue_work(&sdata->local->hw, &sdata->work); + } + + static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata, +@@ -3600,8 +3575,8 @@ static bool ieee80211_assoc_success(stru + * Start timer to probe the connection to the AP now. + * Also start the timer that will detect beacon loss. + */ +- ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt); + ieee80211_sta_reset_beacon_monitor(sdata); ++ ieee80211_sta_reset_conn_monitor(sdata); + + ret = true; + out: +@@ -4569,10 +4544,26 @@ static void ieee80211_sta_conn_mon_timer + from_timer(sdata, t, u.mgd.conn_mon_timer); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct ieee80211_local *local = sdata->local; ++ struct sta_info *sta; ++ unsigned long timeout; + + if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn) + return; + ++ sta = sta_info_get(sdata, ifmgd->bssid); ++ if (!sta) ++ return; ++ ++ timeout = sta->status_stats.last_ack; ++ if (time_before(sta->status_stats.last_ack, sta->rx_stats.last_rx)) ++ timeout = sta->rx_stats.last_rx; ++ timeout += IEEE80211_CONNECTION_IDLE_TIME; ++ ++ if (time_is_before_jiffies(timeout)) { ++ mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout)); ++ return; ++ } ++ + ieee80211_queue_work(&local->hw, &ifmgd->monitor_work); + } + +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -1811,9 +1811,6 @@ ieee80211_rx_h_sta_process(struct ieee80 + sta->rx_stats.last_rate = sta_stats_encode_rate(status); + } + +- if (rx->sdata->vif.type == NL80211_IFTYPE_STATION) +- ieee80211_sta_rx_notify(rx->sdata, hdr); +- + sta->rx_stats.fragments++; + + u64_stats_update_begin(&rx->sta->rx_stats.syncp); +@@ -4148,7 +4145,6 @@ void ieee80211_check_fast_rx(struct sta_ + fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2); + fastrx.expected_ds_bits = 0; + } else { +- fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0; + fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1); + fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3); + fastrx.expected_ds_bits = +@@ -4378,11 +4374,6 @@ static bool ieee80211_invoke_fast_rx(str + pskb_trim(skb, skb->len - fast_rx->icv_len)) + goto drop; + +- if (unlikely(fast_rx->sta_notify)) { +- ieee80211_sta_rx_notify(rx->sdata, hdr); +- fast_rx->sta_notify = false; +- } +- + /* statistics part of ieee80211_rx_h_sta_process() */ + if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { + stats->last_signal = status->signal; +--- a/net/mac80211/sta_info.h ++++ b/net/mac80211/sta_info.h +@@ -336,7 +336,6 @@ struct ieee80211_fast_tx { + * @expected_ds_bits: from/to DS bits expected + * @icv_len: length of the MIC if present + * @key: bool indicating encryption is expected (key is set) +- * @sta_notify: notify the MLME code (once) + * @internal_forward: forward froms internally on AP/VLAN type interfaces + * @uses_rss: copy of USES_RSS hw flag + * @da_offs: offset of the DA in the header (for header conversion) +@@ -352,7 +351,6 @@ struct ieee80211_fast_rx { + __le16 expected_ds_bits; + u8 icv_len; + u8 key:1, +- sta_notify:1, + internal_forward:1, + uses_rss:1; + u8 da_offs, sa_offs; +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -1227,9 +1227,6 @@ void ieee80211_tx_status_8023(struct iee + sta->status_stats.retry_count += retry_count; + + if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) { +- if (acked && vif->type == NL80211_IFTYPE_STATION) +- ieee80211_sta_reset_conn_monitor(sdata); +- + sta->status_stats.last_ack = jiffies; + if (info->flags & IEEE80211_TX_STAT_ACK) { + if (sta->status_stats.lost_packets) diff --git a/package/kernel/mac80211/patches/subsys/318-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch b/package/kernel/mac80211/patches/subsys/318-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch new file mode 100644 index 00000000000..a0ce6a2b15e --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/318-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch @@ -0,0 +1,227 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:35:32 +0200 +Subject: [PATCH] mac80211: swap NEED_TXPROCESSING and HW_80211_ENCAP tx + flags + +In order to unify the tx status path, the hw 802.11 encapsulation flag +needs to survive the trip to the tx status call. +Since we don't have any free bits in info->flags, we need to move one. +IEEE80211_TX_INTFL_NEED_TXPROCESSING is only used internally in mac80211, +and only before the call into the driver. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath11k/dp_tx.c ++++ b/drivers/net/wireless/ath/ath11k/dp_tx.c +@@ -14,7 +14,7 @@ ath11k_dp_tx_get_encap_type(struct ath11 + { + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + +- if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) ++ if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) + return HAL_TCL_ENCAP_TYPE_ETHERNET; + + return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI; +@@ -93,7 +93,7 @@ int ath11k_dp_tx(struct ath11k *ar, stru + if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) + return -ESHUTDOWN; + +- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) && ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + !ieee80211_is_data(hdr->frame_control)) + return -ENOTSUPP; + +--- a/drivers/net/wireless/ath/ath11k/mac.c ++++ b/drivers/net/wireless/ath/ath11k/mac.c +@@ -3749,7 +3749,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct + return -ENOSPC; + + info = IEEE80211_SKB_CB(skb); +- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) { ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) { + if ((ieee80211_is_action(hdr->frame_control) || + ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control)) && +@@ -3876,7 +3876,7 @@ static void ath11k_mac_op_tx(struct ieee + bool is_prb_rsp; + int ret; + +- if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) { ++ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { + skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP; + } else if (ieee80211_is_mgmt(hdr->frame_control)) { + is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -720,9 +720,8 @@ struct ieee80211_bss_conf { + * @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate + * that a frame can be transmitted while the queues are stopped for + * off-channel operation. +- * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211, +- * used to indicate that a pending frame requires TX processing before +- * it can be sent out. ++ * @IEEE80211_TX_CTL_HW_80211_ENCAP: This frame uses hardware encapsulation ++ * (header conversion) + * @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211, + * used to indicate that a frame was already retried due to PS + * @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211, +@@ -791,7 +790,7 @@ enum mac80211_tx_info_flags { + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), + IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13), +- IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14), ++ IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(14), + IEEE80211_TX_INTFL_RETRIED = BIT(15), + IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16), + IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17), +@@ -823,8 +822,9 @@ enum mac80211_tx_info_flags { + * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame + * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path + * @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup +- * @IEEE80211_TX_CTRL_HW_80211_ENCAP: This frame uses hardware encapsulation +- * (header conversion) ++ * @IEEE80211_TX_INTCFL_NEED_TXPROCESSING: completely internal to mac80211, ++ * used to indicate that a pending frame requires TX processing before ++ * it can be sent out. + * + * These flags are used in tx_info->control.flags. + */ +@@ -835,7 +835,7 @@ enum mac80211_tx_control_flags { + IEEE80211_TX_CTRL_AMSDU = BIT(3), + IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), + IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5), +- IEEE80211_TX_CTRL_HW_80211_ENCAP = BIT(6), ++ IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6), + }; + + /* +--- a/net/mac80211/mesh_hwmp.c ++++ b/net/mac80211/mesh_hwmp.c +@@ -212,7 +212,7 @@ static void prepare_frame_for_deferred_t + skb->priority = 7; + + info->control.vif = &sdata->vif; +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + ieee80211_set_qos_hdr(sdata, skb); + ieee80211_mps_set_frame_flags(sdata, NULL, hdr); + } +@@ -1163,7 +1163,7 @@ int mesh_nexthop_resolve(struct ieee8021 + if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN) + skb_to_free = skb_dequeue(&mpath->frame_queue); + +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + ieee80211_set_qos_hdr(sdata, skb); + skb_queue_tail(&mpath->frame_queue, skb); + if (skb_to_free) +--- a/net/mac80211/mesh_ps.c ++++ b/net/mac80211/mesh_ps.c +@@ -432,7 +432,7 @@ static void mpsp_qos_null_append(struct + + info = IEEE80211_SKB_CB(new_skb); + info->control.vif = &sdata->vif; +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + + __skb_queue_tail(frames, new_skb); + } +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -2896,7 +2896,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 + fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY); + info = IEEE80211_SKB_CB(fwd_skb); + memset(info, 0, sizeof(*info)); +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + info->control.vif = &rx->sdata->vif; + info->control.jiffies = jiffies; + if (is_multicast_ether_addr(fwd_hdr->addr1)) { +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -66,8 +66,8 @@ static void ieee80211_handle_filtered_fr + + info->control.jiffies = jiffies; + info->control.vif = &sta->sdata->vif; +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | +- IEEE80211_TX_INTFL_RETRANSMISSION; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; ++ info->flags |= IEEE80211_TX_INTFL_RETRANSMISSION; + info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; + + sta->status_stats.filtered++; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -530,7 +530,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee + + info->control.jiffies = jiffies; + info->control.vif = &tx->sdata->vif; +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; + skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); + spin_unlock(&sta->ps_lock); +@@ -1132,7 +1132,7 @@ static bool ieee80211_tx_prep_agg(struct + tx->sta->sta.addr, tx->sta->sta.aid); + } + info->control.vif = &tx->sdata->vif; +- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; + __skb_queue_tail(&tid_tx->pending, skb); + if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER) +@@ -1177,7 +1177,7 @@ ieee80211_tx_prepare(struct ieee80211_su + * we are doing the needed processing, so remove the flag + * now. + */ +- info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING; ++ info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING; + + hdr = (struct ieee80211_hdr *) skb->data; + +@@ -1256,7 +1256,7 @@ static struct txq_info *ieee80211_get_tx + (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) + return NULL; + +- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) && ++ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && + unlikely(!ieee80211_is_data_present(hdr->frame_control))) { + if ((!ieee80211_is_mgmt(hdr->frame_control) || + ieee80211_is_bufferable_mmpdu(hdr->frame_control) || +@@ -3640,7 +3640,7 @@ begin: + else + info->flags &= ~IEEE80211_TX_CTL_AMPDU; + +- if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) ++ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) + goto encap_out; + + if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { +@@ -4253,7 +4253,7 @@ static void ieee80211_8023_xmit(struct i + sdata = container_of(sdata->bss, + struct ieee80211_sub_if_data, u.ap); + +- info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP; ++ info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP; + info->control.vif = &sdata->vif; + + ieee80211_tx_8023(sdata, skb, skb->len, sta, false); +@@ -4357,7 +4357,7 @@ static bool ieee80211_tx_pending_skb(str + + sdata = vif_to_sdata(info->control.vif); + +- if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) { ++ if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) { + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + if (unlikely(!chanctx_conf)) { + dev_kfree_skb(skb); +@@ -4365,7 +4365,7 @@ static bool ieee80211_tx_pending_skb(str + } + info->band = chanctx_conf->def.chan->band; + result = ieee80211_tx(sdata, NULL, skb, true, 0); +- } else if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) { ++ } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) { + dev_kfree_skb(skb); + return true; diff --git a/package/kernel/mac80211/patches/subsys/319-mac80211-unify-802.3-offload-and-802.11-tx-status-co.patch b/package/kernel/mac80211/patches/subsys/319-mac80211-unify-802.3-offload-and-802.11-tx-status-co.patch new file mode 100644 index 00000000000..7bb54f499ba --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/319-mac80211-unify-802.3-offload-and-802.11-tx-status-co.patch @@ -0,0 +1,159 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:54:19 +0200 +Subject: [PATCH] mac80211: unify 802.3 (offload) and 802.11 tx status + codepath + +Make ieee80211_tx_status_8023 call ieee80211_tx_status_ext, similar to +ieee80211_tx_status. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -903,7 +903,6 @@ static void __ieee80211_tx_status(struct + struct ieee80211_bar *bar; + int shift = 0; + int tid = IEEE80211_NUM_TIDS; +- u16 tx_time_est; + + sband = local->hw.wiphy->bands[info->band]; + fc = hdr->frame_control; +@@ -996,17 +995,6 @@ static void __ieee80211_tx_status(struct + ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) + ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data, + acked, info->status.tx_time); +- +- if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) { +- /* Do this here to avoid the expensive lookup of the sta +- * in ieee80211_report_used_skb(). +- */ +- ieee80211_sta_update_pending_airtime(local, sta, +- skb_get_queue_mapping(skb), +- tx_time_est, +- true); +- ieee80211_info_set_tx_time_est(info, 0); +- } + } + + /* SNMP counters +@@ -1102,9 +1090,11 @@ void ieee80211_tx_status_ext(struct ieee + struct ieee80211_tx_info *info = status->info; + struct ieee80211_sta *pubsta = status->sta; + struct ieee80211_supported_band *sband; +- struct sta_info *sta; ++ struct sk_buff *skb = status->skb; ++ struct sta_info *sta = NULL; + int rates_idx, retry_count; + bool acked, noack_success; ++ u16 tx_time_est; + + if (pubsta) { + sta = container_of(pubsta, struct sta_info, sta); +@@ -1156,7 +1146,18 @@ void ieee80211_tx_status_ext(struct ieee + ieee80211s_update_metric(local, sta, status); + } + +- if (status->skb) ++ if (skb && (tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) { ++ /* Do this here to avoid the expensive lookup of the sta ++ * in ieee80211_report_used_skb(). ++ */ ++ ieee80211_sta_update_pending_airtime(local, sta, ++ skb_get_queue_mapping(skb), ++ tx_time_est, ++ true); ++ ieee80211_info_set_tx_time_est(info, 0); ++ } ++ ++ if (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) + return __ieee80211_tx_status(hw, status, rates_idx, + retry_count); + +@@ -1171,6 +1172,12 @@ void ieee80211_tx_status_ext(struct ieee + } else { + I802_DEBUG_INC(local->dot11FailedCount); + } ++ ++ if (!skb) ++ return; ++ ++ ieee80211_report_used_skb(local, skb, false); ++ dev_kfree_skb(skb); + } + EXPORT_SYMBOL(ieee80211_tx_status_ext); + +@@ -1197,66 +1204,23 @@ void ieee80211_tx_status_8023(struct iee + struct ieee80211_vif *vif, + struct sk_buff *skb) + { +- struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ieee80211_tx_status status = { ++ .skb = skb, ++ .info = IEEE80211_SKB_CB(skb), ++ }; + struct sta_info *sta; +- int retry_count; +- int rates_idx; +- bool acked; + + sdata = vif_to_sdata(vif); + +- acked = info->flags & IEEE80211_TX_STAT_ACK; +- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); +- + rcu_read_lock(); + +- if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) +- goto counters_update; +- +- if (IS_ERR(sta)) +- goto counters_update; +- +- if (!acked) +- sta->status_stats.retry_failed++; +- +- if (rates_idx != -1) +- sta->tx_stats.last_rate = info->status.rates[rates_idx]; +- +- sta->status_stats.retry_count += retry_count; +- +- if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) { +- sta->status_stats.last_ack = jiffies; +- if (info->flags & IEEE80211_TX_STAT_ACK) { +- if (sta->status_stats.lost_packets) +- sta->status_stats.lost_packets = 0; ++ if (!ieee80211_lookup_ra_sta(sdata, skb, &sta) && !IS_ERR(sta)) ++ status.sta = &sta->sta; + +- sta->status_stats.last_pkt_time = jiffies; +- } else { +- ieee80211_lost_packet(sta, info); +- } +- } ++ ieee80211_tx_status_ext(hw, &status); + +-counters_update: + rcu_read_unlock(); +- ieee80211_led_tx(local); +- +- if (!(info->flags & IEEE80211_TX_STAT_ACK) && +- !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED)) +- goto skip_stats_update; +- +- I802_DEBUG_INC(local->dot11TransmittedFrameCount); +- if (is_multicast_ether_addr(skb->data)) +- I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount); +- if (retry_count > 0) +- I802_DEBUG_INC(local->dot11RetryCount); +- if (retry_count > 1) +- I802_DEBUG_INC(local->dot11MultipleRetryCount); +- +-skip_stats_update: +- ieee80211_report_used_skb(local, skb, false); +- dev_kfree_skb(skb); + } + EXPORT_SYMBOL(ieee80211_tx_status_8023); + diff --git a/package/kernel/mac80211/patches/subsys/320-mac80211-add-missing-queue-hash-initialization-to-80.patch b/package/kernel/mac80211/patches/subsys/320-mac80211-add-missing-queue-hash-initialization-to-80.patch new file mode 100644 index 00000000000..1ec22dbbc8a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/320-mac80211-add-missing-queue-hash-initialization-to-80.patch @@ -0,0 +1,25 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 13:55:56 +0200 +Subject: [PATCH] mac80211: add missing queue/hash initialization to 802.3 + xmit + +Fixes AQL for encap-offloaded tx + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4206,6 +4206,12 @@ static void ieee80211_8023_xmit(struct i + if (is_zero_ether_addr(ra)) + goto out_free; + ++ if (local->ops->wake_tx_queue) { ++ u16 queue = __ieee80211_select_queue(sdata, sta, skb); ++ skb_set_queue_mapping(skb, queue); ++ skb_get_hash(skb); ++ } ++ + multicast = is_multicast_ether_addr(ra); + + if (sta) diff --git a/package/kernel/mac80211/patches/subsys/321-mac80211-check-and-refresh-aggregation-session-in-en.patch b/package/kernel/mac80211/patches/subsys/321-mac80211-check-and-refresh-aggregation-session-in-en.patch new file mode 100644 index 00000000000..5c149e7d95a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/321-mac80211-check-and-refresh-aggregation-session-in-en.patch @@ -0,0 +1,45 @@ +From: Felix Fietkau +Date: Mon, 17 Aug 2020 21:11:25 +0200 +Subject: [PATCH] mac80211: check and refresh aggregation session in encap + offload tx + +Update the last_tx timestamp to avoid tearing down the aggregation session +early. Fall back to the slow path if the session setup is still running + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4195,6 +4195,8 @@ static void ieee80211_8023_xmit(struct i + bool authorized = false; + bool multicast; + unsigned char *ra = ehdr->h_dest; ++ struct tid_ampdu_tx *tid_tx; ++ u8 tid; + + if (IS_ERR(sta) || (sta && !sta->uploaded)) + sta = NULL; +@@ -4232,6 +4234,22 @@ static void ieee80211_8023_xmit(struct i + + memset(info, 0, sizeof(*info)); + ++ if (sta) { ++ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; ++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); ++ if (tid_tx) { ++ if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { ++ /* fall back to non-offload slow path */ ++ __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); ++ return; ++ } ++ ++ info->flags |= IEEE80211_TX_CTL_AMPDU; ++ if (tid_tx->timeout) ++ tid_tx->last_tx = jiffies; ++ } ++ } ++ + if (unlikely(!multicast && skb->sk && + skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) + info->ack_frame_id = ieee80211_store_ack_skb(local, skb, diff --git a/package/kernel/mac80211/patches/subsys/322-mac80211-support-using-ieee80211_tx_status_ext-to-fr.patch b/package/kernel/mac80211/patches/subsys/322-mac80211-support-using-ieee80211_tx_status_ext-to-fr.patch new file mode 100644 index 00000000000..5469a419bfe --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/322-mac80211-support-using-ieee80211_tx_status_ext-to-fr.patch @@ -0,0 +1,63 @@ +From: Felix Fietkau +Date: Thu, 20 Aug 2020 17:27:00 +0200 +Subject: [PATCH] mac80211: support using ieee80211_tx_status_ext to free + skbs without status info + +For encap-offloaded packets, ieee80211_free_txskb cannot be used, since it +does not have the vif pointer. +Using ieee80211_tx_status_ext for this purpose has the advantage of being able +avoid an extra station lookup for AQL + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -1103,6 +1103,21 @@ void ieee80211_tx_status_ext(struct ieee + sta->tx_stats.last_rate_info = *status->rate; + } + ++ if (skb && (tx_time_est = ++ ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 0) { ++ /* Do this here to avoid the expensive lookup of the sta ++ * in ieee80211_report_used_skb(). ++ */ ++ ieee80211_sta_update_pending_airtime(local, sta, ++ skb_get_queue_mapping(skb), ++ tx_time_est, ++ true); ++ ieee80211_info_set_tx_time_est(IEEE80211_SKB_CB(skb), 0); ++ } ++ ++ if (!status->info) ++ goto free; ++ + rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); + + sband = hw->wiphy->bands[info->band]; +@@ -1146,17 +1161,6 @@ void ieee80211_tx_status_ext(struct ieee + ieee80211s_update_metric(local, sta, status); + } + +- if (skb && (tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) { +- /* Do this here to avoid the expensive lookup of the sta +- * in ieee80211_report_used_skb(). +- */ +- ieee80211_sta_update_pending_airtime(local, sta, +- skb_get_queue_mapping(skb), +- tx_time_est, +- true); +- ieee80211_info_set_tx_time_est(info, 0); +- } +- + if (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) + return __ieee80211_tx_status(hw, status, rates_idx, + retry_count); +@@ -1173,6 +1177,7 @@ void ieee80211_tx_status_ext(struct ieee + I802_DEBUG_INC(local->dot11FailedCount); + } + ++free: + if (!skb) + return; + diff --git a/package/kernel/mac80211/patches/subsys/323-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch b/package/kernel/mac80211/patches/subsys/323-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch new file mode 100644 index 00000000000..c0f2b7b10a1 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/323-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch @@ -0,0 +1,53 @@ +From: Felix Fietkau +Date: Fri, 21 Aug 2020 05:49:07 +0200 +Subject: [PATCH] mac80211: extend ieee80211_tx_status_ext to support bulk + free + +Store processed skbs ready to be freed in a list so the driver bulk free them + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -1092,12 +1092,14 @@ ieee80211_info_get_tx_time_est(struct ie + * @info: Basic tx status information + * @skb: Packet skb (can be NULL if not provided by the driver) + * @rate: The TX rate that was used when sending the packet ++ * @free_list: list where processed skbs are stored to be free'd by the driver + */ + struct ieee80211_tx_status { + struct ieee80211_sta *sta; + struct ieee80211_tx_info *info; + struct sk_buff *skb; + struct rate_info *rate; ++ struct list_head *free_list; + }; + + /** +--- a/net/mac80211/status.c ++++ b/net/mac80211/status.c +@@ -1053,7 +1053,10 @@ static void __ieee80211_tx_status(struct + * with this test... + */ + if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) { +- dev_kfree_skb(skb); ++ if (status->free_list) ++ list_add_tail(&skb->list, status->free_list); ++ else ++ dev_kfree_skb(skb); + return; + } + +@@ -1182,7 +1185,10 @@ free: + return; + + ieee80211_report_used_skb(local, skb, false); +- dev_kfree_skb(skb); ++ if (status->free_list) ++ list_add_tail(&skb->list, status->free_list); ++ else ++ dev_kfree_skb(skb); + } + EXPORT_SYMBOL(ieee80211_tx_status_ext); + diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch new file mode 100644 index 00000000000..abfb5b76d08 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/324-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch @@ -0,0 +1,109 @@ +From: Felix Fietkau +Date: Fri, 21 Aug 2020 05:51:58 +0200 +Subject: [PATCH] mac80211: notify the driver when a sta uses 4-address + mode + +This is needed for encapsulation offload of 4-address mode packets + +Signed-off-by: Felix Fietkau +--- + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -3840,6 +3840,8 @@ enum ieee80211_reconfig_type { + * This callback may sleep. + * @update_vif_config: Update virtual interface offload flags + * This callback may sleep. ++ * @sta_set_4addr: Called to notify the driver when a station starts/stops using ++ * 4-address mode + */ + struct ieee80211_ops { + void (*tx)(struct ieee80211_hw *hw, +@@ -4153,6 +4155,8 @@ struct ieee80211_ops { + struct ieee80211_sta *sta, u8 tids); + void (*update_vif_offload)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); ++ void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, bool enabled); + }; + + /** +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -1698,6 +1698,7 @@ static int ieee80211_change_station(stru + + rcu_assign_pointer(vlansdata->u.vlan.sta, sta); + __ieee80211_check_fast_rx_iface(vlansdata); ++ drv_sta_set_4addr(local, sta->sdata, &sta->sta, true); + } + + if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN && +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1400,4 +1400,18 @@ static inline void drv_update_vif_offloa + trace_drv_return_void(local); + } + ++static inline void drv_sta_set_4addr(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, bool enabled) ++{ ++ sdata = get_bss_sdata(sdata); ++ if (!check_sdata_in_driver(sdata)) ++ return; ++ ++ trace_drv_sta_set_4addr(local, sdata, sta, enabled); ++ if (local->ops->sta_set_4addr) ++ local->ops->sta_set_4addr(&local->hw, &sdata->vif, sta, enabled); ++ trace_drv_return_void(local); ++} ++ + #endif /* __MAC80211_DRIVER_OPS */ +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -3518,6 +3518,9 @@ static bool ieee80211_assoc_success(stru + goto out; + } + ++ if (sdata->wdev.use_4addr) ++ drv_sta_set_4addr(local, sdata, &sta->sta, true); ++ + mutex_unlock(&sdata->local->sta_mtx); + + /* +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2739,6 +2739,33 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u + TP_ARGS(local, sdata) + ); + ++TRACE_EVENT(drv_sta_set_4addr, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, bool enabled), ++ ++ TP_ARGS(local, sdata, sta, enabled), ++ ++ TP_STRUCT__entry( ++ LOCAL_ENTRY ++ VIF_ENTRY ++ STA_ENTRY ++ __field(bool, enabled) ++ ), ++ ++ TP_fast_assign( ++ LOCAL_ASSIGN; ++ VIF_ASSIGN; ++ STA_ASSIGN; ++ __entry->enabled = enabled; ++ ), ++ ++ TP_printk( ++ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " enabled:%d", ++ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->enabled ++ ) ++); ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ + + #undef TRACE_INCLUDE_PATH diff --git a/package/kernel/mac80211/patches/subsys/325-mac80211-skip-encap-offload-for-tx-multicast-control.patch b/package/kernel/mac80211/patches/subsys/325-mac80211-skip-encap-offload-for-tx-multicast-control.patch new file mode 100644 index 00000000000..6ea9c3c913a --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/325-mac80211-skip-encap-offload-for-tx-multicast-control.patch @@ -0,0 +1,158 @@ +From: Felix Fietkau +Date: Fri, 21 Aug 2020 05:54:10 +0200 +Subject: [PATCH] mac80211: skip encap offload for tx multicast/control + packets + +This simplifies the checks in the encap offload tx handler and allows using +it in cases where software crypto is used for multicast packets, e.g. when +using an AP_VLAN. + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -378,7 +378,8 @@ static bool ieee80211_set_sdata_offload_ + if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC || + key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || +- key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256 || ++ !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) + continue; + if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP || + !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) +@@ -1448,7 +1449,8 @@ static void ieee80211_set_vif_encap_ops( + if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC || + key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || +- key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) ++ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256 || ++ !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE)) + continue; + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + enabled = false; +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4190,88 +4190,47 @@ static void ieee80211_8023_xmit(struct i + struct sk_buff *skb) + { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +- struct ethhdr *ehdr = (struct ethhdr *)skb->data; + struct ieee80211_local *local = sdata->local; +- bool authorized = false; +- bool multicast; +- unsigned char *ra = ehdr->h_dest; + struct tid_ampdu_tx *tid_tx; + u8 tid; + +- if (IS_ERR(sta) || (sta && !sta->uploaded)) +- sta = NULL; +- +- if (sdata->vif.type == NL80211_IFTYPE_STATION && +- (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER))) +- ra = sdata->u.mgd.bssid; +- +- if (is_zero_ether_addr(ra)) +- goto out_free; +- + if (local->ops->wake_tx_queue) { + u16 queue = __ieee80211_select_queue(sdata, sta, skb); + skb_set_queue_mapping(skb, queue); + skb_get_hash(skb); + } + +- multicast = is_multicast_ether_addr(ra); +- +- if (sta) +- authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED); +- +- if (!multicast && !authorized && +- (ehdr->h_proto != sdata->control_port_protocol || +- !ether_addr_equal(sdata->vif.addr, ehdr->h_source))) +- goto out_free; +- +- if (multicast && sdata->vif.type == NL80211_IFTYPE_AP && +- !atomic_read(&sdata->u.ap.num_mcast_sta)) +- goto out_free; +- + if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) && + test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state)) + goto out_free; + + memset(info, 0, sizeof(*info)); + +- if (sta) { +- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; +- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); +- if (tid_tx) { +- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { +- /* fall back to non-offload slow path */ +- __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); +- return; +- } +- +- info->flags |= IEEE80211_TX_CTL_AMPDU; +- if (tid_tx->timeout) +- tid_tx->last_tx = jiffies; ++ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; ++ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]); ++ if (tid_tx) { ++ if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) { ++ /* fall back to non-offload slow path */ ++ __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL); ++ return; + } ++ ++ info->flags |= IEEE80211_TX_CTL_AMPDU; ++ if (tid_tx->timeout) ++ tid_tx->last_tx = jiffies; + } + +- if (unlikely(!multicast && skb->sk && ++ if (unlikely(skb->sk && + skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) + info->ack_frame_id = ieee80211_store_ack_skb(local, skb, + &info->flags, NULL); + +- if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) { +- if (sdata->control_port_no_encrypt) +- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; +- info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO; +- } +- +- if (multicast) +- info->flags |= IEEE80211_TX_CTL_NO_ACK; +- + info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; + + ieee80211_tx_stats(dev, skb->len); + +- if (sta) { +- sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; +- sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; +- } ++ sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; ++ sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; + + if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + sdata = container_of(sdata->bss, +@@ -4292,6 +4251,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8 + struct net_device *dev) + { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); ++ struct ethhdr *ehdr = (struct ethhdr *)skb->data; + struct sta_info *sta; + + if (unlikely(skb->len < ETH_HLEN)) { +@@ -4303,6 +4263,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8 + + if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) + kfree_skb(skb); ++ else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded || ++ !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || ++ sdata->control_port_protocol == ehdr->h_proto)) ++ ieee80211_subif_start_xmit(skb, dev); + else + ieee80211_8023_xmit(sdata, dev, sta, skb); + diff --git a/package/kernel/mac80211/patches/subsys/326-mac80211-set-info-control.hw_key-for-encap-offload-p.patch b/package/kernel/mac80211/patches/subsys/326-mac80211-set-info-control.hw_key-for-encap-offload-p.patch new file mode 100644 index 00000000000..2b7579b24e4 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/326-mac80211-set-info-control.hw_key-for-encap-offload-p.patch @@ -0,0 +1,31 @@ +From: Felix Fietkau +Date: Fri, 21 Aug 2020 06:03:45 +0200 +Subject: [PATCH] mac80211: set info->control.hw_key for encap offload + packets + +This is needed for drivers that don't do the key lookup themselves + +Signed-off-by: Felix Fietkau +--- + +--- a/net/mac80211/tx.c ++++ b/net/mac80211/tx.c +@@ -4191,6 +4191,7 @@ static void ieee80211_8023_xmit(struct i + { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_local *local = sdata->local; ++ struct ieee80211_key *key; + struct tid_ampdu_tx *tid_tx; + u8 tid; + +@@ -4239,6 +4240,10 @@ static void ieee80211_8023_xmit(struct i + info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP; + info->control.vif = &sdata->vif; + ++ key = rcu_dereference(sta->ptk[sta->ptk_idx]); ++ if (key) ++ info->control.hw_key = &key->conf; ++ + ieee80211_tx_8023(sdata, skb, skb->len, sta, false); + + return; diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch index b816146c2aa..1487e10f42d 100644 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch @@ -57,7 +57,7 @@ __NL80211_ATTR_AFTER_LAST, --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2610,6 +2610,19 @@ static int ieee80211_get_tx_power(struct +@@ -2615,6 +2615,19 @@ static int ieee80211_get_tx_power(struct return 0; } @@ -77,7 +77,7 @@ static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, const u8 *addr) { -@@ -4040,6 +4053,7 @@ const struct cfg80211_ops mac80211_confi +@@ -4045,6 +4058,7 @@ const struct cfg80211_ops mac80211_confi .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, @@ -87,7 +87,7 @@ CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -1385,6 +1385,7 @@ struct ieee80211_local { +@@ -1383,6 +1383,7 @@ struct ieee80211_local { int dynamic_ps_forced_timeout; int user_power_level; /* in dBm, for all interfaces */