aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-05-25 00:38:24 -0700
committerDavid S. Miller <davem@davemloft.net>2009-05-25 00:38:24 -0700
commit45ea4ea2af358fe316c918381c7868f9418cad09 (patch)
tree4deb3d87b26e884b06929fe33740d45e78fbdcab /net
parentdddc045e2fdd4eb8d7dfac29bff191d639fff8c3 (diff)
parenta2e2322d83df82a57ba456cfa604c8b8f7b04670 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/debugfs.c16
-rw-r--r--net/mac80211/ibss.c33
-rw-r--r--net/mac80211/ieee80211_i.h43
-rw-r--r--net/mac80211/key.c6
-rw-r--r--net/mac80211/main.c16
-rw-r--r--net/mac80211/mesh.c40
-rw-r--r--net/mac80211/mesh.h16
-rw-r--r--net/mac80211/mesh_hwmp.c8
-rw-r--r--net/mac80211/mesh_plink.c21
-rw-r--r--net/mac80211/mlme.c227
-rw-r--r--net/mac80211/pm.c80
-rw-r--r--net/mac80211/rx.c94
-rw-r--r--net/mac80211/scan.c18
-rw-r--r--net/mac80211/spectmgmt.c101
-rw-r--r--net/mac80211/sta_info.c6
-rw-r--r--net/mac80211/sta_info.h2
-rw-r--r--net/mac80211/tx.c2
-rw-r--r--net/mac80211/util.c116
-rw-r--r--net/mac80211/wext.c5
-rw-r--r--net/mac80211/wme.c30
-rw-r--r--net/wireless/Kconfig8
-rw-r--r--net/wireless/Makefile1
-rw-r--r--net/wireless/core.c7
-rw-r--r--net/wireless/core.h14
-rw-r--r--net/wireless/debugfs.c131
-rw-r--r--net/wireless/debugfs.h14
-rw-r--r--net/wireless/nl80211.c66
-rw-r--r--net/wireless/reg.c216
-rw-r--r--net/wireless/util.c320
-rw-r--r--net/wireless/wext-compat.c7
-rw-r--r--net/wireless/wext.c32
31 files changed, 1240 insertions, 456 deletions
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index e7682fe1c59..11c72311f35 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -52,14 +52,6 @@ static const struct file_operations name## _ops = { \
DEBUGFS_READONLY_FILE(frequency, 20, "%d",
local->hw.conf.channel->center_freq);
-DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d",
- local->hw.wiphy->rts_threshold);
-DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d",
- local->hw.wiphy->frag_threshold);
-DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d",
- local->hw.wiphy->retry_short);
-DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d",
- local->hw.wiphy->retry_long);
DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d",
local->total_ps_buffered);
DEBUGFS_READONLY_FILE(wep_iv, 20, "%#08x",
@@ -303,10 +295,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
local->debugfs.keys = debugfs_create_dir("keys", phyd);
DEBUGFS_ADD(frequency);
- DEBUGFS_ADD(rts_threshold);
- DEBUGFS_ADD(fragmentation_threshold);
- DEBUGFS_ADD(short_retry_limit);
- DEBUGFS_ADD(long_retry_limit);
DEBUGFS_ADD(total_ps_buffered);
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(tsf);
@@ -359,10 +347,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
void debugfs_hw_del(struct ieee80211_local *local)
{
DEBUGFS_DEL(frequency);
- DEBUGFS_DEL(rts_threshold);
- DEBUGFS_DEL(fragmentation_threshold);
- DEBUGFS_DEL(short_retry_limit);
- DEBUGFS_DEL(long_retry_limit);
DEBUGFS_DEL(total_ps_buffered);
DEBUGFS_DEL(wep_iv);
DEBUGFS_DEL(tsf);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index c236079ed38..0b30277eb36 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -535,9 +535,9 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
bssid = ifibss->bssid;
bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid,
ifibss->ssid, ifibss->ssid_len,
- capability,
WLAN_CAPABILITY_IBSS |
- WLAN_CAPABILITY_PRIVACY);
+ WLAN_CAPABILITY_PRIVACY,
+ capability);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (bss)
@@ -737,6 +737,9 @@ static void ieee80211_ibss_work(struct work_struct *work)
struct ieee80211_if_ibss *ifibss;
struct sk_buff *skb;
+ if (WARN_ON(local->suspended))
+ return;
+
if (!netif_running(sdata->dev))
return;
@@ -773,10 +776,36 @@ static void ieee80211_ibss_timer(unsigned long data)
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
+ if (local->quiescing) {
+ ifibss->timer_running = true;
+ return;
+ }
+
set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
queue_work(local->hw.workqueue, &ifibss->work);
}
+#ifdef CONFIG_PM
+void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ cancel_work_sync(&ifibss->work);
+ if (del_timer_sync(&ifibss->timer))
+ ifibss->timer_running = true;
+}
+
+void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+ if (ifibss->timer_running) {
+ add_timer(&ifibss->timer);
+ ifibss->timer_running = false;
+ }
+}
+#endif
+
void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 9d1514727f6..c088c46704a 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -293,6 +293,7 @@ struct ieee80211_if_managed {
int auth_tries; /* retries for auth req */
int assoc_tries; /* retries for assoc req */
+ unsigned long timers_running; /* used for quiesce/restart */
bool powersave; /* powersave requested for this iface */
unsigned long request;
@@ -333,6 +334,9 @@ struct ieee80211_if_ibss {
unsigned long request;
unsigned long last_scan_completed;
+
+ bool timer_running;
+
bool fixed_bssid;
bool fixed_channel;
@@ -358,6 +362,8 @@ struct ieee80211_if_mesh {
struct timer_list mesh_path_timer;
struct sk_buff_head skb_queue;
+ unsigned long timers_running;
+
bool housekeeping;
u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN];
@@ -609,6 +615,21 @@ struct ieee80211_local {
unsigned int filter_flags; /* FIF_* */
struct iw_statistics wstats;
bool tim_in_locked_section; /* see ieee80211_beacon_get() */
+
+ /*
+ * suspended is true if we finished all the suspend _and_ we have
+ * not yet come up from resume. This is to be used by mac80211
+ * to ensure driver sanity during suspend and mac80211's own
+ * sanity. It can eventually be used for WoW as well.
+ */
+ bool suspended;
+
+ /*
+ * quiescing is true during the suspend process _only_ to
+ * ease timer cancelling etc.
+ */
+ bool quiescing;
+
int tx_headroom; /* required headroom for hardware/radiotap */
/* Tasklet and skb queue to process calls from IRQ mode. All frames
@@ -758,10 +779,6 @@ struct ieee80211_local {
struct dentry *rcdir;
struct dentry *rcname;
struct dentry *frequency;
- struct dentry *rts_threshold;
- struct dentry *fragmentation_threshold;
- struct dentry *short_retry_limit;
- struct dentry *long_retry_limit;
struct dentry *total_ps_buffered;
struct dentry *wep_iv;
struct dentry *tsf;
@@ -938,6 +955,11 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
+void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_channel_sw_ie *sw_elem,
+ struct ieee80211_bss *bss);
+void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata);
/* IBSS code */
void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
@@ -950,6 +972,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
struct cfg80211_ibss_params *params);
int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_restart(struct ieee80211_sub_if_data *sdata);
/* scan/BSS handling */
void ieee80211_scan_work(struct work_struct *work);
@@ -960,6 +984,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
int ieee80211_scan_results(struct ieee80211_local *local,
struct iw_request_info *info,
char *buf, size_t len);
+void ieee80211_scan_cancel(struct ieee80211_local *local);
ieee80211_rx_result
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb,
@@ -1035,14 +1060,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
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,
- struct ieee80211_bss *bss);
-void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
- u16 capab_info, u8 *pwr_constr_elem,
- u8 pwr_constr_elem_len);
/* Suspend/resume and hw reconfiguration */
int ieee80211_reconfig(struct ieee80211_local *local);
@@ -1068,8 +1085,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
/* utility functions/constants */
extern void *mac80211_wiphy_privid; /* for wiphy privid */
-extern const unsigned char rfc1042_header[6];
-extern const unsigned char bridge_tunnel_header[6];
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum nl80211_iftype type);
int ieee80211_frame_duration(struct ieee80211_local *local, size_t len,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 827ea8e6ee0..ce267565e18 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -320,7 +320,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
case ALG_TKIP:
key->conf.iv_len = TKIP_IV_LEN;
key->conf.icv_len = TKIP_ICV_LEN;
- if (seq && seq_len == 6) {
+ if (seq) {
for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
key->u.tkip.rx[i].iv32 =
get_unaligned_le32(&seq[2]);
@@ -332,7 +332,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
case ALG_CCMP:
key->conf.iv_len = CCMP_HDR_LEN;
key->conf.icv_len = CCMP_MIC_LEN;
- if (seq && seq_len == CCMP_PN_LEN) {
+ if (seq) {
for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
for (j = 0; j < CCMP_PN_LEN; j++)
key->u.ccmp.rx_pn[i][j] =
@@ -342,7 +342,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
case ALG_AES_CMAC:
key->conf.iv_len = 0;
key->conf.icv_len = sizeof(struct ieee80211_mmie);
- if (seq && seq_len == 6)
+ if (seq)
for (j = 0; j < 6; j++)
key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
break;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 76df5eabf26..6b7e92eaab4 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -219,18 +219,26 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
u32 changed)
{
struct ieee80211_local *local = sdata->local;
+ static const u8 zero[ETH_ALEN] = { 0 };
if (!changed)
return;
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
- else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ /*
+ * While not associated, claim a BSSID of all-zeroes
+ * so that drivers don't do any weird things with the
+ * BSSID at that time.
+ */
+ if (sdata->vif.bss_conf.assoc)
+ sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
+ else
+ sdata->vif.bss_conf.bssid = zero;
+ } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
else if (sdata->vif.type == NL80211_IFTYPE_AP)
sdata->vif.bss_conf.bssid = sdata->dev->dev_addr;
else if (ieee80211_vif_is_mesh(&sdata->vif)) {
- static const u8 zero[ETH_ALEN] = { 0 };
sdata->vif.bss_conf.bssid = zero;
} else {
WARN_ON(1);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9000b01a167..fc712e60705 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -21,6 +21,9 @@
#define CAPAB_OFFSET 17
#define ACCEPT_PLINKS 0x80
+#define TMR_RUNNING_HK 0
+#define TMR_RUNNING_MP 1
+
int mesh_allocated;
static struct kmem_cache *rm_cache;
@@ -45,6 +48,12 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
ifmsh->housekeeping = true;
+
+ if (local->quiescing) {
+ set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
+ return;
+ }
+
queue_work(local->hw.workqueue, &ifmsh->work);
}
@@ -343,6 +352,11 @@ static void ieee80211_mesh_path_timer(unsigned long data)
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_local *local = sdata->local;
+ if (local->quiescing) {
+ set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
+ return;
+ }
+
queue_work(local->hw.workqueue, &ifmsh->work);
}
@@ -424,6 +438,32 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
}
+#ifdef CONFIG_PM
+void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ /* might restart the timer but that doesn't matter */
+ cancel_work_sync(&ifmsh->work);
+
+ /* use atomic bitops in case both timers fire at the same time */
+
+ if (del_timer_sync(&ifmsh->housekeeping_timer))
+ set_bit(TMR_RUNNING_HK, &ifmsh->timers_running);
+ if (del_timer_sync(&ifmsh->mesh_path_timer))
+ set_bit(TMR_RUNNING_MP, &ifmsh->timers_running);
+}
+
+void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+
+ if (test_and_clear_bit(TMR_RUNNING_HK, &ifmsh->timers_running))
+ add_timer(&ifmsh->housekeeping_timer);
+ if (test_and_clear_bit(TMR_RUNNING_MP, &ifmsh->timers_running))
+ add_timer(&ifmsh->mesh_path_timer);
+}
+#endif
void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index d891d7ddccd..c7d72819cdd 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -191,12 +191,8 @@ struct mesh_rmc {
#define PLINK_CATEGORY 30
#define MESH_PATH_SEL_CATEGORY 32
-/* Mesh Header Flags */
-#define IEEE80211S_FLAGS_AE 0x3
-
/* Public interfaces */
/* Various */
-int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr);
int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
struct ieee80211_sub_if_data *sdata);
int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr,
@@ -267,6 +263,8 @@ void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_discard_frame(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
+void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
+void mesh_path_restart(struct ieee80211_sub_if_data *sdata);
#ifdef CONFIG_MAC80211_MESH
extern int mesh_allocated;
@@ -294,10 +292,20 @@ static inline void mesh_path_activate(struct mesh_path *mpath)
void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local);
+void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata);
+void mesh_plink_quiesce(struct sta_info *sta);
+void mesh_plink_restart(struct sta_info *sta);
#else
#define mesh_allocated 0
static inline void
ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {}
+static inline void ieee80211_mesh_quiesce(struct ieee80211_sub_if_data *sdata)
+{}
+static inline void ieee80211_mesh_restart(struct ieee80211_sub_if_data *sdata)
+{}
+static inline void mesh_plink_quiesce(struct sta_info *sta) {}
+static inline void mesh_plink_restart(struct sta_info *sta) {}
#endif
#endif /* IEEE80211S_H */
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 60b35accda9..003cb470ac8 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -836,8 +836,14 @@ void mesh_path_timer(unsigned long data)
mpath = rcu_dereference(mpath);
if (!mpath)
goto endmpathtimer;
- spin_lock_bh(&mpath->state_lock);
sdata = mpath->sdata;
+
+ if (sdata->local->quiescing) {
+ rcu_read_unlock();
+ return;
+ }
+
+ spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED ||
(!(mpath->flags & MESH_PATH_RESOLVING)))
mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED);
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index a8bbdeca013..cb14253587f 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -266,6 +266,11 @@ static void mesh_plink_timer(unsigned long data)
*/
sta = (struct sta_info *) data;
+ if (sta->sdata->local->quiescing) {
+ sta->plink_timer_was_running = true;
+ return;
+ }
+
spin_lock_bh(&sta->lock);
if (sta->ignore_plink_timer) {
sta->ignore_plink_timer = false;
@@ -322,6 +327,22 @@ static void mesh_plink_timer(unsigned long data)
}
}
+#ifdef CONFIG_PM
+void mesh_plink_quiesce(struct sta_info *sta)
+{
+ if (del_timer_sync(&sta->plink_timer))
+ sta->plink_timer_was_running = true;
+}
+
+void mesh_plink_restart(struct sta_info *sta)
+{
+ if (sta->plink_timer_was_running) {
+ add_timer(&sta->plink_timer);
+ sta->plink_timer_was_running = false;
+ }
+}
+#endif
+
static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
{
sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index ae030688771..509469cb926 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -33,10 +33,13 @@
#define IEEE80211_ASSOC_TIMEOUT (HZ / 5)
#define IEEE80211_ASSOC_MAX_TRIES 3
#define IEEE80211_MONITORING_INTERVAL (2 * HZ)
-#define IEEE80211_PROBE_WAIT (HZ / 20)
+#define IEEE80211_PROBE_WAIT (HZ / 5)
#define IEEE80211_PROBE_IDLE_TIME (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
+#define TMR_RUNNING_TIMER 0
+#define TMR_RUNNING_CHANSW 1
+
/* utils */
static int ecw2cw(int ecw)
{
@@ -121,10 +124,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
(hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) {
switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- channel_type = NL80211_CHAN_HT40PLUS;
+ if (!(local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40PLUS))
+ channel_type = NL80211_CHAN_HT40PLUS;
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- channel_type = NL80211_CHAN_HT40MINUS;
+ if (!(local->hw.conf.channel->flags &
+ IEEE80211_CHAN_NO_HT40MINUS))
+ channel_type = NL80211_CHAN_HT40MINUS;
break;
}
}
@@ -349,13 +356,13 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
- if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) {
+ if (flags & IEEE80211_CHAN_NO_HT40PLUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
break;
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
- if (flags & IEEE80211_CHAN_NO_FAT_BELOW) {
+ if (flags & IEEE80211_CHAN_NO_HT40MINUS) {
cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
cap &= ~IEEE80211_HT_CAP_SGI_40;
}
@@ -482,6 +489,108 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
ieee80211_tx_skb(sdata, skb, 0);
}
+/* spectrum management related things */
+static void ieee80211_chswitch_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
+ struct ieee80211_bss *bss;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ if (!netif_running(sdata->dev))
+ return;
+
+ bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
+ sdata->local->hw.conf.channel->center_freq,
+ ifmgd->ssid, ifmgd->ssid_len);
+ if (!bss)
+ goto exit;
+
+ sdata->local->oper_channel = sdata->local->csa_channel;
+ /* XXX: shouldn't really modify cfg80211-owned data! */
+ if (!ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL))
+ bss->cbss.channel = sdata->local->oper_channel;
+
+ ieee80211_rx_bss_put(sdata->local, bss);
+exit:
+ ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+ ieee80211_wake_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+}
+
+static void ieee80211_chswitch_timer(unsigned long data)
+{
+ struct ieee80211_sub_if_data *sdata =
+ (struct ieee80211_sub_if_data *) data;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ if (sdata->local->quiescing) {
+ set_bit(TMR_RUNNING_CHANSW, &ifmgd->timers_running);
+ return;
+ }
+
+ queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+}
+
+void ieee80211_sta_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_managed *ifmgd = &sdata->u.mgd;
+ int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
+
+ if (ifmgd->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 (ifmgd->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;
+
+ sdata->local->csa_channel = new_ch;
+
+ if (sw_elem->count <= 1) {
+ queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
+ } else {
+ ieee80211_stop_queues_by_reason(&sdata->local->hw,
+ IEEE80211_QUEUE_STOP_REASON_CSA);
+ ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+ mod_timer(&ifmgd->chswitch_timer,
+ jiffies +
+ msecs_to_jiffies(sw_elem->count *
+ bss->cbss.beacon_interval));
+ }
+}
+
+static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+ u16 capab_info, u8 *pwr_constr_elem,
+ u8 pwr_constr_elem_len)
+{
+ struct ieee80211_conf *conf = &sdata->local->hw.conf;
+
+ if (!(capab_info & WLAN_CAPABILITY_SPECTRUM_MGMT))
+ return;
+
+ /* Power constraint IE length should be 1 octet */
+ if (pwr_constr_elem_len != 1)
+ return;
+
+ if ((*pwr_constr_elem <= conf->channel->max_power) &&
+ (*pwr_constr_elem != sdata->local->power_constr_level)) {
+ sdata->local->power_constr_level = *pwr_constr_elem;
+ ieee80211_hw_config(sdata->local, 0);
+ }
+}
+
/* powersave */
static void ieee80211_enable_ps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
@@ -613,6 +722,9 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
{
struct ieee80211_local *local = (void *) data;
+ if (local->quiescing)
+ return;
+
queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
}
@@ -865,6 +977,10 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
* changed or not.
*/
bss_info_changed |= BSS_CHANGED_BASIC_RATES;
+
+ /* And the BSSID changed - we're associated now */
+ bss_info_changed |= BSS_CHANGED_BSSID;
+
ieee80211_bss_info_change_notify(sdata, bss_info_changed);
/* will be same as sdata */
@@ -1064,6 +1180,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
}
ieee80211_hw_config(local, config_changed);
+
+ /* And the BSSID changed -- not very interesting here */
+ changed |= BSS_CHANGED_BSSID;
ieee80211_bss_info_change_notify(sdata, changed);
rcu_read_lock();
@@ -1270,8 +1389,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
ifmgd->flags |= IEEE80211_STA_PROBEREQ_POLL;
ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
ifmgd->ssid_len, NULL, 0);
+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
goto unlock;
-
}
if (time_after(jiffies, sta->last_rx + IEEE80211_PROBE_IDLE_TIME)) {
@@ -1280,15 +1399,16 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
ifmgd->ssid_len, NULL, 0);
}
+ if (!disassoc)
+ mod_timer(&ifmgd->timer,
+ jiffies + IEEE80211_MONITORING_INTERVAL);
+
unlock:
rcu_read_unlock();
if (disassoc)
ieee80211_set_disassoc(sdata, true, true,
WLAN_REASON_PREV_AUTH_NOT_VALID);
- else
- mod_timer(&ifmgd->timer, jiffies +
- IEEE80211_MONITORING_INTERVAL);
}
@@ -1732,7 +1852,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
(memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
struct ieee80211_channel_sw_ie *sw_elem =
(struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
- ieee80211_process_chanswitch(sdata, sw_elem, bss);
+ ieee80211_sta_process_chanswitch(sdata, sw_elem, bss);
}
ieee80211_rx_bss_put(local, bss);
@@ -1820,6 +1940,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
return;
+ if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+ if (net_ratelimit()) {
+ printk(KERN_DEBUG "%s: cancelling probereq poll due "
+ "to a received beacon\n", sdata->dev->name);
+ }
+#endif
+ ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+ }
+
ncrc = crc32_be(0, (void *)&mgmt->u.beacon.beacon_int, 4);
ncrc = ieee802_11_parse_elems_crc(mgmt->u.beacon.variable,
len - baselen, &elems,
@@ -1829,16 +1959,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len,
ifmgd->aid);
- ncrc = crc32_be(ncrc, (void *)&directed_tim, sizeof(directed_tim));
+ if (ncrc != ifmgd->beacon_crc) {
+ ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems,
+ true);
- if (ncrc == ifmgd->beacon_crc)
- return;
- ifmgd->beacon_crc = ncrc;
-
- ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
-
- ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
- elems.wmm_param_len);
+ ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
+ elems.wmm_param_len);
+ }
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
if (directed_tim) {
@@ -1863,6 +1990,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
}
+ if (ncrc == ifmgd->beacon_crc)
+ return;
+ ifmgd->beacon_crc = ncrc;
+
if (elems.erp_info && elems.erp_info_len >= 1) {
erp_valid = true;
erp_value = elems.erp_info[0];
@@ -1997,6 +2128,11 @@ static void ieee80211_sta_timer(unsigned long data)
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
+ if (local->quiescing) {
+ set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
+ return;
+ }
+
set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
queue_work(local->hw.workqueue, &ifmgd->work);
}
@@ -2129,6 +2265,17 @@ static void ieee80211_sta_work(struct work_struct *work)
if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
return;
+
+ /*
+ * Nothing should have been stuffed into the workqueue during
+ * the suspend->resume cycle. If this WARN is seen then there
+ * is a bug with either the driver suspend or something in
+ * mac80211 stuffing into the workqueue which we haven't yet
+ * cleared during mac80211's suspend cycle.
+ */
+ if (WARN_ON(local->suspended))
+ return;
+
ifmgd = &sdata->u.mgd;
while ((skb = skb_dequeue(&ifmgd->skb_queue)))
@@ -2196,6 +2343,38 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
}
}
+#ifdef CONFIG_PM
+void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+ /*
+ * we need to use atomic bitops for the running bits
+ * only because both timers might fire at the same
+ * time -- the code here is properly synchronised.
+ */
+
+ cancel_work_sync(&ifmgd->work);
+ cancel_work_sync(&ifmgd->beacon_loss_work);
+ if (del_timer_sync(&ifmgd->timer))
+ set_bit(TMR_RUNNING_TIMER, &ifmgd->timers_running);
+