aboutsummaryrefslogtreecommitdiff
path: root/net/mac80211/ieee80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ieee80211.c')
-rw-r--r--net/mac80211/ieee80211.c99
1 files changed, 42 insertions, 57 deletions
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 22cba82a0c6..484b063a353 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -183,6 +183,7 @@ static int ieee80211_open(struct net_device *dev)
struct ieee80211_if_init_conf conf;
int res;
bool need_hw_reconfig = 0;
+ struct sta_info *sta;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -256,6 +257,20 @@ static int ieee80211_open(struct net_device *dev)
case IEEE80211_IF_TYPE_WDS:
if (is_zero_ether_addr(sdata->u.wds.remote_addr))
return -ENOLINK;
+
+ /* Create STA entry for the WDS peer */
+ sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr,
+ GFP_KERNEL);
+ if (!sta)
+ return -ENOMEM;
+
+ sta->flags |= WLAN_STA_AUTHORIZED;
+
+ res = sta_info_insert(sta);
+ if (res) {
+ sta_info_destroy(sta);
+ return res;
+ }
break;
case IEEE80211_IF_TYPE_VLAN:
if (!sdata->u.vlan.ap)
@@ -367,14 +382,20 @@ static int ieee80211_open(struct net_device *dev)
static int ieee80211_stop(struct net_device *dev)
{
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_init_conf conf;
struct sta_info *sta;
int i;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ /*
+ * Stop TX on this interface first.
+ */
+ netif_stop_queue(dev);
+ /*
+ * Now delete all active aggregation sessions.
+ */
rcu_read_lock();
list_for_each_entry_rcu(sta, &local->sta_list, list) {
@@ -388,7 +409,24 @@ static int ieee80211_stop(struct net_device *dev)
rcu_read_unlock();
- netif_stop_queue(dev);
+ /*
+ * 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!)
+ *
+ * We could relax this and only unlink the stations from the
+ * hash table and list but keep them on a per-sdata list that
+ * will be inserted back again when the interface is brought
+ * up again, but I don't currently see a use case for that,
+ * except with WDS which gets a STA entry created when it is
+ * brought up.
+ */
+ sta_info_flush(local, sdata);
/*
* Don't count this interface for promisc/allmulti while it
@@ -453,8 +491,6 @@ static int ieee80211_stop(struct net_device *dev)
netif_tx_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_MESH_POINT:
- sta_info_flush(local, sdata);
- /* fall through */
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
sdata->u.sta.state = IEEE80211_DISABLED;
@@ -892,57 +928,6 @@ void ieee80211_if_setup(struct net_device *dev)
dev->destructor = ieee80211_if_free;
}
-/* WDS specialties */
-
-int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sta_info *sta;
- int err;
- DECLARE_MAC_BUF(mac);
-
- might_sleep();
-
- if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0)
- return 0;
-
- /* Create STA entry for the new peer */
- sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL);
- if (!sta)
- return -ENOMEM;
-
- sta->flags |= WLAN_STA_AUTHORIZED;
- err = sta_info_insert(sta);
- if (err) {
- sta_info_destroy(sta);
- return err;
- }
-
- rcu_read_lock();
-
- /* Remove STA entry for the old peer */
- sta = sta_info_get(local, sdata->u.wds.remote_addr);
- if (sta)
- sta_info_unlink(&sta);
- else
- printk(KERN_DEBUG "%s: could not find STA entry for WDS link "
- "peer %s\n",
- dev->name, print_mac(mac, sdata->u.wds.remote_addr));
-
- /* Update WDS link data */
- memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN);
-
- rcu_read_unlock();
-
- if (sta) {
- synchronize_rcu();
- sta_info_destroy(sta);
- }
-
- return 0;
-}
-
/* everything else */
static int __ieee80211_if_config(struct net_device *dev,