* [RFC v2] mac80211: Add 802.11h CSA support
@ 2008-12-30 10:26 Sujith
2008-12-30 10:35 ` Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Sujith @ 2008-12-30 10:26 UTC (permalink / raw)
To: linux-wireless; +Cc: johannes, jouni.malinen
Move to the advertised channel on reception of
a CSA element. This is needed for 802.11h compliance.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
---
v2
--
* Drivers might use a mutex in the config() callback, so use a
workqueue to call ieee80211_hw_config().
Address initial review comments:
* Remove CSA_DISABLED channel flag
* Use new queue stop/wake helpers, with a new reason code
net/mac80211/ieee80211_i.h | 8 ++++
net/mac80211/iface.c | 2 +
net/mac80211/mlme.c | 9 ++++
net/mac80211/rx.c | 7 +++
net/mac80211/spectmgmt.c | 88 ++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 117718b..3b5272d 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -259,6 +259,7 @@ struct mesh_preq_queue {
#define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12)
#define IEEE80211_STA_PRIVACY_INVOKED BIT(13)
#define IEEE80211_STA_TKIP_WEP_USED BIT(14)
+#define IEEE80211_STA_CSA_RECEIVED BIT(15)
/* flags for MLME request */
#define IEEE80211_STA_REQ_SCAN 0
#define IEEE80211_STA_REQ_DIRECT_PROBE 1
@@ -283,7 +284,9 @@ enum ieee80211_sta_mlme_state {
struct ieee80211_if_sta {
struct timer_list timer;
+ struct timer_list chswitch_timer;
struct work_struct work;
+ struct work_struct chswitch_work;
u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
u8 ssid[IEEE80211_MAX_SSID_LEN];
enum ieee80211_sta_mlme_state state;
@@ -542,6 +545,7 @@ enum {
enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_DRIVER,
IEEE80211_QUEUE_STOP_REASON_PS,
+ IEEE80211_QUEUE_STOP_REASON_CSA
};
/* maximum number of hardware queues we support. */
@@ -964,6 +968,10 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len);
+void ieee80211_chswitch_timer(unsigned long data);
+void ieee80211_chswitch_work(struct work_struct *work);
+void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_sw_ie *sw_elem);
/* utility functions/constants */
extern void *mac80211_wiphy_privid; /* for wiphy privid */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 2c7a87d..f927641 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -443,6 +443,7 @@ static int ieee80211_stop(struct net_device *dev)
WLAN_REASON_DEAUTH_LEAVING);
memset(sdata->u.sta.bssid, 0, ETH_ALEN);
+ del_timer_sync(&sdata->u.sta.chswitch_timer);
del_timer_sync(&sdata->u.sta.timer);
/*
* If the timer fired while we waited for it, it will have
@@ -452,6 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
* it no longer is.
*/
cancel_work_sync(&sdata->u.sta.work);
+ cancel_work_sync(&sdata->u.sta.chswitch_work);
/*
* When we get here, the interface is marked down.
* Call synchronize_rcu() to wait for the RX path
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e317c6d..eea18ec 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1645,6 +1645,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
if (!bss)
return;
+ if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3)) {
+ struct ieee80211_channel_sw_ie *sw_elem =
+ (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
+ ieee80211_process_chanswitch(sdata, sw_elem);
+ }
+
/* was just updated in ieee80211_bss_info_update */
beacon_timestamp = bss->timestamp;
@@ -2447,8 +2453,11 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ifsta = &sdata->u.sta;
INIT_WORK(&ifsta->work, ieee80211_sta_work);
+ INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work);
setup_timer(&ifsta->timer, ieee80211_sta_timer,
(unsigned long) sdata);
+ setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer,
+ (unsigned long) sdata);
skb_queue_head_init(&ifsta->skb_queue);
ifsta->capab = WLAN_CAPABILITY_ESS;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 384cb3b..a44b109 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1613,6 +1613,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
return RX_DROP_MONITOR;
ieee80211_process_measurement_req(sdata, mgmt, len);
break;
+ case WLAN_ACTION_SPCT_CHL_SWITCH:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.chan_switch)))
+ return RX_DROP_MONITOR;
+ ieee80211_process_chanswitch(sdata,
+ &mgmt->u.action.u.chan_switch.sw_elem);
+ break;
}
break;
default:
diff --git a/net/mac80211/spectmgmt.c b/net/mac80211/spectmgmt.c
index f72bad6..3eec256 100644
--- a/net/mac80211/spectmgmt.c
+++ b/net/mac80211/spectmgmt.c
@@ -84,3 +84,91 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
mgmt->sa, mgmt->bssid,
mgmt->u.action.u.measurement.dialog_token);
}
+
+void ieee80211_chswitch_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+ struct ieee80211_bss *bss;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ if (!netif_running(sdata->dev))
+ return;
+
+ bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
+ if (!bss)
+ goto exit;
+
+ if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
+ bss->freq = sdata->local->oper_channel->center_freq;
+
+ ieee80211_rx_bss_put(sdata->local, bss);
+exit:
+ ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+ ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
+void ieee80211_chswitch_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+
+ queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work);
+}
+
+void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_sw_ie *sw_elem)
+{
+ struct ieee80211_bss *bss;
+ struct ieee80211_channel *new_ch;
+ struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+ int ret, exp;
+ int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
+
+ /* FIXME: Handle ADHOC later */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return;
+
+ if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED)
+ return;
+
+ if (sdata->local->sw_scanning || sdata->local->hw_scanning)
+ return;
+
+ /* Disregard subsequent beacons if we are already running a timer
+ processing a CSA */
+
+ if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED)
+ return;
+
+ new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+ if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
+ return;
+
+ bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifsta->ssid, ifsta->ssid_len);
+ if (!bss)
+ return;
+
+ sdata->local->oper_channel = new_ch;
+
+ if (sw_elem->count <= 1) {
+ ret = ieee80211_hw_config(sdata->local,
+ IEEE80211_CONF_CHANGE_CHANNEL);
+ if (!ret)
+ bss->freq = new_freq;
+ } else {
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+ ifsta->flags |= IEEE80211_STA_CSA_RECEIVED;
+ exp = sw_elem->count * (1024 * bss->beacon_int / 1000 * HZ / 1000);
+ mod_timer(&ifsta->chswitch_timer, jiffies + exp);
+ }
+
+ ieee80211_rx_bss_put(sdata->local, bss);
+}
--
1.6.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC v2] mac80211: Add 802.11h CSA support
2008-12-30 10:26 [RFC v2] mac80211: Add 802.11h CSA support Sujith
@ 2008-12-30 10:35 ` Johannes Berg
2008-12-30 10:39 ` Sujith
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2008-12-30 10:35 UTC (permalink / raw)
To: Sujith; +Cc: linux-wireless, jouni.malinen
[-- Attachment #1: Type: text/plain, Size: 2223 bytes --]
On Tue, 2008-12-30 at 15:56 +0530, Sujith wrote:
> Move to the advertised channel on reception of
> a CSA element. This is needed for 802.11h compliance.
Looks good, two small things:
> @@ -1645,6 +1645,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
> if (!bss)
> return;
>
> + if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3)) {
> + struct ieee80211_channel_sw_ie *sw_elem =
> + (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
> + ieee80211_process_chanswitch(sdata, sw_elem);
> + }
> +
> /* was just updated in ieee80211_bss_info_update */
> beacon_timestamp = bss->timestamp;
We already have a bss pointer here, would it be better to pass that in,
avoid the bss lookup, and do the bss lookup manually in the action frame
case, to avoid a double lookup here?
> +void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
> + struct ieee80211_channel_sw_ie *sw_elem)
> +{
> + struct ieee80211_bss *bss;
> + struct ieee80211_channel *new_ch;
> + struct ieee80211_if_sta *ifsta = &sdata->u.sta;
> + int ret, exp;
> + int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
> +
> + /* FIXME: Handle ADHOC later */
> + if (sdata->vif.type != NL80211_IFTYPE_STATION)
> + return;
> +
> + if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED)
> + return;
> +
> + if (sdata->local->sw_scanning || sdata->local->hw_scanning)
> + return;
> +
> + /* Disregard subsequent beacons if we are already running a timer
> + processing a CSA */
> +
> + if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED)
> + return;
> +
> + new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
> + if (!new_ch || new_ch->flags & IEEE80211_CHAN_DISABLED)
> + return;
> +
> + bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid,
> + sdata->local->hw.conf.channel->center_freq,
> + ifsta->ssid, ifsta->ssid_len);
> + if (!bss)
> + return;
> +
> + sdata->local->oper_channel = new_ch;
> +
> + if (sw_elem->count <= 1) {
> + ret = ieee80211_hw_config(sdata->local,
> + IEEE80211_CONF_CHANGE_CHANNEL);
Didn't you want to put this into the workqueue?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC v2] mac80211: Add 802.11h CSA support
2008-12-30 10:35 ` Johannes Berg
@ 2008-12-30 10:39 ` Sujith
2008-12-30 10:45 ` Johannes Berg
0 siblings, 1 reply; 5+ messages in thread
From: Sujith @ 2008-12-30 10:39 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, jouni.malinen
Johannes Berg wrote:
> We already have a bss pointer here, would it be better to pass that in,
> avoid the bss lookup, and do the bss lookup manually in the action frame
> case, to avoid a double lookup here?
>
We don't have a bss pointer in ieee80211_rx_h_action(), where CSA
action frames are handled too.
> Didn't you want to put this into the workqueue?
Calling ieee80211_hw_config() from the timer was problematic since
drivers might use a mutex, this won't matter.
But if it makes things clearer, I can add it to the workqueue here too.
Sujith
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC v2] mac80211: Add 802.11h CSA support
2008-12-30 10:39 ` Sujith
@ 2008-12-30 10:45 ` Johannes Berg
2008-12-30 10:51 ` Sujith
0 siblings, 1 reply; 5+ messages in thread
From: Johannes Berg @ 2008-12-30 10:45 UTC (permalink / raw)
To: Sujith; +Cc: linux-wireless, jouni.malinen
[-- Attachment #1: Type: text/plain, Size: 1113 bytes --]
On Tue, 2008-12-30 at 16:09 +0530, Sujith wrote:
> Johannes Berg wrote:
> > We already have a bss pointer here, would it be better to pass that in,
> > avoid the bss lookup, and do the bss lookup manually in the action frame
> > case, to avoid a double lookup here?
> >
>
> We don't have a bss pointer in ieee80211_rx_h_action(), where CSA
> action frames are handled too.
Yeah I know, I'm just wondering if it's worth saving the lookup in the
other case by doing the lookup outside of ieee80211_process_chanswitch()
and in ieee80211_rx_h_action()
> > Didn't you want to put this into the workqueue?
>
> Calling ieee80211_hw_config() from the timer was problematic since
> drivers might use a mutex, this won't matter.
> But if it makes things clearer, I can add it to the workqueue here too.
But the RX stuff (rx_h_action) is from a tasklet or directly from the
driver, and in the tasklet we can't sleep either, and if we call back
from ieee80211_rx() into rx_h_action into the driver again via config()
the driver might not like it? Or am I totally off base right now?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC v2] mac80211: Add 802.11h CSA support
2008-12-30 10:45 ` Johannes Berg
@ 2008-12-30 10:51 ` Sujith
0 siblings, 0 replies; 5+ messages in thread
From: Sujith @ 2008-12-30 10:51 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless, jouni.malinen
Johannes Berg wrote:
> Yeah I know, I'm just wondering if it's worth saving the lookup in the
> other case by doing the lookup outside of ieee80211_process_chanswitch()
> and in ieee80211_rx_h_action()
Actually, this might be better since I haven't seen any AP send a CSA action
frame, it was always through the beacon that it was announced.
But then, it is not often that an AP would switch channels.
I'll change the interface anyway.
> But the RX stuff (rx_h_action) is from a tasklet or directly from the
> driver, and in the tasklet we can't sleep either, and if we call back
> from ieee80211_rx() into rx_h_action into the driver again via config()
> the driver might not like it? Or am I totally off base right now?
True, I'll add it to the workqueue here.
Sujith
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-12-30 10:53 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-30 10:26 [RFC v2] mac80211: Add 802.11h CSA support Sujith
2008-12-30 10:35 ` Johannes Berg
2008-12-30 10:39 ` Sujith
2008-12-30 10:45 ` Johannes Berg
2008-12-30 10:51 ` Sujith
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox