summaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/Kconfig5
-rw-r--r--net/mac80211/agg-tx.c6
-rw-r--r--net/mac80211/cfg.c69
-rw-r--r--net/mac80211/driver-ops.h7
-rw-r--r--net/mac80211/ieee80211_i.h5
-rw-r--r--net/mac80211/iface.c4
-rw-r--r--net/mac80211/main.c81
-rw-r--r--net/mac80211/mlme.c57
-rw-r--r--net/mac80211/rc80211_minstrel.c2
-rw-r--r--net/mac80211/rx.c27
-rw-r--r--net/mac80211/sta_info.c9
-rw-r--r--net/mac80211/tx.c21
-rw-r--r--net/mac80211/util.c56
-rw-r--r--net/mac80211/wext.c80
-rw-r--r--net/mac80211/wme.c2
15 files changed, 214 insertions, 217 deletions
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 9cbf545..ba2643a 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -1,16 +1,19 @@
config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
+ depends on CFG80211
select CRYPTO
select CRYPTO_ECB
select CRYPTO_ARC4
select CRYPTO_AES
select CRC32
select WIRELESS_EXT
- select CFG80211
---help---
This option enables the hardware independent IEEE 802.11
networking stack.
+comment "CFG80211 needs to be enabled for MAC80211"
+ depends on CFG80211=n
+
config MAC80211_DEFAULT_PS
bool "enable powersave by default"
depends on MAC80211
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 43d00ff..9e5762a 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -132,6 +132,9 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
state = &sta->ampdu_mlme.tid_state_tx[tid];
+ if (*state == HT_AGG_STATE_OPERATIONAL)
+ sta->ampdu_mlme.addba_req_num[tid] = 0;
+
*state = HT_AGG_STATE_REQ_STOP_BA_MSK |
(initiator << HT_AGG_STATE_INITIATOR_SHIFT);
@@ -337,6 +340,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
0x40, 5000);
+ sta->ampdu_mlme.addba_req_num[tid]++;
/* activate the timer for the recipient's addBA response */
sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires =
jiffies + ADDBA_RESP_INTERVAL;
@@ -606,7 +610,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
*state = HT_AGG_STATE_IDLE;
/* from now on packets are no longer put onto sta->pending */
- sta->ampdu_mlme.addba_req_num[tid] = 0;
kfree(sta->ampdu_mlme.tid_tx[tid]);
sta->ampdu_mlme.tid_tx[tid] = NULL;
@@ -689,7 +692,6 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
sta->ampdu_mlme.addba_req_num[tid] = 0;
} else {
- sta->ampdu_mlme.addba_req_num[tid]++;
___ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
}
spin_unlock_bh(&sta->lock);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 77e9ff5..3f47276 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -664,18 +664,19 @@ static void sta_apply_parameters(struct ieee80211_local *local,
spin_unlock_bh(&sta->lock);
/*
+ * cfg80211 validates this (1-2007) and allows setting the AID
+ * only when creating a new station entry
+ */
+ if (params->aid)
+ sta->sta.aid = params->aid;
+
+ /*
* FIXME: updating the following information is racy when this
* function is called from ieee80211_change_station().
* However, all this information should be static so
* maybe we should just reject attemps to change it.
*/
- if (params->aid) {
- sta->sta.aid = params->aid;
- if (sta->sta.aid > IEEE80211_MAX_AID)
- sta->sta.aid = 0; /* XXX: should this be an error? */
- }
-
if (params->listen_interval >= 0)
sta->listen_interval = params->listen_interval;
@@ -1121,8 +1122,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
p.txop = params->txop;
if (drv_conf_tx(local, params->queue, &p)) {
printk(KERN_DEBUG "%s: failed to set TX queue "
- "parameters for queue %d\n", local->mdev->name,
- params->queue);
+ "parameters for queue %d\n",
+ wiphy_name(local->hw.wiphy), params->queue);
return -EINVAL;
}
@@ -1255,7 +1256,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
- if (ret)
+ if (ret && ret != -EALREADY)
return ret;
if (req->use_mfp) {
@@ -1333,6 +1334,53 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
return 0;
}
+static int ieee80211_set_tx_power(struct wiphy *wiphy,
+ enum tx_power_setting type, int dbm)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+ struct ieee80211_channel *chan = local->hw.conf.channel;
+ u32 changes = 0;
+
+ switch (type) {
+ case TX_POWER_AUTOMATIC:
+ local->user_power_level = -1;
+ break;
+ case TX_POWER_LIMITED:
+ if (dbm < 0)
+ return -EINVAL;
+ local->user_power_level = dbm;
+ break;
+ case TX_POWER_FIXED:
+ if (dbm < 0)
+ return -EINVAL;
+ /* TODO: move to cfg80211 when it knows the channel */
+ if (dbm > chan->max_power)
+ return -EINVAL;
+ local->user_power_level = dbm;
+ break;
+ }
+
+ ieee80211_hw_config(local, changes);
+
+ return 0;
+}
+
+static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ *dbm = local->hw.conf.power_level;
+
+ return 0;
+}
+
+static void ieee80211_rfkill_poll(struct wiphy *wiphy)
+{
+ struct ieee80211_local *local = wiphy_priv(wiphy);
+
+ drv_rfkill_poll(local);
+}
+
struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface,
@@ -1372,4 +1420,7 @@ struct cfg80211_ops mac80211_config_ops = {
.join_ibss = ieee80211_join_ibss,
.leave_ibss = ieee80211_leave_ibss,
.set_wiphy_params = ieee80211_set_wiphy_params,
+ .set_tx_power = ieee80211_set_tx_power,
+ .get_tx_power = ieee80211_get_tx_power,
+ .rfkill_poll = ieee80211_rfkill_poll,
};
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 3912b53..b13446a 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -181,4 +181,11 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
sta, tid, ssn);
return -EOPNOTSUPP;
}
+
+
+static inline void drv_rfkill_poll(struct ieee80211_local *local)
+{
+ if (local->ops->rfkill_poll)
+ local->ops->rfkill_poll(&local->hw);
+}
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c088c46..4dbc289 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -589,6 +589,7 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_PENDING,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
};
struct ieee80211_master_priv {
@@ -1121,6 +1122,10 @@ void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason);
+void ieee80211_add_pending_skb(struct ieee80211_local *local,
+ struct sk_buff *skb);
+int ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8c9f1c7..b7c8a44 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -170,7 +170,7 @@ static int ieee80211_open(struct net_device *dev)
goto err_del_bss;
/* we're brought up, everything changes */
hw_reconf_flags = ~0;
- ieee80211_led_radio(local, local->hw.conf.radio_enabled);
+ ieee80211_led_radio(local, true);
}
/*
@@ -560,7 +560,7 @@ static int ieee80211_stop(struct net_device *dev)
drv_stop(local);
- ieee80211_led_radio(local, 0);
+ ieee80211_led_radio(local, false);
flush_workqueue(local->hw.workqueue);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6b7e92e..092a017 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -289,16 +289,8 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
drv_bss_info_changed(local, &sdata->vif,
&sdata->vif.bss_conf, changed);
- /*
- * DEPRECATED
- *
- * ~changed is just there to not do this at resume time
- */
- if (changed & BSS_CHANGED_BEACON_INT && ~changed) {
- local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
- ieee80211_hw_config(local,
- _IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
- }
+ /* DEPRECATED */
+ local->hw.conf.beacon_int = sdata->vif.bss_conf.beacon_int;
}
u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata)
@@ -377,60 +369,12 @@ static void ieee80211_tasklet_handler(unsigned long data)
}
}
-/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to
- * make a prepared TX frame (one that has been given to hw) to look like brand
- * new IEEE 802.11 frame that is ready to go through TX processing again.
- */
-static void ieee80211_remove_tx_extra(struct ieee80211_local *local,
- struct ieee80211_key *key,
- struct sk_buff *skb)
-{
- unsigned int hdrlen, iv_len, mic_len;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
-
- if (!key)
- goto no_key;
-
- switch (key->conf.alg) {
- case ALG_WEP:
- iv_len = WEP_IV_LEN;
- mic_len = WEP_ICV_LEN;
- break;
- case ALG_TKIP:
- iv_len = TKIP_IV_LEN;
- mic_len = TKIP_ICV_LEN;
- break;
- case ALG_CCMP:
- iv_len = CCMP_HDR_LEN;
- mic_len = CCMP_MIC_LEN;
- break;
- default:
- goto no_key;
- }
-
- if (skb->len >= hdrlen + mic_len &&
- !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
- skb_trim(skb, skb->len - mic_len);
- if (skb->len >= hdrlen + iv_len) {
- memmove(skb->data + iv_len, skb->data, hdrlen);
- hdr = (struct ieee80211_hdr *)skb_pull(skb, iv_len);
- }
-
-no_key:
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
- memmove(skb->data + IEEE80211_QOS_CTL_LEN, skb->data,
- hdrlen - IEEE80211_QOS_CTL_LEN);
- skb_pull(skb, IEEE80211_QOS_CTL_LEN);
- }
-}
-
static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
struct sta_info *sta,
struct sk_buff *skb)
{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
sta->tx_filtered_count++;
/*
@@ -472,16 +416,15 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
*/
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);
skb_queue_tail(&sta->tx_filtered, skb);
return;
}
- if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) {
+ if (!test_sta_flags(sta, WLAN_STA_PS) &&
+ !(info->flags & IEEE80211_TX_INTFL_RETRIED)) {
/* Software retry the packet once */
- skb->requeue = 1;
- ieee80211_remove_tx_extra(local, sta->key, skb);
- dev_queue_xmit(skb);
+ info->flags |= IEEE80211_TX_INTFL_RETRIED;
+ ieee80211_add_pending_skb(local, skb);
return;
}
@@ -735,9 +678,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
* +-------------------------+
*
*/
- priv_size = ((sizeof(struct ieee80211_local) +
- NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) +
- priv_data_len;
+ priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
wiphy = wiphy_new(&mac80211_config_ops, priv_size);
@@ -754,9 +695,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
local->hw.wiphy = wiphy;
- local->hw.priv = (char *)local +
- ((sizeof(struct ieee80211_local) +
- NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
+ local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN);
BUG_ON(!ops->tx);
BUG_ON(!ops->start);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 509469c..d779c57 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -621,9 +621,6 @@ static void ieee80211_change_ps(struct ieee80211_local *local)
struct ieee80211_conf *conf = &local->hw.conf;
if (local->ps_sdata) {
- if (!(local->ps_sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
- return;
-
ieee80211_enable_ps(local, local->ps_sdata);
} else if (conf->flags & IEEE80211_CONF_PS) {
conf->flags &= ~IEEE80211_CONF_PS;
@@ -653,7 +650,9 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
count++;
}
- if (count == 1 && found->u.mgd.powersave) {
+ if (count == 1 && found->u.mgd.powersave &&
+ (found->u.mgd.flags & IEEE80211_STA_ASSOCIATED) &&
+ !(found->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL)) {
s32 beaconint_us;
if (latency < 0)
@@ -793,13 +792,13 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
"cWmin=%d cWmax=%d txop=%d\n",
- local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
- params.cw_max, params.txop);
+ wiphy_name(local->hw.wiphy), queue, aci, acm,
+ params.aifs, params.cw_min, params.cw_max, params.txop);
#endif
if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
printk(KERN_DEBUG "%s: failed to set TX queue "
- "parameters for queue %d\n", local->mdev->name,
- queue);
+ "parameters for queue %d\n",
+ wiphy_name(local->hw.wiphy), queue);
}
}
@@ -1322,6 +1321,11 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
#endif
ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+
+ mutex_lock(&sdata->local->iflist_mtx);
+ ieee80211_recalc_ps(sdata->local, -1);
+ mutex_unlock(&sdata->local->iflist_mtx);
+
ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
ifmgd->ssid_len, NULL, 0);
@@ -1342,6 +1346,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
+ unsigned long last_rx;
bool disassoc = false;
/* TODO: start monitoring current AP signal quality and number of
@@ -1358,17 +1363,21 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
sdata->dev->name, ifmgd->bssid);
disassoc = true;
- goto unlock;
+ rcu_read_unlock();
+ goto out;
}
+ last_rx = sta->last_rx;
+ rcu_read_unlock();
+
if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
- time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) {
+ time_after(jiffies, last_rx + IEEE80211_PROBE_WAIT)) {
printk(KERN_DEBUG "%s: no probe response from AP %pM "
"- disassociating\n",
sdata->dev->name, ifmgd->bssid);
disassoc = true;
ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
- goto unlock;
+ goto out;
}
/*
@@ -1387,26 +1396,29 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
}
#endif
ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
ifmgd->ssid_len, NULL, 0);
mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
- goto unlock;
+ goto out;
}
- if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) {
+ if (time_after(jiffies, last_rx + IEEE80211_PROBE_IDLE_TIME)) {
ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
ifmgd->ssid_len, NULL, 0);
}
+ out:
if (!disassoc)
mod_timer(&ifmgd->timer,
jiffies + IEEE80211_MONITORING_INTERVAL);
-
- unlock:
- rcu_read_unlock();
-
- if (disassoc)
+ else
ieee80211_set_disassoc(sdata, true, true,
WLAN_REASON_PREV_AUTH_NOT_VALID);
}
@@ -1889,8 +1901,12 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_authenticate(sdata);
}
- if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+ if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ mutex_lock(&sdata->local->iflist_mtx);
+ ieee80211_recalc_ps(sdata->local, -1);
+ mutex_unlock(&sdata->local->iflist_mtx);
+ }
}
/*
@@ -1948,6 +1964,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
#endif
ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ mutex_lock(&local->iflist_mtx);
+ ieee80211_recalc_ps(local, -1);
+ mutex_unlock(&local->iflist_mtx);
}
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 0a11515..b218b98 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -215,7 +215,7 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi)
unsigned int sample_ndx;
sample_ndx = SAMPLE_TBL(mi, mi->sample_idx, mi->sample_column);
mi->sample_idx++;
- if (mi->sample_idx > (mi->n_rates - 2)) {
+ if ((int) mi->sample_idx > (mi->n_rates - 2)) {
mi->sample_idx = 0;
mi->sample_column++;
if (mi->sample_column >= SAMPLE_COLUMNS)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6a9b8e6..de5bba7 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -797,8 +797,7 @@ static int ap_sta_ps_end(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
- struct sk_buff *skb;
- int sent = 0;
+ int sent, buffered;
atomic_dec(&sdata->bss->num_sta_ps);
@@ -814,22 +813,16 @@ static int ap_sta_ps_end(struct sta_info *sta)
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
/* Send all buffered frames to the station */
- while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) {
- sent++;
- skb->requeue = 1;
- dev_queue_xmit(skb);
- }
- while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) {
- local->total_ps_buffered--;
- sent++;
+ sent = ieee80211_add_pending_skbs(local, &sta->tx_filtered);
+ buffered = ieee80211_add_pending_skbs(local, &sta->ps_tx_buf);
+ sent += buffered;
+ local->total_ps_buffered -= buffered;
+
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
- printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame "
- "since STA not sleeping anymore\n", sdata->dev->name,
- sta->sta.addr, sta->sta.aid);
+ printk(KERN_DEBUG "%s: STA %pM aid %d sending %d filtered/%d PS frames "
+ "since STA not sleeping anymore\n", sdata->dev->name,
+ sta->sta.addr, sta->sta.aid, sent - buffered, buffered);
#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */
- skb->requeue = 1;
- dev_queue_xmit(skb);
- }
return sent;
}
@@ -1335,7 +1328,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx)
* mac80211. That also explains the __skb_push()
* below.
*/
- align = (unsigned long)skb->data & 3;
+ align = ((unsigned long)(skb->data + sizeof(struct ethhdr))) & 3;
if (align) {
if (WARN_ON(skb_headroom(skb) < 3)) {
dev_kfree_skb(skb);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d5611d8..a360bce 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -44,6 +44,15 @@
* When the insertion fails (sta_info_insert()) returns non-zero), the
* structure will have been freed by sta_info_insert()!
*
+ * sta entries are added by mac80211 when you establish a link with a
+ * peer. This means different things for the different type of interfaces
+ * we support. For a regular station this mean we add the AP sta when we
+ * receive an assocation response from the AP. For IBSS this occurs when
+ * we receive a probe response or a beacon from target IBSS network. For
+ * WDS we add the sta for the peer imediately upon device open. When using
+ * AP mode we add stations for each respective station upon request from
+ * userspace through nl80211.
+ *
* Because there are debugfs entries for each station, and adding those
* must be able to sleep, it is also possible to "pin" a station entry,
* that means it can be removed from the hash table but not be freed.
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index a910148..364222b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -400,6 +400,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta_info_set_tim_bit(sta);
info->control.jiffies = jiffies;
+ info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
skb_queue_tail(&sta->ps_tx_buf, tx->skb);
return TX_QUEUED;
}
@@ -420,7 +421,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
* frame filtering and keeps a station blacklist on its own
* (e.g: p54), so that frames can be delivered unimpeded.
*
- * Note: It should be save to disable the filter now.
+ * Note: It should be safe to disable the filter now.
* As, it is really unlikely that we still have any pending
* frame for this station in the hw's buffers/fifos left,
* that is not rejected with a unsuccessful tx_status yet.
@@ -907,9 +908,8 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
* deal with packet injection down monitor interface
* with Radiotap Header -- only called for monitor mode interface
*/
-static ieee80211_tx_result
-__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
- struct sk_buff *skb)
+static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
+ struct sk_buff *skb)
{
/*
* this is the moment to interpret and discard the radiotap header that
@@ -960,7 +960,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
* on transmission
*/
if (skb->len < (iterator.max_length + FCS_LEN))
- return TX_DROP;
+ return false;
skb_trim(skb, skb->len - FCS_LEN);
}
@@ -982,7 +982,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
}
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
- return TX_DROP;
+ return false;
/*
* remove the radiotap header
@@ -991,7 +991,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
*/
skb_pull(skb, iterator.max_length);
- return TX_CONTINUE;
+ return true;
}
/*
@@ -1025,7 +1025,7 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
/* process and remove the injection radiotap header */
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) {
- if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP)
+ if (!__ieee80211_parse_tx_radiotap(tx, skb))
return TX_DROP;
/*
@@ -1238,7 +1238,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
bool txpending)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct sta_info *sta;
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -1270,7 +1269,6 @@ static void ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
return;
}
- sta = tx.sta;
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
@@ -1417,7 +1415,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
- local->hw.conf.dynamic_ps_timeout > 0) {
+ local->hw.conf.dynamic_ps_timeout > 0 &&
+ !local->sw_scanning && !local->hw_scanning && local->ps_sdata) {
if (local->hw.conf.flags & IEEE80211_CONF_PS) {
ieee80211_stop_queues_by_reason(&local->hw,
IEEE80211_QUEUE_STOP_REASON_PS);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 949d857..66ce96a 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -341,6 +341,52 @@ void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue)
}
EXPORT_SYMBOL(ieee80211_stop_queue);
+void ieee80211_add_pending_skb(struct ieee80211_local *local,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ unsigned long flags;
+ int queue = skb_get_queue_mapping(skb);
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ __ieee80211_stop_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_PENDING);
+ skb_queue_tail(&local->pending[queue], skb);
+ __ieee80211_wake_queue(hw, queue, IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+}
+
+int ieee80211_add_pending_skbs(struct ieee80211_local *local,
+ struct sk_buff_head *skbs)
+{
+ struct ieee80211_hw *hw = &local->hw;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int queue, ret = 0, i;
+
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ for (i = 0; i < hw->queues; i++)
+ __ieee80211_stop_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+
+ while ((skb = skb_dequeue(skbs))) {
+ ret++;
+ queue = skb_get_queue_mapping(skb);
+ skb_queue_tail(&local->pending[queue], skb);
+ }
+
+ for (i = 0; i < hw->queues; i++) {
+ if (ret)
+ __ieee80211_stop_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_PENDING);
+ __ieee80211_wake_queue(hw, i,
+ IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
+ }
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
+ return ret;
+}
+
void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
enum queue_stop_reason reason)
{
@@ -657,15 +703,15 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
switch (queue) {
case 3: /* AC_BK */
- qparam.cw_max = aCWmin;
- qparam.cw_min = aCWmax;
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 7;
break;
default: /* never happens but let's not leave undefined */
case 2: /* AC_BE */
- qparam.cw_max = aCWmin;
- qparam.cw_min = aCWmax;
+ qparam.cw_max = aCWmax;
+ qparam.cw_min = aCWmin;
qparam.txop = 0;
qparam.aifs = 3;
break;
@@ -973,7 +1019,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (local->open_count) {
res = drv_start(local);
- ieee80211_led_radio(local, hw->conf.radio_enabled);
+ ieee80211_led_radio(local, true);
}
/* add interfaces */
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index a01154e..d2d81b1 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -306,82 +306,6 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
return 0;
}
-static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- struct ieee80211_channel* chan = local->hw.conf.channel;
- bool reconf = false;
- u32 reconf_flags = 0;
- int new_power_level;
-
- if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
- return -EINVAL;
- if (data->txpower.flags & IW_TXPOW_RANGE)
- return -EINVAL;
- if (!chan)
- return -EINVAL;
-
- /* only change when not disabling */
- if (!data->txpower.disabled) {
- if (data->txpower.fixed) {
- if (data->txpower.value < 0)
- return -EINVAL;
- new_power_level = data->txpower.value;
- /*
- * Debatable, but we cannot do a fixed power
- * level above the regulatory constraint.
- * Use "iwconfig wlan0 txpower 15dBm" instead.
- */
- if (new_power_level > chan->max_power)
- return -EINVAL;
- } else {
- /*
- * Automatic power level setting, max being the value
- * passed in from userland.
- */
- if (data->txpower.value < 0)
- new_power_level = -1;
- else
- new_power_level = data->txpower.value;
- }
-
- reconf = true;
-
- /*
- * ieee80211_hw_config() will limit to the channel's
- * max power and possibly power constraint from AP.
- */
- local->user_power_level = new_power_level;
- }
-
- if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
- local->hw.conf.radio_enabled = !(data->txpower.disabled);
- reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
- ieee80211_led_radio(local, local->hw.conf.radio_enabled);
- }
-
- if (reconf || reconf_flags)
- ieee80211_hw_config(local, reconf_flags);
-
- return 0;
-}
-
-static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
- struct iw_request_info *info,
- union iwreq_data *data, char *extra)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- data->txpower.fixed = 1;
- data->txpower.disabled = !(local->hw.conf.radio_enabled);
- data->txpower.value = local->hw.conf.power_level;
- data->txpower.flags = IW_TXPOW_DBM;
-
- return 0;
-}
-
static int ieee80211_ioctl_siwpower(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *wrq,
@@ -658,8 +582,8 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
(iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
(iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
- (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */
- (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
+ (iw_handler) cfg80211_wext_siwtxpower, /* SIOCSIWTXPOW */
+ (iw_handler) cfg80211_wext_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
(iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
(iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 694343b..116a923 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -101,7 +101,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
* Now we know the 1d priority, fill in the QoS header if
* there is one (and we haven't done this before).
*/
- if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) {
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
u8 *p = ieee80211_get_qos_ctl(hdr);
u8 ack_policy = 0;
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
OpenPOWER on IntegriCloud