aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch')
-rw-r--r--package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch613
1 files changed, 0 insertions, 613 deletions
diff --git a/package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch b/package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch
deleted file mode 100644
index 811c66499b..0000000000
--- a/package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch
+++ /dev/null
@@ -1,613 +0,0 @@
-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
-@@ -4304,6 +4304,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)
- {
-@@ -4313,7 +4342,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;
-@@ -4407,30 +4435,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,
-@@ -5753,6 +5758,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,
-@@ -6034,6 +6040,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
-@@ -1606,6 +1606,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
- *
-@@ -1626,6 +1641,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
-@@ -1662,6 +1682,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;
-@@ -2328,6 +2349,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 {
-@@ -2380,6 +2404,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
-@@ -3814,6 +3839,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,
-@@ -4125,6 +4152,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/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
-@@ -1384,4 +1384,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
-@@ -993,8 +993,6 @@ struct ieee80211_sub_if_data {
- } debugfs;
- #endif
-
-- bool hw_80211_encap;
--
- /* must be last, dynamically sized area in this! */
- struct ieee80211_vif vif;
- };
-@@ -1772,6 +1770,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,85 @@ static int ieee80211_check_queues(struct
- return 0;
- }
-
-+static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
-+{
-+ switch (iftype) {
-+ /* P2P GO and client are mapped to AP/STATION types */
-+ case NL80211_IFTYPE_AP:
-+ 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;
-+ 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;
-+
-+ 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 +667,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 +697,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 +707,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)
-@@ -1293,61 +1378,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));
-@@ -1378,6 +1408,32 @@ 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;
-+ 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;
-+
-+ 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 =
-@@ -1560,7 +1616,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) {
-@@ -1695,6 +1750,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);
-@@ -1707,6 +1763,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;
-- fallthrough;
--
- case WLAN_CIPHER_SUITE_AES_CMAC:
- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
---- a/net/mac80211/trace.h
-+++ b/net/mac80211/trace.h
-@@ -2734,6 +2734,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
-@@ -4178,11 +4178,10 @@ static bool ieee80211_tx_8023(struct iee
-
- static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
- struct net_device *dev, struct sta_info *sta,
-- struct sk_buff *skb)
-+ struct ieee80211_key *key, struct sk_buff *skb)
- {
- 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;
-
-@@ -4231,7 +4230,6 @@ static void ieee80211_8023_xmit(struct i
- info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
- info->control.vif = &sdata->vif;
-
-- key = rcu_dereference(sta->ptk[sta->ptk_idx]);
- if (key)
- info->control.hw_key = &key->conf;
-
-@@ -4248,12 +4246,9 @@ netdev_tx_t ieee80211_subif_start_xmit_8
- {
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ethhdr *ehdr = (struct ethhdr *)skb->data;
-+ struct ieee80211_key *key;
- struct sta_info *sta;
--
-- if (WARN_ON(!sdata->hw_80211_encap)) {
-- kfree_skb(skb);
-- return NETDEV_TX_OK;
-- }
-+ bool offload = true;
-
- if (unlikely(skb->len < ETH_HLEN)) {
- kfree_skb(skb);
-@@ -4262,15 +4257,26 @@ netdev_tx_t ieee80211_subif_start_xmit_8
-
- rcu_read_lock();
-
-- if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
-+ 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);
-+ goto out;
-+ }
-+
-+ if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
-+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
-+ sdata->control_port_protocol == ehdr->h_proto))
-+ offload = false;
-+ else if ((key = rcu_dereference(sta->ptk[sta->ptk_idx])) &&
-+ (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) ||
-+ key->conf.cipher == WLAN_CIPHER_SUITE_TKIP))
-+ offload = false;
-+
-+ if (offload)
-+ ieee80211_8023_xmit(sdata, dev, sta, key, skb);
- else
-- ieee80211_8023_xmit(sdata, dev, sta, skb);
-+ ieee80211_subif_start_xmit(skb, dev);
-
-+out:
- rcu_read_unlock();
-
- return NETDEV_TX_OK;