summaryrefslogtreecommitdiffstats
path: root/net/mac80211/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/main.c')
-rw-r--r--net/mac80211/main.c609
1 files changed, 284 insertions, 325 deletions
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index df0836f..f1a83d4 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -35,8 +35,6 @@
#include "debugfs.h"
#include "debugfs_netdev.h"
-#define SUPP_MCS_SET_LEN 16
-
/*
* For seeing transmitted packets on monitor interfaces
* we have a radiotap header too.
@@ -107,12 +105,18 @@ static int ieee80211_master_open(struct net_device *dev)
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->dev != dev && netif_running(sdata->dev)) {
+ if (netif_running(sdata->dev)) {
res = 0;
break;
}
}
- return res;
+
+ if (res)
+ return res;
+
+ netif_tx_start_all_queues(local->mdev);
+
+ return 0;
}
static int ieee80211_master_stop(struct net_device *dev)
@@ -122,7 +126,7 @@ static int ieee80211_master_stop(struct net_device *dev)
/* we hold the RTNL here so can safely walk the list */
list_for_each_entry(sdata, &local->interfaces, list)
- if (sdata->dev != dev && netif_running(sdata->dev))
+ if (netif_running(sdata->dev))
dev_close(sdata->dev);
return 0;
@@ -147,9 +151,7 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
/* FIX: what would be proper limits for MTU?
* This interface uses 802.3 frames. */
if (new_mtu < 256 ||
- new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
- printk(KERN_WARNING "%s: invalid MTU %d\n",
- dev->name, new_mtu);
+ new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) {
return -EINVAL;
}
@@ -180,10 +182,11 @@ static int ieee80211_open(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata, *nsdata;
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct sta_info *sta;
struct ieee80211_if_init_conf conf;
+ u32 changed = 0;
int res;
bool need_hw_reconfig = 0;
- struct sta_info *sta;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -191,7 +194,7 @@ static int ieee80211_open(struct net_device *dev)
list_for_each_entry(nsdata, &local->interfaces, list) {
struct net_device *ndev = nsdata->dev;
- if (ndev != dev && ndev != local->mdev && netif_running(ndev)) {
+ if (ndev != dev && netif_running(ndev)) {
/*
* Allow only a single IBSS interface to be up at any
* time. This is restricted because beacon distribution
@@ -207,30 +210,6 @@ static int ieee80211_open(struct net_device *dev)
return -EBUSY;
/*
- * Disallow multiple IBSS/STA mode interfaces.
- *
- * This is a technical restriction, it is possible although
- * most likely not IEEE 802.11 compliant to have multiple
- * STAs with just a single hardware (the TSF timer will not
- * be adjusted properly.)
- *
- * However, because mac80211 uses the master device's BSS
- * information for each STA/IBSS interface, doing this will
- * currently corrupt that BSS information completely, unless,
- * a not very useful case, both STAs are associated to the
- * same BSS.
- *
- * To remove this restriction, the BSS information needs to
- * be embedded in the STA/IBSS mode sdata instead of using
- * the master device's BSS structure.
- */
- if ((sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) &&
- (nsdata->vif.type == IEEE80211_IF_TYPE_STA ||
- nsdata->vif.type == IEEE80211_IF_TYPE_IBSS))
- return -EBUSY;
-
- /*
* The remaining checks are only performed for interfaces
* with the same MAC address.
*/
@@ -249,7 +228,7 @@ static int ieee80211_open(struct net_device *dev)
*/
if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN &&
nsdata->vif.type == IEEE80211_IF_TYPE_AP)
- sdata->u.vlan.ap = nsdata;
+ sdata->bss = &nsdata->u.ap;
}
}
@@ -259,10 +238,13 @@ static int ieee80211_open(struct net_device *dev)
return -ENOLINK;
break;
case IEEE80211_IF_TYPE_VLAN:
- if (!sdata->u.vlan.ap)
+ if (!sdata->bss)
return -ENOLINK;
+ list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
break;
case IEEE80211_IF_TYPE_AP:
+ sdata->bss = &sdata->u.ap;
+ break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_MNTR:
case IEEE80211_IF_TYPE_IBSS:
@@ -280,14 +262,13 @@ static int ieee80211_open(struct net_device *dev)
if (local->ops->start)
res = local->ops->start(local_to_hw(local));
if (res)
- return res;
+ goto err_del_bss;
need_hw_reconfig = 1;
ieee80211_led_radio(local, local->hw.conf.radio_enabled);
}
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN:
- list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans);
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
@@ -310,9 +291,9 @@ static int ieee80211_open(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss++;
- netif_tx_lock_bh(local->mdev);
+ netif_addr_lock_bh(local->mdev);
ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
+ netif_addr_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_STA:
case IEEE80211_IF_TYPE_IBSS:
@@ -326,8 +307,10 @@ static int ieee80211_open(struct net_device *dev)
if (res)
goto err_stop;
- ieee80211_if_config(dev);
- ieee80211_reset_erp_info(dev);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ ieee80211_start_mesh(sdata->dev);
+ changed |= ieee80211_reset_erp_info(dev);
+ ieee80211_bss_info_change_notify(sdata, changed);
ieee80211_enable_keys(sdata);
if (sdata->vif.type == IEEE80211_IF_TYPE_STA &&
@@ -346,6 +329,7 @@ static int ieee80211_open(struct net_device *dev)
goto err_del_interface;
}
+ /* no locking required since STA is not live yet */
sta->flags |= WLAN_STA_AUTHORIZED;
res = sta_info_insert(sta);
@@ -385,13 +369,13 @@ static int ieee80211_open(struct net_device *dev)
* yet be effective. Trigger execution of ieee80211_sta_work
* to fix this.
*/
- if(sdata->vif.type == IEEE80211_IF_TYPE_STA ||
- sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
+ if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
+ sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
queue_work(local->hw.workqueue, &ifsta->work);
}
- netif_start_queue(dev);
+ netif_tx_start_all_queues(dev);
return 0;
err_del_interface:
@@ -399,6 +383,10 @@ static int ieee80211_open(struct net_device *dev)
err_stop:
if (!local->open_count && local->ops->stop)
local->ops->stop(local_to_hw(local));
+ err_del_bss:
+ sdata->bss = NULL;
+ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN)
+ list_del(&sdata->u.vlan.list);
return res;
}
@@ -412,7 +400,7 @@ static int ieee80211_stop(struct net_device *dev)
/*
* Stop TX on this interface first.
*/
- netif_stop_queue(dev);
+ netif_tx_stop_all_queues(dev);
/*
* Now delete all active aggregation sessions.
@@ -481,7 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
switch (sdata->vif.type) {
case IEEE80211_IF_TYPE_VLAN:
list_del(&sdata->u.vlan.list);
- sdata->u.vlan.ap = NULL;
/* no need to tell driver */
break;
case IEEE80211_IF_TYPE_MNTR:
@@ -503,9 +490,9 @@ static int ieee80211_stop(struct net_device *dev)
if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
local->fif_other_bss--;
- netif_tx_lock_bh(local->mdev);
+ netif_addr_lock_bh(local->mdev);
ieee80211_configure_filter(local);
- netif_tx_unlock_bh(local->mdev);
+ netif_addr_unlock_bh(local->mdev);
break;
case IEEE80211_IF_TYPE_MESH_POINT:
case IEEE80211_IF_TYPE_STA:
@@ -544,6 +531,8 @@ static int ieee80211_stop(struct net_device *dev)
local->ops->remove_interface(local_to_hw(local), &conf);
}
+ sdata->bss = NULL;
+
if (local->open_count == 0) {
if (netif_running(local->mdev))
dev_close(local->mdev);
@@ -584,17 +573,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta = sta_info_get(local, ra);
if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find the station\n");
- rcu_read_unlock();
- return -ENOENT;
+#endif
+ ret = -ENOENT;
+ goto exit;
}
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
/* we have tried too many times, receiver does not want A-MPDU */
if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
ret = -EBUSY;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
@@ -605,18 +596,20 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
"idle on tid %u\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
ret = -EAGAIN;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* prepare A-MPDU MLME for Tx aggregation */
sta->ampdu_mlme.tid_tx[tid] =
kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
if (!sta->ampdu_mlme.tid_tx[tid]) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_ERR "allocate tx mlme to tid %d failed\n",
tid);
+#endif
ret = -ENOMEM;
- goto start_ba_exit;
+ goto err_unlock_sta;
}
/* Tx timer */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
@@ -625,10 +618,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
(unsigned long)&sta->timer_to_tid[tid];
init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
- /* ensure that TX flow won't interrupt us
- * until the end of the call to requeue function */
- spin_lock_bh(&local->mdev->queue_lock);
-
/* create a new queue for this aggregation */
ret = ieee80211_ht_agg_queue_add(local, sta, tid);
@@ -639,7 +628,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
printk(KERN_DEBUG "BA request denied - queue unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
- goto start_ba_err;
+ goto err_unlock_queue;
}
sdata = sta->sdata;
@@ -655,18 +644,18 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
/* No need to requeue the packets in the agg queue, since we
* held the tx lock: no packet could be enqueued to the newly
* allocated queue */
- ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
+ ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA request denied - HW unavailable for"
" tid %d\n", tid);
#endif /* CONFIG_MAC80211_HT_DEBUG */
*state = HT_AGG_STATE_IDLE;
- goto start_ba_err;
+ goto err_unlock_queue;
}
/* Will put all the packets in the new SW queue */
ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
- spin_unlock_bh(&local->mdev->queue_lock);
+ spin_unlock_bh(&sta->lock);
/* send an addBA request */
sta->ampdu_mlme.dialog_token_allocator++;
@@ -674,25 +663,27 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+
ieee80211_send_addba_request(sta->sdata->dev, ra, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
0x40, 5000);
-
/* activate the timer for the recipient's addBA response */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
jiffies + ADDBA_RESP_INTERVAL;
add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
- goto start_ba_exit;
+#endif
+ goto exit;
-start_ba_err:
+err_unlock_queue:
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&local->mdev->queue_lock);
ret = -EBUSY;
-start_ba_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+err_unlock_sta:
+ spin_unlock_bh(&sta->lock);
+exit:
rcu_read_unlock();
return ret;
}
@@ -720,7 +711,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
/* check if the TID is in aggregation */
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (*state != HT_AGG_STATE_OPERATIONAL) {
ret = -ENOENT;
@@ -750,7 +741,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw,
}
stop_BA_exit:
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return ret;
}
@@ -764,8 +755,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
DECLARE_MAC_BUF(mac);
if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
tid, STA_TID_NUM);
+#endif
return;
}
@@ -773,18 +766,22 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta = sta_info_get(local, ra);
if (!sta) {
rcu_read_unlock();
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
+#endif
return;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_lock_bh(&sta->lock);
if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
*state);
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#endif
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
return;
}
@@ -794,10 +791,12 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
*state |= HT_ADDBA_DRV_READY_MSK;
if (*state == HT_AGG_STATE_OPERATIONAL) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
+#endif
ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
}
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb);
@@ -811,8 +810,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
DECLARE_MAC_BUF(mac);
if (tid >= STA_TID_NUM) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n",
tid, STA_TID_NUM);
+#endif
return;
}
@@ -824,17 +825,23 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
rcu_read_lock();
sta = sta_info_get(local, ra);
if (!sta) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Could not find station: %s\n",
print_mac(mac, ra));
+#endif
rcu_read_unlock();
return;
}
state = &sta->ampdu_mlme.tid_state_tx[tid];
- spin_lock_bh(&sta->ampdu_mlme.ampdu_tx);
+ /* NOTE: no need to use sta->lock in this state check, as
+ * ieee80211_stop_tx_ba_session will let only one stop call to
+ * pass through per sta/tid
+ */
if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n");
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+#endif
rcu_read_unlock();
return;
}
@@ -845,23 +852,20 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
agg_queue = sta->tid_to_tx_q[tid];
- /* avoid ordering issues: we are the only one that can modify
- * the content of the qdiscs */
- spin_lock_bh(&local->mdev->queue_lock);
- /* remove the queue for this aggregation */
ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
- spin_unlock_bh(&local->mdev->queue_lock);
- /* we just requeued the all the frames that were in the removed
- * queue, and since we might miss a softirq we do netif_schedule.
- * ieee80211_wake_queue is not used here as this queue is not
- * necessarily stopped */
- netif_schedule(local->mdev);
+ /* We just requeued the all the frames that were in the
+ * removed queue, and since we might miss a softirq we do
+ * netif_schedule_queue. ieee80211_wake_queue is not used
+ * here as this queue is not necessarily stopped
+ */
+ netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue));
+ spin_lock_bh(&sta->lock);
*state = HT_AGG_STATE_IDLE;
sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
- spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx);
+ spin_unlock_bh(&sta->lock);
rcu_read_unlock();
}
@@ -875,9 +879,11 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
struct sk_buff *skb = dev_alloc_skb(0);
if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_WARNING "%s: Not enough memory, "
"dropping start BA session", skb->dev->name);
+#endif
return;
}
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -898,9 +904,11 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw,
struct sk_buff *skb = dev_alloc_skb(0);
if (unlikely(!skb)) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
if (net_ratelimit())
printk(KERN_WARNING "%s: Not enough memory, "
"dropping stop BA session", skb->dev->name);
+#endif
return;
}
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -951,7 +959,6 @@ static const struct header_ops ieee80211_header_ops = {
.cache_update = eth_header_cache_update,
};
-/* Must not be called for mdev */
void ieee80211_if_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -961,67 +968,52 @@ void ieee80211_if_setup(struct net_device *dev)
dev->change_mtu = ieee80211_change_mtu;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
- dev->destructor = ieee80211_if_free;
+ dev->destructor = free_netdev;
}
/* everything else */
-static int __ieee80211_if_config(struct net_device *dev,
- struct sk_buff *beacon,
- struct ieee80211_tx_control *control)
+int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_if_conf conf;
- if (!local->ops->config_interface || !netif_running(dev))
+ if (WARN_ON(!netif_running(sdata->dev)))
+ return 0;
+
+ if (!local->ops->config_interface)
return 0;
memset(&conf, 0, sizeof(conf));
- conf.type = sdata->vif.type;
+ conf.changed = changed;
+
if (sdata->vif.type == IEEE80211_IF_TYPE_STA ||
sdata->vif.type == IEEE80211_IF_TYPE_IBSS) {
conf.bssid = sdata->u.sta.bssid;
conf.ssid = sdata->u.sta.ssid;
conf.ssid_len = sdata->u.sta.ssid_len;
- } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
- conf.beacon = beacon;
- conf.beacon_control = control;
- ieee80211_start_mesh(dev);
} else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) {
+ conf.bssid = sdata->dev->dev_addr;
conf.ssid = sdata->u.ap.ssid;
conf.ssid_len = sdata->u.ap.ssid_len;
- conf.beacon = beacon;
- conf.beacon_control = control;
+ } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ u8 zero[ETH_ALEN] = { 0 };
+ conf.bssid = zero;
+ conf.ssid = zero;
+ conf.ssid_len = 0;
+ } else {
+ WARN_ON(1);
+ return -EINVAL;
}
- return local->ops->config_interface(local_to_hw(local),
- &sdata->vif, &conf);
-}
-int ieee80211_if_config(struct net_device *dev)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT &&
- (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return ieee80211_if_config_beacon(dev);
- return __ieee80211_if_config(dev, NULL, NULL);
-}
+ if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID)))
+ return -EINVAL;
-int ieee80211_if_config_beacon(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_tx_control control;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct sk_buff *skb;
+ if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID)))
+ return -EINVAL;
- if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE))
- return 0;
- skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif,
- &control);
- if (!skb)
- return -ENOMEM;
- return __ieee80211_if_config(dev, skb, &control);
+ return local->ops->config_interface(local_to_hw(local),
+ &sdata->vif, &conf);
}
int ieee80211_hw_config(struct ieee80211_local *local)
@@ -1068,56 +1060,84 @@ u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht,
struct ieee80211_supported_band *sband;
struct ieee80211_ht_info ht_conf;
struct ieee80211_ht_bss_info ht_bss_conf;
- int i;
u32 changed = 0;
+ int i;
+ u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS;
+ u8 tx_mcs_set_cap;
sband = local->hw.wiphy->bands[conf->channel->band];
+ memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
+ memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
+
/* HT is not supported */
if (!sband->ht_info.ht_supported) {
conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- return 0;
+ goto out;
}
- memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info));
- memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info));
-
- if (enable_ht) {
- if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ /* disable HT */
+ if (!enable_ht) {
+ if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
changed |= BSS_CHANGED_HT;
+ conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
+ conf->ht_conf.ht_supported = 0;
+ goto out;
+ }
- conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
- ht_conf.ht_supported = 1;
- ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
- ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
- ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE))
+ changed |= BSS_CHANGED_HT;
- for (i = 0; i < SUPP_MCS_SET_LEN; i++)
- ht_conf.supp_mcs_set[i] =
- sband->ht_info.supp_mcs_set[i] &
- req_ht_cap->supp_mcs_set[i];
+ conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE;
+ ht_conf.ht_supported = 1;
- ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
- ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
- ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
+ ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap;
+ ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS);
+ ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS;
+ ht_bss_conf.primary_channel = req_bss_cap->primary_channel;
+ ht_bss_conf.bss_cap = req_bss_cap->bss_cap;
+ ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode;
- ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
- ht_conf.ampdu_density = req_ht_cap->ampdu_density;
+ ht_conf.ampdu_factor = req_ht_cap->ampdu_factor;
+ ht_conf.ampdu_density = req_ht_cap->ampdu_density;
- /* if bss configuration changed store the new one */
- if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
- memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
- changed |= BSS_CHANGED_HT;
- memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
- memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
- }
- } else {
- if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)
- changed |= BSS_CHANGED_HT;
- conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE;
- }
+ /* Bits 96-100 */
+ tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12];
+
+ /* configure suppoerted Tx MCS according to requested MCS
+ * (based in most cases on Rx capabilities of peer) and self
+ * Tx MCS capabilities (as defined by low level driver HW
+ * Tx capabilities) */
+ if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED))
+ goto check_changed;
+ /* Counting from 0 therfore + 1 */
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF)
+ max_tx_streams = ((tx_mcs_set_cap &
+ IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1;
+
+ for (i = 0; i < max_tx_streams; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+ if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM)
+ for (i = IEEE80211_SUPP_MCS_SET_UEQM;
+ i < IEEE80211_SUPP_MCS_SET_LEN; i++)
+ ht_conf.supp_mcs_set[i] =
+ sband->ht_info.supp_mcs_set[i] &
+ req_ht_cap->supp_mcs_set[i];
+
+check_changed:
+ /* if bss configuration changed store the new one */
+ if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) ||
+ memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) {
+ changed |= BSS_CHANGED_HT;
+ memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf));
+ memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf));
+ }
+out:
return changed;
}
@@ -1136,50 +1156,30 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
changed);
}
-void ieee80211_reset_erp_info(struct net_device *dev)
+u32 ieee80211_reset_erp_info(struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata->bss_conf.use_cts_prot = 0;
sdata->bss_conf.use_short_preamble = 0;
- ieee80211_bss_info_change_notify(sdata,
- BSS_CHANGED_ERP_CTS_PROT |
- BSS_CHANGED_ERP_PREAMBLE);
+ return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE;
}
void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_tx_status *saved;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int tmp;
skb->dev = local->mdev;
- saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC);
- if (unlikely(!saved)) {
- if (net_ratelimit())
- printk(KERN_WARNING "%s: Not enough memory, "
- "dropping tx status", skb->dev->name);
- /* should be dev_kfree_skb_irq, but due to this function being
- * named _irqsafe instead of just _irq we can't be sure that
- * people won't call it from non-irq contexts */
- dev_kfree_skb_any(skb);
- return;
- }
- memcpy(saved, status, sizeof(struct ieee80211_tx_status));
- /* copy pointer to saved status into skb->cb for use by tasklet */
- memcpy(skb->cb, &saved, sizeof(saved));
-
skb->pkt_type = IEEE80211_TX_STATUS_MSG;
- skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ?
+ skb_queue_tail(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS ?
&local->skb_queue : &local->skb_queue_unreliable, skb);
tmp = skb_queue_len(&local->skb_queue) +
skb_queue_len(&local->skb_queue_unreliable);
while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT &&
(skb = skb_dequeue(&local->skb_queue_unreliable))) {
- memcpy(&saved, skb->cb, sizeof(saved));
- kfree(saved);
dev_kfree_skb_irq(skb);
tmp--;
I802_DEBUG_INC(local->tx_status_drop);
@@ -1193,7 +1193,6 @@ static void ieee80211_tasklet_handler(unsigned long data)
struct ieee80211_local *local = (struct ieee80211_local *) data;
struct sk_buff *skb;
struct ieee80211_rx_status rx_status;
- struct ieee80211_tx_status *tx_status;
struct ieee80211_ra_tid *ra_tid;
while ((skb = skb_dequeue(&local->skb_queue)) ||
@@ -1208,12 +1207,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
__ieee80211_rx(local_to_hw(local), skb, &rx_status);
break;
case IEEE80211_TX_STATUS_MSG:
- /* get pointer to saved status out of skb->cb */
- memcpy(&tx_status, skb->cb, sizeof(tx_status));
skb->pkt_type = 0;
- ieee80211_tx_status(local_to_hw(local),
- skb, tx_status);
- kfree(tx_status);
+ ieee80211_tx_status(local_to_hw(local), skb);
break;
case IEEE80211_DELBA_MSG:
ra_tid = (struct ieee80211_ra_tid *) &skb->cb;
@@ -1227,9 +1222,8 @@ static void ieee80211_tasklet_handler(unsigned long data)
ra_tid->ra, ra_tid->tid);
dev_kfree_skb(skb);
break ;
- default: /* should never get here! */
- printk(KERN_ERR "%s: Unknown message type (%d)\n",
- wiphy_name(local->hw.wiphy), skb->pkt_type);
+ default:
+ WARN_ON(1);
dev_kfree_skb(skb);
break;
}
@@ -1242,24 +1236,15 @@ static void ieee80211_tasklet_handler(unsigned long data)
* Also, tx_packet_data in cb is restored from tx_control. */
static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
struct ieee80211_key *key,
- struct sk_buff *skb,
- struct ieee80211_tx_control *control)
+ struct sk_buff *skb)
{
int hdrlen, iv_len, mic_len;
- struct ieee80211_tx_packet_data *pkt_data;
-
- pkt_data = (struct ieee80211_tx_packet_data *)skb->cb;
- pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex;
- pkt_data->flags = 0;
- if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS)
- pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS;
- if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)
- pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT;
- if (control->flags & IEEE80211_TXCTL_REQUEUE)
- pkt_data->flags |= IEEE80211_TXPD_REQUEUE;
- if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME)
- pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME;
- pkt_data->queue = control->queue;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+ info->flags &= IEEE80211_TX_CTL_REQ_TX_STATUS |
+ IEEE80211_TX_CTL_DO_NOT_ENCRYPT |
+ IEEE80211_TX_CTL_REQUEUE |
+ IEEE80211_TX_CTL_EAPOL_FRAME;
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
@@ -1306,9 +1291,10 @@ no_key:
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sta_info *sta,
- struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+ struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
sta->tx_filtered_count++;
/*
@@ -1316,7 +1302,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* packet. If the STA went to power save mode, this will happen
* when it wakes up for the next time.
*/
- sta->flags |= WLAN_STA_CLEAR_PS_FILT;
+ set_sta_flags(sta, WLAN_STA_CLEAR_PS_FILT);
/*
* This code races in the following way:
@@ -1348,84 +1334,89 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
* can be unknown, for example with different interrupt status
* bits.
*/
- if (sta->flags & WLAN_STA_PS &&
+ if (test_sta_flags(sta, WLAN_STA_PS) &&
skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) {
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ ieee80211_remove_tx_extra(local, sta->key, skb);
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!(sta->flags & WLAN_STA_PS) &&
- !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) {
+ if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ !(info->flags & IEEE80211_TX_CTL_REQUEUE)) {
/* Software retry the packet once */
- status->control.flags |= IEEE80211_TXCTL_REQUEUE;
- ieee80211_remove_tx_extra(local, sta->key, skb,
- &status->control);
+ info->flags |= IEEE80211_TX_CTL_REQUEUE;
+ ieee80211_remove_tx_extra(local, sta->key, skb);
dev_queue_xmit(skb);
return;
}
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped TX filtered frame, "
"queue_len=%d PS=%d @%lu\n",
wiphy_name(local->hw.wiphy),
skb_queue_len(&sta->tx_filtered),
- !!(sta->flags & WLAN_STA_PS), jiffies);
+ !!test_sta_flags(sta, WLAN_STA_PS), jiffies);
+#endif
dev_kfree_skb(skb);
}
-void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct ieee80211_tx_status *status)
+void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct sk_buff *skb2;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_local *local = hw_to_local(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u16 frag, type;
+ __le16 fc;
struct ieee80211_tx_status_rtap_hdr *rthdr;
struct ieee80211_sub_if_data *sdata;
struct net_device *prev_dev = NULL;
-
- if (!status) {
- printk(KERN_ERR
- "%s: ieee80211_tx_status called with NULL status\n",
- wiphy_name(local->hw.wiphy));
- dev_kfree_skb(skb);
- return;
- }
+ struct sta_info *sta;
rcu_read_lock();
- if (status->excessive_retries) {
- struct sta_info *sta;
+ if (info->status.excessive_retries) {
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- if (sta->flags & WLAN_STA_PS) {
+ if (test_sta_flags(sta, WLAN_STA_PS)) {
/*
* The STA is in power save mode, so assume
* that this TX packet failed because of that.
*/
- status->excessive_retries = 0;
- status->flags |= IEEE80211_TX_STATUS_TX_FILTERED;
- ieee80211_handle_filtered_frame(local, sta,
- skb, status);
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
}
}
- if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) {
- struct sta_info *sta;
+ fc = hdr->frame_control;
+
+ if ((info->flags & IEEE80211_TX_STAT_AMPDU_NO_BACK) &&
+ (ieee80211_is_data_qos(fc))) {
+ u16 tid, ssn;
+ u8 *qc;
sta = sta_info_get(local, hdr->addr1);
if (sta) {
- ieee80211_handle_filtered_frame(local, sta, skb,
- status);
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & 0xf;
+ ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
+ & IEEE80211_SCTL_SEQ);
+ ieee80211_send_bar(sta->sdata->dev, hdr->addr1,
+ tid, ssn);
+ }
+ }
+
+ if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+ sta = sta_info_get(local, hdr->addr1);
+ if (sta) {
+ ieee80211_handle_filtered_frame(local, sta, skb);
rcu_read_unlock();
return;
}
} else
- rate_control_tx_status(local->mdev, skb, status);
+ rate_control_tx_status(local->mdev, skb);
rcu_read_unlock();
@@ -1439,14 +1430,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE;
- if (status->flags & IEEE80211_TX_STATUS_ACK) {
+ if (info->flags & IEEE80211_TX_STAT_ACK) {
if (frag == 0) {
local->dot11TransmittedFrameCount++;
if (is_multicast_ether_addr(hdr->addr1))
local->dot11MulticastTransmittedFrameCount++;
- if (status->retry_count > 0)
+ if (info->status.retry_count > 0)
local->dot11RetryCount++;
- if (status->retry_count > 1)
+ if (info->status.retry_count > 1)
local->dot11MultipleRetryCount++;
}
@@ -1483,7 +1474,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
return;
}
- rthdr = (struct ieee80211_tx_status_rtap_hdr*)
+ rthdr = (struct ieee80211_tx_status_rtap_hdr *)
skb_push(skb, sizeof(*rthdr));
memset(rthdr, 0, sizeof(*rthdr));
@@ -1492,17 +1483,17 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb,
cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) |
(1 << IEEE80211_RADIOTAP_DATA_RETRIES));
- if (!(status->flags & IEEE80211_TX_STATUS_ACK) &&
+ if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
!is_multicast_ether_addr(hdr->addr1))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL);
- if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) &&
- (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT))
+ if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) &&
+ (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT))
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS);
- else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS)
+ else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)
rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS);
- rthdr->data_retries = status->retry_count;
+ rthdr->data_retries = info->status.retry_count;
/* XXX: is this sufficient for BPF? */
skb_set_mac_header(skb, 0);
@@ -1628,7 +1619,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
int result;
enum ieee80211_band band;
struct net_device *mdev;
- struct ieee80211_sub_if_data *sdata;
+ struct wireless_dev *mwdev;
/*
* generic code guarantees at least one band,
@@ -1652,19 +1643,30 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (result < 0)
return result;
- /* for now, mdev needs sub_if_data :/ */
- mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data),
- "wmaster%d", ether_setup);
+ /*
+ * We use the number of queues for feature tests (QoS, HT) internally
+ * so restrict them appropriately.
+ */
+ if (hw->queues > IEEE80211_MAX_QUEUES)
+ hw->queues = IEEE80211_MAX_QUEUES;
+ if (hw->ampdu_queues > IEEE80211_MAX_AMPDU_QUEUES)
+ hw->ampdu_queues = IEEE80211_MAX_AMPDU_QUEUES;
+ if (hw->queues < 4)
+ hw->ampdu_queues = 0;
+
+ mdev = alloc_netdev_mq(sizeof(struct wireless_dev),
+ "wmaster%d", ether_setup,
+ ieee80211_num_queues(hw));
if (!mdev)
goto fail_mdev_alloc;
- sdata = IEEE80211_DEV_TO_SUB_IF(mdev);
- mdev->ieee80211_ptr = &sdata->wdev;
- sdata->wdev.wiphy = local->hw.wiphy;
+ mwdev = netdev_priv(mdev);
+ mdev->ieee80211_ptr = mwdev;
+ mwdev->wiphy = local->hw.wiphy;
local->mdev = mdev;
- ieee80211_rx_bss_list_init(mdev);
+ ieee80211_rx_bss_list_init(local);
mdev->hard_start_xmit = ieee80211_master_start_xmit;
mdev->open = ieee80211_master_open;
@@ -1673,18 +1675,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
mdev->header_ops = &ieee80211_header_ops;
mdev->set_multicast_list = ieee80211_master_set_multicast_list;
- sdata->vif.type = IEEE80211_IF_TYPE_AP;
- sdata->dev = mdev;
- sdata->local = local;
- sdata->u.ap.force_unicast_rateidx = -1;
- sdata->u.ap.max_ratectrl_rateidx = -1;
- ieee80211_if_sdata_init(sdata);
-
- /* no RCU needed since we're still during init phase */
- list_add_tail(&sdata->list, &local->interfaces);
-
name = wiphy_dev(local->hw.wiphy)->driver->name;
- local->hw.workqueue = create_singlethread_workqueue(name);
+ local->hw.workqueue = create_freezeable_workqueue(name);
if (!local->hw.workqueue) {
result = -ENOMEM;
goto fail_workqueue;
@@ -1700,15 +1692,16 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
debugfs_hw_add(local);
- local->hw.conf.beacon_int = 1000;
+ if (local->hw.conf.beacon_int < 10)
+ local->hw.conf.beacon_int = 100;
- local->wstats_flags |= local->hw.max_rssi ?
- IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID;
- local->wstats_flags |= local->hw.max_signal ?
+ local->wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+ IEEE80211_HW_SIGNAL_DB |
+ IEEE80211_HW_SIGNAL_DBM) ?
IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
- local->wstats_flags |= local->hw.max_noise ?
+ local->wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
- if (local->hw.max_rssi < 0 || local->hw.max_noise < 0)
+ if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
local->wstats_flags |= IW_QUAL_DBM;
result = sta_info_start(local);
@@ -1727,9 +1720,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (result < 0)
goto fail_dev;
- ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
- ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP);
-
result = ieee80211_init_rate_ctrl_alg(local,
hw->rate_control_algorithm);
if (result < 0) {
@@ -1746,16 +1736,15 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
goto fail_wep;
}
- ieee80211_install_qdisc(local->mdev);
+ local->mdev->select_queue = ieee80211_select_queue;
/* add one default STA interface */
- result = ieee80211_if_add(local->mdev, "wlan%d", NULL,
+ result = ieee80211_if_add(local, "wlan%d", NULL,
IEEE80211_IF_TYPE_STA, NULL);
if (result)
printk(KERN_WARNING "%s: Failed to add default virtual iface\n",
wiphy_name(local->hw.wiphy));
- local->reg_state = IEEE80211_DEV_REGISTERED;
rtnl_unlock();
ieee80211_led_init(local);
@@ -1765,7 +1754,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
fail_wep:
rate_control_deinitialize(local);
fail_rate:
- ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
unregister_netdevice(local->mdev);
local->mdev = NULL;
fail_dev:
@@ -1775,10 +1763,8 @@ fail_sta_info:
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- if (local->mdev != NULL) {
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
- }
+ if (local->mdev)
+ free_netdev(local->mdev);
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
return result;
@@ -1788,42 +1774,27 @@ EXPORT_SYMBOL(ieee80211_register_hw);
void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
- struct ieee80211_sub_if_data *sdata, *tmp;
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
rtnl_lock();
- BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED);
-
- local->reg_state = IEEE80211_DEV_UNREGISTERED;
-
/*
* At this point, interface list manipulations are fine
* because the driver cannot be handing us frames any
* more and the tasklet is killed.
*/
- /*
- * First, we remove all non-master interfaces. Do this because they
- * may have bss pointer dependency on the master, and when we free
- * the master these would be freed as well, breaking our list
- * iteration completely.
- */
- list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
- if (sdata->dev == local->mdev)
- continue;
- list_del(&sdata->list);
- __ieee80211_if_del(local, sdata);
- }
+ /* First, we remove all virtual interfaces. */
+ ieee80211_remove_interfaces(local);
/* then, finally, remove the master interface */
- __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev));
+ unregister_netdevice(local->mdev);
rtnl_unlock();
- ieee80211_rx_bss_list_deinit(local->mdev);
+ ieee80211_rx_bss_list_deinit(local);
ieee80211_clear_tx_pending(local);
sta_info_stop(local);
rate_control_deinitialize(local);
@@ -1840,8 +1811,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
wiphy_unregister(local->hw.wiphy);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
+ free_netdev(local->mdev);
}
EXPORT_SYMBOL(ieee80211_unregister_hw);
@@ -1858,27 +1828,17 @@ static int __init ieee80211_init(void)
struct sk_buff *skb;
int ret;
- BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb));
+ BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb));
+ BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) +
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb));
ret = rc80211_pid_init();
if (ret)
- goto out;
-
- ret = ieee80211_wme_register();
- if (ret) {
- printk(KERN_DEBUG "ieee80211_init: failed to "
- "initialize WME (err=%d)\n", ret);
- goto out_cleanup_pid;
- }
+ return ret;
ieee80211_debugfs_netdev_init();
return 0;
-
- out_cleanup_pid:
- rc80211_pid_exit();
- out:
- return ret;
}
static void __exit ieee80211_exit(void)
@@ -1894,7 +1854,6 @@ static void __exit ieee80211_exit(void)
if (mesh_allocated)
ieee80211s_stop();
- ieee80211_wme_unregister();
ieee80211_debugfs_netdev_exit();
}
OpenPOWER on IntegriCloud