The removed patches were applied upstream. Remove the 300-mac80211-optimize-skb-resizing.patch. This patch was not applied upstream, but it conflicts with upstream changes and needs bigger changes. It was applied with Felix to remove this patch for now. It should be reworked and then send upstream later. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
1124 lines
33 KiB
Diff
1124 lines
33 KiB
Diff
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,518 @@ 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);
|
|
+ fallthrough;
|
|
+ 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;
|
|
+
|
|
+ fallthrough;
|
|
+ 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_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
+ struct ieee80211_hdr *hdr;
|
|
+ int len_rthdr;
|
|
+
|
|
+ if (local->hw.queues < IEEE80211_NUM_ACS)
|
|
+ return 0;
|
|
+
|
|
+ /* reset flags and info before parsing radiotap header */
|
|
+ memset(info, 0, sizeof(*info));
|
|
+
|
|
+ if (!ieee80211_parse_tx_radiotap(skb, dev))
|
|
+ return 0; /* doesn't matter, frame will be dropped */
|
|
+
|
|
+ len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
|
+ hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
|
+ if (skb->len < len_rthdr + 2 ||
|
|
+ skb->len < len_rthdr + ieee80211_hdrlen(hdr->frame_control))
|
|
+ return 0; /* doesn't matter, frame will be dropped */
|
|
+
|
|
+ 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 +900,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,518 +1402,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);
|
|
- fallthrough;
|
|
- 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;
|
|
-
|
|
- fallthrough;
|
|
- 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_tx_info *info = IEEE80211_SKB_CB(skb);
|
|
- struct ieee80211_hdr *hdr;
|
|
- int len_rthdr;
|
|
-
|
|
- if (local->hw.queues < IEEE80211_NUM_ACS)
|
|
- return 0;
|
|
-
|
|
- /* reset flags and info before parsing radiotap header */
|
|
- memset(info, 0, sizeof(*info));
|
|
-
|
|
- if (!ieee80211_parse_tx_radiotap(skb, dev))
|
|
- return 0; /* doesn't matter, frame will be dropped */
|
|
-
|
|
- len_rthdr = ieee80211_get_radiotap_len(skb->data);
|
|
- hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
|
- if (skb->len < len_rthdr + 2 ||
|
|
- skb->len < len_rthdr + ieee80211_hdrlen(hdr->frame_control))
|
|
- return 0; /* doesn't matter, frame will be dropped */
|
|
-
|
|
- 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));
|
|
@@ -1408,32 +1432,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 =
|