forked from luck/tmp_suning_uos_patched
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
commit
82d048186e
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
|
||||
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 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
* 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 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
* 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 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
|
||||
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
|
||||
|
@ -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*/
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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__ */
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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---
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) &&
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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 -- */
|
||||
|
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(¶ms, 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],
|
||||
¶ms.station_flags))
|
||||
if (parse_station_flags(info, ¶ms))
|
||||
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],
|
||||
¶ms.station_flags))
|
||||
if (parse_station_flags(info, ¶ms))
|
||||
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, ¶ms.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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(¶ms, 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, ¶ms);
|
||||
}
|
||||
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(¶ms, 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, ¶ms);
|
||||
}
|
||||
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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user