summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-05-18 14:48:30 -0700
committerDavid S. Miller <davem@davemloft.net>2009-05-18 14:48:30 -0700
commit82d048186e403f36e083b37ad42aa90abb7dcaac (patch)
treedc0b92ace036ef435318f38ef35b8c6e6b84103a
parent62551d3ea05242d97d47f26fb517b2dfdb752310 (diff)
parentd3707d9918d47c0997a6b1e4ae24e7ab55e43796 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c51
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c59
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c89
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c62
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c233
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c14
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c56
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/wireless/mwl8k.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c2
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig2
-rw-r--r--include/linux/ieee80211.h8
-rw-r--r--include/linux/nl80211.h51
-rw-r--r--include/net/cfg80211.h57
-rw-r--r--include/net/mac80211.h28
-rw-r--r--net/mac80211/cfg.c50
-rw-r--r--net/mac80211/debugfs.c38
-rw-r--r--net/mac80211/ibss.c77
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/iface.c3
-rw-r--r--net/mac80211/key.c21
-rw-r--r--net/mac80211/key.h3
-rw-r--r--net/mac80211/main.c14
-rw-r--r--net/mac80211/mlme.c41
-rw-r--r--net/mac80211/rx.c58
-rw-r--r--net/mac80211/scan.c32
-rw-r--r--net/mac80211/tx.c5
-rw-r--r--net/mac80211/util.c60
-rw-r--r--net/mac80211/wext.c282
-rw-r--r--net/mac80211/wme.c2
-rw-r--r--net/wireless/core.c10
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/ibss.c60
-rw-r--r--net/wireless/nl80211.c128
-rw-r--r--net/wireless/util.c45
-rw-r--r--net/wireless/wext-compat.c286
-rw-r--r--net/wireless/wext.c20
49 files changed, 1116 insertions, 1013 deletions
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 44fee5ae8925..a2fda702b620 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -694,7 +694,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
#undef TMP_VAL_VPD_TABLE
}
-static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
+static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
@@ -805,11 +805,9 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
}
*pTxPowerIndexOffset = 0;
-
- return true;
}
-static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
+static void ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *ratesArray,
u16 cfgCtl,
@@ -1041,10 +1039,9 @@ static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hw *ah,
ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
}
- return true;
}
-static int ath9k_hw_4k_set_txpower(struct ath_hw *ah,
+static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 cfgCtl,
u8 twiceAntennaReduction,
@@ -1065,22 +1062,13 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah,
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
}
- if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan,
+ ath9k_hw_set_4k_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower,
- powerLimit)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set "
- "tx power per rate table\n");
- return -EIO;
- }
+ powerLimit);
- if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set power table\n");
- return -EIO;
- }
+ ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset);
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
@@ -1168,7 +1156,6 @@ static int ath9k_hw_4k_set_txpower(struct ath_hw *ah,
else
ah->regulatory.max_power_level = ratesArray[i];
- return 0;
}
static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
@@ -2103,7 +2090,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
return;
}
-static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
+static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
@@ -2255,13 +2242,11 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
}
*pTxPowerIndexOffset = 0;
-
- return true;
#undef SM_PD_GAIN
#undef SM_PDGAIN_B
}
-static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
+static void ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *ratesArray,
u16 cfgCtl,
@@ -2549,10 +2534,9 @@ static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
targetPowerCckExt.tPow2x[0];
}
}
- return true;
}
-static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
+static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan,
u16 cfgCtl,
u8 twiceAntennaReduction,
@@ -2575,22 +2559,13 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
}
- if (!ath9k_hw_set_def_power_per_rate_table(ah, chan,
+ ath9k_hw_set_def_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower,
- powerLimit)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set "
- "tx power per rate table\n");
- return -EIO;
- }
+ powerLimit);
- if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "ath9k_hw_set_txpower: unable to set power table\n");
- return -EIO;
- }
+ ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset);
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
@@ -2717,8 +2692,6 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
"Invalid chainmask configuration\n");
break;
}
-
- return 0;
}
static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 7c59dc47f912..67b8bd12941a 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -494,7 +494,7 @@ struct eeprom_ops {
struct ath9k_channel *chan);
void (*set_board_values)(struct ath_hw *hw, struct ath9k_channel *chan);
void (*set_addac)(struct ath_hw *hw, struct ath9k_channel *chan);
- int (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
+ void (*set_txpower)(struct ath_hw *hw, struct ath9k_channel *chan,
u16 cfgCtl, u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower, u8 powerLimit);
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 5879c731e9e7..4acfab514916 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1274,7 +1274,6 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
int i, regWrites = 0;
struct ieee80211_channel *channel = chan->chan;
u32 modesIndex, freqIndex;
- int status;
switch (chan->chanmode) {
case CHANNEL_A:
@@ -1376,17 +1375,12 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
if (OLC_FOR_AR9280_20_LATER)
ath9k_olc_init(ah);
- status = ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(&ah->regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit));
- if (status != 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Error initializing transmit power\n");
- return -EIO;
- }
+ ah->eep_ops->set_txpower(ah, chan,
+ ath9k_regd_get_ctl(&ah->regulatory, chan),
+ channel->max_antenna_gain * 2,
+ channel->max_power * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->regulatory.power_limit));
if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1617,11 +1611,9 @@ static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)
switch (type) {
case ATH9K_RESET_POWER_ON:
return ath9k_hw_set_reset_power_on(ah);
- break;
case ATH9K_RESET_WARM:
case ATH9K_RESET_COLD:
return ath9k_hw_set_reset(ah, type);
- break;
default:
return false;
}
@@ -1703,11 +1695,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
ath9k_hw_set_regs(ah, chan, macmode);
if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!(ath9k_hw_ar9280_set_channel(ah, chan))) {
- DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
- "Failed to set channel\n");
- return false;
- }
+ ath9k_hw_ar9280_set_channel(ah, chan);
} else {
if (!(ath9k_hw_set_channel(ah, chan))) {
DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
@@ -1716,16 +1704,12 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
}
}
- if (ah->eep_ops->set_txpower(ah, chan,
+ ah->eep_ops->set_txpower(ah, chan,
ath9k_regd_get_ctl(&ah->regulatory, chan),
channel->max_antenna_gain * 2,
channel->max_power * 2,
min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit)) != 0) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "Error initializing transmit power\n");
- return false;
- }
+ (u32) ah->regulatory.power_limit));
synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY;
if (IS_CHAN_B(chan))
@@ -2313,13 +2297,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);
- if (AR_SREV_9280_10_OR_LATER(ah)) {
- if (!(ath9k_hw_ar9280_set_channel(ah, chan)))
- return -EIO;
- } else {
+ if (AR_SREV_9280_10_OR_LATER(ah))
+ ath9k_hw_ar9280_set_channel(ah, chan);
+ else
if (!(ath9k_hw_set_channel(ah, chan)))
return -EIO;
- }
for (i = 0; i < AR_NUM_DCU; i++)
REG_WRITE(ah, AR_DQCUMASK(i), 1 << i);
@@ -3750,22 +3732,19 @@ bool ath9k_hw_disable(struct ath_hw *ah)
return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD);
}
-bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit)
{
struct ath9k_channel *chan = ah->curchan;
struct ieee80211_channel *channel = chan->chan;
ah->regulatory.power_limit = min(limit, (u32) MAX_RATE_POWER);
- if (ah->eep_ops->set_txpower(ah, chan,
- ath9k_regd_get_ctl(&ah->regulatory, chan),
- channel->max_antenna_gain * 2,
- channel->max_power * 2,
- min((u32) MAX_RATE_POWER,
- (u32) ah->regulatory.power_limit)) != 0)
- return false;
-
- return true;
+ ah->eep_ops->set_txpower(ah, chan,
+ ath9k_regd_get_ctl(&ah->regulatory, chan),
+ channel->max_antenna_gain * 2,
+ channel->max_power * 2,
+ min((u32) MAX_RATE_POWER,
+ (u32) ah->regulatory.power_limit));
}
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac)
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index ddb24c47ebcf..dd8508ef6e05 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -590,7 +590,7 @@ u32 ath9k_hw_getrxfilter(struct ath_hw *ah);
void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits);
bool ath9k_hw_phy_disable(struct ath_hw *ah);
bool ath9k_hw_disable(struct ath_hw *ah);
-bool ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
+void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit);
void ath9k_hw_setmac(struct ath_hw *ah, const u8 *mac);
void ath9k_hw_setopmode(struct ath_hw *ah);
void ath9k_hw_setmcastfilter(struct ath_hw *ah, u32 filter0, u32 filter1);
diff --git a/drivers/net/wireless/ath/ath9k/phy.c b/drivers/net/wireless/ath/ath9k/phy.c
index 5ec9ce91d979..aaa941561c36 100644
--- a/drivers/net/wireless/ath/ath9k/phy.c
+++ b/drivers/net/wireless/ath/ath9k/phy.c
@@ -96,9 +96,8 @@ ath9k_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
return true;
}
-bool
-ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
- struct ath9k_channel *chan)
+void ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
+ struct ath9k_channel *chan)
{
u16 bMode, fracMode, aModeRefSel = 0;
u32 freq, ndiv, channelSel = 0, channelFrac = 0, reg32 = 0;
@@ -169,8 +168,6 @@ ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
ah->curchan = chan;
ah->curchan_rad_index = -1;
-
- return true;
}
static void
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 296d0e985f25..c70f530642f6 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -17,7 +17,7 @@
#ifndef PHY_H
#define PHY_H
-bool ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
+void ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
struct ath9k_channel
*chan);
bool ath9k_hw_set_channel(struct ath_hw *ah,
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 41f1d66cfeba..5b0c6e5bda92 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -1110,6 +1110,11 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
+ /* Determine HW type */
+ pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+
+ IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
+
if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
IWL_DEBUG_INFO(priv, "RTP type \n");
else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
@@ -1163,7 +1168,6 @@ static void iwl3945_nic_config(struct iwl_priv *priv)
int iwl3945_hw_nic_init(struct iwl_priv *priv)
{
- u8 rev_id;
int rc;
unsigned long flags;
struct iwl_rx_queue *rxq = &priv->rxq;
@@ -1172,12 +1176,6 @@ int iwl3945_hw_nic_init(struct iwl_priv *priv)
priv->cfg->ops->lib->apm_ops.init(priv);
spin_unlock_irqrestore(&priv->lock, flags);
- /* Determine HW type */
- rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
- if (rc)
- return rc;
- IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
-
rc = priv->cfg->ops->lib->apm_ops.set_pwr_src(priv, IWL_PWR_SRC_VMAIN);
if (rc)
return rc;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index 0a71bb55d0ee..4c88e8715df2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -100,6 +100,7 @@ struct iwl_scale_tbl_info {
u8 is_fat; /* 1 = 40 MHz channel width */
u8 is_dup; /* 1 = duplicated data streams */
u8 action; /* change modulation; IWL_[LEGACY/SISO/MIMO]_SWITCH_* */
+ u8 max_search; /* maximun number of tables we can search */
s32 *expected_tpt; /* throughput metrics; expected_tpt_G, etc. */
u32 current_rate; /* rate_n_flags, uCode API format */
struct iwl_rate_scale_data win[IWL_RATE_COUNT]; /* rate histories */
@@ -160,6 +161,7 @@ struct iwl_lq_sta {
#ifdef CONFIG_MAC80211_DEBUGFS
struct dentry *rs_sta_dbgfs_scale_table_file;
struct dentry *rs_sta_dbgfs_stats_table_file;
+ struct dentry *rs_sta_dbgfs_rate_scale_data_file;
struct dentry *rs_sta_dbgfs_tx_agg_tid_en_file;
u32 dbg_fixed_rate;
#endif
@@ -579,6 +581,7 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
tbl->is_dup = 0;
tbl->ant_type = (ant_msk >> RATE_MCS_ANT_POS);
tbl->lq_type = LQ_NONE;
+ tbl->max_search = IWL_MAX_SEARCH;
/* legacy rate format */
if (!(rate_n_flags & RATE_MCS_HT_MSK)) {
@@ -612,8 +615,10 @@ static int rs_get_tbl_info_from_mcs(const u32 rate_n_flags,
tbl->lq_type = LQ_MIMO2;
/* MIMO3 */
} else {
- if (num_of_ant == 3)
+ if (num_of_ant == 3) {
+ tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
tbl->lq_type = LQ_MIMO3;
+ }
}
}
return 0;
@@ -771,6 +776,7 @@ static u32 rs_get_lower_rate(struct iwl_lq_sta *lq_sta,
tbl->is_fat = 0;
tbl->is_SGI = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
}
rate_mask = rs_get_supported_rates(lq_sta, NULL, tbl->lq_type);
@@ -1026,6 +1032,7 @@ static void rs_set_stay_in_table(struct iwl_priv *priv, u8 is_legacy,
lq_sta->total_failed = 0;
lq_sta->total_success = 0;
lq_sta->flush_timer = jiffies;
+ lq_sta->action_counter = 0;
}
/*
@@ -1205,6 +1212,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
tbl->lq_type = LQ_MIMO2;
tbl->is_dup = lq_sta->is_dup;
tbl->action = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_mimo2_rate;
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
@@ -1270,6 +1278,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
tbl->lq_type = LQ_MIMO3;
tbl->is_dup = lq_sta->is_dup;
tbl->action = 0;
+ tbl->max_search = IWL_MAX_11N_MIMO3_SEARCH;
rate_mask = lq_sta->active_mimo3_rate;
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
@@ -1328,6 +1337,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
tbl->is_dup = lq_sta->is_dup;
tbl->lq_type = LQ_SISO;
tbl->action = 0;
+ tbl->max_search = IWL_MAX_SEARCH;
rate_mask = lq_sta->active_siso_rate;
if (iwl_is_fat_tx_allowed(priv, &sta->ht_cap))
@@ -1384,15 +1394,15 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
int ret = 0;
+ u8 update_search_tbl_counter = 0;
for (; ;) {
+ lq_sta->action_counter++;
switch (tbl->action) {
case IWL_LEGACY_SWITCH_ANTENNA1:
case IWL_LEGACY_SWITCH_ANTENNA2:
IWL_DEBUG_RATE(priv, "LQ: Legacy toggle Antenna\n");
- lq_sta->action_counter++;
-
if ((tbl->action == IWL_LEGACY_SWITCH_ANTENNA1 &&
tx_chains_num <= 1) ||
(tbl->action == IWL_LEGACY_SWITCH_ANTENNA2 &&
@@ -1408,6 +1418,7 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
if (rs_toggle_antenna(valid_tx_ant,
&search_tbl->current_rate, search_tbl)) {
+ update_search_tbl_counter = 1;
rs_set_expected_tpt_table(lq_sta, search_tbl);
goto out;
}
@@ -1489,6 +1500,8 @@ out:
tbl->action++;
if (tbl->action > IWL_LEGACY_SWITCH_MIMO3_ABC)
tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
return 0;
}
@@ -1511,6 +1524,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
u8 start_action = tbl->action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 update_search_tbl_counter = 0;
int ret;
for (;;) {
@@ -1531,8 +1545,10 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
memcpy(search_tbl, tbl, sz);
if (rs_toggle_antenna(valid_tx_ant,
- &search_tbl->current_rate, search_tbl))
+ &search_tbl->current_rate, search_tbl)) {
+ update_search_tbl_counter = 1;
goto out;
+ }
break;
case IWL_SISO_SWITCH_MIMO2_AB:
case IWL_SISO_SWITCH_MIMO2_AC:
@@ -1586,6 +1602,7 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
search_tbl->current_rate =
rate_n_flags_from_tbl(priv, search_tbl,
index, is_green);
+ update_search_tbl_counter = 1;
goto out;
case IWL_SISO_SWITCH_MIMO3_ABC:
IWL_DEBUG_RATE(priv, "LQ: SISO switch to MIMO3\n");
@@ -1617,6 +1634,9 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
tbl->action++;
if (tbl->action > IWL_SISO_SWITCH_MIMO3_ABC)
tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
return 0;
}
@@ -1638,6 +1658,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
u8 start_action = tbl->action;
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
+ u8 update_search_tbl_counter = 0;
int ret;
for (;;) {
@@ -1655,8 +1676,10 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
memcpy(search_tbl, tbl, sz);
if (rs_toggle_antenna(valid_tx_ant,
- &search_tbl->current_rate, search_tbl))
+ &search_tbl->current_rate, search_tbl)) {
+ update_search_tbl_counter = 1;
goto out;
+ }
break;
case IWL_MIMO2_SWITCH_SISO_A:
case IWL_MIMO2_SWITCH_SISO_B:
@@ -1713,6 +1736,7 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
search_tbl->current_rate =
rate_n_flags_from_tbl(priv, search_tbl,
index, is_green);
+ update_search_tbl_counter = 1;
goto out;
case IWL_MIMO2_SWITCH_MIMO3_ABC:
@@ -1745,6 +1769,9 @@ static int rs_move_mimo2_to_other(struct iwl_priv *priv,
tbl->action++;
if (tbl->action > IWL_MIMO2_SWITCH_MIMO3_ABC)
tbl->action = IWL_MIMO2_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
return 0;
}
@@ -1768,6 +1795,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
u8 valid_tx_ant = priv->hw_params.valid_tx_ant;
u8 tx_chains_num = priv->hw_params.tx_chains_num;
int ret;
+ u8 update_search_tbl_counter = 0;
for (;;) {
lq_sta->action_counter++;
@@ -1866,6 +1894,7 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
search_tbl->current_rate =
rate_n_flags_from_tbl(priv, search_tbl,
index, is_green);
+ update_search_tbl_counter = 1;
goto out;
}
tbl->action++;
@@ -1882,6 +1911,9 @@ static int rs_move_mimo3_to_other(struct iwl_priv *priv,
tbl->action++;
if (tbl->action > IWL_MIMO3_SWITCH_GI)
tbl->action = IWL_MIMO3_SWITCH_ANTENNA1;
+ if (update_search_tbl_counter)
+ search_tbl->action = tbl->action;
+
return 0;
}
@@ -2326,8 +2358,7 @@ lq_update:
* before next round of mode comparisons. */
tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]);
if (is_legacy(tbl1->lq_type) && !conf_is_ht(conf) &&
- lq_sta->action_counter >= 1) {
- lq_sta->action_counter = 0;
+ lq_sta->action_counter > tbl1->max_search) {
IWL_DEBUG_RATE(priv, "LQ: STAY in legacy table\n");
rs_set_stay_in_table(priv, 1, lq_sta);
}
@@ -2336,7 +2367,7 @@ lq_update:
* have been tried and compared, stay in this best modulation
* mode for a while before next round of mode comparisons. */
if (lq_sta->enable_counter &&
- (lq_sta->action_counter >= IWL_ACTION_LIMIT)) {
+ (lq_sta->action_counter >= tbl1->max_search)) {
if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
(lq_sta->tx_agg_tid_en & (1 << tid)) &&
(tid != MAX_TID_COUNT)) {
@@ -2350,7 +2381,6 @@ lq_update:
lq_sta, sta);
}
}
- lq_sta->action_counter = 0;
rs_set_stay_in_table(priv, 0, lq_sta);
}
}
@@ -2955,6 +2985,43 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
.open = open_file_generic,
};
+static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
+ char __user *user_buf, size_t count, loff_t *ppos)
+{
+ char buff[120];
+ int desc = 0;
+ ssize_t ret;
+
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ struct iwl_priv *priv;
+ struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
+
+ priv = lq_sta->drv;
+
+ if (is_Ht(tbl->lq_type))
+ desc += sprintf(buff+desc,
+ "Bit Rate= %d Mb/s\n",
+ tbl->expected_tpt[lq_sta->last_txrate_idx]);
+ else
+ desc += sprintf(buff+desc,
+ "Bit Rate= %d Mb/s\n",
+ iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
+ desc += sprintf(buff+desc,
+ "Signal Level= %d dBm\tNoise Level= %d dBm\n",
+ priv->last_rx_rssi, priv->last_rx_noise);
+ desc += sprintf(buff+desc,
+ "Tsf= 0x%llx\tBeacon time= 0x%08X\n",
+ priv->last_tsf, priv->last_beacon_time);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+ return ret;
+}
+
+static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
+ .read = rs_sta_dbgfs_rate_scale_data_read,
+ .open = open_file_generic,
+};
+
static void rs_add_debugfs(void *priv, void *priv_sta,
struct dentry *dir)
{
@@ -2965,6 +3032,9 @@ static void rs_add_debugfs(void *priv, void *priv_sta,
lq_sta->rs_sta_dbgfs_stats_table_file =
debugfs_create_file("rate_stats_table", 0600, dir,
lq_sta, &rs_sta_dbgfs_stats_table_ops);
+ lq_sta->rs_sta_dbgfs_rate_scale_data_file =
+ debugfs_create_file("rate_scale_data", 0600, dir,
+ lq_sta, &rs_sta_dbgfs_rate_scale_data_ops);
lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file =
debugfs_create_u8("tx_agg_tid_enable", 0600, dir,
&lq_sta->tx_agg_tid_en);
@@ -2976,6 +3046,7 @@ static void rs_remove_debugfs(void *priv, void *priv_sta)
struct iwl_lq_sta *lq_sta = priv_sta;
debugfs_remove(lq_sta->rs_sta_dbgfs_scale_table_file);
debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file);
+ debugfs_remove(lq_sta->rs_sta_dbgfs_rate_scale_data_file);
debugfs_remove(lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file);
}
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index f875136bc5dc..25050bf315a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -275,6 +275,8 @@ enum {
#define IWL_MIMO3_SWITCH_GI 8
+#define IWL_MAX_11N_MIMO3_SEARCH IWL_MIMO3_SWITCH_GI
+#define IWL_MAX_SEARCH IWL_MIMO2_SWITCH_MIMO3_ABC
/*FIXME:RS:add possible actions for MIMO3*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 6cdee0b4b486..3ebf6cf53a51 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -190,8 +190,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
priv->cfg->ops->smgmt->clear_station_table(priv);
- if (!priv->error_recovering)
- priv->start_calib = 0;
+ priv->start_calib = 0;
/* Add the broadcast address so we can send broadcast frames */
if (iwl_rxon_add_station(priv, iwl_bcast_addr, 0) ==
@@ -967,23 +966,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
tasklet_kill(&priv->irq_tasklet);
}
-static void iwl_error_recovery(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- memcpy(&priv->staging_rxon, &priv->recovery_rxon,
- sizeof(priv->staging_rxon));
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
-
- iwl_rxon_add_station(priv, priv->bssid, 1);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
- priv->error_recovering = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
static void iwl_irq_tasklet(struct iwl_priv *priv)
{
u32 inta, handled = 0;
@@ -1514,9 +1496,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
set_bit(STATUS_READY, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
- if (priv->error_recovering)
- iwl_error_recovery(priv);
-
iwl_power_update_mode(priv, 1);
/* reassociate for ADHOC mode */
@@ -1715,9 +1694,6 @@ static int __iwl_up(struct iwl_priv *priv)
continue;
}
- /* Clear out the uCode error bit if it is set */
- clear_bit(STATUS_FW_ERROR, &priv->status);
-
/* start card; "initialize" will load runtime ucode */
iwl_nic_start(priv);
@@ -1812,8 +1788,17 @@ static void iwl_bg_restart(struct work_struct *data)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- iwl_down(priv);
- queue_work(priv->workqueue, &priv->up);
+ if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+ mutex_lock(&priv->mutex);
+ priv->vif = NULL;
+ priv->is_open = 0;
+ mutex_unlock(&priv->mutex);
+ iwl_down(priv);
+ ieee80211_restart_hw(priv->hw);
+ } else {
+ iwl_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+ }
}
static void iwl_bg_rx_replenish(struct work_struct *data)
@@ -1853,7 +1838,6 @@ void iwl_post_associate(struct iwl_priv *priv)
if (!priv->vif || !priv->is_open)
return;
- iwl_power_cancel_timeout(priv);
iwl_scan_cancel_timeout(priv, 200);
conf = ieee80211_get_hw_conf(priv->hw);
@@ -1929,7 +1913,7 @@ void iwl_post_associate(struct iwl_priv *priv)
* If chain noise has already been run, then we need to enable
* power management here */
if (priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE)
- iwl_power_enable_management(priv);
+ iwl_power_update_mode(priv, 0);
/* Enable Rx differential gain and sensitivity calibrations */
iwl_chain_noise_reset(priv);
@@ -2007,10 +1991,8 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (!priv->is_open) {
- IWL_DEBUG_MAC80211(priv, "leave - skip\n");
+ if (!priv->is_open)
return;
- }
priv->is_open = 0;
@@ -2482,32 +2464,37 @@ static ssize_t show_power_level(struct device *d,
{
struct iwl_priv *priv = dev_get_drvdata(d);
int mode = priv->power_data.user_power_setting;
- int system = priv->power_data.system_power_setting;
int level = priv->power_data.power_mode;
char *p = buf;
- switch (system) {
- case IWL_POWER_SYS_AUTO:
- p += sprintf(p, "SYSTEM:auto");
- break;
- case IWL_POWER_SYS_AC:
- p += sprintf(p, "SYSTEM:ac");
- break;
- case IWL_POWER_SYS_BATTERY:
- p += sprintf(p, "SYSTEM:battery");
- break;
- }
-
- p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
- "fixed" : "auto");
- p += sprintf(p, "\tINDEX:%d", level);
- p += sprintf(p, "\n");
+ p += sprintf(p, "INDEX:%d\t", level);
+ p += sprintf(p, "USER:%d\n", mode);
return p - buf + 1;
}
static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
store_power_level);
+static ssize_t show_qos(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+ char *p = buf;
+ int q;
+
+ for (q = 0; q < AC_NUM; q++) {
+ p += sprintf(p, "\tcw_min\tcw_max\taifsn\ttxop\n");
+ p += sprintf(p, "AC[%d]\t%u\t%u\t%u\t%u\n", q,
+ priv->qos_data.def_qos_parm.ac[q].cw_min,
+ priv->qos_data.def_qos_parm.ac[q].cw_max,
+ priv->qos_data.def_qos_parm.ac[q].aifsn,
+ priv->qos_data.def_qos_parm.ac[q].edca_txop);
+ }
+
+ return p - buf + 1;
+}
+
+static DEVICE_ATTR(qos, S_IRUGO, show_qos, NULL);
static ssize_t show_statistics(struct device *d,
struct device_attribute *attr, char *buf)
@@ -2570,7 +2557,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
iwl_setup_scan_deferred_work(priv);
- iwl_setup_power_deferred_work(priv);
if (priv->cfg->ops->lib->setup_deferred_work)
priv->cfg->ops->lib->setup_deferred_work(priv);
@@ -2590,7 +2576,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
cancel_delayed_work_sync(&priv->init_alive_start);
cancel_delayed_work(&priv->scan_check);
- cancel_delayed_work_sync(&priv->set_power_save);
cancel_delayed_work(&priv->alive_start);
cancel_work_sync(&priv->beacon_update);
del_timer_sync(&priv->statistics_periodic);
@@ -2607,7 +2592,7 @@ static struct attribute *iwl_sysfs_entries[] = {
&dev_attr_debug_level.attr,
#endif
&dev_attr_version.attr,
-
+ &dev_attr_qos.attr,
NULL
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c
index 735f3f19928c..a5d63672ad39 100644
--- a/drivers/net/wireless/iwlwifi/iwl-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-calib.c
@@ -857,7 +857,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv,
priv->cfg->ops->lib->update_chain_flags(priv);
data->state = IWL_CHAIN_NOISE_DONE;
- iwl_power_enable_management(priv);
+ iwl_power_update_mode(priv, 0);
}
EXPORT_SYMBOL(iwl_chain_noise_calibration);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 1366222bb50a..5393fb3f452c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -273,6 +273,14 @@ void iwl_activate_qos(struct iwl_priv *priv, u8 force)
}
EXPORT_SYMBOL(iwl_activate_qos);
+/*
+ * AC CWmin CW max AIFSN TXOP Limit TXOP Limit
+ * (802.11b) (802.11a/g)
+ * AC_BK 15 1023 7 0 0
+ * AC_BE 15 1023 3 0 0
+ * AC_VI 7 15 2 6.016ms 3.008ms
+ * AC_VO 3 7 2 3.264ms 1.504ms
+ */
void iwl_reset_qos(struct iwl_priv *priv)
{
u16 cw_min = 15;
@@ -304,6 +312,7 @@ void iwl_reset_qos(struct iwl_priv *priv)
if (priv->qos_data.qos_active)
aifs = 3;
+ /* AC_BE */
priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
@@ -311,6 +320,7 @@ void iwl_reset_qos(struct iwl_priv *priv)
priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
if (priv->qos_data.qos_active) {
+ /* AC_BK */
i = 1;
priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
@@ -318,11 +328,12 @@ void iwl_reset_qos(struct iwl_priv *priv)
priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ /* AC_VI */
i = 2;
priv->qos_data.def_qos_parm.ac[i].cw_min =
cpu_to_le16((cw_min + 1) / 2 - 1);
priv->qos_data.def_qos_parm.ac[i].cw_max =
- cpu_to_le16(cw_max);
+ cpu_to_le16(cw_min);
priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
if (is_legacy)
priv->qos_data.def_qos_parm.ac[i].edca_txop =
@@ -332,11 +343,12 @@ void iwl_reset_qos(struct iwl_priv *priv)
cpu_to_le16(3008);
priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+ /* AC_VO */
i = 3;
priv->qos_data.def_qos_parm.ac[i].cw_min =
cpu_to_le16((cw_min + 1) / 4 - 1);
priv->qos_data.def_qos_parm.ac[i].cw_max =
- cpu_to_le16((cw_max + 1) / 2 - 1);
+ cpu_to_le16((cw_min + 1) / 2 - 1);
priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
if (is_legacy)
@@ -960,10 +972,10 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
if (iwl_is_monitor_mode(priv) &&
!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) &&
((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)) {
- rx_chain = 0x07 << RXON_RX_CHAIN_VALID_POS;
- rx_chain |= 0x06 << RXON_RX_CHAIN_FORCE_SEL_POS;
- rx_chain |= 0x07 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
- rx_chain |= 0x01 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+ rx_chain = ANT_ABC << RXON_RX_CHAIN_VALID_POS;
+ rx_chain |= ANT_BC << RXON_RX_CHAIN_FORCE_SEL_POS;
+ rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+ rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
}
priv->staging_rxon.rx_chain = cpu_to_le16(rx_chain);
@@ -1120,7 +1132,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode)
}
EXPORT_SYMBOL(iwl_connection_init_rx_config);
-void iwl_set_rate(struct iwl_priv *priv)
+static void iwl_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
@@ -1166,7 +1178,6 @@ void iwl_set_rate(struct iwl_priv *priv)
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}
-EXPORT_SYMBOL(iwl_set_rate);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
@@ -1230,11 +1241,6 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
"Restarting adapter due to uCode error.\n");
- if (iwl_is_associated(priv)) {
- memcpy(&priv->recovery_rxon, &priv->active_rxon,
- sizeof(priv->recovery_rxon));
- priv->error_recovering = 1;
- }
if (priv->cfg->mod_params->restart_fw)
queue_work(priv->workqueue, &priv->restart);
}
@@ -1358,7 +1364,6 @@ int iwl_init_drv(struct iwl_priv *priv)
priv->ibss_beacon = NULL;
spin_lock_init(&priv->lock);
- spin_lock_init(&priv->power_data.lock);
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
@@ -2226,9 +2231,9 @@ static void iwl_ht_conf(struct iwl_priv *priv,
iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0;
iwl_conf->ht_protection =
- bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
+ bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_PROTECTION;
iwl_conf->non_GF_STA_present =
- !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ !!(bss_conf->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
rcu_read_unlock();
@@ -2582,14 +2587,13 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_rate(priv);
}
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- if (conf->flags & IEEE80211_CONF_PS)
- ret = iwl_power_set_user_mode(priv, IWL_POWER_INDEX_3);
- else
- ret = iwl_power_set_user_mode(priv, IWL_POWER_MODE_CAM);
+ if (changed & IEEE80211_CONF_CHANGE_PS &&
+ priv->iw_mode == NL80211_IFTYPE_STATION) {
+ priv->power_data.power_disabled =
+ !(conf->flags & IEEE80211_CONF_PS);
+ ret = iwl_power_update_mode(priv, 0);
if (ret)
IWL_DEBUG_MAC80211(priv, "Error setting power level\n");
-
}
if (changed & IEEE80211_CONF_CHANGE_POWER) {
@@ -2725,21 +2729,7 @@ void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
iwlcore_commit_rxon(priv);
}
- iwl_power_update_mode(priv, 0);
-
- /* Per mac80211.h: This is only used in IBSS mode... */
if (priv->iw_mode != NL80211_IFTYPE_ADHOC) {
-
- /* switch to CAM during association period.
- * the ucode will block any association/authentication
- * frome during assiciation period if it can not hear
- * the AP because of PM. the timer enable PM back is
- * association do not complete
- */
- if (priv->hw->conf.channel->flags &
- (IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_RADAR))
- iwl_power_disable_management(priv, 3000);
-
IWL_DEBUG_MAC80211(priv, "leave - not in IBSS\n");
mutex_unlock(&priv->mutex);
return;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index bd7f9d9616bc..f3544ea559a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -363,8 +363,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
-void iwl_set_rate(struct iwl_priv *priv);
-
u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 5aa76a706320..3049ba25c3fc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -933,7 +933,6 @@ struct iwl_priv {
const struct iwl_rxon_cmd active_rxon;
struct iwl_rxon_cmd staging_rxon;
- int error_recovering;
struct iwl_rxon_cmd recovery_rxon;
/* 1st responses from initialize and runtime uCode images.
@@ -1076,7 +1075,6 @@ struct iwl_priv {
struct tasklet_struct irq_tasklet;
- struct delayed_work set_power_save;
struct delayed_work init_alive_start;
struct delayed_work alive_start;
struct delayed_work scan_check;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 75517d05df08..401438aec19c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -285,7 +285,7 @@ int iwl_eeprom_check_version(struct iwl_priv *priv)
return 0;
err:
- IWL_ERR(priv, "Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
+ IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n",
eeprom_ver, priv->cfg->eeprom_ver,
calib_ver, priv->cfg->eeprom_calib_ver);
return -EINVAL;
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 47c894530eb5..f2ea3f05f6e1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -41,38 +41,33 @@
#include "iwl-power.h"
/*
- * Setting power level allow the card to go to sleep when not busy
- * there are three factor that decide the power level to go to, they
- * are list here with its priority
- * 1- critical_power_setting this will be set according to card temperature.
- * 2- system_power_setting this will be set by system PM manager.
- * 3- user_power_setting this will be set by user either by writing to sys or
- * mac80211
+ * Setting power level allow the card to go to sleep when not busy.
*
- * if system_power_setting and user_power_setting is set to auto
- * the power level will be decided according to association status and battery
- * status.
+ * The power level is set to INDEX_1 (the least deep state) by
+ * default, and will, in the future, be the deepest state unless
+ * otherwise required by pm_qos network latency requirements.
*
+ * Using INDEX_1 without pm_qos is ok because mac80211 will disable
+ * PS when even checking every beacon for the TIM bit would exceed
+ * the required latency.
*/
-#define MSEC_TO_USEC 1024
#define IWL_POWER_RANGE_0_MAX (2)
#define IWL_POWER_RANGE_1_MAX (10)
-
-#define IWL_POWER_ON_BATTERY IWL_POWER_INDEX_5
-#define IWL_POWER_ON_AC_DISASSOC IWL_POWER_MODE_CAM
-#define IWL_POWER_ON_AC_ASSOC IWL_POWER_MODE_CAM
-
-
-#define IWL_CT_KILL_TEMPERATURE 110
-#define IWL_MIN_POWER_TEMPERATURE 100
-#define IWL_REDUCED_POWER_TEMPERATURE 95
-
+#define NOSLP cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define TU_TO_USEC 1024
+#define SLP_TOUT(T) cpu_to_le32((T) * TU_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
+ cpu_to_le32(X1), \
+ cpu_to_le32(X2), \
+ cpu_to_le32(X3), \
+ cpu_to_le32(X4)}
/* default power management (not Tx power) table values */
-/* for TIM 0-10 */
-static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
+/* for DTIM period 0 through IWL_POWER_RANGE_0_MAX */
+static const struct iwl_power_vec_entry range_0[IWL_POWER_NUM] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0},
@@ -82,8 +77,8 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = {
};
-/* for TIM = 3-10 */
-static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
+/* for DTIM period IWL_POWER_RANGE_0_MAX + 1 through IWL_POWER_RANGE_1_MAX */
+static const struct iwl_power_vec_entry range_1[IWL_POWER_NUM] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(1, 2, 3, 4, 7)}, 0},
@@ -92,8 +87,8 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = {
{{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2}
};
-/* for TIM > 11 */
-static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
+/* for DTIM period > IWL_POWER_RANGE_1_MAX */
+static const struct iwl_power_vec_entry range_2[IWL_POWER_NUM] = {
{{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
{{SLP, SLP_TOUT(200), SLP_TOUT(300), SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
@@ -106,39 +101,15 @@ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = {
/* set card power command */
static int iwl_set_power(struct iwl_priv *priv, void *cmd)
{
- return iwl_send_cmd_pdu_async(priv, POWER_TABLE_CMD,
- sizeof(struct iwl_powertable_cmd),
- cmd, NULL);
-}
-/* decide the right power level according to association status
- * and battery status
- */
-static u16 iwl_get_auto_power_mode(struct iwl_priv *priv)
-{
- u16 mode;
-
- switch (priv->power_data.user_power_setting) {
- case IWL_POWER_AUTO:
- /* if running on battery */
- if (priv->power_data.is_battery_active)
- mode = IWL_POWER_ON_BATTERY;
- else if (iwl_is_associated(priv))
- mode = IWL_POWER_ON_AC_ASSOC;
- else
- mode = IWL_POWER_ON_AC_DISASSOC;
- break;
- default:
- mode = priv->power_data.user_power_setting;
- break;
- }
- return mode;
+ return iwl_send_cmd_pdu(priv, POWER_TABLE_CMD,
+ sizeof(struct iwl_powertable_cmd), cmd);
}
/* initialize to default */
static void iwl_power_init_handle(struct iwl_priv *priv)
{
struct iwl_power_mgr *pow_data;
- int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_MAX;
+ int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_NUM;
struct iwl_powertable_cmd *cmd;
int i;
u16 lctl;
@@ -157,7 +128,7 @@ static void iwl_power_init_handle(struct iwl_priv *priv)
IWL_DEBUG_POWER(priv, "adjust power command flags\n");
- for (i = 0; i < IWL_POWER_MAX; i++) {
+ for (i = 0; i < IWL_POWER_NUM; i++) {
cmd = &pow_data->pwr_range_0[i].cmd;
if (lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN)
@@ -247,33 +218,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE ||
priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE;
- /* If on battery, set to 3,
- * if plugged into AC power, set to CAM ("continuously aware mode"),
- * else user level */
-
- switch (setting->system_power_setting) {
- case IWL_POWER_SYS_AUTO:
- final_mode = iwl_get_auto_power_mode(priv);
- break;
- case IWL_POWER_SYS_BATTERY:
- final_mode = IWL_POWER_INDEX_3;
- break;
- case IWL_POWER_SYS_AC:
- final_mode = IWL_POWER_MODE_CAM;
- break;
- default:
- final_mode = IWL_POWER_INDEX_3;
- WARN_ON(1);
- }
-
- if (setting->critical_power_setting > final_mode)
- final_mode = setting->critical_power_setting;
+ final_mode = priv->power_data.user_power_setting;
- /* driver only support CAM for non STA network */
- if (priv->iw_mode != NL80211_IFTYPE_STATION)
+ if (setting->power_disabled)
final_mode = IWL_POWER_MODE_CAM;
- if (iwl_is_ready_rf(priv) && !setting->power_disabled &&
+ if (iwl_is_ready_rf(priv) &&
((setting->power_mode != final_mode) || force)) {
struct iwl_powertable_cmd cmd;
@@ -290,8 +240,6 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
if (final_mode == IWL_POWER_MODE_CAM)
clear_bit(STATUS_POWER_PMI, &priv->status);
- else
- set_bit(STATUS_POWER_PMI, &priv->status);
if (priv->cfg->ops->lib->update_chain_flags && update_chains)
priv->cfg->ops->lib->update_chain_flags(priv);
@@ -307,51 +255,10 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force)
}
EXPORT_SYMBOL(iwl_power_update_mode);
-/* Allow other iwl code to disable/enable power management active
- * this will be useful for rate scale to disable PM during heavy
- * Tx/Rx activities
- */
-int iwl_power_disable_management(struct iwl_priv *priv, u32 ms)
-{
- u16 prev_mode;
- int ret = 0;
-
- if (priv->power_data.power_disabled)
- return -EBUSY;
-
- prev_mode = priv->power_data.user_power_setting;
- priv->power_data.user_power_setting = IWL_POWER_MODE_CAM;
- ret = iwl_power_update_mode(priv, 0);
- priv->power_data.power_disabled = 1;
- priv->power_data.user_power_setting = prev_mode;
- cancel_delayed_work(&priv->set_power_save);
- if (ms)
- queue_delayed_work(priv->workqueue, &priv->set_power_save,
- msecs_to_jiffies(ms));
-
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_power_disable_management);
-
-/* Allow other iwl code to disable/enable power management active
- * this will be useful for rate scale to disable PM during high
- * volume activities
- */
-int iwl_power_enable_management(struct iwl_priv *priv)
-{
- int ret = 0;
-
- priv->power_data.power_disabled = 0;
- ret = iwl_power_update_mode(priv, 0);
- return ret;
-}
-EXPORT_SYMBOL(iwl_power_enable_management);
-
/* set user_power_setting */
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
{
- if (mode > IWL_POWER_MAX)
+ if (mode >= IWL_POWER_NUM)
return -EINVAL;
priv->power_data.user_power_setting = mode;
@@ -360,86 +267,12 @@ int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode)
}
EXPORT_SYMBOL(iwl_power_set_user_mode);
-/* set system_power_setting. This should be set by over all
- * PM application.
- */
-int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode)
-{
- if (mode < IWL_POWER_SYS_MAX)
- priv->power_data.system_power_setting = mode;
- else
- return -EINVAL;
- return iwl_power_update_mode(priv, 0);
-}
-EXPORT_SYMBOL(iwl_power_set_system_mode);
-
/* initialize to default */
void iwl_power_initialize(struct iwl_priv *priv)
{
iwl_power_init_handle(priv);
- priv->power_data.user_power_setting = IWL_POWER_AUTO;
- priv->power_data.system_power_setting = IWL_POWER_SYS_AUTO;
- priv->power_data.power_disabled = 0;
- priv->power_data.is_battery_active = 0;
- priv->power_data.critical_power_setting = 0;
+ priv->power_data.user_power_setting = IWL_POWER_INDEX_1;
+ /* default to disabled until mac80211 says otherwise */
+ priv->power_data.power_disabled = 1;
}
EXPORT_SYMBOL(iwl_power_initialize);
-
-/* set critical_power_setting according to temperature value */
-int iwl_power_temperature_change(struct iwl_priv *priv)
-{
- int ret = 0;
- s32 temperature = KELVIN_TO_CELSIUS(priv->last_temperature);
- u16 new_critical = priv->power_data.critical_power_setting;
-
- if (temperature > IWL_CT_KILL_TEMPERATURE)
- return 0;
- else if (temperature > IWL_MIN_POWER_TEMPERATURE)
- new_critical = IWL_POWER_INDEX_5;
- else if (temperature > IWL_REDUCED_POWER_TEMPERATURE)
- new_critical = IWL_POWER_INDEX_3;
- else
- new_critical = IWL_POWER_MODE_CAM;
-
- if (new_critical != priv->power_data.critical_power_setting)
- priv->power_data.critical_power_setting = new_critical;
-
- if (priv->power_data.critical_power_setting >
- priv->power_data.power_mode)
- ret = iwl_power_update_mode(priv, 0);
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_power_temperature_change);
-
-static void iwl_bg_set_power_save(struct work_struct *work)
-{
- struct iwl_priv *priv = container_of(work,
- struct iwl_priv, set_power_save.work);
- IWL_DEBUG_POWER(priv, "update power\n");
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
-
- /* on starting association we disable power management
- * until association, if association failed then this
- * timer will expire and enable PM again.
- */
- if (!iwl_is_associated(priv))
- iwl_power_enable_management(priv);
-
- mutex_unlock(&priv->mutex);
-}
-void iwl_setup_power_deferred_work(struct iwl_priv *priv)
-{
- INIT_DELAYED_WORK(&priv->set_power_save, iwl_bg_set_power_save);
-}
-EXPORT_SYMBOL(iwl_setup_power_deferred_work);
-
-void iwl_power_cancel_timeout(struct iwl_priv *priv)
-{
- cancel_delayed_work(&priv->set_power_save);
-}
-EXPORT_SYMBOL(iwl_power_cancel_timeout);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index 18963392121e..37ba3bb7a25a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -40,56 +40,29 @@ enum {
IWL_POWER_INDEX_3,
IWL_POWER_INDEX_4,
IWL_POWER_INDEX_5,
- IWL_POWER_AUTO,
- IWL_POWER_MAX = IWL_POWER_AUTO,
+ IWL_POWER_NUM
};
-enum {
- IWL_POWER_SYS_AUTO,
- IWL_POWER_SYS_AC,
- IWL_POWER_SYS_BATTERY,
- IWL_POWER_SYS_MAX,
-};
-
-
/* Power management (not Tx power) structures */
-#define NOSLP cpu_to_le16(0), 0, 0
-#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
-#define SLP_TOUT(T) cpu_to_le32((T) * MSEC_TO_USEC)
-#define SLP_VEC(X0, X1, X2, X3, X4) {cpu_to_le32(X0), \
- cpu_to_le32(X1), \
- cpu_to_le32(X2), \
- cpu_to_le32(X3), \
- cpu_to_le32(X4)}
struct iwl_power_vec_entry {
struct iwl_powertable_cmd cmd;
u8 no_dtim;
};
struct iwl_power_mgr {
- spinlock_t lock;
- struct iwl_power_vec_entry pwr_range_0[IWL_POWER_MAX];
- struct iwl_power_vec_entry pwr_range_1[IWL_POWER_MAX];
- struct iwl_power_vec_entry pwr_range_2[IWL_POWER_MAX];
+ struct iwl_power_vec_entry pwr_range_0[IWL_POWER_NUM];
+ struct iwl_power_vec_entry pwr_range_1[IWL_POWER_NUM];
+ struct iwl_power_vec_entry pwr_range_2[IWL_POWER_NUM];
u32 dtim_period;
/* final power level that used to calculate final power command */
u8 power_mode;
- u8 user_power_setting; /* set by user through mac80211 or sysfs */
- u8 system_power_setting; /* set by kernel system tools */
- u8 critical_power_setting; /* set if driver over heated */
- u8 is_battery_active; /* DC/AC power */
- u8 power_disabled; /* flag to disable using power saving level */
+ u8 user_power_setting; /* set by user through sysfs */
+ u8 power_disabled; /* set by mac80211's CONF_PS */
};
-void iwl_setup_power_deferred_work(struct iwl_priv *priv);
-void iwl_power_cancel_timeout(struct iwl_priv *priv);
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
-int iwl_power_disable_management(struct iwl_priv *priv, u32 ms);
-int iwl_power_enable_management(struct iwl_priv *priv);
int iwl_power_set_user_mode(struct iwl_priv *priv, u16 mode);
-int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode);
void iwl_power_initialize(struct iwl_priv *priv);
-int iwl_power_temperature_change(struct iwl_priv *priv);
#endif /* __iwl_power_setting_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index dd8766b80b34..065214b55895 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -580,9 +580,10 @@ static void iwl_bg_request_scan(struct work_struct *data)
int ret = 0;
u32 rate_flags = 0;
u16 cmd_len;
+ u16 rx_chain = 0;
enum ieee80211_band band;
u8 n_probes = 0;
- u8 rx_chain = priv->hw_params.valid_rx_ant;
+ u8 rx_ant = priv->hw_params.valid_rx_ant;
u8 rate;
bool is_active = false;
@@ -723,7 +724,7 @@ static void iwl_bg_request_scan(struct work_struct *data)
* Avoid A (0x1) because of its off-channel reception on A-band.
*/
if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965)
- rx_chain = 0x6;
+ rx_ant = ANT_BC;
} else {
IWL_WARN(priv, "Invalid scan band count\n");
goto done;
@@ -735,10 +736,11 @@ static void iwl_bg_request_scan(struct work_struct *data)
scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
/* MIMO is not used here, but value is required */
- scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
- cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
- (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) |
- (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
+ rx_chain |= ANT_ABC << RXON_RX_CHAIN_VALID_POS;
+ rx_chain |= ANT_ABC << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+ rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+ rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+ scan->rx_chain = cpu_to_le16(rx_chain);
cmd_len = iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
priv->scan_request->ie,
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index f6c1489a0c4a..c32ec809053f 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1837,23 +1837,6 @@ static void iwl3945_dump_nic_event_log(struct iwl_priv *priv)
iwl_release_nic_access(priv);
}
-static void iwl3945_error_recovery(struct iwl_priv *priv)
-{
- unsigned long flags;
-
- memcpy(&priv->staging_rxon, &priv->recovery_rxon,
- sizeof(priv->staging_rxon));
- priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
- iwlcore_commit_rxon(priv);
-
- priv->cfg->ops->smgmt->add_station(priv, priv->bssid, 1, 0, NULL);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
- priv->error_recovering = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
static void iwl3945_irq_tasklet(struct iwl_priv *priv)
{
u32 inta, handled = 0;
@@ -2683,9 +2666,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
/* After the ALIVE response, we can send commands to 3945 uCode */
set_bit(STATUS_ALIVE, &priv->status);
- /* Clear out the uCode error bit if it is set */
- clear_bit(STATUS_FW_ERROR, &priv->status);
-
if (iwl_is_rfkill(priv))
return;
@@ -2722,9 +2702,6 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
set_bit(STATUS_READY, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
- if (priv->error_recovering)
- iwl3945_error_recovery(priv);
-
/* reassociate for ADHOC mode */
if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) {
struct sk_buff *beacon = ieee80211_beacon_get(priv->hw,
@@ -3231,8 +3208,17 @@ static void iwl3945_bg_restart(struct work_struct *data)
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- iwl3945_down(priv);
- queue_work(priv->workqueue, &priv->up);
+ if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
+ mutex_lock(&priv->mutex);
+ priv->vif = NULL;
+ priv->is_open = 0;
+ mutex_unlock(&priv->mutex);
+ iwl3945_down(priv);
+ ieee80211_restart_hw(priv->hw);
+ } else {
+ iwl3945_down(priv);
+ queue_work(priv->workqueue, &priv->up);
+ }
}
static void iwl3945_bg_rx_replenish(struct work_struct *data)
@@ -3859,26 +3845,11 @@ static ssize_t show_power_level(struct device *d,
{
struct iwl_priv *priv = dev_get_drvdata(d);
int mode = priv->power_data.user_power_setting;
- int system = priv->power_data.system_power_setting;
int level = priv->power_data.power_mode;
char *p = buf;
- switch (system) {
- case IWL_POWER_SYS_AUTO:
- p += sprintf(p, "SYSTEM:auto");
- break;
- case IWL_POWER_SYS_AC:
- p += sprintf(p, "SYSTEM:ac");
- break;
- case IWL_POWER_SYS_BATTERY:
- p += sprintf(p, "SYSTEM:battery");
- break;
- }
-
- p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ?
- "fixed" : "auto");
- p += sprintf(p, "\tINDEX:%d", level);
- p += sprintf(p, "\n");
+ p += sprintf(p, "INDEX:%d\t", level);
+ p += sprintf(p, "USER:%d\n", mode);
return p - buf + 1;
}
@@ -4122,7 +4093,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
priv->ibss_beacon = NULL;
spin_lock_init(&priv->lock);
- spin_lock_init(&priv->power_data.lock);
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index b1213b6a6b9f..61a4ad7cc1c2 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -642,7 +642,7 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_HT) {
printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n",
wiphy_name(hw->wiphy),
- info->ht.operation_mode);
+ info->ht_operation_mode);
}
if (changed & BSS_CHANGED_BASIC_RATES) {
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 46b288dc8f4d..a263d5c84c08 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2369,7 +2369,7 @@ static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
if (info->use_cts_prot) {
prot_mode = MWL8K_FRAME_PROT_11G;
} else {
- switch (info->ht.operation_mode &
+ switch (info->ht_operation_mode &
IEEE80211_HT_OP_MODE_PROTECTION) {
case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index d10af3687a8e..270dd4e59f7f 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1847,7 +1847,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) ||
- !rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
+ rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) {
ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
return -ENODEV;
}
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 20a9633569f2..a82c4cd436d8 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -1,6 +1,6 @@
config WL12XX
tristate "TI wl1251/wl1271 support"
- depends on MAC80211 && WLAN_80211 && SPI_MASTER && EXPERIMENTAL
+ depends on MAC80211 && WLAN_80211 && SPI_MASTER && GENERIC_HARDIRQS && EXPERIMENTAL
select FW_LOADER
select CRC7
---help---
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index dc92359f37e6..05c29c01174c 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1068,8 +1068,12 @@ enum ieee80211_category {
WLAN_CATEGORY_DLS = 2,
WLAN_CATEGORY_BACK = 3,
WLAN_CATEGORY_PUBLIC = 4,
+ WLAN_CATEGORY_HT = 7,
WLAN_CATEGORY_SA_QUERY = 8,
+ WLAN_CATEGORY_PROTECTED_DUAL_OF_ACTION = 9,
WLAN_CATEGORY_WMM = 17,
+ WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
+ WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
};
/* SPECTRUM_MGMT action code */
@@ -1261,7 +1265,9 @@ static inline bool ieee80211_is_robust_mgmt_frame(struct ieee80211_hdr *hdr)
if (ieee80211_has_protected(hdr->frame_control))
return true;
category = ((u8 *) hdr) + 24;
- return *category != WLAN_CATEGORY_PUBLIC;
+ return *category != WLAN_CATEGORY_PUBLIC &&
+ *category != WLAN_CATEGORY_HT &&
+ *category != WLAN_CATEGORY_VENDOR_SPECIFIC;
}
return false;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index e9fd13aa79f0..dbea93b694e5 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -25,6 +25,8 @@
*
*/
+#include <linux/types.h>
+
/**
* DOC: Station handling
*
@@ -77,8 +79,8 @@
* @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
* %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
* @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
- * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
- * attributes.
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ * and %NL80211_ATTR_KEY_SEQ attributes.
* @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
* or %NL80211_ATTR_MAC.
*
@@ -380,7 +382,7 @@ enum nl80211_commands {
*
* @NL80211_ATTR_STA_AID: Association ID for the station (u16)
* @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
- * &enum nl80211_sta_flags.
+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
* @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
* IEEE 802.11 7.3.1.6 (u16).
* @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
@@ -494,6 +496,21 @@ enum nl80211_commands {
* @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
* is used, e.g., with %NL80211_CMD_AUTHENTICATE event
*
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ * used for the association (&enum nl80211_mfp, represented as a u32);
+ * this attribute can be used
+ * with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ * &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ * request, the driver will assume that the port is unauthorized until
+ * authorized by user space. Otherwise, port is marked authorized by
+ * default in station mode.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -596,6 +613,12 @@ enum nl80211_attrs {
NL80211_ATTR_TIMED_OUT,
+ NL80211_ATTR_USE_MFP,
+
+ NL80211_ATTR_STA_FLAGS2,
+
+ NL80211_ATTR_CONTROL_PORT,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -685,6 +708,18 @@ enum nl80211_sta_flags {
};
/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+ __u32 mask;
+ __u32 set;
+} __attribute__((packed));
+
+/**
* enum nl80211_rate_info - bitrate information
*
* These attribute types are used with %NL80211_STA_INFO_TXRATE
@@ -1179,4 +1214,14 @@ enum nl80211_key_type {
NL80211_KEYTYPE_PEERKEY,
};
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+ NL80211_MFP_NO,
+ NL80211_MFP_REQUIRED,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b8a76764e1c5..9e17a83d3432 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -252,27 +252,6 @@ struct beacon_parameters {
};
/**
- * enum station_flags - station flags
- *
- * Station capability flags. Note that these must be the bits
- * according to the nl80211 flags.
- *
- * @STATION_FLAG_CHANGED: station flags were changed
- * @STATION_FLAG_AUTHORIZED: station is authorized to send frames (802.1X)
- * @STATION_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
- * with short preambles
- * @STATION_FLAG_WME: station is WME/QoS capable
- * @STATION_FLAG_MFP: station uses management frame protection
- */
-enum station_flags {
- STATION_FLAG_CHANGED = 1<<0,
- STATION_FLAG_AUTHORIZED = 1<<NL80211_STA_FLAG_AUTHORIZED,
- STATION_FLAG_SHORT_PREAMBLE = 1<<NL80211_STA_FLAG_SHORT_PREAMBLE,
- STATION_FLAG_WME = 1<<NL80211_STA_FLAG_WME,
- STATION_FLAG_MFP = 1<<NL80211_STA_FLAG_MFP,
-};
-
-/**
* enum plink_action - actions to perform in mesh peers
*
* @PLINK_ACTION_INVALID: action 0 is reserved
@@ -294,14 +273,17 @@ enum plink_actions {
* @supported_rates: supported rates in IEEE 802.11 format
* (or NULL for no change)
* @supported_rates_len: number of supported rates
- * @station_flags: station flags (see &enum station_flags)
+ * @sta_flags_mask: station flags that changed
+ * (bitmask of BIT(NL80211_STA_FLAG_...))
+ * @sta_flags_set: station flags values
+ * (bitmask of BIT(NL80211_STA_FLAG_...))
* @listen_interval: listen interval or -1 for no change
* @aid: AID or zero for no change
*/
struct station_parameters {
u8 *supported_rates;
struct net_device *vlan;
- u32 station_flags;
+ u32 sta_flags_mask, sta_flags_set;
int listen_interval;
u16 aid;
u8 supported_rates_len;
@@ -672,6 +654,11 @@ struct cfg80211_auth_request {
* @ssid_len: Length of ssid in octets
* @ie: Extra IEs to add to (Re)Association Request frame or %NULL
* @ie_len: Length of ie buffer in octets
+ * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
+ * @control_port: Whether user space controls IEEE 802.1X port, i.e.,
+ * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is
+ * required to assume that the port is unauthorized until authorized by
+ * user space. Otherwise, port is marked authorized by default.
*/
struct cfg80211_assoc_request {
struct ieee80211_channel *chan;
@@ -680,6 +667,8 @@ struct cfg80211_assoc_request {
size_t ssid_len;
const u8 *ie;
size_t ie_len;
+ bool use_mfp;
+ bool control_port;
};
/**
@@ -858,13 +847,13 @@ struct cfg80211_ops {
struct vif_params *params);
int (*add_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, u8 *mac_addr,
+ u8 key_index, const u8 *mac_addr,
struct key_params *params);
int (*get_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, u8 *mac_addr, void *cookie,
+ u8 key_index, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie, struct key_params*));
int (*del_key)(struct wiphy *wiphy, struct net_device *netdev,
- u8 key_index, u8 *mac_addr);
+ u8 key_index, const u8 *mac_addr);
int (*set_default_key)(struct wiphy *wiphy,
struct net_device *netdev,
u8 key_index);
@@ -1145,8 +1134,11 @@ struct wireless_dev {
#ifdef CONFIG_WIRELESS_EXT
/* wext data */
- struct cfg80211_ibss_params wext;
- u8 wext_bssid[ETH_ALEN];
+ struct {
+ struct cfg80211_ibss_params ibss;
+ u8 bssid[ETH_ALEN];
+ s8 default_key, default_mgmt_key;
+ } wext;
#endif
};
@@ -1396,6 +1388,15 @@ int cfg80211_wext_siwretry(struct net_device *dev,
int cfg80211_wext_giwretry(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *retry, char *extra);
+int cfg80211_wext_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra);
+int cfg80211_wext_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf);
+int cfg80211_wext_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf);
/*
* callbacks for asynchronous cfg80211 methods, notification
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 38dc1cd10270..d10ed1776fcd 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -73,22 +73,6 @@
*/
/**
- * struct ieee80211_ht_bss_info - describing BSS's HT characteristics
- *
- * This structure describes most essential parameters needed
- * to describe 802.11n HT characteristics in a BSS.
- *
- * @primary_channel: channel number of primery channel
- * @bss_cap: 802.11n's general BSS capabilities (e.g. channel width)
- * @bss_op_mode: 802.11n's BSS operation modes (e.g. HT protection)
- */
-struct ieee80211_ht_bss_info {
- u8 primary_channel;
- u8 bss_cap; /* use IEEE80211_HT_IE_CHA_ */
- u8 bss_op_mode; /* use IEEE80211_HT_IE_ */
-};
-
-/**
* enum ieee80211_max_queues - maximum number of queues
*
* @IEEE80211_MAX_QUEUES: Maximum number of regular device queues.
@@ -171,14 +155,6 @@ enum ieee80211_bss_change {
};
/**
- * struct ieee80211_bss_ht_conf - BSS's changing HT configuration
- * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info)
- */
-struct ieee80211_bss_ht_conf {
- u16 operation_mode;
-};
-
-/**
* struct ieee80211_bss_conf - holds the BSS's changing parameters
*
* This structure keeps information about a BSS (and an association
@@ -203,6 +179,8 @@ struct ieee80211_bss_ht_conf {
* the current band.
* @bssid: The BSSID for this BSS
* @enable_beacon: whether beaconing should be enabled or not
+ * @ht_operation_mode: HT operation mode (like in &struct ieee80211_ht_info).
+ * This field is only valid when the channel type is one of the HT types.
*/
struct ieee80211_bss_conf {
const u8 *bssid;
@@ -219,7 +197,7 @@ struct ieee80211_bss_conf {
u16 assoc_capability;
u64 timestamp;
u32 basic_rates;
- struct ieee80211_bss_ht_conf ht;
+ u16 ht_operation_mode;
};
/**
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d0ca6da33ca9..77e9ff5ec4f3 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -112,7 +112,7 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex,
}
static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, u8 *mac_addr,
+ u8 key_idx, const u8 *mac_addr,
struct key_params *params)
{
struct ieee80211_sub_if_data *sdata;
@@ -141,7 +141,8 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
- key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key);
+ key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key,
+ params->seq_len, params->seq);
if (!key)
return -ENOMEM;
@@ -166,7 +167,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, u8 *mac_addr)
+ u8 key_idx, const u8 *mac_addr)
{
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
@@ -208,7 +209,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
}
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
- u8 key_idx, u8 *mac_addr, void *cookie,
+ u8 key_idx, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
@@ -629,34 +630,38 @@ static void sta_apply_parameters(struct ieee80211_local *local,
int i, j;
struct ieee80211_supported_band *sband;
struct ieee80211_sub_if_data *sdata = sta->sdata;
+ u32 mask, set;
sband = local->hw.wiphy->bands[local->oper_channel->band];
- /*
- * FIXME: updating the flags is racy when this function is
- * called from ieee80211_change_station(), this will
- * be resolved in a future patch.
- */
+ spin_lock_bh(&sta->lock);
+ mask = params->sta_flags_mask;
+ set = params->sta_flags_set;
- if (params->station_flags & STATION_FLAG_CHANGED) {
- spin_lock_bh(&sta->lock);
+ if (mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
sta->flags &= ~WLAN_STA_AUTHORIZED;
- if (params->station_flags & STATION_FLAG_AUTHORIZED)
+ if (set & BIT(NL80211_STA_FLAG_AUTHORIZED))
sta->flags |= WLAN_STA_AUTHORIZED;
+ }
+ if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
- if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
+ if (set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+ }
+ if (mask & BIT(NL80211_STA_FLAG_WME)) {
sta->flags &= ~WLAN_STA_WME;
- if (params->station_flags & STATION_FLAG_WME)
+ if (set & BIT(NL80211_STA_FLAG_WME))
sta->flags |= WLAN_STA_WME;
+ }
+ if (mask & BIT(NL80211_STA_FLAG_MFP)) {
sta->flags &= ~WLAN_STA_MFP;
- if (params->station_flags & STATION_FLAG_MFP)
+ if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
- spin_unlock_bh(&sta->lock);
}
+ spin_unlock_bh(&sta->lock);
/*
* FIXME: updating the following information is racy when this
@@ -1253,6 +1258,19 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
if (ret)
return ret;
+ if (req->use_mfp) {
+ sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
+ sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
+ } else {
+ sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
+ sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
+ }
+
+ if (req->control_port)
+ sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
+ else
+ sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
+
sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
ieee80211_sta_req_auth(sdata);
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index ac793201b701..e7682fe1c590 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -135,6 +135,42 @@ static const struct file_operations reset_ops = {
.open = mac80211_open_file_generic,
};
+static ssize_t noack_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ int res;
+ char buf[10];
+
+ res = scnprintf(buf, sizeof(buf), "%d\n", local->wifi_wme_noack_test);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static ssize_t noack_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[10];
+ size_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ local->wifi_wme_noack_test = !!simple_strtoul(buf, NULL, 0);
+
+ return count;
+}
+
+static const struct file_operations noack_ops = {
+ .read = noack_read,
+ .write = noack_write,
+ .open = mac80211_open_file_generic
+};
+
/* statistics stuff */
#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
@@ -275,6 +311,7 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(wep_iv);
DEBUGFS_ADD(tsf);
DEBUGFS_ADD_MODE(reset, 0200);
+ DEBUGFS_ADD(noack);
statsd = debugfs_create_dir("statistics", phyd);
local->debugfs.statistics = statsd;
@@ -330,6 +367,7 @@ void debugfs_hw_del(struct ieee80211_local *local)
DEBUGFS_DEL(wep_iv);
DEBUGFS_DEL(tsf);
DEBUGFS_DEL(reset);
+ DEBUGFS_DEL(noack);
DEBUGFS_STATS_DEL(transmitted_fragment_count);
DEBUGFS_STATS_DEL(multicast_transmitted_frame_count);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index aa537681f87c..c236079ed38a 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -63,19 +63,18 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
const u8 *bssid, const int beacon_int,
struct ieee80211_channel *chan,
- const size_t supp_rates_len,
- const u8 *supp_rates,
+ const u32 basic_rates,
const u16 capability, u64 tsf)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
- int rates, i, j;
+ int rates, i;
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos;
struct ieee80211_supported_band *sband;
u32 bss_change;
-
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
/* Reset own TSF to allow time synchronization work. */
drv_reset_tsf(local);
@@ -101,6 +100,16 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
sband = local->hw.wiphy->bands[chan->band];
+ /* build supported rates array */
+ pos = supp_rates;
+ for (i = 0; i < sband->n_bitrates; i++) {
+ int rate = sband->bitrates[i].bitrate;
+ u8 basic = 0;
+ if (basic_rates & BIT(i))
+ basic = 0x80;
+ *pos++ = basic | (u8) (rate / 5);
+ }
+
/* Build IBSS probe response */
mgmt = (void *) skb_put(skb, 24 + sizeof(mgmt->u.beacon));
memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
@@ -118,7 +127,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = ifibss->ssid_len;
memcpy(pos, ifibss->ssid, ifibss->ssid_len);
- rates = supp_rates_len;
+ rates = sband->n_bitrates;
if (rates > 8)
rates = 8;
pos = skb_put(skb, 2 + rates);
@@ -140,8 +149,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
*pos++ = 0;
*pos++ = 0;
- if (supp_rates_len > 8) {
- rates = supp_rates_len - 8;
+ if (sband->n_bitrates > 8) {
+ rates = sband->n_bitrates - 8;
pos = skb_put(skb, 2 + rates);
*pos++ = WLAN_EID_EXT_SUPP_RATES;
*pos++ = rates;
@@ -162,15 +171,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
bss_change |= BSS_CHANGED_BEACON_ENABLED;
ieee80211_bss_info_change_notify(sdata, bss_change);
- rates = 0;
- for (i = 0; i < supp_rates_len; i++) {
- int bitrate = (supp_rates[i] & 0x7f) * 5;
- for (j = 0; j < sband->n_bitrates; j++)
- if (sband->bitrates[j].bitrate == bitrate)
- rates |= BIT(j);
- }
-
- ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
+ ieee80211_sta_def_wmm_params(sdata, sband->n_bitrates, supp_rates);
ifibss->state = IEEE80211_IBSS_MLME_JOINED;
mod_timer(&ifibss->timer,
@@ -184,15 +185,35 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_bss *bss)
{
+ struct ieee80211_supported_band *sband;
+ u32 basic_rates;
+ int i, j;
u16 beacon_int = bss->cbss.beacon_interval;
if (beacon_int < 10)
beacon_int = 10;
+ sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band];
+
+ basic_rates = 0;
+
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int rate = (bss->supp_rates[i] & 0x7f) * 5;
+ bool is_basic = !!(bss->supp_rates[i] & 0x80);
+
+ for (j = 0; j < sband->n_bitrates; j++) {
+ if (sband->bitrates[j].bitrate == rate) {
+ if (is_basic)
+ basic_rates |= BIT(j);
+ break;
+ }
+ }
+ }
+
__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid,
beacon_int,
bss->cbss.channel,
- bss->supp_rates_len, bss->supp_rates,
+ basic_rates,
bss->cbss.capability,
bss->cbss.tsf);
}
@@ -449,9 +470,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
- u8 *pos;
u8 bssid[ETH_ALEN];
- u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
u16 capability;
int i;
@@ -480,15 +499,9 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
else
sdata->drop_unencrypted = 0;
- pos = supp_rates;
- for (i = 0; i < sband->n_bitrates; i++) {
- int rate = sband->bitrates[i].bitrate;
- *pos++ = (u8) (rate / 5);
- }
-
__ieee80211_sta_join_ibss(sdata, bssid, sdata->vif.bss_conf.beacon_int,
- ifibss->channel, sband->n_bitrates,
- supp_rates, capability, 0);
+ ifibss->channel, 3, /* first two are basic */
+ capability, 0);
}
static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
@@ -499,6 +512,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
struct ieee80211_channel *chan = NULL;
const u8 *bssid = NULL;
int active_ibss;
+ u16 capability;
active_ibss = ieee80211_sta_active_ibss(sdata);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -509,6 +523,10 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
if (active_ibss)
return;
+ capability = WLAN_CAPABILITY_IBSS;
+ if (sdata->default_key)
+ capability |= WLAN_CAPABILITY_PRIVACY;
+
if (ifibss->fixed_bssid)
bssid = ifibss->bssid;
if (ifibss->fixed_channel)
@@ -517,8 +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,
- WLAN_CAPABILITY_IBSS,
- WLAN_CAPABILITY_IBSS);
+ capability,
+ WLAN_CAPABILITY_IBSS |
+ WLAN_CAPABILITY_PRIVACY);
#ifdef CONFIG_MAC80211_IBSS_DEBUG
if (bss)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 03e0d22603c8..9d1514727f6e 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -235,7 +235,7 @@ struct mesh_preq_queue {
#define IEEE80211_STA_ASSOCIATED BIT(4)
#define IEEE80211_STA_PROBEREQ_POLL BIT(5)
#define IEEE80211_STA_CREATE_IBSS BIT(6)
-/* hole at 7, please re-use */
+#define IEEE80211_STA_CONTROL_PORT BIT(7)
#define IEEE80211_STA_WMM_ENABLED BIT(8)
/* hole at 9, please re-use */
#define IEEE80211_STA_AUTO_SSID_SEL BIT(10)
@@ -427,6 +427,12 @@ struct ieee80211_sub_if_data {
int drop_unencrypted;
+ /*
+ * keep track of whether the HT opmode (stored in
+ * vif.bss_info.ht_operation_mode) is valid.
+ */
+ bool ht_opmode_valid;
+
/* Fragment table for host-based reassembly */
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
@@ -760,6 +766,7 @@ struct ieee80211_local {
struct dentry *wep_iv;
struct dentry *tsf;
struct dentry *reset;
+ struct dentry *noack;
struct dentry *statistics;
struct local_debugfsdentries_statsdentries {
struct dentry *transmitted_fragment_count;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 8b6daf0219f4..8c9f1c722cdb 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -964,5 +964,6 @@ void ieee80211_recalc_idle(struct ieee80211_local *local)
mutex_lock(&local->iflist_mtx);
chg = __ieee80211_recalc_idle(local);
mutex_unlock(&local->iflist_mtx);
- ieee80211_hw_config(local, chg);
+ if (chg)
+ ieee80211_hw_config(local, chg);
}
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index b7e1350273bb..827ea8e6ee0a 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -290,9 +290,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
int idx,
size_t key_len,
- const u8 *key_data)
+ const u8 *key_data,
+ size_t seq_len, const u8 *seq)
{
struct ieee80211_key *key;
+ int i, j;
BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
@@ -318,14 +320,31 @@ 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) {
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+ key->u.tkip.rx[i].iv32 =
+ get_unaligned_le32(&seq[2]);
+ key->u.tkip.rx[i].iv16 =
+ get_unaligned_le16(seq);
+ }
+ }
break;
case ALG_CCMP:
key->conf.iv_len = CCMP_HDR_LEN;
key->conf.icv_len = CCMP_MIC_LEN;
+ if (seq && seq_len == CCMP_PN_LEN) {
+ for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+ for (j = 0; j < CCMP_PN_LEN; j++)
+ key->u.ccmp.rx_pn[i][j] =
+ seq[CCMP_PN_LEN - j - 1];
+ }
break;
case ALG_AES_CMAC:
key->conf.iv_len = 0;
key->conf.icv_len = sizeof(struct ieee80211_mmie);
+ if (seq && seq_len == 6)
+ for (j = 0; j < 6; j++)
+ key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
break;
}
memcpy(key->conf.key, key_data, key_len);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 215d3ef42a4f..9572e00f532c 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -144,7 +144,8 @@ struct ieee80211_key {
struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
int idx,
size_t key_len,
- const u8 *key_data);
+ const u8 *key_data,
+ size_t seq_len, const u8 *seq);
/*
* Insert a key into data structures (sdata, sta if necessary)
* to make it used, free old key.
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b80bc80e46cf..76df5eabf268 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -154,15 +154,17 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev)
int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
{
- struct ieee80211_channel *chan;
+ struct ieee80211_channel *chan, *scan_chan;
int ret = 0;
int power;
enum nl80211_channel_type channel_type;
might_sleep();
- if (local->sw_scanning) {
- chan = local->scan_channel;
+ scan_chan = local->scan_channel;
+
+ if (scan_chan) {
+ chan = scan_chan;
channel_type = NL80211_CHAN_NO_HT;
} else {
chan = local->oper_channel;
@@ -176,7 +178,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
changed |= IEEE80211_CONF_CHANGE_CHANNEL;
}
- if (local->sw_scanning)
+ if (scan_chan)
power = chan->max_power;
else
power = local->power_constr_level ?
@@ -859,8 +861,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (!local->oper_channel) {
/* init channel we're on */
local->hw.conf.channel =
- local->oper_channel =
- local->scan_channel = &sband->channels[0];
+ local->oper_channel = &sband->channels[0];
+ local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
}
channels += sband->n_channels;
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 75c487229f2e..ae030688771f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -33,6 +33,7 @@
#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_IDLE_TIME (60 * HZ)
#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
@@ -95,16 +96,14 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
- struct ieee80211_bss_ht_conf ht;
struct sta_info *sta;
u32 changed = 0;
+ u16 ht_opmode;
bool enable_ht = true, ht_changed;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
- memset(&ht, 0, sizeof(ht));
-
/* HT is not supported */
if (!sband->ht_cap.ht_supported)
enable_ht = false;
@@ -148,19 +147,20 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
IEEE80211_RC_HT_CHANGED);
rcu_read_unlock();
-
}
/* disable HT */
if (!enable_ht)
return 0;
- ht.operation_mode = le16_to_cpu(hti->operation_mode);
+ ht_opmode = le16_to_cpu(hti->operation_mode);
/* if bss configuration changed store the new one */
- if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) {
+ if (!sdata->ht_opmode_valid ||
+ sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
changed |= BSS_CHANGED_HT;
- sdata->vif.bss_conf.ht = ht;
+ sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
+ sdata->ht_opmode_valid = true;
}
return changed;
@@ -1043,11 +1043,16 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock();
+ ieee80211_set_wmm_default(sdata);
+
ieee80211_recalc_idle(local);
/* channel(_type) changes are handled by ieee80211_hw_config */
local->oper_channel_type = NL80211_CHAN_NO_HT;
+ /* on the next assoc, re-program HT parameters */
+ sdata->ht_opmode_valid = false;
+
local->power_constr_level = 0;
del_timer_sync(&local->dynamic_ps_timer);
@@ -1178,6 +1183,17 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
u.mgd.beacon_loss_work);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ /*
+ * The driver has already reported this event and we have
+ * already sent a probe request. Maybe the AP died and the
+ * driver keeps reporting until we disassociate... We have
+ * to ignore that because otherwise we would continually
+ * reset the timer and never check whether we received a
+ * probe response!
+ */
+ if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL)
+ return;
+
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit()) {
printk(KERN_DEBUG "%s: driver reports beacon loss from AP %pM "
@@ -1190,7 +1206,7 @@ void ieee80211_beacon_loss_work(struct work_struct *work)
ieee80211_send_probe_req(sdata, ifmgd->bssid, ifmgd->ssid,
ifmgd->ssid_len, NULL, 0);
- mod_timer(&ifmgd->timer, jiffies + IEEE80211_MONITORING_INTERVAL);
+ mod_timer(&ifmgd->timer, jiffies + IEEE80211_PROBE_WAIT);
}
void ieee80211_beacon_loss(struct ieee80211_vif *vif)
@@ -1227,7 +1243,7 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
}
if ((ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) &&
- time_after(jiffies, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
+ time_after(jiffies, sta->last_rx + IEEE80211_PROBE_WAIT)) {
printk(KERN_DEBUG "%s: no probe response from AP %pM "
"- disassociating\n",
sdata->dev->name, ifmgd->bssid);
@@ -1577,8 +1593,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
* to between the sta_info_alloc() and sta_info_insert() above.
*/
- set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP |
- WLAN_STA_AUTHORIZED);
+ set_sta_flags(sta, WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP);
+ if (!(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+ set_sta_flags(sta, WLAN_STA_AUTHORIZED);
rates = 0;
basic_rates = 0;
@@ -1658,6 +1675,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (elems.wmm_param)
ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
elems.wmm_param_len);
+ else
+ ieee80211_set_wmm_default(sdata);
if (elems.ht_info_elem && elems.wmm_param &&
(ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d052f4004829..f962bd1b16e2 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -630,15 +630,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
* possible.
*/
- if (!ieee80211_has_protected(hdr->frame_control)) {
- if (!ieee80211_is_mgmt(hdr->frame_control) ||
- rx->sta == NULL || !test_sta_flags(rx->sta, WLAN_STA_MFP))
- return RX_CONTINUE;
- mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
- if (mmie_keyidx < 0)
- return RX_CONTINUE;
- }
-
/*
* No point in finding a key and decrypting if the frame is neither
* addressed to us nor a multicast frame.
@@ -649,8 +640,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
+ if (!ieee80211_has_protected(hdr->frame_control))
+ mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
+
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
rx->key = stakey;
+ /* Skip decryption if the frame is not protected. */
+ if (!ieee80211_has_protected(hdr->frame_control))
+ return RX_CONTINUE;
} else if (mmie_keyidx >= 0) {
/* Broadcast/multicast robust management frame / BIP */
if ((rx->status->flag & RX_FLAG_DECRYPTED) &&
@@ -661,6 +658,21 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
+ } else if (!ieee80211_has_protected(hdr->frame_control)) {
+ /*
+ * The frame was not protected, so skip decryption. However, we
+ * need to set rx->key if there is a key that could have been
+ * used so that the frame may be dropped if encryption would
+ * have been expected.
+ */
+ struct ieee80211_key *key = NULL;
+ if (ieee80211_is_mgmt(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1) &&
+ (key = rcu_dereference(rx->sdata->default_mgmt_key)))
+ rx->key = key;
+ else if ((key = rcu_dereference(rx->sdata->default_key)))
+ rx->key = key;
+ return RX_CONTINUE;
} else {
/*
* The device doesn't give us the IV so we won't be
@@ -1209,17 +1221,27 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
/* Drop unencrypted frames if key is set. */
if (unlikely(!ieee80211_has_protected(fc) &&
!ieee80211_is_nullfunc(fc) &&
- (!ieee80211_is_mgmt(fc) ||
- (ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
- rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP))) &&
- (rx->key || rx->sdata->drop_unencrypted)))
- return -EACCES;
- /* BIP does not use Protected field, so need to check MMIE */
- if (unlikely(rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP) &&
- ieee80211_is_multicast_robust_mgmt_frame(rx->skb) &&
- ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
+ ieee80211_is_data(fc) &&
(rx->key || rx->sdata->drop_unencrypted)))
return -EACCES;
+ if (rx->sta && test_sta_flags(rx->sta, WLAN_STA_MFP)) {
+ if (unlikely(ieee80211_is_unicast_robust_mgmt_frame(rx->skb) &&
+ rx->key))
+ return -EACCES;
+ /* BIP does not use Protected field, so need to check MMIE */
+ if (unlikely(ieee80211_is_multicast_robust_mgmt_frame(rx->skb)
+ && ieee80211_get_mmie_keyidx(rx->skb) < 0 &&
+ rx->key))
+ return -EACCES;
+ /*
+ * When using MFP, Action frames are not allowed prior to
+ * having configured keys.
+ */
+ if (unlikely(ieee80211_is_action(fc) && !rx->key &&
+ ieee80211_is_robust_mgmt_frame(
+ (struct ieee80211_hdr *) rx->skb->data)))
+ return -EACCES;
+ }
return 0;
}
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index c99ef8d04d3d..e65d74ba404b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -298,6 +298,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
was_hw_scan = local->hw_scanning;
local->hw_scanning = false;
local->sw_scanning = false;
+ local->scan_channel = NULL;
/* we only have to protect scan_req and hw/sw scan */
mutex_unlock(&local->scan_mtx);
@@ -558,24 +559,39 @@ void ieee80211_scan_work(struct work_struct *work)
if (skip)
break;
- next_delay = IEEE80211_PROBE_DELAY +
- usecs_to_jiffies(local->hw.channel_change_time);
+ /*
+ * Probe delay is used to update the NAV, cf. 11.1.3.2.2
+ * (which unfortunately doesn't say _why_ step a) is done,
+ * but it waits for the probe delay or until a frame is
+ * received - and the received frame would update the NAV).
+ * For now, we do not support waiting until a frame is
+ * received.
+ *
+ * In any case, it is not necessary for a passive scan.
+ */
+ if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+ !local->scan_req->n_ssids) {
+ next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
+ break;
+ }
+
+ next_delay = IEEE80211_PROBE_DELAY;
local->scan_state = SCAN_SEND_PROBE;
break;
case SCAN_SEND_PROBE:
- next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
- local->scan_state = SCAN_SET_CHANNEL;
-
- if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
- !local->scan_req->n_ssids)
- break;
for (i = 0; i < local->scan_req->n_ssids; i++)
ieee80211_send_probe_req(
sdata, NULL,
local->scan_req->ssids[i].ssid,
local->scan_req->ssids[i].ssid_len,
local->scan_req->ie, local->scan_req->ie_len);
+
+ /*
+ * After sending probe requests, wait for probe responses
+ * on the channel.
+ */
next_delay = IEEE80211_CHANNEL_TIME;
+ local->scan_state = SCAN_SET_CHANNEL;
break;
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 5f9a8d7af83d..8f68bf9746d0 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1087,7 +1087,10 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
info->flags |= IEEE80211_TX_CTL_NO_ACK;
} else {
tx->flags |= IEEE80211_TX_UNICAST;
- info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
+ if (unlikely(local->wifi_wme_noack_test))
+ info->flags |= IEEE80211_TX_CTL_NO_ACK;
+ else
+ info->flags &= ~IEEE80211_TX_CTL_NO_ACK;
}
if (tx->flags & IEEE80211_TX_FRAGMENTED) {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 97b613affe08..0689a8fbd1e6 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -708,26 +708,62 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_queue_params qparam;
- int i;
+ int queue;
+ bool use_11b;
+ int aCWmin, aCWmax;
if (!local->ops->conf_tx)
return;
memset(&qparam, 0, sizeof(qparam));
- qparam.aifs = 2;
-
- if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
- !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
- qparam.cw_min = 31;
- else
- qparam.cw_min = 15;
+ use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
+ !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
- qparam.cw_max = 1023;
- qparam.txop = 0;
+ for (queue = 0; queue < local_to_hw(local)->queues; queue++) {
+ /* Set defaults according to 802.11-2007 Table 7-37 */
+ aCWmax = 1023;
+ if (use_11b)
+ aCWmin = 31;
+ else
+ aCWmin = 15;
+
+ switch (queue) {
+ case 3: /* AC_BK */
+ qparam.cw_max = aCWmin;
+ qparam.cw_min = aCWmax;
+ qparam.txop = 0;
+ qparam.aifs = 7;
+ break;
+ default: /* never happens but let's not leave undefined */
+ case 2: /* AC_BE */
+ qparam.cw_max = aCWmin;
+ qparam.cw_min = aCWmax;
+ qparam.txop = 0;
+ qparam.aifs = 3;
+ break;
+ case 1: /* AC_VI */
+ qparam.cw_max = aCWmin;
+ qparam.cw_min = (aCWmin + 1) / 2 - 1;
+ if (use_11b)
+ qparam.txop = 6016/32;
+ else
+ qparam.txop = 3008/32;
+ qparam.aifs = 2;
+ break;
+ case 0: /* AC_VO */
+ qparam.cw_max = (aCWmin + 1) / 2 - 1;
+ qparam.cw_min = (aCWmin + 1) / 4 - 1;
+ if (use_11b)
+ qparam.txop = 3264/32;
+ else
+ qparam.txop = 1504/32;
+ qparam.aifs = 2;
+ break;
+ }
- for (i = 0; i < local_to_hw(local)->queues; i++)
- drv_conf_tx(local, i, &qparam);
+ drv_conf_tx(local, queue, &qparam);
+ }
}
void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 6b4eb8d43a4e..c14394744a9c 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -27,100 +27,6 @@
#include "aes_ccm.h"
-static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr,
- int idx, int alg, int remove,
- int set_tx_key, const u8 *_key,
- size_t key_len)
-{
- struct ieee80211_local *local = sdata->local;
- struct sta_info *sta;
- struct ieee80211_key *key;
- int err;
-
- if (alg == ALG_AES_CMAC) {
- if (idx < NUM_DEFAULT_KEYS ||
- idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
- printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d "
- "(BIP)\n", sdata->dev->name, idx);
- return -EINVAL;
- }
- } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
- printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
- sdata->dev->name, idx);
- return -EINVAL;
- }
-
- if (remove) {
- rcu_read_lock();
-
- err = 0;
-
- if (is_broadcast_ether_addr(sta_addr)) {
- key = sdata->keys[idx];
- } else {
- sta = sta_info_get(local, sta_addr);
- if (!sta) {
- err = -ENOENT;
- goto out_unlock;
- }
- key = sta->key;
- }
-
- ieee80211_key_free(key);
- } else {
- key = ieee80211_key_alloc(alg, idx, key_len, _key);
- if (!key)
- return -ENOMEM;
-
- sta = NULL;
- err = 0;
-
- rcu_read_lock();
-
- if (!is_broadcast_ether_addr(sta_addr)) {
- set_tx_key = 0;
- /*
- * According to the standard, the key index of a
- * pairwise key must be zero. However, some AP are
- * broken when it comes to WEP key indices, so we
- * work around this.
- */
- if (idx != 0 && alg != ALG_WEP) {
- ieee80211_key_free(key);
- err = -EINVAL;
- goto out_unlock;
- }
-
- sta = sta_info_get(local, sta_addr);
- if (!sta) {
- ieee80211_key_free(key);
- err = -ENOENT;
- goto out_unlock;
- }
- }
-
- if (alg == ALG_WEP &&
- key_len != LEN_WEP40 && key_len != LEN_WEP104) {
- ieee80211_key_free(key);
- err = -EINVAL;
- goto out_unlock;
- }
-
- ieee80211_key_link(key, sdata, sta);
-
- if (set_tx_key || (!sta && !sdata->default_key && key))
- ieee80211_set_default_key(sdata, idx);
- if (alg == ALG_AES_CMAC &&
- (set_tx_key || (!sta && !sdata->default_mgmt_key && key)))
- ieee80211_set_default_mgmt_key(sdata, idx);
- }
-
- out_unlock:
- rcu_read_unlock();
-
- return err;
-}
-
static int ieee80211_ioctl_siwgenie(struct net_device *dev,
struct iw_request_info *info,
struct iw_point *data, char *extra)
@@ -135,6 +41,7 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
return ret;
sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
+ sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
ieee80211_sta_req_auth(sdata);
return 0;
}
@@ -218,6 +125,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
return ret;
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
+ sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
ieee80211_sta_req_auth(sdata);
return 0;
}
@@ -275,6 +183,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
if (ret)
return ret;
sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
+ sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
ieee80211_sta_req_auth(sdata);
return 0;
} else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
@@ -472,109 +381,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
return 0;
}
-static int ieee80211_ioctl_siwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *keybuf)
-{
- struct ieee80211_sub_if_data *sdata;
- int idx, i, alg = ALG_WEP;
- u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- int remove = 0, ret;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx == 0) {
- if (sdata->default_key)
- for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->default_key == sdata->keys[i]) {
- idx = i;
- break;
- }
- }
- } else if (idx < 1 || idx > 4)
- return -EINVAL;
- else
- idx--;
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
- else if (erq->length == 0) {
- /* No key data - just set the default TX key index */
- ieee80211_set_default_key(sdata, idx);
- return 0;
- }
-
- ret = ieee80211_set_encryption(
- sdata, bcaddr,
- idx, alg, remove,
- !sdata->default_key,
- keybuf, erq->length);
-
- if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) {
- if (remove)
- sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED;
- else
- sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED;
- }
-
- return ret;
-}
-
-
-static int ieee80211_ioctl_giwencode(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *key)
-{
- struct ieee80211_sub_if_data *sdata;
- int idx, i;
-
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!sdata->default_key)
- idx = 0;
- else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->default_key == sdata->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
-
- erq->flags = idx + 1;
-
- if (!sdata->keys[idx]) {
- erq->length = 0;
- erq->flags |= IW_ENCODE_DISABLED;
- return 0;
- }
-
- memcpy(key, sdata->keys[idx]->conf.key,
- min_t(int, erq->length, sdata->keys[idx]->conf.keylen));
- erq->length = sdata->keys[idx]->conf.keylen;
- erq->flags |= IW_ENCODE_ENABLED;
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- switch (sdata->u.mgd.auth_alg) {
- case WLAN_AUTH_OPEN:
- case WLAN_AUTH_LEAP:
- erq->flags |= IW_ENCODE_OPEN;
- break;
- case WLAN_AUTH_SHARED_KEY:
- erq->flags |= IW_ENCODE_RESTRICTED;
- break;
- }
- }
-
- return 0;
-}
-
static int ieee80211_ioctl_siwpower(struct net_device *dev,
struct iw_request_info *info,
struct iw_param *wrq,
@@ -809,82 +615,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
}
-static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
- struct iw_request_info *info,
- struct iw_point *erq, char *extra)
-{
- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
- int uninitialized_var(alg), idx, i, remove = 0;
-
- switch (ext->alg) {
- case IW_ENCODE_ALG_NONE:
- remove = 1;
- break;
- case IW_ENCODE_ALG_WEP:
- alg = ALG_WEP;
- break;
- case IW_ENCODE_ALG_TKIP:
- alg = ALG_TKIP;
- break;
- case IW_ENCODE_ALG_CCMP:
- alg = ALG_CCMP;
- break;
- case IW_ENCODE_ALG_AES_CMAC:
- alg = ALG_AES_CMAC;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- if (erq->flags & IW_ENCODE_DISABLED)
- remove = 1;
-
- idx = erq->flags & IW_ENCODE_INDEX;
- if (alg == ALG_AES_CMAC) {
- if (idx < NUM_DEFAULT_KEYS + 1 ||
- idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
- idx = -1;
- if (!sdata->default_mgmt_key)
- idx = 0;
- else for (i = NUM_DEFAULT_KEYS;
- i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
- i++) {
- if (sdata->default_mgmt_key == sdata->keys[i])
- {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
- } else {
- if (idx < 1 || idx > 4) {
- idx = -1;
- if (!sdata->default_key)
- idx = 0;
- else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
- if (sdata->default_key == sdata->keys[i]) {
- idx = i;
- break;
- }
- }
- if (idx < 0)
- return -EINVAL;
- } else
- idx--;
- }
-
- return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
- remove,
- ext->ext_flags &
- IW_ENCODE_EXT_SET_TX_KEY,
- ext->key, ext->key_len);
-}
-
-
/* Structures to export the Wireless Handlers */
static const iw_handler ieee80211_handler[] =
@@ -931,8 +661,8 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
(iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
(iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
- (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
- (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
+ (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
+ (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
(iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
(iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
@@ -941,7 +671,7 @@ static const iw_handler ieee80211_handler[] =
(iw_handler) NULL, /* SIOCGIWGENIE */
(iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
(iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
- (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
(iw_handler) NULL, /* -- hole -- */
diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c
index 0b8ad1f4ecdd..45b74f38b867 100644
--- a/net/mac80211/wme.c
+++ b/net/mac80211/wme.c
@@ -133,7 +133,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
u8 *p = ieee80211_get_qos_ctl(hdr);
u8 ack_policy = 0;
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- if (local->wifi_wme_noack_test)
+ if (unlikely(local->wifi_wme_noack_test))
ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK <<
QOS_CONTROL_ACK_POLICY_SHIFT;
/* qos header is 2 bytes, second reserved */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 2006a4ee60eb..47c20eb0c04d 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1,7 +1,7 @@
/*
* This is the linux wireless configuration interface.
*
- * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
"symlink to netdev!\n");
}
dev->ieee80211_ptr->netdev = dev;
+#ifdef CONFIG_WIRELESS_EXT
+ dev->ieee80211_ptr->wext.default_key = -1;
+ dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+#endif
mutex_unlock(&rdev->devlist_mtx);
break;
case NETDEV_GOING_DOWN:
@@ -470,9 +474,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
#ifdef CONFIG_WIRELESS_EXT
if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
break;
- if (!dev->ieee80211_ptr->wext.ssid_len)
+ if (!dev->ieee80211_ptr->wext.ibss.ssid_len)
break;
- cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext);
+ cfg80211_join_ibss(rdev, dev, &dev->ieee80211_ptr->wext.ibss);
break;
#endif
case NETDEV_UNREGISTER:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3e49d3399311..f14b6c5f4221 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -1,7 +1,7 @@
/*
* Wireless configuration interface internals.
*
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#ifndef __NET_WIRELESS_CORE_H
#define __NET_WIRELESS_CORE_H
@@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
struct net_device *dev, bool nowext);
+/* internal helpers */
+int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+ const u8 *mac_addr);
+
#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 3c38afaed28a..a4a1c3498ff2 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -63,7 +63,7 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
return -EALREADY;
#ifdef CONFIG_WIRELESS_EXT
- wdev->wext.channel = params->channel;
+ wdev->wext.ibss.channel = params->channel;
#endif
err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
@@ -90,7 +90,7 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
memset(wdev->bssid, 0, ETH_ALEN);
#ifdef CONFIG_WIRELESS_EXT
if (!nowext)
- wdev->wext.ssid_len = 0;
+ wdev->wext.ibss.ssid_len = 0;
#endif
}
@@ -116,11 +116,11 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
enum ieee80211_band band;
int i;
- if (!wdev->wext.beacon_interval)
- wdev->wext.beacon_interval = 100;
+ if (!wdev->wext.ibss.beacon_interval)
+ wdev->wext.ibss.beacon_interval = 100;
/* try to find an IBSS channel if none requested ... */
- if (!wdev->wext.channel) {
+ if (!wdev->wext.ibss.channel) {
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband;
struct ieee80211_channel *chan;
@@ -135,27 +135,27 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
continue;
if (chan->flags & IEEE80211_CHAN_DISABLED)
continue;
- wdev->wext.channel = chan;
+ wdev->wext.ibss.channel = chan;
break;
}
- if (wdev->wext.channel)
+ if (wdev->wext.ibss.channel)
break;
}
- if (!wdev->wext.channel)
+ if (!wdev->wext.ibss.channel)
return -EINVAL;
}
/* don't join -- SSID is not there */
- if (!wdev->wext.ssid_len)
+ if (!wdev->wext.ibss.ssid_len)
return 0;
if (!netif_running(wdev->netdev))
return 0;
return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy),
- wdev->netdev, &wdev->wext);
+ wdev->netdev, &wdev->wext.ibss);
}
int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -182,7 +182,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
chan->flags & IEEE80211_CHAN_DISABLED))
return -EINVAL;
- if (wdev->wext.channel == chan)
+ if (wdev->wext.ibss.channel == chan)
return 0;
if (wdev->ssid_len) {
@@ -193,11 +193,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
}
if (chan) {
- wdev->wext.channel = chan;
- wdev->wext.channel_fixed = true;
+ wdev->wext.ibss.channel = chan;
+ wdev->wext.ibss.channel_fixed = true;
} else {
/* cfg80211_ibss_wext_join will pick one if needed */
- wdev->wext.channel_fixed = false;
+ wdev->wext.ibss.channel_fixed = false;
}
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
@@ -218,8 +218,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
if (wdev->current_bss)
chan = wdev->current_bss->channel;
- else if (wdev->wext.channel)
- chan = wdev->wext.channel;
+ else if (wdev->wext.ibss.channel)
+ chan = wdev->wext.ibss.channel;
if (chan) {
freq->m = chan->center_freq;
@@ -259,9 +259,9 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
if (len > 0 && ssid[len - 1] == '\0')
len--;
- wdev->wext.ssid = wdev->ssid;
- memcpy(wdev->wext.ssid, ssid, len);
- wdev->wext.ssid_len = len;
+ wdev->wext.ibss.ssid = wdev->ssid;
+ memcpy(wdev->wext.ibss.ssid, ssid, len);
+ wdev->wext.ibss.ssid_len = len;
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
}
@@ -284,10 +284,10 @@ int cfg80211_ibss_wext_giwessid(struct net_device *dev,
data->flags = 1;
data->length = wdev->ssid_len;
memcpy(ssid, wdev->ssid, data->length);
- } else if (wdev->wext.ssid && wdev->wext.ssid_len) {
+ } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
data->flags = 1;
- data->length = wdev->wext.ssid_len;
- memcpy(ssid, wdev->wext.ssid, data->length);
+ data->length = wdev->wext.ibss.ssid_len;
+ memcpy(ssid, wdev->wext.ibss.ssid, data->length);
}
return 0;
@@ -318,12 +318,12 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
bssid = NULL;
/* both automatic */
- if (!bssid && !wdev->wext.bssid)
+ if (!bssid && !wdev->wext.ibss.bssid)
return 0;
/* fixed already - and no change */
- if (wdev->wext.bssid && bssid &&
- compare_ether_addr(bssid, wdev->wext.bssid) == 0)
+ if (wdev->wext.ibss.bssid && bssid &&
+ compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
return 0;
if (wdev->ssid_len) {
@@ -334,10 +334,10 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
}
if (bssid) {
- memcpy(wdev->wext_bssid, bssid, ETH_ALEN);
- wdev->wext.bssid = wdev->wext_bssid;
+ memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
+ wdev->wext.ibss.bssid = wdev->wext.bssid;
} else
- wdev->wext.bssid = NULL;
+ wdev->wext.ibss.bssid = NULL;
return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
}
@@ -356,8 +356,8 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
ap_addr->sa_family = ARPHRD_ETHER;
- if (wdev->wext.bssid) {
- memcpy(ap_addr->sa_data, wdev->wext.bssid, ETH_ALEN);
+ if (wdev->wext.ibss.bssid) {
+ memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
return 0;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 3c53c5cbc3a9..f0fec2f49828 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1,7 +1,7 @@
/*
* This is the new netlink-based wireless configuration interface.
*
- * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/if.h>
@@ -122,6 +122,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
[NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
[NL80211_ATTR_FREQ_FIXED] = { .type = NLA_FLAG },
[NL80211_ATTR_TIMED_OUT] = { .type = NLA_FLAG },
+ [NL80211_ATTR_USE_MFP] = { .type = NLA_U32 },
+ [NL80211_ATTR_STA_FLAGS2] = {
+ .len = sizeof(struct nl80211_sta_flag_update),
+ },
+ [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG },
};
/* IE validation */
@@ -1072,6 +1077,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
}
err = func(&drv->wiphy, dev, key_idx);
+#ifdef CONFIG_WIRELESS_EXT
+ if (!err) {
+ if (func == drv->ops->set_default_key)
+ dev->ieee80211_ptr->wext.default_key = key_idx;
+ else
+ dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
+ }
+#endif
out:
cfg80211_put_dev(drv);
@@ -1102,6 +1115,11 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
params.key_len = nla_len(info->attrs[NL80211_ATTR_KEY_DATA]);
}
+ if (info->attrs[NL80211_ATTR_KEY_SEQ]) {
+ params.seq = nla_data(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ params.seq_len = nla_len(info->attrs[NL80211_ATTR_KEY_SEQ]);
+ }
+
if (info->attrs[NL80211_ATTR_KEY_IDX])
key_idx = nla_get_u8(info->attrs[NL80211_ATTR_KEY_IDX]);
@@ -1110,44 +1128,8 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
if (info->attrs[NL80211_ATTR_MAC])
mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
- if (key_idx > 5)
- return -EINVAL;
-
- /*
- * Disallow pairwise keys with non-zero index unless it's WEP
- * (because current deployments use pairwise WEP keys with
- * non-zero indizes but 802.11i clearly specifies to use zero)
- */
- if (mac_addr && key_idx &&
- params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
- params.cipher != WLAN_CIPHER_SUITE_WEP104)
- return -EINVAL;
-
- /* TODO: add definitions for the lengths to linux/ieee80211.h */
- switch (params.cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- if (params.key_len != 5)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- if (params.key_len != 32)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- if (params.key_len != 16)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- if (params.key_len != 13)
- return -EINVAL;
- break;
- case WLAN_CIPHER_SUITE_AES_CMAC:
- if (params.key_len != 16)
- return -EINVAL;
- break;
- default:
+ if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
return -EINVAL;
- }
rtnl_lock();
@@ -1209,6 +1191,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
+#ifdef CONFIG_WIRELESS_EXT
+ if (!err) {
+ if (key_idx == dev->ieee80211_ptr->wext.default_key)
+ dev->ieee80211_ptr->wext.default_key = -1;
+ else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
+ dev->ieee80211_ptr->wext.default_mgmt_key = -1;
+ }
+#endif
+
out:
cfg80211_put_dev(drv);
dev_put(dev);
@@ -1349,15 +1340,36 @@ static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
[NL80211_STA_FLAG_AUTHORIZED] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_SHORT_PREAMBLE] = { .type = NLA_FLAG },
[NL80211_STA_FLAG_WME] = { .type = NLA_FLAG },
+ [NL80211_STA_FLAG_MFP] = { .type = NLA_FLAG },
};
-static int parse_station_flags(struct nlattr *nla, u32 *staflags)
+static int parse_station_flags(struct genl_info *info,
+ struct station_parameters *params)
{
struct nlattr *flags[NL80211_STA_FLAG_MAX + 1];
+ struct nlattr *nla;
int flag;
- *staflags = 0;
+ /*
+ * Try parsing the new attribute first so userspace
+ * can specify both for older kernels.
+ */
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS2];
+ if (nla) {
+ struct nl80211_sta_flag_update *sta_flags;
+
+ sta_flags = nla_data(nla);
+ params->sta_flags_mask = sta_flags->mask;
+ params->sta_flags_set = sta_flags->set;
+ if ((params->sta_flags_mask |
+ params->sta_flags_set) & BIT(__NL80211_STA_FLAG_INVALID))
+ return -EINVAL;
+ return 0;
+ }
+
+ /* if present, parse the old attribute */
+ nla = info->attrs[NL80211_ATTR_STA_FLAGS];
if (!nla)
return 0;
@@ -1365,11 +1377,12 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags)
nla, sta_flags_policy))
return -EINVAL;
- *staflags = STATION_FLAG_CHANGED;
+ params->sta_flags_mask = (1 << __NL80211_STA_FLAG_AFTER_LAST) - 1;
+ params->sta_flags_mask &= ~1;
for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++)
if (flags[flag])
- *staflags |= (1<<flag);
+ params->sta_flags_set |= (1<<flag);
return 0;
}
@@ -1665,8 +1678,7 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
- &params.station_flags))
+ if (parse_station_flags(info, &params))
return -EINVAL;
if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION])
@@ -1735,8 +1747,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
params.ht_capa =
nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]);
- if (parse_station_flags(info->attrs[NL80211_ATTR_STA_FLAGS],
- &params.station_flags))
+ if (parse_station_flags(info, &params))
return -EINVAL;
rtnl_lock();
@@ -1745,6 +1756,12 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out_rtnl;
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+ err = -EINVAL;
+ goto out;
+ }
+
err = get_vlan(info->attrs[NL80211_ATTR_STA_VLAN], drv, &params.vlan);
if (err)
goto out;
@@ -1788,6 +1805,12 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info)
if (err)
goto out_rtnl;
+ if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+ dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (!drv->ops->del_station) {
err = -EOPNOTSUPP;
goto out;
@@ -3012,6 +3035,19 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
}
+ if (info->attrs[NL80211_ATTR_USE_MFP]) {
+ enum nl80211_mfp use_mfp =
+ nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]);
+ if (use_mfp == NL80211_MFP_REQUIRED)
+ req.use_mfp = true;
+ else if (use_mfp != NL80211_MFP_NO) {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+ req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT];
+
err = drv->ops->assoc(&drv->wiphy, dev, &req);
out:
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 5f7e997195c7..beb226e78cd7 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
if (wiphy->bands[band])
set_mandatory_flags_band(wiphy->bands[band], band);
}
+
+int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
+ const u8 *mac_addr)
+{
+ if (key_idx > 5)
+ return -EINVAL;
+
+ /*
+ * Disallow pairwise keys with non-zero index unless it's WEP
+ * (because current deployments use pairwise WEP keys with
+ * non-zero indizes but 802.11i clearly specifies to use zero)
+ */
+ if (mac_addr && key_idx &&
+ params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
+ params->cipher != WLAN_CIPHER_SUITE_WEP104)
+ return -EINVAL;
+
+ /* TODO: add definitions for the lengths to linux/ieee80211.h */
+ switch (params->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ if (params->key_len != 5)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ if (params->key_len != 32)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ if (params->key_len != 16)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_WEP104:
+ if (params->key_len != 13)
+ return -EINVAL;
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ if (params->key_len != 16)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 5ef82f2ca88f..f98090b90fbf 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -5,12 +5,13 @@
* into cfg80211, when that happens all the exports here go away and
* we directly assign the wireless handlers of wireless interfaces.
*
- * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
*/
#include <linux/wireless.h>
#include <linux/nl80211.h>
#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
#include <net/iw_handler.h>
#include <net/cfg80211.h>
#include "core.h"
@@ -296,22 +297,34 @@ EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
struct iw_freq *freq)
{
+ struct ieee80211_channel *chan;
+ int f;
+
+ /*
+ * Parse frequency - return NULL for auto and
+ * -EINVAL for impossible things.
+ */
if (freq->e == 0) {
if (freq->m < 0)
return NULL;
- else
- return ieee80211_get_channel(wiphy,
- ieee80211_channel_to_frequency(freq->m));
+ f = ieee80211_channel_to_frequency(freq->m);
} else {
int i, div = 1000000;
for (i = 0; i < freq->e; i++)
div /= 10;
- if (div > 0)
- return ieee80211_get_channel(wiphy, freq->m / div);
- else
+ if (div <= 0)
return ERR_PTR(-EINVAL);
+ f = freq->m / div;
}
+ /*
+ * Look up channel struct and return -EINVAL when
+ * it cannot be found.
+ */
+ chan = ieee80211_get_channel(wiphy, f);
+ if (!chan)
+ return ERR_PTR(-EINVAL);
+ return chan;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
@@ -465,3 +478,262 @@ int cfg80211_wext_giwretry(struct net_device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
+
+static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
+ struct net_device *dev, const u8 *addr,
+ bool remove, bool tx_key, int idx,
+ struct key_params *params)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
+
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (!rdev->ops->set_default_mgmt_key)
+ return -EOPNOTSUPP;
+
+ if (idx < 4 || idx > 5)
+ return -EINVAL;
+ } else if (idx < 0 || idx > 3)
+ return -EINVAL;
+
+ if (remove) {
+ err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
+ if (!err) {
+ if (idx == wdev->wext.default_key)
+ wdev->wext.default_key = -1;
+ else if (idx == wdev->wext.default_mgmt_key)
+ wdev->wext.default_mgmt_key = -1;
+ }
+ return err;
+ } else {
+ if (addr)
+ tx_key = false;
+
+ if (cfg80211_validate_key_settings(params, idx, addr))
+ return -EINVAL;
+
+ err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
+ if (err)
+ return err;
+
+ if (tx_key || (!addr && wdev->wext.default_key == -1)) {
+ err = rdev->ops->set_default_key(&rdev->wiphy,
+ dev, idx);
+ if (!err)
+ wdev->wext.default_key = idx;
+ return err;
+ }
+
+ if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
+ (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
+ err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
+ dev, idx);
+ if (!err)
+ wdev->wext.default_mgmt_key = idx;
+ return err;
+ }
+
+ return 0;
+ }
+}
+
+int cfg80211_wext_siwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int idx, err;
+ bool remove = false;
+ struct key_params params;
+
+ /* no use -- only MFP (set_default_mgmt_key) is optional */
+ if (!rdev->ops->del_key ||
+ !rdev->ops->add_key ||
+ !rdev->ops->set_default_key)
+ return -EOPNOTSUPP;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx == 0) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ idx = 0;
+ } else if (idx < 1 || idx > 4)
+ return -EINVAL;
+ else
+ idx--;
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ remove = true;
+ else if (erq->length == 0) {
+ /* No key data - just set the default TX key index */
+ err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
+ if (!err)
+ wdev->wext.default_key = idx;
+ return err;
+ }
+
+ memset(&params, 0, sizeof(params));
+ params.key = keybuf;
+ params.key_len = erq->length;
+ if (erq->length == 5)
+ params.cipher = WLAN_CIPHER_SUITE_WEP40;
+ else if (erq->length == 13)
+ params.cipher = WLAN_CIPHER_SUITE_WEP104;
+ else if (!remove)
+ return -EINVAL;
+
+ return cfg80211_set_encryption(rdev, dev, NULL, remove,
+ wdev->wext.default_key == -1,
+ idx, &params);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode);
+
+int cfg80211_wext_siwencodeext(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *extra)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
+ const u8 *addr;
+ int idx;
+ bool remove = false;
+ struct key_params params;
+ u32 cipher;
+
+ /* no use -- only MFP (set_default_mgmt_key) is optional */
+ if (!rdev->ops->del_key ||
+ !rdev->ops->add_key ||
+ !rdev->ops->set_default_key)
+ return -EOPNOTSUPP;
+
+ switch (ext->alg) {
+ case IW_ENCODE_ALG_NONE:
+ remove = true;
+ cipher = 0;
+ break;
+ case IW_ENCODE_ALG_WEP:
+ if (ext->key_len == 5)
+ cipher = WLAN_CIPHER_SUITE_WEP40;
+ else if (ext->key_len == 13)
+ cipher = WLAN_CIPHER_SUITE_WEP104;
+ else
+ return -EINVAL;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ cipher = WLAN_CIPHER_SUITE_TKIP;
+ break;
+ case IW_ENCODE_ALG_CCMP:
+ cipher = WLAN_CIPHER_SUITE_CCMP;
+ break;
+ case IW_ENCODE_ALG_AES_CMAC:
+ cipher = WLAN_CIPHER_SUITE_AES_CMAC;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (erq->flags & IW_ENCODE_DISABLED)
+ remove = true;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ if (idx < 4 || idx > 5) {
+ idx = wdev->wext.default_mgmt_key;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ } else {
+ if (idx < 1 || idx > 4) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ return -EINVAL;
+ } else
+ idx--;
+ }
+
+ addr = ext->addr.sa_data;
+ if (is_broadcast_ether_addr(addr))
+ addr = NULL;
+
+ memset(&params, 0, sizeof(params));
+ params.key = ext->key;
+ params.key_len = ext->key_len;
+ params.cipher = cipher;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
+ params.seq = ext->rx_seq;
+ params.seq_len = 6;
+ }
+
+ return cfg80211_set_encryption(
+ rdev, dev, addr, remove,
+ ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
+ idx, &params);
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
+
+struct giwencode_cookie {
+ size_t buflen;
+ char *keybuf;
+};
+
+static void giwencode_get_key_cb(void *cookie, struct key_params *params)
+{
+ struct giwencode_cookie *data = cookie;
+
+ if (!params->key) {
+ data->buflen = 0;
+ return;
+ }
+
+ data->buflen = min_t(size_t, data->buflen, params->key_len);
+ memcpy(data->keybuf, params->key, data->buflen);
+}
+
+int cfg80211_wext_giwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq, char *keybuf)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ int idx, err;
+ struct giwencode_cookie data = {
+ .keybuf = keybuf,
+ .buflen = erq->length,
+ };
+
+ if (!rdev->ops->get_key)
+ return -EOPNOTSUPP;
+
+ idx = erq->flags & IW_ENCODE_INDEX;
+ if (idx == 0) {
+ idx = wdev->wext.default_key;
+ if (idx < 0)
+ idx = 0;
+ } else if (idx < 1 || idx > 4)
+ return -EINVAL;
+ else
+ idx--;
+
+ erq->flags = idx + 1;
+
+ err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
+ giwencode_get_key_cb);
+ if (!err) {
+ erq->length = data.buflen;
+ erq->flags |= IW_ENCODE_ENABLED;
+ return 0;
+ }
+
+ if (err == -ENOENT) {
+ erq->flags |= IW_ENCODE_DISABLED;
+ erq->length = 0;
+ return 0;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
diff --git a/net/wireless/wext.c b/net/wireless/wext.c
index cb6a5bb85d80..d3bbef70cc7c 100644
--- a/net/wireless/wext.c
+++ b/net/wireless/wext.c
@@ -649,14 +649,26 @@ static int wireless_seq_show(struct seq_file *seq, void *v)
return 0;
}
+static void *wireless_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ rtnl_lock();
+ return dev_seq_start(seq, pos);
+}
+
+static void wireless_dev_seq_stop(struct seq_file *seq, void *v)
+{
+ dev_seq_stop(seq, v);
+ rtnl_unlock();
+}
+
static const struct seq_operations wireless_seq_ops = {
- .start = dev_seq_start,
+ .start = wireless_dev_seq_start,
.next = dev_seq_next,
- .stop = dev_seq_stop,
+ .stop = wireless_dev_seq_stop,
.show = wireless_seq_show,
};
-static int wireless_seq_open(struct inode *inode, struct file *file)
+static int seq_open_wireless(struct inode *inode, struct file *file)
{
return seq_open_net(inode, file, &wireless_seq_ops,
sizeof(struct seq_net_private));
@@ -664,7 +676,7 @@ static int wireless_seq_open(struct inode *inode, struct file *file)
static const struct file_operations wireless_seq_fops = {
.owner = THIS_MODULE,
- .open = wireless_seq_open,
+ .open = seq_open_wireless,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_net,