diff options
Diffstat (limited to 'package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch')
-rw-r--r-- | package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch | 1110 |
1 files changed, 1110 insertions, 0 deletions
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 index 0000000000..a3d600152c --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/327-mac80211-reorganize-code-to-remove-a-forward-declara.patch @@ -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 = |