diff options
author | Felix Fietkau <nbd@nbd.name> | 2020-08-17 18:27:25 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@nbd.name> | 2020-08-22 07:02:01 +0200 |
commit | e7f7101182f84b5ecdbfac5764b642512feef870 (patch) | |
tree | bf0a3e30c374def30035521c99b4f6017ab5438c /package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch | |
parent | f51f18e0998568e6a53c834b50f8fa1b20f634f3 (diff) | |
download | upstream-e7f7101182f84b5ecdbfac5764b642512feef870.tar.gz upstream-e7f7101182f84b5ecdbfac5764b642512feef870.tar.bz2 upstream-e7f7101182f84b5ecdbfac5764b642512feef870.zip |
mac80211: rework encapsulation offload support
Fix a number of deficiencies in the existing API
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Diffstat (limited to 'package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch')
-rw-r--r-- | package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch | 651 |
1 files changed, 651 insertions, 0 deletions
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 0000000000..22697718f8 --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch @@ -0,0 +1,651 @@ +From: Felix Fietkau <nbd@nbd.name> +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 <nbd@nbd.name> +--- + +--- 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; |