From: Michael Wu <[email protected]>
This switches the code from curr_rates and num_curr_rates to directly using
the mode and converts portions of the code to use pointers to rates instead
of indices to refer to rates. Two new fields are introduced in struct
ieee80211_conf which may replace the channel/frequency/channel_val/phymode
fields in the future. The rate control is now cleared only when the
operating channel is changed.
Signed-off-by: Michael Wu <[email protected]>
---
include/net/mac80211.h | 7 ++-
net/mac80211/ieee80211.c | 97 +++++++++++++++++-------------------
net/mac80211/ieee80211_i.h | 7 +--
net/mac80211/ieee80211_ioctl.c | 40 ++++++++++-----
net/mac80211/ieee80211_rate.h | 3 -
net/mac80211/ieee80211_scan.c | 2 -
net/mac80211/ieee80211_sta.c | 64 ++++++++++++++----------
net/mac80211/ieee80211_sysfs_sta.c | 5 +-
net/mac80211/rc80211_simple.c | 57 ++++++++++++---------
net/mac80211/sta_info.c | 4 +
10 files changed, 156 insertions(+), 130 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c5257d2..394b0fd 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -209,8 +209,9 @@ struct ieee80211_tx_control {
u8 sw_retry_attempt; /* number of times hw has tried to
* transmit frame (not incl. hw retries) */
- int rateidx; /* internal 80211.o rateidx */
- int rts_rateidx; /* internal 80211.o rateidx for RTS/CTS */
+ struct ieee80211_rate *rate; /* internal 80211.o rate */
+ struct ieee80211_rate *rts_rate; /* internal 80211.o rate
+ * for RTS/CTS */
int alt_retry_rate; /* retry rate for the last retries, given as the
* hw specific value for the rate (from
* struct ieee80211_rate). To be used to limit
@@ -272,6 +273,8 @@ struct ieee80211_conf {
int channel_val; /* hw specific value for the channel */
int phymode; /* MODE_IEEE80211A, .. */
+ struct ieee80211_channel *chan;
+ struct ieee80211_hw_mode *mode;
unsigned int regulatory_domain;
int radio_enabled;
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 577dbe3..bbdf928 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -136,16 +136,16 @@ static int rate_list_match(const int *ra
void ieee80211_prepare_rates(struct ieee80211_local *local)
{
int i;
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
IEEE80211_RATE_BASIC);
- if (local->supp_rates[local->hw.conf.phymode]) {
- if (!rate_list_match(local->supp_rates
- [local->hw.conf.phymode],
+ if (local->supp_rates[mode->mode]) {
+ if (!rate_list_match(local->supp_rates[mode->mode],
rate->rate))
continue;
}
@@ -154,12 +154,11 @@ void ieee80211_prepare_rates(struct ieee
/* Use configured basic rate set if it is available. If not,
* use defaults that are sane for most cases. */
- if (local->basic_rates[local->hw.conf.phymode]) {
- if (rate_list_match(local->basic_rates
- [local->hw.conf.phymode],
+ if (local->basic_rates[mode->mode]) {
+ if (rate_list_match(local->basic_rates[mode->mode],
rate->rate))
rate->flags |= IEEE80211_RATE_BASIC;
- } else switch (local->hw.conf.phymode) {
+ } else switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
@@ -182,7 +181,7 @@ void ieee80211_prepare_rates(struct ieee
}
/* Set ERP and MANDATORY flags based on phymode */
- switch (local->hw.conf.phymode) {
+ switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
@@ -358,11 +357,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
struct rate_control_extra extra;
memset(&extra, 0, sizeof(extra));
+ extra.mode = tx->u.tx.mode;
extra.mgmt_data = tx->sdata &&
tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
extra.ethertype = tx->ethertype;
- extra.startidx = 0;
- extra.endidx = tx->local->num_curr_rates;
tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
&extra);
@@ -376,20 +374,18 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
}
if (!tx->u.tx.rate)
return TXRX_DROP;
- if (tx->local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
tx->local->cts_protect_erp_frames && tx->fragmented &&
extra.nonerp) {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
- tx->u.tx.last_frag_rateidx = extra.rateidx;
tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
tx->u.tx.rate = extra.nonerp;
- tx->u.tx.control->rateidx = extra.nonerp_idx;
+ tx->u.tx.control->rate = extra.nonerp;
tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
} else {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
- tx->u.tx.last_frag_rateidx = extra.rateidx;
- tx->u.tx.control->rateidx = extra.rateidx;
+ tx->u.tx.control->rate = tx->u.tx.rate;
}
tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
@@ -657,6 +653,7 @@ static u16 ieee80211_duration(struct iee
int rate, mrate, erp, dur, i;
struct ieee80211_rate *txrate = tx->u.tx.rate;
struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
erp = txrate->flags & IEEE80211_RATE_ERP;
@@ -715,8 +712,8 @@ static u16 ieee80211_duration(struct iee
*/
rate = -1;
mrate = 10; /* use 1 Mbps if everything fails */
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *r = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
if (r->rate > txrate->rate)
break;
@@ -762,6 +759,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
@@ -788,7 +786,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
/* Use CTS protection for unicast frames sent using extended rates if
* there are associated non-ERP stations and RTS/CTS is not configured
* for the frame. */
- if (tx->local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211G &&
(tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
tx->u.tx.unicast &&
tx->local->cts_protect_erp_frames &&
@@ -812,12 +810,12 @@ ieee80211_tx_h_misc(struct ieee80211_txr
/* Use min(data rate, max base rate) as CTS/RTS rate */
rate = tx->u.tx.rate;
- while (rate > tx->local->curr_rates &&
+ while (rate > mode->rates &&
!(rate->flags & IEEE80211_RATE_BASIC))
rate--;
control->rts_cts_rate = rate->val;
- control->rts_rateidx = (int)(rate - tx->local->curr_rates);
+ control->rts_rate = rate;
}
if (tx->sta) {
@@ -1164,7 +1162,7 @@ static int __ieee80211_tx(struct ieee802
return IEEE80211_TX_FRAG_AGAIN;
if (i == tx->u.tx.num_extra_frag) {
control->tx_rate = tx->u.tx.last_frag_hwrate;
- control->rateidx = tx->u.tx.last_frag_rateidx;
+ control->rate = tx->u.tx.last_frag_rate;
if (tx->u.tx.probe_last_frag)
control->flags |=
IEEE80211_TXCTL_RATE_CTRL_PROBE;
@@ -1209,6 +1207,7 @@ static int ieee80211_tx(struct net_devic
__ieee80211_tx_prepare(&tx, skb, dev, control);
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
+ tx.u.tx.mode = local->hw.conf.mode;
for (handler = local->tx_handlers; *handler != NULL; handler++) {
res = (*handler)(&tx);
@@ -1281,7 +1280,7 @@ retry:
store->extra_frag = tx.u.tx.extra_frag;
store->num_extra_frag = tx.u.tx.num_extra_frag;
store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
- store->last_frag_rateidx = tx.u.tx.last_frag_rateidx;
+ store->last_frag_rate = tx.u.tx.last_frag_rate;
store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
}
return 0;
@@ -1317,7 +1316,7 @@ static void ieee80211_tx_pending(unsigne
tx.u.tx.extra_frag = store->extra_frag;
tx.u.tx.num_extra_frag = store->num_extra_frag;
tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
- tx.u.tx.last_frag_rateidx = store->last_frag_rateidx;
+ tx.u.tx.last_frag_rate = store->last_frag_rate;
tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
ret = __ieee80211_tx(local, store->skb, &tx);
if (ret) {
@@ -1778,7 +1777,7 @@ struct sk_buff * ieee80211_beacon_get(st
if (control) {
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->oper_hw_mode;
rate = rate_control_get_rate(local, local->mdev, skb, &extra);
if (!rate) {
@@ -1815,7 +1814,7 @@ __le16 ieee80211_rts_duration(struct iee
int erp;
u16 dur;
- rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
/* CTS duration */
@@ -1843,7 +1842,7 @@ __le16 ieee80211_ctstoself_duration(stru
int erp;
u16 dur;
- rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
/* Data frame duration */
@@ -2027,6 +2026,8 @@ int ieee80211_hw_config(struct ieee80211
local->hw.conf.freq = chan->freq;
local->hw.conf.phymode = mode->mode;
local->hw.conf.antenna_max = chan->antenna_max;
+ local->hw.conf.chan = chan;
+ local->hw.conf.mode = mode;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
@@ -2037,12 +2038,6 @@ int ieee80211_hw_config(struct ieee80211
if (local->ops->config)
ret = local->ops->config(local_to_hw(local), &local->hw.conf);
- if (local->curr_rates != mode->rates)
- rate_control_clear(local);
- local->curr_rates = mode->rates;
- local->num_curr_rates = mode->num_rates;
- ieee80211_prepare_rates(local);
-
return ret;
}
@@ -3893,6 +3888,7 @@ static ieee80211_txrx_result
ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
{
struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
struct sk_buff *skb = tx->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 load = 0, hdrtime;
@@ -3906,10 +3902,10 @@ ieee80211_tx_h_load_stats(struct ieee802
/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
* 1 usec = 1/8 * (1080 / 10) = 13.5 */
- if (local->hw.conf.phymode == MODE_IEEE80211A ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG ||
- (local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
hdrtime = CHAN_UTIL_HDR_SHORT;
else
@@ -3954,17 +3950,18 @@ ieee80211_rx_h_load_stats(struct ieee802
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 load = 0, hdrtime;
struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode = local->hw.conf.mode;
int i;
/* Estimate total channel use caused by this frame */
- if (unlikely(local->num_curr_rates < 0))
+ if (unlikely(mode->num_rates < 0))
return TXRX_CONTINUE;
- rate = &local->curr_rates[0];
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].val == rx->u.rx.status->rate) {
- rate = &local->curr_rates[i];
+ rate = &mode->rates[0];
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].val == rx->u.rx.status->rate) {
+ rate = &mode->rates[i];
break;
}
}
@@ -3972,10 +3969,10 @@ ieee80211_rx_h_load_stats(struct ieee802
/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
* 1 usec = 1/8 * (1080 / 10) = 13.5 */
- if (local->hw.conf.phymode == MODE_IEEE80211A ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG ||
- (local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
rate->flags & IEEE80211_RATE_ERP))
hdrtime = CHAN_UTIL_HDR_SHORT;
else
@@ -4739,13 +4736,13 @@ int ieee80211_register_hwmode(struct iee
rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
}
- if (!local->curr_rates) {
+ if (!local->oper_hw_mode) {
/* Default to this mode */
local->hw.conf.phymode = mode->mode;
local->oper_hw_mode = local->scan_hw_mode = mode;
local->oper_channel = local->scan_channel = &mode->channels[0];
- local->curr_rates = mode->rates;
- local->num_curr_rates = mode->num_rates;
+ local->hw.conf.mode = local->oper_hw_mode;
+ local->hw.conf.chan = local->oper_channel;
ieee80211_prepare_rates(local);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9df8ef0..1eb4f49 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -123,12 +123,12 @@ struct ieee80211_txrx_data {
unsigned int ps_buffered:1;
unsigned int short_preamble:1;
unsigned int probe_last_frag:1;
+ struct ieee80211_hw_mode *mode;
struct ieee80211_rate *rate;
/* use this rate (if set) for last fragment; rate can
* be set to lower rate for the first fragments, e.g.,
* when using CTS protection with IEEE 802.11g. */
struct ieee80211_rate *last_frag_rate;
- int last_frag_rateidx;
int last_frag_hwrate;
int mgmt_interface;
@@ -171,6 +171,7 @@ struct ieee80211_tx_stored_packet {
struct sk_buff **extra_frag;
int last_frag_rateidx;
int last_frag_hwrate;
+ struct ieee80211_rate *last_frag_rate;
unsigned int last_frag_rate_ctrl_probe:1;
};
@@ -396,10 +397,6 @@ struct ieee80211_local {
int iff_allmultis, iff_promiscs;
/* number of interfaces with corresponding IFF_ flags */
- /* Current rate table. This is a pointer to hw->modes structure. */
- struct ieee80211_rate *curr_rates;
- int num_curr_rates;
-
struct rate_control_ref *rate_ctrl;
int next_mode; /* MODE_IEEE80211*
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index ae224c6..1cfc32b 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -269,6 +269,7 @@ static int ieee80211_ioctl_add_sta(struc
u32 rates;
int i, j;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int add_key_entry = 1;
/* Prevent a race with changing the rate control algorithm */
@@ -306,13 +307,14 @@ static int ieee80211_ioctl_add_sta(struc
sta->listen_interval = param->u.add_sta.listen_interval;
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < sizeof(param->u.add_sta.supp_rates); i++) {
int rate = (param->u.add_sta.supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG)
+ if (mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++) {
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++) {
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
@@ -405,6 +407,7 @@ static int ieee80211_ioctl_get_info_sta(
struct prism2_hostapd_param *param)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sta_info *sta;
if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
@@ -417,7 +420,7 @@ static int ieee80211_ioctl_get_info_sta(
param->u.get_info_sta.tx_bytes = stats->tx_bytes;
/* go through all STAs and get STA with lowest max. rate */
param->u.get_info_sta.current_tx_rate =
- local->curr_rates[sta_info_min_txrate_get(local)].rate;
+ sta_info_min_txrate_get(local);
return 0;
}
@@ -434,9 +437,10 @@ static int ieee80211_ioctl_get_info_sta(
param->u.get_info_sta.tx_bytes = sta->tx_bytes;
param->u.get_info_sta.channel_use = sta->channel_use;
param->u.get_info_sta.flags = sta->flags;
- if (sta->txrate >= 0 && sta->txrate < local->num_curr_rates)
+ mode = local->oper_hw_mode;
+ if (sta->txrate >= 0 && sta->txrate < mode->num_rates)
param->u.get_info_sta.current_tx_rate =
- local->curr_rates[sta->txrate].rate;
+ mode->rates[sta->txrate].rate;
param->u.get_info_sta.num_ps_buf_frames =
skb_queue_len(&sta->ps_tx_buf);
param->u.get_info_sta.tx_retry_failed = sta->tx_retry_failed;
@@ -1805,6 +1809,7 @@ int ieee80211_set_channel(struct ieee802
{
struct ieee80211_hw_mode *mode;
int c, set = 0;
+ int ret = -EINVAL;
list_for_each_entry(mode, &local->modes_list, list) {
if (!(local->enabled_modes & (1 << mode->mode)))
@@ -1827,12 +1832,15 @@ int ieee80211_set_channel(struct ieee802
if (set) {
if (local->sta_scanning)
- return 0;
+ ret = 0;
else
- return ieee80211_hw_config(local);
+ ret = ieee80211_hw_config(local);
+
+ rate_control_clear(local);
+ ieee80211_prepare_rates(local);
}
- return -EINVAL;
+ return ret;
}
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
@@ -2283,6 +2291,7 @@ ieee80211_ioctl_force_unicast_rate(struc
int rate)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
int i;
if (sdata->type != IEEE80211_IF_TYPE_AP)
@@ -2293,8 +2302,9 @@ ieee80211_ioctl_force_unicast_rate(struc
return 0;
}
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].rate == rate) {
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
sdata->u.ap.force_unicast_rateidx = i;
return 0;
}
@@ -2309,6 +2319,7 @@ ieee80211_ioctl_max_ratectrl_rate(struct
int rate)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
int i;
if (sdata->type != IEEE80211_IF_TYPE_AP)
@@ -2319,8 +2330,9 @@ ieee80211_ioctl_max_ratectrl_rate(struct
return 0;
}
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].rate == rate) {
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
sdata->u.ap.max_ratectrl_rateidx = i;
return 0;
}
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h
index 3f51594..3bb09f2 100644
--- a/net/mac80211/ieee80211_rate.h
+++ b/net/mac80211/ieee80211_rate.h
@@ -26,11 +26,10 @@ struct rate_control_extra {
/* values from rate_control_get_rate() to the caller: */
struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
* probing */
- int startidx, endidx, rateidx;
struct ieee80211_rate *nonerp;
- int nonerp_idx;
/* parameters from the caller to rate_control_get_rate(): */
+ struct ieee80211_hw_mode *mode;
int mgmt_data; /* this is data frame that is used for management
* (e.g., IEEE 802.1X EAPOL) */
u16 ethertype;
diff --git a/net/mac80211/ieee80211_scan.c b/net/mac80211/ieee80211_scan.c
index f9b42d4..07f8d9a 100644
--- a/net/mac80211/ieee80211_scan.c
+++ b/net/mac80211/ieee80211_scan.c
@@ -326,7 +326,7 @@ void ieee80211_init_scan(struct ieee8021
local->scan.tx_control.key_idx = HW_KEY_IDX_INVALID;
local->scan.tx_control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->hw.conf.mode;
local->scan.tx_control.tx_rate =
rate_control_get_rate(local, local->mdev,
local->scan.skb, &extra)->val;
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 44646be..a264008 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -480,6 +480,7 @@ static void ieee80211_send_assoc(struct
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *ies;
@@ -498,8 +499,9 @@ static void ieee80211_send_assoc(struct
}
skb_reserve(skb, local->hw.extra_tx_headroom);
+ mode = local->oper_hw_mode;
capab = ifsta->capab;
- if (local->hw.conf.phymode == MODE_IEEE80211G) {
+ if (mode->mode == MODE_IEEE80211G) {
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE;
}
@@ -541,26 +543,26 @@ static void ieee80211_send_assoc(struct
*pos++ = ifsta->ssid_len;
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- len = local->num_curr_rates;
+ len = mode->num_rates;
if (len > 8)
len = 8;
pos = skb_put(skb, len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = len;
for (i = 0; i < len; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
- if (local->num_curr_rates > len) {
- pos = skb_put(skb, local->num_curr_rates - len + 2);
+ if (mode->num_rates > len) {
+ pos = skb_put(skb, mode->num_rates - len + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = local->num_curr_rates - len;
- for (i = len; i < local->num_curr_rates; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ *pos++ = mode->num_rates - len;
+ for (i = len; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
@@ -771,6 +773,7 @@ static void ieee80211_send_probe_req(str
u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *supp_rates, *esupp_rates = NULL;
@@ -804,8 +807,9 @@ static void ieee80211_send_probe_req(str
supp_rates = skb_put(skb, 2);
supp_rates[0] = WLAN_EID_SUPP_RATES;
supp_rates[1] = 0;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
continue;
if (esupp_rates) {
@@ -820,7 +824,7 @@ static void ieee80211_send_probe_req(str
pos = skb_put(skb, 1);
supp_rates[1]++;
}
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
*pos = rate->rate / 10;
else
*pos = rate->rate / 5;
@@ -1096,6 +1100,7 @@ static void ieee80211_rx_mgmt_assoc_resp
int reassoc)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sta_info *sta;
u32 rates;
u16 capab_info, status_code, aid;
@@ -1197,20 +1202,21 @@ static void ieee80211_rx_mgmt_assoc_resp
sta->assoc_ap = 1;
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < elems.supp_rates_len; i++) {
int rate = (elems.supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
for (i = 0; i < elems.ext_supp_rates_len; i++) {
int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
sta->supp_rates = rates;
@@ -2124,6 +2130,7 @@ static int ieee80211_sta_join_ibss(struc
struct ieee80211_mgmt *mgmt;
struct ieee80211_tx_control control;
struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode;
struct rate_control_extra extra;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
@@ -2210,7 +2217,7 @@ static int ieee80211_sta_join_ibss(struc
memset(&control, 0, sizeof(control));
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->oper_hw_mode;
rate = rate_control_get_rate(local, dev, skb, &extra);
if (!rate) {
printk(KERN_DEBUG "%s: Failed to determine TX rate "
@@ -2246,12 +2253,13 @@ static int ieee80211_sta_join_ibss(struc
}
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < bss->supp_rates_len; i++) {
int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
bitrate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == bitrate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == bitrate)
rates |= BIT(j);
}
ifsta->supp_rates_bits = rates;
@@ -2278,6 +2286,7 @@ static int ieee80211_sta_create_ibss(str
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
u8 bssid[ETH_ALEN], *pos;
int i;
@@ -2303,6 +2312,7 @@ static int ieee80211_sta_create_ibss(str
return -ENOMEM;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ mode = local->oper_hw_mode;
if (local->hw.conf.beacon_int == 0)
local->hw.conf.beacon_int = 100;
@@ -2316,11 +2326,11 @@ static int ieee80211_sta_create_ibss(str
bss->capability |= WLAN_CAPABILITY_PRIVACY;
} else
sdata->drop_unencrypted = 0;
- bss->supp_rates_len = local->num_curr_rates;
+ bss->supp_rates_len = mode->num_rates;
pos = bss->supp_rates;
- for (i = 0; i < local->num_curr_rates; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ for (i = 0; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
diff --git a/net/mac80211/ieee80211_sysfs_sta.c b/net/mac80211/ieee80211_sysfs_sta.c
index e3a6d32..ae62bcf 100644
--- a/net/mac80211/ieee80211_sysfs_sta.c
+++ b/net/mac80211/ieee80211_sysfs_sta.c
@@ -40,10 +40,11 @@ static ssize_t show_sta_##name(const str
static ssize_t show_sta_##name(const struct sta_info *sta, char *buf) \
{ \
struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode; \
return sprintf(buf, "%d\n", \
(sta->field >= 0 && \
- sta->field < local->num_curr_rates) ? \
- local->curr_rates[sta->field].rate : -1); \
+ sta->field < mode->num_rates) ? \
+ mode->rates[sta->field].rate : -1); \
}
#define __STA_ATTR(name) \
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
index 16bec51..1b5c82c 100644
--- a/net/mac80211/rc80211_simple.c
+++ b/net/mac80211/rc80211_simple.c
@@ -34,6 +34,7 @@ static void rate_control_rate_inc(struct
struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int i = sta->txrate;
int maxrate;
@@ -43,15 +44,16 @@ static void rate_control_rate_inc(struct
return;
}
+ mode = local->oper_hw_mode;
maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
- if (i > local->num_curr_rates)
- i = local->num_curr_rates - 2;
+ if (i > mode->num_rates)
+ i = mode->num_rates - 2;
- while (i + 1 < local->num_curr_rates) {
+ while (i + 1 < mode->num_rates) {
i++;
if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
(maxrate < 0 || i <= maxrate)) {
sta->txrate = i;
break;
@@ -64,6 +66,7 @@ static void rate_control_rate_dec(struct
struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int i = sta->txrate;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
@@ -72,13 +75,14 @@ static void rate_control_rate_dec(struct
return;
}
- if (i > local->num_curr_rates)
- i = local->num_curr_rates;
+ mode = local->oper_hw_mode;
+ if (i > mode->num_rates)
+ i = mode->num_rates;
while (i > 0) {
i--;
if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED) {
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
sta->txrate = i;
break;
}
@@ -87,21 +91,21 @@ static void rate_control_rate_dec(struct
static struct ieee80211_rate *
-rate_control_lowest_rate(struct ieee80211_local *local)
+rate_control_lowest_rate(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode)
{
int i;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
- if (rate->flags & IEEE80211_RATE_SUPPORTED
- )
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
return rate;
}
printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
"found\n");
- return &local->curr_rates[0];
+ return &mode->rates[0];
}
@@ -182,7 +186,7 @@ static void rate_control_simple_tx_statu
} else if (per_failed < local->rate_ctrl_num_up) {
rate_control_rate_inc(local, sta);
}
- srctrl->tx_avg_rate_sum += local->curr_rates[sta->txrate].rate;
+ srctrl->tx_avg_rate_sum += status->control.rate->rate;
srctrl->tx_avg_rate_num++;
srctrl->tx_num_failures = 0;
srctrl->tx_num_xmit = 0;
@@ -220,6 +224,7 @@ rate_control_simple_get_rate(void *priv,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hw_mode *mode = extra->mode;
struct sta_info *sta;
int rateidx, nonerp_idx;
u16 fc;
@@ -232,13 +237,13 @@ rate_control_simple_get_rate(void *priv,
/* Send management frames and broadcast/multicast data using
* lowest rate. */
/* TODO: this could probably be improved.. */
- return rate_control_lowest_rate(local);
+ return rate_control_lowest_rate(local, mode);
}
sta = sta_info_get(local, hdr->addr1);
if (!sta)
- return rate_control_lowest_rate(local);
+ return rate_control_lowest_rate(local, mode);
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
@@ -246,23 +251,21 @@ rate_control_simple_get_rate(void *priv,
rateidx = sta->txrate;
- if (rateidx >= local->num_curr_rates)
- rateidx = local->num_curr_rates - 1;
+ if (rateidx >= mode->num_rates)
+ rateidx = mode->num_rates - 1;
sta->last_txrate = rateidx;
nonerp_idx = rateidx;
while (nonerp_idx > 0 &&
- ((local->curr_rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
- !(local->curr_rates[nonerp_idx].flags &
- IEEE80211_RATE_SUPPORTED) ||
+ ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
+ !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
!(sta->supp_rates & BIT(nonerp_idx))))
nonerp_idx--;
- extra->nonerp_idx = nonerp_idx;
- extra->nonerp = &local->curr_rates[extra->nonerp_idx];
+ extra->nonerp = &mode->rates[nonerp_idx];
sta_info_put(sta);
- return &local->curr_rates[rateidx];
+ return &mode->rates[rateidx];
}
@@ -270,15 +273,17 @@ static void rate_control_simple_rate_ini
struct ieee80211_local *local,
struct sta_info *sta)
{
+ struct ieee80211_hw_mode *mode;
int i;
sta->txrate = 0;
+ mode = local->oper_hw_mode;
/* TODO: what is a good starting rate for STA? About middle? Maybe not
* the lowest or the highest rate.. Could consider using RSSI from
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
- for (i = 0; i < local->num_curr_rates; i++) {
+ for (i = 0; i < mode->num_rates; i++) {
if ((sta->supp_rates & BIT(i)) &&
- (local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
sta->txrate = i;
}
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 09554aa..2e258cf 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -80,10 +80,12 @@ EXPORT_SYMBOL(sta_info_get);
int sta_info_min_txrate_get(struct ieee80211_local *local)
{
struct sta_info *sta;
+ struct ieee80211_hw_mode *mode;
int min_txrate = 9999999;
int i;
spin_lock_bh(&local->sta_lock);
+ mode = local->oper_hw_mode;
for (i = 0; i < STA_HASH_SIZE; i++) {
sta = local->sta_hash[i];
while (sta) {
@@ -96,7 +98,7 @@ int sta_info_min_txrate_get(struct ieee8
if (min_txrate == 9999999)
min_txrate = 0;
- return min_txrate;
+ return mode->rates[min_txrate].rate;
}
On Wednesday 28 February 2007 16:09, Jouni Malinen wrote:
> Why bother with PS Poll in this case? Just send data::nullfunc with PS
> Poll flag cleared. That will make the AP deliver all buffered frames (if
> any).
Didn't think of it. :)
Here's a version that does that:
--
d80211: switch STA interfaces to PS mode during scan
From: Michael Wu <[email protected]>
This makes scans switch STA interfaces into PS mode so the AP queues frames
destined for us while we are scanning. This is achieved by sending a
nullfunc data frame with the PS mode bit set before scanning commences,
and a PS poll frame after scanning is completed.
Signed-off-by: Michael Wu <[email protected]>
---
include/linux/ieee80211.h | 7 ++++++
net/mac80211/ieee80211_sta.c | 51
+++++++++++++++++++++++++++++++++++-------
2 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4379b1d..836bde2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -203,6 +203,13 @@ struct ieee80211_cts {
__u8 ra[6];
} __attribute__ ((packed));
+struct ieee80211_ps_poll {
+ __le16 frame_control;
+ __le16 aid;
+ __u8 bssid[6];
+ __u8 ta[6];
+} __attribute__ ((packed));
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 280b24f..747662d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2523,6 +2523,37 @@ int ieee80211_sta_set_bssid(struct net_d
}
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -2544,10 +2575,12 @@ void ieee80211_scan_completed(struct iee
spin_lock_bh(&local->sub_if_lock);
list_for_each_entry(sdata, &local->sub_if_list, list) {
- netif_wake_queue(sdata->dev);
-
- if (sdata->type == IEEE80211_IF_TYPE_STA)
+ if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 0);
ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ netif_wake_queue(sdata->dev);
}
spin_unlock_bh(&local->sub_if_lock);
@@ -2667,9 +2700,6 @@ static int ieee80211_sta_start_scan(stru
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- /* TODO: if assoc, move to power save mode for the duration of the
- * scan */
-
if (local->sta_scanning) {
if (local->scan_dev == dev)
return 0;
@@ -2691,8 +2721,12 @@ static int ieee80211_sta_start_scan(stru
local->sta_scanning = 1;
spin_lock_bh(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list)
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
netif_stop_queue(sdata->dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ }
spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
@@ -2706,7 +2740,8 @@ static int ieee80211_sta_start_scan(stru
list);
local->scan_channel_idx = 0;
local->scan_dev = dev;
- schedule_delayed_work(&local->scan_work, 0);
+ /* TODO: start scan as soon as all nullfunc frames are ACKed */
+ schedule_delayed_work(&local->scan_work, IEEE80211_CHANNEL_TIME);
return 0;
}
On Wed, Feb 28, 2007 at 03:39:43PM -0500, Michael Wu wrote:
> This makes scans switch STA interfaces into PS mode so the AP queues frames
> destined for us while we are scanning. This is achieved by sending a
> nullfunc data frame with the PS mode bit set before scanning commences,
> and a PS poll frame after scanning is completed.
Why bother with PS Poll in this case? Just send data::nullfunc with PS
Poll flag cleared. That will make the AP deliver all buffered frames (if
any).
--
Jouni Malinen PGP id EFC895FA
From: Michael Wu <[email protected]>
This prevents drivers from crashing if there is a TX timeout and the reset
callback isn't implemented.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index bbdf928..15344c7 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -2084,7 +2084,7 @@ static void ieee80211_tx_timeout(struct
printk(KERN_WARNING "%s: resetting interface.\n", dev->name);
- if (local->ops->reset(local_to_hw(local)))
+ if (local->ops->reset && local->ops->reset(local_to_hw(local)))
printk(KERN_ERR "%s: failed to reset interface.\n", dev->name);
else
netif_wake_queue(dev);
On Wednesday 28 February 2007 16:42, Michael Wu wrote:
> This makes scans switch STA interfaces into PS mode so the AP queues frames
> destined for us while we are scanning. This is achieved by sending a
> nullfunc data frame with the PS mode bit set before scanning commences,
> and a PS poll frame after scanning is completed.
>
Er. I should update the description too..
--
d80211: switch STA interfaces to PS mode during scan
From: Michael Wu <[email protected]>
This makes scans switch STA interfaces into PS mode so the AP queues frames
destined for us while we are scanning. This is achieved by sending a
nullfunc data frame with the PS mode bit set before scanning commences,
and a nullfunc data frame without the PS mode bit set after scanning is
completed.
Signed-off-by: Michael Wu <[email protected]>
---
include/linux/ieee80211.h | 7 ++++++
net/mac80211/ieee80211_sta.c | 51
+++++++++++++++++++++++++++++++++++-------
2 files changed, 50 insertions(+), 8 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4379b1d..836bde2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -203,6 +203,13 @@ struct ieee80211_cts {
__u8 ra[6];
} __attribute__ ((packed));
+struct ieee80211_ps_poll {
+ __le16 frame_control;
+ __le16 aid;
+ __u8 bssid[6];
+ __u8 ta[6];
+} __attribute__ ((packed));
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 280b24f..747662d 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2523,6 +2523,37 @@ int ieee80211_sta_set_bssid(struct net_d
}
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -2544,10 +2575,12 @@ void ieee80211_scan_completed(struct iee
spin_lock_bh(&local->sub_if_lock);
list_for_each_entry(sdata, &local->sub_if_list, list) {
- netif_wake_queue(sdata->dev);
-
- if (sdata->type == IEEE80211_IF_TYPE_STA)
+ if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 0);
ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ netif_wake_queue(sdata->dev);
}
spin_unlock_bh(&local->sub_if_lock);
@@ -2667,9 +2700,6 @@ static int ieee80211_sta_start_scan(stru
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- /* TODO: if assoc, move to power save mode for the duration of the
- * scan */
-
if (local->sta_scanning) {
if (local->scan_dev == dev)
return 0;
@@ -2691,8 +2721,12 @@ static int ieee80211_sta_start_scan(stru
local->sta_scanning = 1;
spin_lock_bh(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list)
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
netif_stop_queue(sdata->dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ }
spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
@@ -2706,7 +2740,8 @@ static int ieee80211_sta_start_scan(stru
list);
local->scan_channel_idx = 0;
local->scan_dev = dev;
- schedule_delayed_work(&local->scan_work, 0);
+ /* TODO: start scan as soon as all nullfunc frames are ACKed */
+ schedule_delayed_work(&local->scan_work, IEEE80211_CHANNEL_TIME);
return 0;
}
From: Michael Wu <[email protected]>
This prevents data frames from being queued on the master device if it is
in the midst of a scan. It also makes both master and virtual interfaces
properly set trans_start when frames are sent so the network watchdog does
not try to reset the interfaces. tx_queue_len is left as the default on
virtual interfaces to allow frames to be queued while the device is
scanning.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211.c | 5 +++--
net/mac80211/ieee80211_sta.c | 23 ++++++++++++++++++-----
2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index a0879ba..967df9c 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -1148,6 +1148,7 @@ static int __ieee80211_tx(struct ieee802
ret = local->ops->tx(local_to_hw(local), skb, control);
if (ret)
return IEEE80211_TX_AGAIN;
+ local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
}
if (tx->u.tx.extra_frag) {
@@ -1178,6 +1179,7 @@ static int __ieee80211_tx(struct ieee802
control);
if (ret)
return IEEE80211_TX_FRAG_AGAIN;
+ local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
tx->u.tx.extra_frag[i] = NULL;
}
@@ -1588,6 +1590,7 @@ static int ieee80211_subif_start_xmit(st
skb->nh.raw = skb->data + nh_pos;
skb->h.raw = skb->data + h_pos;
+ dev->trans_start = jiffies;
dev_queue_xmit(skb);
return 0;
@@ -4433,7 +4436,6 @@ void ieee80211_if_setup(struct net_devic
dev->get_stats = ieee80211_get_stats;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
- dev->tx_queue_len = 0;
dev->uninit = ieee80211_if_reinit;
dev->destructor = ieee80211_if_free;
}
@@ -4448,7 +4450,6 @@ void ieee80211_if_mgmt_setup(struct net_
dev->stop = ieee80211_mgmt_stop;
dev->type = ARPHRD_IEEE80211_PRISM;
dev->hard_header_parse = header_parse_80211;
- dev->tx_queue_len = 0;
dev->uninit = ieee80211_if_reinit;
dev->destructor = ieee80211_if_free;
}
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 9d08a37..280b24f 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2527,7 +2527,7 @@ void ieee80211_scan_completed(struct iee
{
struct ieee80211_local *local = hw_to_local(hw);
struct net_device *dev = local->scan_dev;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata;
union iwreq_data wrqu;
printk(KERN_DEBUG "%s: scan completed\n", dev->name);
@@ -2542,15 +2542,23 @@ void ieee80211_scan_completed(struct iee
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ netif_wake_queue(sdata->dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA)
+ ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
if (!ifsta->bssid_set ||
(!ifsta->state == IEEE80211_IBSS_JOINED &&
!ieee80211_sta_active_ibss(dev)))
ieee80211_sta_find_ibss(dev, ifsta);
- /* TODO: need to wake every sta interface */
- } else if (sdata->type == IEEE80211_IF_TYPE_STA)
- ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
}
EXPORT_SYMBOL(ieee80211_scan_completed);
@@ -2637,6 +2645,7 @@ static int ieee80211_sta_start_scan(stru
u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
if (ssid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
@@ -2680,7 +2689,11 @@ static int ieee80211_sta_start_scan(stru
}
local->sta_scanning = 1;
- /* TODO: stop TX queue? */
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list)
+ netif_stop_queue(sdata->dev);
+ spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
local->scan_ssid_len = ssid_len;
From: Michael Wu <[email protected]>
This makes STA interfaces set the carrier status based on the current
association status.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211.c | 4 ++++
net/mac80211/ieee80211_sta.c | 3 +++
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 15344c7..a0879ba 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -2377,6 +2377,10 @@ static int ieee80211_open(struct net_dev
else
ieee80211_if_config(dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ !local->user_space_mlme)
+ netif_carrier_off(dev);
+
netif_start_queue(dev);
return 0;
}
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index a264008..9d08a37 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -375,11 +375,13 @@ static void ieee80211_set_associated(str
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type != IEEE80211_IF_TYPE_STA)
return;
+ netif_carrier_on(dev);
ifsta->prev_bssid_set = 1;
memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
ieee80211_sta_send_associnfo(dev, ifsta);
} else {
+ netif_carrier_off(dev);
memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN);
}
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -2007,6 +2009,7 @@ static void ieee80211_sta_reset_auth(str
ifsta->auth_alg);
ifsta->auth_transaction = -1;
ifsta->associated = ifsta->auth_tries = ifsta->assoc_tries = 0;
+ netif_carrier_off(dev);
}
From: Michael Wu <[email protected]>
This makes scans switch STA interfaces into PS mode so the AP queues frames
destined for us while we are scanning. This is achieved by sending a
nullfunc data frame with the PS mode bit set before scanning commences,
and a PS poll frame after scanning is completed.
Signed-off-by: Michael Wu <[email protected]>
---
include/linux/ieee80211.h | 7 ++++
net/mac80211/ieee80211_sta.c | 77 ++++++++++++++++++++++++++++++++++++++----
2 files changed, 76 insertions(+), 8 deletions(-)
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 4379b1d..836bde2 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -203,6 +203,13 @@ struct ieee80211_cts {
__u8 ra[6];
} __attribute__ ((packed));
+struct ieee80211_ps_poll {
+ __le16 frame_control;
+ __le16 aid;
+ __u8 bssid[6];
+ __u8 ta[6];
+} __attribute__ ((packed));
+
/* Authentication algorithms */
#define WLAN_AUTH_OPEN 0
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 280b24f..7270ae2 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2523,6 +2523,32 @@ int ieee80211_sta_set_bssid(struct net_d
}
+static void ieee80211_send_ps_poll(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ struct sk_buff *skb;
+ struct ieee80211_ps_poll *ps_poll;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*ps_poll));
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for PS poll "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ ps_poll = (struct ieee80211_ps_poll *) skb_put(skb, sizeof(*ps_poll));
+ memset(ps_poll, 0, sizeof(*ps_poll));
+ ps_poll->frame_control = IEEE80211_FC(IEEE80211_FTYPE_CTL,
+ IEEE80211_STYPE_PSPOLL);
+ ps_poll->aid = cpu_to_le16((1 << 15) | (1 << 14) | sdata->u.sta.aid);
+ memcpy(ps_poll->bssid, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(ps_poll->ta, sdata->dev->dev_addr, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -2544,10 +2570,12 @@ void ieee80211_scan_completed(struct iee
spin_lock_bh(&local->sub_if_lock);
list_for_each_entry(sdata, &local->sub_if_list, list) {
- netif_wake_queue(sdata->dev);
-
- if (sdata->type == IEEE80211_IF_TYPE_STA)
+ if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->u.sta.associated)
+ ieee80211_send_ps_poll(local, sdata);
ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ netif_wake_queue(sdata->dev);
}
spin_unlock_bh(&local->sub_if_lock);
@@ -2641,6 +2669,37 @@ void ieee80211_sta_scan_work(struct work
}
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
static int ieee80211_sta_start_scan(struct net_device *dev,
u8 *ssid, size_t ssid_len)
{
@@ -2667,9 +2726,6 @@ static int ieee80211_sta_start_scan(stru
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- /* TODO: if assoc, move to power save mode for the duration of the
- * scan */
-
if (local->sta_scanning) {
if (local->scan_dev == dev)
return 0;
@@ -2691,8 +2747,12 @@ static int ieee80211_sta_start_scan(stru
local->sta_scanning = 1;
spin_lock_bh(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list)
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
netif_stop_queue(sdata->dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ }
spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
@@ -2706,7 +2766,8 @@ static int ieee80211_sta_start_scan(stru
list);
local->scan_channel_idx = 0;
local->scan_dev = dev;
- schedule_delayed_work(&local->scan_work, 0);
+ /* TODO: start scan as soon as all nullfunc frames are ACKed */
+ schedule_delayed_work(&local->scan_work, IEEE80211_CHANNEL_TIME);
return 0;
}
On Wednesday 28 February 2007 15:39, Michael Wu wrote:
> This prevents drivers from crashing if there is a TX timeout and the reset
> callback isn't implemented.
>
Actually, I don't think we should bother setting the TX timeout callback at
all.
--
d80211: Remove tx_timeout callback
From: Michael Wu <[email protected]>
This never worked in the first place and we can't use the network watchdog
anyway since that checks if the queue is stopped, but wireless devices can
have many queues. TX timeouts on virtual interfaces don't really make sense
either since they can't stall.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211.c | 15 ---------------
1 files changed, 0 insertions(+), 15 deletions(-)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index bbdf928..cdc8df4 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -2078,19 +2078,6 @@ static int ieee80211_change_mtu_apdev(st
}
-static void ieee80211_tx_timeout(struct net_device *dev)
-{
- struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-
- printk(KERN_WARNING "%s: resetting interface.\n", dev->name);
-
- if (local->ops->reset(local_to_hw(local)))
- printk(KERN_ERR "%s: failed to reset interface.\n", dev->name);
- else
- netif_wake_queue(dev);
-}
-
-
static int ieee80211_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *a = addr;
@@ -4425,7 +4412,6 @@ void ieee80211_if_setup(struct net_devic
dev->set_mac_address = ieee80211_set_mac_address;
dev->set_multicast_list = ieee80211_set_multicast_list;
dev->change_mtu = ieee80211_change_mtu;
- dev->tx_timeout = ieee80211_tx_timeout;
dev->get_stats = ieee80211_get_stats;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
@@ -4593,7 +4579,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(
mdev->wireless_handlers = &ieee80211_iw_master_handler_def;
mdev->do_ioctl = ieee80211_ioctl;
mdev->change_mtu = ieee80211_change_mtu;
- mdev->tx_timeout = ieee80211_tx_timeout;
mdev->get_stats = ieee80211_get_stats;
mdev->open = ieee80211_master_open;
mdev->stop = ieee80211_master_stop;
On Wednesday 21 March 2007 13:25, Jiri Benc wrote:
> On Wed, 28 Feb 2007 15:39:43 -0500, Michael Wu wrote:
> > This makes STA interfaces set the carrier status based on the current
> > association status.
>
> Does this really work? Last time I checked, when the carrier is off, no
> frames are sent to hard_start_xmit.
>
This applies only to STA interfaces, whose frames to the master dev are
dropped anyways if there is no association.
-Michael Wu
On Wed, 28 Feb 2007 15:39:43 -0500, Michael Wu wrote:
> This makes STA interfaces set the carrier status based on the current
> association status.
Does this really work? Last time I checked, when the carrier is off, no
frames are sent to hard_start_xmit.
Jiri
--
Jiri Benc
SUSE Labs
On Thu, 1 Mar 2007 00:43:10 -0500, Michael Wu wrote:
> On Wednesday 28 February 2007 16:44, Michael Wu wrote:
> > On Wednesday 28 February 2007 16:42, Michael Wu wrote:
> > > This makes scans switch STA interfaces into PS mode so the AP queues
> > > frames destined for us while we are scanning. This is achieved by sending
> > > a nullfunc data frame with the PS mode bit set before scanning commences,
> > > and a PS poll frame after scanning is completed.
> >
> > Er. I should update the description too..
> >
> And drop the ps_poll part since we don't use the ps poll frame now..
>
> [...]
> @@ -2541,10 +2572,12 @@ void ieee80211_scan_completed(struct iee
>
> spin_lock_bh(&local->sub_if_lock);
> list_for_each_entry(sdata, &local->sub_if_list, list) {
> - netif_wake_queue(sdata->dev);
> -
> - if (sdata->type == IEEE80211_IF_TYPE_STA)
> + if (sdata->type == IEEE80211_IF_TYPE_STA) {
> + if (sdata->u.sta.associated)
> + ieee80211_send_nullfunc(local, sdata, 0);
> ieee80211_sta_timer((unsigned long)&sdata->u.sta);
> + }
> + netif_wake_queue(sdata->dev);
Shouldn't the queue be woken before calling ieee80211_sta_timer?
Thanks,
Jiri
--
Jiri Benc
SUSE Labs
On Wed, 28 Feb 2007 21:14:21 -0500, Michael Wu wrote:
> This never worked in the first place and we can't use the network watchdog
> anyway since that checks if the queue is stopped, but wireless devices can
> have many queues. TX timeouts on virtual interfaces don't really make sense
> either since they can't stall.
Okay. Let's reintroduce this when multiqueue support is implemented in
the kernel.
Jiri
--
Jiri Benc
SUSE Labs
On Friday 23 March 2007 12:01, Jiri Benc wrote:
> > @@ -2541,10 +2572,12 @@ void ieee80211_scan_completed(struct iee
> >
> > spin_lock_bh(&local->sub_if_lock);
> > list_for_each_entry(sdata, &local->sub_if_list, list) {
> > - netif_wake_queue(sdata->dev);
> > -
> > - if (sdata->type == IEEE80211_IF_TYPE_STA)
> > + if (sdata->type == IEEE80211_IF_TYPE_STA) {
> > + if (sdata->u.sta.associated)
> > + ieee80211_send_nullfunc(local, sdata, 0);
> > ieee80211_sta_timer((unsigned long)&sdata->u.sta);
> > + }
> > + netif_wake_queue(sdata->dev);
>
> Shouldn't the queue be woken before calling ieee80211_sta_timer?
>
ieee80211_sta_timer just schedules the workqueue to run. I'm not sure if the
workqueue can run immediately after that, but even if it did, the sta code
doesn't depend on the queue of a virtual interface so these lines don't need
to run in any particular order.
-Michael Wu
On Thu, 1 Mar 2007 00:40:09 -0500, Michael Wu wrote:
> On Wednesday 28 February 2007 15:39, Michael Wu wrote:
> > From: Michael Wu <[email protected]>
> >
> > This prevents data frames from being queued on the master device if it is
> > in the midst of a scan. It also makes both master and virtual interfaces
> > properly set trans_start when frames are sent so the network watchdog does
> > not try to reset the interfaces. tx_queue_len is left as the default on
> > virtual interfaces to allow frames to be queued while the device is
> > scanning.
> >
> And now that all STA interfaces are woken up after a scan, we also can remove
> the scan_dev check.
Looks good, thanks!
Jiri
--
Jiri Benc
SUSE Labs
On Wednesday 28 February 2007 15:39, Michael Wu wrote:
> diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
> index 577dbe3..bbdf928 100644
> --- a/net/mac80211/ieee80211.c
> +++ b/net/mac80211/ieee80211.c
> @@ -136,16 +136,16 @@ static int rate_list_match(const int *ra
> void ieee80211_prepare_rates(struct ieee80211_local *local)
> {
> int i;
> + struct ieee80211_hw_mode *mode = local->oper_hw_mode;
>
Ehh, this isn't quite right and may break things on ABG devices.
--
d80211: Remove curr_rates and fix related concurrency issues
From: Michael Wu <[email protected]>
This switches the code from curr_rates and num_curr_rates to directly using
the mode and converts portions of the code to use pointers to rates instead
of indices to refer to rates. Two new fields are introduced in struct
ieee80211_conf which may replace the channel/frequency/channel_val/phymode
fields in the future. The rate control is now cleared only when the
operating channel is changed.
Signed-off-by: Michael Wu <[email protected]>
---
include/net/mac80211.h | 7 ++
net/mac80211/ieee80211.c | 101 +++++++++++++++++-------------------
net/mac80211/ieee80211_i.h | 10 +---
net/mac80211/ieee80211_ioctl.c | 52 +++++++++++--------
net/mac80211/ieee80211_rate.h | 3 -
net/mac80211/ieee80211_scan.c | 2 -
net/mac80211/ieee80211_sta.c | 64 +++++++++++++----------
net/mac80211/ieee80211_sysfs_sta.c | 5 +-
net/mac80211/rc80211_simple.c | 57 +++++++++++---------
net/mac80211/sta_info.c | 4 +
10 files changed, 166 insertions(+), 139 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c5257d2..394b0fd 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -209,8 +209,9 @@ struct ieee80211_tx_control {
u8 sw_retry_attempt; /* number of times hw has tried to
* transmit frame (not incl. hw retries) */
- int rateidx; /* internal 80211.o rateidx */
- int rts_rateidx; /* internal 80211.o rateidx for RTS/CTS */
+ struct ieee80211_rate *rate; /* internal 80211.o rate */
+ struct ieee80211_rate *rts_rate; /* internal 80211.o rate
+ * for RTS/CTS */
int alt_retry_rate; /* retry rate for the last retries, given as the
* hw specific value for the rate (from
* struct ieee80211_rate). To be used to limit
@@ -272,6 +273,8 @@ struct ieee80211_conf {
int channel_val; /* hw specific value for the channel */
int phymode; /* MODE_IEEE80211A, .. */
+ struct ieee80211_channel *chan;
+ struct ieee80211_hw_mode *mode;
unsigned int regulatory_domain;
int radio_enabled;
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 577dbe3..5f050fd 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -133,19 +133,19 @@ static int rate_list_match(const int *ra
}
-void ieee80211_prepare_rates(struct ieee80211_local *local)
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode)
{
int i;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
rate->flags &= ~(IEEE80211_RATE_SUPPORTED |
IEEE80211_RATE_BASIC);
- if (local->supp_rates[local->hw.conf.phymode]) {
- if (!rate_list_match(local->supp_rates
- [local->hw.conf.phymode],
+ if (local->supp_rates[mode->mode]) {
+ if (!rate_list_match(local->supp_rates[mode->mode],
rate->rate))
continue;
}
@@ -154,12 +154,11 @@ void ieee80211_prepare_rates(struct ieee
/* Use configured basic rate set if it is available. If not,
* use defaults that are sane for most cases. */
- if (local->basic_rates[local->hw.conf.phymode]) {
- if (rate_list_match(local->basic_rates
- [local->hw.conf.phymode],
+ if (local->basic_rates[mode->mode]) {
+ if (rate_list_match(local->basic_rates[mode->mode],
rate->rate))
rate->flags |= IEEE80211_RATE_BASIC;
- } else switch (local->hw.conf.phymode) {
+ } else switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
@@ -182,7 +181,7 @@ void ieee80211_prepare_rates(struct ieee
}
/* Set ERP and MANDATORY flags based on phymode */
- switch (local->hw.conf.phymode) {
+ switch (mode->mode) {
case MODE_IEEE80211A:
if (rate->rate == 60 || rate->rate == 120 ||
rate->rate == 240)
@@ -358,11 +357,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
struct rate_control_extra extra;
memset(&extra, 0, sizeof(extra));
+ extra.mode = tx->u.tx.mode;
extra.mgmt_data = tx->sdata &&
tx->sdata->type == IEEE80211_IF_TYPE_MGMT;
extra.ethertype = tx->ethertype;
- extra.startidx = 0;
- extra.endidx = tx->local->num_curr_rates;
tx->u.tx.rate = rate_control_get_rate(tx->local, tx->dev, tx->skb,
&extra);
@@ -376,20 +374,18 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
}
if (!tx->u.tx.rate)
return TXRX_DROP;
- if (tx->local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (tx->u.tx.mode->mode == MODE_IEEE80211G &&
tx->local->cts_protect_erp_frames && tx->fragmented &&
extra.nonerp) {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
- tx->u.tx.last_frag_rateidx = extra.rateidx;
tx->u.tx.probe_last_frag = extra.probe ? 1 : 0;
tx->u.tx.rate = extra.nonerp;
- tx->u.tx.control->rateidx = extra.nonerp_idx;
+ tx->u.tx.control->rate = extra.nonerp;
tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE;
} else {
tx->u.tx.last_frag_rate = tx->u.tx.rate;
- tx->u.tx.last_frag_rateidx = extra.rateidx;
- tx->u.tx.control->rateidx = extra.rateidx;
+ tx->u.tx.control->rate = tx->u.tx.rate;
}
tx->u.tx.control->tx_rate = tx->u.tx.rate->val;
if ((tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) &&
@@ -657,6 +653,7 @@ static u16 ieee80211_duration(struct iee
int rate, mrate, erp, dur, i;
struct ieee80211_rate *txrate = tx->u.tx.rate;
struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
erp = txrate->flags & IEEE80211_RATE_ERP;
@@ -715,8 +712,8 @@ static u16 ieee80211_duration(struct iee
*/
rate = -1;
mrate = 10; /* use 1 Mbps if everything fails */
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *r = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *r = &mode->rates[i];
if (r->rate > txrate->rate)
break;
@@ -762,6 +759,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data;
u16 dur;
struct ieee80211_tx_control *control = tx->u.tx.control;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
if (!is_multicast_ether_addr(hdr->addr1)) {
if (tx->skb->len + FCS_LEN > tx->local->rts_threshold &&
@@ -788,7 +786,7 @@ ieee80211_tx_h_misc(struct ieee80211_txr
/* Use CTS protection for unicast frames sent using extended rates if
* there are associated non-ERP stations and RTS/CTS is not configured
* for the frame. */
- if (tx->local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211G &&
(tx->u.tx.rate->flags & IEEE80211_RATE_ERP) &&
tx->u.tx.unicast &&
tx->local->cts_protect_erp_frames &&
@@ -812,12 +810,12 @@ ieee80211_tx_h_misc(struct ieee80211_txr
/* Use min(data rate, max base rate) as CTS/RTS rate */
rate = tx->u.tx.rate;
- while (rate > tx->local->curr_rates &&
+ while (rate > mode->rates &&
!(rate->flags & IEEE80211_RATE_BASIC))
rate--;
control->rts_cts_rate = rate->val;
- control->rts_rateidx = (int)(rate - tx->local->curr_rates);
+ control->rts_rate = rate;
}
if (tx->sta) {
@@ -1164,7 +1162,7 @@ static int __ieee80211_tx(struct ieee802
return IEEE80211_TX_FRAG_AGAIN;
if (i == tx->u.tx.num_extra_frag) {
control->tx_rate = tx->u.tx.last_frag_hwrate;
- control->rateidx = tx->u.tx.last_frag_rateidx;
+ control->rate = tx->u.tx.last_frag_rate;
if (tx->u.tx.probe_last_frag)
control->flags |=
IEEE80211_TXCTL_RATE_CTRL_PROBE;
@@ -1209,6 +1207,7 @@ static int ieee80211_tx(struct net_devic
__ieee80211_tx_prepare(&tx, skb, dev, control);
sta = tx.sta;
tx.u.tx.mgmt_interface = mgmt;
+ tx.u.tx.mode = local->hw.conf.mode;
for (handler = local->tx_handlers; *handler != NULL; handler++) {
res = (*handler)(&tx);
@@ -1281,7 +1280,7 @@ retry:
store->extra_frag = tx.u.tx.extra_frag;
store->num_extra_frag = tx.u.tx.num_extra_frag;
store->last_frag_hwrate = tx.u.tx.last_frag_hwrate;
- store->last_frag_rateidx = tx.u.tx.last_frag_rateidx;
+ store->last_frag_rate = tx.u.tx.last_frag_rate;
store->last_frag_rate_ctrl_probe = tx.u.tx.probe_last_frag;
}
return 0;
@@ -1317,7 +1316,7 @@ static void ieee80211_tx_pending(unsigne
tx.u.tx.extra_frag = store->extra_frag;
tx.u.tx.num_extra_frag = store->num_extra_frag;
tx.u.tx.last_frag_hwrate = store->last_frag_hwrate;
- tx.u.tx.last_frag_rateidx = store->last_frag_rateidx;
+ tx.u.tx.last_frag_rate = store->last_frag_rate;
tx.u.tx.probe_last_frag = store->last_frag_rate_ctrl_probe;
ret = __ieee80211_tx(local, store->skb, &tx);
if (ret) {
@@ -1778,7 +1777,7 @@ struct sk_buff * ieee80211_beacon_get(st
if (control) {
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->oper_hw_mode;
rate = rate_control_get_rate(local, local->mdev, skb, &extra);
if (!rate) {
@@ -1815,7 +1814,7 @@ __le16 ieee80211_rts_duration(struct iee
int erp;
u16 dur;
- rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
/* CTS duration */
@@ -1843,7 +1842,7 @@ __le16 ieee80211_ctstoself_duration(stru
int erp;
u16 dur;
- rate = &(local->curr_rates[frame_txctl->rts_rateidx]);
+ rate = frame_txctl->rts_rate;
erp = !!(rate->flags & IEEE80211_RATE_ERP);
/* Data frame duration */
@@ -2027,6 +2026,8 @@ int ieee80211_hw_config(struct ieee80211
local->hw.conf.freq = chan->freq;
local->hw.conf.phymode = mode->mode;
local->hw.conf.antenna_max = chan->antenna_max;
+ local->hw.conf.chan = chan;
+ local->hw.conf.mode = mode;
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d "
@@ -2037,12 +2038,6 @@ int ieee80211_hw_config(struct ieee80211
if (local->ops->config)
ret = local->ops->config(local_to_hw(local), &local->hw.conf);
- if (local->curr_rates != mode->rates)
- rate_control_clear(local);
- local->curr_rates = mode->rates;
- local->num_curr_rates = mode->num_rates;
- ieee80211_prepare_rates(local);
-
return ret;
}
@@ -3893,6 +3888,7 @@ static ieee80211_txrx_result
ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx)
{
struct ieee80211_local *local = tx->local;
+ struct ieee80211_hw_mode *mode = tx->u.tx.mode;
struct sk_buff *skb = tx->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 load = 0, hdrtime;
@@ -3906,10 +3902,10 @@ ieee80211_tx_h_load_stats(struct ieee802
/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
* 1 usec = 1/8 * (1080 / 10) = 13.5 */
- if (local->hw.conf.phymode == MODE_IEEE80211A ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG ||
- (local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
tx->u.tx.rate->flags & IEEE80211_RATE_ERP))
hdrtime = CHAN_UTIL_HDR_SHORT;
else
@@ -3954,17 +3950,18 @@ ieee80211_rx_h_load_stats(struct ieee802
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u32 load = 0, hdrtime;
struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode = local->hw.conf.mode;
int i;
/* Estimate total channel use caused by this frame */
- if (unlikely(local->num_curr_rates < 0))
+ if (unlikely(mode->num_rates < 0))
return TXRX_CONTINUE;
- rate = &local->curr_rates[0];
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].val == rx->u.rx.status->rate) {
- rate = &local->curr_rates[i];
+ rate = &mode->rates[0];
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].val == rx->u.rx.status->rate) {
+ rate = &mode->rates[i];
break;
}
}
@@ -3972,10 +3969,10 @@ ieee80211_rx_h_load_stats(struct ieee802
/* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values,
* 1 usec = 1/8 * (1080 / 10) = 13.5 */
- if (local->hw.conf.phymode == MODE_IEEE80211A ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG ||
- (local->hw.conf.phymode == MODE_IEEE80211G &&
+ if (mode->mode == MODE_IEEE80211A ||
+ mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG ||
+ (mode->mode == MODE_IEEE80211G &&
rate->flags & IEEE80211_RATE_ERP))
hdrtime = CHAN_UTIL_HDR_SHORT;
else
@@ -4738,15 +4735,15 @@ int ieee80211_register_hwmode(struct iee
rate = &(mode->rates[i]);
rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate;
}
+ ieee80211_prepare_rates(local, mode);
- if (!local->curr_rates) {
+ if (!local->oper_hw_mode) {
/* Default to this mode */
local->hw.conf.phymode = mode->mode;
local->oper_hw_mode = local->scan_hw_mode = mode;
local->oper_channel = local->scan_channel = &mode->channels[0];
- local->curr_rates = mode->rates;
- local->num_curr_rates = mode->num_rates;
- ieee80211_prepare_rates(local);
+ local->hw.conf.mode = local->oper_hw_mode;
+ local->hw.conf.chan = local->oper_channel;
}
ieee80211_init_client(local->mdev);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9df8ef0..6709965 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -123,12 +123,12 @@ struct ieee80211_txrx_data {
unsigned int ps_buffered:1;
unsigned int short_preamble:1;
unsigned int probe_last_frag:1;
+ struct ieee80211_hw_mode *mode;
struct ieee80211_rate *rate;
/* use this rate (if set) for last fragment; rate can
* be set to lower rate for the first fragments, e.g.,
* when using CTS protection with IEEE 802.11g. */
struct ieee80211_rate *last_frag_rate;
- int last_frag_rateidx;
int last_frag_hwrate;
int mgmt_interface;
@@ -171,6 +171,7 @@ struct ieee80211_tx_stored_packet {
struct sk_buff **extra_frag;
int last_frag_rateidx;
int last_frag_hwrate;
+ struct ieee80211_rate *last_frag_rate;
unsigned int last_frag_rate_ctrl_probe:1;
};
@@ -396,10 +397,6 @@ struct ieee80211_local {
int iff_allmultis, iff_promiscs;
/* number of interfaces with corresponding IFF_ flags */
- /* Current rate table. This is a pointer to hw->modes structure. */
- struct ieee80211_rate *curr_rates;
- int num_curr_rates;
-
struct rate_control_ref *rate_ctrl;
int next_mode; /* MODE_IEEE80211*
@@ -614,7 +611,8 @@ void ieee80211_key_free(struct ieee80211
void ieee80211_key_release(struct kobject *kobj);
void ieee80211_rx_mgmt(struct ieee80211_local *local, struct sk_buff *skb,
struct ieee80211_rx_status *status, u32 msg_type);
-void ieee80211_prepare_rates(struct ieee80211_local *local);
+void ieee80211_prepare_rates(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode);
void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx);
int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr);
void ieee80211_if_setup(struct net_device *dev);
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index ae224c6..0ebeef3 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -269,6 +269,7 @@ static int ieee80211_ioctl_add_sta(struc
u32 rates;
int i, j;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int add_key_entry = 1;
/* Prevent a race with changing the rate control algorithm */
@@ -306,13 +307,14 @@ static int ieee80211_ioctl_add_sta(struc
sta->listen_interval = param->u.add_sta.listen_interval;
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < sizeof(param->u.add_sta.supp_rates); i++) {
int rate = (param->u.add_sta.supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO ||
- local->hw.conf.phymode == MODE_ATHEROS_TURBOG)
+ if (mode->mode == MODE_ATHEROS_TURBO ||
+ mode->mode == MODE_ATHEROS_TURBOG)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++) {
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++) {
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
@@ -405,6 +407,7 @@ static int ieee80211_ioctl_get_info_sta(
struct prism2_hostapd_param *param)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sta_info *sta;
if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff &&
@@ -417,7 +420,7 @@ static int ieee80211_ioctl_get_info_sta(
param->u.get_info_sta.tx_bytes = stats->tx_bytes;
/* go through all STAs and get STA with lowest max. rate */
param->u.get_info_sta.current_tx_rate =
- local->curr_rates[sta_info_min_txrate_get(local)].rate;
+ sta_info_min_txrate_get(local);
return 0;
}
@@ -434,9 +437,10 @@ static int ieee80211_ioctl_get_info_sta(
param->u.get_info_sta.tx_bytes = sta->tx_bytes;
param->u.get_info_sta.channel_use = sta->channel_use;
param->u.get_info_sta.flags = sta->flags;
- if (sta->txrate >= 0 && sta->txrate < local->num_curr_rates)
+ mode = local->oper_hw_mode;
+ if (sta->txrate >= 0 && sta->txrate < mode->num_rates)
param->u.get_info_sta.current_tx_rate =
- local->curr_rates[sta->txrate].rate;
+ mode->rates[sta->txrate].rate;
param->u.get_info_sta.num_ps_buf_frames =
skb_queue_len(&sta->ps_tx_buf);
param->u.get_info_sta.tx_retry_failed = sta->tx_retry_failed;
@@ -936,6 +940,7 @@ static int ieee80211_ioctl_set_rate_sets
u16 *pos = (u16 *) param->u.set_rate_sets.data;
int left = param_len - ((u8 *) pos - (u8 *) param);
int i, mode, num_supp, num_basic, *supp, *basic, *prev;
+ struct ieee80211_hw_mode *hw_mode;
mode = param->u.set_rate_sets.mode;
num_supp = param->u.set_rate_sets.num_supported_rates;
@@ -983,12 +988,12 @@ static int ieee80211_ioctl_set_rate_sets
local->basic_rates[mode] = basic;
kfree(prev);
- if (mode == local->hw.conf.phymode) {
- /* TODO: should update STA TX rates and remove STAs if they
- * do not have any remaining supported rates after the change
- */
- ieee80211_prepare_rates(local);
- }
+ /* TODO: should update STA TX rates and remove STAs if they
+ * do not have any remaining supported rates after the change
+ */
+ list_for_each_entry(hw_mode, &local->modes_list, list)
+ if (hw_mode->mode == mode)
+ ieee80211_prepare_rates(local, hw_mode);
return 0;
}
@@ -1805,6 +1810,7 @@ int ieee80211_set_channel(struct ieee802
{
struct ieee80211_hw_mode *mode;
int c, set = 0;
+ int ret = -EINVAL;
list_for_each_entry(mode, &local->modes_list, list) {
if (!(local->enabled_modes & (1 << mode->mode)))
@@ -1827,12 +1833,14 @@ int ieee80211_set_channel(struct ieee802
if (set) {
if (local->sta_scanning)
- return 0;
+ ret = 0;
else
- return ieee80211_hw_config(local);
+ ret = ieee80211_hw_config(local);
+
+ rate_control_clear(local);
}
- return -EINVAL;
+ return ret;
}
static int ieee80211_ioctl_siwfreq(struct net_device *dev,
@@ -2283,6 +2291,7 @@ ieee80211_ioctl_force_unicast_rate(struc
int rate)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
int i;
if (sdata->type != IEEE80211_IF_TYPE_AP)
@@ -2293,8 +2302,9 @@ ieee80211_ioctl_force_unicast_rate(struc
return 0;
}
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].rate == rate) {
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
sdata->u.ap.force_unicast_rateidx = i;
return 0;
}
@@ -2309,6 +2319,7 @@ ieee80211_ioctl_max_ratectrl_rate(struct
int rate)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
int i;
if (sdata->type != IEEE80211_IF_TYPE_AP)
@@ -2319,8 +2330,9 @@ ieee80211_ioctl_max_ratectrl_rate(struct
return 0;
}
- for (i = 0; i < local->num_curr_rates; i++) {
- if (local->curr_rates[i].rate == rate) {
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ if (mode->rates[i].rate == rate) {
sdata->u.ap.max_ratectrl_rateidx = i;
return 0;
}
diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h
index 3f51594..3bb09f2 100644
--- a/net/mac80211/ieee80211_rate.h
+++ b/net/mac80211/ieee80211_rate.h
@@ -26,11 +26,10 @@ struct rate_control_extra {
/* values from rate_control_get_rate() to the caller: */
struct ieee80211_rate *probe; /* probe with this rate, or NULL for no
* probing */
- int startidx, endidx, rateidx;
struct ieee80211_rate *nonerp;
- int nonerp_idx;
/* parameters from the caller to rate_control_get_rate(): */
+ struct ieee80211_hw_mode *mode;
int mgmt_data; /* this is data frame that is used for management
* (e.g., IEEE 802.1X EAPOL) */
u16 ethertype;
diff --git a/net/mac80211/ieee80211_scan.c b/net/mac80211/ieee80211_scan.c
index f9b42d4..07f8d9a 100644
--- a/net/mac80211/ieee80211_scan.c
+++ b/net/mac80211/ieee80211_scan.c
@@ -326,7 +326,7 @@ void ieee80211_init_scan(struct ieee8021
local->scan.tx_control.key_idx = HW_KEY_IDX_INVALID;
local->scan.tx_control.flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT;
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->hw.conf.mode;
local->scan.tx_control.tx_rate =
rate_control_get_rate(local, local->mdev,
local->scan.skb, &extra)->val;
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 44646be..a264008 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -480,6 +480,7 @@ static void ieee80211_send_assoc(struct
struct ieee80211_if_sta *ifsta)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *ies;
@@ -498,8 +499,9 @@ static void ieee80211_send_assoc(struct
}
skb_reserve(skb, local->hw.extra_tx_headroom);
+ mode = local->oper_hw_mode;
capab = ifsta->capab;
- if (local->hw.conf.phymode == MODE_IEEE80211G) {
+ if (mode->mode == MODE_IEEE80211G) {
capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
WLAN_CAPABILITY_SHORT_PREAMBLE;
}
@@ -541,26 +543,26 @@ static void ieee80211_send_assoc(struct
*pos++ = ifsta->ssid_len;
memcpy(pos, ifsta->ssid, ifsta->ssid_len);
- len = local->num_curr_rates;
+ len = mode->num_rates;
if (len > 8)
len = 8;
pos = skb_put(skb, len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = len;
for (i = 0; i < len; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
- if (local->num_curr_rates > len) {
- pos = skb_put(skb, local->num_curr_rates - len + 2);
+ if (mode->num_rates > len) {
+ pos = skb_put(skb, mode->num_rates - len + 2);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
- *pos++ = local->num_curr_rates - len;
- for (i = len; i < local->num_curr_rates; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ *pos++ = mode->num_rates - len;
+ for (i = len; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
@@ -771,6 +773,7 @@ static void ieee80211_send_probe_req(str
u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, *supp_rates, *esupp_rates = NULL;
@@ -804,8 +807,9 @@ static void ieee80211_send_probe_req(str
supp_rates = skb_put(skb, 2);
supp_rates[0] = WLAN_EID_SUPP_RATES;
supp_rates[1] = 0;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ mode = local->oper_hw_mode;
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
if (!(rate->flags & IEEE80211_RATE_SUPPORTED))
continue;
if (esupp_rates) {
@@ -820,7 +824,7 @@ static void ieee80211_send_probe_req(str
pos = skb_put(skb, 1);
supp_rates[1]++;
}
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
*pos = rate->rate / 10;
else
*pos = rate->rate / 5;
@@ -1096,6 +1100,7 @@ static void ieee80211_rx_mgmt_assoc_resp
int reassoc)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_hw_mode *mode;
struct sta_info *sta;
u32 rates;
u16 capab_info, status_code, aid;
@@ -1197,20 +1202,21 @@ static void ieee80211_rx_mgmt_assoc_resp
sta->assoc_ap = 1;
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < elems.supp_rates_len; i++) {
int rate = (elems.supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
for (i = 0; i < elems.ext_supp_rates_len; i++) {
int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == rate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == rate)
rates |= BIT(j);
}
sta->supp_rates = rates;
@@ -2124,6 +2130,7 @@ static int ieee80211_sta_join_ibss(struc
struct ieee80211_mgmt *mgmt;
struct ieee80211_tx_control control;
struct ieee80211_rate *rate;
+ struct ieee80211_hw_mode *mode;
struct rate_control_extra extra;
u8 *pos;
struct ieee80211_sub_if_data *sdata;
@@ -2210,7 +2217,7 @@ static int ieee80211_sta_join_ibss(struc
memset(&control, 0, sizeof(control));
memset(&extra, 0, sizeof(extra));
- extra.endidx = local->num_curr_rates;
+ extra.mode = local->oper_hw_mode;
rate = rate_control_get_rate(local, dev, skb, &extra);
if (!rate) {
printk(KERN_DEBUG "%s: Failed to determine TX rate "
@@ -2246,12 +2253,13 @@ static int ieee80211_sta_join_ibss(struc
}
rates = 0;
+ mode = local->oper_hw_mode;
for (i = 0; i < bss->supp_rates_len; i++) {
int bitrate = (bss->supp_rates[i] & 0x7f) * 5;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ if (mode->mode == MODE_ATHEROS_TURBO)
bitrate *= 2;
- for (j = 0; j < local->num_curr_rates; j++)
- if (local->curr_rates[j].rate == bitrate)
+ for (j = 0; j < mode->num_rates; j++)
+ if (mode->rates[j].rate == bitrate)
rates |= BIT(j);
}
ifsta->supp_rates_bits = rates;
@@ -2278,6 +2286,7 @@ static int ieee80211_sta_create_ibss(str
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sta_bss *bss;
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
u8 bssid[ETH_ALEN], *pos;
int i;
@@ -2303,6 +2312,7 @@ static int ieee80211_sta_create_ibss(str
return -ENOMEM;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ mode = local->oper_hw_mode;
if (local->hw.conf.beacon_int == 0)
local->hw.conf.beacon_int = 100;
@@ -2316,11 +2326,11 @@ static int ieee80211_sta_create_ibss(str
bss->capability |= WLAN_CAPABILITY_PRIVACY;
} else
sdata->drop_unencrypted = 0;
- bss->supp_rates_len = local->num_curr_rates;
+ bss->supp_rates_len = mode->num_rates;
pos = bss->supp_rates;
- for (i = 0; i < local->num_curr_rates; i++) {
- int rate = local->curr_rates[i].rate;
- if (local->hw.conf.phymode == MODE_ATHEROS_TURBO)
+ for (i = 0; i < mode->num_rates; i++) {
+ int rate = mode->rates[i].rate;
+ if (mode->mode == MODE_ATHEROS_TURBO)
rate /= 2;
*pos++ = (u8) (rate / 5);
}
diff --git a/net/mac80211/ieee80211_sysfs_sta.c b/net/mac80211/ieee80211_sysfs_sta.c
index e3a6d32..ae62bcf 100644
--- a/net/mac80211/ieee80211_sysfs_sta.c
+++ b/net/mac80211/ieee80211_sysfs_sta.c
@@ -40,10 +40,11 @@ static ssize_t show_sta_##name(const str
static ssize_t show_sta_##name(const struct sta_info *sta, char *buf) \
{ \
struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\
+ struct ieee80211_hw_mode *mode = local->oper_hw_mode; \
return sprintf(buf, "%d\n", \
(sta->field >= 0 && \
- sta->field < local->num_curr_rates) ? \
- local->curr_rates[sta->field].rate : -1); \
+ sta->field < mode->num_rates) ? \
+ mode->rates[sta->field].rate : -1); \
}
#define __STA_ATTR(name) \
diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c
index 16bec51..1b5c82c 100644
--- a/net/mac80211/rc80211_simple.c
+++ b/net/mac80211/rc80211_simple.c
@@ -34,6 +34,7 @@ static void rate_control_rate_inc(struct
struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int i = sta->txrate;
int maxrate;
@@ -43,15 +44,16 @@ static void rate_control_rate_inc(struct
return;
}
+ mode = local->oper_hw_mode;
maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1;
- if (i > local->num_curr_rates)
- i = local->num_curr_rates - 2;
+ if (i > mode->num_rates)
+ i = mode->num_rates - 2;
- while (i + 1 < local->num_curr_rates) {
+ while (i + 1 < mode->num_rates) {
i++;
if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED &&
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED &&
(maxrate < 0 || i <= maxrate)) {
sta->txrate = i;
break;
@@ -64,6 +66,7 @@ static void rate_control_rate_dec(struct
struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_hw_mode *mode;
int i = sta->txrate;
sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev);
@@ -72,13 +75,14 @@ static void rate_control_rate_dec(struct
return;
}
- if (i > local->num_curr_rates)
- i = local->num_curr_rates;
+ mode = local->oper_hw_mode;
+ if (i > mode->num_rates)
+ i = mode->num_rates;
while (i > 0) {
i--;
if (sta->supp_rates & BIT(i) &&
- local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED) {
+ mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) {
sta->txrate = i;
break;
}
@@ -87,21 +91,21 @@ static void rate_control_rate_dec(struct
static struct ieee80211_rate *
-rate_control_lowest_rate(struct ieee80211_local *local)
+rate_control_lowest_rate(struct ieee80211_local *local,
+ struct ieee80211_hw_mode *mode)
{
int i;
- for (i = 0; i < local->num_curr_rates; i++) {
- struct ieee80211_rate *rate = &local->curr_rates[i];
+ for (i = 0; i < mode->num_rates; i++) {
+ struct ieee80211_rate *rate = &mode->rates[i];
- if (rate->flags & IEEE80211_RATE_SUPPORTED
- )
+ if (rate->flags & IEEE80211_RATE_SUPPORTED)
return rate;
}
printk(KERN_DEBUG "rate_control_lowest_rate - no supported rates "
"found\n");
- return &local->curr_rates[0];
+ return &mode->rates[0];
}
@@ -182,7 +186,7 @@ static void rate_control_simple_tx_statu
} else if (per_failed < local->rate_ctrl_num_up) {
rate_control_rate_inc(local, sta);
}
- srctrl->tx_avg_rate_sum += local->curr_rates[sta->txrate].rate;
+ srctrl->tx_avg_rate_sum += status->control.rate->rate;
srctrl->tx_avg_rate_num++;
srctrl->tx_num_failures = 0;
srctrl->tx_num_xmit = 0;
@@ -220,6 +224,7 @@ rate_control_simple_get_rate(void *priv,
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
struct ieee80211_sub_if_data *sdata;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct ieee80211_hw_mode *mode = extra->mode;
struct sta_info *sta;
int rateidx, nonerp_idx;
u16 fc;
@@ -232,13 +237,13 @@ rate_control_simple_get_rate(void *priv,
/* Send management frames and broadcast/multicast data using
* lowest rate. */
/* TODO: this could probably be improved.. */
- return rate_control_lowest_rate(local);
+ return rate_control_lowest_rate(local, mode);
}
sta = sta_info_get(local, hdr->addr1);
if (!sta)
- return rate_control_lowest_rate(local);
+ return rate_control_lowest_rate(local, mode);
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->bss && sdata->bss->force_unicast_rateidx > -1)
@@ -246,23 +251,21 @@ rate_control_simple_get_rate(void *priv,
rateidx = sta->txrate;
- if (rateidx >= local->num_curr_rates)
- rateidx = local->num_curr_rates - 1;
+ if (rateidx >= mode->num_rates)
+ rateidx = mode->num_rates - 1;
sta->last_txrate = rateidx;
nonerp_idx = rateidx;
while (nonerp_idx > 0 &&
- ((local->curr_rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
- !(local->curr_rates[nonerp_idx].flags &
- IEEE80211_RATE_SUPPORTED) ||
+ ((mode->rates[nonerp_idx].flags & IEEE80211_RATE_ERP) ||
+ !(mode->rates[nonerp_idx].flags & IEEE80211_RATE_SUPPORTED) ||
!(sta->supp_rates & BIT(nonerp_idx))))
nonerp_idx--;
- extra->nonerp_idx = nonerp_idx;
- extra->nonerp = &local->curr_rates[extra->nonerp_idx];
+ extra->nonerp = &mode->rates[nonerp_idx];
sta_info_put(sta);
- return &local->curr_rates[rateidx];
+ return &mode->rates[rateidx];
}
@@ -270,15 +273,17 @@ static void rate_control_simple_rate_ini
struct ieee80211_local *local,
struct sta_info *sta)
{
+ struct ieee80211_hw_mode *mode;
int i;
sta->txrate = 0;
+ mode = local->oper_hw_mode;
/* TODO: what is a good starting rate for STA? About middle? Maybe not
* the lowest or the highest rate.. Could consider using RSSI from
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
- for (i = 0; i < local->num_curr_rates; i++) {
+ for (i = 0; i < mode->num_rates; i++) {
if ((sta->supp_rates & BIT(i)) &&
- (local->curr_rates[i].flags & IEEE80211_RATE_SUPPORTED))
+ (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
sta->txrate = i;
}
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 09554aa..2e258cf 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -80,10 +80,12 @@ EXPORT_SYMBOL(sta_info_get);
int sta_info_min_txrate_get(struct ieee80211_local *local)
{
struct sta_info *sta;
+ struct ieee80211_hw_mode *mode;
int min_txrate = 9999999;
int i;
spin_lock_bh(&local->sta_lock);
+ mode = local->oper_hw_mode;
for (i = 0; i < STA_HASH_SIZE; i++) {
sta = local->sta_hash[i];
while (sta) {
@@ -96,7 +98,7 @@ int sta_info_min_txrate_get(struct ieee8
if (min_txrate == 9999999)
min_txrate = 0;
- return min_txrate;
+ return mode->rates[min_txrate].rate;
}
On Fri, 23 Mar 2007 14:05:15 -0400, Michael Wu wrote:
> ieee80211_sta_timer just schedules the workqueue to run. I'm not sure if the
> workqueue can run immediately after that, but even if it did, the sta code
> doesn't depend on the queue of a virtual interface so these lines don't need
> to run in any particular order.
Okay, you're right. Applied, thanks!
Jiri
--
Jiri Benc
SUSE Labs
On Wednesday 28 February 2007 15:39, Michael Wu wrote:
> From: Michael Wu <[email protected]>
>
> This prevents data frames from being queued on the master device if it is
> in the midst of a scan. It also makes both master and virtual interfaces
> properly set trans_start when frames are sent so the network watchdog does
> not try to reset the interfaces. tx_queue_len is left as the default on
> virtual interfaces to allow frames to be queued while the device is
> scanning.
>
And now that all STA interfaces are woken up after a scan, we also can remove
the scan_dev check.
--
d80211: Stop virtual interfaces during scan
From: Michael Wu <[email protected]>
This prevents data frames from being queued on the master device if it is
in the midst of a scan. It also makes both master and virtual interfaces
properly set trans_start when frames are sent. tx_queue_len is left as the
default on virtual interfaces to allow frames to be queued while the device
is scanning.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211.c | 5 +++--
net/mac80211/ieee80211_sta.c | 28 +++++++++++++++++++---------
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c
index 4d08266..52d0e1e 100644
--- a/net/mac80211/ieee80211.c
+++ b/net/mac80211/ieee80211.c
@@ -1148,6 +1148,7 @@ static int __ieee80211_tx(struct ieee802
ret = local->ops->tx(local_to_hw(local), skb, control);
if (ret)
return IEEE80211_TX_AGAIN;
+ local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
}
if (tx->u.tx.extra_frag) {
@@ -1178,6 +1179,7 @@ static int __ieee80211_tx(struct ieee802
control);
if (ret)
return IEEE80211_TX_FRAG_AGAIN;
+ local->mdev->trans_start = jiffies;
ieee80211_led_tx(local, 1);
tx->u.tx.extra_frag[i] = NULL;
}
@@ -1588,6 +1590,7 @@ static int ieee80211_subif_start_xmit(st
skb->nh.raw = skb->data + nh_pos;
skb->h.raw = skb->data + h_pos;
+ dev->trans_start = jiffies;
dev_queue_xmit(skb);
return 0;
@@ -4419,7 +4422,6 @@ void ieee80211_if_setup(struct net_devic
dev->get_stats = ieee80211_get_stats;
dev->open = ieee80211_open;
dev->stop = ieee80211_stop;
- dev->tx_queue_len = 0;
dev->uninit = ieee80211_if_reinit;
dev->destructor = ieee80211_if_free;
}
@@ -4434,7 +4436,6 @@ void ieee80211_if_mgmt_setup(struct net_
dev->stop = ieee80211_mgmt_stop;
dev->type = ARPHRD_IEEE80211_PRISM;
dev->hard_header_parse = header_parse_80211;
- dev->tx_queue_len = 0;
dev->uninit = ieee80211_if_reinit;
dev->destructor = ieee80211_if_free;
}
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index 9d08a37..ce7dc28 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -1918,10 +1918,7 @@ void ieee80211_sta_work(struct work_stru
if (!netif_running(dev))
return;
- /* TODO: scan_dev check should be removed once scan_completed wakes
- * every STA interface */
- if (local->sta_scanning &&
- local->scan_dev == dev)
+ if (local->sta_scanning)
return;
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -2527,7 +2524,7 @@ void ieee80211_scan_completed(struct iee
{
struct ieee80211_local *local = hw_to_local(hw);
struct net_device *dev = local->scan_dev;
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_sub_if_data *sdata;
union iwreq_data wrqu;
printk(KERN_DEBUG "%s: scan completed\n", dev->name);
@@ -2542,15 +2539,23 @@ void ieee80211_scan_completed(struct iee
memset(&wrqu, 0, sizeof(wrqu));
wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
+ netif_wake_queue(sdata->dev);
+
+ if (sdata->type == IEEE80211_IF_TYPE_STA)
+ ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+
+ sdata = IEEE80211_DEV_TO_SUB_IF(dev);
if (sdata->type == IEEE80211_IF_TYPE_IBSS) {
struct ieee80211_if_sta *ifsta = &sdata->u.sta;
if (!ifsta->bssid_set ||
(!ifsta->state == IEEE80211_IBSS_JOINED &&
!ieee80211_sta_active_ibss(dev)))
ieee80211_sta_find_ibss(dev, ifsta);
- /* TODO: need to wake every sta interface */
- } else if (sdata->type == IEEE80211_IF_TYPE_STA)
- ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
}
EXPORT_SYMBOL(ieee80211_scan_completed);
@@ -2637,6 +2642,7 @@ static int ieee80211_sta_start_scan(stru
u8 *ssid, size_t ssid_len)
{
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+ struct ieee80211_sub_if_data *sdata;
if (ssid_len > IEEE80211_MAX_SSID_LEN)
return -EINVAL;
@@ -2680,7 +2686,11 @@ static int ieee80211_sta_start_scan(stru
}
local->sta_scanning = 1;
- /* TODO: stop TX queue? */
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each_entry(sdata, &local->sub_if_list, list)
+ netif_stop_queue(sdata->dev);
+ spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
local->scan_ssid_len = ssid_len;
On Wednesday 28 February 2007 16:44, Michael Wu wrote:
> On Wednesday 28 February 2007 16:42, Michael Wu wrote:
> > This makes scans switch STA interfaces into PS mode so the AP queues
> > frames destined for us while we are scanning. This is achieved by sending
> > a nullfunc data frame with the PS mode bit set before scanning commences,
> > and a PS poll frame after scanning is completed.
>
> Er. I should update the description too..
>
And drop the ps_poll part since we don't use the ps poll frame now..
--
d80211: switch STA interfaces to PS mode during scan
From: Michael Wu <[email protected]>
This makes scans switch STA interfaces into PS mode so the AP queues frames
destined for us while we are scanning. This is achieved by sending a
nullfunc data frame with the PS mode bit set before scanning commences,
and a nullfunc data frame without the PS mode bit set after scanning is
completed.
Signed-off-by: Michael Wu <[email protected]>
---
net/mac80211/ieee80211_sta.c | 51 +++++++++++++++++++++++++++++++++++-------
1 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c
index ce7dc28..087f176 100644
--- a/net/mac80211/ieee80211_sta.c
+++ b/net/mac80211/ieee80211_sta.c
@@ -2520,6 +2520,37 @@ int ieee80211_sta_set_bssid(struct net_d
}
+static void ieee80211_send_nullfunc(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ int powersave)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr *nullfunc;
+ u16 fc;
+
+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+ if (!skb) {
+ printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+ "frame\n", sdata->dev->name);
+ return;
+ }
+ skb_reserve(skb, local->hw.extra_tx_headroom);
+
+ nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+ memset(nullfunc, 0, 24);
+ fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS;
+ if (powersave)
+ fc |= IEEE80211_FCTL_PM;
+ nullfunc->frame_control = cpu_to_le16(fc);
+ memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
+ memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+ memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
+
+ ieee80211_sta_tx(sdata->dev, skb, 0);
+}
+
+
void ieee80211_scan_completed(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -2541,10 +2572,12 @@ void ieee80211_scan_completed(struct iee
spin_lock_bh(&local->sub_if_lock);
list_for_each_entry(sdata, &local->sub_if_list, list) {
- netif_wake_queue(sdata->dev);
-
- if (sdata->type == IEEE80211_IF_TYPE_STA)
+ if (sdata->type == IEEE80211_IF_TYPE_STA) {
+ if (sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 0);
ieee80211_sta_timer((unsigned long)&sdata->u.sta);
+ }
+ netif_wake_queue(sdata->dev);
}
spin_unlock_bh(&local->sub_if_lock);
@@ -2664,9 +2697,6 @@ static int ieee80211_sta_start_scan(stru
* ResultCode: SUCCESS, INVALID_PARAMETERS
*/
- /* TODO: if assoc, move to power save mode for the duration of the
- * scan */
-
if (local->sta_scanning) {
if (local->scan_dev == dev)
return 0;
@@ -2688,8 +2718,12 @@ static int ieee80211_sta_start_scan(stru
local->sta_scanning = 1;
spin_lock_bh(&local->sub_if_lock);
- list_for_each_entry(sdata, &local->sub_if_list, list)
+ list_for_each_entry(sdata, &local->sub_if_list, list) {
netif_stop_queue(sdata->dev);
+ if (sdata->type == IEEE80211_IF_TYPE_STA &&
+ sdata->u.sta.associated)
+ ieee80211_send_nullfunc(local, sdata, 1);
+ }
spin_unlock_bh(&local->sub_if_lock);
if (ssid) {
@@ -2703,7 +2737,8 @@ static int ieee80211_sta_start_scan(stru
list);
local->scan_channel_idx = 0;
local->scan_dev = dev;
- schedule_delayed_work(&local->scan_work, 0);
+ /* TODO: start scan as soon as all nullfunc frames are ACKed */
+ schedule_delayed_work(&local->scan_work, IEEE80211_CHANNEL_TIME);
return 0;
}
On Wed, 21 Mar 2007 14:08:51 -0400, Michael Wu wrote:
> On Wednesday 21 March 2007 13:25, Jiri Benc wrote:
> > Does this really work? Last time I checked, when the carrier is off, no
> > frames are sent to hard_start_xmit.
> >
> This applies only to STA interfaces, whose frames to the master dev are
> dropped anyways if there is no association.
True, you're right.
Thanks,
Jiri
--
Jiri Benc
SUSE Labs
On Thu, 1 Mar 2007 12:00:18 -0500, Michael Wu wrote:
> This switches the code from curr_rates and num_curr_rates to directly using
> the mode and converts portions of the code to use pointers to rates instead
> of indices to refer to rates. Two new fields are introduced in struct
> ieee80211_conf which may replace the channel/frequency/channel_val/phymode
> fields in the future. The rate control is now cleared only when the
> operating channel is changed.
Looks correct to me. I'll apply it to my tree (if John isn't
faster :-)).
Thanks,
Jiri
--
Jiri Benc
SUSE Labs