Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6

This commit is contained in:
David S. Miller 2009-05-18 14:48:30 -07:00
commit 82d048186e
49 changed files with 1124 additions and 1021 deletions

View file

@ -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,

View file

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

View file

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

View file

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

View file

@ -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

View file

@ -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,

View file

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

View file

@ -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

View file

@ -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*/

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 */
final_mode = priv->power_data.user_power_setting;
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;
/* 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);

View file

@ -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__ */

View file

@ -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,

View file

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

View file

@ -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) {

View file

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

View file

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

View file

@ -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---

View file

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

View file

@ -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,
@ -684,6 +707,18 @@ enum nl80211_sta_flags {
NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
};
/**
* 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
*
@ -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 */

View file

@ -251,27 +251,6 @@ struct beacon_parameters {
int head_len, tail_len;
};
/**
* 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
*
@ -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

View file

@ -72,22 +72,6 @@
* not do so then mac80211 may add this under certain circumstances.
*/
/**
* 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
*
@ -170,14 +154,6 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_ENABLED = 1<<9,
};
/**
* 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
*
@ -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;
};
/**

View file

@ -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,35 +630,39 @@ 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;
sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
if (params->station_flags & STATION_FLAG_SHORT_PREAMBLE)
sta->flags |= WLAN_STA_SHORT_PREAMBLE;
sta->flags &= ~WLAN_STA_WME;
if (params->station_flags & STATION_FLAG_WME)
sta->flags |= WLAN_STA_WME;
sta->flags &= ~WLAN_STA_MFP;
if (params->station_flags & STATION_FLAG_MFP)
sta->flags |= WLAN_STA_MFP;
spin_unlock_bh(&sta->lock);
}
if (mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE)) {
sta->flags &= ~WLAN_STA_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 (set & BIT(NL80211_STA_FLAG_WME))
sta->flags |= WLAN_STA_WME;
}
if (mask & BIT(NL80211_STA_FLAG_MFP)) {
sta->flags &= ~WLAN_STA_MFP;
if (set & BIT(NL80211_STA_FLAG_MFP))
sta->flags |= WLAN_STA_MFP;
}
spin_unlock_bh(&sta->lock);
/*
* FIXME: updating the following information is racy when this
* function is called from ieee80211_change_station().
@ -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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.

View file

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

View file

@ -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) &&

View file

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

View file

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

View file

@ -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) {

View file

@ -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;
use_11b = (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
!(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE))
qparam.cw_min = 31;
else
qparam.cw_min = 15;
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;
qparam.cw_max = 1023;
qparam.txop = 0;
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,

View file

@ -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 -- */

View file

@ -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 */

View file

@ -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:

View file

@ -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 */

View file

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

View file

@ -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,45 +1128,9 @@ 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)
if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
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;
}
rtnl_lock();
err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@ -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:

View file

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

View file

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

View file

@ -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,