summaryrefslogtreecommitdiff
path: root/net/mac80211/iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/iface.c')
-rw-r--r--net/mac80211/iface.c54
1 files changed, 32 insertions, 22 deletions
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d85282f64405..69aaba79a9f7 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -78,7 +78,7 @@ void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
}
-static u32 ieee80211_idle_off(struct ieee80211_local *local)
+u32 ieee80211_idle_off(struct ieee80211_local *local)
{
if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE))
return 0;
@@ -92,7 +92,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
return 0;
- drv_flush(local, false);
+ ieee80211_flush_queues(local, NULL);
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
return IEEE80211_CONF_CHANGE_IDLE;
@@ -349,21 +349,19 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata)
static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
- int ret = 0;
+ int ret;
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return 0;
- mutex_lock(&local->iflist_mtx);
+ ASSERT_RTNL();
if (local->monitor_sdata)
- goto out_unlock;
+ return 0;
sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
- if (!sdata) {
- ret = -ENOMEM;
- goto out_unlock;
- }
+ if (!sdata)
+ return -ENOMEM;
/* set up data */
sdata->local = local;
@@ -377,13 +375,13 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (WARN_ON(ret)) {
/* ok .. stupid driver, it asked for this! */
kfree(sdata);
- goto out_unlock;
+ return ret;
}
ret = ieee80211_check_queues(sdata);
if (ret) {
kfree(sdata);
- goto out_unlock;
+ return ret;
}
ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
@@ -391,13 +389,14 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
if (ret) {
drv_remove_interface(local, sdata);
kfree(sdata);
- goto out_unlock;
+ return ret;
}
+ mutex_lock(&local->iflist_mtx);
rcu_assign_pointer(local->monitor_sdata, sdata);
- out_unlock:
mutex_unlock(&local->iflist_mtx);
- return ret;
+
+ return 0;
}
static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
@@ -407,14 +406,20 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))
return;
+ ASSERT_RTNL();
+
mutex_lock(&local->iflist_mtx);
sdata = rcu_dereference_protected(local->monitor_sdata,
lockdep_is_held(&local->iflist_mtx));
- if (!sdata)
- goto out_unlock;
+ if (!sdata) {
+ mutex_unlock(&local->iflist_mtx);
+ return;
+ }
rcu_assign_pointer(local->monitor_sdata, NULL);
+ mutex_unlock(&local->iflist_mtx);
+
synchronize_net();
ieee80211_vif_release_channel(sdata);
@@ -422,8 +427,6 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
drv_remove_interface(local, sdata);
kfree(sdata);
- out_unlock:
- mutex_unlock(&local->iflist_mtx);
}
/*
@@ -557,8 +560,6 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
goto err_del_interface;
}
- drv_add_interface_debugfs(local, sdata);
-
if (sdata->vif.type == NL80211_IFTYPE_AP) {
local->fif_pspoll++;
local->fif_probe_req++;
@@ -846,8 +847,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
skb_queue_purge(&sdata->skb_queue);
- drv_remove_interface_debugfs(local, sdata);
-
if (going_down)
drv_remove_interface(local, sdata);
}
@@ -919,6 +918,17 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
atomic_dec(&local->iff_promiscs);
sdata->flags ^= IEEE80211_SDATA_PROMISC;
}
+
+ /*
+ * TODO: If somebody needs this on AP interfaces,
+ * it can be enabled easily but multicast
+ * addresses from VLANs need to be synced.
+ */
+ if (sdata->vif.type != NL80211_IFTYPE_MONITOR &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
+ drv_set_multicast_list(local, sdata, &dev->mc);
+
spin_lock_bh(&local->filter_lock);
__hw_addr_sync(&local->mc_list, &dev->mc, dev->addr_len);
spin_unlock_bh(&local->filter_lock);