summaryrefslogtreecommitdiff
path: root/net/mac80211/ieee80211_iface.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/ieee80211_iface.c')
-rw-r--r--net/mac80211/ieee80211_iface.c164
1 files changed, 55 insertions, 109 deletions
diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c
index 8532a5ccdd1e..43e505d29452 100644
--- a/net/mac80211/ieee80211_iface.c
+++ b/net/mac80211/ieee80211_iface.c
@@ -25,6 +25,8 @@ void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
sdata->eapol = 1;
for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
skb_queue_head_init(&sdata->fragments[i].skb_list);
+
+ INIT_LIST_HEAD(&sdata->key_list);
}
static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
@@ -77,18 +79,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name,
ieee80211_debugfs_add_netdev(sdata);
ieee80211_if_set_type(ndev, type);
- write_lock_bh(&local->sub_if_lock);
+ /* we're under RTNL so all this is fine */
if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) {
- write_unlock_bh(&local->sub_if_lock);
__ieee80211_if_del(local, sdata);
return -ENODEV;
}
- list_add(&sdata->list, &local->sub_if_list);
+ list_add_tail_rcu(&sdata->list, &local->interfaces);
+
if (new_dev)
*new_dev = ndev;
- write_unlock_bh(&local->sub_if_lock);
-
- ieee80211_update_default_wep_only(local);
return 0;
@@ -97,74 +96,35 @@ fail:
return ret;
}
-int ieee80211_if_add_mgmt(struct ieee80211_local *local)
-{
- struct net_device *ndev;
- struct ieee80211_sub_if_data *nsdata;
- int ret;
-
- ASSERT_RTNL();
-
- ndev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), "wmgmt%d",
- ieee80211_if_mgmt_setup);
- if (!ndev)
- return -ENOMEM;
- ret = dev_alloc_name(ndev, ndev->name);
- if (ret < 0)
- goto fail;
-
- memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
- SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
-
- nsdata = IEEE80211_DEV_TO_SUB_IF(ndev);
- ndev->ieee80211_ptr = &nsdata->wdev;
- nsdata->wdev.wiphy = local->hw.wiphy;
- nsdata->type = IEEE80211_IF_TYPE_MGMT;
- nsdata->dev = ndev;
- nsdata->local = local;
- ieee80211_if_sdata_init(nsdata);
-
- ret = register_netdevice(ndev);
- if (ret)
- goto fail;
-
- ieee80211_debugfs_add_netdev(nsdata);
-
- if (local->open_count > 0)
- dev_open(ndev);
- local->apdev = ndev;
- return 0;
-
-fail:
- free_netdev(ndev);
- return ret;
-}
-
-void ieee80211_if_del_mgmt(struct ieee80211_local *local)
-{
- struct net_device *apdev;
-
- ASSERT_RTNL();
- apdev = local->apdev;
- ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(apdev));
- local->apdev = NULL;
- unregister_netdevice(apdev);
-}
-
void ieee80211_if_set_type(struct net_device *dev, int type)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
int oldtype = sdata->type;
- dev->hard_start_xmit = ieee80211_subif_start_xmit;
-
+ /*
+ * We need to call this function on the master interface
+ * which already has a hard_start_xmit routine assigned
+ * which must not be changed.
+ */
+ if (dev != sdata->local->mdev)
+ dev->hard_start_xmit = ieee80211_subif_start_xmit;
+
+ /*
+ * Called even when register_netdevice fails, it would
+ * oops if assigned before initialising the rest.
+ */
+ dev->uninit = ieee80211_if_reinit;
+
+ /* most have no BSS pointer */
+ sdata->bss = NULL;
sdata->type = type;
+
switch (type) {
case IEEE80211_IF_TYPE_WDS:
- sdata->bss = NULL;
+ /* nothing special */
break;
case IEEE80211_IF_TYPE_VLAN:
+ sdata->u.vlan.ap = NULL;
break;
case IEEE80211_IF_TYPE_AP:
sdata->u.ap.dtim_period = 2;
@@ -172,6 +132,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
sdata->u.ap.max_ratectrl_rateidx = -1;
skb_queue_head_init(&sdata->u.ap.ps_bc_buf);
sdata->bss = &sdata->u.ap;
+ INIT_LIST_HEAD(&sdata->u.ap.vlans);
break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS: {
@@ -187,10 +148,10 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
ifsta->capab = WLAN_CAPABILITY_ESS;
ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
IEEE80211_AUTH_ALG_SHARED_KEY;
- ifsta->create_ibss = 1;
- ifsta->wmm_enabled = 1;
- ifsta->auto_channel_sel = 1;
- ifsta->auto_bssid_sel = 1;
+ ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+ IEEE80211_STA_WMM_ENABLED |
+ IEEE80211_STA_AUTO_BSSID_SEL |
+ IEEE80211_STA_AUTO_CHANNEL_SEL;
msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev);
sdata->bss = &msdata->u.ap;
@@ -205,7 +166,6 @@ void ieee80211_if_set_type(struct net_device *dev, int type)
dev->name, __FUNCTION__, type);
}
ieee80211_debugfs_change_if_type(sdata, oldtype);
- ieee80211_update_default_wep_only(local);
}
/* Must be called with rtnl lock held. */
@@ -214,57 +174,46 @@ void ieee80211_if_reinit(struct net_device *dev)
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 i;
+ struct sk_buff *skb;
ASSERT_RTNL();
+
+ ieee80211_free_keys(sdata);
+
ieee80211_if_sdata_deinit(sdata);
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (!sdata->keys[i])
- continue;
-#if 0
- /* The interface is down at the moment, so there is not
- * really much point in disabling the keys at this point. */
- memset(addr, 0xff, ETH_ALEN);
- if (local->ops->set_key)
- local->ops->set_key(local_to_hw(local), DISABLE_KEY, addr,
- local->keys[i], 0);
-#endif
- ieee80211_key_free(sdata->keys[i]);
- sdata->keys[i] = NULL;
- }
switch (sdata->type) {
+ case IEEE80211_IF_TYPE_INVALID:
+ /* cannot happen */
+ WARN_ON(1);
+ break;
case IEEE80211_IF_TYPE_AP: {
/* Remove all virtual interfaces that use this BSS
* as their sdata->bss */
struct ieee80211_sub_if_data *tsdata, *n;
- LIST_HEAD(tmp_list);
- write_lock_bh(&local->sub_if_lock);
- list_for_each_entry_safe(tsdata, n, &local->sub_if_list, list) {
+ list_for_each_entry_safe(tsdata, n, &local->interfaces, list) {
if (tsdata != sdata && tsdata->bss == &sdata->u.ap) {
printk(KERN_DEBUG "%s: removing virtual "
"interface %s because its BSS interface"
" is being removed\n",
sdata->dev->name, tsdata->dev->name);
- list_move_tail(&tsdata->list, &tmp_list);
+ list_del_rcu(&tsdata->list);
+ /*
+ * We have lots of time and can afford
+ * to sync for each interface
+ */
+ synchronize_rcu();
+ __ieee80211_if_del(local, tsdata);
}
}
- write_unlock_bh(&local->sub_if_lock);
-
- list_for_each_entry_safe(tsdata, n, &tmp_list, list)
- __ieee80211_if_del(local, tsdata);
kfree(sdata->u.ap.beacon_head);
kfree(sdata->u.ap.beacon_tail);
- kfree(sdata->u.ap.generic_elem);
- if (dev != local->mdev) {
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
- local->total_ps_buffered--;
- dev_kfree_skb(skb);
- }
+ while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
+ local->total_ps_buffered--;
+ dev_kfree_skb(skb);
}
break;
@@ -272,8 +221,8 @@ void ieee80211_if_reinit(struct net_device *dev)
case IEEE80211_IF_TYPE_WDS:
sta = sta_info_get(local, sdata->u.wds.remote_addr);
if (sta) {
+ sta_info_free(sta);
sta_info_put(sta);
- sta_info_free(sta, 0);
} else {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: Someone had deleted my STA "
@@ -298,6 +247,9 @@ void ieee80211_if_reinit(struct net_device *dev)
case IEEE80211_IF_TYPE_MNTR:
dev->type = ARPHRD_ETHER;
break;
+ case IEEE80211_IF_TYPE_VLAN:
+ sdata->u.vlan.ap = NULL;
+ break;
}
/* remove all STAs that are bound to this virtual interface */
@@ -327,29 +279,23 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id)
ASSERT_RTNL();
- write_lock_bh(&local->sub_if_lock);
- list_for_each_entry_safe(sdata, n, &local->sub_if_list, list) {
+ list_for_each_entry_safe(sdata, n, &local->interfaces, list) {
if ((sdata->type == id || id == -1) &&
strcmp(name, sdata->dev->name) == 0 &&
sdata->dev != local->mdev) {
- list_del(&sdata->list);
- write_unlock_bh(&local->sub_if_lock);
+ list_del_rcu(&sdata->list);
+ synchronize_rcu();
__ieee80211_if_del(local, sdata);
- ieee80211_update_default_wep_only(local);
return 0;
}
}
- write_unlock_bh(&local->sub_if_lock);
return -ENODEV;
}
void ieee80211_if_free(struct net_device *dev)
{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- /* local->apdev must be NULL when freeing management interface */
- BUG_ON(dev == local->apdev);
ieee80211_if_sdata_deinit(sdata);
free_netdev(dev);
}