···295295 /* Several PCIe massages to ensure proper behaviour */296296 if (ah->config.pcie_waen)297297 REG_WRITE(ah, AR_WA, ah->config.pcie_waen);298298+ else299299+ REG_WRITE(ah, AR_WA, ah->WARegVal);300300+ }301301+302302+ /*303303+ * Configire PCIE after Ini init. SERDES values now come from ini file304304+ * This enables PCIe low power mode.305305+ */306306+ if (ah->config.pcieSerDesWrite) {307307+ unsigned int i;308308+ struct ar5416IniArray *array;309309+310310+ array = power_off ? &ah->iniPcieSerdes :311311+ &ah->iniPcieSerdesLowPower;312312+313313+ for (i = 0; i < array->ia_rows; i++) {314314+ REG_WRITE(ah,315315+ INI_RA(array, i, 0),316316+ INI_RA(array, i, 1));317317+ }298318 }299319}300320
···244244 */245245246246 switch(devid) {247247- case 0x9271:248248- case 0x1006:249249- priv->htc->credits = 33;250250- break;251247 case 0x7010:248248+ case 0x9018:252249 priv->htc->credits = 45;253250 break;254251 default:255255- dev_err(priv->dev, "ath9k_htc: Unsupported device id: 0x%x\n",256256- devid);257257- goto err;252252+ priv->htc->credits = 33;258253 }259254260255 ret = htc_init(priv->htc);
+2
drivers/net/wireless/ath/ath9k/htc_drv_main.c
···931931 priv->ah->led_pin = ATH_LED_PIN_9287;932932 else if (AR_SREV_9271(priv->ah))933933 priv->ah->led_pin = ATH_LED_PIN_9271;934934+ else if (AR_DEVID_7010(priv->ah))935935+ priv->ah->led_pin = ATH_LED_PIN_7010;934936 else935937 priv->ah->led_pin = ATH_LED_PIN_DEF;936938
+83-36
drivers/net/wireless/ath/ath9k/hw.c
···388388 ah->config.ht_enable = 0;389389390390 ah->config.rx_intr_mitigation = true;391391+ ah->config.pcieSerDesWrite = true;391392392393 /*393394 * We need this for PCI devices only (Cardbus, PCI, miniPCI)···572571 ath9k_hw_init_mode_regs(ah);573572574573 /*575575- * Configire PCIE after Ini init. SERDES values now come from ini file576576- * This enables PCIe low power mode.574574+ * Read back AR_WA into a permanent copy and set bits 14 and 17.575575+ * We need to do this to avoid RMW of this register. We cannot576576+ * read the reg when chip is asleep.577577 */578578- if (AR_SREV_9300_20_OR_LATER(ah)) {579579- u32 regval;580580- unsigned int i;581581-582582- /* Set Bits 16 and 17 in the AR_WA register. */583583- regval = REG_READ(ah, AR_WA);584584- regval |= 0x00030000;585585- REG_WRITE(ah, AR_WA, regval);586586-587587- for (i = 0; i < ah->iniPcieSerdesLowPower.ia_rows; i++) {588588- REG_WRITE(ah,589589- INI_RA(&ah->iniPcieSerdesLowPower, i, 0),590590- INI_RA(&ah->iniPcieSerdesLowPower, i, 1));591591- }592592- }578578+ ah->WARegVal = REG_READ(ah, AR_WA);579579+ ah->WARegVal |= (AR_WA_D3_L1_DISABLE |580580+ AR_WA_ASPM_TIMER_BASED_DISABLE);593581594582 if (ah->is_pciexpress)595583 ath9k_hw_configpcipowersave(ah, 0, 0);···999100910001010 ENABLE_REGWRITE_BUFFER(ah);1001101110121012+ if (AR_SREV_9300_20_OR_LATER(ah)) {10131013+ REG_WRITE(ah, AR_WA, ah->WARegVal);10141014+ udelay(10);10151015+ }10161016+10021017 REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |10031018 AR_RTC_FORCE_WAKE_ON_INT);10041019···10581063{10591064 ENABLE_REGWRITE_BUFFER(ah);1060106510661066+ if (AR_SREV_9300_20_OR_LATER(ah)) {10671067+ REG_WRITE(ah, AR_WA, ah->WARegVal);10681068+ udelay(10);10691069+ }10701070+10611071 REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |10621072 AR_RTC_FORCE_WAKE_ON_INT);10631073···10701070 REG_WRITE(ah, AR_RC, AR_RC_AHB);1071107110721072 REG_WRITE(ah, AR_RTC_RESET, 0);10731073+ udelay(2);1073107410741075 REGWRITE_BUFFER_FLUSH(ah);10751076 DISABLE_REGWRITE_BUFFER(ah);···1100109911011100static bool ath9k_hw_set_reset_reg(struct ath_hw *ah, u32 type)11021101{11021102+ if (AR_SREV_9300_20_OR_LATER(ah)) {11031103+ REG_WRITE(ah, AR_WA, ah->WARegVal);11041104+ udelay(10);11051105+ }11061106+11031107 REG_WRITE(ah, AR_RTC_FORCE_WAKE,11041108 AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT);11051109···12681262 macStaId1 = REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_BASE_RATE_11B;1269126312701264 /* For chips on which RTC reset is done, save TSF before it gets cleared */12711271- if (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))12651265+ if (AR_SREV_9100(ah) ||12661266+ (AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL)))12721267 tsf = ath9k_hw_gettsf64(ah);1273126812741269 saveLedState = REG_READ(ah, AR_CFG_LED) &···13011294 }1302129513031296 /* Restore TSF */13041304- if (tsf && AR_SREV_9280(ah) && ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))12971297+ if (tsf)13051298 ath9k_hw_settsf64(ah, tsf);1306129913071300 if (AR_SREV_9280_10_OR_LATER(ah))···13131306 r = ath9k_hw_process_ini(ah, chan);13141307 if (r)13151308 return r;13091309+13101310+ /*13111311+ * Some AR91xx SoC devices frequently fail to accept TSF writes13121312+ * right after the chip reset. When that happens, write a new13131313+ * value after the initvals have been applied, with an offset13141314+ * based on measured time difference13151315+ */13161316+ if (AR_SREV_9100(ah) && (ath9k_hw_gettsf64(ah) < tsf)) {13171317+ tsf += 1500;13181318+ ath9k_hw_settsf64(ah, tsf);13191319+ }1316132013171321 /* Setup MFP options for CCMP */13181322 if (AR_SREV_9280_20_OR_LATER(ah)) {···15101492}15111493EXPORT_SYMBOL(ath9k_hw_keyreset);1512149415131513-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)14951495+static bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)15141496{15151497 u32 macHi, macLo;15161498 u32 unicast_flag = AR_KEYTABLE_VALID;···1548153015491531 return true;15501532}15511551-EXPORT_SYMBOL(ath9k_hw_keysetmac);1552153315531534bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,15541535 const struct ath9k_keyval *k,···17481731}17491732EXPORT_SYMBOL(ath9k_hw_set_keycache_entry);1750173317511751-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry)17521752-{17531753- if (entry < ah->caps.keycache_size) {17541754- u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry));17551755- if (val & AR_KEYTABLE_VALID)17561756- return true;17571757- }17581758- return false;17591759-}17601760-EXPORT_SYMBOL(ath9k_hw_keyisvalid);17611761-17621734/******************************/17631735/* Power Management (Chipset) */17641736/******************************/···17741768 REG_CLR_BIT(ah, (AR_RTC_RESET),17751769 AR_RTC_RESET_EN);17761770 }17711771+17721772+ /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */17731773+ if (AR_SREV_9300_20_OR_LATER(ah))17741774+ REG_WRITE(ah, AR_WA,17751775+ ah->WARegVal & ~AR_WA_D3_L1_DISABLE);17771776}1778177717791778/*···18051794 AR_RTC_FORCE_WAKE_EN);18061795 }18071796 }17971797+17981798+ /* Clear Bit 14 of AR_WA after putting chip into Net Sleep mode. */17991799+ if (AR_SREV_9300_20_OR_LATER(ah))18001800+ REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE);18081801}1809180218101803static bool ath9k_hw_set_power_awake(struct ath_hw *ah, int setChip)18111804{18121805 u32 val;18131806 int i;18071807+18081808+ /* Set Bits 14 and 17 of AR_WA before powering on the chip. */18091809+ if (AR_SREV_9300_20_OR_LATER(ah)) {18101810+ REG_WRITE(ah, AR_WA, ah->WARegVal);18111811+ udelay(10);18121812+ }1814181318151814 if (setChip) {18161815 if ((REG_READ(ah, AR_RTC_STATUS) &···2176215521772156 if (AR_SREV_9271(ah))21782157 pCap->num_gpio_pins = AR9271_NUM_GPIO;21582158+ else if (AR_DEVID_7010(ah))21592159+ pCap->num_gpio_pins = AR7010_NUM_GPIO;21792160 else if (AR_SREV_9285_10_OR_LATER(ah))21802161 pCap->num_gpio_pins = AR9285_NUM_GPIO;21812162 else if (AR_SREV_9280_10_OR_LATER(ah))···2318229523192296 BUG_ON(gpio >= ah->caps.num_gpio_pins);2320229723212321- gpio_shift = gpio << 1;22982298+ if (AR_DEVID_7010(ah)) {22992299+ gpio_shift = gpio;23002300+ REG_RMW(ah, AR7010_GPIO_OE,23012301+ (AR7010_GPIO_OE_AS_INPUT << gpio_shift),23022302+ (AR7010_GPIO_OE_MASK << gpio_shift));23032303+ return;23042304+ }2322230523062306+ gpio_shift = gpio << 1;23232307 REG_RMW(ah,23242308 AR_GPIO_OE_OUT,23252309 (AR_GPIO_OE_OUT_DRV_NO << gpio_shift),···23422312 if (gpio >= ah->caps.num_gpio_pins)23432313 return 0xffffffff;2344231423452345- if (AR_SREV_9300_20_OR_LATER(ah))23152315+ if (AR_DEVID_7010(ah)) {23162316+ u32 val;23172317+ val = REG_READ(ah, AR7010_GPIO_IN);23182318+ return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;23192319+ } else if (AR_SREV_9300_20_OR_LATER(ah))23462320 return MS_REG_READ(AR9300, gpio) != 0;23472321 else if (AR_SREV_9271(ah))23482322 return MS_REG_READ(AR9271, gpio) != 0;···23662332{23672333 u32 gpio_shift;2368233423352335+ if (AR_DEVID_7010(ah)) {23362336+ gpio_shift = gpio;23372337+ REG_RMW(ah, AR7010_GPIO_OE,23382338+ (AR7010_GPIO_OE_AS_OUTPUT << gpio_shift),23392339+ (AR7010_GPIO_OE_MASK << gpio_shift));23402340+ return;23412341+ }23422342+23692343 ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type);23702370-23712344 gpio_shift = 2 * gpio;23722372-23732345 REG_RMW(ah,23742346 AR_GPIO_OE_OUT,23752347 (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift),···2385234523862346void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val)23872347{23482348+ if (AR_DEVID_7010(ah)) {23492349+ val = val ? 0 : 1;23502350+ REG_RMW(ah, AR7010_GPIO_OUT, ((val&1) << gpio),23512351+ AR_GPIO_BIT(gpio));23522352+ return;23532353+ }23542354+23882355 if (AR_SREV_9271(ah))23892356 val = ~val;23902357
+7-2
drivers/net/wireless/ath/ath9k/hw.h
···235235 int ack_6mb;236236 u32 cwm_ignore_extcca;237237 u8 pcie_powersave_enable;238238+ bool pcieSerDesWrite;238239 u8 pcie_clock_req;239240 u32 pcie_waen;240241 u8 analog_shiftreg;···820819821820 u32 paprd_gain_table_entries[PAPRD_GAIN_TABLE_ENTRIES];822821 u8 paprd_gain_table_index[PAPRD_GAIN_TABLE_ENTRIES];822822+ /*823823+ * Store the permanent value of Reg 0x4004in WARegVal824824+ * so we dont have to R/M/W. We should not be reading825825+ * this register when in sleep states.826826+ */827827+ u32 WARegVal;823828};824829825830static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)···859852860853/* Key Cache Management */861854bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);862862-bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);863855bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,864856 const struct ath9k_keyval *k,865857 const u8 *mac);866866-bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);867858868859/* GPIO / RFKILL / Antennae */869860void ath9k_hw_cfg_gpio_input(struct ath_hw *ah, u32 gpio);
+4
drivers/net/wireless/ath/ath9k/init.c
···3333module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);3434MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");35353636+int led_blink = 1;3737+module_param_named(blink, led_blink, int, 0444);3838+MODULE_PARM_DESC(blink, "Enable LED blink on activity");3939+3640/* We use the hw_value as an index into our private channel structure */37413842#define CHAN2G(_freq, _idx) { \
···18041804 dma_reason[2], dma_reason[3],18051805 dma_reason[4], dma_reason[5]);18061806 b43err(dev->wl, "This device does not support DMA "18071807- "on your system. Please use PIO instead.\n");18071807+ "on your system. It will now be switched to PIO.\n");18081808 /* Fall back to PIO transfers if we get fatal DMA errors! */18091809 dev->use_pio = 1;18101810 b43_controller_restart(dev, "DMA error");
···214214static void iwlagn_rts_tx_cmd_flag(struct ieee80211_tx_info *info,215215 __le32 *tx_flags)216216{217217- if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) ||218218- (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT))219219- *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK;220220- else221221- *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK;217217+ *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;222218}223219224220/* Calc max signal level (dBm) among 3 possible receivers */
+2-1
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
···361361void iwlagn_temperature(struct iwl_priv *priv)362362{363363 /* store temperature from statistics (in Celsius) */364364- priv->temperature = le32_to_cpu(priv->statistics.general.temperature);364364+ priv->temperature =365365+ le32_to_cpu(priv->_agn.statistics.general.temperature);365366 iwl_tt_handler(priv);366367}367368
+5-12
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
···324324 struct iwl_lq_sta *lq_data,325325 struct ieee80211_sta *sta)326326{327327- if ((tid < TID_MAX_LOAD_COUNT) &&328328- !rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta)) {329329- if (priv->cfg->use_rts_for_ht) {330330- /*331331- * switch to RTS/CTS if it is the prefer protection332332- * method for HT traffic333333- */334334- IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");335335- priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;336336- iwlcore_commit_rxon(priv);337337- }338338- }327327+ if (tid < TID_MAX_LOAD_COUNT)328328+ rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);329329+ else330330+ IWL_ERR(priv, "tid exceeds max load count: %d/%d\n",331331+ tid, TID_MAX_LOAD_COUNT);339332}340333341334static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
+284
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
···11+/******************************************************************************22+ *33+ * GPL LICENSE SUMMARY44+ *55+ * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.66+ *77+ * This program is free software; you can redistribute it and/or modify88+ * it under the terms of version 2 of the GNU General Public License as99+ * published by the Free Software Foundation.1010+ *1111+ * This program is distributed in the hope that it will be useful, but1212+ * WITHOUT ANY WARRANTY; without even the implied warranty of1313+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU1414+ * General Public License for more details.1515+ *1616+ * You should have received a copy of the GNU General Public License1717+ * along with this program; if not, write to the Free Software1818+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,1919+ * USA2020+ *2121+ * The full GNU General Public License is included in this distribution2222+ * in the file called LICENSE.GPL.2323+ *2424+ * Contact Information:2525+ * Intel Linux Wireless <ilw@linux.intel.com>2626+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-64972727+ *2828+ *****************************************************************************/2929+3030+#include <linux/kernel.h>3131+#include <linux/module.h>3232+#include <linux/init.h>3333+#include <linux/sched.h>3434+3535+#include "iwl-dev.h"3636+#include "iwl-core.h"3737+#include "iwl-calib.h"3838+#include "iwl-sta.h"3939+#include "iwl-io.h"4040+#include "iwl-helpers.h"4141+#include "iwl-agn-hw.h"4242+#include "iwl-agn.h"4343+4444+void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,4545+ struct iwl_rx_mem_buffer *rxb)4646+4747+{4848+ struct iwl_rx_packet *pkt = rxb_addr(rxb);4949+ struct iwl_missed_beacon_notif *missed_beacon;5050+5151+ missed_beacon = &pkt->u.missed_beacon;5252+ if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >5353+ priv->missed_beacon_threshold) {5454+ IWL_DEBUG_CALIB(priv,5555+ "missed bcn cnsq %d totl %d rcd %d expctd %d\n",5656+ le32_to_cpu(missed_beacon->consecutive_missed_beacons),5757+ le32_to_cpu(missed_beacon->total_missed_becons),5858+ le32_to_cpu(missed_beacon->num_recvd_beacons),5959+ le32_to_cpu(missed_beacon->num_expected_beacons));6060+ if (!test_bit(STATUS_SCANNING, &priv->status))6161+ iwl_init_sensitivity(priv);6262+ }6363+}6464+6565+/* Calculate noise level, based on measurements during network silence just6666+ * before arriving beacon. This measurement can be done only if we know6767+ * exactly when to expect beacons, therefore only when we're associated. */6868+static void iwl_rx_calc_noise(struct iwl_priv *priv)6969+{7070+ struct statistics_rx_non_phy *rx_info7171+ = &(priv->_agn.statistics.rx.general);7272+ int num_active_rx = 0;7373+ int total_silence = 0;7474+ int bcn_silence_a =7575+ le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;7676+ int bcn_silence_b =7777+ le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;7878+ int bcn_silence_c =7979+ le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;8080+ int last_rx_noise;8181+8282+ if (bcn_silence_a) {8383+ total_silence += bcn_silence_a;8484+ num_active_rx++;8585+ }8686+ if (bcn_silence_b) {8787+ total_silence += bcn_silence_b;8888+ num_active_rx++;8989+ }9090+ if (bcn_silence_c) {9191+ total_silence += bcn_silence_c;9292+ num_active_rx++;9393+ }9494+9595+ /* Average among active antennas */9696+ if (num_active_rx)9797+ last_rx_noise = (total_silence / num_active_rx) - 107;9898+ else9999+ last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;100100+101101+ IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",102102+ bcn_silence_a, bcn_silence_b, bcn_silence_c,103103+ last_rx_noise);104104+}105105+106106+#ifdef CONFIG_IWLWIFI_DEBUGFS107107+/*108108+ * based on the assumption of all statistics counter are in DWORD109109+ * FIXME: This function is for debugging, do not deal with110110+ * the case of counters roll-over.111111+ */112112+static void iwl_accumulative_statistics(struct iwl_priv *priv,113113+ __le32 *stats)114114+{115115+ int i;116116+ __le32 *prev_stats;117117+ u32 *accum_stats;118118+ u32 *delta, *max_delta;119119+120120+ prev_stats = (__le32 *)&priv->_agn.statistics;121121+ accum_stats = (u32 *)&priv->_agn.accum_statistics;122122+ delta = (u32 *)&priv->_agn.delta_statistics;123123+ max_delta = (u32 *)&priv->_agn.max_delta;124124+125125+ for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);126126+ i += sizeof(__le32), stats++, prev_stats++, delta++,127127+ max_delta++, accum_stats++) {128128+ if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {129129+ *delta = (le32_to_cpu(*stats) -130130+ le32_to_cpu(*prev_stats));131131+ *accum_stats += *delta;132132+ if (*delta > *max_delta)133133+ *max_delta = *delta;134134+ }135135+ }136136+137137+ /* reset accumulative statistics for "no-counter" type statistics */138138+ priv->_agn.accum_statistics.general.temperature =139139+ priv->_agn.statistics.general.temperature;140140+ priv->_agn.accum_statistics.general.temperature_m =141141+ priv->_agn.statistics.general.temperature_m;142142+ priv->_agn.accum_statistics.general.ttl_timestamp =143143+ priv->_agn.statistics.general.ttl_timestamp;144144+ priv->_agn.accum_statistics.tx.tx_power.ant_a =145145+ priv->_agn.statistics.tx.tx_power.ant_a;146146+ priv->_agn.accum_statistics.tx.tx_power.ant_b =147147+ priv->_agn.statistics.tx.tx_power.ant_b;148148+ priv->_agn.accum_statistics.tx.tx_power.ant_c =149149+ priv->_agn.statistics.tx.tx_power.ant_c;150150+}151151+#endif152152+153153+#define REG_RECALIB_PERIOD (60)154154+155155+/**156156+ * iwl_good_plcp_health - checks for plcp error.157157+ *158158+ * When the plcp error is exceeding the thresholds, reset the radio159159+ * to improve the throughput.160160+ */161161+bool iwl_good_plcp_health(struct iwl_priv *priv,162162+ struct iwl_rx_packet *pkt)163163+{164164+ bool rc = true;165165+ int combined_plcp_delta;166166+ unsigned int plcp_msec;167167+ unsigned long plcp_received_jiffies;168168+169169+ if (priv->cfg->plcp_delta_threshold ==170170+ IWL_MAX_PLCP_ERR_THRESHOLD_DISABLE) {171171+ IWL_DEBUG_RADIO(priv, "plcp_err check disabled\n");172172+ return rc;173173+ }174174+175175+ /*176176+ * check for plcp_err and trigger radio reset if it exceeds177177+ * the plcp error threshold plcp_delta.178178+ */179179+ plcp_received_jiffies = jiffies;180180+ plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -181181+ (long) priv->plcp_jiffies);182182+ priv->plcp_jiffies = plcp_received_jiffies;183183+ /*184184+ * check to make sure plcp_msec is not 0 to prevent division185185+ * by zero.186186+ */187187+ if (plcp_msec) {188188+ combined_plcp_delta =189189+ (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -190190+ le32_to_cpu(priv->_agn.statistics.rx.ofdm.plcp_err)) +191191+ (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -192192+ le32_to_cpu(priv->_agn.statistics.rx.ofdm_ht.plcp_err));193193+194194+ if ((combined_plcp_delta > 0) &&195195+ ((combined_plcp_delta * 100) / plcp_msec) >196196+ priv->cfg->plcp_delta_threshold) {197197+ /*198198+ * if plcp_err exceed the threshold,199199+ * the following data is printed in csv format:200200+ * Text: plcp_err exceeded %d,201201+ * Received ofdm.plcp_err,202202+ * Current ofdm.plcp_err,203203+ * Received ofdm_ht.plcp_err,204204+ * Current ofdm_ht.plcp_err,205205+ * combined_plcp_delta,206206+ * plcp_msec207207+ */208208+ IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "209209+ "%u, %u, %u, %u, %d, %u mSecs\n",210210+ priv->cfg->plcp_delta_threshold,211211+ le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),212212+ le32_to_cpu(213213+ priv->_agn.statistics.rx.ofdm.plcp_err),214214+ le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),215215+ le32_to_cpu(216216+ priv->_agn.statistics.rx.ofdm_ht.plcp_err),217217+ combined_plcp_delta, plcp_msec);218218+ rc = false;219219+ }220220+ }221221+ return rc;222222+}223223+224224+void iwl_rx_statistics(struct iwl_priv *priv,225225+ struct iwl_rx_mem_buffer *rxb)226226+{227227+ int change;228228+ struct iwl_rx_packet *pkt = rxb_addr(rxb);229229+230230+231231+ IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",232232+ (int)sizeof(priv->_agn.statistics),233233+ le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);234234+235235+ change = ((priv->_agn.statistics.general.temperature !=236236+ pkt->u.stats.general.temperature) ||237237+ ((priv->_agn.statistics.flag &238238+ STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=239239+ (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));240240+241241+#ifdef CONFIG_IWLWIFI_DEBUGFS242242+ iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);243243+#endif244244+ iwl_recover_from_statistics(priv, pkt);245245+246246+ memcpy(&priv->_agn.statistics, &pkt->u.stats,247247+ sizeof(priv->_agn.statistics));248248+249249+ set_bit(STATUS_STATISTICS, &priv->status);250250+251251+ /* Reschedule the statistics timer to occur in252252+ * REG_RECALIB_PERIOD seconds to ensure we get a253253+ * thermal update even if the uCode doesn't give254254+ * us one */255255+ mod_timer(&priv->statistics_periodic, jiffies +256256+ msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));257257+258258+ if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&259259+ (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {260260+ iwl_rx_calc_noise(priv);261261+ queue_work(priv->workqueue, &priv->run_time_calib_work);262262+ }263263+ if (priv->cfg->ops->lib->temp_ops.temperature && change)264264+ priv->cfg->ops->lib->temp_ops.temperature(priv);265265+}266266+267267+void iwl_reply_statistics(struct iwl_priv *priv,268268+ struct iwl_rx_mem_buffer *rxb)269269+{270270+ struct iwl_rx_packet *pkt = rxb_addr(rxb);271271+272272+ if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {273273+#ifdef CONFIG_IWLWIFI_DEBUGFS274274+ memset(&priv->_agn.accum_statistics, 0,275275+ sizeof(struct iwl_notif_statistics));276276+ memset(&priv->_agn.delta_statistics, 0,277277+ sizeof(struct iwl_notif_statistics));278278+ memset(&priv->_agn.max_delta, 0,279279+ sizeof(struct iwl_notif_statistics));280280+#endif281281+ IWL_DEBUG_RX(priv, "Statistics have been cleared\n");282282+ }283283+ iwl_rx_statistics(priv, rxb);284284+}
+4-1
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
···233233{234234 unsigned long flags;235235 u16 ra_tid;236236+ int ret;236237237238 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||238239 (IWLAGN_FIRST_AMPDU_QUEUE + priv->cfg->num_of_ampdu_queues···249248 ra_tid = BUILD_RAxTID(sta_id, tid);250249251250 /* Modify device's station table to Tx this TID */252252- iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);251251+ ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);252252+ if (ret)253253+ return ret;253254254255 spin_lock_irqsave(&priv->lock, flags);255256
+49-24
drivers/net/wireless/iwlwifi/iwl-agn.c
···1461146114621462 actual_ack_cnt_delta =14631463 le32_to_cpu(pkt->u.stats.tx.actual_ack_cnt) -14641464- le32_to_cpu(priv->statistics.tx.actual_ack_cnt);14641464+ le32_to_cpu(priv->_agn.statistics.tx.actual_ack_cnt);14651465 expected_ack_cnt_delta =14661466 le32_to_cpu(pkt->u.stats.tx.expected_ack_cnt) -14671467- le32_to_cpu(priv->statistics.tx.expected_ack_cnt);14671467+ le32_to_cpu(priv->_agn.statistics.tx.expected_ack_cnt);14681468 ba_timeout_delta =14691469 le32_to_cpu(pkt->u.stats.tx.agg.ba_timeout) -14701470- le32_to_cpu(priv->statistics.tx.agg.ba_timeout);14701470+ le32_to_cpu(priv->_agn.statistics.tx.agg.ba_timeout);14711471 if ((priv->_agn.agg_tids_count > 0) &&14721472 (expected_ack_cnt_delta > 0) &&14731473 (((actual_ack_cnt_delta * 100) / expected_ack_cnt_delta)···14841484 * DEBUG is not, these will just compile out.14851485 */14861486 IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",14871487- priv->delta_statistics.tx.rx_detected_cnt);14871487+ priv->_agn.delta_statistics.tx.rx_detected_cnt);14881488 IWL_DEBUG_RADIO(priv,14891489 "ack_or_ba_timeout_collision delta = %d\n",14901490- priv->delta_statistics.tx.14901490+ priv->_agn.delta_statistics.tx.14911491 ack_or_ba_timeout_collision);14921492#endif14931493 IWL_DEBUG_RADIO(priv, "agg ba_timeout delta = %d\n",···23102310 trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,23112311 blink1, blink2, ilink1, ilink2);2312231223132313- IWL_ERR(priv, "Desc Time "23132313+ IWL_ERR(priv, "Desc Time "23142314 "data1 data2 line\n");23152315- IWL_ERR(priv, "%-28s (#%02d) %010u 0x%08X 0x%08X %u\n",23152315+ IWL_ERR(priv, "%-28s (0x%04X) %010u 0x%08X 0x%08X %u\n",23162316 desc_lookup(desc), desc, time, data1, data2, line);23172317 IWL_ERR(priv, "pc blink1 blink2 ilink1 ilink2 hcmd\n");23182318 IWL_ERR(priv, "0x%05X 0x%05X 0x%05X 0x%05X 0x%05X 0x%05X\n",···29352935 }2936293629372937 if (priv->start_calib) {29382938- iwl_chain_noise_calibration(priv, &priv->statistics);29382938+ iwl_chain_noise_calibration(priv, &priv->_agn.statistics);2939293929402940- iwl_sensitivity_calibration(priv, &priv->statistics);29402940+ iwl_sensitivity_calibration(priv, &priv->_agn.statistics);29412941 }2942294229432943 mutex_unlock(&priv->mutex);···33683368 return ret;33693369}3370337033713371+/*33723372+ * switch to RTS/CTS for TX33733373+ */33743374+static void iwl_enable_rts_cts(struct iwl_priv *priv)33753375+{33763376+33773377+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))33783378+ return;33793379+33803380+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;33813381+ if (!test_bit(STATUS_SCANNING, &priv->status)) {33823382+ IWL_DEBUG_INFO(priv, "use RTS/CTS protection\n");33833383+ iwlcore_commit_rxon(priv);33843384+ } else {33853385+ /* scanning, defer the request until scan completed */33863386+ IWL_DEBUG_INFO(priv, "defer setting RTS/CTS protection\n");33873387+ }33883388+}33893389+33713390static int iwl_mac_ampdu_action(struct ieee80211_hw *hw,33723391 struct ieee80211_vif *vif,33733392 enum ieee80211_ampdu_mlme_action action,33743393 struct ieee80211_sta *sta, u16 tid, u16 *ssn)33753394{33763395 struct iwl_priv *priv = hw->priv;33773377- int ret;33963396+ int ret = -EINVAL;3378339733793398 IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",33803399 sta->addr, tid);···34013382 if (!(priv->cfg->sku & IWL_SKU_N))34023383 return -EACCES;3403338433853385+ mutex_lock(&priv->mutex);33863386+34043387 switch (action) {34053388 case IEEE80211_AMPDU_RX_START:34063389 IWL_DEBUG_HT(priv, "start Rx\n");34073407- return iwl_sta_rx_agg_start(priv, sta, tid, *ssn);33903390+ ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);33913391+ break;34083392 case IEEE80211_AMPDU_RX_STOP:34093393 IWL_DEBUG_HT(priv, "stop Rx\n");34103394 ret = iwl_sta_rx_agg_stop(priv, sta, tid);34113395 if (test_bit(STATUS_EXIT_PENDING, &priv->status))34123412- return 0;34133413- else34143414- return ret;33963396+ ret = 0;33973397+ break;34153398 case IEEE80211_AMPDU_TX_START:34163399 IWL_DEBUG_HT(priv, "start Tx\n");34173400 ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);···34223401 IWL_DEBUG_HT(priv, "priv->_agn.agg_tids_count = %u\n",34233402 priv->_agn.agg_tids_count);34243403 }34253425- return ret;34043404+ break;34263405 case IEEE80211_AMPDU_TX_STOP:34273406 IWL_DEBUG_HT(priv, "stop Tx\n");34283407 ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);···34323411 priv->_agn.agg_tids_count);34333412 }34343413 if (test_bit(STATUS_EXIT_PENDING, &priv->status))34353435- return 0;34363436- else34373437- return ret;34143414+ ret = 0;34153415+ break;34383416 case IEEE80211_AMPDU_TX_OPERATIONAL:34393439- /* do nothing */34403440- return -EOPNOTSUPP;34413441- default:34423442- IWL_DEBUG_HT(priv, "unknown\n");34433443- return -EINVAL;34173417+ if (priv->cfg->use_rts_for_ht) {34183418+ /*34193419+ * switch to RTS/CTS if it is the prefer protection34203420+ * method for HT traffic34213421+ */34223422+ iwl_enable_rts_cts(priv);34233423+ }34243424+ ret = 0;34443425 break;34453426 }34463446- return 0;34273427+ mutex_unlock(&priv->mutex);34283428+34293429+ return ret;34473430}3448343134493432static void iwl_mac_sta_notify(struct ieee80211_hw *hw,
···9696 hcmd.len = priv->calib_results[i].buf_len;9797 hcmd.data = priv->calib_results[i].buf;9898 ret = iwl_send_cmd_sync(priv, &hcmd);9999- if (ret)100100- goto err;9999+ if (ret) {100100+ IWL_ERR(priv, "Error %d iteration %d\n",101101+ ret, i);102102+ break;103103+ }101104 }102105 }103106104104- return 0;105105-err:106106- IWL_ERR(priv, "Error %d iteration %d\n", ret, i);107107 return ret;108108}109109-EXPORT_SYMBOL(iwl_send_calib_results);110109111110int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len)112111{···120121 memcpy(res->buf, buf, len);121122 return 0;122123}123123-EXPORT_SYMBOL(iwl_calib_set);124124125125void iwl_calib_free_results(struct iwl_priv *priv)126126{···131133 priv->calib_results[i].buf_len = 0;132134 }133135}134134-EXPORT_SYMBOL(iwl_calib_free_results);135136136137/*****************************************************************************137138 * RUNTIME calibrations framework···530533 ret |= iwl_sensitivity_write(priv);531534 IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);532535}533533-EXPORT_SYMBOL(iwl_init_sensitivity);534536535537void iwl_sensitivity_calibration(struct iwl_priv *priv,536538 struct iwl_notif_statistics *resp)···635639 iwl_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);636640 iwl_sensitivity_write(priv);637641}638638-EXPORT_SYMBOL(iwl_sensitivity_calibration);639642640643static inline u8 find_first_chain(u8 mask)641644{···843848844849 if (active_chains != priv->hw_params.valid_rx_ant &&845850 active_chains != priv->chain_noise_data.active_chains)846846- IWL_WARN(priv,847847- "Detected that not all antennas are connected! "848848- "Connected: %#x, valid: %#x.\n",849849- active_chains, priv->hw_params.valid_rx_ant);851851+ IWL_DEBUG_CALIB(priv,852852+ "Detected that not all antennas are connected! "853853+ "Connected: %#x, valid: %#x.\n",854854+ active_chains, priv->hw_params.valid_rx_ant);850855851856 /* Save for use within RXON, TX, SCAN commands, etc. */852857 priv->chain_noise_data.active_chains = active_chains;···892897 data->state = IWL_CHAIN_NOISE_DONE;893898 iwl_power_update_mode(priv, false);894899}895895-EXPORT_SYMBOL(iwl_chain_noise_calibration);896896-897900898901void iwl_reset_run_time_calib(struct iwl_priv *priv)899902{···908915 * periodically after association */909916 iwl_send_statistics_request(priv, CMD_ASYNC, true);910917}911911-EXPORT_SYMBOL(iwl_reset_run_time_calib);912912-
+21-9
drivers/net/wireless/iwlwifi/iwl-commands.h
···1399139914001400/* REPLY_TX Tx flags field */1401140114021402-/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it14021402+/*14031403+ * 1: Use RTS/CTS protocol or CTS-to-self if spec allows it14031404 * before this frame. if CTS-to-self required check14041404- * RXON_FLG_SELF_CTS_EN status. */14051405-#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0)14051405+ * RXON_FLG_SELF_CTS_EN status.14061406+ * unused in 3945/4965, used in 5000 series and after14071407+ */14081408+#define TX_CMD_FLG_PROT_REQUIRE_MSK cpu_to_le32(1 << 0)1406140914071407-/* 1: Use Request-To-Send protocol before this frame.14081408- * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */14101410+/*14111411+ * 1: Use Request-To-Send protocol before this frame.14121412+ * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK.14131413+ * used in 3945/4965, unused in 5000 series and after14141414+ */14091415#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1)1410141614111411-/* 1: Transmit Clear-To-Send to self before this frame.14171417+/*14181418+ * 1: Transmit Clear-To-Send to self before this frame.14121419 * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames.14131413- * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */14201420+ * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK.14211421+ * used in 3945/4965, unused in 5000 series and after14221422+ */14141423#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2)1415142414161425/* 1: Expect ACK from receiving station···14391430 * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */14401431#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6)1441143214421442-/* 1: Frame requires full Tx-Op protection.14431443- * Set this if either RTS or CTS Tx Flag gets set. */14331433+/*14341434+ * 1: Frame requires full Tx-Op protection.14351435+ * Set this if either RTS or CTS Tx Flag gets set.14361436+ * used in 3945/4965, unused in 5000 series and after14371437+ */14441438#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7)1445143914461440/* Tx antenna selection field; used only for 3945, reserved (0) for 4965.
+21-1
drivers/net/wireless/iwlwifi/iwl-core.c
···13311331 changed_flags, *total_flags);1332133213331333 CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);13341334- CHK(FIF_ALLMULTI, RXON_FILTER_ACCEPT_GRP_MSK);13351334 CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK);13361335 CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);13371336···1345134613461347 mutex_unlock(&priv->mutex);1347134813491349+ /*13501350+ * Receiving all multicast frames is always enabled by the13511351+ * default flags setup in iwl_connection_init_rx_config()13521352+ * since we currently do not support programming multicast13531353+ * filters into the device.13541354+ */13481355 *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |13491356 FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;13501357}···21102105 iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);21112106 spin_unlock_irqrestore(&priv->lock, flags);2112210721082108+ if (priv->cfg->ops->lib->update_bcast_station)21092109+ ret = priv->cfg->ops->lib->update_bcast_station(priv);21102110+21132111 set_ch_out:21142112 /* The list of supported rates and rate mask can be different21152113 * for each band; since the band may have changed, reset···28452837{28462838 struct iwl_priv *priv = pci_get_drvdata(pdev);28472839 int ret;28402840+ bool hw_rfkill = false;2848284128492842 /*28502843 * We disable the RETRY_TIMEOUT register (0x41) to keep···28592850 return ret;28602851 pci_restore_state(pdev);28612852 iwl_enable_interrupts(priv);28532853+28542854+ if (!(iwl_read32(priv, CSR_GP_CNTRL) &28552855+ CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))28562856+ hw_rfkill = true;28572857+28582858+ if (hw_rfkill)28592859+ set_bit(STATUS_RF_KILL_HW, &priv->status);28602860+ else28612861+ clear_bit(STATUS_RF_KILL_HW, &priv->status);28622862+28632863+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, hw_rfkill);2862286428632865 return 0;28642866}
···205205}206206EXPORT_SYMBOL(iwl_rx_queue_alloc);207207208208-void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,209209- struct iwl_rx_mem_buffer *rxb)210210-211211-{212212- struct iwl_rx_packet *pkt = rxb_addr(rxb);213213- struct iwl_missed_beacon_notif *missed_beacon;214214-215215- missed_beacon = &pkt->u.missed_beacon;216216- if (le32_to_cpu(missed_beacon->consecutive_missed_beacons) >217217- priv->missed_beacon_threshold) {218218- IWL_DEBUG_CALIB(priv, "missed bcn cnsq %d totl %d rcd %d expctd %d\n",219219- le32_to_cpu(missed_beacon->consecutive_missed_beacons),220220- le32_to_cpu(missed_beacon->total_missed_becons),221221- le32_to_cpu(missed_beacon->num_recvd_beacons),222222- le32_to_cpu(missed_beacon->num_expected_beacons));223223- if (!test_bit(STATUS_SCANNING, &priv->status))224224- iwl_init_sensitivity(priv);225225- }226226-}227227-EXPORT_SYMBOL(iwl_rx_missed_beacon_notif);228208229209void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,230210 struct iwl_rx_mem_buffer *rxb)···222242 priv->measurement_status |= MEASUREMENT_READY;223243}224244EXPORT_SYMBOL(iwl_rx_spectrum_measure_notif);225225-226226-227227-228228-/* Calculate noise level, based on measurements during network silence just229229- * before arriving beacon. This measurement can be done only if we know230230- * exactly when to expect beacons, therefore only when we're associated. */231231-static void iwl_rx_calc_noise(struct iwl_priv *priv)232232-{233233- struct statistics_rx_non_phy *rx_info234234- = &(priv->statistics.rx.general);235235- int num_active_rx = 0;236236- int total_silence = 0;237237- int bcn_silence_a =238238- le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;239239- int bcn_silence_b =240240- le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;241241- int bcn_silence_c =242242- le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;243243- int last_rx_noise;244244-245245- if (bcn_silence_a) {246246- total_silence += bcn_silence_a;247247- num_active_rx++;248248- }249249- if (bcn_silence_b) {250250- total_silence += bcn_silence_b;251251- num_active_rx++;252252- }253253- if (bcn_silence_c) {254254- total_silence += bcn_silence_c;255255- num_active_rx++;256256- }257257-258258- /* Average among active antennas */259259- if (num_active_rx)260260- last_rx_noise = (total_silence / num_active_rx) - 107;261261- else262262- last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;263263-264264- IWL_DEBUG_CALIB(priv, "inband silence a %u, b %u, c %u, dBm %d\n",265265- bcn_silence_a, bcn_silence_b, bcn_silence_c,266266- last_rx_noise);267267-}268268-269269-#ifdef CONFIG_IWLWIFI_DEBUGFS270270-/*271271- * based on the assumption of all statistics counter are in DWORD272272- * FIXME: This function is for debugging, do not deal with273273- * the case of counters roll-over.274274- */275275-static void iwl_accumulative_statistics(struct iwl_priv *priv,276276- __le32 *stats)277277-{278278- int i;279279- __le32 *prev_stats;280280- u32 *accum_stats;281281- u32 *delta, *max_delta;282282-283283- prev_stats = (__le32 *)&priv->statistics;284284- accum_stats = (u32 *)&priv->accum_statistics;285285- delta = (u32 *)&priv->delta_statistics;286286- max_delta = (u32 *)&priv->max_delta;287287-288288- for (i = sizeof(__le32); i < sizeof(struct iwl_notif_statistics);289289- i += sizeof(__le32), stats++, prev_stats++, delta++,290290- max_delta++, accum_stats++) {291291- if (le32_to_cpu(*stats) > le32_to_cpu(*prev_stats)) {292292- *delta = (le32_to_cpu(*stats) -293293- le32_to_cpu(*prev_stats));294294- *accum_stats += *delta;295295- if (*delta > *max_delta)296296- *max_delta = *delta;297297- }298298- }299299-300300- /* reset accumulative statistics for "no-counter" type statistics */301301- priv->accum_statistics.general.temperature =302302- priv->statistics.general.temperature;303303- priv->accum_statistics.general.temperature_m =304304- priv->statistics.general.temperature_m;305305- priv->accum_statistics.general.ttl_timestamp =306306- priv->statistics.general.ttl_timestamp;307307- priv->accum_statistics.tx.tx_power.ant_a =308308- priv->statistics.tx.tx_power.ant_a;309309- priv->accum_statistics.tx.tx_power.ant_b =310310- priv->statistics.tx.tx_power.ant_b;311311- priv->accum_statistics.tx.tx_power.ant_c =312312- priv->statistics.tx.tx_power.ant_c;313313-}314314-#endif315315-316316-#define REG_RECALIB_PERIOD (60)317317-318318-/**319319- * iwl_good_plcp_health - checks for plcp error.320320- *321321- * When the plcp error is exceeding the thresholds, reset the radio322322- * to improve the throughput.323323- */324324-bool iwl_good_plcp_health(struct iwl_priv *priv,325325- struct iwl_rx_packet *pkt)326326-{327327- bool rc = true;328328- int combined_plcp_delta;329329- unsigned int plcp_msec;330330- unsigned long plcp_received_jiffies;331331-332332- /*333333- * check for plcp_err and trigger radio reset if it exceeds334334- * the plcp error threshold plcp_delta.335335- */336336- plcp_received_jiffies = jiffies;337337- plcp_msec = jiffies_to_msecs((long) plcp_received_jiffies -338338- (long) priv->plcp_jiffies);339339- priv->plcp_jiffies = plcp_received_jiffies;340340- /*341341- * check to make sure plcp_msec is not 0 to prevent division342342- * by zero.343343- */344344- if (plcp_msec) {345345- combined_plcp_delta =346346- (le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err) -347347- le32_to_cpu(priv->statistics.rx.ofdm.plcp_err)) +348348- (le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err) -349349- le32_to_cpu(priv->statistics.rx.ofdm_ht.plcp_err));350350-351351- if ((combined_plcp_delta > 0) &&352352- ((combined_plcp_delta * 100) / plcp_msec) >353353- priv->cfg->plcp_delta_threshold) {354354- /*355355- * if plcp_err exceed the threshold,356356- * the following data is printed in csv format:357357- * Text: plcp_err exceeded %d,358358- * Received ofdm.plcp_err,359359- * Current ofdm.plcp_err,360360- * Received ofdm_ht.plcp_err,361361- * Current ofdm_ht.plcp_err,362362- * combined_plcp_delta,363363- * plcp_msec364364- */365365- IWL_DEBUG_RADIO(priv, "plcp_err exceeded %u, "366366- "%u, %u, %u, %u, %d, %u mSecs\n",367367- priv->cfg->plcp_delta_threshold,368368- le32_to_cpu(pkt->u.stats.rx.ofdm.plcp_err),369369- le32_to_cpu(priv->statistics.rx.ofdm.plcp_err),370370- le32_to_cpu(pkt->u.stats.rx.ofdm_ht.plcp_err),371371- le32_to_cpu(372372- priv->statistics.rx.ofdm_ht.plcp_err),373373- combined_plcp_delta, plcp_msec);374374- rc = false;375375- }376376- }377377- return rc;378378-}379379-EXPORT_SYMBOL(iwl_good_plcp_health);380245381246void iwl_recover_from_statistics(struct iwl_priv *priv,382247 struct iwl_rx_packet *pkt)···255430 }256431}257432EXPORT_SYMBOL(iwl_recover_from_statistics);258258-259259-void iwl_rx_statistics(struct iwl_priv *priv,260260- struct iwl_rx_mem_buffer *rxb)261261-{262262- int change;263263- struct iwl_rx_packet *pkt = rxb_addr(rxb);264264-265265-266266- IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",267267- (int)sizeof(priv->statistics),268268- le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);269269-270270- change = ((priv->statistics.general.temperature !=271271- pkt->u.stats.general.temperature) ||272272- ((priv->statistics.flag &273273- STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=274274- (pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));275275-276276-#ifdef CONFIG_IWLWIFI_DEBUGFS277277- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);278278-#endif279279- iwl_recover_from_statistics(priv, pkt);280280-281281- memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));282282-283283- set_bit(STATUS_STATISTICS, &priv->status);284284-285285- /* Reschedule the statistics timer to occur in286286- * REG_RECALIB_PERIOD seconds to ensure we get a287287- * thermal update even if the uCode doesn't give288288- * us one */289289- mod_timer(&priv->statistics_periodic, jiffies +290290- msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));291291-292292- if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&293293- (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {294294- iwl_rx_calc_noise(priv);295295- queue_work(priv->workqueue, &priv->run_time_calib_work);296296- }297297- if (priv->cfg->ops->lib->temp_ops.temperature && change)298298- priv->cfg->ops->lib->temp_ops.temperature(priv);299299-}300300-EXPORT_SYMBOL(iwl_rx_statistics);301301-302302-void iwl_reply_statistics(struct iwl_priv *priv,303303- struct iwl_rx_mem_buffer *rxb)304304-{305305- struct iwl_rx_packet *pkt = rxb_addr(rxb);306306-307307- if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {308308-#ifdef CONFIG_IWLWIFI_DEBUGFS309309- memset(&priv->accum_statistics, 0,310310- sizeof(struct iwl_notif_statistics));311311- memset(&priv->delta_statistics, 0,312312- sizeof(struct iwl_notif_statistics));313313- memset(&priv->max_delta, 0,314314- sizeof(struct iwl_notif_statistics));315315-#endif316316- IWL_DEBUG_RX(priv, "Statistics have been cleared\n");317317- }318318- iwl_rx_statistics(priv, rxb);319319-}320320-EXPORT_SYMBOL(iwl_reply_statistics);321433322434/*323435 * returns non-zero if packet should be dropped
+9
drivers/net/wireless/iwlwifi/iwl-scan.c
···537537 /* Since setting the TXPOWER may have been deferred while538538 * performing the scan, fire one off */539539 iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);540540+541541+ /*542542+ * Since setting the RXON may have been deferred while543543+ * performing the scan, fire one off if needed544544+ */545545+ if (memcmp(&priv->active_rxon,546546+ &priv->staging_rxon, sizeof(priv->staging_rxon)))547547+ iwlcore_commit_rxon(priv);548548+540549 out:541550 mutex_unlock(&priv->mutex);542551
+80-26
drivers/net/wireless/iwlwifi/iwl-sta.c
···3030#include <net/mac80211.h>3131#include <linux/etherdevice.h>3232#include <linux/sched.h>3333+#include <linux/lockdep.h>33343435#include "iwl-dev.h"3536#include "iwl-core.h"···5554 }5655}57565858-static void iwl_process_add_sta_resp(struct iwl_priv *priv,5959- struct iwl_addsta_cmd *addsta,6060- struct iwl_rx_packet *pkt,6161- bool sync)5757+static int iwl_process_add_sta_resp(struct iwl_priv *priv,5858+ struct iwl_addsta_cmd *addsta,5959+ struct iwl_rx_packet *pkt,6060+ bool sync)6261{6362 u8 sta_id = addsta->sta.sta_id;6463 unsigned long flags;6464+ int ret = -EIO;65656666 if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {6767 IWL_ERR(priv, "Bad return from REPLY_ADD_STA (0x%08X)\n",6868 pkt->hdr.flags);6969- return;6969+ return ret;7070 }71717272 IWL_DEBUG_INFO(priv, "Processing response for adding station %u\n",···7977 case ADD_STA_SUCCESS_MSK:8078 IWL_DEBUG_INFO(priv, "REPLY_ADD_STA PASSED\n");8179 iwl_sta_ucode_activate(priv, sta_id);8080+ ret = 0;8281 break;8382 case ADD_STA_NO_ROOM_IN_TABLE:8483 IWL_ERR(priv, "Adding station %d failed, no room in table.\n",···117114 STA_CONTROL_MODIFY_MSK ? "Modified" : "Added",118115 addsta->sta.addr);119116 spin_unlock_irqrestore(&priv->sta_lock, flags);117117+118118+ return ret;120119}121120122121static void iwl_add_sta_callback(struct iwl_priv *priv,···150145151146 if (flags & CMD_ASYNC)152147 cmd.callback = iwl_add_sta_callback;153153- else148148+ else {154149 cmd.flags |= CMD_WANT_SKB;150150+ might_sleep();151151+ }155152156153 cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);157154 ret = iwl_send_cmd(priv, &cmd);···163156164157 if (ret == 0) {165158 pkt = (struct iwl_rx_packet *)cmd.reply_page;166166- iwl_process_add_sta_resp(priv, sta, pkt, true);159159+ ret = iwl_process_add_sta_resp(priv, sta, pkt, true);167160 }168161 iwl_free_pages(priv, cmd.reply_page);169162···838831{839832 unsigned long flags;840833 __le16 key_flags = 0;841841- int ret;834834+ struct iwl_addsta_cmd sta_cmd;835835+836836+ lockdep_assert_held(&priv->mutex);842837843838 keyconf->flags &= ~IEEE80211_KEY_FLAG_GENERATE_IV;844839···880871 priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;881872 priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;882873883883- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);884884-874874+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));885875 spin_unlock_irqrestore(&priv->sta_lock, flags);886876887887- return ret;877877+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);888878}889879890880static int iwl_set_ccmp_dynamic_key_info(struct iwl_priv *priv,···892884{893885 unsigned long flags;894886 __le16 key_flags = 0;895895- int ret;887887+ struct iwl_addsta_cmd sta_cmd;888888+889889+ lockdep_assert_held(&priv->mutex);896890897891 key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);898892 key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);···929919 priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;930920 priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;931921932932- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);933933-922922+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));934923 spin_unlock_irqrestore(&priv->sta_lock, flags);935924936936- return ret;925925+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);937926}938927939928static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv,···10221013 u8 sta_id)10231014{10241015 unsigned long flags;10251025- int ret = 0;10261016 u16 key_flags;10271017 u8 keyidx;10181018+ struct iwl_addsta_cmd sta_cmd;10191019+10201020+ lockdep_assert_held(&priv->mutex);1028102110291022 priv->key_mapping_key--;10301023···10731062 spin_unlock_irqrestore(&priv->sta_lock, flags);10741063 return 0;10751064 }10761076- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);10651065+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));10771066 spin_unlock_irqrestore(&priv->sta_lock, flags);10781078- return ret;10671067+10681068+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);10791069}10801070EXPORT_SYMBOL(iwl_remove_dynamic_key);10811071···10841072 struct ieee80211_key_conf *keyconf, u8 sta_id)10851073{10861074 int ret;10751075+10761076+ lockdep_assert_held(&priv->mutex);1087107710881078 priv->key_mapping_key++;10891079 keyconf->hw_key_idx = HW_KEY_DYNAMIC;···12591245}12601246EXPORT_SYMBOL_GPL(iwl_alloc_bcast_station);1261124712481248+/**12491249+ * iwl_update_bcast_station - update broadcast station's LQ command12501250+ *12511251+ * Only used by iwlagn. Placed here to have all bcast station management12521252+ * code together.12531253+ */12541254+int iwl_update_bcast_station(struct iwl_priv *priv)12551255+{12561256+ unsigned long flags;12571257+ struct iwl_link_quality_cmd *link_cmd;12581258+ u8 sta_id = priv->hw_params.bcast_sta_id;12591259+12601260+ link_cmd = iwl_sta_alloc_lq(priv, sta_id);12611261+ if (!link_cmd) {12621262+ IWL_ERR(priv, "Unable to initialize rate scaling for bcast station.\n");12631263+ return -ENOMEM;12641264+ }12651265+12661266+ spin_lock_irqsave(&priv->sta_lock, flags);12671267+ if (priv->stations[sta_id].lq)12681268+ kfree(priv->stations[sta_id].lq);12691269+ else12701270+ IWL_DEBUG_INFO(priv, "Bcast station rate scaling has not been initialized yet.\n");12711271+ priv->stations[sta_id].lq = link_cmd;12721272+ spin_unlock_irqrestore(&priv->sta_lock, flags);12731273+12741274+ return 0;12751275+}12761276+EXPORT_SYMBOL_GPL(iwl_update_bcast_station);12771277+12621278void iwl_dealloc_bcast_station(struct iwl_priv *priv)12631279{12641280 unsigned long flags;···13121268/**13131269 * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table13141270 */13151315-void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)12711271+int iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)13161272{13171273 unsigned long flags;12741274+ struct iwl_addsta_cmd sta_cmd;12751275+12761276+ lockdep_assert_held(&priv->mutex);1318127713191278 /* Remove "disable" flag, to enable Tx for this TID */13201279 spin_lock_irqsave(&priv->sta_lock, flags);13211280 priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;13221281 priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));13231282 priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;13241324- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);12831283+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));13251284 spin_unlock_irqrestore(&priv->sta_lock, flags);12851285+12861286+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);13261287}13271288EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);13281289···13361287{13371288 unsigned long flags;13381289 int sta_id;12901290+ struct iwl_addsta_cmd sta_cmd;12911291+12921292+ lockdep_assert_held(&priv->mutex);1339129313401294 sta_id = iwl_sta_id(sta);13411295 if (sta_id == IWL_INVALID_STATION)···13501298 priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;13511299 priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);13521300 priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;13011301+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));13531302 spin_unlock_irqrestore(&priv->sta_lock, flags);1354130313551355- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,13561356- CMD_ASYNC);13041304+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);13571305}13581306EXPORT_SYMBOL(iwl_sta_rx_agg_start);13591307···13611309 int tid)13621310{13631311 unsigned long flags;13641364- int sta_id, ret;13121312+ int sta_id;13131313+ struct iwl_addsta_cmd sta_cmd;13141314+13151315+ lockdep_assert_held(&priv->mutex);1365131613661317 sta_id = iwl_sta_id(sta);13671318 if (sta_id == IWL_INVALID_STATION) {···13771322 priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;13781323 priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;13791324 priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;13801380- ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);13251325+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));13811326 spin_unlock_irqrestore(&priv->sta_lock, flags);1382132713831383- return ret;13841384-13281328+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);13851329}13861330EXPORT_SYMBOL(iwl_sta_rx_agg_stop);13871331
···44#include <linux/etherdevice.h>55#include <linux/slab.h>66#include <linux/types.h>77+#include <net/cfg80211.h>7899+#include "defs.h"810#include "host.h"911#include "radiotap.h"1012#include "decl.h"1113#include "dev.h"1212-#include "wext.h"13141415struct eth803hdr {1516 u8 dest_addr[6];···4039 struct sk_buff *skb);41404241/**4343- * @brief This function computes the avgSNR .4444- *4545- * @param priv A pointer to struct lbs_private structure4646- * @return avgSNR4747- */4848-static u8 lbs_getavgsnr(struct lbs_private *priv)4949-{5050- u8 i;5151- u16 temp = 0;5252- if (priv->numSNRNF == 0)5353- return 0;5454- for (i = 0; i < priv->numSNRNF; i++)5555- temp += priv->rawSNR[i];5656- return (u8) (temp / priv->numSNRNF);5757-5858-}5959-6060-/**6161- * @brief This function computes the AvgNF6262- *6363- * @param priv A pointer to struct lbs_private structure6464- * @return AvgNF6565- */6666-static u8 lbs_getavgnf(struct lbs_private *priv)6767-{6868- u8 i;6969- u16 temp = 0;7070- if (priv->numSNRNF == 0)7171- return 0;7272- for (i = 0; i < priv->numSNRNF; i++)7373- temp += priv->rawNF[i];7474- return (u8) (temp / priv->numSNRNF);7575-7676-}7777-7878-/**7979- * @brief This function save the raw SNR/NF to our internel buffer8080- *8181- * @param priv A pointer to struct lbs_private structure8282- * @param prxpd A pointer to rxpd structure of received packet8383- * @return n/a8484- */8585-static void lbs_save_rawSNRNF(struct lbs_private *priv, struct rxpd *p_rx_pd)8686-{8787- if (priv->numSNRNF < DEFAULT_DATA_AVG_FACTOR)8888- priv->numSNRNF++;8989- priv->rawSNR[priv->nextSNRNF] = p_rx_pd->snr;9090- priv->rawNF[priv->nextSNRNF] = p_rx_pd->nf;9191- priv->nextSNRNF++;9292- if (priv->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)9393- priv->nextSNRNF = 0;9494-}9595-9696-/**9797- * @brief This function computes the RSSI in received packet.9898- *9999- * @param priv A pointer to struct lbs_private structure100100- * @param prxpd A pointer to rxpd structure of received packet101101- * @return n/a102102- */103103-static void lbs_compute_rssi(struct lbs_private *priv, struct rxpd *p_rx_pd)104104-{105105-106106- lbs_deb_enter(LBS_DEB_RX);107107-108108- lbs_deb_rx("rxpd: SNR %d, NF %d\n", p_rx_pd->snr, p_rx_pd->nf);109109- lbs_deb_rx("before computing SNR: SNR-avg = %d, NF-avg = %d\n",110110- priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,111111- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);112112-113113- priv->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr;114114- priv->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;115115- lbs_save_rawSNRNF(priv, p_rx_pd);116116-117117- priv->SNR[TYPE_RXPD][TYPE_AVG] = lbs_getavgsnr(priv) * AVG_SCALE;118118- priv->NF[TYPE_RXPD][TYPE_AVG] = lbs_getavgnf(priv) * AVG_SCALE;119119- lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",120120- priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,121121- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);122122-123123- priv->RSSI[TYPE_RXPD][TYPE_NOAVG] =124124- CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_NOAVG],125125- priv->NF[TYPE_RXPD][TYPE_NOAVG]);126126-127127- priv->RSSI[TYPE_RXPD][TYPE_AVG] =128128- CAL_RSSI(priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE,129129- priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE);130130-131131- lbs_deb_leave(LBS_DEB_RX);132132-}133133-134134-/**13542 * @brief This function processes received packet and forwards it13643 * to kernel/upper layer13744 *···6315464155 skb->ip_summed = CHECKSUM_NONE;651566666- if (priv->monitormode)157157+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR)67158 return process_rxed_802_11_packet(priv, skb);6815969160 p_rx_pd = (struct rxpd *) skb->data;···134225 */135226 skb_pull(skb, hdrchop);136227137137- /* Take the data rate from the rxpd structure138138- * only if the rate is auto139139- */140140- if (priv->enablehwauto)141141- priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);142142-143143- lbs_compute_rssi(priv, p_rx_pd);228228+ priv->cur_rate = lbs_fw_index_to_data_rate(p_rx_pd->rx_rate);144229145230 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);146231 dev->stats.rx_bytes += skb->len;···255352 pradiotap_hdr = (void *)skb_push(skb, sizeof(struct rx_radiotap_hdr));256353 memcpy(pradiotap_hdr, &radiotap_hdr, sizeof(struct rx_radiotap_hdr));257354258258- /* Take the data rate from the rxpd structure259259- * only if the rate is auto260260- */261261- if (priv->enablehwauto)262262- priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);263263-264264- lbs_compute_rssi(priv, prxpd);355355+ priv->cur_rate = lbs_fw_index_to_data_rate(prxpd->rx_rate);265356266357 lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);267358 dev->stats.rx_bytes += skb->len;268359 dev->stats.rx_packets++;269360270270- skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);271271- netif_rx(skb);361361+ skb->protocol = eth_type_trans(skb, priv->dev);362362+363363+ if (in_interrupt())364364+ netif_rx(skb);365365+ else366366+ netif_rx_ni(skb);272367273368 ret = 0;274369
-1354
drivers/net/wireless/libertas/scan.c
···11-/**22- * Functions implementing wlan scan IOCTL and firmware command APIs33- *44- * IOCTL handlers as well as command preperation and response routines55- * for sending scan commands to the firmware.66- */77-#include <linux/slab.h>88-#include <linux/types.h>99-#include <linux/kernel.h>1010-#include <linux/etherdevice.h>1111-#include <linux/if_arp.h>1212-#include <asm/unaligned.h>1313-#include <net/lib80211.h>1414-1515-#include "host.h"1616-#include "dev.h"1717-#include "scan.h"1818-#include "assoc.h"1919-#include "wext.h"2020-#include "cmd.h"2121-2222-//! Approximate amount of data needed to pass a scan result back to iwlist2323-#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \2424- + IEEE80211_MAX_SSID_LEN \2525- + IW_EV_UINT_LEN \2626- + IW_EV_FREQ_LEN \2727- + IW_EV_QUAL_LEN \2828- + IEEE80211_MAX_SSID_LEN \2929- + IW_EV_PARAM_LEN \3030- + 40) /* 40 for WPAIE */3131-3232-//! Memory needed to store a max sized channel List TLV for a firmware scan3333-#define CHAN_TLV_MAX_SIZE (sizeof(struct mrvl_ie_header) \3434- + (MRVDRV_MAX_CHANNELS_PER_SCAN \3535- * sizeof(struct chanscanparamset)))3636-3737-//! Memory needed to store a max number/size SSID TLV for a firmware scan3838-#define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvl_ie_ssid_param_set))3939-4040-//! Maximum memory needed for a cmd_ds_802_11_scan with all TLVs at max4141-#define MAX_SCAN_CFG_ALLOC (sizeof(struct cmd_ds_802_11_scan) \4242- + CHAN_TLV_MAX_SIZE + SSID_TLV_MAX_SIZE)4343-4444-//! The maximum number of channels the firmware can scan per command4545-#define MRVDRV_MAX_CHANNELS_PER_SCAN 144646-4747-/**4848- * @brief Number of channels to scan per firmware scan command issuance.4949- *5050- * Number restricted to prevent hitting the limit on the amount of scan data5151- * returned in a single firmware scan command.5252- */5353-#define MRVDRV_CHANNELS_PER_SCAN_CMD 45454-5555-//! Scan time specified in the channel TLV for each channel for passive scans5656-#define MRVDRV_PASSIVE_SCAN_CHAN_TIME 1005757-5858-//! Scan time specified in the channel TLV for each channel for active scans5959-#define MRVDRV_ACTIVE_SCAN_CHAN_TIME 1006060-6161-#define DEFAULT_MAX_SCAN_AGE (15 * HZ)6262-6363-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,6464- struct cmd_header *resp);6565-6666-/*********************************************************************/6767-/* */6868-/* Misc helper functions */6969-/* */7070-/*********************************************************************/7171-7272-/**7373- * @brief Unsets the MSB on basic rates7474- *7575- * Scan through an array and unset the MSB for basic data rates.7676- *7777- * @param rates buffer of data rates7878- * @param len size of buffer7979- */8080-static void lbs_unset_basic_rate_flags(u8 *rates, size_t len)8181-{8282- int i;8383-8484- for (i = 0; i < len; i++)8585- rates[i] &= 0x7f;8686-}8787-8888-8989-static inline void clear_bss_descriptor(struct bss_descriptor *bss)9090-{9191- /* Don't blow away ->list, just BSS data */9292- memset(bss, 0, offsetof(struct bss_descriptor, list));9393-}9494-9595-/**9696- * @brief Compare two SSIDs9797- *9898- * @param ssid1 A pointer to ssid to compare9999- * @param ssid2 A pointer to ssid to compare100100- *101101- * @return 0: ssid is same, otherwise is different102102- */103103-int lbs_ssid_cmp(uint8_t *ssid1, uint8_t ssid1_len, uint8_t *ssid2,104104- uint8_t ssid2_len)105105-{106106- if (ssid1_len != ssid2_len)107107- return -1;108108-109109- return memcmp(ssid1, ssid2, ssid1_len);110110-}111111-112112-static inline int is_same_network(struct bss_descriptor *src,113113- struct bss_descriptor *dst)114114-{115115- /* A network is only a duplicate if the channel, BSSID, and ESSID116116- * all match. We treat all <hidden> with the same BSSID and channel117117- * as one network */118118- return ((src->ssid_len == dst->ssid_len) &&119119- (src->channel == dst->channel) &&120120- !compare_ether_addr(src->bssid, dst->bssid) &&121121- !memcmp(src->ssid, dst->ssid, src->ssid_len));122122-}123123-124124-125125-126126-/*********************************************************************/127127-/* */128128-/* Region channel support */129129-/* */130130-/*********************************************************************/131131-132132-#define LBS_TX_PWR_DEFAULT 20 /*100mW */133133-#define LBS_TX_PWR_US_DEFAULT 20 /*100mW */134134-#define LBS_TX_PWR_JP_DEFAULT 16 /*50mW */135135-#define LBS_TX_PWR_FR_DEFAULT 20 /*100mW */136136-#define LBS_TX_PWR_EMEA_DEFAULT 20 /*100mW */137137-138138-/* Format { channel, frequency (MHz), maxtxpower } */139139-/* band: 'B/G', region: USA FCC/Canada IC */140140-static struct chan_freq_power channel_freq_power_US_BG[] = {141141- {1, 2412, LBS_TX_PWR_US_DEFAULT},142142- {2, 2417, LBS_TX_PWR_US_DEFAULT},143143- {3, 2422, LBS_TX_PWR_US_DEFAULT},144144- {4, 2427, LBS_TX_PWR_US_DEFAULT},145145- {5, 2432, LBS_TX_PWR_US_DEFAULT},146146- {6, 2437, LBS_TX_PWR_US_DEFAULT},147147- {7, 2442, LBS_TX_PWR_US_DEFAULT},148148- {8, 2447, LBS_TX_PWR_US_DEFAULT},149149- {9, 2452, LBS_TX_PWR_US_DEFAULT},150150- {10, 2457, LBS_TX_PWR_US_DEFAULT},151151- {11, 2462, LBS_TX_PWR_US_DEFAULT}152152-};153153-154154-/* band: 'B/G', region: Europe ETSI */155155-static struct chan_freq_power channel_freq_power_EU_BG[] = {156156- {1, 2412, LBS_TX_PWR_EMEA_DEFAULT},157157- {2, 2417, LBS_TX_PWR_EMEA_DEFAULT},158158- {3, 2422, LBS_TX_PWR_EMEA_DEFAULT},159159- {4, 2427, LBS_TX_PWR_EMEA_DEFAULT},160160- {5, 2432, LBS_TX_PWR_EMEA_DEFAULT},161161- {6, 2437, LBS_TX_PWR_EMEA_DEFAULT},162162- {7, 2442, LBS_TX_PWR_EMEA_DEFAULT},163163- {8, 2447, LBS_TX_PWR_EMEA_DEFAULT},164164- {9, 2452, LBS_TX_PWR_EMEA_DEFAULT},165165- {10, 2457, LBS_TX_PWR_EMEA_DEFAULT},166166- {11, 2462, LBS_TX_PWR_EMEA_DEFAULT},167167- {12, 2467, LBS_TX_PWR_EMEA_DEFAULT},168168- {13, 2472, LBS_TX_PWR_EMEA_DEFAULT}169169-};170170-171171-/* band: 'B/G', region: Spain */172172-static struct chan_freq_power channel_freq_power_SPN_BG[] = {173173- {10, 2457, LBS_TX_PWR_DEFAULT},174174- {11, 2462, LBS_TX_PWR_DEFAULT}175175-};176176-177177-/* band: 'B/G', region: France */178178-static struct chan_freq_power channel_freq_power_FR_BG[] = {179179- {10, 2457, LBS_TX_PWR_FR_DEFAULT},180180- {11, 2462, LBS_TX_PWR_FR_DEFAULT},181181- {12, 2467, LBS_TX_PWR_FR_DEFAULT},182182- {13, 2472, LBS_TX_PWR_FR_DEFAULT}183183-};184184-185185-/* band: 'B/G', region: Japan */186186-static struct chan_freq_power channel_freq_power_JPN_BG[] = {187187- {1, 2412, LBS_TX_PWR_JP_DEFAULT},188188- {2, 2417, LBS_TX_PWR_JP_DEFAULT},189189- {3, 2422, LBS_TX_PWR_JP_DEFAULT},190190- {4, 2427, LBS_TX_PWR_JP_DEFAULT},191191- {5, 2432, LBS_TX_PWR_JP_DEFAULT},192192- {6, 2437, LBS_TX_PWR_JP_DEFAULT},193193- {7, 2442, LBS_TX_PWR_JP_DEFAULT},194194- {8, 2447, LBS_TX_PWR_JP_DEFAULT},195195- {9, 2452, LBS_TX_PWR_JP_DEFAULT},196196- {10, 2457, LBS_TX_PWR_JP_DEFAULT},197197- {11, 2462, LBS_TX_PWR_JP_DEFAULT},198198- {12, 2467, LBS_TX_PWR_JP_DEFAULT},199199- {13, 2472, LBS_TX_PWR_JP_DEFAULT},200200- {14, 2484, LBS_TX_PWR_JP_DEFAULT}201201-};202202-203203-/**204204- * the structure for channel, frequency and power205205- */206206-struct region_cfp_table {207207- u8 region;208208- struct chan_freq_power *cfp_BG;209209- int cfp_no_BG;210210-};211211-212212-/**213213- * the structure for the mapping between region and CFP214214- */215215-static struct region_cfp_table region_cfp_table[] = {216216- {0x10, /*US FCC */217217- channel_freq_power_US_BG,218218- ARRAY_SIZE(channel_freq_power_US_BG),219219- }220220- ,221221- {0x20, /*CANADA IC */222222- channel_freq_power_US_BG,223223- ARRAY_SIZE(channel_freq_power_US_BG),224224- }225225- ,226226- {0x30, /*EU*/ channel_freq_power_EU_BG,227227- ARRAY_SIZE(channel_freq_power_EU_BG),228228- }229229- ,230230- {0x31, /*SPAIN*/ channel_freq_power_SPN_BG,231231- ARRAY_SIZE(channel_freq_power_SPN_BG),232232- }233233- ,234234- {0x32, /*FRANCE*/ channel_freq_power_FR_BG,235235- ARRAY_SIZE(channel_freq_power_FR_BG),236236- }237237- ,238238- {0x40, /*JAPAN*/ channel_freq_power_JPN_BG,239239- ARRAY_SIZE(channel_freq_power_JPN_BG),240240- }241241- ,242242-/*Add new region here */243243-};244244-245245-/**246246- * @brief This function finds the CFP in247247- * region_cfp_table based on region and band parameter.248248- *249249- * @param region The region code250250- * @param band The band251251- * @param cfp_no A pointer to CFP number252252- * @return A pointer to CFP253253- */254254-static struct chan_freq_power *lbs_get_region_cfp_table(u8 region, int *cfp_no)255255-{256256- int i, end;257257-258258- lbs_deb_enter(LBS_DEB_MAIN);259259-260260- end = ARRAY_SIZE(region_cfp_table);261261-262262- for (i = 0; i < end ; i++) {263263- lbs_deb_main("region_cfp_table[i].region=%d\n",264264- region_cfp_table[i].region);265265- if (region_cfp_table[i].region == region) {266266- *cfp_no = region_cfp_table[i].cfp_no_BG;267267- lbs_deb_leave(LBS_DEB_MAIN);268268- return region_cfp_table[i].cfp_BG;269269- }270270- }271271-272272- lbs_deb_leave_args(LBS_DEB_MAIN, "ret NULL");273273- return NULL;274274-}275275-276276-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band)277277-{278278- int ret = 0;279279- int i = 0;280280-281281- struct chan_freq_power *cfp;282282- int cfp_no;283283-284284- lbs_deb_enter(LBS_DEB_MAIN);285285-286286- memset(priv->region_channel, 0, sizeof(priv->region_channel));287287-288288- cfp = lbs_get_region_cfp_table(region, &cfp_no);289289- if (cfp != NULL) {290290- priv->region_channel[i].nrcfp = cfp_no;291291- priv->region_channel[i].CFP = cfp;292292- } else {293293- lbs_deb_main("wrong region code %#x in band B/G\n",294294- region);295295- ret = -1;296296- goto out;297297- }298298- priv->region_channel[i].valid = 1;299299- priv->region_channel[i].region = region;300300- priv->region_channel[i].band = band;301301- i++;302302-out:303303- lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);304304- return ret;305305-}306306-307307-308308-309309-310310-/*********************************************************************/311311-/* */312312-/* Main scanning support */313313-/* */314314-/*********************************************************************/315315-316316-/**317317- * @brief Create a channel list for the driver to scan based on region info318318- *319319- * Only used from lbs_scan_setup_scan_config()320320- *321321- * Use the driver region/band information to construct a comprehensive list322322- * of channels to scan. This routine is used for any scan that is not323323- * provided a specific channel list to scan.324324- *325325- * @param priv A pointer to struct lbs_private structure326326- * @param scanchanlist Output parameter: resulting channel list to scan327327- *328328- * @return void329329- */330330-static int lbs_scan_create_channel_list(struct lbs_private *priv,331331- struct chanscanparamset *scanchanlist)332332-{333333- struct region_channel *scanregion;334334- struct chan_freq_power *cfp;335335- int rgnidx;336336- int chanidx;337337- int nextchan;338338- uint8_t scantype;339339-340340- chanidx = 0;341341-342342- /* Set the default scan type to the user specified type, will later343343- * be changed to passive on a per channel basis if restricted by344344- * regulatory requirements (11d or 11h)345345- */346346- scantype = CMD_SCAN_TYPE_ACTIVE;347347-348348- for (rgnidx = 0; rgnidx < ARRAY_SIZE(priv->region_channel); rgnidx++) {349349- if (!priv->region_channel[rgnidx].valid)350350- continue;351351- scanregion = &priv->region_channel[rgnidx];352352-353353- for (nextchan = 0; nextchan < scanregion->nrcfp; nextchan++, chanidx++) {354354- struct chanscanparamset *chan = &scanchanlist[chanidx];355355-356356- cfp = scanregion->CFP + nextchan;357357-358358- if (scanregion->band == BAND_B || scanregion->band == BAND_G)359359- chan->radiotype = CMD_SCAN_RADIO_TYPE_BG;360360-361361- if (scantype == CMD_SCAN_TYPE_PASSIVE) {362362- chan->maxscantime = cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);363363- chan->chanscanmode.passivescan = 1;364364- } else {365365- chan->maxscantime = cpu_to_le16(MRVDRV_ACTIVE_SCAN_CHAN_TIME);366366- chan->chanscanmode.passivescan = 0;367367- }368368-369369- chan->channumber = cfp->channel;370370- }371371- }372372- return chanidx;373373-}374374-375375-/*376376- * Add SSID TLV of the form:377377- *378378- * TLV-ID SSID 00 00379379- * length 06 00380380- * ssid 4d 4e 54 45 53 54381381- */382382-static int lbs_scan_add_ssid_tlv(struct lbs_private *priv, u8 *tlv)383383-{384384- struct mrvl_ie_ssid_param_set *ssid_tlv = (void *)tlv;385385-386386- ssid_tlv->header.type = cpu_to_le16(TLV_TYPE_SSID);387387- ssid_tlv->header.len = cpu_to_le16(priv->scan_ssid_len);388388- memcpy(ssid_tlv->ssid, priv->scan_ssid, priv->scan_ssid_len);389389- return sizeof(ssid_tlv->header) + priv->scan_ssid_len;390390-}391391-392392-/*393393- * Add CHANLIST TLV of the form394394- *395395- * TLV-ID CHANLIST 01 01396396- * length 5b 00397397- * channel 1 00 01 00 00 00 64 00398398- * radio type 00399399- * channel 01400400- * scan type 00401401- * min scan time 00 00402402- * max scan time 64 00403403- * channel 2 00 02 00 00 00 64 00404404- * channel 3 00 03 00 00 00 64 00405405- * channel 4 00 04 00 00 00 64 00406406- * channel 5 00 05 00 00 00 64 00407407- * channel 6 00 06 00 00 00 64 00408408- * channel 7 00 07 00 00 00 64 00409409- * channel 8 00 08 00 00 00 64 00410410- * channel 9 00 09 00 00 00 64 00411411- * channel 10 00 0a 00 00 00 64 00412412- * channel 11 00 0b 00 00 00 64 00413413- * channel 12 00 0c 00 00 00 64 00414414- * channel 13 00 0d 00 00 00 64 00415415- *416416- */417417-static int lbs_scan_add_chanlist_tlv(uint8_t *tlv,418418- struct chanscanparamset *chan_list,419419- int chan_count)420420-{421421- size_t size = sizeof(struct chanscanparamset) *chan_count;422422- struct mrvl_ie_chanlist_param_set *chan_tlv = (void *)tlv;423423-424424- chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);425425- memcpy(chan_tlv->chanscanparam, chan_list, size);426426- chan_tlv->header.len = cpu_to_le16(size);427427- return sizeof(chan_tlv->header) + size;428428-}429429-430430-/*431431- * Add RATES TLV of the form432432- *433433- * TLV-ID RATES 01 00434434- * length 0e 00435435- * rates 82 84 8b 96 0c 12 18 24 30 48 60 6c436436- *437437- * The rates are in lbs_bg_rates[], but for the 802.11b438438- * rates the high bit isn't set.439439- */440440-static int lbs_scan_add_rates_tlv(uint8_t *tlv)441441-{442442- int i;443443- struct mrvl_ie_rates_param_set *rate_tlv = (void *)tlv;444444-445445- rate_tlv->header.type = cpu_to_le16(TLV_TYPE_RATES);446446- tlv += sizeof(rate_tlv->header);447447- for (i = 0; i < MAX_RATES; i++) {448448- *tlv = lbs_bg_rates[i];449449- if (*tlv == 0)450450- break;451451- /* This code makes sure that the 802.11b rates (1 MBit/s, 2452452- MBit/s, 5.5 MBit/s and 11 MBit/s get's the high bit set.453453- Note that the values are MBit/s * 2, to mark them as454454- basic rates so that the firmware likes it better */455455- if (*tlv == 0x02 || *tlv == 0x04 ||456456- *tlv == 0x0b || *tlv == 0x16)457457- *tlv |= 0x80;458458- tlv++;459459- }460460- rate_tlv->header.len = cpu_to_le16(i);461461- return sizeof(rate_tlv->header) + i;462462-}463463-464464-/*465465- * Generate the CMD_802_11_SCAN command with the proper tlv466466- * for a bunch of channels.467467- */468468-static int lbs_do_scan(struct lbs_private *priv, uint8_t bsstype,469469- struct chanscanparamset *chan_list, int chan_count)470470-{471471- int ret = -ENOMEM;472472- struct cmd_ds_802_11_scan *scan_cmd;473473- uint8_t *tlv; /* pointer into our current, growing TLV storage area */474474-475475- lbs_deb_enter_args(LBS_DEB_SCAN, "bsstype %d, chanlist[].chan %d, chan_count %d",476476- bsstype, chan_list ? chan_list[0].channumber : -1,477477- chan_count);478478-479479- /* create the fixed part for scan command */480480- scan_cmd = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);481481- if (scan_cmd == NULL)482482- goto out;483483-484484- tlv = scan_cmd->tlvbuffer;485485- /* TODO: do we need to scan for a specific BSSID?486486- memcpy(scan_cmd->bssid, priv->scan_bssid, ETH_ALEN); */487487- scan_cmd->bsstype = bsstype;488488-489489- /* add TLVs */490490- if (priv->scan_ssid_len)491491- tlv += lbs_scan_add_ssid_tlv(priv, tlv);492492- if (chan_list && chan_count)493493- tlv += lbs_scan_add_chanlist_tlv(tlv, chan_list, chan_count);494494- tlv += lbs_scan_add_rates_tlv(tlv);495495-496496- /* This is the final data we are about to send */497497- scan_cmd->hdr.size = cpu_to_le16(tlv - (uint8_t *)scan_cmd);498498- lbs_deb_hex(LBS_DEB_SCAN, "SCAN_CMD", (void *)scan_cmd,499499- sizeof(*scan_cmd));500500- lbs_deb_hex(LBS_DEB_SCAN, "SCAN_TLV", scan_cmd->tlvbuffer,501501- tlv - scan_cmd->tlvbuffer);502502-503503- ret = __lbs_cmd(priv, CMD_802_11_SCAN, &scan_cmd->hdr,504504- le16_to_cpu(scan_cmd->hdr.size),505505- lbs_ret_80211_scan, 0);506506-507507-out:508508- kfree(scan_cmd);509509- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);510510- return ret;511511-}512512-513513-/**514514- * @brief Internal function used to start a scan based on an input config515515- *516516- * Use the input user scan configuration information when provided in517517- * order to send the appropriate scan commands to firmware to populate or518518- * update the internal driver scan table519519- *520520- * @param priv A pointer to struct lbs_private structure521521- * @param full_scan Do a full-scan (blocking)522522- *523523- * @return 0 or < 0 if error524524- */525525-int lbs_scan_networks(struct lbs_private *priv, int full_scan)526526-{527527- int ret = -ENOMEM;528528- struct chanscanparamset *chan_list;529529- struct chanscanparamset *curr_chans;530530- int chan_count;531531- uint8_t bsstype = CMD_BSS_TYPE_ANY;532532- int numchannels = MRVDRV_CHANNELS_PER_SCAN_CMD;533533- union iwreq_data wrqu;534534-#ifdef CONFIG_LIBERTAS_DEBUG535535- struct bss_descriptor *iter;536536- int i = 0;537537- DECLARE_SSID_BUF(ssid);538538-#endif539539-540540- lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);541541-542542- /* Cancel any partial outstanding partial scans if this scan543543- * is a full scan.544544- */545545- if (full_scan && delayed_work_pending(&priv->scan_work))546546- cancel_delayed_work(&priv->scan_work);547547-548548- /* User-specified bsstype or channel list549549- TODO: this can be implemented if some user-space application550550- need the feature. Formerly, it was accessible from debugfs,551551- but then nowhere used.552552- if (user_cfg) {553553- if (user_cfg->bsstype)554554- bsstype = user_cfg->bsstype;555555- } */556556-557557- lbs_deb_scan("numchannels %d, bsstype %d\n", numchannels, bsstype);558558-559559- /* Create list of channels to scan */560560- chan_list = kzalloc(sizeof(struct chanscanparamset) *561561- LBS_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);562562- if (!chan_list) {563563- lbs_pr_alert("SCAN: chan_list empty\n");564564- goto out;565565- }566566-567567- /* We want to scan all channels */568568- chan_count = lbs_scan_create_channel_list(priv, chan_list);569569-570570- netif_stop_queue(priv->dev);571571- if (priv->mesh_dev)572572- netif_stop_queue(priv->mesh_dev);573573-574574- /* Prepare to continue an interrupted scan */575575- lbs_deb_scan("chan_count %d, scan_channel %d\n",576576- chan_count, priv->scan_channel);577577- curr_chans = chan_list;578578- /* advance channel list by already-scanned-channels */579579- if (priv->scan_channel > 0) {580580- curr_chans += priv->scan_channel;581581- chan_count -= priv->scan_channel;582582- }583583-584584- /* Send scan command(s)585585- * numchannels contains the number of channels we should maximally scan586586- * chan_count is the total number of channels to scan587587- */588588-589589- while (chan_count) {590590- int to_scan = min(numchannels, chan_count);591591- lbs_deb_scan("scanning %d of %d channels\n",592592- to_scan, chan_count);593593- ret = lbs_do_scan(priv, bsstype, curr_chans,594594- to_scan);595595- if (ret) {596596- lbs_pr_err("SCAN_CMD failed\n");597597- goto out2;598598- }599599- curr_chans += to_scan;600600- chan_count -= to_scan;601601-602602- /* somehow schedule the next part of the scan */603603- if (chan_count && !full_scan &&604604- !priv->surpriseremoved) {605605- /* -1 marks just that we're currently scanning */606606- if (priv->scan_channel < 0)607607- priv->scan_channel = to_scan;608608- else609609- priv->scan_channel += to_scan;610610- cancel_delayed_work(&priv->scan_work);611611- queue_delayed_work(priv->work_thread, &priv->scan_work,612612- msecs_to_jiffies(300));613613- /* skip over GIWSCAN event */614614- goto out;615615- }616616-617617- }618618- memset(&wrqu, 0, sizeof(union iwreq_data));619619- wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);620620-621621-#ifdef CONFIG_LIBERTAS_DEBUG622622- /* Dump the scan table */623623- mutex_lock(&priv->lock);624624- lbs_deb_scan("scan table:\n");625625- list_for_each_entry(iter, &priv->network_list, list)626626- lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n",627627- i++, iter->bssid, iter->rssi,628628- print_ssid(ssid, iter->ssid, iter->ssid_len));629629- mutex_unlock(&priv->lock);630630-#endif631631-632632-out2:633633- priv->scan_channel = 0;634634-635635-out:636636- if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len)637637- netif_wake_queue(priv->dev);638638-639639- if (priv->mesh_dev && lbs_mesh_connected(priv) &&640640- !priv->tx_pending_len)641641- netif_wake_queue(priv->mesh_dev);642642-643643- kfree(chan_list);644644-645645- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);646646- return ret;647647-}648648-649649-void lbs_scan_worker(struct work_struct *work)650650-{651651- struct lbs_private *priv =652652- container_of(work, struct lbs_private, scan_work.work);653653-654654- lbs_deb_enter(LBS_DEB_SCAN);655655- lbs_scan_networks(priv, 0);656656- lbs_deb_leave(LBS_DEB_SCAN);657657-}658658-659659-660660-/*********************************************************************/661661-/* */662662-/* Result interpretation */663663-/* */664664-/*********************************************************************/665665-666666-/**667667- * @brief Interpret a BSS scan response returned from the firmware668668- *669669- * Parse the various fixed fields and IEs passed back for a BSS probe670670- * response or beacon from the scan command. Record information as needed671671- * in the scan table struct bss_descriptor for that entry.672672- *673673- * @param bss Output parameter: Pointer to the BSS Entry674674- *675675- * @return 0 or -1676676- */677677-static int lbs_process_bss(struct bss_descriptor *bss,678678- uint8_t **pbeaconinfo, int *bytesleft)679679-{680680- struct ieee_ie_fh_param_set *fh;681681- struct ieee_ie_ds_param_set *ds;682682- struct ieee_ie_cf_param_set *cf;683683- struct ieee_ie_ibss_param_set *ibss;684684- DECLARE_SSID_BUF(ssid);685685- uint8_t *pos, *end, *p;686686- uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;687687- uint16_t beaconsize = 0;688688- int ret;689689-690690- lbs_deb_enter(LBS_DEB_SCAN);691691-692692- if (*bytesleft >= sizeof(beaconsize)) {693693- /* Extract & convert beacon size from the command buffer */694694- beaconsize = get_unaligned_le16(*pbeaconinfo);695695- *bytesleft -= sizeof(beaconsize);696696- *pbeaconinfo += sizeof(beaconsize);697697- }698698-699699- if (beaconsize == 0 || beaconsize > *bytesleft) {700700- *pbeaconinfo += *bytesleft;701701- *bytesleft = 0;702702- ret = -1;703703- goto done;704704- }705705-706706- /* Initialize the current working beacon pointer for this BSS iteration */707707- pos = *pbeaconinfo;708708- end = pos + beaconsize;709709-710710- /* Advance the return beacon pointer past the current beacon */711711- *pbeaconinfo += beaconsize;712712- *bytesleft -= beaconsize;713713-714714- memcpy(bss->bssid, pos, ETH_ALEN);715715- lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid);716716- pos += ETH_ALEN;717717-718718- if ((end - pos) < 12) {719719- lbs_deb_scan("process_bss: Not enough bytes left\n");720720- ret = -1;721721- goto done;722722- }723723-724724- /*725725- * next 4 fields are RSSI, time stamp, beacon interval,726726- * and capability information727727- */728728-729729- /* RSSI is 1 byte long */730730- bss->rssi = *pos;731731- lbs_deb_scan("process_bss: RSSI %d\n", *pos);732732- pos++;733733-734734- /* time stamp is 8 bytes long */735735- pos += 8;736736-737737- /* beacon interval is 2 bytes long */738738- bss->beaconperiod = get_unaligned_le16(pos);739739- pos += 2;740740-741741- /* capability information is 2 bytes long */742742- bss->capability = get_unaligned_le16(pos);743743- lbs_deb_scan("process_bss: capabilities 0x%04x\n", bss->capability);744744- pos += 2;745745-746746- if (bss->capability & WLAN_CAPABILITY_PRIVACY)747747- lbs_deb_scan("process_bss: WEP enabled\n");748748- if (bss->capability & WLAN_CAPABILITY_IBSS)749749- bss->mode = IW_MODE_ADHOC;750750- else751751- bss->mode = IW_MODE_INFRA;752752-753753- /* rest of the current buffer are IE's */754754- lbs_deb_scan("process_bss: IE len %zd\n", end - pos);755755- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);756756-757757- /* process variable IE */758758- while (pos <= end - 2) {759759- if (pos + pos[1] > end) {760760- lbs_deb_scan("process_bss: error in processing IE, "761761- "bytes left < IE length\n");762762- break;763763- }764764-765765- switch (pos[0]) {766766- case WLAN_EID_SSID:767767- bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]);768768- memcpy(bss->ssid, pos + 2, bss->ssid_len);769769- lbs_deb_scan("got SSID IE: '%s', len %u\n",770770- print_ssid(ssid, bss->ssid, bss->ssid_len),771771- bss->ssid_len);772772- break;773773-774774- case WLAN_EID_SUPP_RATES:775775- n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]);776776- memcpy(bss->rates, pos + 2, n_basic_rates);777777- got_basic_rates = 1;778778- lbs_deb_scan("got RATES IE\n");779779- break;780780-781781- case WLAN_EID_FH_PARAMS:782782- fh = (struct ieee_ie_fh_param_set *) pos;783783- memcpy(&bss->phy.fh, fh, sizeof(*fh));784784- lbs_deb_scan("got FH IE\n");785785- break;786786-787787- case WLAN_EID_DS_PARAMS:788788- ds = (struct ieee_ie_ds_param_set *) pos;789789- bss->channel = ds->channel;790790- memcpy(&bss->phy.ds, ds, sizeof(*ds));791791- lbs_deb_scan("got DS IE, channel %d\n", bss->channel);792792- break;793793-794794- case WLAN_EID_CF_PARAMS:795795- cf = (struct ieee_ie_cf_param_set *) pos;796796- memcpy(&bss->ss.cf, cf, sizeof(*cf));797797- lbs_deb_scan("got CF IE\n");798798- break;799799-800800- case WLAN_EID_IBSS_PARAMS:801801- ibss = (struct ieee_ie_ibss_param_set *) pos;802802- bss->atimwindow = ibss->atimwindow;803803- memcpy(&bss->ss.ibss, ibss, sizeof(*ibss));804804- lbs_deb_scan("got IBSS IE\n");805805- break;806806-807807- case WLAN_EID_EXT_SUPP_RATES:808808- /* only process extended supported rate if data rate is809809- * already found. Data rate IE should come before810810- * extended supported rate IE811811- */812812- lbs_deb_scan("got RATESEX IE\n");813813- if (!got_basic_rates) {814814- lbs_deb_scan("... but ignoring it\n");815815- break;816816- }817817-818818- n_ex_rates = pos[1];819819- if (n_basic_rates + n_ex_rates > MAX_RATES)820820- n_ex_rates = MAX_RATES - n_basic_rates;821821-822822- p = bss->rates + n_basic_rates;823823- memcpy(p, pos + 2, n_ex_rates);824824- break;825825-826826- case WLAN_EID_GENERIC:827827- if (pos[1] >= 4 &&828828- pos[2] == 0x00 && pos[3] == 0x50 &&829829- pos[4] == 0xf2 && pos[5] == 0x01) {830830- bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);831831- memcpy(bss->wpa_ie, pos, bss->wpa_ie_len);832832- lbs_deb_scan("got WPA IE\n");833833- lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie,834834- bss->wpa_ie_len);835835- } else if (pos[1] >= MARVELL_MESH_IE_LENGTH &&836836- pos[2] == 0x00 && pos[3] == 0x50 &&837837- pos[4] == 0x43 && pos[5] == 0x04) {838838- lbs_deb_scan("got mesh IE\n");839839- bss->mesh = 1;840840- } else {841841- lbs_deb_scan("got generic IE: %02x:%02x:%02x:%02x, len %d\n",842842- pos[2], pos[3],843843- pos[4], pos[5],844844- pos[1]);845845- }846846- break;847847-848848- case WLAN_EID_RSN:849849- lbs_deb_scan("got RSN IE\n");850850- bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN);851851- memcpy(bss->rsn_ie, pos, bss->rsn_ie_len);852852- lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE",853853- bss->rsn_ie, bss->rsn_ie_len);854854- break;855855-856856- default:857857- lbs_deb_scan("got IE 0x%04x, len %d\n",858858- pos[0], pos[1]);859859- break;860860- }861861-862862- pos += pos[1] + 2;863863- }864864-865865- /* Timestamp */866866- bss->last_scanned = jiffies;867867- lbs_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));868868-869869- ret = 0;870870-871871-done:872872- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);873873- return ret;874874-}875875-876876-/**877877- * @brief Send a scan command for all available channels filtered on a spec878878- *879879- * Used in association code and from debugfs880880- *881881- * @param priv A pointer to struct lbs_private structure882882- * @param ssid A pointer to the SSID to scan for883883- * @param ssid_len Length of the SSID884884- *885885- * @return 0-success, otherwise fail886886- */887887-int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid,888888- uint8_t ssid_len)889889-{890890- DECLARE_SSID_BUF(ssid_buf);891891- int ret = 0;892892-893893- lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n",894894- print_ssid(ssid_buf, ssid, ssid_len));895895-896896- if (!ssid_len)897897- goto out;898898-899899- memcpy(priv->scan_ssid, ssid, ssid_len);900900- priv->scan_ssid_len = ssid_len;901901-902902- lbs_scan_networks(priv, 1);903903- if (priv->surpriseremoved) {904904- ret = -1;905905- goto out;906906- }907907-908908-out:909909- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);910910- return ret;911911-}912912-913913-914914-915915-916916-/*********************************************************************/917917-/* */918918-/* Support for Wireless Extensions */919919-/* */920920-/*********************************************************************/921921-922922-923923-#define MAX_CUSTOM_LEN 64924924-925925-static inline char *lbs_translate_scan(struct lbs_private *priv,926926- struct iw_request_info *info,927927- char *start, char *stop,928928- struct bss_descriptor *bss)929929-{930930- struct chan_freq_power *cfp;931931- char *current_val; /* For rates */932932- struct iw_event iwe; /* Temporary buffer */933933- int j;934934-#define PERFECT_RSSI ((uint8_t)50)935935-#define WORST_RSSI ((uint8_t)0)936936-#define RSSI_DIFF ((uint8_t)(PERFECT_RSSI - WORST_RSSI))937937- uint8_t rssi;938938-939939- lbs_deb_enter(LBS_DEB_SCAN);940940-941941- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, bss->channel);942942- if (!cfp) {943943- lbs_deb_scan("Invalid channel number %d\n", bss->channel);944944- start = NULL;945945- goto out;946946- }947947-948948- /* First entry *MUST* be the BSSID */949949- iwe.cmd = SIOCGIWAP;950950- iwe.u.ap_addr.sa_family = ARPHRD_ETHER;951951- memcpy(iwe.u.ap_addr.sa_data, &bss->bssid, ETH_ALEN);952952- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);953953-954954- /* SSID */955955- iwe.cmd = SIOCGIWESSID;956956- iwe.u.data.flags = 1;957957- iwe.u.data.length = min((uint32_t) bss->ssid_len, (uint32_t) IEEE80211_MAX_SSID_LEN);958958- start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);959959-960960- /* Mode */961961- iwe.cmd = SIOCGIWMODE;962962- iwe.u.mode = bss->mode;963963- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN);964964-965965- /* Frequency */966966- iwe.cmd = SIOCGIWFREQ;967967- iwe.u.freq.m = (long)cfp->freq * 100000;968968- iwe.u.freq.e = 1;969969- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);970970-971971- /* Add quality statistics */972972- iwe.cmd = IWEVQUAL;973973- iwe.u.qual.updated = IW_QUAL_ALL_UPDATED;974974- iwe.u.qual.level = SCAN_RSSI(bss->rssi);975975-976976- rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE;977977- iwe.u.qual.qual =978978- (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) *979979- (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) /980980- (RSSI_DIFF * RSSI_DIFF);981981- if (iwe.u.qual.qual > 100)982982- iwe.u.qual.qual = 100;983983-984984- if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {985985- iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;986986- } else {987987- iwe.u.qual.noise = CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);988988- }989989-990990- /* Locally created ad-hoc BSSs won't have beacons if this is the991991- * only station in the adhoc network; so get signal strength992992- * from receive statistics.993993- */994994- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate995995- && !lbs_ssid_cmp(priv->curbssparams.ssid,996996- priv->curbssparams.ssid_len,997997- bss->ssid, bss->ssid_len)) {998998- int snr, nf;999999- snr = priv->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;10001000- nf = priv->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE;10011001- iwe.u.qual.level = CAL_RSSI(snr, nf);10021002- }10031003- start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);10041004-10051005- /* Add encryption capability */10061006- iwe.cmd = SIOCGIWENCODE;10071007- if (bss->capability & WLAN_CAPABILITY_PRIVACY) {10081008- iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;10091009- } else {10101010- iwe.u.data.flags = IW_ENCODE_DISABLED;10111011- }10121012- iwe.u.data.length = 0;10131013- start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid);10141014-10151015- current_val = start + iwe_stream_lcp_len(info);10161016-10171017- iwe.cmd = SIOCGIWRATE;10181018- iwe.u.bitrate.fixed = 0;10191019- iwe.u.bitrate.disabled = 0;10201020- iwe.u.bitrate.value = 0;10211021-10221022- for (j = 0; j < ARRAY_SIZE(bss->rates) && bss->rates[j]; j++) {10231023- /* Bit rate given in 500 kb/s units */10241024- iwe.u.bitrate.value = bss->rates[j] * 500000;10251025- current_val = iwe_stream_add_value(info, start, current_val,10261026- stop, &iwe, IW_EV_PARAM_LEN);10271027- }10281028- if ((bss->mode == IW_MODE_ADHOC) && priv->adhoccreate10291029- && !lbs_ssid_cmp(priv->curbssparams.ssid,10301030- priv->curbssparams.ssid_len,10311031- bss->ssid, bss->ssid_len)) {10321032- iwe.u.bitrate.value = 22 * 500000;10331033- current_val = iwe_stream_add_value(info, start, current_val,10341034- stop, &iwe, IW_EV_PARAM_LEN);10351035- }10361036- /* Check if we added any event */10371037- if ((current_val - start) > iwe_stream_lcp_len(info))10381038- start = current_val;10391039-10401040- memset(&iwe, 0, sizeof(iwe));10411041- if (bss->wpa_ie_len) {10421042- char buf[MAX_WPA_IE_LEN];10431043- memcpy(buf, bss->wpa_ie, bss->wpa_ie_len);10441044- iwe.cmd = IWEVGENIE;10451045- iwe.u.data.length = bss->wpa_ie_len;10461046- start = iwe_stream_add_point(info, start, stop, &iwe, buf);10471047- }10481048-10491049- memset(&iwe, 0, sizeof(iwe));10501050- if (bss->rsn_ie_len) {10511051- char buf[MAX_WPA_IE_LEN];10521052- memcpy(buf, bss->rsn_ie, bss->rsn_ie_len);10531053- iwe.cmd = IWEVGENIE;10541054- iwe.u.data.length = bss->rsn_ie_len;10551055- start = iwe_stream_add_point(info, start, stop, &iwe, buf);10561056- }10571057-10581058- if (bss->mesh) {10591059- char custom[MAX_CUSTOM_LEN];10601060- char *p = custom;10611061-10621062- iwe.cmd = IWEVCUSTOM;10631063- p += snprintf(p, MAX_CUSTOM_LEN, "mesh-type: olpc");10641064- iwe.u.data.length = p - custom;10651065- if (iwe.u.data.length)10661066- start = iwe_stream_add_point(info, start, stop,10671067- &iwe, custom);10681068- }10691069-10701070-out:10711071- lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);10721072- return start;10731073-}10741074-10751075-10761076-/**10771077- * @brief Handle Scan Network ioctl10781078- *10791079- * @param dev A pointer to net_device structure10801080- * @param info A pointer to iw_request_info structure10811081- * @param vwrq A pointer to iw_param structure10821082- * @param extra A pointer to extra data buf10831083- *10841084- * @return 0 --success, otherwise fail10851085- */10861086-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,10871087- union iwreq_data *wrqu, char *extra)10881088-{10891089- DECLARE_SSID_BUF(ssid);10901090- struct lbs_private *priv = dev->ml_priv;10911091- int ret = 0;10921092-10931093- lbs_deb_enter(LBS_DEB_WEXT);10941094-10951095- if (!priv->radio_on) {10961096- ret = -EINVAL;10971097- goto out;10981098- }10991099-11001100- if (!netif_running(dev)) {11011101- ret = -ENETDOWN;11021102- goto out;11031103- }11041104-11051105- /* mac80211 does this:11061106- struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);11071107- if (sdata->type != IEEE80211_IF_TYPE_xxx) {11081108- ret = -EOPNOTSUPP;11091109- goto out;11101110- }11111111- */11121112-11131113- if (wrqu->data.length == sizeof(struct iw_scan_req) &&11141114- wrqu->data.flags & IW_SCAN_THIS_ESSID) {11151115- struct iw_scan_req *req = (struct iw_scan_req *)extra;11161116- priv->scan_ssid_len = req->essid_len;11171117- memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len);11181118- lbs_deb_wext("set_scan, essid '%s'\n",11191119- print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len));11201120- } else {11211121- priv->scan_ssid_len = 0;11221122- }11231123-11241124- if (!delayed_work_pending(&priv->scan_work))11251125- queue_delayed_work(priv->work_thread, &priv->scan_work,11261126- msecs_to_jiffies(50));11271127- /* set marker that currently a scan is taking place */11281128- priv->scan_channel = -1;11291129-11301130- if (priv->surpriseremoved)11311131- ret = -EIO;11321132-11331133-out:11341134- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);11351135- return ret;11361136-}11371137-11381138-11391139-/**11401140- * @brief Handle Retrieve scan table ioctl11411141- *11421142- * @param dev A pointer to net_device structure11431143- * @param info A pointer to iw_request_info structure11441144- * @param dwrq A pointer to iw_point structure11451145- * @param extra A pointer to extra data buf11461146- *11471147- * @return 0 --success, otherwise fail11481148- */11491149-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,11501150- struct iw_point *dwrq, char *extra)11511151-{11521152-#define SCAN_ITEM_SIZE 12811531153- struct lbs_private *priv = dev->ml_priv;11541154- int err = 0;11551155- char *ev = extra;11561156- char *stop = ev + dwrq->length;11571157- struct bss_descriptor *iter_bss;11581158- struct bss_descriptor *safe;11591159-11601160- lbs_deb_enter(LBS_DEB_WEXT);11611161-11621162- /* iwlist should wait until the current scan is finished */11631163- if (priv->scan_channel)11641164- return -EAGAIN;11651165-11661166- /* Update RSSI if current BSS is a locally created ad-hoc BSS */11671167- if ((priv->mode == IW_MODE_ADHOC) && priv->adhoccreate) {11681168- err = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,11691169- CMD_OPTION_WAITFORRSP, 0, NULL);11701170- if (err)11711171- goto out;11721172- }11731173-11741174- mutex_lock(&priv->lock);11751175- list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {11761176- char *next_ev;11771177- unsigned long stale_time;11781178-11791179- if (stop - ev < SCAN_ITEM_SIZE) {11801180- err = -E2BIG;11811181- break;11821182- }11831183-11841184- /* For mesh device, list only mesh networks */11851185- if (dev == priv->mesh_dev && !iter_bss->mesh)11861186- continue;11871187-11881188- /* Prune old an old scan result */11891189- stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;11901190- if (time_after(jiffies, stale_time)) {11911191- list_move_tail(&iter_bss->list, &priv->network_free_list);11921192- clear_bss_descriptor(iter_bss);11931193- continue;11941194- }11951195-11961196- /* Translate to WE format this entry */11971197- next_ev = lbs_translate_scan(priv, info, ev, stop, iter_bss);11981198- if (next_ev == NULL)11991199- continue;12001200- ev = next_ev;12011201- }12021202- mutex_unlock(&priv->lock);12031203-12041204- dwrq->length = (ev - extra);12051205- dwrq->flags = 0;12061206-out:12071207- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", err);12081208- return err;12091209-}12101210-12111211-12121212-12131213-12141214-/*********************************************************************/12151215-/* */12161216-/* Command execution */12171217-/* */12181218-/*********************************************************************/12191219-12201220-12211221-/**12221222- * @brief This function handles the command response of scan12231223- *12241224- * Called from handle_cmd_response() in cmdrespc.12251225- *12261226- * The response buffer for the scan command has the following12271227- * memory layout:12281228- *12291229- * .-----------------------------------------------------------.12301230- * | header (4 * sizeof(u16)): Standard command response hdr |12311231- * .-----------------------------------------------------------.12321232- * | bufsize (u16) : sizeof the BSS Description data |12331233- * .-----------------------------------------------------------.12341234- * | NumOfSet (u8) : Number of BSS Descs returned |12351235- * .-----------------------------------------------------------.12361236- * | BSSDescription data (variable, size given in bufsize) |12371237- * .-----------------------------------------------------------.12381238- * | TLV data (variable, size calculated using header->size, |12391239- * | bufsize and sizeof the fixed fields above) |12401240- * .-----------------------------------------------------------.12411241- *12421242- * @param priv A pointer to struct lbs_private structure12431243- * @param resp A pointer to cmd_ds_command12441244- *12451245- * @return 0 or -112461246- */12471247-static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy,12481248- struct cmd_header *resp)12491249-{12501250- struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;12511251- struct bss_descriptor *iter_bss;12521252- struct bss_descriptor *safe;12531253- uint8_t *bssinfo;12541254- uint16_t scanrespsize;12551255- int bytesleft;12561256- int idx;12571257- int tlvbufsize;12581258- int ret;12591259-12601260- lbs_deb_enter(LBS_DEB_SCAN);12611261-12621262- /* Prune old entries from scan table */12631263- list_for_each_entry_safe (iter_bss, safe, &priv->network_list, list) {12641264- unsigned long stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;12651265- if (time_before(jiffies, stale_time))12661266- continue;12671267- list_move_tail (&iter_bss->list, &priv->network_free_list);12681268- clear_bss_descriptor(iter_bss);12691269- }12701270-12711271- if (scanresp->nr_sets > MAX_NETWORK_COUNT) {12721272- lbs_deb_scan("SCAN_RESP: too many scan results (%d, max %d)\n",12731273- scanresp->nr_sets, MAX_NETWORK_COUNT);12741274- ret = -1;12751275- goto done;12761276- }12771277-12781278- bytesleft = get_unaligned_le16(&scanresp->bssdescriptsize);12791279- lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);12801280-12811281- scanrespsize = le16_to_cpu(resp->size);12821282- lbs_deb_scan("SCAN_RESP: scan results %d\n", scanresp->nr_sets);12831283-12841284- bssinfo = scanresp->bssdesc_and_tlvbuffer;12851285-12861286- /* The size of the TLV buffer is equal to the entire command response12871287- * size (scanrespsize) minus the fixed fields (sizeof()'s), the12881288- * BSS Descriptions (bssdescriptsize as bytesLef) and the command12891289- * response header (sizeof(struct cmd_header))12901290- */12911291- tlvbufsize = scanrespsize - (bytesleft + sizeof(scanresp->bssdescriptsize)12921292- + sizeof(scanresp->nr_sets)12931293- + sizeof(struct cmd_header));12941294-12951295- /*12961296- * Process each scan response returned (scanresp->nr_sets). Save12971297- * the information in the newbssentry and then insert into the12981298- * driver scan table either as an update to an existing entry12991299- * or as an addition at the end of the table13001300- */13011301- for (idx = 0; idx < scanresp->nr_sets && bytesleft; idx++) {13021302- struct bss_descriptor new;13031303- struct bss_descriptor *found = NULL;13041304- struct bss_descriptor *oldest = NULL;13051305-13061306- /* Process the data fields and IEs returned for this BSS */13071307- memset(&new, 0, sizeof (struct bss_descriptor));13081308- if (lbs_process_bss(&new, &bssinfo, &bytesleft) != 0) {13091309- /* error parsing the scan response, skipped */13101310- lbs_deb_scan("SCAN_RESP: process_bss returned ERROR\n");13111311- continue;13121312- }13131313-13141314- /* Try to find this bss in the scan table */13151315- list_for_each_entry (iter_bss, &priv->network_list, list) {13161316- if (is_same_network(iter_bss, &new)) {13171317- found = iter_bss;13181318- break;13191319- }13201320-13211321- if ((oldest == NULL) ||13221322- (iter_bss->last_scanned < oldest->last_scanned))13231323- oldest = iter_bss;13241324- }13251325-13261326- if (found) {13271327- /* found, clear it */13281328- clear_bss_descriptor(found);13291329- } else if (!list_empty(&priv->network_free_list)) {13301330- /* Pull one from the free list */13311331- found = list_entry(priv->network_free_list.next,13321332- struct bss_descriptor, list);13331333- list_move_tail(&found->list, &priv->network_list);13341334- } else if (oldest) {13351335- /* If there are no more slots, expire the oldest */13361336- found = oldest;13371337- clear_bss_descriptor(found);13381338- list_move_tail(&found->list, &priv->network_list);13391339- } else {13401340- continue;13411341- }13421342-13431343- lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid);13441344-13451345- /* Copy the locally created newbssentry to the scan table */13461346- memcpy(found, &new, offsetof(struct bss_descriptor, list));13471347- }13481348-13491349- ret = 0;13501350-13511351-done:13521352- lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);13531353- return ret;13541354-}
-63
drivers/net/wireless/libertas/scan.h
···11-/**22- * Interface for the wlan network scan routines33- *44- * Driver interface functions and type declarations for the scan module55- * implemented in scan.c.66- */77-#ifndef _LBS_SCAN_H88-#define _LBS_SCAN_H99-1010-#include <net/iw_handler.h>1111-1212-struct lbs_private;1313-1414-#define MAX_NETWORK_COUNT 1281515-1616-/** Chan-freq-TxPower mapping table*/1717-struct chan_freq_power {1818- /** channel Number */1919- u16 channel;2020- /** frequency of this channel */2121- u32 freq;2222- /** Max allowed Tx power level */2323- u16 maxtxpower;2424- /** TRUE:channel unsupported; FLASE:supported*/2525- u8 unsupported;2626-};2727-2828-/** region-band mapping table*/2929-struct region_channel {3030- /** TRUE if this entry is valid */3131- u8 valid;3232- /** region code for US, Japan ... */3333- u8 region;3434- /** band B/G/A, used for BAND_CONFIG cmd */3535- u8 band;3636- /** Actual No. of elements in the array below */3737- u8 nrcfp;3838- /** chan-freq-txpower mapping table*/3939- struct chan_freq_power *CFP;4040-};4141-4242-/**4343- * @brief Maximum number of channels that can be sent in a setuserscan ioctl4444- */4545-#define LBS_IOCTL_USER_SCAN_CHAN_MAX 504646-4747-int lbs_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);4848-4949-int lbs_set_regiontable(struct lbs_private *priv, u8 region, u8 band);5050-5151-int lbs_send_specific_ssid_scan(struct lbs_private *priv, u8 *ssid,5252- u8 ssid_len);5353-5454-int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,5555- struct iw_point *dwrq, char *extra);5656-int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,5757- union iwreq_data *wrqu, char *extra);5858-5959-int lbs_scan_networks(struct lbs_private *priv, int full_scan);6060-6161-void lbs_scan_worker(struct work_struct *work);6262-6363-#endif
+7-5
drivers/net/wireless/libertas/tx.c
···44#include <linux/netdevice.h>55#include <linux/etherdevice.h>66#include <linux/sched.h>77+#include <net/cfg80211.h>7889#include "host.h"910#include "radiotap.h"1011#include "decl.h"1112#include "defs.h"1213#include "dev.h"1313-#include "wext.h"14141515/**1616 * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE···111111 p802x_hdr = skb->data;112112 pkt_len = skb->len;113113114114- if (dev == priv->rtap_net_dev) {114114+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {115115 struct tx_radiotap_hdr *rtap_hdr = (void *)skb->data;116116117117 /* set txpd fields from the radiotap header */···147147 dev->stats.tx_packets++;148148 dev->stats.tx_bytes += skb->len;149149150150- if (priv->monitormode) {150150+ if (priv->wdev->iftype == NL80211_IFTYPE_MONITOR) {151151 /* Keep the skb to echo it back once Tx feedback is152152 received from FW */153153 skb_orphan(skb);···158158 free:159159 dev_kfree_skb_any(skb);160160 }161161+161162 unlock:162163 spin_unlock_irqrestore(&priv->driver_lock, flags);163164 wake_up(&priv->waitq);···180179{181180 struct tx_radiotap_hdr *radiotap_hdr;182181183183- if (!priv->monitormode || priv->currenttxskb == NULL)182182+ if (!priv->wdev->iftype == NL80211_IFTYPE_MONITOR ||183183+ priv->currenttxskb == NULL)184184 return;185185186186 radiotap_hdr = (struct tx_radiotap_hdr *)priv->currenttxskb->data;···190188 (1 + priv->txretrycount - try_count) : 0;191189192190 priv->currenttxskb->protocol = eth_type_trans(priv->currenttxskb,193193- priv->rtap_net_dev);191191+ priv->dev);194192 netif_rx(priv->currenttxskb);195193196194 priv->currenttxskb = NULL;
-2353
drivers/net/wireless/libertas/wext.c
···11-/**22- * This file contains ioctl functions33- */44-#include <linux/ctype.h>55-#include <linux/slab.h>66-#include <linux/delay.h>77-#include <linux/if.h>88-#include <linux/if_arp.h>99-#include <linux/wireless.h>1010-#include <linux/bitops.h>1111-1212-#include <net/lib80211.h>1313-#include <net/iw_handler.h>1414-1515-#include "host.h"1616-#include "radiotap.h"1717-#include "decl.h"1818-#include "defs.h"1919-#include "dev.h"2020-#include "wext.h"2121-#include "scan.h"2222-#include "assoc.h"2323-#include "cmd.h"2424-2525-2626-static inline void lbs_postpone_association_work(struct lbs_private *priv)2727-{2828- if (priv->surpriseremoved)2929- return;3030- cancel_delayed_work(&priv->assoc_work);3131- queue_delayed_work(priv->work_thread, &priv->assoc_work, HZ / 2);3232-}3333-3434-static inline void lbs_do_association_work(struct lbs_private *priv)3535-{3636- if (priv->surpriseremoved)3737- return;3838- cancel_delayed_work(&priv->assoc_work);3939- queue_delayed_work(priv->work_thread, &priv->assoc_work, 0);4040-}4141-4242-static inline void lbs_cancel_association_work(struct lbs_private *priv)4343-{4444- cancel_delayed_work(&priv->assoc_work);4545- kfree(priv->pending_assoc_req);4646- priv->pending_assoc_req = NULL;4747-}4848-4949-void lbs_send_disconnect_notification(struct lbs_private *priv)5050-{5151- union iwreq_data wrqu;5252-5353- memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);5454- wrqu.ap_addr.sa_family = ARPHRD_ETHER;5555- wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);5656-}5757-5858-static void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str)5959-{6060- union iwreq_data iwrq;6161- u8 buf[50];6262-6363- lbs_deb_enter(LBS_DEB_WEXT);6464-6565- memset(&iwrq, 0, sizeof(union iwreq_data));6666- memset(buf, 0, sizeof(buf));6767-6868- snprintf(buf, sizeof(buf) - 1, "%s", str);6969-7070- iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;7171-7272- /* Send Event to upper layer */7373- lbs_deb_wext("event indication string %s\n", (char *)buf);7474- lbs_deb_wext("event indication length %d\n", iwrq.data.length);7575- lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);7676-7777- wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);7878-7979- lbs_deb_leave(LBS_DEB_WEXT);8080-}8181-8282-/**8383- * @brief This function handles MIC failure event.8484- *8585- * @param priv A pointer to struct lbs_private structure8686- * @para event the event id8787- * @return n/a8888- */8989-void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)9090-{9191- char buf[50];9292-9393- lbs_deb_enter(LBS_DEB_CMD);9494- memset(buf, 0, sizeof(buf));9595-9696- sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");9797-9898- if (event == MACREG_INT_CODE_MIC_ERR_UNICAST)9999- strcat(buf, "unicast ");100100- else101101- strcat(buf, "multicast ");102102-103103- lbs_send_iwevcustom_event(priv, buf);104104- lbs_deb_leave(LBS_DEB_CMD);105105-}106106-107107-/**108108- * @brief Find the channel frequency power info with specific channel109109- *110110- * @param priv A pointer to struct lbs_private structure111111- * @param band it can be BAND_A, BAND_G or BAND_B112112- * @param channel the channel for looking113113- * @return A pointer to struct chan_freq_power structure or NULL if not find.114114- */115115-struct chan_freq_power *lbs_find_cfp_by_band_and_channel(116116- struct lbs_private *priv,117117- u8 band,118118- u16 channel)119119-{120120- struct chan_freq_power *cfp = NULL;121121- struct region_channel *rc;122122- int i, j;123123-124124- for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {125125- rc = &priv->region_channel[j];126126-127127- if (!rc->valid || !rc->CFP)128128- continue;129129- if (rc->band != band)130130- continue;131131- for (i = 0; i < rc->nrcfp; i++) {132132- if (rc->CFP[i].channel == channel) {133133- cfp = &rc->CFP[i];134134- break;135135- }136136- }137137- }138138-139139- if (!cfp && channel)140140- lbs_deb_wext("lbs_find_cfp_by_band_and_channel: can't find "141141- "cfp by band %d / channel %d\n", band, channel);142142-143143- return cfp;144144-}145145-146146-/**147147- * @brief Find the channel frequency power info with specific frequency148148- *149149- * @param priv A pointer to struct lbs_private structure150150- * @param band it can be BAND_A, BAND_G or BAND_B151151- * @param freq the frequency for looking152152- * @return A pointer to struct chan_freq_power structure or NULL if not find.153153- */154154-static struct chan_freq_power *find_cfp_by_band_and_freq(155155- struct lbs_private *priv,156156- u8 band,157157- u32 freq)158158-{159159- struct chan_freq_power *cfp = NULL;160160- struct region_channel *rc;161161- int i, j;162162-163163- for (j = 0; !cfp && (j < ARRAY_SIZE(priv->region_channel)); j++) {164164- rc = &priv->region_channel[j];165165-166166- if (!rc->valid || !rc->CFP)167167- continue;168168- if (rc->band != band)169169- continue;170170- for (i = 0; i < rc->nrcfp; i++) {171171- if (rc->CFP[i].freq == freq) {172172- cfp = &rc->CFP[i];173173- break;174174- }175175- }176176- }177177-178178- if (!cfp && freq)179179- lbs_deb_wext("find_cfp_by_band_and_freql: can't find cfp by "180180- "band %d / freq %d\n", band, freq);181181-182182- return cfp;183183-}184184-185185-/**186186- * @brief Copy active data rates based on adapter mode and status187187- *188188- * @param priv A pointer to struct lbs_private structure189189- * @param rate The buf to return the active rates190190- */191191-static void copy_active_data_rates(struct lbs_private *priv, u8 *rates)192192-{193193- lbs_deb_enter(LBS_DEB_WEXT);194194-195195- if ((priv->connect_status != LBS_CONNECTED) &&196196- !lbs_mesh_connected(priv))197197- memcpy(rates, lbs_bg_rates, MAX_RATES);198198- else199199- memcpy(rates, priv->curbssparams.rates, MAX_RATES);200200-201201- lbs_deb_leave(LBS_DEB_WEXT);202202-}203203-204204-static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,205205- char *cwrq, char *extra)206206-{207207-208208- lbs_deb_enter(LBS_DEB_WEXT);209209-210210- /* We could add support for 802.11n here as needed. Jean II */211211- snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");212212-213213- lbs_deb_leave(LBS_DEB_WEXT);214214- return 0;215215-}216216-217217-static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,218218- struct iw_freq *fwrq, char *extra)219219-{220220- struct lbs_private *priv = dev->ml_priv;221221- struct chan_freq_power *cfp;222222-223223- lbs_deb_enter(LBS_DEB_WEXT);224224-225225- cfp = lbs_find_cfp_by_band_and_channel(priv, 0,226226- priv->channel);227227-228228- if (!cfp) {229229- if (priv->channel)230230- lbs_deb_wext("invalid channel %d\n",231231- priv->channel);232232- return -EINVAL;233233- }234234-235235- fwrq->m = (long)cfp->freq * 100000;236236- fwrq->e = 1;237237-238238- lbs_deb_wext("freq %u\n", fwrq->m);239239- lbs_deb_leave(LBS_DEB_WEXT);240240- return 0;241241-}242242-243243-static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,244244- struct sockaddr *awrq, char *extra)245245-{246246- struct lbs_private *priv = dev->ml_priv;247247-248248- lbs_deb_enter(LBS_DEB_WEXT);249249-250250- if (priv->connect_status == LBS_CONNECTED) {251251- memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN);252252- } else {253253- memset(awrq->sa_data, 0, ETH_ALEN);254254- }255255- awrq->sa_family = ARPHRD_ETHER;256256-257257- lbs_deb_leave(LBS_DEB_WEXT);258258- return 0;259259-}260260-261261-static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,262262- struct iw_point *dwrq, char *extra)263263-{264264- struct lbs_private *priv = dev->ml_priv;265265-266266- lbs_deb_enter(LBS_DEB_WEXT);267267-268268- /*269269- * Check the size of the string270270- */271271-272272- if (dwrq->length > 16) {273273- return -E2BIG;274274- }275275-276276- mutex_lock(&priv->lock);277277- memset(priv->nodename, 0, sizeof(priv->nodename));278278- memcpy(priv->nodename, extra, dwrq->length);279279- mutex_unlock(&priv->lock);280280-281281- lbs_deb_leave(LBS_DEB_WEXT);282282- return 0;283283-}284284-285285-static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,286286- struct iw_point *dwrq, char *extra)287287-{288288- struct lbs_private *priv = dev->ml_priv;289289-290290- lbs_deb_enter(LBS_DEB_WEXT);291291-292292- dwrq->length = strlen(priv->nodename);293293- memcpy(extra, priv->nodename, dwrq->length);294294- extra[dwrq->length] = '\0';295295-296296- dwrq->flags = 1; /* active */297297-298298- lbs_deb_leave(LBS_DEB_WEXT);299299- return 0;300300-}301301-302302-#ifdef CONFIG_LIBERTAS_MESH303303-static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,304304- struct iw_point *dwrq, char *extra)305305-{306306- struct lbs_private *priv = dev->ml_priv;307307-308308- lbs_deb_enter(LBS_DEB_WEXT);309309-310310- /* Use nickname to indicate that mesh is on */311311-312312- if (lbs_mesh_connected(priv)) {313313- strncpy(extra, "Mesh", 12);314314- extra[12] = '\0';315315- dwrq->length = strlen(extra);316316- }317317-318318- else {319319- extra[0] = '\0';320320- dwrq->length = 0;321321- }322322-323323- lbs_deb_leave(LBS_DEB_WEXT);324324- return 0;325325-}326326-#endif327327-328328-static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,329329- struct iw_param *vwrq, char *extra)330330-{331331- int ret = 0;332332- struct lbs_private *priv = dev->ml_priv;333333- u32 val = vwrq->value;334334-335335- lbs_deb_enter(LBS_DEB_WEXT);336336-337337- if (vwrq->disabled)338338- val = MRVDRV_RTS_MAX_VALUE;339339-340340- if (val > MRVDRV_RTS_MAX_VALUE) /* min rts value is 0 */341341- return -EINVAL;342342-343343- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, (u16) val);344344-345345- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);346346- return ret;347347-}348348-349349-static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,350350- struct iw_param *vwrq, char *extra)351351-{352352- struct lbs_private *priv = dev->ml_priv;353353- int ret = 0;354354- u16 val = 0;355355-356356- lbs_deb_enter(LBS_DEB_WEXT);357357-358358- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_RTS_THRESHOLD, &val);359359- if (ret)360360- goto out;361361-362362- vwrq->value = val;363363- vwrq->disabled = val > MRVDRV_RTS_MAX_VALUE; /* min rts value is 0 */364364- vwrq->fixed = 1;365365-366366-out:367367- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);368368- return ret;369369-}370370-371371-static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,372372- struct iw_param *vwrq, char *extra)373373-{374374- struct lbs_private *priv = dev->ml_priv;375375- int ret = 0;376376- u32 val = vwrq->value;377377-378378- lbs_deb_enter(LBS_DEB_WEXT);379379-380380- if (vwrq->disabled)381381- val = MRVDRV_FRAG_MAX_VALUE;382382-383383- if (val < MRVDRV_FRAG_MIN_VALUE || val > MRVDRV_FRAG_MAX_VALUE)384384- return -EINVAL;385385-386386- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, (u16) val);387387-388388- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);389389- return ret;390390-}391391-392392-static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,393393- struct iw_param *vwrq, char *extra)394394-{395395- struct lbs_private *priv = dev->ml_priv;396396- int ret = 0;397397- u16 val = 0;398398-399399- lbs_deb_enter(LBS_DEB_WEXT);400400-401401- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_FRAG_THRESHOLD, &val);402402- if (ret)403403- goto out;404404-405405- vwrq->value = val;406406- vwrq->disabled = ((val < MRVDRV_FRAG_MIN_VALUE)407407- || (val > MRVDRV_FRAG_MAX_VALUE));408408- vwrq->fixed = 1;409409-410410-out:411411- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);412412- return ret;413413-}414414-415415-static int lbs_get_mode(struct net_device *dev,416416- struct iw_request_info *info, u32 * uwrq, char *extra)417417-{418418- struct lbs_private *priv = dev->ml_priv;419419-420420- lbs_deb_enter(LBS_DEB_WEXT);421421-422422- *uwrq = priv->mode;423423-424424- lbs_deb_leave(LBS_DEB_WEXT);425425- return 0;426426-}427427-428428-#ifdef CONFIG_LIBERTAS_MESH429429-static int mesh_wlan_get_mode(struct net_device *dev,430430- struct iw_request_info *info, u32 * uwrq,431431- char *extra)432432-{433433- lbs_deb_enter(LBS_DEB_WEXT);434434-435435- *uwrq = IW_MODE_REPEAT;436436-437437- lbs_deb_leave(LBS_DEB_WEXT);438438- return 0;439439-}440440-#endif441441-442442-static int lbs_get_txpow(struct net_device *dev,443443- struct iw_request_info *info,444444- struct iw_param *vwrq, char *extra)445445-{446446- struct lbs_private *priv = dev->ml_priv;447447- s16 curlevel = 0;448448- int ret = 0;449449-450450- lbs_deb_enter(LBS_DEB_WEXT);451451-452452- if (!priv->radio_on) {453453- lbs_deb_wext("tx power off\n");454454- vwrq->value = 0;455455- vwrq->disabled = 1;456456- goto out;457457- }458458-459459- ret = lbs_get_tx_power(priv, &curlevel, NULL, NULL);460460- if (ret)461461- goto out;462462-463463- lbs_deb_wext("tx power level %d dbm\n", curlevel);464464- priv->txpower_cur = curlevel;465465-466466- vwrq->value = curlevel;467467- vwrq->fixed = 1;468468- vwrq->disabled = 0;469469- vwrq->flags = IW_TXPOW_DBM;470470-471471-out:472472- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);473473- return ret;474474-}475475-476476-static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,477477- struct iw_param *vwrq, char *extra)478478-{479479- struct lbs_private *priv = dev->ml_priv;480480- int ret = 0;481481- u16 slimit = 0, llimit = 0;482482-483483- lbs_deb_enter(LBS_DEB_WEXT);484484-485485- if ((vwrq->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)486486- return -EOPNOTSUPP;487487-488488- /* The MAC has a 4-bit Total_Tx_Count register489489- Total_Tx_Count = 1 + Tx_Retry_Count */490490-#define TX_RETRY_MIN 0491491-#define TX_RETRY_MAX 14492492- if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX)493493- return -EINVAL;494494-495495- /* Add 1 to convert retry count to try count */496496- if (vwrq->flags & IW_RETRY_SHORT)497497- slimit = (u16) (vwrq->value + 1);498498- else if (vwrq->flags & IW_RETRY_LONG)499499- llimit = (u16) (vwrq->value + 1);500500- else501501- slimit = llimit = (u16) (vwrq->value + 1); /* set both */502502-503503- if (llimit) {504504- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT,505505- llimit);506506- if (ret)507507- goto out;508508- }509509-510510- if (slimit) {511511- /* txretrycount follows the short retry limit */512512- priv->txretrycount = slimit;513513- ret = lbs_set_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT,514514- slimit);515515- if (ret)516516- goto out;517517- }518518-519519-out:520520- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);521521- return ret;522522-}523523-524524-static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,525525- struct iw_param *vwrq, char *extra)526526-{527527- struct lbs_private *priv = dev->ml_priv;528528- int ret = 0;529529- u16 val = 0;530530-531531- lbs_deb_enter(LBS_DEB_WEXT);532532-533533- vwrq->disabled = 0;534534-535535- if (vwrq->flags & IW_RETRY_LONG) {536536- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_LONG_RETRY_LIMIT, &val);537537- if (ret)538538- goto out;539539-540540- /* Subtract 1 to convert try count to retry count */541541- vwrq->value = val - 1;542542- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;543543- } else {544544- ret = lbs_get_snmp_mib(priv, SNMP_MIB_OID_SHORT_RETRY_LIMIT, &val);545545- if (ret)546546- goto out;547547-548548- /* txretry count follows the short retry limit */549549- priv->txretrycount = val;550550- /* Subtract 1 to convert try count to retry count */551551- vwrq->value = val - 1;552552- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;553553- }554554-555555-out:556556- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);557557- return ret;558558-}559559-560560-static inline void sort_channels(struct iw_freq *freq, int num)561561-{562562- int i, j;563563- struct iw_freq temp;564564-565565- for (i = 0; i < num; i++)566566- for (j = i + 1; j < num; j++)567567- if (freq[i].i > freq[j].i) {568568- temp.i = freq[i].i;569569- temp.m = freq[i].m;570570-571571- freq[i].i = freq[j].i;572572- freq[i].m = freq[j].m;573573-574574- freq[j].i = temp.i;575575- freq[j].m = temp.m;576576- }577577-}578578-579579-/* data rate listing580580- MULTI_BANDS:581581- abg a b b/g582582- Infra G(12) A(8) B(4) G(12)583583- Adhoc A+B(12) A(8) B(4) B(4)584584-585585- non-MULTI_BANDS:586586- b b/g587587- Infra B(4) G(12)588588- Adhoc B(4) B(4)589589- */590590-/**591591- * @brief Get Range Info592592- *593593- * @param dev A pointer to net_device structure594594- * @param info A pointer to iw_request_info structure595595- * @param vwrq A pointer to iw_param structure596596- * @param extra A pointer to extra data buf597597- * @return 0 --success, otherwise fail598598- */599599-static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,600600- struct iw_point *dwrq, char *extra)601601-{602602- int i, j;603603- struct lbs_private *priv = dev->ml_priv;604604- struct iw_range *range = (struct iw_range *)extra;605605- struct chan_freq_power *cfp;606606- u8 rates[MAX_RATES + 1];607607-608608- lbs_deb_enter(LBS_DEB_WEXT);609609-610610- dwrq->length = sizeof(struct iw_range);611611- memset(range, 0, sizeof(struct iw_range));612612-613613- range->min_nwid = 0;614614- range->max_nwid = 0;615615-616616- memset(rates, 0, sizeof(rates));617617- copy_active_data_rates(priv, rates);618618- range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);619619- for (i = 0; i < range->num_bitrates; i++)620620- range->bitrate[i] = rates[i] * 500000;621621- range->num_bitrates = i;622622- lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,623623- range->num_bitrates);624624-625625- range->num_frequency = 0;626626-627627- range->scan_capa = IW_SCAN_CAPA_ESSID;628628-629629- for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES)630630- && (j < ARRAY_SIZE(priv->region_channel)); j++) {631631- cfp = priv->region_channel[j].CFP;632632- for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES)633633- && priv->region_channel[j].valid634634- && cfp635635- && (i < priv->region_channel[j].nrcfp); i++) {636636- range->freq[range->num_frequency].i =637637- (long)cfp->channel;638638- range->freq[range->num_frequency].m =639639- (long)cfp->freq * 100000;640640- range->freq[range->num_frequency].e = 1;641641- cfp++;642642- range->num_frequency++;643643- }644644- }645645-646646- lbs_deb_wext("IW_MAX_FREQUENCIES %d, num_frequency %d\n",647647- IW_MAX_FREQUENCIES, range->num_frequency);648648-649649- range->num_channels = range->num_frequency;650650-651651- sort_channels(&range->freq[0], range->num_frequency);652652-653653- /*654654- * Set an indication of the max TCP throughput in bit/s that we can655655- * expect using this interface656656- */657657- if (i > 2)658658- range->throughput = 5000 * 1000;659659- else660660- range->throughput = 1500 * 1000;661661-662662- range->min_rts = MRVDRV_RTS_MIN_VALUE;663663- range->max_rts = MRVDRV_RTS_MAX_VALUE;664664- range->min_frag = MRVDRV_FRAG_MIN_VALUE;665665- range->max_frag = MRVDRV_FRAG_MAX_VALUE;666666-667667- range->encoding_size[0] = 5;668668- range->encoding_size[1] = 13;669669- range->num_encoding_sizes = 2;670670- range->max_encoding_tokens = 4;671671-672672- /*673673- * Right now we support only "iwconfig ethX power on|off"674674- */675675- range->pm_capa = IW_POWER_ON;676676-677677- /*678678- * Minimum version we recommend679679- */680680- range->we_version_source = 15;681681-682682- /*683683- * Version we are compiled with684684- */685685- range->we_version_compiled = WIRELESS_EXT;686686-687687- range->retry_capa = IW_RETRY_LIMIT;688688- range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;689689-690690- range->min_retry = TX_RETRY_MIN;691691- range->max_retry = TX_RETRY_MAX;692692-693693- /*694694- * Set the qual, level and noise range values695695- */696696- range->max_qual.qual = 100;697697- range->max_qual.level = 0;698698- range->max_qual.noise = 0;699699- range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;700700-701701- range->avg_qual.qual = 70;702702- /* TODO: Find real 'good' to 'bad' threshold value for RSSI */703703- range->avg_qual.level = 0;704704- range->avg_qual.noise = 0;705705- range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;706706-707707- range->sensitivity = 0;708708-709709- /* Setup the supported power level ranges */710710- memset(range->txpower, 0, sizeof(range->txpower));711711- range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE;712712- range->txpower[0] = priv->txpower_min;713713- range->txpower[1] = priv->txpower_max;714714- range->num_txpower = 2;715715-716716- range->event_capa[0] = (IW_EVENT_CAPA_K_0 |717717- IW_EVENT_CAPA_MASK(SIOCGIWAP) |718718- IW_EVENT_CAPA_MASK(SIOCGIWSCAN));719719- range->event_capa[1] = IW_EVENT_CAPA_K_1;720720-721721- if (priv->fwcapinfo & FW_CAPINFO_WPA) {722722- range->enc_capa = IW_ENC_CAPA_WPA723723- | IW_ENC_CAPA_WPA2724724- | IW_ENC_CAPA_CIPHER_TKIP725725- | IW_ENC_CAPA_CIPHER_CCMP;726726- }727727-728728- lbs_deb_leave(LBS_DEB_WEXT);729729- return 0;730730-}731731-732732-static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,733733- struct iw_param *vwrq, char *extra)734734-{735735- struct lbs_private *priv = dev->ml_priv;736736- int ret = 0;737737-738738- lbs_deb_enter(LBS_DEB_WEXT);739739-740740- if (!(priv->fwcapinfo & FW_CAPINFO_PS)) {741741- if (vwrq->disabled)742742- return 0;743743- else744744- return -EINVAL;745745- }746746-747747- /* PS is currently supported only in Infrastructure mode748748- * Remove this check if it is to be supported in IBSS mode also749749- */750750-751751- if (vwrq->disabled) {752752- priv->psmode = LBS802_11POWERMODECAM;753753- if (priv->psstate != PS_STATE_FULL_POWER) {754754- lbs_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);755755- }756756-757757- return 0;758758- }759759-760760- if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) {761761- lbs_deb_wext(762762- "setting power timeout is not supported\n");763763- return -EINVAL;764764- } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) {765765- vwrq->value = vwrq->value / 1000;766766- if (!priv->enter_deep_sleep) {767767- lbs_pr_err("deep sleep feature is not implemented "768768- "for this interface driver\n");769769- return -EINVAL;770770- }771771-772772- if (priv->connect_status == LBS_CONNECTED) {773773- if ((priv->is_auto_deep_sleep_enabled) &&774774- (vwrq->value == -1000)) {775775- lbs_exit_auto_deep_sleep(priv);776776- return 0;777777- } else {778778- lbs_pr_err("can't use deep sleep cmd in "779779- "connected state\n");780780- return -EINVAL;781781- }782782- }783783-784784- if ((vwrq->value < 0) && (vwrq->value != -1000)) {785785- lbs_pr_err("unknown option\n");786786- return -EINVAL;787787- }788788-789789- if (vwrq->value > 0) {790790- if (!priv->is_auto_deep_sleep_enabled) {791791- priv->is_activity_detected = 0;792792- priv->auto_deep_sleep_timeout = vwrq->value;793793- lbs_enter_auto_deep_sleep(priv);794794- } else {795795- priv->auto_deep_sleep_timeout = vwrq->value;796796- lbs_deb_debugfs("auto deep sleep: "797797- "already enabled\n");798798- }799799- return 0;800800- } else {801801- if (priv->is_auto_deep_sleep_enabled) {802802- lbs_exit_auto_deep_sleep(priv);803803- /* Try to exit deep sleep if auto */804804- /*deep sleep disabled */805805- ret = lbs_set_deep_sleep(priv, 0);806806- }807807- if (vwrq->value == 0)808808- ret = lbs_set_deep_sleep(priv, 1);809809- else if (vwrq->value == -1000)810810- ret = lbs_set_deep_sleep(priv, 0);811811- return ret;812812- }813813- }814814-815815- if (priv->psmode != LBS802_11POWERMODECAM) {816816- return 0;817817- }818818-819819- priv->psmode = LBS802_11POWERMODEMAX_PSP;820820-821821- if (priv->connect_status == LBS_CONNECTED) {822822- lbs_ps_sleep(priv, CMD_OPTION_WAITFORRSP);823823- }824824-825825- lbs_deb_leave(LBS_DEB_WEXT);826826-827827- return 0;828828-}829829-830830-static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,831831- struct iw_param *vwrq, char *extra)832832-{833833- struct lbs_private *priv = dev->ml_priv;834834-835835- lbs_deb_enter(LBS_DEB_WEXT);836836-837837- vwrq->value = 0;838838- vwrq->flags = 0;839839- vwrq->disabled = priv->psmode == LBS802_11POWERMODECAM840840- || priv->connect_status == LBS_DISCONNECTED;841841-842842- lbs_deb_leave(LBS_DEB_WEXT);843843- return 0;844844-}845845-846846-static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)847847-{848848- enum {849849- POOR = 30,850850- FAIR = 60,851851- GOOD = 80,852852- VERY_GOOD = 90,853853- EXCELLENT = 95,854854- PERFECT = 100855855- };856856- struct lbs_private *priv = dev->ml_priv;857857- u32 rssi_qual;858858- u32 tx_qual;859859- u32 quality = 0;860860- int ret, stats_valid = 0;861861- u8 rssi;862862- u32 tx_retries;863863- struct cmd_ds_802_11_get_log log;864864-865865- lbs_deb_enter(LBS_DEB_WEXT);866866-867867- priv->wstats.status = priv->mode;868868-869869- /* If we're not associated, all quality values are meaningless */870870- if ((priv->connect_status != LBS_CONNECTED) &&871871- !lbs_mesh_connected(priv))872872- goto out;873873-874874- /* Quality by RSSI */875875- priv->wstats.qual.level =876876- CAL_RSSI(priv->SNR[TYPE_BEACON][TYPE_NOAVG],877877- priv->NF[TYPE_BEACON][TYPE_NOAVG]);878878-879879- if (priv->NF[TYPE_BEACON][TYPE_NOAVG] == 0) {880880- priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE;881881- } else {882882- priv->wstats.qual.noise =883883- CAL_NF(priv->NF[TYPE_BEACON][TYPE_NOAVG]);884884- }885885-886886- lbs_deb_wext("signal level %#x\n", priv->wstats.qual.level);887887- lbs_deb_wext("noise %#x\n", priv->wstats.qual.noise);888888-889889- rssi = priv->wstats.qual.level - priv->wstats.qual.noise;890890- if (rssi < 15)891891- rssi_qual = rssi * POOR / 10;892892- else if (rssi < 20)893893- rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR;894894- else if (rssi < 30)895895- rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR;896896- else if (rssi < 40)897897- rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) /898898- 10 + GOOD;899899- else900900- rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) /901901- 10 + VERY_GOOD;902902- quality = rssi_qual;903903-904904- /* Quality by TX errors */905905- priv->wstats.discard.retries = dev->stats.tx_errors;906906-907907- memset(&log, 0, sizeof(log));908908- log.hdr.size = cpu_to_le16(sizeof(log));909909- ret = lbs_cmd_with_response(priv, CMD_802_11_GET_LOG, &log);910910- if (ret)911911- goto out;912912-913913- tx_retries = le32_to_cpu(log.retry);914914-915915- if (tx_retries > 75)916916- tx_qual = (90 - tx_retries) * POOR / 15;917917- else if (tx_retries > 70)918918- tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR;919919- else if (tx_retries > 65)920920- tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR;921921- else if (tx_retries > 50)922922- tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) /923923- 15 + GOOD;924924- else925925- tx_qual = (50 - tx_retries) *926926- (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;927927- quality = min(quality, tx_qual);928928-929929- priv->wstats.discard.code = le32_to_cpu(log.wepundecryptable);930930- priv->wstats.discard.retries = tx_retries;931931- priv->wstats.discard.misc = le32_to_cpu(log.ackfailure);932932-933933- /* Calculate quality */934934- priv->wstats.qual.qual = min_t(u8, quality, 100);935935- priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;936936- stats_valid = 1;937937-938938- /* update stats asynchronously for future calls */939939- ret = lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,940940- 0, 0, NULL);941941- if (ret)942942- lbs_pr_err("RSSI command failed\n");943943-out:944944- if (!stats_valid) {945945- priv->wstats.miss.beacon = 0;946946- priv->wstats.discard.retries = 0;947947- priv->wstats.qual.qual = 0;948948- priv->wstats.qual.level = 0;949949- priv->wstats.qual.noise = 0;950950- priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED;951951- priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID |952952- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;953953- }954954-955955- lbs_deb_leave(LBS_DEB_WEXT);956956- return &priv->wstats;957957-958958-959959-}960960-961961-static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,962962- struct iw_freq *fwrq, char *extra)963963-{964964- int ret = -EINVAL;965965- struct lbs_private *priv = dev->ml_priv;966966- struct chan_freq_power *cfp;967967- struct assoc_request * assoc_req;968968-969969- lbs_deb_enter(LBS_DEB_WEXT);970970-971971- mutex_lock(&priv->lock);972972- assoc_req = lbs_get_association_request(priv);973973- if (!assoc_req) {974974- ret = -ENOMEM;975975- goto out;976976- }977977-978978- /* If setting by frequency, convert to a channel */979979- if (fwrq->e == 1) {980980- long f = fwrq->m / 100000;981981-982982- cfp = find_cfp_by_band_and_freq(priv, 0, f);983983- if (!cfp) {984984- lbs_deb_wext("invalid freq %ld\n", f);985985- goto out;986986- }987987-988988- fwrq->e = 0;989989- fwrq->m = (int) cfp->channel;990990- }991991-992992- /* Setting by channel number */993993- if (fwrq->m > 1000 || fwrq->e > 0) {994994- goto out;995995- }996996-997997- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);998998- if (!cfp) {999999- goto out;10001000- }10011001-10021002- assoc_req->channel = fwrq->m;10031003- ret = 0;10041004-10051005-out:10061006- if (ret == 0) {10071007- set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);10081008- lbs_postpone_association_work(priv);10091009- } else {10101010- lbs_cancel_association_work(priv);10111011- }10121012- mutex_unlock(&priv->lock);10131013-10141014- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);10151015- return ret;10161016-}10171017-10181018-#ifdef CONFIG_LIBERTAS_MESH10191019-static int lbs_mesh_set_freq(struct net_device *dev,10201020- struct iw_request_info *info,10211021- struct iw_freq *fwrq, char *extra)10221022-{10231023- struct lbs_private *priv = dev->ml_priv;10241024- struct chan_freq_power *cfp;10251025- int ret = -EINVAL;10261026-10271027- lbs_deb_enter(LBS_DEB_WEXT);10281028-10291029- /* If setting by frequency, convert to a channel */10301030- if (fwrq->e == 1) {10311031- long f = fwrq->m / 100000;10321032-10331033- cfp = find_cfp_by_band_and_freq(priv, 0, f);10341034- if (!cfp) {10351035- lbs_deb_wext("invalid freq %ld\n", f);10361036- goto out;10371037- }10381038-10391039- fwrq->e = 0;10401040- fwrq->m = (int) cfp->channel;10411041- }10421042-10431043- /* Setting by channel number */10441044- if (fwrq->m > 1000 || fwrq->e > 0) {10451045- goto out;10461046- }10471047-10481048- cfp = lbs_find_cfp_by_band_and_channel(priv, 0, fwrq->m);10491049- if (!cfp) {10501050- goto out;10511051- }10521052-10531053- if (fwrq->m != priv->channel) {10541054- lbs_deb_wext("mesh channel change forces eth disconnect\n");10551055- if (priv->mode == IW_MODE_INFRA)10561056- lbs_cmd_80211_deauthenticate(priv,10571057- priv->curbssparams.bssid,10581058- WLAN_REASON_DEAUTH_LEAVING);10591059- else if (priv->mode == IW_MODE_ADHOC)10601060- lbs_adhoc_stop(priv);10611061- }10621062- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START, fwrq->m);10631063- lbs_update_channel(priv);10641064- ret = 0;10651065-10661066-out:10671067- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);10681068- return ret;10691069-}10701070-#endif10711071-10721072-static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,10731073- struct iw_param *vwrq, char *extra)10741074-{10751075- struct lbs_private *priv = dev->ml_priv;10761076- u8 new_rate = 0;10771077- int ret = -EINVAL;10781078- u8 rates[MAX_RATES + 1];10791079-10801080- lbs_deb_enter(LBS_DEB_WEXT);10811081-10821082- lbs_deb_wext("vwrq->value %d\n", vwrq->value);10831083- lbs_deb_wext("vwrq->fixed %d\n", vwrq->fixed);10841084-10851085- if (vwrq->fixed && vwrq->value == -1)10861086- goto out;10871087-10881088- /* Auto rate? */10891089- priv->enablehwauto = !vwrq->fixed;10901090-10911091- if (vwrq->value == -1)10921092- priv->cur_rate = 0;10931093- else {10941094- if (vwrq->value % 100000)10951095- goto out;10961096-10971097- new_rate = vwrq->value / 500000;10981098- priv->cur_rate = new_rate;10991099- /* the rest is only needed for lbs_set_data_rate() */11001100- memset(rates, 0, sizeof(rates));11011101- copy_active_data_rates(priv, rates);11021102- if (!memchr(rates, new_rate, sizeof(rates))) {11031103- lbs_pr_alert("fixed data rate 0x%X out of range\n",11041104- new_rate);11051105- goto out;11061106- }11071107- if (priv->fwrelease < 0x09000000) {11081108- ret = lbs_set_power_adapt_cfg(priv, 0,11091109- POW_ADAPT_DEFAULT_P0,11101110- POW_ADAPT_DEFAULT_P1,11111111- POW_ADAPT_DEFAULT_P2);11121112- if (ret)11131113- goto out;11141114- }11151115- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,11161116- TPC_DEFAULT_P2, 1);11171117- if (ret)11181118- goto out;11191119- }11201120-11211121- /* Try the newer command first (Firmware Spec 5.1 and above) */11221122- ret = lbs_cmd_802_11_rate_adapt_rateset(priv, CMD_ACT_SET);11231123-11241124- /* Fallback to older version */11251125- if (ret)11261126- ret = lbs_set_data_rate(priv, new_rate);11271127-11281128-out:11291129- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);11301130- return ret;11311131-}11321132-11331133-static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,11341134- struct iw_param *vwrq, char *extra)11351135-{11361136- struct lbs_private *priv = dev->ml_priv;11371137-11381138- lbs_deb_enter(LBS_DEB_WEXT);11391139-11401140- if (priv->connect_status == LBS_CONNECTED) {11411141- vwrq->value = priv->cur_rate * 500000;11421142-11431143- if (priv->enablehwauto)11441144- vwrq->fixed = 0;11451145- else11461146- vwrq->fixed = 1;11471147-11481148- } else {11491149- vwrq->fixed = 0;11501150- vwrq->value = 0;11511151- }11521152-11531153- lbs_deb_leave(LBS_DEB_WEXT);11541154- return 0;11551155-}11561156-11571157-static int lbs_set_mode(struct net_device *dev,11581158- struct iw_request_info *info, u32 * uwrq, char *extra)11591159-{11601160- int ret = 0;11611161- struct lbs_private *priv = dev->ml_priv;11621162- struct assoc_request * assoc_req;11631163-11641164- lbs_deb_enter(LBS_DEB_WEXT);11651165-11661166- if ( (*uwrq != IW_MODE_ADHOC)11671167- && (*uwrq != IW_MODE_INFRA)11681168- && (*uwrq != IW_MODE_AUTO)) {11691169- lbs_deb_wext("Invalid mode: 0x%x\n", *uwrq);11701170- ret = -EINVAL;11711171- goto out;11721172- }11731173-11741174- mutex_lock(&priv->lock);11751175- assoc_req = lbs_get_association_request(priv);11761176- if (!assoc_req) {11771177- ret = -ENOMEM;11781178- lbs_cancel_association_work(priv);11791179- } else {11801180- assoc_req->mode = *uwrq;11811181- set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);11821182- lbs_postpone_association_work(priv);11831183- lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);11841184- }11851185- mutex_unlock(&priv->lock);11861186-11871187-out:11881188- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);11891189- return ret;11901190-}11911191-11921192-11931193-/**11941194- * @brief Get Encryption key11951195- *11961196- * @param dev A pointer to net_device structure11971197- * @param info A pointer to iw_request_info structure11981198- * @param vwrq A pointer to iw_param structure11991199- * @param extra A pointer to extra data buf12001200- * @return 0 --success, otherwise fail12011201- */12021202-static int lbs_get_encode(struct net_device *dev,12031203- struct iw_request_info *info,12041204- struct iw_point *dwrq, u8 * extra)12051205-{12061206- struct lbs_private *priv = dev->ml_priv;12071207- int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;12081208-12091209- lbs_deb_enter(LBS_DEB_WEXT);12101210-12111211- lbs_deb_wext("flags 0x%x, index %d, length %d, wep_tx_keyidx %d\n",12121212- dwrq->flags, index, dwrq->length, priv->wep_tx_keyidx);12131213-12141214- dwrq->flags = 0;12151215-12161216- /* Authentication method */12171217- switch (priv->secinfo.auth_mode) {12181218- case IW_AUTH_ALG_OPEN_SYSTEM:12191219- dwrq->flags = IW_ENCODE_OPEN;12201220- break;12211221-12221222- case IW_AUTH_ALG_SHARED_KEY:12231223- case IW_AUTH_ALG_LEAP:12241224- dwrq->flags = IW_ENCODE_RESTRICTED;12251225- break;12261226- default:12271227- dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;12281228- break;12291229- }12301230-12311231- memset(extra, 0, 16);12321232-12331233- mutex_lock(&priv->lock);12341234-12351235- /* Default to returning current transmit key */12361236- if (index < 0)12371237- index = priv->wep_tx_keyidx;12381238-12391239- if ((priv->wep_keys[index].len) && priv->secinfo.wep_enabled) {12401240- memcpy(extra, priv->wep_keys[index].key,12411241- priv->wep_keys[index].len);12421242- dwrq->length = priv->wep_keys[index].len;12431243-12441244- dwrq->flags |= (index + 1);12451245- /* Return WEP enabled */12461246- dwrq->flags &= ~IW_ENCODE_DISABLED;12471247- } else if ((priv->secinfo.WPAenabled)12481248- || (priv->secinfo.WPA2enabled)) {12491249- /* return WPA enabled */12501250- dwrq->flags &= ~IW_ENCODE_DISABLED;12511251- dwrq->flags |= IW_ENCODE_NOKEY;12521252- } else {12531253- dwrq->flags |= IW_ENCODE_DISABLED;12541254- }12551255-12561256- mutex_unlock(&priv->lock);12571257-12581258- lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",12591259- extra[0], extra[1], extra[2],12601260- extra[3], extra[4], extra[5], dwrq->length);12611261-12621262- lbs_deb_wext("return flags 0x%x\n", dwrq->flags);12631263-12641264- lbs_deb_leave(LBS_DEB_WEXT);12651265- return 0;12661266-}12671267-12681268-/**12691269- * @brief Set Encryption key (internal)12701270- *12711271- * @param priv A pointer to private card structure12721272- * @param key_material A pointer to key material12731273- * @param key_length length of key material12741274- * @param index key index to set12751275- * @param set_tx_key Force set TX key (1 = yes, 0 = no)12761276- * @return 0 --success, otherwise fail12771277- */12781278-static int lbs_set_wep_key(struct assoc_request *assoc_req,12791279- const char *key_material,12801280- u16 key_length,12811281- u16 index,12821282- int set_tx_key)12831283-{12841284- int ret = 0;12851285- struct enc_key *pkey;12861286-12871287- lbs_deb_enter(LBS_DEB_WEXT);12881288-12891289- /* Paranoid validation of key index */12901290- if (index > 3) {12911291- ret = -EINVAL;12921292- goto out;12931293- }12941294-12951295- /* validate max key length */12961296- if (key_length > KEY_LEN_WEP_104) {12971297- ret = -EINVAL;12981298- goto out;12991299- }13001300-13011301- pkey = &assoc_req->wep_keys[index];13021302-13031303- if (key_length > 0) {13041304- memset(pkey, 0, sizeof(struct enc_key));13051305- pkey->type = KEY_TYPE_ID_WEP;13061306-13071307- /* Standardize the key length */13081308- pkey->len = (key_length > KEY_LEN_WEP_40) ?13091309- KEY_LEN_WEP_104 : KEY_LEN_WEP_40;13101310- memcpy(pkey->key, key_material, key_length);13111311- }13121312-13131313- if (set_tx_key) {13141314- /* Ensure the chosen key is valid */13151315- if (!pkey->len) {13161316- lbs_deb_wext("key not set, so cannot enable it\n");13171317- ret = -EINVAL;13181318- goto out;13191319- }13201320- assoc_req->wep_tx_keyidx = index;13211321- }13221322-13231323- assoc_req->secinfo.wep_enabled = 1;13241324-13251325-out:13261326- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);13271327- return ret;13281328-}13291329-13301330-static int validate_key_index(u16 def_index, u16 raw_index,13311331- u16 *out_index, u16 *is_default)13321332-{13331333- if (!out_index || !is_default)13341334- return -EINVAL;13351335-13361336- /* Verify index if present, otherwise use default TX key index */13371337- if (raw_index > 0) {13381338- if (raw_index > 4)13391339- return -EINVAL;13401340- *out_index = raw_index - 1;13411341- } else {13421342- *out_index = def_index;13431343- *is_default = 1;13441344- }13451345- return 0;13461346-}13471347-13481348-static void disable_wep(struct assoc_request *assoc_req)13491349-{13501350- int i;13511351-13521352- lbs_deb_enter(LBS_DEB_WEXT);13531353-13541354- /* Set Open System auth mode */13551355- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;13561356-13571357- /* Clear WEP keys and mark WEP as disabled */13581358- assoc_req->secinfo.wep_enabled = 0;13591359- for (i = 0; i < 4; i++)13601360- assoc_req->wep_keys[i].len = 0;13611361-13621362- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);13631363- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);13641364-13651365- lbs_deb_leave(LBS_DEB_WEXT);13661366-}13671367-13681368-static void disable_wpa(struct assoc_request *assoc_req)13691369-{13701370- lbs_deb_enter(LBS_DEB_WEXT);13711371-13721372- memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));13731373- assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;13741374- set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);13751375-13761376- memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));13771377- assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;13781378- set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);13791379-13801380- assoc_req->secinfo.WPAenabled = 0;13811381- assoc_req->secinfo.WPA2enabled = 0;13821382- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);13831383-13841384- lbs_deb_leave(LBS_DEB_WEXT);13851385-}13861386-13871387-/**13881388- * @brief Set Encryption key13891389- *13901390- * @param dev A pointer to net_device structure13911391- * @param info A pointer to iw_request_info structure13921392- * @param vwrq A pointer to iw_param structure13931393- * @param extra A pointer to extra data buf13941394- * @return 0 --success, otherwise fail13951395- */13961396-static int lbs_set_encode(struct net_device *dev,13971397- struct iw_request_info *info,13981398- struct iw_point *dwrq, char *extra)13991399-{14001400- int ret = 0;14011401- struct lbs_private *priv = dev->ml_priv;14021402- struct assoc_request * assoc_req;14031403- u16 is_default = 0, index = 0, set_tx_key = 0;14041404-14051405- lbs_deb_enter(LBS_DEB_WEXT);14061406-14071407- mutex_lock(&priv->lock);14081408- assoc_req = lbs_get_association_request(priv);14091409- if (!assoc_req) {14101410- ret = -ENOMEM;14111411- goto out;14121412- }14131413-14141414- if (dwrq->flags & IW_ENCODE_DISABLED) {14151415- disable_wep (assoc_req);14161416- disable_wpa (assoc_req);14171417- goto out;14181418- }14191419-14201420- ret = validate_key_index(assoc_req->wep_tx_keyidx,14211421- (dwrq->flags & IW_ENCODE_INDEX),14221422- &index, &is_default);14231423- if (ret) {14241424- ret = -EINVAL;14251425- goto out;14261426- }14271427-14281428- /* If WEP isn't enabled, or if there is no key data but a valid14291429- * index, set the TX key.14301430- */14311431- if (!assoc_req->secinfo.wep_enabled || (dwrq->length == 0 && !is_default))14321432- set_tx_key = 1;14331433-14341434- ret = lbs_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key);14351435- if (ret)14361436- goto out;14371437-14381438- if (dwrq->length)14391439- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);14401440- if (set_tx_key)14411441- set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);14421442-14431443- if (dwrq->flags & IW_ENCODE_RESTRICTED) {14441444- priv->authtype_auto = 0;14451445- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;14461446- } else if (dwrq->flags & IW_ENCODE_OPEN) {14471447- priv->authtype_auto = 0;14481448- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;14491449- }14501450-14511451-out:14521452- if (ret == 0) {14531453- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);14541454- lbs_postpone_association_work(priv);14551455- } else {14561456- lbs_cancel_association_work(priv);14571457- }14581458- mutex_unlock(&priv->lock);14591459-14601460- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);14611461- return ret;14621462-}14631463-14641464-/**14651465- * @brief Get Extended Encryption key (WPA/802.1x and WEP)14661466- *14671467- * @param dev A pointer to net_device structure14681468- * @param info A pointer to iw_request_info structure14691469- * @param vwrq A pointer to iw_param structure14701470- * @param extra A pointer to extra data buf14711471- * @return 0 on success, otherwise failure14721472- */14731473-static int lbs_get_encodeext(struct net_device *dev,14741474- struct iw_request_info *info,14751475- struct iw_point *dwrq,14761476- char *extra)14771477-{14781478- int ret = -EINVAL;14791479- struct lbs_private *priv = dev->ml_priv;14801480- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;14811481- int index, max_key_len;14821482-14831483- lbs_deb_enter(LBS_DEB_WEXT);14841484-14851485- max_key_len = dwrq->length - sizeof(*ext);14861486- if (max_key_len < 0)14871487- goto out;14881488-14891489- index = dwrq->flags & IW_ENCODE_INDEX;14901490- if (index) {14911491- if (index < 1 || index > 4)14921492- goto out;14931493- index--;14941494- } else {14951495- index = priv->wep_tx_keyidx;14961496- }14971497-14981498- if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&14991499- ext->alg != IW_ENCODE_ALG_WEP) {15001500- if (index != 0 || priv->mode != IW_MODE_INFRA)15011501- goto out;15021502- }15031503-15041504- dwrq->flags = index + 1;15051505- memset(ext, 0, sizeof(*ext));15061506-15071507- if ( !priv->secinfo.wep_enabled15081508- && !priv->secinfo.WPAenabled15091509- && !priv->secinfo.WPA2enabled) {15101510- ext->alg = IW_ENCODE_ALG_NONE;15111511- ext->key_len = 0;15121512- dwrq->flags |= IW_ENCODE_DISABLED;15131513- } else {15141514- u8 *key = NULL;15151515-15161516- if ( priv->secinfo.wep_enabled15171517- && !priv->secinfo.WPAenabled15181518- && !priv->secinfo.WPA2enabled) {15191519- /* WEP */15201520- ext->alg = IW_ENCODE_ALG_WEP;15211521- ext->key_len = priv->wep_keys[index].len;15221522- key = &priv->wep_keys[index].key[0];15231523- } else if ( !priv->secinfo.wep_enabled15241524- && (priv->secinfo.WPAenabled ||15251525- priv->secinfo.WPA2enabled)) {15261526- /* WPA */15271527- struct enc_key * pkey = NULL;15281528-15291529- if ( priv->wpa_mcast_key.len15301530- && (priv->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))15311531- pkey = &priv->wpa_mcast_key;15321532- else if ( priv->wpa_unicast_key.len15331533- && (priv->wpa_unicast_key.flags & KEY_INFO_WPA_ENABLED))15341534- pkey = &priv->wpa_unicast_key;15351535-15361536- if (pkey) {15371537- if (pkey->type == KEY_TYPE_ID_AES) {15381538- ext->alg = IW_ENCODE_ALG_CCMP;15391539- } else {15401540- ext->alg = IW_ENCODE_ALG_TKIP;15411541- }15421542- ext->key_len = pkey->len;15431543- key = &pkey->key[0];15441544- } else {15451545- ext->alg = IW_ENCODE_ALG_TKIP;15461546- ext->key_len = 0;15471547- }15481548- } else {15491549- goto out;15501550- }15511551-15521552- if (ext->key_len > max_key_len) {15531553- ret = -E2BIG;15541554- goto out;15551555- }15561556-15571557- if (ext->key_len)15581558- memcpy(ext->key, key, ext->key_len);15591559- else15601560- dwrq->flags |= IW_ENCODE_NOKEY;15611561- dwrq->flags |= IW_ENCODE_ENABLED;15621562- }15631563- ret = 0;15641564-15651565-out:15661566- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);15671567- return ret;15681568-}15691569-15701570-/**15711571- * @brief Set Encryption key Extended (WPA/802.1x and WEP)15721572- *15731573- * @param dev A pointer to net_device structure15741574- * @param info A pointer to iw_request_info structure15751575- * @param vwrq A pointer to iw_param structure15761576- * @param extra A pointer to extra data buf15771577- * @return 0 --success, otherwise fail15781578- */15791579-static int lbs_set_encodeext(struct net_device *dev,15801580- struct iw_request_info *info,15811581- struct iw_point *dwrq,15821582- char *extra)15831583-{15841584- int ret = 0;15851585- struct lbs_private *priv = dev->ml_priv;15861586- struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;15871587- int alg = ext->alg;15881588- struct assoc_request * assoc_req;15891589-15901590- lbs_deb_enter(LBS_DEB_WEXT);15911591-15921592- mutex_lock(&priv->lock);15931593- assoc_req = lbs_get_association_request(priv);15941594- if (!assoc_req) {15951595- ret = -ENOMEM;15961596- goto out;15971597- }15981598-15991599- if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) {16001600- disable_wep (assoc_req);16011601- disable_wpa (assoc_req);16021602- } else if (alg == IW_ENCODE_ALG_WEP) {16031603- u16 is_default = 0, index, set_tx_key = 0;16041604-16051605- ret = validate_key_index(assoc_req->wep_tx_keyidx,16061606- (dwrq->flags & IW_ENCODE_INDEX),16071607- &index, &is_default);16081608- if (ret)16091609- goto out;16101610-16111611- /* If WEP isn't enabled, or if there is no key data but a valid16121612- * index, or if the set-TX-key flag was passed, set the TX key.16131613- */16141614- if ( !assoc_req->secinfo.wep_enabled16151615- || (dwrq->length == 0 && !is_default)16161616- || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY))16171617- set_tx_key = 1;16181618-16191619- /* Copy key to driver */16201620- ret = lbs_set_wep_key(assoc_req, ext->key, ext->key_len, index,16211621- set_tx_key);16221622- if (ret)16231623- goto out;16241624-16251625- if (dwrq->flags & IW_ENCODE_RESTRICTED) {16261626- priv->authtype_auto = 0;16271627- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;16281628- } else if (dwrq->flags & IW_ENCODE_OPEN) {16291629- priv->authtype_auto = 0;16301630- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;16311631- }16321632-16331633- /* Mark the various WEP bits as modified */16341634- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);16351635- if (dwrq->length)16361636- set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags);16371637- if (set_tx_key)16381638- set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);16391639- } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {16401640- struct enc_key * pkey;16411641-16421642- /* validate key length */16431643- if (((alg == IW_ENCODE_ALG_TKIP)16441644- && (ext->key_len != KEY_LEN_WPA_TKIP))16451645- || ((alg == IW_ENCODE_ALG_CCMP)16461646- && (ext->key_len != KEY_LEN_WPA_AES))) {16471647- lbs_deb_wext("invalid size %d for key of alg "16481648- "type %d\n",16491649- ext->key_len,16501650- alg);16511651- ret = -EINVAL;16521652- goto out;16531653- }16541654-16551655- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {16561656- pkey = &assoc_req->wpa_mcast_key;16571657- set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);16581658- } else {16591659- pkey = &assoc_req->wpa_unicast_key;16601660- set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);16611661- }16621662-16631663- memset(pkey, 0, sizeof (struct enc_key));16641664- memcpy(pkey->key, ext->key, ext->key_len);16651665- pkey->len = ext->key_len;16661666- if (pkey->len)16671667- pkey->flags |= KEY_INFO_WPA_ENABLED;16681668-16691669- /* Do this after zeroing key structure */16701670- if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {16711671- pkey->flags |= KEY_INFO_WPA_MCAST;16721672- } else {16731673- pkey->flags |= KEY_INFO_WPA_UNICAST;16741674- }16751675-16761676- if (alg == IW_ENCODE_ALG_TKIP) {16771677- pkey->type = KEY_TYPE_ID_TKIP;16781678- } else if (alg == IW_ENCODE_ALG_CCMP) {16791679- pkey->type = KEY_TYPE_ID_AES;16801680- }16811681-16821682- /* If WPA isn't enabled yet, do that now */16831683- if ( assoc_req->secinfo.WPAenabled == 016841684- && assoc_req->secinfo.WPA2enabled == 0) {16851685- assoc_req->secinfo.WPAenabled = 1;16861686- assoc_req->secinfo.WPA2enabled = 1;16871687- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);16881688- }16891689-16901690- /* Only disable wep if necessary: can't waste time here. */16911691- if (priv->mac_control & CMD_ACT_MAC_WEP_ENABLE)16921692- disable_wep(assoc_req);16931693- }16941694-16951695-out:16961696- if (ret == 0) {16971697- /* 802.1x and WPA rekeying must happen as quickly as possible,16981698- * especially during the 4-way handshake; thus if in16991699- * infrastructure mode, and either (a) 802.1x is enabled or17001700- * (b) WPA is being used, set the key right away.17011701- */17021702- if (assoc_req->mode == IW_MODE_INFRA &&17031703- ((assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_802_1X) ||17041704- (assoc_req->secinfo.key_mgmt & IW_AUTH_KEY_MGMT_PSK) ||17051705- assoc_req->secinfo.WPAenabled ||17061706- assoc_req->secinfo.WPA2enabled)) {17071707- lbs_do_association_work(priv);17081708- } else17091709- lbs_postpone_association_work(priv);17101710- } else {17111711- lbs_cancel_association_work(priv);17121712- }17131713- mutex_unlock(&priv->lock);17141714-17151715- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);17161716- return ret;17171717-}17181718-17191719-17201720-static int lbs_set_genie(struct net_device *dev,17211721- struct iw_request_info *info,17221722- struct iw_point *dwrq,17231723- char *extra)17241724-{17251725- struct lbs_private *priv = dev->ml_priv;17261726- int ret = 0;17271727- struct assoc_request * assoc_req;17281728-17291729- lbs_deb_enter(LBS_DEB_WEXT);17301730-17311731- mutex_lock(&priv->lock);17321732- assoc_req = lbs_get_association_request(priv);17331733- if (!assoc_req) {17341734- ret = -ENOMEM;17351735- goto out;17361736- }17371737-17381738- if (dwrq->length > MAX_WPA_IE_LEN ||17391739- (dwrq->length && extra == NULL)) {17401740- ret = -EINVAL;17411741- goto out;17421742- }17431743-17441744- if (dwrq->length) {17451745- memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length);17461746- assoc_req->wpa_ie_len = dwrq->length;17471747- } else {17481748- memset(&assoc_req->wpa_ie[0], 0, sizeof(priv->wpa_ie));17491749- assoc_req->wpa_ie_len = 0;17501750- }17511751-17521752-out:17531753- if (ret == 0) {17541754- set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);17551755- lbs_postpone_association_work(priv);17561756- } else {17571757- lbs_cancel_association_work(priv);17581758- }17591759- mutex_unlock(&priv->lock);17601760-17611761- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);17621762- return ret;17631763-}17641764-17651765-static int lbs_get_genie(struct net_device *dev,17661766- struct iw_request_info *info,17671767- struct iw_point *dwrq,17681768- char *extra)17691769-{17701770- int ret = 0;17711771- struct lbs_private *priv = dev->ml_priv;17721772-17731773- lbs_deb_enter(LBS_DEB_WEXT);17741774-17751775- if (priv->wpa_ie_len == 0) {17761776- dwrq->length = 0;17771777- goto out;17781778- }17791779-17801780- if (dwrq->length < priv->wpa_ie_len) {17811781- ret = -E2BIG;17821782- goto out;17831783- }17841784-17851785- dwrq->length = priv->wpa_ie_len;17861786- memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len);17871787-17881788-out:17891789- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);17901790- return ret;17911791-}17921792-17931793-17941794-static int lbs_set_auth(struct net_device *dev,17951795- struct iw_request_info *info,17961796- struct iw_param *dwrq,17971797- char *extra)17981798-{17991799- struct lbs_private *priv = dev->ml_priv;18001800- struct assoc_request * assoc_req;18011801- int ret = 0;18021802- int updated = 0;18031803-18041804- lbs_deb_enter(LBS_DEB_WEXT);18051805-18061806- mutex_lock(&priv->lock);18071807- assoc_req = lbs_get_association_request(priv);18081808- if (!assoc_req) {18091809- ret = -ENOMEM;18101810- goto out;18111811- }18121812-18131813- switch (dwrq->flags & IW_AUTH_INDEX) {18141814- case IW_AUTH_PRIVACY_INVOKED:18151815- case IW_AUTH_RX_UNENCRYPTED_EAPOL:18161816- case IW_AUTH_TKIP_COUNTERMEASURES:18171817- case IW_AUTH_CIPHER_PAIRWISE:18181818- case IW_AUTH_CIPHER_GROUP:18191819- case IW_AUTH_DROP_UNENCRYPTED:18201820- /*18211821- * libertas does not use these parameters18221822- */18231823- break;18241824-18251825- case IW_AUTH_KEY_MGMT:18261826- assoc_req->secinfo.key_mgmt = dwrq->value;18271827- updated = 1;18281828- break;18291829-18301830- case IW_AUTH_WPA_VERSION:18311831- if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) {18321832- assoc_req->secinfo.WPAenabled = 0;18331833- assoc_req->secinfo.WPA2enabled = 0;18341834- disable_wpa (assoc_req);18351835- }18361836- if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) {18371837- assoc_req->secinfo.WPAenabled = 1;18381838- assoc_req->secinfo.wep_enabled = 0;18391839- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;18401840- }18411841- if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) {18421842- assoc_req->secinfo.WPA2enabled = 1;18431843- assoc_req->secinfo.wep_enabled = 0;18441844- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;18451845- }18461846- updated = 1;18471847- break;18481848-18491849- case IW_AUTH_80211_AUTH_ALG:18501850- if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) {18511851- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY;18521852- } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) {18531853- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;18541854- } else if (dwrq->value & IW_AUTH_ALG_LEAP) {18551855- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_LEAP;18561856- } else {18571857- ret = -EINVAL;18581858- }18591859- updated = 1;18601860- break;18611861-18621862- case IW_AUTH_WPA_ENABLED:18631863- if (dwrq->value) {18641864- if (!assoc_req->secinfo.WPAenabled &&18651865- !assoc_req->secinfo.WPA2enabled) {18661866- assoc_req->secinfo.WPAenabled = 1;18671867- assoc_req->secinfo.WPA2enabled = 1;18681868- assoc_req->secinfo.wep_enabled = 0;18691869- assoc_req->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;18701870- }18711871- } else {18721872- assoc_req->secinfo.WPAenabled = 0;18731873- assoc_req->secinfo.WPA2enabled = 0;18741874- disable_wpa (assoc_req);18751875- }18761876- updated = 1;18771877- break;18781878-18791879- default:18801880- ret = -EOPNOTSUPP;18811881- break;18821882- }18831883-18841884-out:18851885- if (ret == 0) {18861886- if (updated)18871887- set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);18881888- lbs_postpone_association_work(priv);18891889- } else if (ret != -EOPNOTSUPP) {18901890- lbs_cancel_association_work(priv);18911891- }18921892- mutex_unlock(&priv->lock);18931893-18941894- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);18951895- return ret;18961896-}18971897-18981898-static int lbs_get_auth(struct net_device *dev,18991899- struct iw_request_info *info,19001900- struct iw_param *dwrq,19011901- char *extra)19021902-{19031903- int ret = 0;19041904- struct lbs_private *priv = dev->ml_priv;19051905-19061906- lbs_deb_enter(LBS_DEB_WEXT);19071907-19081908- switch (dwrq->flags & IW_AUTH_INDEX) {19091909- case IW_AUTH_KEY_MGMT:19101910- dwrq->value = priv->secinfo.key_mgmt;19111911- break;19121912-19131913- case IW_AUTH_WPA_VERSION:19141914- dwrq->value = 0;19151915- if (priv->secinfo.WPAenabled)19161916- dwrq->value |= IW_AUTH_WPA_VERSION_WPA;19171917- if (priv->secinfo.WPA2enabled)19181918- dwrq->value |= IW_AUTH_WPA_VERSION_WPA2;19191919- if (!dwrq->value)19201920- dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED;19211921- break;19221922-19231923- case IW_AUTH_80211_AUTH_ALG:19241924- dwrq->value = priv->secinfo.auth_mode;19251925- break;19261926-19271927- case IW_AUTH_WPA_ENABLED:19281928- if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled)19291929- dwrq->value = 1;19301930- break;19311931-19321932- default:19331933- ret = -EOPNOTSUPP;19341934- }19351935-19361936- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);19371937- return ret;19381938-}19391939-19401940-19411941-static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,19421942- struct iw_param *vwrq, char *extra)19431943-{19441944- int ret = 0;19451945- struct lbs_private *priv = dev->ml_priv;19461946- s16 dbm = (s16) vwrq->value;19471947-19481948- lbs_deb_enter(LBS_DEB_WEXT);19491949-19501950- if (vwrq->disabled) {19511951- lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 0);19521952- goto out;19531953- }19541954-19551955- if (vwrq->fixed == 0) {19561956- /* User requests automatic tx power control, however there are19571957- * many auto tx settings. For now use firmware defaults until19581958- * we come up with a good way to expose these to the user. */19591959- if (priv->fwrelease < 0x09000000) {19601960- ret = lbs_set_power_adapt_cfg(priv, 1,19611961- POW_ADAPT_DEFAULT_P0,19621962- POW_ADAPT_DEFAULT_P1,19631963- POW_ADAPT_DEFAULT_P2);19641964- if (ret)19651965- goto out;19661966- }19671967- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,19681968- TPC_DEFAULT_P2, 1);19691969- if (ret)19701970- goto out;19711971- dbm = priv->txpower_max;19721972- } else {19731973- /* Userspace check in iwrange if it should use dBm or mW,19741974- * therefore this should never happen... Jean II */19751975- if ((vwrq->flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {19761976- ret = -EOPNOTSUPP;19771977- goto out;19781978- }19791979-19801980- /* Validate requested power level against firmware allowed19811981- * levels */19821982- if (priv->txpower_min && (dbm < priv->txpower_min)) {19831983- ret = -EINVAL;19841984- goto out;19851985- }19861986-19871987- if (priv->txpower_max && (dbm > priv->txpower_max)) {19881988- ret = -EINVAL;19891989- goto out;19901990- }19911991- if (priv->fwrelease < 0x09000000) {19921992- ret = lbs_set_power_adapt_cfg(priv, 0,19931993- POW_ADAPT_DEFAULT_P0,19941994- POW_ADAPT_DEFAULT_P1,19951995- POW_ADAPT_DEFAULT_P2);19961996- if (ret)19971997- goto out;19981998- }19991999- ret = lbs_set_tpc_cfg(priv, 0, TPC_DEFAULT_P0, TPC_DEFAULT_P1,20002000- TPC_DEFAULT_P2, 1);20012001- if (ret)20022002- goto out;20032003- }20042004-20052005- /* If the radio was off, turn it on */20062006- if (!priv->radio_on) {20072007- ret = lbs_set_radio(priv, RADIO_PREAMBLE_AUTO, 1);20082008- if (ret)20092009- goto out;20102010- }20112011-20122012- lbs_deb_wext("txpower set %d dBm\n", dbm);20132013-20142014- ret = lbs_set_tx_power(priv, dbm);20152015-20162016-out:20172017- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);20182018- return ret;20192019-}20202020-20212021-static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,20222022- struct iw_point *dwrq, char *extra)20232023-{20242024- struct lbs_private *priv = dev->ml_priv;20252025-20262026- lbs_deb_enter(LBS_DEB_WEXT);20272027-20282028- /*20292029- * Note : if dwrq->flags != 0, we should get the relevant SSID from20302030- * the SSID list...20312031- */20322032-20332033- /*20342034- * Get the current SSID20352035- */20362036- if (priv->connect_status == LBS_CONNECTED) {20372037- memcpy(extra, priv->curbssparams.ssid,20382038- priv->curbssparams.ssid_len);20392039- } else {20402040- memset(extra, 0, 32);20412041- }20422042- /*20432043- * If none, we may want to get the one that was set20442044- */20452045-20462046- dwrq->length = priv->curbssparams.ssid_len;20472047-20482048- dwrq->flags = 1; /* active */20492049-20502050- lbs_deb_leave(LBS_DEB_WEXT);20512051- return 0;20522052-}20532053-20542054-static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,20552055- struct iw_point *dwrq, char *extra)20562056-{20572057- struct lbs_private *priv = dev->ml_priv;20582058- int ret = 0;20592059- u8 ssid[IEEE80211_MAX_SSID_LEN];20602060- u8 ssid_len = 0;20612061- struct assoc_request * assoc_req;20622062- int in_ssid_len = dwrq->length;20632063- DECLARE_SSID_BUF(ssid_buf);20642064-20652065- lbs_deb_enter(LBS_DEB_WEXT);20662066-20672067- if (!priv->radio_on) {20682068- ret = -EINVAL;20692069- goto out;20702070- }20712071-20722072- /* Check the size of the string */20732073- if (in_ssid_len > IEEE80211_MAX_SSID_LEN) {20742074- ret = -E2BIG;20752075- goto out;20762076- }20772077-20782078- memset(&ssid, 0, sizeof(ssid));20792079-20802080- if (!dwrq->flags || !in_ssid_len) {20812081- /* "any" SSID requested; leave SSID blank */20822082- } else {20832083- /* Specific SSID requested */20842084- memcpy(&ssid, extra, in_ssid_len);20852085- ssid_len = in_ssid_len;20862086- }20872087-20882088- if (!ssid_len) {20892089- lbs_deb_wext("requested any SSID\n");20902090- } else {20912091- lbs_deb_wext("requested SSID '%s'\n",20922092- print_ssid(ssid_buf, ssid, ssid_len));20932093- }20942094-20952095-out:20962096- mutex_lock(&priv->lock);20972097- if (ret == 0) {20982098- /* Get or create the current association request */20992099- assoc_req = lbs_get_association_request(priv);21002100- if (!assoc_req) {21012101- ret = -ENOMEM;21022102- } else {21032103- /* Copy the SSID to the association request */21042104- memcpy(&assoc_req->ssid, &ssid, IEEE80211_MAX_SSID_LEN);21052105- assoc_req->ssid_len = ssid_len;21062106- set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);21072107- lbs_postpone_association_work(priv);21082108- }21092109- }21102110-21112111- /* Cancel the association request if there was an error */21122112- if (ret != 0) {21132113- lbs_cancel_association_work(priv);21142114- }21152115-21162116- mutex_unlock(&priv->lock);21172117-21182118- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);21192119- return ret;21202120-}21212121-21222122-#ifdef CONFIG_LIBERTAS_MESH21232123-static int lbs_mesh_get_essid(struct net_device *dev,21242124- struct iw_request_info *info,21252125- struct iw_point *dwrq, char *extra)21262126-{21272127- struct lbs_private *priv = dev->ml_priv;21282128-21292129- lbs_deb_enter(LBS_DEB_WEXT);21302130-21312131- memcpy(extra, priv->mesh_ssid, priv->mesh_ssid_len);21322132-21332133- dwrq->length = priv->mesh_ssid_len;21342134-21352135- dwrq->flags = 1; /* active */21362136-21372137- lbs_deb_leave(LBS_DEB_WEXT);21382138- return 0;21392139-}21402140-21412141-static int lbs_mesh_set_essid(struct net_device *dev,21422142- struct iw_request_info *info,21432143- struct iw_point *dwrq, char *extra)21442144-{21452145- struct lbs_private *priv = dev->ml_priv;21462146- int ret = 0;21472147-21482148- lbs_deb_enter(LBS_DEB_WEXT);21492149-21502150- if (!priv->radio_on) {21512151- ret = -EINVAL;21522152- goto out;21532153- }21542154-21552155- /* Check the size of the string */21562156- if (dwrq->length > IEEE80211_MAX_SSID_LEN) {21572157- ret = -E2BIG;21582158- goto out;21592159- }21602160-21612161- if (!dwrq->flags || !dwrq->length) {21622162- ret = -EINVAL;21632163- goto out;21642164- } else {21652165- /* Specific SSID requested */21662166- memcpy(priv->mesh_ssid, extra, dwrq->length);21672167- priv->mesh_ssid_len = dwrq->length;21682168- }21692169-21702170- lbs_mesh_config(priv, CMD_ACT_MESH_CONFIG_START,21712171- priv->channel);21722172- out:21732173- lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);21742174- return ret;21752175-}21762176-#endif21772177-21782178-/**21792179- * @brief Connect to the AP or Ad-hoc Network with specific bssid21802180- *21812181- * @param dev A pointer to net_device structure21822182- * @param info A pointer to iw_request_info structure21832183- * @param awrq A pointer to iw_param structure21842184- * @param extra A pointer to extra data buf21852185- * @return 0 --success, otherwise fail21862186- */21872187-static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,21882188- struct sockaddr *awrq, char *extra)21892189-{21902190- struct lbs_private *priv = dev->ml_priv;21912191- struct assoc_request * assoc_req;21922192- int ret = 0;21932193-21942194- lbs_deb_enter(LBS_DEB_WEXT);21952195-21962196- if (!priv->radio_on)21972197- return -EINVAL;21982198-21992199- if (awrq->sa_family != ARPHRD_ETHER)22002200- return -EINVAL;22012201-22022202- lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data);22032203-22042204- mutex_lock(&priv->lock);22052205-22062206- /* Get or create the current association request */22072207- assoc_req = lbs_get_association_request(priv);22082208- if (!assoc_req) {22092209- lbs_cancel_association_work(priv);22102210- ret = -ENOMEM;22112211- } else {22122212- /* Copy the BSSID to the association request */22132213- memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);22142214- set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);22152215- lbs_postpone_association_work(priv);22162216- }22172217-22182218- mutex_unlock(&priv->lock);22192219-22202220- return ret;22212221-}22222222-22232223-/*22242224- * iwconfig settable callbacks22252225- */22262226-static const iw_handler lbs_handler[] = {22272227- (iw_handler) NULL, /* SIOCSIWCOMMIT */22282228- (iw_handler) lbs_get_name, /* SIOCGIWNAME */22292229- (iw_handler) NULL, /* SIOCSIWNWID */22302230- (iw_handler) NULL, /* SIOCGIWNWID */22312231- (iw_handler) lbs_set_freq, /* SIOCSIWFREQ */22322232- (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */22332233- (iw_handler) lbs_set_mode, /* SIOCSIWMODE */22342234- (iw_handler) lbs_get_mode, /* SIOCGIWMODE */22352235- (iw_handler) NULL, /* SIOCSIWSENS */22362236- (iw_handler) NULL, /* SIOCGIWSENS */22372237- (iw_handler) NULL, /* SIOCSIWRANGE */22382238- (iw_handler) lbs_get_range, /* SIOCGIWRANGE */22392239- (iw_handler) NULL, /* SIOCSIWPRIV */22402240- (iw_handler) NULL, /* SIOCGIWPRIV */22412241- (iw_handler) NULL, /* SIOCSIWSTATS */22422242- (iw_handler) NULL, /* SIOCGIWSTATS */22432243- iw_handler_set_spy, /* SIOCSIWSPY */22442244- iw_handler_get_spy, /* SIOCGIWSPY */22452245- iw_handler_set_thrspy, /* SIOCSIWTHRSPY */22462246- iw_handler_get_thrspy, /* SIOCGIWTHRSPY */22472247- (iw_handler) lbs_set_wap, /* SIOCSIWAP */22482248- (iw_handler) lbs_get_wap, /* SIOCGIWAP */22492249- (iw_handler) NULL, /* SIOCSIWMLME */22502250- (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */22512251- (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */22522252- (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */22532253- (iw_handler) lbs_set_essid, /* SIOCSIWESSID */22542254- (iw_handler) lbs_get_essid, /* SIOCGIWESSID */22552255- (iw_handler) lbs_set_nick, /* SIOCSIWNICKN */22562256- (iw_handler) lbs_get_nick, /* SIOCGIWNICKN */22572257- (iw_handler) NULL, /* -- hole -- */22582258- (iw_handler) NULL, /* -- hole -- */22592259- (iw_handler) lbs_set_rate, /* SIOCSIWRATE */22602260- (iw_handler) lbs_get_rate, /* SIOCGIWRATE */22612261- (iw_handler) lbs_set_rts, /* SIOCSIWRTS */22622262- (iw_handler) lbs_get_rts, /* SIOCGIWRTS */22632263- (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */22642264- (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */22652265- (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */22662266- (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */22672267- (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */22682268- (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */22692269- (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */22702270- (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */22712271- (iw_handler) lbs_set_power, /* SIOCSIWPOWER */22722272- (iw_handler) lbs_get_power, /* SIOCGIWPOWER */22732273- (iw_handler) NULL, /* -- hole -- */22742274- (iw_handler) NULL, /* -- hole -- */22752275- (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */22762276- (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */22772277- (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */22782278- (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */22792279- (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */22802280- (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */22812281- (iw_handler) NULL, /* SIOCSIWPMKSA */22822282-};22832283-struct iw_handler_def lbs_handler_def = {22842284- .num_standard = ARRAY_SIZE(lbs_handler),22852285- .standard = (iw_handler *) lbs_handler,22862286- .get_wireless_stats = lbs_get_wireless_stats,22872287-};22882288-22892289-#ifdef CONFIG_LIBERTAS_MESH22902290-static const iw_handler mesh_wlan_handler[] = {22912291- (iw_handler) NULL, /* SIOCSIWCOMMIT */22922292- (iw_handler) lbs_get_name, /* SIOCGIWNAME */22932293- (iw_handler) NULL, /* SIOCSIWNWID */22942294- (iw_handler) NULL, /* SIOCGIWNWID */22952295- (iw_handler) lbs_mesh_set_freq, /* SIOCSIWFREQ */22962296- (iw_handler) lbs_get_freq, /* SIOCGIWFREQ */22972297- (iw_handler) NULL, /* SIOCSIWMODE */22982298- (iw_handler) mesh_wlan_get_mode, /* SIOCGIWMODE */22992299- (iw_handler) NULL, /* SIOCSIWSENS */23002300- (iw_handler) NULL, /* SIOCGIWSENS */23012301- (iw_handler) NULL, /* SIOCSIWRANGE */23022302- (iw_handler) lbs_get_range, /* SIOCGIWRANGE */23032303- (iw_handler) NULL, /* SIOCSIWPRIV */23042304- (iw_handler) NULL, /* SIOCGIWPRIV */23052305- (iw_handler) NULL, /* SIOCSIWSTATS */23062306- (iw_handler) NULL, /* SIOCGIWSTATS */23072307- iw_handler_set_spy, /* SIOCSIWSPY */23082308- iw_handler_get_spy, /* SIOCGIWSPY */23092309- iw_handler_set_thrspy, /* SIOCSIWTHRSPY */23102310- iw_handler_get_thrspy, /* SIOCGIWTHRSPY */23112311- (iw_handler) NULL, /* SIOCSIWAP */23122312- (iw_handler) NULL, /* SIOCGIWAP */23132313- (iw_handler) NULL, /* SIOCSIWMLME */23142314- (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */23152315- (iw_handler) lbs_set_scan, /* SIOCSIWSCAN */23162316- (iw_handler) lbs_get_scan, /* SIOCGIWSCAN */23172317- (iw_handler) lbs_mesh_set_essid,/* SIOCSIWESSID */23182318- (iw_handler) lbs_mesh_get_essid,/* SIOCGIWESSID */23192319- (iw_handler) NULL, /* SIOCSIWNICKN */23202320- (iw_handler) mesh_get_nick, /* SIOCGIWNICKN */23212321- (iw_handler) NULL, /* -- hole -- */23222322- (iw_handler) NULL, /* -- hole -- */23232323- (iw_handler) lbs_set_rate, /* SIOCSIWRATE */23242324- (iw_handler) lbs_get_rate, /* SIOCGIWRATE */23252325- (iw_handler) lbs_set_rts, /* SIOCSIWRTS */23262326- (iw_handler) lbs_get_rts, /* SIOCGIWRTS */23272327- (iw_handler) lbs_set_frag, /* SIOCSIWFRAG */23282328- (iw_handler) lbs_get_frag, /* SIOCGIWFRAG */23292329- (iw_handler) lbs_set_txpow, /* SIOCSIWTXPOW */23302330- (iw_handler) lbs_get_txpow, /* SIOCGIWTXPOW */23312331- (iw_handler) lbs_set_retry, /* SIOCSIWRETRY */23322332- (iw_handler) lbs_get_retry, /* SIOCGIWRETRY */23332333- (iw_handler) lbs_set_encode, /* SIOCSIWENCODE */23342334- (iw_handler) lbs_get_encode, /* SIOCGIWENCODE */23352335- (iw_handler) lbs_set_power, /* SIOCSIWPOWER */23362336- (iw_handler) lbs_get_power, /* SIOCGIWPOWER */23372337- (iw_handler) NULL, /* -- hole -- */23382338- (iw_handler) NULL, /* -- hole -- */23392339- (iw_handler) lbs_set_genie, /* SIOCSIWGENIE */23402340- (iw_handler) lbs_get_genie, /* SIOCGIWGENIE */23412341- (iw_handler) lbs_set_auth, /* SIOCSIWAUTH */23422342- (iw_handler) lbs_get_auth, /* SIOCGIWAUTH */23432343- (iw_handler) lbs_set_encodeext,/* SIOCSIWENCODEEXT */23442344- (iw_handler) lbs_get_encodeext,/* SIOCGIWENCODEEXT */23452345- (iw_handler) NULL, /* SIOCSIWPMKSA */23462346-};23472347-23482348-struct iw_handler_def mesh_handler_def = {23492349- .num_standard = ARRAY_SIZE(mesh_wlan_handler),23502350- .standard = (iw_handler *) mesh_wlan_handler,23512351- .get_wireless_stats = lbs_get_wireless_stats,23522352-};23532353-#endif
···347347{348348 u32 mask;349349 u16 reg;350350+ enum cipher curr_cipher;350351351352 if (crypto->cmd == SET_KEY) {352353 /*···358357 mask = TXRX_CSR0_KEY_ID.bit_mask;359358360359 rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®);360360+ curr_cipher = rt2x00_get_field16(reg, TXRX_CSR0_ALGORITHM);361361 reg &= mask;362362363363 if (reg && reg == mask)···367365 reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID);368366369367 key->hw_key_idx += reg ? ffz(reg) : 0;368368+ /*369369+ * Hardware requires that all keys use the same cipher370370+ * (e.g. TKIP-only, AES-only, but not TKIP+AES).371371+ * If this is not the first key, compare the cipher with the372372+ * first one and fall back to SW crypto if not the same.373373+ */374374+ if (key->hw_key_idx > 0 && crypto->cipher != curr_cipher)375375+ return -EOPNOTSUPP;370376371377 rt2500usb_register_multiwrite(rt2x00dev, reg,372378 crypto->key, sizeof(crypto->key));···17791769 .link_stats = rt2500usb_link_stats,17801770 .reset_tuner = rt2500usb_reset_tuner,17811771 .write_tx_desc = rt2500usb_write_tx_desc,17821782- .write_tx_data = rt2x00usb_write_tx_data,17831772 .write_beacon = rt2500usb_write_beacon,17841773 .get_tx_data_len = rt2500usb_get_tx_data_len,17851774 .kick_tx_queue = rt2x00usb_kick_tx_queue,
+73-31
drivers/net/wireless/rt2x00/rt2800lib.c
···9999 rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word);100100 rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1);101101 rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0);102102- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))103103- rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);102102+ rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);104103105104 rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);106105 }···127128 rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word);128129 rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1);129130 rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1);130130- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))131131- rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);131131+ rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1);132132133133 rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg);134134···430432}431433EXPORT_SYMBOL(rt2800_write_beacon);432434435435+static void inline rt2800_clear_beacon(struct rt2x00_dev *rt2x00dev,436436+ unsigned int beacon_base)437437+{438438+ int i;439439+440440+ /*441441+ * For the Beacon base registers we only need to clear442442+ * the whole TXWI which (when set to 0) will invalidate443443+ * the entire beacon.444444+ */445445+ for (i = 0; i < TXWI_DESC_SIZE; i += sizeof(__le32))446446+ rt2800_register_write(rt2x00dev, beacon_base + i, 0);447447+}448448+433449#ifdef CONFIG_RT2X00_LIB_DEBUGFS434450const struct rt2x00debug rt2800_rt2x00debug = {435451 .owner = THIS_MODULE,···745733void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,746734 struct rt2x00intf_conf *conf, const unsigned int flags)747735{748748- unsigned int beacon_base;749736 u32 reg;750737751738 if (flags & CONFIG_UPDATE_TYPE) {752739 /*753740 * Clear current synchronisation setup.754754- * For the Beacon base registers we only need to clear755755- * the first byte since that byte contains the VALID and OWNER756756- * bits which (when set to 0) will invalidate the entire beacon.757741 */758758- beacon_base = HW_BEACON_OFFSET(intf->beacon->entry_idx);759759- rt2800_register_write(rt2x00dev, beacon_base, 0);760760-742742+ rt2800_clear_beacon(rt2x00dev,743743+ HW_BEACON_OFFSET(intf->beacon->entry_idx));761744 /*762745 * Enable synchronisation.763746 */···775768776769 if (flags & CONFIG_UPDATE_BSSID) {777770 reg = le32_to_cpu(conf->bssid[1]);778778- rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 0);779779- rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 0);771771+ rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_ID_MASK, 3);772772+ rt2x00_set_field32(®, MAC_BSSID_DW1_BSS_BCN_NUM, 7);780773 conf->bssid[1] = cpu_to_le32(reg);781774782775 rt2800_register_multiwrite(rt2x00dev, MAC_BSSID_DW0,···834827 switch ((int)ant->tx) {835828 case 1:836829 rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);837837- if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev))838838- rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);839830 break;840831 case 2:841832 rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);842833 break;843834 case 3:844844- /* Do nothing */835835+ rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);845836 break;846837 }847838···1570156515711566 /*15721567 * Clear all beacons15731573- * For the Beacon base registers we only need to clear15741574- * the first byte since that byte contains the VALID and OWNER15751575- * bits which (when set to 0) will invalidate the entire beacon.15761568 */15771577- rt2800_register_write(rt2x00dev, HW_BEACON_BASE0, 0);15781578- rt2800_register_write(rt2x00dev, HW_BEACON_BASE1, 0);15791579- rt2800_register_write(rt2x00dev, HW_BEACON_BASE2, 0);15801580- rt2800_register_write(rt2x00dev, HW_BEACON_BASE3, 0);15811581- rt2800_register_write(rt2x00dev, HW_BEACON_BASE4, 0);15821582- rt2800_register_write(rt2x00dev, HW_BEACON_BASE5, 0);15831583- rt2800_register_write(rt2x00dev, HW_BEACON_BASE6, 0);15841584- rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);15691569+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE0);15701570+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE1);15711571+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE2);15721572+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE3);15731573+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE4);15741574+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE5);15751575+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE6);15761576+ rt2800_clear_beacon(rt2x00dev, HW_BEACON_BASE7);1585157715861578 if (rt2x00_is_usb(rt2x00dev)) {15871579 rt2800_register_read(rt2x00dev, US_CYC_CNT, ®);···21872185 rt2x00_set_field16(&word, EEPROM_NIC_WPS_PBC, 0);21882186 rt2x00_set_field16(&word, EEPROM_NIC_BW40M_BG, 0);21892187 rt2x00_set_field16(&word, EEPROM_NIC_BW40M_A, 0);21882188+ rt2x00_set_field16(&word, EEPROM_NIC_ANT_DIVERSITY, 0);21892189+ rt2x00_set_field16(&word, EEPROM_NIC_DAC_TEST, 0);21902190 rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);21912191 EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);21922192 }···21962192 rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);21972193 if ((word & 0x00ff) == 0x00ff) {21982194 rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);21952195+ rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);21962196+ EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);21972197+ }21982198+ if ((word & 0xff00) == 0xff00) {21992199 rt2x00_set_field16(&word, EEPROM_FREQ_LED_MODE,22002200 LED_MODE_TXRX_ACTIVITY);22012201 rt2x00_set_field16(&word, EEPROM_FREQ_LED_POLARITY, 0);···22072199 rt2x00_eeprom_write(rt2x00dev, EEPROM_LED1, 0x5555);22082200 rt2x00_eeprom_write(rt2x00dev, EEPROM_LED2, 0x2221);22092201 rt2x00_eeprom_write(rt2x00dev, EEPROM_LED3, 0xa9f8);22102210- EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);22022202+ EEPROM(rt2x00dev, "Led Mode: 0x%04x\n", word);22112203 }2212220422132205 /*···25072499 IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |25082500 IEEE80211_HW_SIGNAL_DBM |25092501 IEEE80211_HW_SUPPORTS_PS |25102510- IEEE80211_HW_PS_NULLFUNC_STACK;25022502+ IEEE80211_HW_PS_NULLFUNC_STACK |25032503+ IEEE80211_HW_AMPDU_AGGREGATION;2511250425122505 SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);25132506 SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,···25682559 IEEE80211_HT_CAP_SUP_WIDTH_20_40 |25692560 IEEE80211_HT_CAP_GRN_FLD |25702561 IEEE80211_HT_CAP_SGI_20 |25712571- IEEE80211_HT_CAP_SGI_40 |25722572- IEEE80211_HT_CAP_RX_STBC;25622562+ IEEE80211_HT_CAP_SGI_40;2573256325742564 if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)25752565 spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;25662566+25672567+ spec->ht.cap |=25682568+ rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RXPATH) <<25692569+ IEEE80211_HT_CAP_RX_STBC_SHIFT;2576257025772571 spec->ht.ampdu_factor = 3;25782572 spec->ht.ampdu_density = 4;···27632751 return tsf;27642752}2765275327542754+static int rt2800_ampdu_action(struct ieee80211_hw *hw,27552755+ struct ieee80211_vif *vif,27562756+ enum ieee80211_ampdu_mlme_action action,27572757+ struct ieee80211_sta *sta,27582758+ u16 tid, u16 *ssn)27592759+{27602760+ int ret = 0;27612761+27622762+ switch (action) {27632763+ case IEEE80211_AMPDU_RX_START:27642764+ case IEEE80211_AMPDU_RX_STOP:27652765+ /* we don't support RX aggregation yet */27662766+ ret = -ENOTSUPP;27672767+ break;27682768+ case IEEE80211_AMPDU_TX_START:27692769+ ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);27702770+ break;27712771+ case IEEE80211_AMPDU_TX_STOP:27722772+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);27732773+ break;27742774+ case IEEE80211_AMPDU_TX_OPERATIONAL:27752775+ break;27762776+ default:27772777+ WARNING((struct rt2x00_dev *)hw->priv, "Unknown AMPDU action\n");27782778+ }27792779+27802780+ return ret;27812781+}27822782+27662783const struct ieee80211_ops rt2800_mac80211_ops = {27672784 .tx = rt2x00mac_tx,27682785 .start = rt2x00mac_start,···28092768 .conf_tx = rt2800_conf_tx,28102769 .get_tsf = rt2800_get_tsf,28112770 .rfkill_poll = rt2x00mac_rfkill_poll,27712771+ .ampdu_action = rt2800_ampdu_action,28122772};28132773EXPORT_SYMBOL_GPL(rt2800_mac80211_ops);28142774
···211211 bool success;212212213213 /*214214+ * Unmap the skb.215215+ */216216+ rt2x00queue_unmap_skb(rt2x00dev, entry->skb);217217+218218+ /*219219+ * Remove the extra tx headroom from the skb.220220+ */221221+ skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);222222+223223+ /*224224+ * Signal that the TX descriptor is no longer in the skb.225225+ */226226+ skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;227227+228228+ /*214229 * Remove L2 padding which was added during215230 */216231 if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))···299284 tx_info->flags |= IEEE80211_TX_STAT_ACK;300285 else301286 rt2x00dev->low_level_stats.dot11ACKFailureCount++;287287+ }288288+289289+ /*290290+ * Every single frame has it's own tx status, hence report291291+ * every frame as ampdu of size 1.292292+ *293293+ * TODO: if we can find out how many frames were aggregated294294+ * by the hw we could provide the real ampdu_len to mac80211295295+ * which would allow the rc algorithm to better decide on296296+ * which rates are suitable.297297+ */298298+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {299299+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU;300300+ tx_info->status.ampdu_len = 1;301301+ tx_info->status.ampdu_ack_len = success ? 1 : 0;302302 }303303304304 if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+4-4
drivers/net/wireless/rt2x00/rt2x00link.c
···271271272272 /*273273 * Link tuning should only be performed when274274- * an active sta or master interface exists.275275- * Single monitor mode interfaces should never have276276- * work with link tuners.274274+ * an active sta interface exists. AP interfaces275275+ * don't need link tuning and monitor mode interfaces276276+ * should never have to work with link tuners.277277 */278278- if (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)278278+ if (!rt2x00dev->intf_sta_count)279279 return;280280281281 rt2x00link_reset_tuner(rt2x00dev, false);
+4-6
drivers/net/wireless/rt2x00/rt2x00mac.c
···282282 * has been initialized. Otherwise the device can reset283283 * the MAC registers.284284 */285285- rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL);285285+ rt2x00lib_config_intf(rt2x00dev, intf, vif->type,286286+ intf->mac, intf->bssid);286287287288 /*288289 * Some filters depend on the current working mode. We can force···563562{564563 struct rt2x00_dev *rt2x00dev = hw->priv;565564 struct rt2x00_intf *intf = vif_to_intf(vif);566566- int update_bssid = 0;567565568566 /*569567 * mac80211 might be calling this function while we are trying···577577 * conf->bssid can be NULL if coming from the internal578578 * beacon update routine.579579 */580580- if (changes & BSS_CHANGED_BSSID) {581581- update_bssid = 1;580580+ if (changes & BSS_CHANGED_BSSID)582581 memcpy(&intf->bssid, bss_conf->bssid, ETH_ALEN);583583- }584582585583 spin_unlock(&intf->lock);586584···590592 */591593 if (changes & BSS_CHANGED_BSSID)592594 rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL,593593- update_bssid ? bss_conf->bssid : NULL);595595+ bss_conf->bssid);594596595597 /*596598 * Update the beacon.
-74
drivers/net/wireless/rt2x00/rt2x00pci.c
···6060}6161EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);62626363-/*6464- * TX data handlers.6565- */6666-int rt2x00pci_write_tx_data(struct queue_entry *entry,6767- struct txentry_desc *txdesc)6868-{6969- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;7070-7171- /*7272- * This should not happen, we already checked the entry7373- * was ours. When the hardware disagrees there has been7474- * a queue corruption!7575- */7676- if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) {7777- ERROR(rt2x00dev,7878- "Corrupt queue %d, accessing entry which is not ours.\n"7979- "Please file bug report to %s.\n",8080- entry->queue->qid, DRV_PROJECT);8181- return -EINVAL;8282- }8383-8484- /*8585- * Add the requested extra tx headroom in front of the skb.8686- */8787- skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);8888- memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);8989-9090- /*9191- * Call the driver's write_tx_datadesc function, if it exists.9292- */9393- if (rt2x00dev->ops->lib->write_tx_datadesc)9494- rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);9595-9696- /*9797- * Map the skb to DMA.9898- */9999- if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))100100- rt2x00queue_map_txskb(rt2x00dev, entry->skb);101101-102102- return 0;103103-}104104-EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);105105-106106-/*107107- * TX/RX data handlers.108108- */109109-void rt2x00pci_txdone(struct queue_entry *entry,110110- struct txdone_entry_desc *txdesc)111111-{112112- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;113113- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);114114-115115- /*116116- * Unmap the skb.117117- */118118- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);119119-120120- /*121121- * Remove the extra tx headroom from the skb.122122- */123123- skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);124124-125125- /*126126- * Signal that the TX descriptor is no longer in the skb.127127- */128128- skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;129129-130130- /*131131- * Pass on to rt2x00lib.132132- */133133- rt2x00lib_txdone(entry, txdesc);134134-}135135-EXPORT_SYMBOL_GPL(rt2x00pci_txdone);136136-13763void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)13864{13965 struct data_queue *queue = rt2x00dev->rx;
-18
drivers/net/wireless/rt2x00/rt2x00pci.h
···8686 u32 *reg);87878888/**8989- * rt2x00pci_write_tx_data - Initialize data for TX operation9090- * @entry: The entry where the frame is located9191- *9292- * This function will initialize the DMA and skb descriptor9393- * to prepare the entry for the actual TX operation.9494- */9595-int rt2x00pci_write_tx_data(struct queue_entry *entry,9696- struct txentry_desc *txdesc);9797-9898-/**9989 * struct queue_entry_priv_pci: Per entry PCI specific information10090 *10191 * @desc: Pointer to device descriptor···97107 __le32 *desc;98108 dma_addr_t desc_dma;99109};100100-101101-/**102102- * rt2x00pci_txdone - Handle TX done events.103103- * @entry: The queue entry for which a TX done event was received.104104- * @txdesc: The TX done descriptor for the entry.105105- */106106-void rt2x00pci_txdone(struct queue_entry *entry,107107- struct txdone_entry_desc *txdesc);108110109111/**110112 * rt2x00pci_rxdone - Handle RX done events
+41-2
drivers/net/wireless/rt2x00/rt2x00queue.c
···404404 rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);405405}406406407407+static int rt2x00queue_write_tx_data(struct queue_entry *entry,408408+ struct txentry_desc *txdesc)409409+{410410+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;411411+412412+ /*413413+ * This should not happen, we already checked the entry414414+ * was ours. When the hardware disagrees there has been415415+ * a queue corruption!416416+ */417417+ if (unlikely(rt2x00dev->ops->lib->get_entry_state &&418418+ rt2x00dev->ops->lib->get_entry_state(entry))) {419419+ ERROR(rt2x00dev,420420+ "Corrupt queue %d, accessing entry which is not ours.\n"421421+ "Please file bug report to %s.\n",422422+ entry->queue->qid, DRV_PROJECT);423423+ return -EINVAL;424424+ }425425+426426+ /*427427+ * Add the requested extra tx headroom in front of the skb.428428+ */429429+ skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);430430+ memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);431431+432432+ /*433433+ * Call the driver's write_tx_data function, if it exists.434434+ */435435+ if (rt2x00dev->ops->lib->write_tx_data)436436+ rt2x00dev->ops->lib->write_tx_data(entry, txdesc);437437+438438+ /*439439+ * Map the skb to DMA.440440+ */441441+ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))442442+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);443443+444444+ return 0;445445+}446446+407447static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,408448 struct txentry_desc *txdesc)409449{···555515 * call failed. Since we always return NETDEV_TX_OK to mac80211,556516 * this frame will simply be dropped.557517 */558558- if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry,559559- &txdesc))) {518518+ if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {560519 clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);561520 entry->skb = NULL;562521 return -EIO;
+13-38
drivers/net/wireless/rt2x00/rt2x00usb.c
···178178 return;179179180180 /*181181- * Remove the descriptor from the front of the skb.182182- */183183- skb_pull(entry->skb, entry->queue->desc_size);184184-185185- /*186181 * Obtain the status about this packet.187182 * Note that when the status is 0 it does not mean the188183 * frame was send out correctly. It only means the frame···196201 rt2x00lib_txdone(entry, &txdesc);197202}198203199199-int rt2x00usb_write_tx_data(struct queue_entry *entry,200200- struct txentry_desc *txdesc)204204+static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)201205{202206 struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;203207 struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);204208 struct queue_entry_priv_usb *entry_priv = entry->priv_data;205209 u32 length;206210207207- /*208208- * Add the descriptor in front of the skb.209209- */210210- skb_push(entry->skb, entry->queue->desc_size);211211- memset(entry->skb->data, 0, entry->queue->desc_size);211211+ if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags)) {212212+ /*213213+ * USB devices cannot blindly pass the skb->len as the214214+ * length of the data to usb_fill_bulk_urb. Pass the skb215215+ * to the driver to determine what the length should be.216216+ */217217+ length = rt2x00dev->ops->lib->get_tx_data_len(entry);212218213213- /*214214- * USB devices cannot blindly pass the skb->len as the215215- * length of the data to usb_fill_bulk_urb. Pass the skb216216- * to the driver to determine what the length should be.217217- */218218- length = rt2x00dev->ops->lib->get_tx_data_len(entry);219219+ usb_fill_bulk_urb(entry_priv->urb, usb_dev,220220+ usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),221221+ entry->skb->data, length,222222+ rt2x00usb_interrupt_txdone, entry);219223220220- usb_fill_bulk_urb(entry_priv->urb, usb_dev,221221- usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint),222222- entry->skb->data, length,223223- rt2x00usb_interrupt_txdone, entry);224224-225225- /*226226- * Call the driver's write_tx_datadesc function, if it exists.227227- */228228- if (rt2x00dev->ops->lib->write_tx_datadesc)229229- rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);230230-231231- return 0;232232-}233233-EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);234234-235235-static inline void rt2x00usb_kick_tx_entry(struct queue_entry *entry)236236-{237237- struct queue_entry_priv_usb *entry_priv = entry->priv_data;238238-239239- if (test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags))240224 usb_submit_urb(entry_priv->urb, GFP_ATOMIC);225225+ }241226}242227243228void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
-10
drivers/net/wireless/rt2x00/rt2x00usb.h
···351351void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);352352353353/**354354- * rt2x00usb_write_tx_data - Initialize URB for TX operation355355- * @entry: The entry where the frame is located356356- *357357- * This function will initialize the URB and skb descriptor358358- * to prepare the entry for the actual TX operation.359359- */360360-int rt2x00usb_write_tx_data(struct queue_entry *entry,361361- struct txentry_desc *txdesc);362362-363363-/**364354 * struct queue_entry_priv_usb: Per entry USB specific information365355 *366356 * @urb: Urb structure used for device communication.
···725725 * @NL80211_ATTR_AP_ISOLATE: (AP mode) Do not forward traffic between stations726726 * connected to this BSS.727727 *728728+ * @NL80211_ATTR_WIPHY_TX_POWER_SETTING: Transmit power setting type. See729729+ * &enum nl80211_tx_power_setting for possible values.730730+ * @NL80211_ATTR_WIPHY_TX_POWER_LEVEL: Transmit power level in signed mBm units.731731+ * This is used in association with @NL80211_ATTR_WIPHY_TX_POWER_SETTING732732+ * for non-automatic settings.733733+ *728734 * @NL80211_ATTR_MAX: highest attribute number currently defined729735 * @__NL80211_ATTR_AFTER_LAST: internal use730736 */···887881 NL80211_ATTR_LOCAL_STATE_CHANGE,888882889883 NL80211_ATTR_AP_ISOLATE,884884+885885+ NL80211_ATTR_WIPHY_TX_POWER_SETTING,886886+ NL80211_ATTR_WIPHY_TX_POWER_LEVEL,890887891888 /* add attributes here, update the policy in nl80211.c */892889···16661657enum nl80211_cqm_rssi_threshold_event {16671658 NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,16681659 NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH,16601660+};16611661+16621662+16631663+/**16641664+ * enum nl80211_tx_power_setting - TX power adjustment16651665+ * @NL80211_TX_POWER_AUTOMATIC: automatically determine transmit power16661666+ * @NL80211_TX_POWER_LIMITED: limit TX power by the mBm parameter16671667+ * @NL80211_TX_POWER_FIXED: fix TX power to the mBm parameter16681668+ */16691669+enum nl80211_tx_power_setting {16701670+ NL80211_TX_POWER_AUTOMATIC,16711671+ NL80211_TX_POWER_LIMITED,16721672+ NL80211_TX_POWER_FIXED,16691673};1670167416711675#endif /* __LINUX_NL80211_H */
+1-14
include/net/cfg80211.h
···875875 WIPHY_PARAM_COVERAGE_CLASS = 1 << 4,876876};877877878878-/**879879- * enum tx_power_setting - TX power adjustment880880- *881881- * @TX_POWER_AUTOMATIC: the dbm parameter is ignored882882- * @TX_POWER_LIMITED: limit TX power by the dbm parameter883883- * @TX_POWER_FIXED: fix TX power to the dbm parameter884884- */885885-enum tx_power_setting {886886- TX_POWER_AUTOMATIC,887887- TX_POWER_LIMITED,888888- TX_POWER_FIXED,889889-};890890-891878/*892879 * cfg80211_bitrate_mask - masks for bitrate control893880 */···11361149 int (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);1137115011381151 int (*set_tx_power)(struct wiphy *wiphy,11391139- enum tx_power_setting type, int dbm);11521152+ enum nl80211_tx_power_setting type, int mbm);11401153 int (*get_tx_power)(struct wiphy *wiphy, int *dbm);1141115411421155 int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
+39
include/net/mac80211.h
···12711271 * dynamic PS feature in stack and will just keep %IEEE80211_CONF_PS12721272 * enabled whenever user has enabled powersave.12731273 *12741274+ * Some hardware need to toggle a single shared antenna between WLAN and12751275+ * Bluetooth to facilitate co-existence. These types of hardware set12761276+ * limitations on the use of host controlled dynamic powersave whenever there12771277+ * is simultaneous WLAN and Bluetooth traffic. For these types of hardware, the12781278+ * driver may request temporarily going into full power save, in order to12791279+ * enable toggling the antenna between BT and WLAN. If the driver requests12801280+ * disabling dynamic powersave, the @dynamic_ps_timeout value will be12811281+ * temporarily set to zero until the driver re-enables dynamic powersave.12821282+ *12741283 * Driver informs U-APSD client support by enabling12751284 * %IEEE80211_HW_SUPPORTS_UAPSD flag. The mode is configured through the12761285 * uapsd paramater in conf_tx() operation. Hardware needs to send the QoS···24542445 * without connection recovery attempts.24552446 */24562447void ieee80211_connection_loss(struct ieee80211_vif *vif);24482448+24492449+/**24502450+ * ieee80211_disable_dyn_ps - force mac80211 to temporarily disable dynamic psm24512451+ *24522452+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.24532453+ *24542454+ * Some hardware require full power save to manage simultaneous BT traffic24552455+ * on the WLAN frequency. Full PSM is required periodically, whenever there are24562456+ * burst of BT traffic. The hardware gets information of BT traffic via24572457+ * hardware co-existence lines, and consequentially requests mac80211 to24582458+ * (temporarily) enter full psm.24592459+ * This function will only temporarily disable dynamic PS, not enable PSM if24602460+ * it was not already enabled.24612461+ * The driver must make sure to re-enable dynamic PS using24622462+ * ieee80211_enable_dyn_ps() if the driver has disabled it.24632463+ *24642464+ */24652465+void ieee80211_disable_dyn_ps(struct ieee80211_vif *vif);24662466+24672467+/**24682468+ * ieee80211_enable_dyn_ps - restore dynamic psm after being disabled24692469+ *24702470+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.24712471+ *24722472+ * This function restores dynamic PS after being temporarily disabled via24732473+ * ieee80211_disable_dyn_ps(). Each ieee80211_disable_dyn_ps() call must24742474+ * be coupled with an eventual call to this function.24752475+ *24762476+ */24772477+void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif);2457247824582479/**24592480 * ieee80211_cqm_rssi_notify - inform a configured connection quality monitoring
+1
net/mac80211/Kconfig
···69697070config MAC80211_RC_DEFAULT7171 string7272+ default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT7273 default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL7374 default "pid" if MAC80211_RC_DEFAULT_PID7475 default ""
+11-14
net/mac80211/cfg.c
···413413{414414 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);415415416416- if (!local->ops->get_survey)417417- return -EOPNOTSUPP;418418-419416 return drv_get_survey(local, idx, survey);420417}421418···13261329}1327133013281331static int ieee80211_set_tx_power(struct wiphy *wiphy,13291329- enum tx_power_setting type, int dbm)13321332+ enum nl80211_tx_power_setting type, int mbm)13301333{13311334 struct ieee80211_local *local = wiphy_priv(wiphy);13321335 struct ieee80211_channel *chan = local->hw.conf.channel;13331336 u32 changes = 0;1334133713351338 switch (type) {13361336- case TX_POWER_AUTOMATIC:13391339+ case NL80211_TX_POWER_AUTOMATIC:13371340 local->user_power_level = -1;13381341 break;13391339- case TX_POWER_LIMITED:13401340- if (dbm < 0)13411341- return -EINVAL;13421342- local->user_power_level = dbm;13421342+ case NL80211_TX_POWER_LIMITED:13431343+ if (mbm < 0 || (mbm % 100))13441344+ return -EOPNOTSUPP;13451345+ local->user_power_level = MBM_TO_DBM(mbm);13431346 break;13441344- case TX_POWER_FIXED:13451345- if (dbm < 0)13461346- return -EINVAL;13471347+ case NL80211_TX_POWER_FIXED:13481348+ if (mbm < 0 || (mbm % 100))13491349+ return -EOPNOTSUPP;13471350 /* TODO: move to cfg80211 when it knows the channel */13481348- if (dbm > chan->max_power)13511351+ if (MBM_TO_DBM(mbm) > chan->max_power)13491352 return -EINVAL;13501350- local->user_power_level = dbm;13531353+ local->user_power_level = MBM_TO_DBM(mbm);13511354 break;13521355 }13531356
+6-1
net/mac80211/driver-ops.h
···375375 struct survey_info *survey)376376{377377 int ret = -EOPNOTSUPP;378378+379379+ trace_drv_get_survey(local, idx, survey);380380+378381 if (local->ops->get_survey)379382 ret = local->ops->get_survey(&local->hw, idx, survey);380380- /* trace_drv_get_survey(local, idx, survey, ret); */383383+384384+ trace_drv_return_int(local, ret);385385+381386 return ret;382387}383388
···855855 * this will override whatever chosen by mac80211 internally.856856 */857857 int dynamic_ps_forced_timeout;858858+ int dynamic_ps_user_timeout;859859+ bool disable_dynamic_ps;858860859861 int user_power_level; /* in dBm */860862 int power_constr_level; /* in dBm */
···328328}329329330330static void331331-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary)331331+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, unsigned int *idx,332332+ bool primary)332333{333334 int group, orig_group;334335
+2
net/mac80211/rc80211_minstrel_ht.h
···2929 unsigned int duration[MCS_GROUP_RATES];3030};31313232+extern const struct mcs_group minstrel_mcs_groups[];3333+3234struct minstrel_rate_stats {3335 /* current / last sampling period attempts/success counters */3436 unsigned int attempts, last_attempts;