All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/5] d80211: Do not require drivers to implement reset callback
  2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
  2007-02-28 20:39 ` [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan Michael Wu
  2007-02-28 20:39 ` [PATCH 3/5] d80211: Set carrier status for STA interfaces Michael Wu
@ 2007-02-28 20:39 ` Michael Wu
  2007-03-01  2:14   ` [PATCH] d80211: Remove tx_timeout callback Michael Wu
  2007-02-28 20:39 ` [PATCH 4/5] d80211: Stop virtual interfaces during scan Michael Wu
  2007-03-01 17:00 ` [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
  4 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 20:39 UTC (permalink / raw)
  To: linux-wireless

From: Michael Wu <flamingice@sourmilk.net>

This prevents drivers from crashing if there is a TX timeout and the reset
callback isn't implemented.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 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);


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues
@ 2007-02-28 20:39 Michael Wu
  2007-02-28 20:39 ` [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan Michael Wu
                   ` (4 more replies)
  0 siblings, 5 replies; 21+ messages in thread
From: Michael Wu @ 2007-02-28 20:39 UTC (permalink / raw)
  To: linux-wireless

From: Michael Wu <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }
 
 


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 4/5] d80211: Stop virtual interfaces during scan
  2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
                   ` (2 preceding siblings ...)
  2007-02-28 20:39 ` [PATCH 2/5] d80211: Do not require drivers to implement reset callback Michael Wu
@ 2007-02-28 20:39 ` Michael Wu
  2007-03-01  5:40   ` Michael Wu
  2007-03-01 17:00 ` [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
  4 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 20:39 UTC (permalink / raw)
  To: linux-wireless

From: Michael Wu <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 3/5] d80211: Set carrier status for STA interfaces
  2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
  2007-02-28 20:39 ` [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan Michael Wu
@ 2007-02-28 20:39 ` Michael Wu
  2007-03-21 17:25   ` Jiri Benc
  2007-02-28 20:39 ` [PATCH 2/5] d80211: Do not require drivers to implement reset callback Michael Wu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 20:39 UTC (permalink / raw)
  To: linux-wireless

From: Michael Wu <flamingice@sourmilk.net>

This makes STA interfaces set the carrier status based on the current
association status.

Signed-off-by: Michael Wu <flamingice@sourmilk.net>
---

 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);
 }
 
 


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
@ 2007-02-28 20:39 ` Michael Wu
  2007-02-28 21:09   ` Jouni Malinen
  2007-02-28 20:39 ` [PATCH 3/5] d80211: Set carrier status for STA interfaces Michael Wu
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 20:39 UTC (permalink / raw)
  To: linux-wireless

From: Michael Wu <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-02-28 20:39 ` [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan Michael Wu
@ 2007-02-28 21:09   ` Jouni Malinen
  2007-02-28 21:42     ` Michael Wu
  0 siblings, 1 reply; 21+ messages in thread
From: Jouni Malinen @ 2007-02-28 21:09 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-02-28 21:09   ` Jouni Malinen
@ 2007-02-28 21:42     ` Michael Wu
  2007-02-28 21:44       ` Michael Wu
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 21:42 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 4313 bytes --]

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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-02-28 21:42     ` Michael Wu
@ 2007-02-28 21:44       ` Michael Wu
  2007-03-01  5:43         ` Michael Wu
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-02-28 21:44 UTC (permalink / raw)
  To: Jouni Malinen; +Cc: linux-wireless, Jiri Benc

[-- Attachment #1: Type: text/plain, Size: 4450 bytes --]

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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH] d80211: Remove tx_timeout callback
  2007-02-28 20:39 ` [PATCH 2/5] d80211: Do not require drivers to implement reset callback Michael Wu
@ 2007-03-01  2:14   ` Michael Wu
  2007-03-21 17:26     ` Jiri Benc
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-01  2:14 UTC (permalink / raw)
  To: linux-wireless; +Cc: Jiri Benc

[-- Attachment #1: Type: text/plain, Size: 2212 bytes --]

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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/5] d80211: Stop virtual interfaces during scan
  2007-02-28 20:39 ` [PATCH 4/5] d80211: Stop virtual interfaces during scan Michael Wu
@ 2007-03-01  5:40   ` Michael Wu
  2007-03-23 15:54     ` Jiri Benc
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-01  5:40 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 5200 bytes --]

On Wednesday 28 February 2007 15:39, Michael Wu wrote:
> From: Michael Wu <flamingice@sourmilk.net>
>
> 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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-02-28 21:44       ` Michael Wu
@ 2007-03-01  5:43         ` Michael Wu
  2007-03-23 16:01           ` Jiri Benc
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-01  5:43 UTC (permalink / raw)
  To: Jiri Benc; +Cc: Jouni Malinen, linux-wireless

[-- Attachment #1: Type: text/plain, Size: 4087 bytes --]

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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues
  2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
                   ` (3 preceding siblings ...)
  2007-02-28 20:39 ` [PATCH 4/5] d80211: Stop virtual interfaces during scan Michael Wu
@ 2007-03-01 17:00 ` Michael Wu
  2007-03-21 17:22   ` Jiri Benc
  4 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-01 17:00 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 36367 bytes --]

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 <flamingice@sourmilk.net>

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 <flamingice@sourmilk.net>
---

 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;
 }
 
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH 1/5] d80211: Remove curr_rates and fix related  concurrency issues
  2007-03-01 17:00 ` [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
@ 2007-03-21 17:22   ` Jiri Benc
  0 siblings, 0 replies; 21+ messages in thread
From: Jiri Benc @ 2007-03-21 17:22 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/5] d80211: Set carrier status for STA interfaces
  2007-02-28 20:39 ` [PATCH 3/5] d80211: Set carrier status for STA interfaces Michael Wu
@ 2007-03-21 17:25   ` Jiri Benc
  2007-03-21 18:08     ` Michael Wu
  0 siblings, 1 reply; 21+ messages in thread
From: Jiri Benc @ 2007-03-21 17:25 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH] d80211: Remove tx_timeout callback
  2007-03-01  2:14   ` [PATCH] d80211: Remove tx_timeout callback Michael Wu
@ 2007-03-21 17:26     ` Jiri Benc
  0 siblings, 0 replies; 21+ messages in thread
From: Jiri Benc @ 2007-03-21 17:26 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/5] d80211: Set carrier status for STA interfaces
  2007-03-21 17:25   ` Jiri Benc
@ 2007-03-21 18:08     ` Michael Wu
  2007-03-23 15:24       ` Jiri Benc
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-21 18:08 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

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

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 3/5] d80211: Set carrier status for STA interfaces
  2007-03-21 18:08     ` Michael Wu
@ 2007-03-23 15:24       ` Jiri Benc
  0 siblings, 0 replies; 21+ messages in thread
From: Jiri Benc @ 2007-03-23 15:24 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 4/5] d80211: Stop virtual interfaces during scan
  2007-03-01  5:40   ` Michael Wu
@ 2007-03-23 15:54     ` Jiri Benc
  0 siblings, 0 replies; 21+ messages in thread
From: Jiri Benc @ 2007-03-23 15:54 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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 <flamingice@sourmilk.net>
> >
> > 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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during  scan
  2007-03-01  5:43         ` Michael Wu
@ 2007-03-23 16:01           ` Jiri Benc
  2007-03-23 18:05             ` Michael Wu
  0 siblings, 1 reply; 21+ messages in thread
From: Jiri Benc @ 2007-03-23 16:01 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan
  2007-03-23 16:01           ` Jiri Benc
@ 2007-03-23 18:05             ` Michael Wu
  2007-03-23 19:01               ` Jiri Benc
  0 siblings, 1 reply; 21+ messages in thread
From: Michael Wu @ 2007-03-23 18:05 UTC (permalink / raw)
  To: Jiri Benc; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 931 bytes --]

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

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH 5/5] d80211: switch STA interfaces to PS mode during  scan
  2007-03-23 18:05             ` Michael Wu
@ 2007-03-23 19:01               ` Jiri Benc
  0 siblings, 0 replies; 21+ messages in thread
From: Jiri Benc @ 2007-03-23 19:01 UTC (permalink / raw)
  To: Michael Wu; +Cc: linux-wireless

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

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2007-03-23 19:01 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-02-28 20:39 [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
2007-02-28 20:39 ` [PATCH 5/5] d80211: switch STA interfaces to PS mode during scan Michael Wu
2007-02-28 21:09   ` Jouni Malinen
2007-02-28 21:42     ` Michael Wu
2007-02-28 21:44       ` Michael Wu
2007-03-01  5:43         ` Michael Wu
2007-03-23 16:01           ` Jiri Benc
2007-03-23 18:05             ` Michael Wu
2007-03-23 19:01               ` Jiri Benc
2007-02-28 20:39 ` [PATCH 3/5] d80211: Set carrier status for STA interfaces Michael Wu
2007-03-21 17:25   ` Jiri Benc
2007-03-21 18:08     ` Michael Wu
2007-03-23 15:24       ` Jiri Benc
2007-02-28 20:39 ` [PATCH 2/5] d80211: Do not require drivers to implement reset callback Michael Wu
2007-03-01  2:14   ` [PATCH] d80211: Remove tx_timeout callback Michael Wu
2007-03-21 17:26     ` Jiri Benc
2007-02-28 20:39 ` [PATCH 4/5] d80211: Stop virtual interfaces during scan Michael Wu
2007-03-01  5:40   ` Michael Wu
2007-03-23 15:54     ` Jiri Benc
2007-03-01 17:00 ` [PATCH 1/5] d80211: Remove curr_rates and fix related concurrency issues Michael Wu
2007-03-21 17:22   ` Jiri Benc

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.