]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
mac80211: update encap offload patches to the latest version
authorFelix Fietkau <nbd@nbd.name>
Tue, 8 Sep 2020 12:22:28 +0000 (14:22 +0200)
committerFelix Fietkau <nbd@nbd.name>
Wed, 9 Sep 2020 09:51:47 +0000 (11:51 +0200)
Minor cleanup and code reorganization, along with a change to not disable
offload anymore when a tkip or sw crypto key is added

Signed-off-by: Felix Fietkau <nbd@nbd.name>
17 files changed:
package/kernel/mac80211/patches/subsys/314-mac80211-add-missing-queue-hash-initialization-to-80.patch [moved from package/kernel/mac80211/patches/subsys/320-mac80211-add-missing-queue-hash-initialization-to-80.patch with 97% similarity]
package/kernel/mac80211/patches/subsys/315-mac80211-check-and-refresh-aggregation-session-in-en.patch [moved from package/kernel/mac80211/patches/subsys/321-mac80211-check-and-refresh-aggregation-session-in-en.patch with 98% similarity]
package/kernel/mac80211/patches/subsys/316-mac80211-skip-encap-offload-for-tx-multicast-control.patch [moved from package/kernel/mac80211/patches/subsys/325-mac80211-skip-encap-offload-for-tx-multicast-control.patch with 77% similarity]
package/kernel/mac80211/patches/subsys/317-mac80211-set-info-control.hw_key-for-encap-offload-p.patch [moved from package/kernel/mac80211/patches/subsys/326-mac80211-set-info-control.hw_key-for-encap-offload-p.patch with 93% similarity]
package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch [moved from package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch with 82% similarity]
package/kernel/mac80211/patches/subsys/319-mac80211-reduce-duplication-in-tx-status-functions.patch [moved from package/kernel/mac80211/patches/subsys/315-mac80211-reduce-duplication-in-tx-status-functions.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/320-mac80211-remove-tx-status-call-to-ieee80211_sta_regi.patch [moved from package/kernel/mac80211/patches/subsys/316-mac80211-remove-tx-status-call-to-ieee80211_sta_regi.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/321-mac80211-optimize-station-connection-monitor.patch [moved from package/kernel/mac80211/patches/subsys/317-mac80211-optimize-station-connection-monitor.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/322-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch [moved from package/kernel/mac80211/patches/subsys/318-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch with 97% similarity]
package/kernel/mac80211/patches/subsys/323-mac80211-unify-802.3-offload-and-802.11-tx-status-co.patch [moved from package/kernel/mac80211/patches/subsys/319-mac80211-unify-802.3-offload-and-802.11-tx-status-co.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/324-mac80211-support-using-ieee80211_tx_status_ext-to-fr.patch [moved from package/kernel/mac80211/patches/subsys/322-mac80211-support-using-ieee80211_tx_status_ext-to-fr.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/325-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch [moved from package/kernel/mac80211/patches/subsys/323-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch with 98% similarity]
package/kernel/mac80211/patches/subsys/326-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch [moved from package/kernel/mac80211/patches/subsys/324-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch with 97% similarity]
package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch [new file with mode: 0644]
package/kernel/mac80211/patches/subsys/328-mac80211-extend-AQL-aggregation-estimation-to-HE-and.patch [moved from package/kernel/mac80211/patches/subsys/327-mac80211-extend-AQL-aggregation-estimation-to-HE-and.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/329-mac80211-add-AQL-support-for-VHT160-tx-rates.patch [moved from package/kernel/mac80211/patches/subsys/328-mac80211-add-AQL-support-for-VHT160-tx-rates.patch with 100% similarity]
package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch

similarity index 97%
rename from package/kernel/mac80211/patches/subsys/320-mac80211-add-missing-queue-hash-initialization-to-80.patch
rename to package/kernel/mac80211/patches/subsys/314-mac80211-add-missing-queue-hash-initialization-to-80.patch
index d9d3fded75e9d2f8bd53b6d6ec4bd889251fac31..eb56a2cac58df1d9c2fca26fb4579cc54b3bb304 100644 (file)
@@ -1,7 +1,7 @@
 From: Felix Fietkau <nbd@nbd.name>
 Date: Mon, 17 Aug 2020 13:55:56 +0200
-Subject: [PATCH] mac80211: add missing queue/hash initialization to 802.3
- xmit
+Subject: [PATCH] mac80211: add missing queue/hash initialization to
802.3 xmit
 
 Fixes AQL for encap-offloaded tx
 
similarity index 98%
rename from package/kernel/mac80211/patches/subsys/321-mac80211-check-and-refresh-aggregation-session-in-en.patch
rename to package/kernel/mac80211/patches/subsys/315-mac80211-check-and-refresh-aggregation-session-in-en.patch
index 0188e19b71687363c89ef2bb8b282d3d14f24e96..e411d597224a5b39f7d4b66c86ae2452fb990e00 100644 (file)
@@ -1,7 +1,7 @@
 From: Felix Fietkau <nbd@nbd.name>
 Date: Mon, 17 Aug 2020 21:11:25 +0200
-Subject: [PATCH] mac80211: check and refresh aggregation session in encap
- offload tx
+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
similarity index 77%
rename from package/kernel/mac80211/patches/subsys/325-mac80211-skip-encap-offload-for-tx-multicast-control.patch
rename to package/kernel/mac80211/patches/subsys/316-mac80211-skip-encap-offload-for-tx-multicast-control.patch
index a32075768a09b1d15034dfba0ecd28a2c8f2fc2d..6dce21db1e2f4bb714af389534c16106efa5c6c0 100644 (file)
@@ -10,28 +10,6 @@ using an AP_VLAN.
 Signed-off-by: Felix Fietkau <nbd@nbd.name>
 ---
 
---- 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
 @@ -4184,88 +4184,47 @@ static void ieee80211_8023_xmit(struct i
@@ -144,8 +122,8 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      struct ethhdr *ehdr = (struct ethhdr *)skb->data;
        struct sta_info *sta;
  
-       if (unlikely(skb->len < ETH_HLEN)) {
-@@ -4297,6 +4257,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8
+       if (WARN_ON(!sdata->hw_80211_encap)) {
+@@ -4302,6 +4262,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8
  
        if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
                kfree_skb(skb);
similarity index 93%
rename from package/kernel/mac80211/patches/subsys/326-mac80211-set-info-control.hw_key-for-encap-offload-p.patch
rename to package/kernel/mac80211/patches/subsys/317-mac80211-set-info-control.hw_key-for-encap-offload-p.patch
index 421d18f2c294a8ec84121f9d174232c419d10b66..cb5a98631239413e4d3125d06bf3e28db04f0fb0 100644 (file)
@@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        u8 tid;
  
 @@ -4233,6 +4234,10 @@ static void ieee80211_8023_xmit(struct i
-       info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
+       info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
        info->control.vif = &sdata->vif;
  
 +      key = rcu_dereference(sta->ptk[sta->ptk_idx]);
similarity index 82%
rename from package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch
rename to package/kernel/mac80211/patches/subsys/318-mac80211-rework-tx-encapsulation-offload-API.patch
index 4f0d264947e712fdabbb54c3718fffcceaf21df0..7593c41da068a5476af97f3c198d60ef736dfd14 100644 (file)
@@ -198,34 +198,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  };
  
  /**
---- 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[] = {
@@ -287,16 +259,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  
  bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
  {
-@@ -348,6 +349,99 @@ static int ieee80211_check_queues(struct
+@@ -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_P2P_GO:
-+      case NL80211_IFTYPE_P2P_CLIENT:
 +      case NL80211_IFTYPE_STATION:
 +              return true;
 +      default:
@@ -307,7 +278,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +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;
@@ -315,18 +285,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      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)
@@ -387,7 +345,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  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
+@@ -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);
@@ -395,7 +353,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                } else {
                        netif_carrier_off(dev);
                }
-@@ -616,6 +711,7 @@ int ieee80211_do_open(struct wireless_de
+@@ -616,6 +697,7 @@ int ieee80211_do_open(struct wireless_de
  
                ieee80211_adjust_monitor_flags(sdata, 1);
                ieee80211_configure_filter(local);
@@ -403,7 +361,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                mutex_lock(&local->mtx);
                ieee80211_recalc_idle(local);
                mutex_unlock(&local->mtx);
-@@ -625,10 +721,13 @@ int ieee80211_do_open(struct wireless_de
+@@ -625,10 +707,13 @@ int ieee80211_do_open(struct wireless_de
        default:
                if (coming_up) {
                        ieee80211_del_virtual_monitor(local);
@@ -417,7 +375,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                        res = ieee80211_check_queues(sdata,
                                ieee80211_vif_type_p2p(&sdata->vif));
                        if (res)
-@@ -1286,61 +1385,6 @@ static const struct net_device_ops ieee8
+@@ -1286,61 +1371,6 @@ static const struct net_device_ops ieee8
  
  };
  
@@ -479,7 +437,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  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(
+@@ -1371,6 +1401,32 @@ static void ieee80211_if_setup_no_queue(
  #endif
  }
  
@@ -487,7 +445,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +{
 +      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) {
@@ -506,24 +463,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +          !(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;
 +}
@@ -531,7 +470,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  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
+@@ -1553,7 +1609,6 @@ static void ieee80211_setup_sdata(struct
        sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
  
        sdata->noack_map = 0;
@@ -539,7 +478,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  
        /* only monitor/p2p-device differ */
        if (sdata->dev) {
-@@ -1688,6 +1776,7 @@ static int ieee80211_runtime_change_ifty
+@@ -1688,6 +1743,7 @@ static int ieee80211_runtime_change_ifty
  
        ieee80211_teardown_sdata(sdata);
  
@@ -547,7 +486,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        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
+@@ -1700,6 +1756,7 @@ static int ieee80211_runtime_change_ifty
        ieee80211_check_queues(sdata, type);
  
        ieee80211_setup_sdata(sdata, type);
@@ -586,40 +525,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
        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,
@@ -637,15 +542,72 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  #undef TRACE_INCLUDE_PATH
 --- a/net/mac80211/tx.c
 +++ b/net/mac80211/tx.c
-@@ -4264,11 +4264,6 @@ netdev_tx_t ieee80211_subif_start_xmit_8
+@@ -4181,11 +4181,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;
+@@ -4234,7 +4233,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;
+@@ -4251,12 +4249,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);
-               return NETDEV_TX_OK;
+@@ -4265,15 +4260,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;
similarity index 97%
rename from package/kernel/mac80211/patches/subsys/318-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch
rename to package/kernel/mac80211/patches/subsys/322-mac80211-swap-NEED_TXPROCESSING-and-HW_80211_ENCAP-t.patch
index 85287a6ef171a1241bcf880e4baa3b737bffc528..b9069ef9b8ce939f281794c49f5b1e355f65a48a 100644 (file)
@@ -198,7 +198,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                goto encap_out;
  
        if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
-@@ -4247,7 +4247,7 @@ static void ieee80211_8023_xmit(struct i
+@@ -4230,7 +4230,7 @@ static void ieee80211_8023_xmit(struct i
                sdata = container_of(sdata->bss,
                                     struct ieee80211_sub_if_data, u.ap);
  
@@ -206,8 +206,8 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +      info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
        info->control.vif = &sdata->vif;
  
-       ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
-@@ -4351,7 +4351,7 @@ static bool ieee80211_tx_pending_skb(str
+       if (key)
+@@ -4355,7 +4355,7 @@ static bool ieee80211_tx_pending_skb(str
  
        sdata = vif_to_sdata(info->control.vif);
  
@@ -216,7 +216,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (unlikely(!chanctx_conf)) {
                        dev_kfree_skb(skb);
-@@ -4359,7 +4359,7 @@ static bool ieee80211_tx_pending_skb(str
+@@ -4363,7 +4363,7 @@ static bool ieee80211_tx_pending_skb(str
                }
                info->band = chanctx_conf->def.chan->band;
                result = ieee80211_tx(sdata, NULL, skb, true, 0);
similarity index 98%
rename from package/kernel/mac80211/patches/subsys/323-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch
rename to package/kernel/mac80211/patches/subsys/325-mac80211-extend-ieee80211_tx_status_ext-to-support-b.patch
index c0f2b7b10a1cecf280fc2cbd77139578919b219f..e8b29bb4c54024fd87b4d2cfd70315e5248fe22d 100644 (file)
@@ -1,7 +1,7 @@
 From: Felix Fietkau <nbd@nbd.name>
 Date: Fri, 21 Aug 2020 05:49:07 +0200
-Subject: [PATCH] mac80211: extend ieee80211_tx_status_ext to support bulk
- free
+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
 
similarity index 97%
rename from package/kernel/mac80211/patches/subsys/324-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch
rename to package/kernel/mac80211/patches/subsys/326-mac80211-notify-the-driver-when-a-sta-uses-4-address.patch
index abfb5b76d085bcef63be89debf3c4723d2570fec..5ad5ac6a783fdc8981a8451c4a0d83096b6f51f5 100644 (file)
@@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
  /**
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -1698,6 +1698,7 @@ static int ieee80211_change_station(stru
+@@ -1693,6 +1693,7 @@ static int ieee80211_change_station(stru
  
                        rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
                        __ieee80211_check_fast_rx_iface(vlansdata);
diff --git a/package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch b/package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch
new file mode 100644 (file)
index 0000000..a3d6001
--- /dev/null
@@ -0,0 +1,1110 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 8 Sep 2020 12:16:26 +0200
+Subject: [PATCH] mac80211: reorganize code to remove a forward
+ declaration
+
+Remove the newly added ieee80211_set_vif_encap_ops declaration.
+No further code changes
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -43,7 +43,6 @@
+  */
+ 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)
+ {
+@@ -349,6 +348,511 @@ static int ieee80211_check_queues(struct
+       return 0;
+ }
++static int ieee80211_open(struct net_device *dev)
++{
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      int err;
++
++      /* fail early if user set an invalid address */
++      if (!is_valid_ether_addr(dev->dev_addr))
++              return -EADDRNOTAVAIL;
++
++      err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
++      if (err)
++              return err;
++
++      return ieee80211_do_open(&sdata->wdev, true);
++}
++
++static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
++                            bool going_down)
++{
++      struct ieee80211_local *local = sdata->local;
++      unsigned long flags;
++      struct sk_buff *skb, *tmp;
++      u32 hw_reconf_flags = 0;
++      int i, flushed;
++      struct ps_data *ps;
++      struct cfg80211_chan_def chandef;
++      bool cancel_scan;
++      struct cfg80211_nan_func *func;
++
++      clear_bit(SDATA_STATE_RUNNING, &sdata->state);
++
++      cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
++      if (cancel_scan)
++              ieee80211_scan_cancel(local);
++
++      /*
++       * Stop TX on this interface first.
++       */
++      if (sdata->dev)
++              netif_tx_stop_all_queues(sdata->dev);
++
++      ieee80211_roc_purge(local, sdata);
++
++      switch (sdata->vif.type) {
++      case NL80211_IFTYPE_STATION:
++              ieee80211_mgd_stop(sdata);
++              break;
++      case NL80211_IFTYPE_ADHOC:
++              ieee80211_ibss_stop(sdata);
++              break;
++      case NL80211_IFTYPE_MONITOR:
++              if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
++                      break;
++              list_del_rcu(&sdata->u.mntr.list);
++              break;
++      default:
++              break;
++      }
++
++      /*
++       * Remove all stations associated with this interface.
++       *
++       * This must be done before calling ops->remove_interface()
++       * because otherwise we can later invoke ops->sta_notify()
++       * whenever the STAs are removed, and that invalidates driver
++       * assumptions about always getting a vif pointer that is valid
++       * (because if we remove a STA after ops->remove_interface()
++       * the driver will have removed the vif info already!)
++       *
++       * In WDS mode a station must exist here and be flushed, for
++       * AP_VLANs stations may exist since there's nothing else that
++       * would have removed them, but in other modes there shouldn't
++       * be any stations.
++       */
++      flushed = sta_info_flush(sdata);
++      WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
++                   ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
++                    (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
++
++      /* don't count this interface for allmulti while it is down */
++      if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
++              atomic_dec(&local->iff_allmultis);
++
++      if (sdata->vif.type == NL80211_IFTYPE_AP) {
++              local->fif_pspoll--;
++              local->fif_probe_req--;
++      } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
++              local->fif_probe_req--;
++      }
++
++      if (sdata->dev) {
++              netif_addr_lock_bh(sdata->dev);
++              spin_lock_bh(&local->filter_lock);
++              __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
++                               sdata->dev->addr_len);
++              spin_unlock_bh(&local->filter_lock);
++              netif_addr_unlock_bh(sdata->dev);
++      }
++
++      del_timer_sync(&local->dynamic_ps_timer);
++      cancel_work_sync(&local->dynamic_ps_enable_work);
++
++      cancel_work_sync(&sdata->recalc_smps);
++      sdata_lock(sdata);
++      mutex_lock(&local->mtx);
++      sdata->vif.csa_active = false;
++      if (sdata->vif.type == NL80211_IFTYPE_STATION)
++              sdata->u.mgd.csa_waiting_bcn = false;
++      if (sdata->csa_block_tx) {
++              ieee80211_wake_vif_queues(local, sdata,
++                                        IEEE80211_QUEUE_STOP_REASON_CSA);
++              sdata->csa_block_tx = false;
++      }
++      mutex_unlock(&local->mtx);
++      sdata_unlock(sdata);
++
++      cancel_work_sync(&sdata->csa_finalize_work);
++
++      cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
++
++      if (sdata->wdev.cac_started) {
++              chandef = sdata->vif.bss_conf.chandef;
++              WARN_ON(local->suspended);
++              mutex_lock(&local->mtx);
++              ieee80211_vif_release_channel(sdata);
++              mutex_unlock(&local->mtx);
++              cfg80211_cac_event(sdata->dev, &chandef,
++                                 NL80211_RADAR_CAC_ABORTED,
++                                 GFP_KERNEL);
++      }
++
++      /* APs need special treatment */
++      if (sdata->vif.type == NL80211_IFTYPE_AP) {
++              struct ieee80211_sub_if_data *vlan, *tmpsdata;
++
++              /* down all dependent devices, that is VLANs */
++              list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
++                                       u.vlan.list)
++                      dev_close(vlan->dev);
++              WARN_ON(!list_empty(&sdata->u.ap.vlans));
++      } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
++              /* remove all packets in parent bc_buf pointing to this dev */
++              ps = &sdata->bss->ps;
++
++              spin_lock_irqsave(&ps->bc_buf.lock, flags);
++              skb_queue_walk_safe(&ps->bc_buf, skb, tmp) {
++                      if (skb->dev == sdata->dev) {
++                              __skb_unlink(skb, &ps->bc_buf);
++                              local->total_ps_buffered--;
++                              ieee80211_free_txskb(&local->hw, skb);
++                      }
++              }
++              spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
++      }
++
++      if (going_down)
++              local->open_count--;
++
++      switch (sdata->vif.type) {
++      case NL80211_IFTYPE_AP_VLAN:
++              mutex_lock(&local->mtx);
++              list_del(&sdata->u.vlan.list);
++              mutex_unlock(&local->mtx);
++              RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
++              /* see comment in the default case below */
++              ieee80211_free_keys(sdata, true);
++              /* no need to tell driver */
++              break;
++      case NL80211_IFTYPE_MONITOR:
++              if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
++                      local->cooked_mntrs--;
++                      break;
++              }
++
++              local->monitors--;
++              if (local->monitors == 0) {
++                      local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
++                      hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
++              }
++
++              ieee80211_adjust_monitor_flags(sdata, -1);
++              break;
++      case NL80211_IFTYPE_NAN:
++              /* clean all the functions */
++              spin_lock_bh(&sdata->u.nan.func_lock);
++
++              idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
++                      idr_remove(&sdata->u.nan.function_inst_ids, i);
++                      cfg80211_free_nan_func(func);
++              }
++              idr_destroy(&sdata->u.nan.function_inst_ids);
++
++              spin_unlock_bh(&sdata->u.nan.func_lock);
++              break;
++      case NL80211_IFTYPE_P2P_DEVICE:
++              /* relies on synchronize_rcu() below */
++              RCU_INIT_POINTER(local->p2p_sdata, NULL);
++              /* fall through */
++      default:
++              cancel_work_sync(&sdata->work);
++              /*
++               * When we get here, the interface is marked down.
++               * Free the remaining keys, if there are any
++               * (which can happen in AP mode if userspace sets
++               * keys before the interface is operating, and maybe
++               * also in WDS mode)
++               *
++               * Force the key freeing to always synchronize_net()
++               * to wait for the RX path in case it is using this
++               * interface enqueuing frames at this very time on
++               * another CPU.
++               */
++              ieee80211_free_keys(sdata, true);
++              skb_queue_purge(&sdata->skb_queue);
++      }
++
++      spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
++      for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
++              skb_queue_walk_safe(&local->pending[i], skb, tmp) {
++                      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
++                      if (info->control.vif == &sdata->vif) {
++                              __skb_unlink(skb, &local->pending[i]);
++                              ieee80211_free_txskb(&local->hw, skb);
++                      }
++              }
++      }
++      spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
++
++      if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
++              ieee80211_txq_remove_vlan(local, sdata);
++
++      sdata->bss = NULL;
++
++      if (local->open_count == 0)
++              ieee80211_clear_tx_pending(local);
++
++      sdata->vif.bss_conf.beacon_int = 0;
++
++      /*
++       * If the interface goes down while suspended, presumably because
++       * the device was unplugged and that happens before our resume,
++       * then the driver is already unconfigured and the remainder of
++       * this function isn't needed.
++       * XXX: what about WoWLAN? If the device has software state, e.g.
++       *      memory allocated, it might expect teardown commands from
++       *      mac80211 here?
++       */
++      if (local->suspended) {
++              WARN_ON(local->wowlan);
++              WARN_ON(rtnl_dereference(local->monitor_sdata));
++              return;
++      }
++
++      switch (sdata->vif.type) {
++      case NL80211_IFTYPE_AP_VLAN:
++              break;
++      case NL80211_IFTYPE_MONITOR:
++              if (local->monitors == 0)
++                      ieee80211_del_virtual_monitor(local);
++
++              mutex_lock(&local->mtx);
++              ieee80211_recalc_idle(local);
++              mutex_unlock(&local->mtx);
++
++              if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
++                      break;
++
++              /* fall through */
++      default:
++              if (going_down)
++                      drv_remove_interface(local, sdata);
++      }
++
++      ieee80211_recalc_ps(local);
++
++      if (cancel_scan)
++              flush_delayed_work(&local->scan_work);
++
++      if (local->open_count == 0) {
++              ieee80211_stop_device(local);
++
++              /* no reconfiguring after stop! */
++              return;
++      }
++
++      /* do after stop to avoid reconfiguring when we stop anyway */
++      ieee80211_configure_filter(local);
++      ieee80211_hw_config(local, hw_reconf_flags);
++
++      if (local->monitors == local->open_count)
++              ieee80211_add_virtual_monitor(local);
++}
++
++static int ieee80211_stop(struct net_device *dev)
++{
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++
++      ieee80211_do_stop(sdata, true);
++
++      return 0;
++}
++
++static void ieee80211_set_multicast_list(struct net_device *dev)
++{
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      struct ieee80211_local *local = sdata->local;
++      int allmulti, sdata_allmulti;
++
++      allmulti = !!(dev->flags & IFF_ALLMULTI);
++      sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
++
++      if (allmulti != sdata_allmulti) {
++              if (dev->flags & IFF_ALLMULTI)
++                      atomic_inc(&local->iff_allmultis);
++              else
++                      atomic_dec(&local->iff_allmultis);
++              sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
++      }
++
++      spin_lock_bh(&local->filter_lock);
++      __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
++      spin_unlock_bh(&local->filter_lock);
++      ieee80211_queue_work(&local->hw, &local->reconfig_filter);
++}
++
++/*
++ * Called when the netdev is removed or, by the code below, before
++ * the interface type changes.
++ */
++static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
++{
++      int i;
++
++      /* free extra data */
++      ieee80211_free_keys(sdata, false);
++
++      ieee80211_debugfs_remove_netdev(sdata);
++
++      for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
++              __skb_queue_purge(&sdata->fragments[i].skb_list);
++      sdata->fragment_next = 0;
++
++      if (ieee80211_vif_is_mesh(&sdata->vif))
++              ieee80211_mesh_teardown_sdata(sdata);
++}
++
++static void ieee80211_uninit(struct net_device *dev)
++{
++      ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
++}
++
++#if LINUX_VERSION_IS_GEQ(5,2,0)
++static u16 ieee80211_netdev_select_queue(struct net_device *dev,
++                                       struct sk_buff *skb,
++                                       struct net_device *sb_dev)
++#elif LINUX_VERSION_IS_GEQ(4,19,0)
++static u16 ieee80211_netdev_select_queue(struct net_device *dev,
++                                       struct sk_buff *skb,
++                                       struct net_device *sb_dev,
++                                       select_queue_fallback_t fallback)
++#elif LINUX_VERSION_IS_GEQ(3,14,0) || \
++    (LINUX_VERSION_CODE == KERNEL_VERSION(3,13,11) && UTS_UBUNTU_RELEASE_ABI > 30)
++static u16 ieee80211_netdev_select_queue(struct net_device *dev,
++                                       struct sk_buff *skb,
++                                       void *accel_priv,
++                                       select_queue_fallback_t fallback)
++#elif LINUX_VERSION_IS_GEQ(3,13,0)
++static u16 ieee80211_netdev_select_queue(struct net_device *dev,
++                                       struct sk_buff *skb,
++                                       void *accel_priv)
++#else
++static u16 ieee80211_netdev_select_queue(struct net_device *dev,
++                                       struct sk_buff *skb)
++#endif
++{
++      return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
++}
++
++static void
++ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
++{
++      int i;
++
++      for_each_possible_cpu(i) {
++              const struct pcpu_sw_netstats *tstats;
++              u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
++              unsigned int start;
++
++              tstats = per_cpu_ptr(netdev_tstats(dev), i);
++
++              do {
++                      start = u64_stats_fetch_begin_irq(&tstats->syncp);
++                      rx_packets = tstats->rx_packets;
++                      tx_packets = tstats->tx_packets;
++                      rx_bytes = tstats->rx_bytes;
++                      tx_bytes = tstats->tx_bytes;
++              } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
++
++              stats->rx_packets += rx_packets;
++              stats->tx_packets += tx_packets;
++              stats->rx_bytes   += rx_bytes;
++              stats->tx_bytes   += tx_bytes;
++      }
++}
++#if LINUX_VERSION_IS_LESS(4,11,0)
++/* Just declare it here to keep sparse happy */
++struct rtnl_link_stats64 *bp_ieee80211_get_stats64(struct net_device *dev,
++                                                 struct rtnl_link_stats64 *stats);
++struct rtnl_link_stats64 *
++bp_ieee80211_get_stats64(struct net_device *dev,
++                       struct rtnl_link_stats64 *stats){
++      ieee80211_get_stats64(dev, stats);
++      return stats;
++}
++#endif
++
++static const struct net_device_ops ieee80211_dataif_ops = {
++      .ndo_open               = ieee80211_open,
++      .ndo_stop               = ieee80211_stop,
++      .ndo_uninit             = ieee80211_uninit,
++      .ndo_start_xmit         = ieee80211_subif_start_xmit,
++      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
++      .ndo_set_mac_address    = ieee80211_change_mac,
++      .ndo_select_queue       = ieee80211_netdev_select_queue,
++#if LINUX_VERSION_IS_GEQ(4,11,0)
++      .ndo_get_stats64        = ieee80211_get_stats64,
++#else
++      .ndo_get_stats64 = bp_ieee80211_get_stats64,
++#endif
++
++};
++
++#if LINUX_VERSION_IS_GEQ(5,2,0)
++static u16 ieee80211_monitor_select_queue(struct net_device *dev,
++                                        struct sk_buff *skb,
++                                        struct net_device *sb_dev)
++#elif LINUX_VERSION_IS_GEQ(4,19,0)
++static u16 ieee80211_monitor_select_queue(struct net_device *dev,
++                                        struct sk_buff *skb,
++                                        struct net_device *sb_dev,
++                                        select_queue_fallback_t fallback)
++#elif LINUX_VERSION_IS_GEQ(3,14,0) || \
++    (LINUX_VERSION_CODE == KERNEL_VERSION(3,13,11) && UTS_UBUNTU_RELEASE_ABI > 30)
++static u16 ieee80211_monitor_select_queue(struct net_device *dev,
++                                        struct sk_buff *skb,
++                                        void *accel_priv,
++                                        select_queue_fallback_t fallback)
++#elif LINUX_VERSION_IS_GEQ(3,13,0)
++static u16 ieee80211_monitor_select_queue(struct net_device *dev,
++                                        struct sk_buff *skb,
++                                        void *accel_priv)
++#else
++static u16 ieee80211_monitor_select_queue(struct net_device *dev,
++                                        struct sk_buff *skb)
++#endif
++{
++      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++      struct ieee80211_local *local = sdata->local;
++      struct ieee80211_hdr *hdr;
++      struct ieee80211_radiotap_header *rtap = (void *)skb->data;
++
++      if (local->hw.queues < IEEE80211_NUM_ACS)
++              return 0;
++
++      if (skb->len < 4 ||
++          skb->len < le16_to_cpu(rtap->it_len) + 2 /* frame control */)
++              return 0; /* doesn't matter, frame will be dropped */
++
++      hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
++
++      return ieee80211_select_queue_80211(sdata, skb, hdr);
++}
++
++static const struct net_device_ops ieee80211_monitorif_ops = {
++      .ndo_open               = ieee80211_open,
++      .ndo_stop               = ieee80211_stop,
++      .ndo_uninit             = ieee80211_uninit,
++      .ndo_start_xmit         = ieee80211_monitor_start_xmit,
++      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
++      .ndo_set_mac_address    = ieee80211_change_mac,
++      .ndo_select_queue       = ieee80211_monitor_select_queue,
++#if LINUX_VERSION_IS_GEQ(4,11,0)
++      .ndo_get_stats64        = ieee80211_get_stats64,
++#else
++      .ndo_get_stats64 = bp_ieee80211_get_stats64,
++#endif
++
++};
++
++static const struct net_device_ops ieee80211_dataif_8023_ops = {
++      .ndo_open               = ieee80211_open,
++      .ndo_stop               = ieee80211_stop,
++      .ndo_uninit             = ieee80211_uninit,
++      .ndo_start_xmit         = ieee80211_subif_start_xmit_8023,
++      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
++      .ndo_set_mac_address    = ieee80211_change_mac,
++      .ndo_select_queue       = ieee80211_netdev_select_queue,
++#if LINUX_VERSION_IS_GEQ(4,11,0)
++      .ndo_get_stats64        = ieee80211_get_stats64,
++#else
++      .ndo_get_stats64 = bp_ieee80211_get_stats64,
++#endif
++
++};
++
+ static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
+ {
+       switch (iftype) {
+@@ -389,6 +893,31 @@ static bool ieee80211_set_sdata_offload_
+       return true;
+ }
++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_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
+ {
+@@ -866,511 +1395,6 @@ int ieee80211_do_open(struct wireless_de
+       return res;
+ }
+-static int ieee80211_open(struct net_device *dev)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      int err;
+-
+-      /* fail early if user set an invalid address */
+-      if (!is_valid_ether_addr(dev->dev_addr))
+-              return -EADDRNOTAVAIL;
+-
+-      err = ieee80211_check_concurrent_iface(sdata, sdata->vif.type);
+-      if (err)
+-              return err;
+-
+-      return ieee80211_do_open(&sdata->wdev, true);
+-}
+-
+-static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
+-                            bool going_down)
+-{
+-      struct ieee80211_local *local = sdata->local;
+-      unsigned long flags;
+-      struct sk_buff *skb, *tmp;
+-      u32 hw_reconf_flags = 0;
+-      int i, flushed;
+-      struct ps_data *ps;
+-      struct cfg80211_chan_def chandef;
+-      bool cancel_scan;
+-      struct cfg80211_nan_func *func;
+-
+-      clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+-
+-      cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
+-      if (cancel_scan)
+-              ieee80211_scan_cancel(local);
+-
+-      /*
+-       * Stop TX on this interface first.
+-       */
+-      if (sdata->dev)
+-              netif_tx_stop_all_queues(sdata->dev);
+-
+-      ieee80211_roc_purge(local, sdata);
+-
+-      switch (sdata->vif.type) {
+-      case NL80211_IFTYPE_STATION:
+-              ieee80211_mgd_stop(sdata);
+-              break;
+-      case NL80211_IFTYPE_ADHOC:
+-              ieee80211_ibss_stop(sdata);
+-              break;
+-      case NL80211_IFTYPE_MONITOR:
+-              if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES)
+-                      break;
+-              list_del_rcu(&sdata->u.mntr.list);
+-              break;
+-      default:
+-              break;
+-      }
+-
+-      /*
+-       * Remove all stations associated with this interface.
+-       *
+-       * This must be done before calling ops->remove_interface()
+-       * because otherwise we can later invoke ops->sta_notify()
+-       * whenever the STAs are removed, and that invalidates driver
+-       * assumptions about always getting a vif pointer that is valid
+-       * (because if we remove a STA after ops->remove_interface()
+-       * the driver will have removed the vif info already!)
+-       *
+-       * In WDS mode a station must exist here and be flushed, for
+-       * AP_VLANs stations may exist since there's nothing else that
+-       * would have removed them, but in other modes there shouldn't
+-       * be any stations.
+-       */
+-      flushed = sta_info_flush(sdata);
+-      WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+-                   ((sdata->vif.type != NL80211_IFTYPE_WDS && flushed > 0) ||
+-                    (sdata->vif.type == NL80211_IFTYPE_WDS && flushed != 1)));
+-
+-      /* don't count this interface for allmulti while it is down */
+-      if (sdata->flags & IEEE80211_SDATA_ALLMULTI)
+-              atomic_dec(&local->iff_allmultis);
+-
+-      if (sdata->vif.type == NL80211_IFTYPE_AP) {
+-              local->fif_pspoll--;
+-              local->fif_probe_req--;
+-      } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+-              local->fif_probe_req--;
+-      }
+-
+-      if (sdata->dev) {
+-              netif_addr_lock_bh(sdata->dev);
+-              spin_lock_bh(&local->filter_lock);
+-              __hw_addr_unsync(&local->mc_list, &sdata->dev->mc,
+-                               sdata->dev->addr_len);
+-              spin_unlock_bh(&local->filter_lock);
+-              netif_addr_unlock_bh(sdata->dev);
+-      }
+-
+-      del_timer_sync(&local->dynamic_ps_timer);
+-      cancel_work_sync(&local->dynamic_ps_enable_work);
+-
+-      cancel_work_sync(&sdata->recalc_smps);
+-      sdata_lock(sdata);
+-      mutex_lock(&local->mtx);
+-      sdata->vif.csa_active = false;
+-      if (sdata->vif.type == NL80211_IFTYPE_STATION)
+-              sdata->u.mgd.csa_waiting_bcn = false;
+-      if (sdata->csa_block_tx) {
+-              ieee80211_wake_vif_queues(local, sdata,
+-                                        IEEE80211_QUEUE_STOP_REASON_CSA);
+-              sdata->csa_block_tx = false;
+-      }
+-      mutex_unlock(&local->mtx);
+-      sdata_unlock(sdata);
+-
+-      cancel_work_sync(&sdata->csa_finalize_work);
+-
+-      cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+-
+-      if (sdata->wdev.cac_started) {
+-              chandef = sdata->vif.bss_conf.chandef;
+-              WARN_ON(local->suspended);
+-              mutex_lock(&local->mtx);
+-              ieee80211_vif_release_channel(sdata);
+-              mutex_unlock(&local->mtx);
+-              cfg80211_cac_event(sdata->dev, &chandef,
+-                                 NL80211_RADAR_CAC_ABORTED,
+-                                 GFP_KERNEL);
+-      }
+-
+-      /* APs need special treatment */
+-      if (sdata->vif.type == NL80211_IFTYPE_AP) {
+-              struct ieee80211_sub_if_data *vlan, *tmpsdata;
+-
+-              /* down all dependent devices, that is VLANs */
+-              list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
+-                                       u.vlan.list)
+-                      dev_close(vlan->dev);
+-              WARN_ON(!list_empty(&sdata->u.ap.vlans));
+-      } else if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+-              /* remove all packets in parent bc_buf pointing to this dev */
+-              ps = &sdata->bss->ps;
+-
+-              spin_lock_irqsave(&ps->bc_buf.lock, flags);
+-              skb_queue_walk_safe(&ps->bc_buf, skb, tmp) {
+-                      if (skb->dev == sdata->dev) {
+-                              __skb_unlink(skb, &ps->bc_buf);
+-                              local->total_ps_buffered--;
+-                              ieee80211_free_txskb(&local->hw, skb);
+-                      }
+-              }
+-              spin_unlock_irqrestore(&ps->bc_buf.lock, flags);
+-      }
+-
+-      if (going_down)
+-              local->open_count--;
+-
+-      switch (sdata->vif.type) {
+-      case NL80211_IFTYPE_AP_VLAN:
+-              mutex_lock(&local->mtx);
+-              list_del(&sdata->u.vlan.list);
+-              mutex_unlock(&local->mtx);
+-              RCU_INIT_POINTER(sdata->vif.chanctx_conf, NULL);
+-              /* see comment in the default case below */
+-              ieee80211_free_keys(sdata, true);
+-              /* no need to tell driver */
+-              break;
+-      case NL80211_IFTYPE_MONITOR:
+-              if (sdata->u.mntr.flags & MONITOR_FLAG_COOK_FRAMES) {
+-                      local->cooked_mntrs--;
+-                      break;
+-              }
+-
+-              local->monitors--;
+-              if (local->monitors == 0) {
+-                      local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR;
+-                      hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR;
+-              }
+-
+-              ieee80211_adjust_monitor_flags(sdata, -1);
+-              break;
+-      case NL80211_IFTYPE_NAN:
+-              /* clean all the functions */
+-              spin_lock_bh(&sdata->u.nan.func_lock);
+-
+-              idr_for_each_entry(&sdata->u.nan.function_inst_ids, func, i) {
+-                      idr_remove(&sdata->u.nan.function_inst_ids, i);
+-                      cfg80211_free_nan_func(func);
+-              }
+-              idr_destroy(&sdata->u.nan.function_inst_ids);
+-
+-              spin_unlock_bh(&sdata->u.nan.func_lock);
+-              break;
+-      case NL80211_IFTYPE_P2P_DEVICE:
+-              /* relies on synchronize_rcu() below */
+-              RCU_INIT_POINTER(local->p2p_sdata, NULL);
+-              /* fall through */
+-      default:
+-              cancel_work_sync(&sdata->work);
+-              /*
+-               * When we get here, the interface is marked down.
+-               * Free the remaining keys, if there are any
+-               * (which can happen in AP mode if userspace sets
+-               * keys before the interface is operating, and maybe
+-               * also in WDS mode)
+-               *
+-               * Force the key freeing to always synchronize_net()
+-               * to wait for the RX path in case it is using this
+-               * interface enqueuing frames at this very time on
+-               * another CPU.
+-               */
+-              ieee80211_free_keys(sdata, true);
+-              skb_queue_purge(&sdata->skb_queue);
+-      }
+-
+-      spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+-      for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
+-              skb_queue_walk_safe(&local->pending[i], skb, tmp) {
+-                      struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+-                      if (info->control.vif == &sdata->vif) {
+-                              __skb_unlink(skb, &local->pending[i]);
+-                              ieee80211_free_txskb(&local->hw, skb);
+-                      }
+-              }
+-      }
+-      spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+-
+-      if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+-              ieee80211_txq_remove_vlan(local, sdata);
+-
+-      sdata->bss = NULL;
+-
+-      if (local->open_count == 0)
+-              ieee80211_clear_tx_pending(local);
+-
+-      sdata->vif.bss_conf.beacon_int = 0;
+-
+-      /*
+-       * If the interface goes down while suspended, presumably because
+-       * the device was unplugged and that happens before our resume,
+-       * then the driver is already unconfigured and the remainder of
+-       * this function isn't needed.
+-       * XXX: what about WoWLAN? If the device has software state, e.g.
+-       *      memory allocated, it might expect teardown commands from
+-       *      mac80211 here?
+-       */
+-      if (local->suspended) {
+-              WARN_ON(local->wowlan);
+-              WARN_ON(rtnl_dereference(local->monitor_sdata));
+-              return;
+-      }
+-
+-      switch (sdata->vif.type) {
+-      case NL80211_IFTYPE_AP_VLAN:
+-              break;
+-      case NL80211_IFTYPE_MONITOR:
+-              if (local->monitors == 0)
+-                      ieee80211_del_virtual_monitor(local);
+-
+-              mutex_lock(&local->mtx);
+-              ieee80211_recalc_idle(local);
+-              mutex_unlock(&local->mtx);
+-
+-              if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+-                      break;
+-
+-              /* fall through */
+-      default:
+-              if (going_down)
+-                      drv_remove_interface(local, sdata);
+-      }
+-
+-      ieee80211_recalc_ps(local);
+-
+-      if (cancel_scan)
+-              flush_delayed_work(&local->scan_work);
+-
+-      if (local->open_count == 0) {
+-              ieee80211_stop_device(local);
+-
+-              /* no reconfiguring after stop! */
+-              return;
+-      }
+-
+-      /* do after stop to avoid reconfiguring when we stop anyway */
+-      ieee80211_configure_filter(local);
+-      ieee80211_hw_config(local, hw_reconf_flags);
+-
+-      if (local->monitors == local->open_count)
+-              ieee80211_add_virtual_monitor(local);
+-}
+-
+-static int ieee80211_stop(struct net_device *dev)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-
+-      ieee80211_do_stop(sdata, true);
+-
+-      return 0;
+-}
+-
+-static void ieee80211_set_multicast_list(struct net_device *dev)
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      struct ieee80211_local *local = sdata->local;
+-      int allmulti, sdata_allmulti;
+-
+-      allmulti = !!(dev->flags & IFF_ALLMULTI);
+-      sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI);
+-
+-      if (allmulti != sdata_allmulti) {
+-              if (dev->flags & IFF_ALLMULTI)
+-                      atomic_inc(&local->iff_allmultis);
+-              else
+-                      atomic_dec(&local->iff_allmultis);
+-              sdata->flags ^= IEEE80211_SDATA_ALLMULTI;
+-      }
+-
+-      spin_lock_bh(&local->filter_lock);
+-      __hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
+-      spin_unlock_bh(&local->filter_lock);
+-      ieee80211_queue_work(&local->hw, &local->reconfig_filter);
+-}
+-
+-/*
+- * Called when the netdev is removed or, by the code below, before
+- * the interface type changes.
+- */
+-static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)
+-{
+-      int i;
+-
+-      /* free extra data */
+-      ieee80211_free_keys(sdata, false);
+-
+-      ieee80211_debugfs_remove_netdev(sdata);
+-
+-      for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+-              __skb_queue_purge(&sdata->fragments[i].skb_list);
+-      sdata->fragment_next = 0;
+-
+-      if (ieee80211_vif_is_mesh(&sdata->vif))
+-              ieee80211_mesh_teardown_sdata(sdata);
+-}
+-
+-static void ieee80211_uninit(struct net_device *dev)
+-{
+-      ieee80211_teardown_sdata(IEEE80211_DEV_TO_SUB_IF(dev));
+-}
+-
+-#if LINUX_VERSION_IS_GEQ(5,2,0)
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb,
+-                                       struct net_device *sb_dev)
+-#elif LINUX_VERSION_IS_GEQ(4,19,0)
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb,
+-                                       struct net_device *sb_dev,
+-                                       select_queue_fallback_t fallback)
+-#elif LINUX_VERSION_IS_GEQ(3,14,0) || \
+-    (LINUX_VERSION_CODE == KERNEL_VERSION(3,13,11) && UTS_UBUNTU_RELEASE_ABI > 30)
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb,
+-                                       void *accel_priv,
+-                                       select_queue_fallback_t fallback)
+-#elif LINUX_VERSION_IS_GEQ(3,13,0)
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb,
+-                                       void *accel_priv)
+-#else
+-static u16 ieee80211_netdev_select_queue(struct net_device *dev,
+-                                       struct sk_buff *skb)
+-#endif
+-{
+-      return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb);
+-}
+-
+-static void
+-ieee80211_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
+-{
+-      int i;
+-
+-      for_each_possible_cpu(i) {
+-              const struct pcpu_sw_netstats *tstats;
+-              u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+-              unsigned int start;
+-
+-              tstats = per_cpu_ptr(netdev_tstats(dev), i);
+-
+-              do {
+-                      start = u64_stats_fetch_begin_irq(&tstats->syncp);
+-                      rx_packets = tstats->rx_packets;
+-                      tx_packets = tstats->tx_packets;
+-                      rx_bytes = tstats->rx_bytes;
+-                      tx_bytes = tstats->tx_bytes;
+-              } while (u64_stats_fetch_retry_irq(&tstats->syncp, start));
+-
+-              stats->rx_packets += rx_packets;
+-              stats->tx_packets += tx_packets;
+-              stats->rx_bytes   += rx_bytes;
+-              stats->tx_bytes   += tx_bytes;
+-      }
+-}
+-#if LINUX_VERSION_IS_LESS(4,11,0)
+-/* Just declare it here to keep sparse happy */
+-struct rtnl_link_stats64 *bp_ieee80211_get_stats64(struct net_device *dev,
+-                                                 struct rtnl_link_stats64 *stats);
+-struct rtnl_link_stats64 *
+-bp_ieee80211_get_stats64(struct net_device *dev,
+-                       struct rtnl_link_stats64 *stats){
+-      ieee80211_get_stats64(dev, stats);
+-      return stats;
+-}
+-#endif
+-
+-static const struct net_device_ops ieee80211_dataif_ops = {
+-      .ndo_open               = ieee80211_open,
+-      .ndo_stop               = ieee80211_stop,
+-      .ndo_uninit             = ieee80211_uninit,
+-      .ndo_start_xmit         = ieee80211_subif_start_xmit,
+-      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
+-      .ndo_set_mac_address    = ieee80211_change_mac,
+-      .ndo_select_queue       = ieee80211_netdev_select_queue,
+-#if LINUX_VERSION_IS_GEQ(4,11,0)
+-      .ndo_get_stats64        = ieee80211_get_stats64,
+-#else
+-      .ndo_get_stats64 = bp_ieee80211_get_stats64,
+-#endif
+-
+-};
+-
+-#if LINUX_VERSION_IS_GEQ(5,2,0)
+-static u16 ieee80211_monitor_select_queue(struct net_device *dev,
+-                                        struct sk_buff *skb,
+-                                        struct net_device *sb_dev)
+-#elif LINUX_VERSION_IS_GEQ(4,19,0)
+-static u16 ieee80211_monitor_select_queue(struct net_device *dev,
+-                                        struct sk_buff *skb,
+-                                        struct net_device *sb_dev,
+-                                        select_queue_fallback_t fallback)
+-#elif LINUX_VERSION_IS_GEQ(3,14,0) || \
+-    (LINUX_VERSION_CODE == KERNEL_VERSION(3,13,11) && UTS_UBUNTU_RELEASE_ABI > 30)
+-static u16 ieee80211_monitor_select_queue(struct net_device *dev,
+-                                        struct sk_buff *skb,
+-                                        void *accel_priv,
+-                                        select_queue_fallback_t fallback)
+-#elif LINUX_VERSION_IS_GEQ(3,13,0)
+-static u16 ieee80211_monitor_select_queue(struct net_device *dev,
+-                                        struct sk_buff *skb,
+-                                        void *accel_priv)
+-#else
+-static u16 ieee80211_monitor_select_queue(struct net_device *dev,
+-                                        struct sk_buff *skb)
+-#endif
+-{
+-      struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+-      struct ieee80211_local *local = sdata->local;
+-      struct ieee80211_hdr *hdr;
+-      struct ieee80211_radiotap_header *rtap = (void *)skb->data;
+-
+-      if (local->hw.queues < IEEE80211_NUM_ACS)
+-              return 0;
+-
+-      if (skb->len < 4 ||
+-          skb->len < le16_to_cpu(rtap->it_len) + 2 /* frame control */)
+-              return 0; /* doesn't matter, frame will be dropped */
+-
+-      hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len));
+-
+-      return ieee80211_select_queue_80211(sdata, skb, hdr);
+-}
+-
+-static const struct net_device_ops ieee80211_monitorif_ops = {
+-      .ndo_open               = ieee80211_open,
+-      .ndo_stop               = ieee80211_stop,
+-      .ndo_uninit             = ieee80211_uninit,
+-      .ndo_start_xmit         = ieee80211_monitor_start_xmit,
+-      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
+-      .ndo_set_mac_address    = ieee80211_change_mac,
+-      .ndo_select_queue       = ieee80211_monitor_select_queue,
+-#if LINUX_VERSION_IS_GEQ(4,11,0)
+-      .ndo_get_stats64        = ieee80211_get_stats64,
+-#else
+-      .ndo_get_stats64 = bp_ieee80211_get_stats64,
+-#endif
+-
+-};
+-
+-static const struct net_device_ops ieee80211_dataif_8023_ops = {
+-      .ndo_open               = ieee80211_open,
+-      .ndo_stop               = ieee80211_stop,
+-      .ndo_uninit             = ieee80211_uninit,
+-      .ndo_start_xmit         = ieee80211_subif_start_xmit_8023,
+-      .ndo_set_rx_mode        = ieee80211_set_multicast_list,
+-      .ndo_set_mac_address    = ieee80211_change_mac,
+-      .ndo_select_queue       = ieee80211_netdev_select_queue,
+-#if LINUX_VERSION_IS_GEQ(4,11,0)
+-      .ndo_get_stats64        = ieee80211_get_stats64,
+-#else
+-      .ndo_get_stats64 = bp_ieee80211_get_stats64,
+-#endif
+-
+-};
+-
+ static void ieee80211_if_free(struct net_device *dev)
+ {
+       free_percpu(netdev_tstats(dev));
+@@ -1401,32 +1425,6 @@ 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 =
index 1487e10f42de0c9195fda064e771c785f261cf1b..8db3a758a1b346afbf566cd566a15bddf3688a07 100644 (file)
@@ -18,7 +18,7 @@
                                const u8 *addr);
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -1519,6 +1519,7 @@ enum ieee80211_smps_mode {
+@@ -1521,6 +1521,7 @@ enum ieee80211_smps_mode {
   *
   * @power_level: requested transmit power (in dBm), backward compatibility
   *    value only that is set to the minimum of all interfaces
@@ -26,7 +26,7 @@
   *
   * @chandef: the channel definition to tune to
   * @radar_enabled: whether radar detection is enabled
-@@ -1539,6 +1540,7 @@ enum ieee80211_smps_mode {
+@@ -1541,6 +1542,7 @@ enum ieee80211_smps_mode {
  struct ieee80211_conf {
        u32 flags;
        int power_level, dynamic_ps_timeout;
@@ -57,7 +57,7 @@
        __NL80211_ATTR_AFTER_LAST,
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2615,6 +2615,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2611,6 +2611,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)
  {
-@@ -4045,6 +4058,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -4041,6 +4054,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,