···86868787config ATH9K_TX998888 bool "Atheros ath9k TX99 testing support"8989- depends on CFG80211_CERTIFICATION_ONUS8989+ depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS9090 default n9191 ---help---9292 Say N. This should only be enabled on systems undergoing···103103 Regulatory bodies around the world require that wireless device104104 be evaluated to meet the RF exposure limits set forth in the105105 governmental SAR regulations.106106+107107+config ATH9K_WOW108108+ bool "Wake on Wireless LAN support (EXPERIMENTAL)"109109+ depends on ATH9K && PM110110+ default n111111+ ---help---112112+ This option enables Wake on Wireless LAN support for certain cards.113113+ Currently, AR9462 is supported.106114107115config ATH9K_LEGACY_RATE_CONTROL108116 bool "Atheros ath9k rate control"
···11+/*22+ * Copyright (c) 2012 Qualcomm Atheros, Inc.33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+1717+#include <linux/export.h>1818+#include "ath9k.h"1919+#include "reg.h"2020+#include "hw-ops.h"2121+2222+const char *ath9k_hw_wow_event_to_string(u32 wow_event)2323+{2424+ if (wow_event & AH_WOW_MAGIC_PATTERN_EN)2525+ return "Magic pattern";2626+ if (wow_event & AH_WOW_USER_PATTERN_EN)2727+ return "User pattern";2828+ if (wow_event & AH_WOW_LINK_CHANGE)2929+ return "Link change";3030+ if (wow_event & AH_WOW_BEACON_MISS)3131+ return "Beacon miss";3232+3333+ return "unknown reason";3434+}3535+EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);3636+3737+static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)3838+{3939+ struct ath_common *common = ath9k_hw_common(ah);4040+4141+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);4242+4343+ /* set rx disable bit */4444+ REG_WRITE(ah, AR_CR, AR_CR_RXD);4545+4646+ if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {4747+ ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",4848+ REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));4949+ return;5050+ }5151+5252+ REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);5353+}5454+5555+static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)5656+{5757+ struct ath_common *common = ath9k_hw_common(ah);5858+ u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];5959+ u32 ctl[13] = {0};6060+ u32 data_word[KAL_NUM_DATA_WORDS];6161+ u8 i;6262+ u32 wow_ka_data_word0;6363+6464+ memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);6565+ memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);6666+6767+ /* set the transmit buffer */6868+ ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));6969+ ctl[1] = 0;7070+ ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */7171+ ctl[4] = 0;7272+ ctl[7] = (ah->txchainmask) << 2;7373+ ctl[2] = 0xf << 16; /* tx_tries 0 */7474+7575+ for (i = 0; i < KAL_NUM_DESC_WORDS; i++)7676+ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);7777+7878+ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);7979+8080+ data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |8181+ (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);8282+ data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |8383+ (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);8484+ data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |8585+ (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);8686+ data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |8787+ (sta_mac_addr[3] << 8) | (sta_mac_addr[2]);8888+ data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |8989+ (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);9090+ data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);9191+9292+ if (AR_SREV_9462_20(ah)) {9393+ /* AR9462 2.0 has an extra descriptor word (time based9494+ * discard) compared to other chips */9595+ REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);9696+ wow_ka_data_word0 = AR_WOW_TXBUF(13);9797+ } else {9898+ wow_ka_data_word0 = AR_WOW_TXBUF(12);9999+ }100100+101101+ for (i = 0; i < KAL_NUM_DATA_WORDS; i++)102102+ REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);103103+104104+}105105+106106+void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,107107+ u8 *user_mask, int pattern_count,108108+ int pattern_len)109109+{110110+ int i;111111+ u32 pattern_val, mask_val;112112+ u32 set, clr;113113+114114+ /* FIXME: should check count by querying the hardware capability */115115+ if (pattern_count >= MAX_NUM_PATTERN)116116+ return;117117+118118+ REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));119119+120120+ /* set the registers for pattern */121121+ for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {122122+ memcpy(&pattern_val, user_pattern, 4);123123+ REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),124124+ pattern_val);125125+ user_pattern += 4;126126+ }127127+128128+ /* set the registers for mask */129129+ for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {130130+ memcpy(&mask_val, user_mask, 4);131131+ REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);132132+ user_mask += 4;133133+ }134134+135135+ /* set the pattern length to be matched136136+ *137137+ * AR_WOW_LENGTH1_REG1138138+ * bit 31:24 pattern 0 length139139+ * bit 23:16 pattern 1 length140140+ * bit 15:8 pattern 2 length141141+ * bit 7:0 pattern 3 length142142+ *143143+ * AR_WOW_LENGTH1_REG2144144+ * bit 31:24 pattern 4 length145145+ * bit 23:16 pattern 5 length146146+ * bit 15:8 pattern 6 length147147+ * bit 7:0 pattern 7 length148148+ *149149+ * the below logic writes out the new150150+ * pattern length for the corresponding151151+ * pattern_count, while masking out the152152+ * other fields153153+ */154154+155155+ ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);156156+157157+ if (pattern_count < 4) {158158+ /* Pattern 0-3 uses AR_WOW_LENGTH1 register */159159+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<160160+ AR_WOW_LEN1_SHIFT(pattern_count);161161+ clr = AR_WOW_LENGTH1_MASK(pattern_count);162162+ REG_RMW(ah, AR_WOW_LENGTH1, set, clr);163163+ } else {164164+ /* Pattern 4-7 uses AR_WOW_LENGTH2 register */165165+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<166166+ AR_WOW_LEN2_SHIFT(pattern_count);167167+ clr = AR_WOW_LENGTH2_MASK(pattern_count);168168+ REG_RMW(ah, AR_WOW_LENGTH2, set, clr);169169+ }170170+171171+}172172+EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);173173+174174+u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)175175+{176176+ u32 wow_status = 0;177177+ u32 val = 0, rval;178178+179179+ /*180180+ * read the WoW status register to know181181+ * the wakeup reason182182+ */183183+ rval = REG_READ(ah, AR_WOW_PATTERN);184184+ val = AR_WOW_STATUS(rval);185185+186186+ /*187187+ * mask only the WoW events that we have enabled. Sometimes188188+ * we have spurious WoW events from the AR_WOW_PATTERN189189+ * register. This mask will clean it up.190190+ */191191+192192+ val &= ah->wow_event_mask;193193+194194+ if (val) {195195+ if (val & AR_WOW_MAGIC_PAT_FOUND)196196+ wow_status |= AH_WOW_MAGIC_PATTERN_EN;197197+ if (AR_WOW_PATTERN_FOUND(val))198198+ wow_status |= AH_WOW_USER_PATTERN_EN;199199+ if (val & AR_WOW_KEEP_ALIVE_FAIL)200200+ wow_status |= AH_WOW_LINK_CHANGE;201201+ if (val & AR_WOW_BEACON_FAIL)202202+ wow_status |= AH_WOW_BEACON_MISS;203203+ }204204+205205+ /*206206+ * set and clear WOW_PME_CLEAR registers for the chip to207207+ * generate next wow signal.208208+ * disable D3 before accessing other registers ?209209+ */210210+211211+ /* do we need to check the bit value 0x01000000 (7-10) ?? */212212+ REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,213213+ AR_PMCTRL_PWR_STATE_D1D3);214214+215215+ /*216216+ * clear all events217217+ */218218+ REG_WRITE(ah, AR_WOW_PATTERN,219219+ AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));220220+221221+ /*222222+ * restore the beacon threshold to init value223223+ */224224+ REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);225225+226226+ /*227227+ * Restore the way the PCI-E reset, Power-On-Reset, external228228+ * PCIE_POR_SHORT pins are tied to its original value.229229+ * Previously just before WoW sleep, we untie the PCI-E230230+ * reset to our Chip's Power On Reset so that any PCI-E231231+ * reset from the bus will not reset our chip232232+ */233233+ if (ah->is_pciexpress)234234+ ath9k_hw_configpcipowersave(ah, false);235235+236236+ ah->wow_event_mask = 0;237237+238238+ return wow_status;239239+}240240+EXPORT_SYMBOL(ath9k_hw_wow_wakeup);241241+242242+void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)243243+{244244+ u32 wow_event_mask;245245+ u32 set, clr;246246+247247+ /*248248+ * wow_event_mask is a mask to the AR_WOW_PATTERN register to249249+ * indicate which WoW events we have enabled. The WoW events250250+ * are from the 'pattern_enable' in this function and251251+ * 'pattern_count' of ath9k_hw_wow_apply_pattern()252252+ */253253+ wow_event_mask = ah->wow_event_mask;254254+255255+ /*256256+ * Untie Power-on-Reset from the PCI-E-Reset. When we are in257257+ * WOW sleep, we do want the Reset from the PCI-E to disturb258258+ * our hw state259259+ */260260+ if (ah->is_pciexpress) {261261+ /*262262+ * we need to untie the internal POR (power-on-reset)263263+ * to the external PCI-E reset. We also need to tie264264+ * the PCI-E Phy reset to the PCI-E reset.265265+ */266266+ set = AR_WA_RESET_EN | AR_WA_POR_SHORT;267267+ clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;268268+ REG_RMW(ah, AR_WA, set, clr);269269+ }270270+271271+ /*272272+ * set the power states appropriately and enable PME273273+ */274274+ set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |275275+ AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;276276+277277+ /*278278+ * set and clear WOW_PME_CLEAR registers for the chip279279+ * to generate next wow signal.280280+ */281281+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);282282+ clr = AR_PMCTRL_WOW_PME_CLR;283283+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);284284+285285+ /*286286+ * Setup for:287287+ * - beacon misses288288+ * - magic pattern289289+ * - keep alive timeout290290+ * - pattern matching291291+ */292292+293293+ /*294294+ * Program default values for pattern backoff, aifs/slot/KAL count,295295+ * beacon miss timeout, KAL timeout, etc.296296+ */297297+ set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);298298+ REG_SET_BIT(ah, AR_WOW_PATTERN, set);299299+300300+ set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |301301+ AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |302302+ AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);303303+ REG_SET_BIT(ah, AR_WOW_COUNT, set);304304+305305+ if (pattern_enable & AH_WOW_BEACON_MISS)306306+ set = AR_WOW_BEACON_TIMO;307307+ /* We are not using beacon miss, program a large value */308308+ else309309+ set = AR_WOW_BEACON_TIMO_MAX;310310+311311+ REG_WRITE(ah, AR_WOW_BCN_TIMO, set);312312+313313+ /*314314+ * Keep alive timo in ms except AR9280315315+ */316316+ if (!pattern_enable)317317+ set = AR_WOW_KEEP_ALIVE_NEVER;318318+ else319319+ set = KAL_TIMEOUT * 32;320320+321321+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);322322+323323+ /*324324+ * Keep alive delay in us. based on 'power on clock',325325+ * therefore in usec326326+ */327327+ set = KAL_DELAY * 1000;328328+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);329329+330330+ /*331331+ * Create keep alive pattern to respond to beacons332332+ */333333+ ath9k_wow_create_keep_alive_pattern(ah);334334+335335+ /*336336+ * Configure MAC WoW Registers337337+ */338338+ set = 0;339339+ /* Send keep alive timeouts anyway */340340+ clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;341341+342342+ if (pattern_enable & AH_WOW_LINK_CHANGE)343343+ wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;344344+ else345345+ set = AR_WOW_KEEP_ALIVE_FAIL_DIS;346346+347347+ set = AR_WOW_KEEP_ALIVE_FAIL_DIS;348348+ REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);349349+350350+ /*351351+ * we are relying on a bmiss failure. ensure we have352352+ * enough threshold to prevent false positives353353+ */354354+ REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,355355+ AR_WOW_BMISSTHRESHOLD);356356+357357+ set = 0;358358+ clr = 0;359359+360360+ if (pattern_enable & AH_WOW_BEACON_MISS) {361361+ set = AR_WOW_BEACON_FAIL_EN;362362+ wow_event_mask |= AR_WOW_BEACON_FAIL;363363+ } else {364364+ clr = AR_WOW_BEACON_FAIL_EN;365365+ }366366+367367+ REG_RMW(ah, AR_WOW_BCN_EN, set, clr);368368+369369+ set = 0;370370+ clr = 0;371371+ /*372372+ * Enable the magic packet registers373373+ */374374+ if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {375375+ set = AR_WOW_MAGIC_EN;376376+ wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;377377+ } else {378378+ clr = AR_WOW_MAGIC_EN;379379+ }380380+ set |= AR_WOW_MAC_INTR_EN;381381+ REG_RMW(ah, AR_WOW_PATTERN, set, clr);382382+383383+ REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,384384+ AR_WOW_PATTERN_SUPPORTED);385385+386386+ /*387387+ * Set the power states appropriately and enable PME388388+ */389389+ clr = 0;390390+ set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |391391+ AR_PMCTRL_PWR_PM_CTRL_ENA;392392+393393+ clr = AR_PCIE_PM_CTRL_ENA;394394+ REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);395395+396396+ /*397397+ * this is needed to prevent the chip waking up398398+ * the host within 3-4 seconds with certain399399+ * platform/BIOS. The fix is to enable400400+ * D1 & D3 to match original definition and401401+ * also match the OTP value. Anyway this402402+ * is more related to SW WOW.403403+ */404404+ clr = AR_PMCTRL_PWR_STATE_D1D3;405405+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);406406+407407+ set = AR_PMCTRL_PWR_STATE_D1D3_REAL;408408+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);409409+410410+ REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);411411+412412+ /* to bring down WOW power low margin */413413+ set = BIT(13);414414+ REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);415415+ /* HW WoW */416416+ clr = BIT(5);417417+ REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);418418+419419+ ath9k_hw_set_powermode_wow_sleep(ah);420420+ ah->wow_event_mask = wow_event_mask;421421+}422422+EXPORT_SYMBOL(ath9k_hw_wow_enable);
···11+/*22+ * Copyright (c) 2010-2011 Atheros Communications Inc.33+ * Copyright (c) 2011-2012 Qualcomm Atheros Inc.44+ *55+ * Permission to use, copy, modify, and/or distribute this software for any66+ * purpose with or without fee is hereby granted, provided that the above77+ * copyright notice and this permission notice appear in all copies.88+ *99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1616+ */1717+1818+#ifndef INITVALS_9565_1P1_H1919+#define INITVALS_9565_1P1_H2020+2121+/* AR9565 1.1 */2222+2323+#define ar9565_1p1_mac_core ar9565_1p0_mac_core2424+2525+#define ar9565_1p1_mac_postamble ar9565_1p0_mac_postamble2626+2727+#define ar9565_1p1_baseband_core ar9565_1p0_baseband_core2828+2929+#define ar9565_1p1_baseband_postamble ar9565_1p0_baseband_postamble3030+3131+#define ar9565_1p1_radio_core ar9565_1p0_radio_core3232+3333+#define ar9565_1p1_soc_preamble ar9565_1p0_soc_preamble3434+3535+#define ar9565_1p1_soc_postamble ar9565_1p0_soc_postamble3636+3737+#define ar9565_1p1_Common_rx_gain_table ar9565_1p0_Common_rx_gain_table3838+3939+#define ar9565_1p1_Modes_lowest_ob_db_tx_gain_table ar9565_1p0_Modes_lowest_ob_db_tx_gain_table4040+4141+#define ar9565_1p1_pciephy_clkreq_disable_L1 ar9565_1p0_pciephy_clkreq_disable_L14242+4343+#define ar9565_1p1_modes_fast_clock ar9565_1p0_modes_fast_clock4444+4545+#define ar9565_1p1_common_wo_xlna_rx_gain_table ar9565_1p0_common_wo_xlna_rx_gain_table4646+4747+#define ar9565_1p1_modes_low_ob_db_tx_gain_table ar9565_1p0_modes_low_ob_db_tx_gain_table4848+4949+#define ar9565_1p1_modes_high_ob_db_tx_gain_table ar9565_1p0_modes_high_ob_db_tx_gain_table5050+5151+#define ar9565_1p1_modes_high_power_tx_gain_table ar9565_1p0_modes_high_power_tx_gain_table5252+5353+#define ar9565_1p1_baseband_core_txfir_coeff_japan_2484 ar9565_1p0_baseband_core_txfir_coeff_japan_24845454+5555+static const u32 ar9565_1p1_radio_postamble[][5] = {5656+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */5757+ {0x0001609c, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524, 0x0b8ee524},5858+ {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},5959+ {0x000160b0, 0x01d67f70, 0x01d67f70, 0x01d67f70, 0x01d67f70},6060+ {0x0001610c, 0x40000000, 0x40000000, 0x40000000, 0x40000000},6161+ {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},6262+};6363+6464+#endif /* INITVALS_9565_1P1_H */
···11+/*22+ * Copyright (c) 2013 Qualcomm Atheros, Inc.33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR1111+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN1313+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF1414+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+1717+#include "ath9k.h"1818+1919+static void ath9k_tx99_stop(struct ath_softc *sc)2020+{2121+ struct ath_hw *ah = sc->sc_ah;2222+ struct ath_common *common = ath9k_hw_common(ah);2323+2424+ ath_drain_all_txq(sc);2525+ ath_startrecv(sc);2626+2727+ ath9k_hw_set_interrupts(ah);2828+ ath9k_hw_enable_interrupts(ah);2929+3030+ ieee80211_wake_queues(sc->hw);3131+3232+ kfree_skb(sc->tx99_skb);3333+ sc->tx99_skb = NULL;3434+ sc->tx99_state = false;3535+3636+ ath9k_hw_tx99_stop(sc->sc_ah);3737+ ath_dbg(common, XMIT, "TX99 stopped\n");3838+}3939+4040+static struct sk_buff *ath9k_build_tx99_skb(struct ath_softc *sc)4141+{4242+ static u8 PN9Data[] = {0xff, 0x87, 0xb8, 0x59, 0xb7, 0xa1, 0xcc, 0x24,4343+ 0x57, 0x5e, 0x4b, 0x9c, 0x0e, 0xe9, 0xea, 0x50,4444+ 0x2a, 0xbe, 0xb4, 0x1b, 0xb6, 0xb0, 0x5d, 0xf1,4545+ 0xe6, 0x9a, 0xe3, 0x45, 0xfd, 0x2c, 0x53, 0x18,4646+ 0x0c, 0xca, 0xc9, 0xfb, 0x49, 0x37, 0xe5, 0xa8,4747+ 0x51, 0x3b, 0x2f, 0x61, 0xaa, 0x72, 0x18, 0x84,4848+ 0x02, 0x23, 0x23, 0xab, 0x63, 0x89, 0x51, 0xb3,4949+ 0xe7, 0x8b, 0x72, 0x90, 0x4c, 0xe8, 0xfb, 0xc0};5050+ u32 len = 1200;5151+ struct ieee80211_hw *hw = sc->hw;5252+ struct ieee80211_hdr *hdr;5353+ struct ieee80211_tx_info *tx_info;5454+ struct sk_buff *skb;5555+5656+ skb = alloc_skb(len, GFP_KERNEL);5757+ if (!skb)5858+ return NULL;5959+6060+ skb_put(skb, len);6161+6262+ memset(skb->data, 0, len);6363+6464+ hdr = (struct ieee80211_hdr *)skb->data;6565+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA);6666+ hdr->duration_id = 0;6767+6868+ memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN);6969+ memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);7070+ memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);7171+7272+ hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);7373+7474+ tx_info = IEEE80211_SKB_CB(skb);7575+ memset(tx_info, 0, sizeof(*tx_info));7676+ tx_info->band = hw->conf.chandef.chan->band;7777+ tx_info->flags = IEEE80211_TX_CTL_NO_ACK;7878+ tx_info->control.vif = sc->tx99_vif;7979+ tx_info->control.rates[0].count = 1;8080+8181+ memcpy(skb->data + sizeof(*hdr), PN9Data, sizeof(PN9Data));8282+8383+ return skb;8484+}8585+8686+static void ath9k_tx99_deinit(struct ath_softc *sc)8787+{8888+ ath_reset(sc);8989+9090+ ath9k_ps_wakeup(sc);9191+ ath9k_tx99_stop(sc);9292+ ath9k_ps_restore(sc);9393+}9494+9595+static int ath9k_tx99_init(struct ath_softc *sc)9696+{9797+ struct ieee80211_hw *hw = sc->hw;9898+ struct ath_hw *ah = sc->sc_ah;9999+ struct ath_common *common = ath9k_hw_common(ah);100100+ struct ath_tx_control txctl;101101+ int r;102102+103103+ if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {104104+ ath_err(common,105105+ "driver is in invalid state unable to use TX99");106106+ return -EINVAL;107107+ }108108+109109+ sc->tx99_skb = ath9k_build_tx99_skb(sc);110110+ if (!sc->tx99_skb)111111+ return -ENOMEM;112112+113113+ memset(&txctl, 0, sizeof(txctl));114114+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO];115115+116116+ ath_reset(sc);117117+118118+ ath9k_ps_wakeup(sc);119119+120120+ ath9k_hw_disable_interrupts(ah);121121+ atomic_set(&ah->intr_ref_cnt, -1);122122+ ath_drain_all_txq(sc);123123+ ath_stoprecv(sc);124124+125125+ sc->tx99_state = true;126126+127127+ ieee80211_stop_queues(hw);128128+129129+ if (sc->tx99_power == MAX_RATE_POWER + 1)130130+ sc->tx99_power = MAX_RATE_POWER;131131+132132+ ath9k_hw_tx99_set_txpower(ah, sc->tx99_power);133133+ r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl);134134+ if (r) {135135+ ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n");136136+ return r;137137+ }138138+139139+ ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n",140140+ sc->tx99_power,141141+ sc->tx99_power / 2);142142+143143+ /* We leave the harware awake as it will be chugging on */144144+145145+ return 0;146146+}147147+148148+static ssize_t read_file_tx99(struct file *file, char __user *user_buf,149149+ size_t count, loff_t *ppos)150150+{151151+ struct ath_softc *sc = file->private_data;152152+ char buf[3];153153+ unsigned int len;154154+155155+ len = sprintf(buf, "%d\n", sc->tx99_state);156156+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);157157+}158158+159159+static ssize_t write_file_tx99(struct file *file, const char __user *user_buf,160160+ size_t count, loff_t *ppos)161161+{162162+ struct ath_softc *sc = file->private_data;163163+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);164164+ char buf[32];165165+ bool start;166166+ ssize_t len;167167+ int r;168168+169169+ if (sc->nvifs > 1)170170+ return -EOPNOTSUPP;171171+172172+ len = min(count, sizeof(buf) - 1);173173+ if (copy_from_user(buf, user_buf, len))174174+ return -EFAULT;175175+176176+ if (strtobool(buf, &start))177177+ return -EINVAL;178178+179179+ if (start == sc->tx99_state) {180180+ if (!start)181181+ return count;182182+ ath_dbg(common, XMIT, "Resetting TX99\n");183183+ ath9k_tx99_deinit(sc);184184+ }185185+186186+ if (!start) {187187+ ath9k_tx99_deinit(sc);188188+ return count;189189+ }190190+191191+ r = ath9k_tx99_init(sc);192192+ if (r)193193+ return r;194194+195195+ return count;196196+}197197+198198+static const struct file_operations fops_tx99 = {199199+ .read = read_file_tx99,200200+ .write = write_file_tx99,201201+ .open = simple_open,202202+ .owner = THIS_MODULE,203203+ .llseek = default_llseek,204204+};205205+206206+static ssize_t read_file_tx99_power(struct file *file,207207+ char __user *user_buf,208208+ size_t count, loff_t *ppos)209209+{210210+ struct ath_softc *sc = file->private_data;211211+ char buf[32];212212+ unsigned int len;213213+214214+ len = sprintf(buf, "%d (%d dBm)\n",215215+ sc->tx99_power,216216+ sc->tx99_power / 2);217217+218218+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);219219+}220220+221221+static ssize_t write_file_tx99_power(struct file *file,222222+ const char __user *user_buf,223223+ size_t count, loff_t *ppos)224224+{225225+ struct ath_softc *sc = file->private_data;226226+ int r;227227+ u8 tx_power;228228+229229+ r = kstrtou8_from_user(user_buf, count, 0, &tx_power);230230+ if (r)231231+ return r;232232+233233+ if (tx_power > MAX_RATE_POWER)234234+ return -EINVAL;235235+236236+ sc->tx99_power = tx_power;237237+238238+ ath9k_ps_wakeup(sc);239239+ ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power);240240+ ath9k_ps_restore(sc);241241+242242+ return count;243243+}244244+245245+static const struct file_operations fops_tx99_power = {246246+ .read = read_file_tx99_power,247247+ .write = write_file_tx99_power,248248+ .open = simple_open,249249+ .owner = THIS_MODULE,250250+ .llseek = default_llseek,251251+};252252+253253+void ath9k_tx99_init_debug(struct ath_softc *sc)254254+{255255+ if (!AR_SREV_9300_20_OR_LATER(sc->sc_ah))256256+ return;257257+258258+ debugfs_create_file("tx99", S_IRUSR | S_IWUSR,259259+ sc->debug.debugfs_phy, sc,260260+ &fops_tx99);261261+ debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR,262262+ sc->debug.debugfs_phy, sc,263263+ &fops_tx99_power);264264+}
+323-384
drivers/net/wireless/ath/ath9k/wow.c
···11/*22- * Copyright (c) 2012 Qualcomm Atheros, Inc.22+ * Copyright (c) 2013 Qualcomm Atheros, Inc.33 *44 * Permission to use, copy, modify, and/or distribute this software for any55 * purpose with or without fee is hereby granted, provided that the above···1414 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515 */16161717-#include <linux/export.h>1817#include "ath9k.h"1919-#include "reg.h"2020-#include "hw-ops.h"21182222-const char *ath9k_hw_wow_event_to_string(u32 wow_event)1919+static const struct wiphy_wowlan_support ath9k_wowlan_support = {2020+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,2121+ .n_patterns = MAX_NUM_USER_PATTERN,2222+ .pattern_min_len = 1,2323+ .pattern_max_len = MAX_PATTERN_SIZE,2424+};2525+2626+static void ath9k_wow_map_triggers(struct ath_softc *sc,2727+ struct cfg80211_wowlan *wowlan,2828+ u32 *wow_triggers)2329{2424- if (wow_event & AH_WOW_MAGIC_PATTERN_EN)2525- return "Magic pattern";2626- if (wow_event & AH_WOW_USER_PATTERN_EN)2727- return "User pattern";2828- if (wow_event & AH_WOW_LINK_CHANGE)2929- return "Link change";3030- if (wow_event & AH_WOW_BEACON_MISS)3131- return "Beacon miss";3030+ if (wowlan->disconnect)3131+ *wow_triggers |= AH_WOW_LINK_CHANGE |3232+ AH_WOW_BEACON_MISS;3333+ if (wowlan->magic_pkt)3434+ *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;32353333- return "unknown reason";3636+ if (wowlan->n_patterns)3737+ *wow_triggers |= AH_WOW_USER_PATTERN_EN;3838+3939+ sc->wow_enabled = *wow_triggers;4040+3441}3535-EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);36423737-static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)4343+static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)3844{4545+ struct ath_hw *ah = sc->sc_ah;3946 struct ath_common *common = ath9k_hw_common(ah);4747+ int pattern_count = 0;4848+ int i, byte_cnt;4949+ u8 dis_deauth_pattern[MAX_PATTERN_SIZE];5050+ u8 dis_deauth_mask[MAX_PATTERN_SIZE];40514141- REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV);5252+ memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE);5353+ memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE);42544343- /* set rx disable bit */4444- REG_WRITE(ah, AR_CR, AR_CR_RXD);5555+ /*5656+ * Create Dissassociate / Deauthenticate packet filter5757+ *5858+ * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes5959+ * +--------------+----------+---------+--------+--------+----6060+ * + Frame Control+ Duration + DA + SA + BSSID +6161+ * +--------------+----------+---------+--------+--------+----6262+ *6363+ * The above is the management frame format for disassociate/6464+ * deauthenticate pattern, from this we need to match the first byte6565+ * of 'Frame Control' and DA, SA, and BSSID fields6666+ * (skipping 2nd byte of FC and Duration feild.6767+ *6868+ * Disassociate pattern6969+ * --------------------7070+ * Frame control = 00 00 10107171+ * DA, SA, BSSID = x:x:x:x:x:x7272+ * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x7373+ * | x:x:x:x:x:x -- 22 bytes7474+ *7575+ * Deauthenticate pattern7676+ * ----------------------7777+ * Frame control = 00 00 11007878+ * DA, SA, BSSID = x:x:x:x:x:x7979+ * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x8080+ * | x:x:x:x:x:x -- 22 bytes8181+ */45824646- if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) {4747- ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",4848- REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));8383+ /* Create Disassociate Pattern first */8484+8585+ byte_cnt = 0;8686+8787+ /* Fill out the mask with all FF's */8888+8989+ for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)9090+ dis_deauth_mask[i] = 0xff;9191+9292+ /* copy the first byte of frame control field */9393+ dis_deauth_pattern[byte_cnt] = 0xa0;9494+ byte_cnt++;9595+9696+ /* skip 2nd byte of frame control and Duration field */9797+ byte_cnt += 3;9898+9999+ /*100100+ * need not match the destination mac address, it can be a broadcast101101+ * mac address or an unicast to this station102102+ */103103+ byte_cnt += 6;104104+105105+ /* copy the source mac address */106106+ memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);107107+108108+ byte_cnt += 6;109109+110110+ /* copy the bssid, its same as the source mac address */111111+112112+ memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);113113+114114+ /* Create Disassociate pattern mask */115115+116116+ dis_deauth_mask[0] = 0xfe;117117+ dis_deauth_mask[1] = 0x03;118118+ dis_deauth_mask[2] = 0xc0;119119+120120+ ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");121121+122122+ ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,123123+ pattern_count, byte_cnt);124124+125125+ pattern_count++;126126+ /*127127+ * for de-authenticate pattern, only the first byte of the frame128128+ * control field gets changed from 0xA0 to 0xC0129129+ */130130+ dis_deauth_pattern[0] = 0xC0;131131+132132+ ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,133133+ pattern_count, byte_cnt);134134+135135+}136136+137137+static void ath9k_wow_add_pattern(struct ath_softc *sc,138138+ struct cfg80211_wowlan *wowlan)139139+{140140+ struct ath_hw *ah = sc->sc_ah;141141+ struct ath9k_wow_pattern *wow_pattern = NULL;142142+ struct cfg80211_pkt_pattern *patterns = wowlan->patterns;143143+ int mask_len;144144+ s8 i = 0;145145+146146+ if (!wowlan->n_patterns)49147 return;5050- }5151-5252- REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);5353-}5454-5555-static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)5656-{5757- struct ath_common *common = ath9k_hw_common(ah);5858- u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN];5959- u32 ctl[13] = {0};6060- u32 data_word[KAL_NUM_DATA_WORDS];6161- u8 i;6262- u32 wow_ka_data_word0;6363-6464- memcpy(sta_mac_addr, common->macaddr, ETH_ALEN);6565- memcpy(ap_mac_addr, common->curbssid, ETH_ALEN);6666-6767- /* set the transmit buffer */6868- ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));6969- ctl[1] = 0;7070- ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */7171- ctl[4] = 0;7272- ctl[7] = (ah->txchainmask) << 2;7373- ctl[2] = 0xf << 16; /* tx_tries 0 */7474-7575- for (i = 0; i < KAL_NUM_DESC_WORDS; i++)7676- REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);7777-7878- REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);7979-8080- data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) |8181- (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16);8282- data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |8383- (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);8484- data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) |8585- (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);8686- data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) |8787- (sta_mac_addr[3] << 8) | (sta_mac_addr[2]);8888- data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) |8989- (ap_mac_addr[1] << 8) | (ap_mac_addr[0]);9090- data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]);9191-9292- if (AR_SREV_9462_20(ah)) {9393- /* AR9462 2.0 has an extra descriptor word (time based9494- * discard) compared to other chips */9595- REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0);9696- wow_ka_data_word0 = AR_WOW_TXBUF(13);9797- } else {9898- wow_ka_data_word0 = AR_WOW_TXBUF(12);9999- }100100-101101- for (i = 0; i < KAL_NUM_DATA_WORDS; i++)102102- REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]);103103-104104-}105105-106106-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,107107- u8 *user_mask, int pattern_count,108108- int pattern_len)109109-{110110- int i;111111- u32 pattern_val, mask_val;112112- u32 set, clr;113113-114114- /* FIXME: should check count by querying the hardware capability */115115- if (pattern_count >= MAX_NUM_PATTERN)116116- return;117117-118118- REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));119119-120120- /* set the registers for pattern */121121- for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {122122- memcpy(&pattern_val, user_pattern, 4);123123- REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),124124- pattern_val);125125- user_pattern += 4;126126- }127127-128128- /* set the registers for mask */129129- for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {130130- memcpy(&mask_val, user_mask, 4);131131- REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);132132- user_mask += 4;133133- }134134-135135- /* set the pattern length to be matched136136- *137137- * AR_WOW_LENGTH1_REG1138138- * bit 31:24 pattern 0 length139139- * bit 23:16 pattern 1 length140140- * bit 15:8 pattern 2 length141141- * bit 7:0 pattern 3 length142142- *143143- * AR_WOW_LENGTH1_REG2144144- * bit 31:24 pattern 4 length145145- * bit 23:16 pattern 5 length146146- * bit 15:8 pattern 6 length147147- * bit 7:0 pattern 7 length148148- *149149- * the below logic writes out the new150150- * pattern length for the corresponding151151- * pattern_count, while masking out the152152- * other fields153153- */154154-155155- ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);156156-157157- if (pattern_count < 4) {158158- /* Pattern 0-3 uses AR_WOW_LENGTH1 register */159159- set = (pattern_len & AR_WOW_LENGTH_MAX) <<160160- AR_WOW_LEN1_SHIFT(pattern_count);161161- clr = AR_WOW_LENGTH1_MASK(pattern_count);162162- REG_RMW(ah, AR_WOW_LENGTH1, set, clr);163163- } else {164164- /* Pattern 4-7 uses AR_WOW_LENGTH2 register */165165- set = (pattern_len & AR_WOW_LENGTH_MAX) <<166166- AR_WOW_LEN2_SHIFT(pattern_count);167167- clr = AR_WOW_LENGTH2_MASK(pattern_count);168168- REG_RMW(ah, AR_WOW_LENGTH2, set, clr);169169- }170170-171171-}172172-EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);173173-174174-u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)175175-{176176- u32 wow_status = 0;177177- u32 val = 0, rval;178148179149 /*180180- * read the WoW status register to know181181- * the wakeup reason150150+ * Add the new user configured patterns182151 */183183- rval = REG_READ(ah, AR_WOW_PATTERN);184184- val = AR_WOW_STATUS(rval);152152+ for (i = 0; i < wowlan->n_patterns; i++) {185153186186- /*187187- * mask only the WoW events that we have enabled. Sometimes188188- * we have spurious WoW events from the AR_WOW_PATTERN189189- * register. This mask will clean it up.190190- */154154+ wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);191155192192- val &= ah->wow_event_mask;156156+ if (!wow_pattern)157157+ return;193158194194- if (val) {195195- if (val & AR_WOW_MAGIC_PAT_FOUND)196196- wow_status |= AH_WOW_MAGIC_PATTERN_EN;197197- if (AR_WOW_PATTERN_FOUND(val))198198- wow_status |= AH_WOW_USER_PATTERN_EN;199199- if (val & AR_WOW_KEEP_ALIVE_FAIL)200200- wow_status |= AH_WOW_LINK_CHANGE;201201- if (val & AR_WOW_BEACON_FAIL)202202- wow_status |= AH_WOW_BEACON_MISS;203203- }204204-205205- /*206206- * set and clear WOW_PME_CLEAR registers for the chip to207207- * generate next wow signal.208208- * disable D3 before accessing other registers ?209209- */210210-211211- /* do we need to check the bit value 0x01000000 (7-10) ?? */212212- REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR,213213- AR_PMCTRL_PWR_STATE_D1D3);214214-215215- /*216216- * clear all events217217- */218218- REG_WRITE(ah, AR_WOW_PATTERN,219219- AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN)));220220-221221- /*222222- * restore the beacon threshold to init value223223- */224224- REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR);225225-226226- /*227227- * Restore the way the PCI-E reset, Power-On-Reset, external228228- * PCIE_POR_SHORT pins are tied to its original value.229229- * Previously just before WoW sleep, we untie the PCI-E230230- * reset to our Chip's Power On Reset so that any PCI-E231231- * reset from the bus will not reset our chip232232- */233233- if (ah->is_pciexpress)234234- ath9k_hw_configpcipowersave(ah, false);235235-236236- ah->wow_event_mask = 0;237237-238238- return wow_status;239239-}240240-EXPORT_SYMBOL(ath9k_hw_wow_wakeup);241241-242242-void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)243243-{244244- u32 wow_event_mask;245245- u32 set, clr;246246-247247- /*248248- * wow_event_mask is a mask to the AR_WOW_PATTERN register to249249- * indicate which WoW events we have enabled. The WoW events250250- * are from the 'pattern_enable' in this function and251251- * 'pattern_count' of ath9k_hw_wow_apply_pattern()252252- */253253- wow_event_mask = ah->wow_event_mask;254254-255255- /*256256- * Untie Power-on-Reset from the PCI-E-Reset. When we are in257257- * WOW sleep, we do want the Reset from the PCI-E to disturb258258- * our hw state259259- */260260- if (ah->is_pciexpress) {261159 /*262262- * we need to untie the internal POR (power-on-reset)263263- * to the external PCI-E reset. We also need to tie264264- * the PCI-E Phy reset to the PCI-E reset.160160+ * TODO: convert the generic user space pattern to161161+ * appropriate chip specific/802.11 pattern.265162 */266266- set = AR_WA_RESET_EN | AR_WA_POR_SHORT;267267- clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;268268- REG_RMW(ah, AR_WA, set, clr);163163+164164+ mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);165165+ memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);166166+ memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);167167+ memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,168168+ patterns[i].pattern_len);169169+ memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);170170+ wow_pattern->pattern_len = patterns[i].pattern_len;171171+172172+ /*173173+ * just need to take care of deauth and disssoc pattern,174174+ * make sure we don't overwrite them.175175+ */176176+177177+ ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,178178+ wow_pattern->mask_bytes,179179+ i + 2,180180+ wow_pattern->pattern_len);181181+ kfree(wow_pattern);182182+269183 }270184271271- /*272272- * set the power states appropriately and enable PME273273- */274274- set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |275275- AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;276276-277277- /*278278- * set and clear WOW_PME_CLEAR registers for the chip279279- * to generate next wow signal.280280- */281281- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);282282- clr = AR_PMCTRL_WOW_PME_CLR;283283- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);284284-285285- /*286286- * Setup for:287287- * - beacon misses288288- * - magic pattern289289- * - keep alive timeout290290- * - pattern matching291291- */292292-293293- /*294294- * Program default values for pattern backoff, aifs/slot/KAL count,295295- * beacon miss timeout, KAL timeout, etc.296296- */297297- set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);298298- REG_SET_BIT(ah, AR_WOW_PATTERN, set);299299-300300- set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |301301- AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |302302- AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);303303- REG_SET_BIT(ah, AR_WOW_COUNT, set);304304-305305- if (pattern_enable & AH_WOW_BEACON_MISS)306306- set = AR_WOW_BEACON_TIMO;307307- /* We are not using beacon miss, program a large value */308308- else309309- set = AR_WOW_BEACON_TIMO_MAX;310310-311311- REG_WRITE(ah, AR_WOW_BCN_TIMO, set);312312-313313- /*314314- * Keep alive timo in ms except AR9280315315- */316316- if (!pattern_enable)317317- set = AR_WOW_KEEP_ALIVE_NEVER;318318- else319319- set = KAL_TIMEOUT * 32;320320-321321- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);322322-323323- /*324324- * Keep alive delay in us. based on 'power on clock',325325- * therefore in usec326326- */327327- set = KAL_DELAY * 1000;328328- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);329329-330330- /*331331- * Create keep alive pattern to respond to beacons332332- */333333- ath9k_wow_create_keep_alive_pattern(ah);334334-335335- /*336336- * Configure MAC WoW Registers337337- */338338- set = 0;339339- /* Send keep alive timeouts anyway */340340- clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;341341-342342- if (pattern_enable & AH_WOW_LINK_CHANGE)343343- wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;344344- else345345- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;346346-347347- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;348348- REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);349349-350350- /*351351- * we are relying on a bmiss failure. ensure we have352352- * enough threshold to prevent false positives353353- */354354- REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,355355- AR_WOW_BMISSTHRESHOLD);356356-357357- set = 0;358358- clr = 0;359359-360360- if (pattern_enable & AH_WOW_BEACON_MISS) {361361- set = AR_WOW_BEACON_FAIL_EN;362362- wow_event_mask |= AR_WOW_BEACON_FAIL;363363- } else {364364- clr = AR_WOW_BEACON_FAIL_EN;365365- }366366-367367- REG_RMW(ah, AR_WOW_BCN_EN, set, clr);368368-369369- set = 0;370370- clr = 0;371371- /*372372- * Enable the magic packet registers373373- */374374- if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {375375- set = AR_WOW_MAGIC_EN;376376- wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;377377- } else {378378- clr = AR_WOW_MAGIC_EN;379379- }380380- set |= AR_WOW_MAC_INTR_EN;381381- REG_RMW(ah, AR_WOW_PATTERN, set, clr);382382-383383- REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,384384- AR_WOW_PATTERN_SUPPORTED);385385-386386- /*387387- * Set the power states appropriately and enable PME388388- */389389- clr = 0;390390- set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |391391- AR_PMCTRL_PWR_PM_CTRL_ENA;392392-393393- clr = AR_PCIE_PM_CTRL_ENA;394394- REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);395395-396396- /*397397- * this is needed to prevent the chip waking up398398- * the host within 3-4 seconds with certain399399- * platform/BIOS. The fix is to enable400400- * D1 & D3 to match original definition and401401- * also match the OTP value. Anyway this402402- * is more related to SW WOW.403403- */404404- clr = AR_PMCTRL_PWR_STATE_D1D3;405405- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);406406-407407- set = AR_PMCTRL_PWR_STATE_D1D3_REAL;408408- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);409409-410410- REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);411411-412412- /* to bring down WOW power low margin */413413- set = BIT(13);414414- REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);415415- /* HW WoW */416416- clr = BIT(5);417417- REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);418418-419419- ath9k_hw_set_powermode_wow_sleep(ah);420420- ah->wow_event_mask = wow_event_mask;421185}422422-EXPORT_SYMBOL(ath9k_hw_wow_enable);186186+187187+int ath9k_suspend(struct ieee80211_hw *hw,188188+ struct cfg80211_wowlan *wowlan)189189+{190190+ struct ath_softc *sc = hw->priv;191191+ struct ath_hw *ah = sc->sc_ah;192192+ struct ath_common *common = ath9k_hw_common(ah);193193+ u32 wow_triggers_enabled = 0;194194+ int ret = 0;195195+196196+ mutex_lock(&sc->mutex);197197+198198+ ath_cancel_work(sc);199199+ ath_stop_ani(sc);200200+ del_timer_sync(&sc->rx_poll_timer);201201+202202+ if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {203203+ ath_dbg(common, ANY, "Device not present\n");204204+ ret = -EINVAL;205205+ goto fail_wow;206206+ }207207+208208+ if (WARN_ON(!wowlan)) {209209+ ath_dbg(common, WOW, "None of the WoW triggers enabled\n");210210+ ret = -EINVAL;211211+ goto fail_wow;212212+ }213213+214214+ if (!device_can_wakeup(sc->dev)) {215215+ ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");216216+ ret = 1;217217+ goto fail_wow;218218+ }219219+220220+ /*221221+ * none of the sta vifs are associated222222+ * and we are not currently handling multivif223223+ * cases, for instance we have to seperately224224+ * configure 'keep alive frame' for each225225+ * STA.226226+ */227227+228228+ if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {229229+ ath_dbg(common, WOW, "None of the STA vifs are associated\n");230230+ ret = 1;231231+ goto fail_wow;232232+ }233233+234234+ if (sc->nvifs > 1) {235235+ ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");236236+ ret = 1;237237+ goto fail_wow;238238+ }239239+240240+ ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);241241+242242+ ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",243243+ wow_triggers_enabled);244244+245245+ ath9k_ps_wakeup(sc);246246+247247+ ath9k_stop_btcoex(sc);248248+249249+ /*250250+ * Enable wake up on recieving disassoc/deauth251251+ * frame by default.252252+ */253253+ ath9k_wow_add_disassoc_deauth_pattern(sc);254254+255255+ if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)256256+ ath9k_wow_add_pattern(sc, wowlan);257257+258258+ spin_lock_bh(&sc->sc_pcu_lock);259259+ /*260260+ * To avoid false wake, we enable beacon miss interrupt only261261+ * when we go to sleep. We save the current interrupt mask262262+ * so we can restore it after the system wakes up263263+ */264264+ sc->wow_intr_before_sleep = ah->imask;265265+ ah->imask &= ~ATH9K_INT_GLOBAL;266266+ ath9k_hw_disable_interrupts(ah);267267+ ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL;268268+ ath9k_hw_set_interrupts(ah);269269+ ath9k_hw_enable_interrupts(ah);270270+271271+ spin_unlock_bh(&sc->sc_pcu_lock);272272+273273+ /*274274+ * we can now sync irq and kill any running tasklets, since we already275275+ * disabled interrupts and not holding a spin lock276276+ */277277+ synchronize_irq(sc->irq);278278+ tasklet_kill(&sc->intr_tq);279279+280280+ ath9k_hw_wow_enable(ah, wow_triggers_enabled);281281+282282+ ath9k_ps_restore(sc);283283+ ath_dbg(common, ANY, "WoW enabled in ath9k\n");284284+ atomic_inc(&sc->wow_sleep_proc_intr);285285+286286+fail_wow:287287+ mutex_unlock(&sc->mutex);288288+ return ret;289289+}290290+291291+int ath9k_resume(struct ieee80211_hw *hw)292292+{293293+ struct ath_softc *sc = hw->priv;294294+ struct ath_hw *ah = sc->sc_ah;295295+ struct ath_common *common = ath9k_hw_common(ah);296296+ u32 wow_status;297297+298298+ mutex_lock(&sc->mutex);299299+300300+ ath9k_ps_wakeup(sc);301301+302302+ spin_lock_bh(&sc->sc_pcu_lock);303303+304304+ ath9k_hw_disable_interrupts(ah);305305+ ah->imask = sc->wow_intr_before_sleep;306306+ ath9k_hw_set_interrupts(ah);307307+ ath9k_hw_enable_interrupts(ah);308308+309309+ spin_unlock_bh(&sc->sc_pcu_lock);310310+311311+ wow_status = ath9k_hw_wow_wakeup(ah);312312+313313+ if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {314314+ /*315315+ * some devices may not pick beacon miss316316+ * as the reason they woke up so we add317317+ * that here for that shortcoming.318318+ */319319+ wow_status |= AH_WOW_BEACON_MISS;320320+ atomic_dec(&sc->wow_got_bmiss_intr);321321+ ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");322322+ }323323+324324+ atomic_dec(&sc->wow_sleep_proc_intr);325325+326326+ if (wow_status) {327327+ ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",328328+ ath9k_hw_wow_event_to_string(wow_status), wow_status);329329+ }330330+331331+ ath_restart_work(sc);332332+ ath9k_start_btcoex(sc);333333+334334+ ath9k_ps_restore(sc);335335+ mutex_unlock(&sc->mutex);336336+337337+ return 0;338338+}339339+340340+void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)341341+{342342+ struct ath_softc *sc = hw->priv;343343+344344+ mutex_lock(&sc->mutex);345345+ device_init_wakeup(sc->dev, 1);346346+ device_set_wakeup_enable(sc->dev, enabled);347347+ mutex_unlock(&sc->mutex);348348+}349349+350350+void ath9k_init_wow(struct ieee80211_hw *hw)351351+{352352+ struct ath_softc *sc = hw->priv;353353+354354+ if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&355355+ (sc->driver_data & ATH9K_PCI_WOW) &&356356+ device_can_wakeup(sc->dev))357357+ hw->wiphy->wowlan = &ath9k_wowlan_support;358358+359359+ atomic_set(&sc->wow_sleep_proc_intr, -1);360360+ atomic_set(&sc->wow_got_bmiss_intr, -1);361361+}
···37373838/* We enable active scan on these a case by case basis by regulatory domain */3939#define ATH9K_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\4040- NL80211_RRF_PASSIVE_SCAN)4040+ NL80211_RRF_NO_IR)4141#define ATH9K_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\4242- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_OFDM)4242+ NL80211_RRF_NO_IR | \4343+ NL80211_RRF_NO_OFDM)43444445/* We allow IBSS on these on a case by case basis by regulatory domain */4546#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\4646- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)4747+ NL80211_RRF_NO_IR)4748#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\4848- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)4949+ NL80211_RRF_NO_IR)4950#define ATH9K_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\5050- NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS)5151+ NL80211_RRF_NO_IR)51525253#define ATH9K_2GHZ_ALL ATH9K_2GHZ_CH01_11, \5354 ATH9K_2GHZ_CH12_13, \···113112 ATH9K_5GHZ_ALL,114113 }115114};116116-117117-static inline bool is_wwr_sku(u16 regd)118118-{119119- return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&120120- (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||121121- (regd == WORLD));122122-}123123-124124-static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)125125-{126126- return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;127127-}128128-129129-bool ath_is_world_regd(struct ath_regulatory *reg)130130-{131131- return is_wwr_sku(ath_regd_get_eepromRD(reg));132132-}133133-EXPORT_SYMBOL(ath_is_world_regd);134134-135135-static const struct ieee80211_regdomain *ath_default_world_regdomain(void)136136-{137137- /* this is the most restrictive */138138- return &ath_world_regdom_64;139139-}140140-141141-static const struct142142-ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)143143-{144144- switch (reg->regpair->regDmnEnum) {145145- case 0x60:146146- case 0x61:147147- case 0x62:148148- return &ath_world_regdom_60_61_62;149149- case 0x63:150150- case 0x65:151151- return &ath_world_regdom_63_65;152152- case 0x64:153153- return &ath_world_regdom_64;154154- case 0x66:155155- case 0x69:156156- return &ath_world_regdom_66_69;157157- case 0x67:158158- case 0x68:159159- case 0x6A:160160- case 0x6C:161161- return &ath_world_regdom_67_68_6A_6C;162162- default:163163- WARN_ON(1);164164- return ath_default_world_regdomain();165165- }166166-}167167-168168-bool ath_is_49ghz_allowed(u16 regdomain)169169-{170170- /* possibly more */171171- return regdomain == MKK9_MKKC;172172-}173173-EXPORT_SYMBOL(ath_is_49ghz_allowed);174174-175175-/* Frequency is one where radar detection is required */176176-static bool ath_is_radar_freq(u16 center_freq)177177-{178178- return (center_freq >= 5260 && center_freq <= 5700);179179-}180180-181181-/*182182- * N.B: These exception rules do not apply radar freqs.183183- *184184- * - We enable adhoc (or beaconing) if allowed by 11d185185- * - We enable active scan if the channel is allowed by 11d186186- * - If no country IE has been processed and a we determine we have187187- * received a beacon on a channel we can enable active scan and188188- * adhoc (or beaconing).189189- */190190-static void191191-ath_reg_apply_beaconing_flags(struct wiphy *wiphy,192192- enum nl80211_reg_initiator initiator)193193-{194194- enum ieee80211_band band;195195- struct ieee80211_supported_band *sband;196196- const struct ieee80211_reg_rule *reg_rule;197197- struct ieee80211_channel *ch;198198- unsigned int i;199199-200200- for (band = 0; band < IEEE80211_NUM_BANDS; band++) {201201-202202- if (!wiphy->bands[band])203203- continue;204204-205205- sband = wiphy->bands[band];206206-207207- for (i = 0; i < sband->n_channels; i++) {208208-209209- ch = &sband->channels[i];210210-211211- if (ath_is_radar_freq(ch->center_freq) ||212212- (ch->flags & IEEE80211_CHAN_RADAR))213213- continue;214214-215215- if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {216216- reg_rule = freq_reg_info(wiphy, ch->center_freq);217217- if (IS_ERR(reg_rule))218218- continue;219219- /*220220- * If 11d had a rule for this channel ensure221221- * we enable adhoc/beaconing if it allows us to222222- * use it. Note that we would have disabled it223223- * by applying our static world regdomain by224224- * default during init, prior to calling our225225- * regulatory_hint().226226- */227227- if (!(reg_rule->flags &228228- NL80211_RRF_NO_IBSS))229229- ch->flags &=230230- ~IEEE80211_CHAN_NO_IBSS;231231- if (!(reg_rule->flags &232232- NL80211_RRF_PASSIVE_SCAN))233233- ch->flags &=234234- ~IEEE80211_CHAN_PASSIVE_SCAN;235235- } else {236236- if (ch->beacon_found)237237- ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |238238- IEEE80211_CHAN_PASSIVE_SCAN);239239- }240240- }241241- }242242-243243-}244244-245245-/* Allows active scan scan on Ch 12 and 13 */246246-static void247247-ath_reg_apply_active_scan_flags(struct wiphy *wiphy,248248- enum nl80211_reg_initiator initiator)249249-{250250- struct ieee80211_supported_band *sband;251251- struct ieee80211_channel *ch;252252- const struct ieee80211_reg_rule *reg_rule;253253-254254- sband = wiphy->bands[IEEE80211_BAND_2GHZ];255255- if (!sband)256256- return;257257-258258- /*259259- * If no country IE has been received always enable active scan260260- * on these channels. This is only done for specific regulatory SKUs261261- */262262- if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {263263- ch = &sband->channels[11]; /* CH 12 */264264- if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)265265- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;266266- ch = &sband->channels[12]; /* CH 13 */267267- if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)268268- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;269269- return;270270- }271271-272272- /*273273- * If a country IE has been received check its rule for this274274- * channel first before enabling active scan. The passive scan275275- * would have been enforced by the initial processing of our276276- * custom regulatory domain.277277- */278278-279279- ch = &sband->channels[11]; /* CH 12 */280280- reg_rule = freq_reg_info(wiphy, ch->center_freq);281281- if (!IS_ERR(reg_rule)) {282282- if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))283283- if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)284284- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;285285- }286286-287287- ch = &sband->channels[12]; /* CH 13 */288288- reg_rule = freq_reg_info(wiphy, ch->center_freq);289289- if (!IS_ERR(reg_rule)) {290290- if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))291291- if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)292292- ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;293293- }294294-}295295-296296-/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */297297-static void ath_reg_apply_radar_flags(struct wiphy *wiphy)298298-{299299- struct ieee80211_supported_band *sband;300300- struct ieee80211_channel *ch;301301- unsigned int i;302302-303303- if (!wiphy->bands[IEEE80211_BAND_5GHZ])304304- return;305305-306306- sband = wiphy->bands[IEEE80211_BAND_5GHZ];307307-308308- for (i = 0; i < sband->n_channels; i++) {309309- ch = &sband->channels[i];310310- if (!ath_is_radar_freq(ch->center_freq))311311- continue;312312- /* We always enable radar detection/DFS on this313313- * frequency range. Additionally we also apply on314314- * this frequency range:315315- * - If STA mode does not yet have DFS supports disable316316- * active scanning317317- * - If adhoc mode does not support DFS yet then318318- * disable adhoc in the frequency.319319- * - If AP mode does not yet support radar detection/DFS320320- * do not allow AP mode321321- */322322- if (!(ch->flags & IEEE80211_CHAN_DISABLED))323323- ch->flags |= IEEE80211_CHAN_RADAR |324324- IEEE80211_CHAN_NO_IBSS |325325- IEEE80211_CHAN_PASSIVE_SCAN;326326- }327327-}328328-329329-static void ath_reg_apply_world_flags(struct wiphy *wiphy,330330- enum nl80211_reg_initiator initiator,331331- struct ath_regulatory *reg)332332-{333333- switch (reg->regpair->regDmnEnum) {334334- case 0x60:335335- case 0x63:336336- case 0x66:337337- case 0x67:338338- case 0x6C:339339- ath_reg_apply_beaconing_flags(wiphy, initiator);340340- break;341341- case 0x68:342342- ath_reg_apply_beaconing_flags(wiphy, initiator);343343- ath_reg_apply_active_scan_flags(wiphy, initiator);344344- break;345345- }346346-}347347-348348-static u16 ath_regd_find_country_by_name(char *alpha2)349349-{350350- unsigned int i;351351-352352- for (i = 0; i < ARRAY_SIZE(allCountries); i++) {353353- if (!memcmp(allCountries[i].isoName, alpha2, 2))354354- return allCountries[i].countryCode;355355- }356356-357357- return -1;358358-}359359-360360-static int __ath_reg_dyn_country(struct wiphy *wiphy,361361- struct ath_regulatory *reg,362362- struct regulatory_request *request)363363-{364364- u16 country_code;365365-366366- if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&367367- !ath_is_world_regd(reg))368368- return -EINVAL;369369-370370- country_code = ath_regd_find_country_by_name(request->alpha2);371371- if (country_code == (u16) -1)372372- return -EINVAL;373373-374374- reg->current_rd = COUNTRY_ERD_FLAG;375375- reg->current_rd |= country_code;376376-377377- __ath_regd_init(reg);378378-379379- ath_reg_apply_world_flags(wiphy, request->initiator, reg);380380-381381- return 0;382382-}383383-384384-static void ath_reg_dyn_country(struct wiphy *wiphy,385385- struct ath_regulatory *reg,386386- struct regulatory_request *request)387387-{388388- if (__ath_reg_dyn_country(wiphy, reg, request))389389- return;390390-391391- printk(KERN_DEBUG "ath: regdomain 0x%0x "392392- "dynamically updated by %s\n",393393- reg->current_rd,394394- reg_initiator_name(request->initiator));395395-}396115397116static bool dynamic_country_user_possible(struct ath_regulatory *reg)398117{···186465 return true;187466}188467189189-static void ath_reg_dyn_country_user(struct wiphy *wiphy,190190- struct ath_regulatory *reg,191191- struct regulatory_request *request)468468+static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg)192469{193470 if (!config_enabled(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS))194194- return;471471+ return false;195472 if (!dynamic_country_user_possible(reg))473473+ return false;474474+ return true;475475+}476476+477477+static inline bool is_wwr_sku(u16 regd)478478+{479479+ return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) &&480480+ (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||481481+ (regd == WORLD));482482+}483483+484484+static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg)485485+{486486+ return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG;487487+}488488+489489+bool ath_is_world_regd(struct ath_regulatory *reg)490490+{491491+ return is_wwr_sku(ath_regd_get_eepromRD(reg));492492+}493493+EXPORT_SYMBOL(ath_is_world_regd);494494+495495+static const struct ieee80211_regdomain *ath_default_world_regdomain(void)496496+{497497+ /* this is the most restrictive */498498+ return &ath_world_regdom_64;499499+}500500+501501+static const struct502502+ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)503503+{504504+ switch (reg->regpair->regDmnEnum) {505505+ case 0x60:506506+ case 0x61:507507+ case 0x62:508508+ return &ath_world_regdom_60_61_62;509509+ case 0x63:510510+ case 0x65:511511+ return &ath_world_regdom_63_65;512512+ case 0x64:513513+ return &ath_world_regdom_64;514514+ case 0x66:515515+ case 0x69:516516+ return &ath_world_regdom_66_69;517517+ case 0x67:518518+ case 0x68:519519+ case 0x6A:520520+ case 0x6C:521521+ return &ath_world_regdom_67_68_6A_6C;522522+ default:523523+ WARN_ON(1);524524+ return ath_default_world_regdomain();525525+ }526526+}527527+528528+bool ath_is_49ghz_allowed(u16 regdomain)529529+{530530+ /* possibly more */531531+ return regdomain == MKK9_MKKC;532532+}533533+EXPORT_SYMBOL(ath_is_49ghz_allowed);534534+535535+/* Frequency is one where radar detection is required */536536+static bool ath_is_radar_freq(u16 center_freq)537537+{538538+ return (center_freq >= 5260 && center_freq <= 5700);539539+}540540+541541+static void ath_force_clear_no_ir_chan(struct wiphy *wiphy,542542+ struct ieee80211_channel *ch)543543+{544544+ const struct ieee80211_reg_rule *reg_rule;545545+546546+ reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq));547547+ if (IS_ERR(reg_rule))196548 return;197197- ath_reg_dyn_country(wiphy, reg, request);549549+550550+ if (!(reg_rule->flags & NL80211_RRF_NO_IR))551551+ if (ch->flags & IEEE80211_CHAN_NO_IR)552552+ ch->flags &= ~IEEE80211_CHAN_NO_IR;553553+}554554+555555+static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq)556556+{557557+ struct ieee80211_channel *ch;558558+559559+ ch = ieee80211_get_channel(wiphy, center_freq);560560+ if (!ch)561561+ return;562562+563563+ ath_force_clear_no_ir_chan(wiphy, ch);564564+}565565+566566+static void ath_force_no_ir_chan(struct ieee80211_channel *ch)567567+{568568+ ch->flags |= IEEE80211_CHAN_NO_IR;569569+}570570+571571+static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq)572572+{573573+ struct ieee80211_channel *ch;574574+575575+ ch = ieee80211_get_channel(wiphy, center_freq);576576+ if (!ch)577577+ return;578578+579579+ ath_force_no_ir_chan(ch);580580+}581581+582582+static void583583+__ath_reg_apply_beaconing_flags(struct wiphy *wiphy,584584+ struct ath_regulatory *reg,585585+ enum nl80211_reg_initiator initiator,586586+ struct ieee80211_channel *ch)587587+{588588+ if (ath_is_radar_freq(ch->center_freq) ||589589+ (ch->flags & IEEE80211_CHAN_RADAR))590590+ return;591591+592592+ switch (initiator) {593593+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:594594+ ath_force_clear_no_ir_chan(wiphy, ch);595595+ break;596596+ case NL80211_REGDOM_SET_BY_USER:597597+ if (ath_reg_dyn_country_user_allow(reg))598598+ ath_force_clear_no_ir_chan(wiphy, ch);599599+ break;600600+ default:601601+ if (ch->beacon_found)602602+ ch->flags &= ~IEEE80211_CHAN_NO_IR;603603+ }604604+}605605+606606+/*607607+ * These exception rules do not apply radar frequencies.608608+ *609609+ * - We enable initiating radiation if the country IE says its fine:610610+ * - If no country IE has been processed and a we determine we have611611+ * received a beacon on a channel we can enable initiating radiation.612612+ */613613+static void614614+ath_reg_apply_beaconing_flags(struct wiphy *wiphy,615615+ struct ath_regulatory *reg,616616+ enum nl80211_reg_initiator initiator)617617+{618618+ enum ieee80211_band band;619619+ struct ieee80211_supported_band *sband;620620+ struct ieee80211_channel *ch;621621+ unsigned int i;622622+623623+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {624624+ if (!wiphy->bands[band])625625+ continue;626626+ sband = wiphy->bands[band];627627+ for (i = 0; i < sband->n_channels; i++) {628628+ ch = &sband->channels[i];629629+ __ath_reg_apply_beaconing_flags(wiphy, reg,630630+ initiator, ch);631631+ }632632+ }633633+}634634+635635+/**636636+ * ath_reg_apply_ir_flags()637637+ * @wiphy: the wiphy to use638638+ * @initiator: the regulatory hint initiator639639+ *640640+ * If no country IE has been received always enable passive scan641641+ * and no-ibss on these channels. This is only done for specific642642+ * regulatory SKUs.643643+ *644644+ * If a country IE has been received check its rule for this645645+ * channel first before enabling active scan. The passive scan646646+ * would have been enforced by the initial processing of our647647+ * custom regulatory domain.648648+ */649649+static void650650+ath_reg_apply_ir_flags(struct wiphy *wiphy,651651+ struct ath_regulatory *reg,652652+ enum nl80211_reg_initiator initiator)653653+{654654+ struct ieee80211_supported_band *sband;655655+656656+ sband = wiphy->bands[IEEE80211_BAND_2GHZ];657657+ if (!sband)658658+ return;659659+660660+ switch(initiator) {661661+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:662662+ ath_force_clear_no_ir_freq(wiphy, 2467);663663+ ath_force_clear_no_ir_freq(wiphy, 2472);664664+ break;665665+ case NL80211_REGDOM_SET_BY_USER:666666+ if (!ath_reg_dyn_country_user_allow(reg))667667+ break;668668+ ath_force_clear_no_ir_freq(wiphy, 2467);669669+ ath_force_clear_no_ir_freq(wiphy, 2472);670670+ break;671671+ default:672672+ ath_force_no_ir_freq(wiphy, 2467);673673+ ath_force_no_ir_freq(wiphy, 2472);674674+ }675675+}676676+677677+/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */678678+static void ath_reg_apply_radar_flags(struct wiphy *wiphy)679679+{680680+ struct ieee80211_supported_band *sband;681681+ struct ieee80211_channel *ch;682682+ unsigned int i;683683+684684+ if (!wiphy->bands[IEEE80211_BAND_5GHZ])685685+ return;686686+687687+ sband = wiphy->bands[IEEE80211_BAND_5GHZ];688688+689689+ for (i = 0; i < sband->n_channels; i++) {690690+ ch = &sband->channels[i];691691+ if (!ath_is_radar_freq(ch->center_freq))692692+ continue;693693+ /* We always enable radar detection/DFS on this694694+ * frequency range. Additionally we also apply on695695+ * this frequency range:696696+ * - If STA mode does not yet have DFS supports disable697697+ * active scanning698698+ * - If adhoc mode does not support DFS yet then699699+ * disable adhoc in the frequency.700700+ * - If AP mode does not yet support radar detection/DFS701701+ * do not allow AP mode702702+ */703703+ if (!(ch->flags & IEEE80211_CHAN_DISABLED))704704+ ch->flags |= IEEE80211_CHAN_RADAR |705705+ IEEE80211_CHAN_NO_IR;706706+ }707707+}708708+709709+static void ath_reg_apply_world_flags(struct wiphy *wiphy,710710+ enum nl80211_reg_initiator initiator,711711+ struct ath_regulatory *reg)712712+{713713+ switch (reg->regpair->regDmnEnum) {714714+ case 0x60:715715+ case 0x63:716716+ case 0x66:717717+ case 0x67:718718+ case 0x6C:719719+ ath_reg_apply_beaconing_flags(wiphy, reg, initiator);720720+ break;721721+ case 0x68:722722+ ath_reg_apply_beaconing_flags(wiphy, reg, initiator);723723+ ath_reg_apply_ir_flags(wiphy, reg, initiator);724724+ break;725725+ default:726726+ if (ath_reg_dyn_country_user_allow(reg))727727+ ath_reg_apply_beaconing_flags(wiphy, reg, initiator);728728+ }729729+}730730+731731+static u16 ath_regd_find_country_by_name(char *alpha2)732732+{733733+ unsigned int i;734734+735735+ for (i = 0; i < ARRAY_SIZE(allCountries); i++) {736736+ if (!memcmp(allCountries[i].isoName, alpha2, 2))737737+ return allCountries[i].countryCode;738738+ }739739+740740+ return -1;741741+}742742+743743+static int __ath_reg_dyn_country(struct wiphy *wiphy,744744+ struct ath_regulatory *reg,745745+ struct regulatory_request *request)746746+{747747+ u16 country_code;748748+749749+ if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&750750+ !ath_is_world_regd(reg))751751+ return -EINVAL;752752+753753+ country_code = ath_regd_find_country_by_name(request->alpha2);754754+ if (country_code == (u16) -1)755755+ return -EINVAL;756756+757757+ reg->current_rd = COUNTRY_ERD_FLAG;758758+ reg->current_rd |= country_code;759759+760760+ __ath_regd_init(reg);761761+762762+ ath_reg_apply_world_flags(wiphy, request->initiator, reg);763763+764764+ return 0;765765+}766766+767767+static void ath_reg_dyn_country(struct wiphy *wiphy,768768+ struct ath_regulatory *reg,769769+ struct regulatory_request *request)770770+{771771+ if (__ath_reg_dyn_country(wiphy, reg, request))772772+ return;773773+774774+ printk(KERN_DEBUG "ath: regdomain 0x%0x "775775+ "dynamically updated by %s\n",776776+ reg->current_rd,777777+ reg_initiator_name(request->initiator));198778}199779200780void ath_reg_notifier_apply(struct wiphy *wiphy,···530508 case NL80211_REGDOM_SET_BY_DRIVER:531509 break;532510 case NL80211_REGDOM_SET_BY_USER:533533- ath_reg_dyn_country_user(wiphy, reg, request);511511+ if (ath_reg_dyn_country_user_allow(reg))512512+ ath_reg_dyn_country(wiphy, reg, request);534513 break;535514 case NL80211_REGDOM_SET_BY_COUNTRY_IE:536515 ath_reg_dyn_country(wiphy, reg, request);···632609 const struct ieee80211_regdomain *regd;633610634611 wiphy->reg_notifier = reg_notifier;635635- wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY;612612+ wiphy->regulatory_flags |= REGULATORY_STRICT_REG;636613637614 if (ath_is_world_regd(reg)) {638615 /*···640617 * saved on the wiphy orig_* parameters641618 */642619 regd = ath_world_regdomain(reg);643643- wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;620620+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG |621621+ REGULATORY_COUNTRY_IE_FOLLOW_POWER;644622 } else {645623 /*646624 * This gets applied in the case of the absence of CRDA,
···44config BRCMSMAC55 tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver"66 depends on MAC8021177- depends on BCMA77+ depends on BCMA_POSSIBLE88+ select BCMA89 select NEW_LEDS if BCMA_DRIVER_GPIO910 select LEDS_CLASS if BCMA_DRIVER_GPIO1011 select BRCMUTIL1112 select FW_LOADER1212- select CRC_CCITT1313- select CRC81413 select CORDIC1514 ---help---1615 This module adds support for PCIe wireless adapters based on Broadcom
···11+/*22+ * Copyright (c) 2010 Broadcom Corporation33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+1717+/*******************************************************************************1818+ * Communicates with the dongle by using dcmd codes.1919+ * For certain dcmd codes, the dongle interprets string data from the host.2020+ ******************************************************************************/2121+2222+#include <linux/types.h>2323+#include <linux/netdevice.h>2424+2525+#include <brcmu_utils.h>2626+#include <brcmu_wifi.h>2727+2828+#include "dhd.h"2929+#include "dhd_bus.h"3030+#include "fwsignal.h"3131+#include "dhd_dbg.h"3232+#include "tracepoint.h"3333+#include "proto.h"3434+#include "bcdc.h"3535+3636+struct brcmf_proto_bcdc_dcmd {3737+ __le32 cmd; /* dongle command value */3838+ __le32 len; /* lower 16: output buflen;3939+ * upper 16: input buflen (excludes header) */4040+ __le32 flags; /* flag defns given below */4141+ __le32 status; /* status code returned from the device */4242+};4343+4444+/* Max valid buffer size that can be sent to the dongle */4545+#define BCDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)4646+4747+/* BCDC flag definitions */4848+#define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */4949+#define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */5050+#define BCDC_DCMD_IF_MASK 0xF000 /* I/F index */5151+#define BCDC_DCMD_IF_SHIFT 125252+#define BCDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */5353+#define BCDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */5454+#define BCDC_DCMD_ID(flags) \5555+ (((flags) & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT)5656+5757+/*5858+ * BCDC header - Broadcom specific extension of CDC.5959+ * Used on data packets to convey priority across USB.6060+ */6161+#define BCDC_HEADER_LEN 46262+#define BCDC_PROTO_VER 2 /* Protocol version */6363+#define BCDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */6464+#define BCDC_FLAG_VER_SHIFT 4 /* Protocol version shift */6565+#define BCDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */6666+#define BCDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */6767+#define BCDC_PRIORITY_MASK 0x76868+#define BCDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */6969+#define BCDC_FLAG2_IF_SHIFT 07070+7171+#define BCDC_GET_IF_IDX(hdr) \7272+ ((int)((((hdr)->flags2) & BCDC_FLAG2_IF_MASK) >> BCDC_FLAG2_IF_SHIFT))7373+#define BCDC_SET_IF_IDX(hdr, idx) \7474+ ((hdr)->flags2 = (((hdr)->flags2 & ~BCDC_FLAG2_IF_MASK) | \7575+ ((idx) << BCDC_FLAG2_IF_SHIFT)))7676+7777+/**7878+ * struct brcmf_proto_bcdc_header - BCDC header format7979+ *8080+ * @flags: flags contain protocol and checksum info.8181+ * @priority: 802.1d priority and USB flow control info (bit 4:7).8282+ * @flags2: additional flags containing dongle interface index.8383+ * @data_offset: start of packet data. header is following by firmware signals.8484+ */8585+struct brcmf_proto_bcdc_header {8686+ u8 flags;8787+ u8 priority;8888+ u8 flags2;8989+ u8 data_offset;9090+};9191+9292+/*9393+ * maximum length of firmware signal data between9494+ * the BCDC header and packet data in the tx path.9595+ */9696+#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 129797+9898+#define RETRIES 2 /* # of retries to retrieve matching dcmd response */9999+#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE100100+ * (amount of header tha might be added)101101+ * plus any space that might be needed102102+ * for bus alignment padding.103103+ */104104+#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for105105+ * round off at the end of buffer106106+ * Currently is SDIO107107+ */108108+109109+struct brcmf_bcdc {110110+ u16 reqid;111111+ u8 bus_header[BUS_HEADER_LEN];112112+ struct brcmf_proto_bcdc_dcmd msg;113113+ unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];114114+};115115+116116+static int brcmf_proto_bcdc_msg(struct brcmf_pub *drvr)117117+{118118+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;119119+ int len = le32_to_cpu(bcdc->msg.len) +120120+ sizeof(struct brcmf_proto_bcdc_dcmd);121121+122122+ brcmf_dbg(BCDC, "Enter\n");123123+124124+ /* NOTE : bcdc->msg.len holds the desired length of the buffer to be125125+ * returned. Only up to BCDC_MAX_MSG_SIZE of this buffer area126126+ * is actually sent to the dongle127127+ */128128+ if (len > BCDC_MAX_MSG_SIZE)129129+ len = BCDC_MAX_MSG_SIZE;130130+131131+ /* Send request */132132+ return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);133133+}134134+135135+static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)136136+{137137+ int ret;138138+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;139139+140140+ brcmf_dbg(BCDC, "Enter\n");141141+ len += sizeof(struct brcmf_proto_bcdc_dcmd);142142+ do {143143+ ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&bcdc->msg,144144+ len);145145+ if (ret < 0)146146+ break;147147+ } while (BCDC_DCMD_ID(le32_to_cpu(bcdc->msg.flags)) != id);148148+149149+ return ret;150150+}151151+152152+static int153153+brcmf_proto_bcdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,154154+ void *buf, uint len)155155+{156156+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;157157+ struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;158158+ void *info;159159+ int ret = 0, retries = 0;160160+ u32 id, flags;161161+162162+ brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);163163+164164+ memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));165165+166166+ msg->cmd = cpu_to_le32(cmd);167167+ msg->len = cpu_to_le32(len);168168+ flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT);169169+ flags = (flags & ~BCDC_DCMD_IF_MASK) |170170+ (ifidx << BCDC_DCMD_IF_SHIFT);171171+ msg->flags = cpu_to_le32(flags);172172+173173+ if (buf)174174+ memcpy(bcdc->buf, buf, len);175175+176176+ ret = brcmf_proto_bcdc_msg(drvr);177177+ if (ret < 0) {178178+ brcmf_err("brcmf_proto_bcdc_msg failed w/status %d\n",179179+ ret);180180+ goto done;181181+ }182182+183183+retry:184184+ /* wait for interrupt and get first fragment */185185+ ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);186186+ if (ret < 0)187187+ goto done;188188+189189+ flags = le32_to_cpu(msg->flags);190190+ id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;191191+192192+ if ((id < bcdc->reqid) && (++retries < RETRIES))193193+ goto retry;194194+ if (id != bcdc->reqid) {195195+ brcmf_err("%s: unexpected request id %d (expected %d)\n",196196+ brcmf_ifname(drvr, ifidx), id, bcdc->reqid);197197+ ret = -EINVAL;198198+ goto done;199199+ }200200+201201+ /* Check info buffer */202202+ info = (void *)&msg[1];203203+204204+ /* Copy info buffer */205205+ if (buf) {206206+ if (ret < (int)len)207207+ len = ret;208208+ memcpy(buf, info, len);209209+ }210210+211211+ /* Check the ERROR flag */212212+ if (flags & BCDC_DCMD_ERROR)213213+ ret = le32_to_cpu(msg->status);214214+215215+done:216216+ return ret;217217+}218218+219219+static int220220+brcmf_proto_bcdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,221221+ void *buf, uint len)222222+{223223+ struct brcmf_bcdc *bcdc = (struct brcmf_bcdc *)drvr->proto->pd;224224+ struct brcmf_proto_bcdc_dcmd *msg = &bcdc->msg;225225+ int ret = 0;226226+ u32 flags, id;227227+228228+ brcmf_dbg(BCDC, "Enter, cmd %d len %d\n", cmd, len);229229+230230+ memset(msg, 0, sizeof(struct brcmf_proto_bcdc_dcmd));231231+232232+ msg->cmd = cpu_to_le32(cmd);233233+ msg->len = cpu_to_le32(len);234234+ flags = (++bcdc->reqid << BCDC_DCMD_ID_SHIFT) | BCDC_DCMD_SET;235235+ flags = (flags & ~BCDC_DCMD_IF_MASK) |236236+ (ifidx << BCDC_DCMD_IF_SHIFT);237237+ msg->flags = cpu_to_le32(flags);238238+239239+ if (buf)240240+ memcpy(bcdc->buf, buf, len);241241+242242+ ret = brcmf_proto_bcdc_msg(drvr);243243+ if (ret < 0)244244+ goto done;245245+246246+ ret = brcmf_proto_bcdc_cmplt(drvr, bcdc->reqid, len);247247+ if (ret < 0)248248+ goto done;249249+250250+ flags = le32_to_cpu(msg->flags);251251+ id = (flags & BCDC_DCMD_ID_MASK) >> BCDC_DCMD_ID_SHIFT;252252+253253+ if (id != bcdc->reqid) {254254+ brcmf_err("%s: unexpected request id %d (expected %d)\n",255255+ brcmf_ifname(drvr, ifidx), id, bcdc->reqid);256256+ ret = -EINVAL;257257+ goto done;258258+ }259259+260260+ /* Check the ERROR flag */261261+ if (flags & BCDC_DCMD_ERROR)262262+ ret = le32_to_cpu(msg->status);263263+264264+done:265265+ return ret;266266+}267267+268268+static void269269+brcmf_proto_bcdc_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,270270+ struct sk_buff *pktbuf)271271+{272272+ struct brcmf_proto_bcdc_header *h;273273+274274+ brcmf_dbg(BCDC, "Enter\n");275275+276276+ /* Push BDC header used to convey priority for buses that don't */277277+ skb_push(pktbuf, BCDC_HEADER_LEN);278278+279279+ h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);280280+281281+ h->flags = (BCDC_PROTO_VER << BCDC_FLAG_VER_SHIFT);282282+ if (pktbuf->ip_summed == CHECKSUM_PARTIAL)283283+ h->flags |= BCDC_FLAG_SUM_NEEDED;284284+285285+ h->priority = (pktbuf->priority & BCDC_PRIORITY_MASK);286286+ h->flags2 = 0;287287+ h->data_offset = offset;288288+ BCDC_SET_IF_IDX(h, ifidx);289289+ trace_brcmf_bcdchdr(pktbuf->data);290290+}291291+292292+static int293293+brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,294294+ struct sk_buff *pktbuf)295295+{296296+ struct brcmf_proto_bcdc_header *h;297297+298298+ brcmf_dbg(BCDC, "Enter\n");299299+300300+ /* Pop BCDC header used to convey priority for buses that don't */301301+ if (pktbuf->len <= BCDC_HEADER_LEN) {302302+ brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",303303+ pktbuf->len, BCDC_HEADER_LEN);304304+ return -EBADE;305305+ }306306+307307+ trace_brcmf_bcdchdr(pktbuf->data);308308+ h = (struct brcmf_proto_bcdc_header *)(pktbuf->data);309309+310310+ *ifidx = BCDC_GET_IF_IDX(h);311311+ if (*ifidx >= BRCMF_MAX_IFS) {312312+ brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);313313+ return -EBADE;314314+ }315315+ /* The ifidx is the idx to map to matching netdev/ifp. When receiving316316+ * events this is easy because it contains the bssidx which maps317317+ * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.318318+ * bssidx 1 is used for p2p0 and no data can be received or319319+ * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0320320+ */321321+ if (*ifidx)322322+ (*ifidx)++;323323+324324+ if (((h->flags & BCDC_FLAG_VER_MASK) >> BCDC_FLAG_VER_SHIFT) !=325325+ BCDC_PROTO_VER) {326326+ brcmf_err("%s: non-BCDC packet received, flags 0x%x\n",327327+ brcmf_ifname(drvr, *ifidx), h->flags);328328+ return -EBADE;329329+ }330330+331331+ if (h->flags & BCDC_FLAG_SUM_GOOD) {332332+ brcmf_dbg(BCDC, "%s: BDC rcv, good checksum, flags 0x%x\n",333333+ brcmf_ifname(drvr, *ifidx), h->flags);334334+ pktbuf->ip_summed = CHECKSUM_UNNECESSARY;335335+ }336336+337337+ pktbuf->priority = h->priority & BCDC_PRIORITY_MASK;338338+339339+ skb_pull(pktbuf, BCDC_HEADER_LEN);340340+ if (do_fws)341341+ brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);342342+ else343343+ skb_pull(pktbuf, h->data_offset << 2);344344+345345+ if (pktbuf->len == 0)346346+ return -ENODATA;347347+ return 0;348348+}349349+350350+int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)351351+{352352+ struct brcmf_bcdc *bcdc;353353+354354+ bcdc = kzalloc(sizeof(*bcdc), GFP_ATOMIC);355355+ if (!bcdc)356356+ goto fail;357357+358358+ /* ensure that the msg buf directly follows the cdc msg struct */359359+ if ((unsigned long)(&bcdc->msg + 1) != (unsigned long)bcdc->buf) {360360+ brcmf_err("struct brcmf_proto_bcdc is not correctly defined\n");361361+ goto fail;362362+ }363363+364364+ drvr->proto->hdrpush = brcmf_proto_bcdc_hdrpush;365365+ drvr->proto->hdrpull = brcmf_proto_bcdc_hdrpull;366366+ drvr->proto->query_dcmd = brcmf_proto_bcdc_query_dcmd;367367+ drvr->proto->set_dcmd = brcmf_proto_bcdc_set_dcmd;368368+ drvr->proto->pd = bcdc;369369+370370+ drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;371371+ drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +372372+ sizeof(struct brcmf_proto_bcdc_dcmd) + ROUND_UP_MARGIN;373373+ return 0;374374+375375+fail:376376+ kfree(bcdc);377377+ return -ENOMEM;378378+}379379+380380+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr)381381+{382382+ kfree(drvr->proto->pd);383383+ drvr->proto->pd = NULL;384384+}
+24
drivers/net/wireless/brcm80211/brcmfmac/bcdc.h
···11+/*22+ * Copyright (c) 2013 Broadcom Corporation33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+#ifndef BRCMFMAC_BCDC_H1717+#define BRCMFMAC_BCDC_H1818+1919+2020+int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr);2121+void brcmf_proto_bcdc_detach(struct brcmf_pub *drvr);2222+2323+2424+#endif /* BRCMFMAC_BCDC_H */
···158158 }159159 }160160161161- if (err_ret)162162- brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",163163- rw ? "write" : "read", func, regaddr, *byte, err_ret);164164-161161+ if (err_ret) {162162+ /*163163+ * SleepCSR register access can fail when164164+ * waking up the device so reduce this noise165165+ * in the logs.166166+ */167167+ if (regaddr != SBSDIO_FUNC1_SLEEPCSR)168168+ brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",169169+ rw ? "write" : "read", func, regaddr, *byte,170170+ err_ret);171171+ else172172+ brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",173173+ rw ? "write" : "read", func, regaddr, *byte,174174+ err_ret);175175+ }165176 return err_ret;166177}167178···280269int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)281270{282271 int err_ret = 0;272272+ struct mmc_host *host;273273+ struct sdio_func *func;274274+ uint max_blocks;283275284276 brcmf_dbg(SDIO, "\n");285277···304290305291 brcmf_sdioh_enablefuncs(sdiodev);306292293293+ /*294294+ * determine host related variables after brcmf_sdio_probe()295295+ * as func->cur_blksize is properly set and F2 init has been296296+ * completed successfully.297297+ */298298+ func = sdiodev->func[2];299299+ host = func->card->host;300300+ sdiodev->sg_support = host->max_segs > 1;301301+ max_blocks = min_t(uint, host->max_blk_count, 511u);302302+ sdiodev->max_request_size = min_t(uint, host->max_req_size,303303+ max_blocks * func->cur_blksize);304304+ sdiodev->max_segment_count = min_t(uint, host->max_segs,305305+ SG_MAX_SINGLE_ALLOC);306306+ sdiodev->max_segment_size = host->max_seg_size;307307out:308308 sdio_release_host(sdiodev->func[1]);309309 brcmf_dbg(SDIO, "Done\n");···346318 int err;347319 struct brcmf_sdio_dev *sdiodev;348320 struct brcmf_bus *bus_if;349349- struct mmc_host *host;350350- uint max_blocks;351321352322 brcmf_dbg(SDIO, "Enter\n");353323 brcmf_dbg(SDIO, "Class=%x\n", func->class);···393367 goto fail;394368 }395369396396- /*397397- * determine host related variables after brcmf_sdio_probe()398398- * as func->cur_blksize is properly set and F2 init has been399399- * completed successfully.400400- */401401- host = func->card->host;402402- sdiodev->sg_support = host->max_segs > 1;403403- max_blocks = min_t(uint, host->max_blk_count, 511u);404404- sdiodev->max_request_size = min_t(uint, host->max_req_size,405405- max_blocks * func->cur_blksize);406406- sdiodev->max_segment_count = min_t(uint, host->max_segs,407407- SG_MAX_SINGLE_ALLOC);408408- sdiodev->max_segment_size = host->max_seg_size;409370 brcmf_dbg(SDIO, "F2 init completed...\n");410371 return 0;411372
+8-474
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
···25252626#include "fweh.h"27272828-/*******************************************************************************2929- * IO codes that are interpreted by dongle firmware3030- ******************************************************************************/3131-#define BRCMF_C_GET_VERSION 13232-#define BRCMF_C_UP 23333-#define BRCMF_C_DOWN 33434-#define BRCMF_C_SET_PROMISC 103535-#define BRCMF_C_GET_RATE 123636-#define BRCMF_C_GET_INFRA 193737-#define BRCMF_C_SET_INFRA 203838-#define BRCMF_C_GET_AUTH 213939-#define BRCMF_C_SET_AUTH 224040-#define BRCMF_C_GET_BSSID 234141-#define BRCMF_C_GET_SSID 254242-#define BRCMF_C_SET_SSID 264343-#define BRCMF_C_TERMINATED 284444-#define BRCMF_C_GET_CHANNEL 294545-#define BRCMF_C_SET_CHANNEL 304646-#define BRCMF_C_GET_SRL 314747-#define BRCMF_C_SET_SRL 324848-#define BRCMF_C_GET_LRL 334949-#define BRCMF_C_SET_LRL 345050-#define BRCMF_C_GET_RADIO 375151-#define BRCMF_C_SET_RADIO 385252-#define BRCMF_C_GET_PHYTYPE 395353-#define BRCMF_C_SET_KEY 455454-#define BRCMF_C_SET_PASSIVE_SCAN 495555-#define BRCMF_C_SCAN 505656-#define BRCMF_C_SCAN_RESULTS 515757-#define BRCMF_C_DISASSOC 525858-#define BRCMF_C_REASSOC 535959-#define BRCMF_C_SET_ROAM_TRIGGER 556060-#define BRCMF_C_SET_ROAM_DELTA 576161-#define BRCMF_C_GET_BCNPRD 756262-#define BRCMF_C_SET_BCNPRD 766363-#define BRCMF_C_GET_DTIMPRD 776464-#define BRCMF_C_SET_DTIMPRD 786565-#define BRCMF_C_SET_COUNTRY 846666-#define BRCMF_C_GET_PM 856767-#define BRCMF_C_SET_PM 866868-#define BRCMF_C_GET_CURR_RATESET 1146969-#define BRCMF_C_GET_AP 1177070-#define BRCMF_C_SET_AP 1187171-#define BRCMF_C_GET_RSSI 1277272-#define BRCMF_C_GET_WSEC 1337373-#define BRCMF_C_SET_WSEC 1347474-#define BRCMF_C_GET_PHY_NOISE 1357575-#define BRCMF_C_GET_BSS_INFO 1367676-#define BRCMF_C_GET_BANDLIST 1407777-#define BRCMF_C_SET_SCB_TIMEOUT 1587878-#define BRCMF_C_GET_PHYLIST 1807979-#define BRCMF_C_SET_SCAN_CHANNEL_TIME 1858080-#define BRCMF_C_SET_SCAN_UNASSOC_TIME 1878181-#define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON 2018282-#define BRCMF_C_GET_VALID_CHANNELS 2178383-#define BRCMF_C_GET_KEY_PRIMARY 2358484-#define BRCMF_C_SET_KEY_PRIMARY 2368585-#define BRCMF_C_SET_SCAN_PASSIVE_TIME 2588686-#define BRCMF_C_GET_VAR 2628787-#define BRCMF_C_SET_VAR 2638888-8989-/* phy types (returned by WLC_GET_PHYTPE) */9090-#define WLC_PHY_TYPE_A 09191-#define WLC_PHY_TYPE_B 19292-#define WLC_PHY_TYPE_G 29393-#define WLC_PHY_TYPE_N 49494-#define WLC_PHY_TYPE_LP 59595-#define WLC_PHY_TYPE_SSN 69696-#define WLC_PHY_TYPE_HT 79797-#define WLC_PHY_TYPE_LCN 89898-#define WLC_PHY_TYPE_NULL 0xf9999-10028#define TOE_TX_CSUM_OL 0x0000000110129#define TOE_RX_CSUM_OL 0x00000002102102-103103-#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */104104-105105-/* size of brcmf_scan_params not including variable length array */106106-#define BRCMF_SCAN_PARAMS_FIXED_SIZE 64107107-108108-/* masks for channel and ssid count */109109-#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff110110-#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16111111-112112-/* primary (ie tx) key */113113-#define BRCMF_PRIMARY_KEY (1 << 1)1143011531/* For supporting multiple interfaces */11632#define BRCMF_MAX_IFS 1611733118118-#define DOT11_BSSTYPE_ANY 211934#define DOT11_MAX_DEFAULT_KEYS 4120120-121121-#define BRCMF_ESCAN_REQ_VERSION 1122122-123123-#define WLC_BSS_RSSI_ON_CHANNEL 0x0002124124-125125-#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */126126-#define BRCMF_STA_ASSOC 0x10 /* Associated */127127-128128-#define BRCMF_E_STATUS_SUCCESS 0129129-#define BRCMF_E_STATUS_FAIL 1130130-#define BRCMF_E_STATUS_TIMEOUT 2131131-#define BRCMF_E_STATUS_NO_NETWORKS 3132132-#define BRCMF_E_STATUS_ABORT 4133133-#define BRCMF_E_STATUS_NO_ACK 5134134-#define BRCMF_E_STATUS_UNSOLICITED 6135135-#define BRCMF_E_STATUS_ATTEMPT 7136136-#define BRCMF_E_STATUS_PARTIAL 8137137-#define BRCMF_E_STATUS_NEWSCAN 9138138-#define BRCMF_E_STATUS_NEWASSOC 10139139-#define BRCMF_E_STATUS_11HQUIET 11140140-#define BRCMF_E_STATUS_SUPPRESS 12141141-#define BRCMF_E_STATUS_NOCHANS 13142142-#define BRCMF_E_STATUS_CS_ABORT 15143143-#define BRCMF_E_STATUS_ERROR 16144144-145145-#define BRCMF_E_REASON_INITIAL_ASSOC 0146146-#define BRCMF_E_REASON_LOW_RSSI 1147147-#define BRCMF_E_REASON_DEAUTH 2148148-#define BRCMF_E_REASON_DISASSOC 3149149-#define BRCMF_E_REASON_BCNS_LOST 4150150-#define BRCMF_E_REASON_MINTXRATE 9151151-#define BRCMF_E_REASON_TXFAIL 10152152-153153-#define BRCMF_E_REASON_LINK_BSSCFG_DIS 4154154-#define BRCMF_E_REASON_FAST_ROAM_FAILED 5155155-#define BRCMF_E_REASON_DIRECTED_ROAM 6156156-#define BRCMF_E_REASON_TSPEC_REJECTED 7157157-#define BRCMF_E_REASON_BETTER_AP 8158158-159159-#define BRCMF_E_PRUNE_ENCR_MISMATCH 1160160-#define BRCMF_E_PRUNE_BCAST_BSSID 2161161-#define BRCMF_E_PRUNE_MAC_DENY 3162162-#define BRCMF_E_PRUNE_MAC_NA 4163163-#define BRCMF_E_PRUNE_REG_PASSV 5164164-#define BRCMF_E_PRUNE_SPCT_MGMT 6165165-#define BRCMF_E_PRUNE_RADAR 7166166-#define BRCMF_E_RSN_MISMATCH 8167167-#define BRCMF_E_PRUNE_NO_COMMON_RATES 9168168-#define BRCMF_E_PRUNE_BASIC_RATES 10169169-#define BRCMF_E_PRUNE_CIPHER_NA 12170170-#define BRCMF_E_PRUNE_KNOWN_STA 13171171-#define BRCMF_E_PRUNE_WDS_PEER 15172172-#define BRCMF_E_PRUNE_QBSS_LOAD 16173173-#define BRCMF_E_PRUNE_HOME_AP 17174174-175175-#define BRCMF_E_SUP_OTHER 0176176-#define BRCMF_E_SUP_DECRYPT_KEY_DATA 1177177-#define BRCMF_E_SUP_BAD_UCAST_WEP128 2178178-#define BRCMF_E_SUP_BAD_UCAST_WEP40 3179179-#define BRCMF_E_SUP_UNSUP_KEY_LEN 4180180-#define BRCMF_E_SUP_PW_KEY_CIPHER 5181181-#define BRCMF_E_SUP_MSG3_TOO_MANY_IE 6182182-#define BRCMF_E_SUP_MSG3_IE_MISMATCH 7183183-#define BRCMF_E_SUP_NO_INSTALL_FLAG 8184184-#define BRCMF_E_SUP_MSG3_NO_GTK 9185185-#define BRCMF_E_SUP_GRP_KEY_CIPHER 10186186-#define BRCMF_E_SUP_GRP_MSG1_NO_GTK 11187187-#define BRCMF_E_SUP_GTK_DECRYPT_FAIL 12188188-#define BRCMF_E_SUP_SEND_FAIL 13189189-#define BRCMF_E_SUP_DEAUTH 14190190-191191-#define BRCMF_E_IF_ADD 1192192-#define BRCMF_E_IF_DEL 2193193-#define BRCMF_E_IF_CHANGE 3194194-195195-#define BRCMF_E_IF_FLAG_NOIF 1196196-197197-#define BRCMF_E_IF_ROLE_STA 0198198-#define BRCMF_E_IF_ROLE_AP 1199199-#define BRCMF_E_IF_ROLE_WDS 2200200-201201-#define BRCMF_E_LINK_BCN_LOSS 1202202-#define BRCMF_E_LINK_DISASSOC 2203203-#define BRCMF_E_LINK_ASSOC_REC 3204204-#define BRCMF_E_LINK_BSSCFG_DIS 42053520636/* Small, medium and maximum buffer size for dcmd20737 */···4121142212#define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256432134444-/* Pattern matching filter. Specifies an offset within received packets to4545- * start matching, the pattern to match, the size of the pattern, and a bitmask4646- * that indicates which bits within the pattern should be matched.214214+/* Length of firmware version string stored for215215+ * ethtool driver info which uses 32 bytes as well.47216 */4848-struct brcmf_pkt_filter_pattern_le {4949- /*5050- * Offset within received packet to start pattern matching.5151- * Offset '0' is the first byte of the ethernet header.5252- */5353- __le32 offset;5454- /* Size of the pattern. Bitmask must be the same size.*/5555- __le32 size_bytes;5656- /*5757- * Variable length mask and pattern data. mask starts at offset 0.5858- * Pattern immediately follows mask.5959- */6060- u8 mask_and_pattern[1];6161-};6262-6363-/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */6464-struct brcmf_pkt_filter_le {6565- __le32 id; /* Unique filter id, specified by app. */6666- __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */6767- __le32 negate_match; /* Negate the result of filter matches */6868- union { /* Filter definitions */6969- struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */7070- } u;7171-};7272-7373-/* IOVAR "pkt_filter_enable" parameter. */7474-struct brcmf_pkt_filter_enable_le {7575- __le32 id; /* Unique filter id */7676- __le32 enable; /* Enable/disable bool */7777-};7878-7979-/* BSS info structure8080- * Applications MUST CHECK ie_offset field and length field to access IEs and8181- * next bss_info structure in a vector (in struct brcmf_scan_results)8282- */8383-struct brcmf_bss_info_le {8484- __le32 version; /* version field */8585- __le32 length; /* byte length of data in this record,8686- * starting at version and including IEs8787- */8888- u8 BSSID[ETH_ALEN];8989- __le16 beacon_period; /* units are Kusec */9090- __le16 capability; /* Capability information */9191- u8 SSID_len;9292- u8 SSID[32];9393- struct {9494- __le32 count; /* # rates in this set */9595- u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */9696- } rateset; /* supported rates */9797- __le16 chanspec; /* chanspec for bss */9898- __le16 atim_window; /* units are Kusec */9999- u8 dtim_period; /* DTIM period */100100- __le16 RSSI; /* receive signal strength (in dBm) */101101- s8 phy_noise; /* noise (in dBm) */102102-103103- u8 n_cap; /* BSS is 802.11N Capable */104104- /* 802.11N BSS Capabilities (based on HT_CAP_*): */105105- __le32 nbss_cap;106106- u8 ctl_ch; /* 802.11N BSS control channel number */107107- __le32 reserved32[1]; /* Reserved for expansion of BSS properties */108108- u8 flags; /* flags */109109- u8 reserved[3]; /* Reserved for expansion of BSS properties */110110- u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */111111-112112- __le16 ie_offset; /* offset at which IEs start, from beginning */113113- __le32 ie_length; /* byte length of Information Elements */114114- __le16 SNR; /* average SNR of during frame reception */115115- /* Add new fields here */116116- /* variable length Information Elements */117117-};118118-119119-struct brcm_rateset_le {120120- /* # rates in this set */121121- __le32 count;122122- /* rates in 500kbps units w/hi bit set if basic */123123- u8 rates[BRCMF_MAXRATES_IN_SET];124124-};125125-126126-struct brcmf_ssid {127127- u32 SSID_len;128128- unsigned char SSID[32];129129-};130130-131131-struct brcmf_ssid_le {132132- __le32 SSID_len;133133- unsigned char SSID[32];134134-};135135-136136-struct brcmf_scan_params_le {137137- struct brcmf_ssid_le ssid_le; /* default: {0, ""} */138138- u8 bssid[ETH_ALEN]; /* default: bcast */139139- s8 bss_type; /* default: any,140140- * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT141141- */142142- u8 scan_type; /* flags, 0 use default */143143- __le32 nprobes; /* -1 use default, number of probes per channel */144144- __le32 active_time; /* -1 use default, dwell time per channel for145145- * active scanning146146- */147147- __le32 passive_time; /* -1 use default, dwell time per channel148148- * for passive scanning149149- */150150- __le32 home_time; /* -1 use default, dwell time for the151151- * home channel between channel scans152152- */153153- __le32 channel_num; /* count of channels and ssids that follow154154- *155155- * low half is count of channels in156156- * channel_list, 0 means default (use all157157- * available channels)158158- *159159- * high half is entries in struct brcmf_ssid160160- * array that follows channel_list, aligned for161161- * s32 (4 bytes) meaning an odd channel count162162- * implies a 2-byte pad between end of163163- * channel_list and first ssid164164- *165165- * if ssid count is zero, single ssid in the166166- * fixed parameter portion is assumed, otherwise167167- * ssid in the fixed portion is ignored168168- */169169- __le16 channel_list[1]; /* list of chanspecs */170170-};171171-172172-struct brcmf_scan_results {173173- u32 buflen;174174- u32 version;175175- u32 count;176176- struct brcmf_bss_info_le bss_info_le[];177177-};178178-179179-struct brcmf_escan_params_le {180180- __le32 version;181181- __le16 action;182182- __le16 sync_id;183183- struct brcmf_scan_params_le params_le;184184-};185185-186186-struct brcmf_escan_result_le {187187- __le32 buflen;188188- __le32 version;189189- __le16 sync_id;190190- __le16 bss_count;191191- struct brcmf_bss_info_le bss_info_le;192192-};193193-194194-#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \195195- sizeof(struct brcmf_bss_info_le))196196-197197-/* used for association with a specific BSSID and chanspec list */198198-struct brcmf_assoc_params_le {199199- /* 00:00:00:00:00:00: broadcast scan */200200- u8 bssid[ETH_ALEN];201201- /* 0: all available channels, otherwise count of chanspecs in202202- * chanspec_list */203203- __le32 chanspec_num;204204- /* list of chanspecs */205205- __le16 chanspec_list[1];206206-};207207-208208-/* used for join with or without a specific bssid and channel list */209209-struct brcmf_join_params {210210- struct brcmf_ssid_le ssid_le;211211- struct brcmf_assoc_params_le params_le;212212-};213213-214214-/* scan params for extended join */215215-struct brcmf_join_scan_params_le {216216- u8 scan_type; /* 0 use default, active or passive scan */217217- __le32 nprobes; /* -1 use default, nr of probes per channel */218218- __le32 active_time; /* -1 use default, dwell time per channel for219219- * active scanning220220- */221221- __le32 passive_time; /* -1 use default, dwell time per channel222222- * for passive scanning223223- */224224- __le32 home_time; /* -1 use default, dwell time for the home225225- * channel between channel scans226226- */227227-};228228-229229-/* extended join params */230230-struct brcmf_ext_join_params_le {231231- struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */232232- struct brcmf_join_scan_params_le scan_le;233233- struct brcmf_assoc_params_le assoc_le;234234-};235235-236236-struct brcmf_wsec_key {237237- u32 index; /* key index */238238- u32 len; /* key length */239239- u8 data[WLAN_MAX_KEY_LEN]; /* key data */240240- u32 pad_1[18];241241- u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */242242- u32 flags; /* misc flags */243243- u32 pad_2[3];244244- u32 iv_initialized; /* has IV been initialized already? */245245- u32 pad_3;246246- /* Rx IV */247247- struct {248248- u32 hi; /* upper 32 bits of IV */249249- u16 lo; /* lower 16 bits of IV */250250- } rxiv;251251- u32 pad_4[2];252252- u8 ea[ETH_ALEN]; /* per station */253253-};254254-255255-/*256256- * dongle requires same struct as above but with fields in little endian order257257- */258258-struct brcmf_wsec_key_le {259259- __le32 index; /* key index */260260- __le32 len; /* key length */261261- u8 data[WLAN_MAX_KEY_LEN]; /* key data */262262- __le32 pad_1[18];263263- __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */264264- __le32 flags; /* misc flags */265265- __le32 pad_2[3];266266- __le32 iv_initialized; /* has IV been initialized already? */267267- __le32 pad_3;268268- /* Rx IV */269269- struct {270270- __le32 hi; /* upper 32 bits of IV */271271- __le16 lo; /* lower 16 bits of IV */272272- } rxiv;273273- __le32 pad_4[2];274274- u8 ea[ETH_ALEN]; /* per station */275275-};276276-277277-/* Used to get specific STA parameters */278278-struct brcmf_scb_val_le {279279- __le32 val;280280- u8 ea[ETH_ALEN];281281-};282282-283283-/* channel encoding */284284-struct brcmf_channel_info_le {285285- __le32 hw_channel;286286- __le32 target_channel;287287- __le32 scan_channel;288288-};289289-290290-struct brcmf_sta_info_le {291291- __le16 ver; /* version of this struct */292292- __le16 len; /* length in bytes of this structure */293293- __le16 cap; /* sta's advertised capabilities */294294- __le32 flags; /* flags defined below */295295- __le32 idle; /* time since data pkt rx'd from sta */296296- u8 ea[ETH_ALEN]; /* Station address */297297- __le32 count; /* # rates in this set */298298- u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */299299- /* w/hi bit set if basic */300300- __le32 in; /* seconds elapsed since associated */301301- __le32 listen_interval_inms; /* Min Listen interval in ms for STA */302302- __le32 tx_pkts; /* # of packets transmitted */303303- __le32 tx_failures; /* # of packets failed */304304- __le32 rx_ucast_pkts; /* # of unicast packets received */305305- __le32 rx_mcast_pkts; /* # of multicast packets received */306306- __le32 tx_rate; /* Rate of last successful tx frame */307307- __le32 rx_rate; /* Rate of last successful rx frame */308308- __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */309309- __le32 rx_decrypt_failures; /* # of packet decrypted failed */310310-};311311-312312-struct brcmf_chanspec_list {313313- __le32 count; /* # of entries */314314- __le32 element[1]; /* variable length uint32 list */315315-};316316-317317-/*318318- * WLC_E_PROBRESP_MSG319319- * WLC_E_P2P_PROBREQ_MSG320320- * WLC_E_ACTION_FRAME_RX321321- */322322-struct brcmf_rx_mgmt_data {323323- __be16 version;324324- __be16 chanspec;325325- __be32 rssi;326326- __be32 mactime;327327- __be32 rate;328328-};217217+#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32329218330219/* Bus independent dongle command */331220struct brcmf_dcmd {···84535struct brcmf_pub {85536 /* Linkage ponters */86537 struct brcmf_bus *bus_if;8787- struct brcmf_proto *prot;538538+ struct brcmf_proto *proto;88539 struct brcmf_cfg80211_info *config;8954090541 /* Internal brcmf items */···93544 u8 wme_dp; /* wme discard priority */9454595546 /* Dongle media info */9696- unsigned long drv_version; /* Version of dongle-resident driver */547547+ char fwver[BRCMF_DRIVER_FIRMWARE_VERSION_LEN];97548 u8 mac[ETH_ALEN]; /* MAC address obtained from dongle */9854999550 /* Multicast data packets sent to dongle */···113564#ifdef DEBUG114565 struct dentry *dbgfs_dir;115566#endif116116-};117117-118118-struct brcmf_if_event {119119- u8 ifidx;120120- u8 action;121121- u8 flags;122122- u8 bssidx;123123- u8 role;124567};125568126569/* forward declarations */···176635/* Return pointer to interface name */177636char *brcmf_ifname(struct brcmf_pub *drvr, int idx);178637179179-/* Query dongle */180180-int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,181181- void *buf, uint len);182182-int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,183183- void *buf, uint len);184184-185185-/* Remove any protocol-specific data header. */186186-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,187187- struct sk_buff *rxp);188188-189638int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked);190639struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, s32 bssidx, s32 ifidx,191640 char *name, u8 *mac_addr);···185654u32 brcmf_get_chip_info(struct brcmf_if *ifp);186655void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,187656 bool success);657657+658658+/* Sets dongle media info (drv_version, mac address). */659659+int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);188660189661#endif /* _BRCMF_H_ */
+13-2
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
···3434/**3535 * struct brcmf_bus_ops - bus callback operations.3636 *3737+ * @preinit: execute bus/device specific dongle init commands (optional).3738 * @init: prepare for communication with dongle.3839 * @stop: clear pending frames, disable data flow.3940 * @txdata: send a data frame to the dongle. When the data···5251 * indicated otherwise these callbacks are mandatory.5352 */5453struct brcmf_bus_ops {5454+ int (*preinit)(struct device *dev);5555 int (*init)(struct device *dev);5656 void (*stop)(struct device *dev);5757 int (*txdata)(struct device *dev, struct sk_buff *skb);···8785 unsigned long tx_realloc;8886 u32 chip;8987 u32 chiprev;9090- struct list_head dcmd_list;91889289 struct brcmf_bus_ops *ops;9390};···9493/*9594 * callback wrappers9695 */9696+static inline int brcmf_bus_preinit(struct brcmf_bus *bus)9797+{9898+ if (!bus->ops->preinit)9999+ return 0;100100+ return bus->ops->preinit(bus->dev);101101+}102102+97103static inline int brcmf_bus_init(struct brcmf_bus *bus)98104{99105 return bus->ops->init(bus->dev);···147139void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);148140149141/* Indication from bus module regarding presence/insertion of dongle. */150150-int brcmf_attach(uint bus_hdrlen, struct device *dev);142142+int brcmf_attach(struct device *dev);151143/* Indication from bus module regarding removal/absence of dongle */152144void brcmf_detach(struct device *dev);153145/* Indication from bus module that dongle should be reset */···159151void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);160152161153int brcmf_bus_start(struct device *dev);154154+s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data,155155+ u32 len);156156+void brcmf_bus_add_txhdrlen(struct device *dev, uint len);162157163158#ifdef CONFIG_BRCMFMAC_SDIO164159void brcmf_sdio_exit(void);
-392
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
···11-/*22- * Copyright (c) 2010 Broadcom Corporation33- *44- * Permission to use, copy, modify, and/or distribute this software for any55- * purpose with or without fee is hereby granted, provided that the above66- * copyright notice and this permission notice appear in all copies.77- *88- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515- */1616-1717-/*******************************************************************************1818- * Communicates with the dongle by using dcmd codes.1919- * For certain dcmd codes, the dongle interprets string data from the host.2020- ******************************************************************************/2121-2222-#include <linux/types.h>2323-#include <linux/netdevice.h>2424-2525-#include <brcmu_utils.h>2626-#include <brcmu_wifi.h>2727-2828-#include "dhd.h"2929-#include "dhd_proto.h"3030-#include "dhd_bus.h"3131-#include "fwsignal.h"3232-#include "dhd_dbg.h"3333-#include "tracepoint.h"3434-3535-struct brcmf_proto_cdc_dcmd {3636- __le32 cmd; /* dongle command value */3737- __le32 len; /* lower 16: output buflen;3838- * upper 16: input buflen (excludes header) */3939- __le32 flags; /* flag defns given below */4040- __le32 status; /* status code returned from the device */4141-};4242-4343-/* Max valid buffer size that can be sent to the dongle */4444-#define CDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN)4545-4646-/* CDC flag definitions */4747-#define CDC_DCMD_ERROR 0x01 /* 1=cmd failed */4848-#define CDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */4949-#define CDC_DCMD_IF_MASK 0xF000 /* I/F index */5050-#define CDC_DCMD_IF_SHIFT 125151-#define CDC_DCMD_ID_MASK 0xFFFF0000 /* id an cmd pairing */5252-#define CDC_DCMD_ID_SHIFT 16 /* ID Mask shift bits */5353-#define CDC_DCMD_ID(flags) \5454- (((flags) & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT)5555-5656-/*5757- * BDC header - Broadcom specific extension of CDC.5858- * Used on data packets to convey priority across USB.5959- */6060-#define BDC_HEADER_LEN 46161-#define BDC_PROTO_VER 2 /* Protocol version */6262-#define BDC_FLAG_VER_MASK 0xf0 /* Protocol version mask */6363-#define BDC_FLAG_VER_SHIFT 4 /* Protocol version shift */6464-#define BDC_FLAG_SUM_GOOD 0x04 /* Good RX checksums */6565-#define BDC_FLAG_SUM_NEEDED 0x08 /* Dongle needs to do TX checksums */6666-#define BDC_PRIORITY_MASK 0x76767-#define BDC_FLAG2_IF_MASK 0x0f /* packet rx interface in APSTA */6868-#define BDC_FLAG2_IF_SHIFT 06969-7070-#define BDC_GET_IF_IDX(hdr) \7171- ((int)((((hdr)->flags2) & BDC_FLAG2_IF_MASK) >> BDC_FLAG2_IF_SHIFT))7272-#define BDC_SET_IF_IDX(hdr, idx) \7373- ((hdr)->flags2 = (((hdr)->flags2 & ~BDC_FLAG2_IF_MASK) | \7474- ((idx) << BDC_FLAG2_IF_SHIFT)))7575-7676-/**7777- * struct brcmf_proto_bdc_header - BDC header format7878- *7979- * @flags: flags contain protocol and checksum info.8080- * @priority: 802.1d priority and USB flow control info (bit 4:7).8181- * @flags2: additional flags containing dongle interface index.8282- * @data_offset: start of packet data. header is following by firmware signals.8383- */8484-struct brcmf_proto_bdc_header {8585- u8 flags;8686- u8 priority;8787- u8 flags2;8888- u8 data_offset;8989-};9090-9191-/*9292- * maximum length of firmware signal data between9393- * the BDC header and packet data in the tx path.9494- */9595-#define BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES 129696-9797-#define RETRIES 2 /* # of retries to retrieve matching dcmd response */9898-#define BUS_HEADER_LEN (16+64) /* Must be atleast SDPCM_RESERVE9999- * (amount of header tha might be added)100100- * plus any space that might be needed101101- * for bus alignment padding.102102- */103103-#define ROUND_UP_MARGIN 2048 /* Biggest bus block size possible for104104- * round off at the end of buffer105105- * Currently is SDIO106106- */107107-108108-struct brcmf_proto {109109- u16 reqid;110110- u8 bus_header[BUS_HEADER_LEN];111111- struct brcmf_proto_cdc_dcmd msg;112112- unsigned char buf[BRCMF_DCMD_MAXLEN + ROUND_UP_MARGIN];113113-};114114-115115-static int brcmf_proto_cdc_msg(struct brcmf_pub *drvr)116116-{117117- struct brcmf_proto *prot = drvr->prot;118118- int len = le32_to_cpu(prot->msg.len) +119119- sizeof(struct brcmf_proto_cdc_dcmd);120120-121121- brcmf_dbg(CDC, "Enter\n");122122-123123- /* NOTE : cdc->msg.len holds the desired length of the buffer to be124124- * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area125125- * is actually sent to the dongle126126- */127127- if (len > CDC_MAX_MSG_SIZE)128128- len = CDC_MAX_MSG_SIZE;129129-130130- /* Send request */131131- return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&prot->msg, len);132132-}133133-134134-static int brcmf_proto_cdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)135135-{136136- int ret;137137- struct brcmf_proto *prot = drvr->prot;138138-139139- brcmf_dbg(CDC, "Enter\n");140140- len += sizeof(struct brcmf_proto_cdc_dcmd);141141- do {142142- ret = brcmf_bus_rxctl(drvr->bus_if, (unsigned char *)&prot->msg,143143- len);144144- if (ret < 0)145145- break;146146- } while (CDC_DCMD_ID(le32_to_cpu(prot->msg.flags)) != id);147147-148148- return ret;149149-}150150-151151-int152152-brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,153153- void *buf, uint len)154154-{155155- struct brcmf_proto *prot = drvr->prot;156156- struct brcmf_proto_cdc_dcmd *msg = &prot->msg;157157- void *info;158158- int ret = 0, retries = 0;159159- u32 id, flags;160160-161161- brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);162162-163163- memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));164164-165165- msg->cmd = cpu_to_le32(cmd);166166- msg->len = cpu_to_le32(len);167167- flags = (++prot->reqid << CDC_DCMD_ID_SHIFT);168168- flags = (flags & ~CDC_DCMD_IF_MASK) |169169- (ifidx << CDC_DCMD_IF_SHIFT);170170- msg->flags = cpu_to_le32(flags);171171-172172- if (buf)173173- memcpy(prot->buf, buf, len);174174-175175- ret = brcmf_proto_cdc_msg(drvr);176176- if (ret < 0) {177177- brcmf_err("brcmf_proto_cdc_msg failed w/status %d\n",178178- ret);179179- goto done;180180- }181181-182182-retry:183183- /* wait for interrupt and get first fragment */184184- ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);185185- if (ret < 0)186186- goto done;187187-188188- flags = le32_to_cpu(msg->flags);189189- id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;190190-191191- if ((id < prot->reqid) && (++retries < RETRIES))192192- goto retry;193193- if (id != prot->reqid) {194194- brcmf_err("%s: unexpected request id %d (expected %d)\n",195195- brcmf_ifname(drvr, ifidx), id, prot->reqid);196196- ret = -EINVAL;197197- goto done;198198- }199199-200200- /* Check info buffer */201201- info = (void *)&msg[1];202202-203203- /* Copy info buffer */204204- if (buf) {205205- if (ret < (int)len)206206- len = ret;207207- memcpy(buf, info, len);208208- }209209-210210- /* Check the ERROR flag */211211- if (flags & CDC_DCMD_ERROR)212212- ret = le32_to_cpu(msg->status);213213-214214-done:215215- return ret;216216-}217217-218218-int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,219219- void *buf, uint len)220220-{221221- struct brcmf_proto *prot = drvr->prot;222222- struct brcmf_proto_cdc_dcmd *msg = &prot->msg;223223- int ret = 0;224224- u32 flags, id;225225-226226- brcmf_dbg(CDC, "Enter, cmd %d len %d\n", cmd, len);227227-228228- memset(msg, 0, sizeof(struct brcmf_proto_cdc_dcmd));229229-230230- msg->cmd = cpu_to_le32(cmd);231231- msg->len = cpu_to_le32(len);232232- flags = (++prot->reqid << CDC_DCMD_ID_SHIFT) | CDC_DCMD_SET;233233- flags = (flags & ~CDC_DCMD_IF_MASK) |234234- (ifidx << CDC_DCMD_IF_SHIFT);235235- msg->flags = cpu_to_le32(flags);236236-237237- if (buf)238238- memcpy(prot->buf, buf, len);239239-240240- ret = brcmf_proto_cdc_msg(drvr);241241- if (ret < 0)242242- goto done;243243-244244- ret = brcmf_proto_cdc_cmplt(drvr, prot->reqid, len);245245- if (ret < 0)246246- goto done;247247-248248- flags = le32_to_cpu(msg->flags);249249- id = (flags & CDC_DCMD_ID_MASK) >> CDC_DCMD_ID_SHIFT;250250-251251- if (id != prot->reqid) {252252- brcmf_err("%s: unexpected request id %d (expected %d)\n",253253- brcmf_ifname(drvr, ifidx), id, prot->reqid);254254- ret = -EINVAL;255255- goto done;256256- }257257-258258- /* Check the ERROR flag */259259- if (flags & CDC_DCMD_ERROR)260260- ret = le32_to_cpu(msg->status);261261-262262-done:263263- return ret;264264-}265265-266266-static bool pkt_sum_needed(struct sk_buff *skb)267267-{268268- return skb->ip_summed == CHECKSUM_PARTIAL;269269-}270270-271271-static void pkt_set_sum_good(struct sk_buff *skb, bool x)272272-{273273- skb->ip_summed = (x ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE);274274-}275275-276276-void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx, u8 offset,277277- struct sk_buff *pktbuf)278278-{279279- struct brcmf_proto_bdc_header *h;280280-281281- brcmf_dbg(CDC, "Enter\n");282282-283283- /* Push BDC header used to convey priority for buses that don't */284284- skb_push(pktbuf, BDC_HEADER_LEN);285285-286286- h = (struct brcmf_proto_bdc_header *)(pktbuf->data);287287-288288- h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT);289289- if (pkt_sum_needed(pktbuf))290290- h->flags |= BDC_FLAG_SUM_NEEDED;291291-292292- h->priority = (pktbuf->priority & BDC_PRIORITY_MASK);293293- h->flags2 = 0;294294- h->data_offset = offset;295295- BDC_SET_IF_IDX(h, ifidx);296296- trace_brcmf_bdchdr(pktbuf->data);297297-}298298-299299-int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,300300- struct sk_buff *pktbuf)301301-{302302- struct brcmf_proto_bdc_header *h;303303-304304- brcmf_dbg(CDC, "Enter\n");305305-306306- /* Pop BDC header used to convey priority for buses that don't */307307-308308- if (pktbuf->len <= BDC_HEADER_LEN) {309309- brcmf_dbg(INFO, "rx data too short (%d <= %d)\n",310310- pktbuf->len, BDC_HEADER_LEN);311311- return -EBADE;312312- }313313-314314- trace_brcmf_bdchdr(pktbuf->data);315315- h = (struct brcmf_proto_bdc_header *)(pktbuf->data);316316-317317- *ifidx = BDC_GET_IF_IDX(h);318318- if (*ifidx >= BRCMF_MAX_IFS) {319319- brcmf_err("rx data ifnum out of range (%d)\n", *ifidx);320320- return -EBADE;321321- }322322- /* The ifidx is the idx to map to matching netdev/ifp. When receiving323323- * events this is easy because it contains the bssidx which maps324324- * 1-on-1 to the netdev/ifp. But for data frames the ifidx is rcvd.325325- * bssidx 1 is used for p2p0 and no data can be received or326326- * transmitted on it. Therefor bssidx is ifidx + 1 if ifidx > 0327327- */328328- if (*ifidx)329329- (*ifidx)++;330330-331331- if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) !=332332- BDC_PROTO_VER) {333333- brcmf_err("%s: non-BDC packet received, flags 0x%x\n",334334- brcmf_ifname(drvr, *ifidx), h->flags);335335- return -EBADE;336336- }337337-338338- if (h->flags & BDC_FLAG_SUM_GOOD) {339339- brcmf_dbg(CDC, "%s: BDC rcv, good checksum, flags 0x%x\n",340340- brcmf_ifname(drvr, *ifidx), h->flags);341341- pkt_set_sum_good(pktbuf, true);342342- }343343-344344- pktbuf->priority = h->priority & BDC_PRIORITY_MASK;345345-346346- skb_pull(pktbuf, BDC_HEADER_LEN);347347- if (do_fws)348348- brcmf_fws_hdrpull(drvr, *ifidx, h->data_offset << 2, pktbuf);349349- else350350- skb_pull(pktbuf, h->data_offset << 2);351351-352352- if (pktbuf->len == 0)353353- return -ENODATA;354354- return 0;355355-}356356-357357-int brcmf_proto_attach(struct brcmf_pub *drvr)358358-{359359- struct brcmf_proto *cdc;360360-361361- cdc = kzalloc(sizeof(struct brcmf_proto), GFP_ATOMIC);362362- if (!cdc)363363- goto fail;364364-365365- /* ensure that the msg buf directly follows the cdc msg struct */366366- if ((unsigned long)(&cdc->msg + 1) != (unsigned long)cdc->buf) {367367- brcmf_err("struct brcmf_proto is not correctly defined\n");368368- goto fail;369369- }370370-371371- drvr->prot = cdc;372372- drvr->hdrlen += BDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;373373- drvr->bus_if->maxctl = BRCMF_DCMD_MAXLEN +374374- sizeof(struct brcmf_proto_cdc_dcmd) + ROUND_UP_MARGIN;375375- return 0;376376-377377-fail:378378- kfree(cdc);379379- return -ENOMEM;380380-}381381-382382-/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */383383-void brcmf_proto_detach(struct brcmf_pub *drvr)384384-{385385- kfree(drvr->prot);386386- drvr->prot = NULL;387387-}388388-389389-void brcmf_proto_stop(struct brcmf_pub *drvr)390390-{391391- /* Nothing to do for CDC */392392-}
···2121#include <brcmu_utils.h>2222#include "dhd.h"2323#include "dhd_bus.h"2424-#include "dhd_proto.h"2524#include "dhd_dbg.h"2625#include "fwil.h"2626+#include "fwil_types.h"2727#include "tracepoint.h"28282929#define PKTFILTER_BUF_SIZE 128···257257 u8 buf[BRCMF_DCMD_SMLEN];258258 char *ptr;259259 s32 err;260260- struct brcmf_bus_dcmd *cmdlst;261261- struct list_head *cur, *q;262260263261 /* retreive mac address */264262 err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,···279281 }280282 ptr = (char *)buf;281283 strsep(&ptr, "\n");284284+282285 /* Print fw version info */283286 brcmf_err("Firmware version = %s\n", buf);287287+288288+ /* locate firmware version number for ethtool */289289+ ptr = strrchr(buf, ' ') + 1;290290+ strlcpy(ifp->drvr->fwver, ptr, sizeof(ifp->drvr->fwver));284291285292 /*286293 * Setup timeout if Beacons are lost and roam is off to report···345342 brcmf_c_pktfilter_offload_enable(ifp, BRCMF_DEFAULT_PACKET_FILTER,346343 0, true);347344348348- /* set bus specific command if there is any */349349- list_for_each_safe(cur, q, &ifp->drvr->bus_if->dcmd_list) {350350- cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list);351351- if (cmdlst->name && cmdlst->param && cmdlst->param_len) {352352- brcmf_fil_iovar_data_set(ifp, cmdlst->name,353353- cmdlst->param,354354- cmdlst->param_len);355355- }356356- list_del(cur);357357- kfree(cmdlst);358358- }345345+ /* do bus specific preinit here */346346+ err = brcmf_bus_preinit(ifp->drvr->bus_if);359347done:360348 return err;361349}
···11-/*22- * Copyright (c) 2010 Broadcom Corporation33- *44- * Permission to use, copy, modify, and/or distribute this software for any55- * purpose with or without fee is hereby granted, provided that the above66- * copyright notice and this permission notice appear in all copies.77- *88- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111- * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515- */1616-1717-#ifndef _BRCMF_PROTO_H_1818-#define _BRCMF_PROTO_H_1919-2020-/*2121- * Exported from the brcmf protocol module (brcmf_cdc)2222- */2323-2424-/* Linkage, sets prot link and updates hdrlen in pub */2525-int brcmf_proto_attach(struct brcmf_pub *drvr);2626-2727-/* Unlink, frees allocated protocol memory (including brcmf_proto) */2828-void brcmf_proto_detach(struct brcmf_pub *drvr);2929-3030-/* Stop protocol: sync w/dongle state. */3131-void brcmf_proto_stop(struct brcmf_pub *drvr);3232-3333-/* Add any protocol-specific data header.3434- * Caller must reserve prot_hdrlen prepend space.3535- */3636-void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx, u8 offset,3737- struct sk_buff *txp);3838-3939-/* Sets dongle media info (drv_version, mac address). */4040-int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);4141-4242-#endif /* _BRCMF_PROTO_H_ */
···2929#define BRCMF_ARP_OL_HOST_AUTO_REPLY 0x000000043030#define BRCMF_ARP_OL_PEER_AUTO_REPLY 0x0000000831313232+#define BRCMF_BSS_INFO_VERSION 109 /* curr ver of brcmf_bss_info_le struct */3333+#define BRCMF_BSS_RSSI_ON_CHANNEL 0x00023434+3535+#define BRCMF_STA_ASSOC 0x10 /* Associated */3636+3737+/* size of brcmf_scan_params not including variable length array */3838+#define BRCMF_SCAN_PARAMS_FIXED_SIZE 643939+4040+/* masks for channel and ssid count */4141+#define BRCMF_SCAN_PARAMS_COUNT_MASK 0x0000ffff4242+#define BRCMF_SCAN_PARAMS_NSSID_SHIFT 164343+4444+/* primary (ie tx) key */4545+#define BRCMF_PRIMARY_KEY (1 << 1)4646+#define DOT11_BSSTYPE_ANY 24747+#define BRCMF_ESCAN_REQ_VERSION 14848+4949+#define BRCMF_MAXRATES_IN_SET 16 /* max # of rates in rateset */32503351enum brcmf_fil_p2p_if_types {3452 BRCMF_FIL_P2P_IF_CLIENT,···10688 BRCMF_TDLS_MANUAL_EP_CREATE = 1,10789 BRCMF_TDLS_MANUAL_EP_DELETE = 3,10890 BRCMF_TDLS_MANUAL_EP_DISCOVERY = 69191+};9292+9393+/* Pattern matching filter. Specifies an offset within received packets to9494+ * start matching, the pattern to match, the size of the pattern, and a bitmask9595+ * that indicates which bits within the pattern should be matched.9696+ */9797+struct brcmf_pkt_filter_pattern_le {9898+ /*9999+ * Offset within received packet to start pattern matching.100100+ * Offset '0' is the first byte of the ethernet header.101101+ */102102+ __le32 offset;103103+ /* Size of the pattern. Bitmask must be the same size.*/104104+ __le32 size_bytes;105105+ /*106106+ * Variable length mask and pattern data. mask starts at offset 0.107107+ * Pattern immediately follows mask.108108+ */109109+ u8 mask_and_pattern[1];110110+};111111+112112+/* IOVAR "pkt_filter_add" parameter. Used to install packet filters. */113113+struct brcmf_pkt_filter_le {114114+ __le32 id; /* Unique filter id, specified by app. */115115+ __le32 type; /* Filter type (WL_PKT_FILTER_TYPE_xxx). */116116+ __le32 negate_match; /* Negate the result of filter matches */117117+ union { /* Filter definitions */118118+ struct brcmf_pkt_filter_pattern_le pattern; /* Filter pattern */119119+ } u;120120+};121121+122122+/* IOVAR "pkt_filter_enable" parameter. */123123+struct brcmf_pkt_filter_enable_le {124124+ __le32 id; /* Unique filter id */125125+ __le32 enable; /* Enable/disable bool */126126+};127127+128128+/* BSS info structure129129+ * Applications MUST CHECK ie_offset field and length field to access IEs and130130+ * next bss_info structure in a vector (in struct brcmf_scan_results)131131+ */132132+struct brcmf_bss_info_le {133133+ __le32 version; /* version field */134134+ __le32 length; /* byte length of data in this record,135135+ * starting at version and including IEs136136+ */137137+ u8 BSSID[ETH_ALEN];138138+ __le16 beacon_period; /* units are Kusec */139139+ __le16 capability; /* Capability information */140140+ u8 SSID_len;141141+ u8 SSID[32];142142+ struct {143143+ __le32 count; /* # rates in this set */144144+ u8 rates[16]; /* rates in 500kbps units w/hi bit set if basic */145145+ } rateset; /* supported rates */146146+ __le16 chanspec; /* chanspec for bss */147147+ __le16 atim_window; /* units are Kusec */148148+ u8 dtim_period; /* DTIM period */149149+ __le16 RSSI; /* receive signal strength (in dBm) */150150+ s8 phy_noise; /* noise (in dBm) */151151+152152+ u8 n_cap; /* BSS is 802.11N Capable */153153+ /* 802.11N BSS Capabilities (based on HT_CAP_*): */154154+ __le32 nbss_cap;155155+ u8 ctl_ch; /* 802.11N BSS control channel number */156156+ __le32 reserved32[1]; /* Reserved for expansion of BSS properties */157157+ u8 flags; /* flags */158158+ u8 reserved[3]; /* Reserved for expansion of BSS properties */159159+ u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */160160+161161+ __le16 ie_offset; /* offset at which IEs start, from beginning */162162+ __le32 ie_length; /* byte length of Information Elements */163163+ __le16 SNR; /* average SNR of during frame reception */164164+ /* Add new fields here */165165+ /* variable length Information Elements */166166+};167167+168168+struct brcm_rateset_le {169169+ /* # rates in this set */170170+ __le32 count;171171+ /* rates in 500kbps units w/hi bit set if basic */172172+ u8 rates[BRCMF_MAXRATES_IN_SET];173173+};174174+175175+struct brcmf_ssid {176176+ u32 SSID_len;177177+ unsigned char SSID[32];178178+};179179+180180+struct brcmf_ssid_le {181181+ __le32 SSID_len;182182+ unsigned char SSID[32];183183+};184184+185185+struct brcmf_scan_params_le {186186+ struct brcmf_ssid_le ssid_le; /* default: {0, ""} */187187+ u8 bssid[ETH_ALEN]; /* default: bcast */188188+ s8 bss_type; /* default: any,189189+ * DOT11_BSSTYPE_ANY/INFRASTRUCTURE/INDEPENDENT190190+ */191191+ u8 scan_type; /* flags, 0 use default */192192+ __le32 nprobes; /* -1 use default, number of probes per channel */193193+ __le32 active_time; /* -1 use default, dwell time per channel for194194+ * active scanning195195+ */196196+ __le32 passive_time; /* -1 use default, dwell time per channel197197+ * for passive scanning198198+ */199199+ __le32 home_time; /* -1 use default, dwell time for the200200+ * home channel between channel scans201201+ */202202+ __le32 channel_num; /* count of channels and ssids that follow203203+ *204204+ * low half is count of channels in205205+ * channel_list, 0 means default (use all206206+ * available channels)207207+ *208208+ * high half is entries in struct brcmf_ssid209209+ * array that follows channel_list, aligned for210210+ * s32 (4 bytes) meaning an odd channel count211211+ * implies a 2-byte pad between end of212212+ * channel_list and first ssid213213+ *214214+ * if ssid count is zero, single ssid in the215215+ * fixed parameter portion is assumed, otherwise216216+ * ssid in the fixed portion is ignored217217+ */218218+ __le16 channel_list[1]; /* list of chanspecs */219219+};220220+221221+struct brcmf_scan_results {222222+ u32 buflen;223223+ u32 version;224224+ u32 count;225225+ struct brcmf_bss_info_le bss_info_le[];226226+};227227+228228+struct brcmf_escan_params_le {229229+ __le32 version;230230+ __le16 action;231231+ __le16 sync_id;232232+ struct brcmf_scan_params_le params_le;233233+};234234+235235+struct brcmf_escan_result_le {236236+ __le32 buflen;237237+ __le32 version;238238+ __le16 sync_id;239239+ __le16 bss_count;240240+ struct brcmf_bss_info_le bss_info_le;241241+};242242+243243+#define WL_ESCAN_RESULTS_FIXED_SIZE (sizeof(struct brcmf_escan_result_le) - \244244+ sizeof(struct brcmf_bss_info_le))245245+246246+/* used for association with a specific BSSID and chanspec list */247247+struct brcmf_assoc_params_le {248248+ /* 00:00:00:00:00:00: broadcast scan */249249+ u8 bssid[ETH_ALEN];250250+ /* 0: all available channels, otherwise count of chanspecs in251251+ * chanspec_list */252252+ __le32 chanspec_num;253253+ /* list of chanspecs */254254+ __le16 chanspec_list[1];255255+};256256+257257+/* used for join with or without a specific bssid and channel list */258258+struct brcmf_join_params {259259+ struct brcmf_ssid_le ssid_le;260260+ struct brcmf_assoc_params_le params_le;261261+};262262+263263+/* scan params for extended join */264264+struct brcmf_join_scan_params_le {265265+ u8 scan_type; /* 0 use default, active or passive scan */266266+ __le32 nprobes; /* -1 use default, nr of probes per channel */267267+ __le32 active_time; /* -1 use default, dwell time per channel for268268+ * active scanning269269+ */270270+ __le32 passive_time; /* -1 use default, dwell time per channel271271+ * for passive scanning272272+ */273273+ __le32 home_time; /* -1 use default, dwell time for the home274274+ * channel between channel scans275275+ */276276+};277277+278278+/* extended join params */279279+struct brcmf_ext_join_params_le {280280+ struct brcmf_ssid_le ssid_le; /* {0, ""}: wildcard scan */281281+ struct brcmf_join_scan_params_le scan_le;282282+ struct brcmf_assoc_params_le assoc_le;283283+};284284+285285+struct brcmf_wsec_key {286286+ u32 index; /* key index */287287+ u32 len; /* key length */288288+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */289289+ u32 pad_1[18];290290+ u32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */291291+ u32 flags; /* misc flags */292292+ u32 pad_2[3];293293+ u32 iv_initialized; /* has IV been initialized already? */294294+ u32 pad_3;295295+ /* Rx IV */296296+ struct {297297+ u32 hi; /* upper 32 bits of IV */298298+ u16 lo; /* lower 16 bits of IV */299299+ } rxiv;300300+ u32 pad_4[2];301301+ u8 ea[ETH_ALEN]; /* per station */302302+};303303+304304+/*305305+ * dongle requires same struct as above but with fields in little endian order306306+ */307307+struct brcmf_wsec_key_le {308308+ __le32 index; /* key index */309309+ __le32 len; /* key length */310310+ u8 data[WLAN_MAX_KEY_LEN]; /* key data */311311+ __le32 pad_1[18];312312+ __le32 algo; /* CRYPTO_ALGO_AES_CCM, CRYPTO_ALGO_WEP128, etc */313313+ __le32 flags; /* misc flags */314314+ __le32 pad_2[3];315315+ __le32 iv_initialized; /* has IV been initialized already? */316316+ __le32 pad_3;317317+ /* Rx IV */318318+ struct {319319+ __le32 hi; /* upper 32 bits of IV */320320+ __le16 lo; /* lower 16 bits of IV */321321+ } rxiv;322322+ __le32 pad_4[2];323323+ u8 ea[ETH_ALEN]; /* per station */324324+};325325+326326+/* Used to get specific STA parameters */327327+struct brcmf_scb_val_le {328328+ __le32 val;329329+ u8 ea[ETH_ALEN];330330+};331331+332332+/* channel encoding */333333+struct brcmf_channel_info_le {334334+ __le32 hw_channel;335335+ __le32 target_channel;336336+ __le32 scan_channel;337337+};338338+339339+struct brcmf_sta_info_le {340340+ __le16 ver; /* version of this struct */341341+ __le16 len; /* length in bytes of this structure */342342+ __le16 cap; /* sta's advertised capabilities */343343+ __le32 flags; /* flags defined below */344344+ __le32 idle; /* time since data pkt rx'd from sta */345345+ u8 ea[ETH_ALEN]; /* Station address */346346+ __le32 count; /* # rates in this set */347347+ u8 rates[BRCMF_MAXRATES_IN_SET]; /* rates in 500kbps units */348348+ /* w/hi bit set if basic */349349+ __le32 in; /* seconds elapsed since associated */350350+ __le32 listen_interval_inms; /* Min Listen interval in ms for STA */351351+ __le32 tx_pkts; /* # of packets transmitted */352352+ __le32 tx_failures; /* # of packets failed */353353+ __le32 rx_ucast_pkts; /* # of unicast packets received */354354+ __le32 rx_mcast_pkts; /* # of multicast packets received */355355+ __le32 tx_rate; /* Rate of last successful tx frame */356356+ __le32 rx_rate; /* Rate of last successful rx frame */357357+ __le32 rx_decrypt_succeeds; /* # of packet decrypted successfully */358358+ __le32 rx_decrypt_failures; /* # of packet decrypted failed */359359+};360360+361361+struct brcmf_chanspec_list {362362+ __le32 count; /* # of entries */363363+ __le32 element[1]; /* variable length uint32 list */364364+};365365+366366+/*367367+ * WLC_E_PROBRESP_MSG368368+ * WLC_E_P2P_PROBREQ_MSG369369+ * WLC_E_ACTION_FRAME_RX370370+ */371371+struct brcmf_rx_mgmt_data {372372+ __be16 version;373373+ __be16 chanspec;374374+ __be32 rssi;375375+ __be32 mactime;376376+ __be32 rate;109377};110378111379#endif /* FWIL_TYPES_H_ */
···11+/*22+ * Copyright (c) 2013 Broadcom Corporation33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+1717+1818+ #include <linux/types.h>1919+#include <linux/slab.h>2020+#include <linux/netdevice.h>2121+2222+#include <brcmu_wifi.h>2323+#include "dhd.h"2424+#include "dhd_dbg.h"2525+#include "proto.h"2626+#include "bcdc.h"2727+2828+2929+int brcmf_proto_attach(struct brcmf_pub *drvr)3030+{3131+ struct brcmf_proto *proto;3232+3333+ proto = kzalloc(sizeof(*proto), GFP_ATOMIC);3434+ if (!proto)3535+ goto fail;3636+3737+ drvr->proto = proto;3838+ /* BCDC protocol is only protocol supported for the moment */3939+ if (brcmf_proto_bcdc_attach(drvr))4040+ goto fail;4141+4242+ if ((proto->hdrpush == NULL) || (proto->hdrpull == NULL) ||4343+ (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL)) {4444+ brcmf_err("Not all proto handlers have been installed\n");4545+ goto fail;4646+ }4747+ return 0;4848+4949+fail:5050+ kfree(proto);5151+ drvr->proto = NULL;5252+ return -ENOMEM;5353+}5454+5555+void brcmf_proto_detach(struct brcmf_pub *drvr)5656+{5757+ if (drvr->proto) {5858+ brcmf_proto_bcdc_detach(drvr);5959+ kfree(drvr->proto);6060+ drvr->proto = NULL;6161+ }6262+}
+57
drivers/net/wireless/brcm80211/brcmfmac/proto.h
···11+/*22+ * Copyright (c) 2013 Broadcom Corporation33+ *44+ * Permission to use, copy, modify, and/or distribute this software for any55+ * purpose with or without fee is hereby granted, provided that the above66+ * copyright notice and this permission notice appear in all copies.77+ *88+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES99+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF1010+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY1111+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES1212+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION1313+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN1414+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.1515+ */1616+#ifndef BRCMFMAC_PROTO_H1717+#define BRCMFMAC_PROTO_H1818+1919+struct brcmf_proto {2020+ void (*hdrpush)(struct brcmf_pub *drvr, int ifidx, u8 offset,2121+ struct sk_buff *skb);2222+ int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws, u8 *ifidx,2323+ struct sk_buff *skb);2424+ int (*query_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd,2525+ void *buf, uint len);2626+ int (*set_dcmd)(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,2727+ uint len);2828+ void *pd;2929+};3030+3131+3232+int brcmf_proto_attach(struct brcmf_pub *drvr);3333+void brcmf_proto_detach(struct brcmf_pub *drvr);3434+3535+static inline void brcmf_proto_hdrpush(struct brcmf_pub *drvr, int ifidx,3636+ u8 offset, struct sk_buff *skb)3737+{3838+ drvr->proto->hdrpush(drvr, ifidx, offset, skb);3939+}4040+static inline int brcmf_proto_hdrpull(struct brcmf_pub *drvr, bool do_fws,4141+ u8 *ifidx, struct sk_buff *skb)4242+{4343+ return drvr->proto->hdrpull(drvr, do_fws, ifidx, skb);4444+}4545+static inline int brcmf_proto_query_dcmd(struct brcmf_pub *drvr, int ifidx,4646+ uint cmd, void *buf, uint len)4747+{4848+ return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len);4949+}5050+static inline int brcmf_proto_set_dcmd(struct brcmf_pub *drvr, int ifidx,5151+ uint cmd, void *buf, uint len)5252+{5353+ return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len);5454+}5555+5656+5757+#endif /* BRCMFMAC_PROTO_H */
···192192 for (i = 0; i < cmd->channel_count; i++) {193193 chan->channel = cpu_to_le16(req->channels[i]->hw_value);194194 chan->type = cpu_to_le32(type);195195- if (req->channels[i]->flags & IEEE80211_CHAN_PASSIVE_SCAN)195195+ if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)196196 chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);197197 chan->active_dwell = cpu_to_le16(active_dwell);198198 chan->passive_dwell = cpu_to_le16(passive_dwell);···642642 channels->iter_count[index] = cpu_to_le16(1);643643 channels->iter_interval[index] = 0;644644645645- if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))645645+ if (!(s_band->channels[i].flags & IEEE80211_CHAN_NO_IR))646646 channels->type[index] |=647647 cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);648648
+3-3
drivers/net/wireless/libertas/if_sdio.c
···849849 card->started = true;850850 /* Tell PM core that we don't need the card to be851851 * powered now */852852- pm_runtime_put_noidle(&func->dev);852852+ pm_runtime_put(&func->dev);853853 }854854 }855855···907907 sdio_release_host(func);908908 ret = if_sdio_prog_firmware(card);909909 if (ret) {910910- sdio_disable_func(func);911911- return ret;910910+ sdio_claim_host(func);911911+ goto disable;912912 }913913914914 return 0;
···416416 struct rtl8187_rx_info *info;417417 int ret = 0;418418419419- while (skb_queue_len(&priv->rx_queue) < 16) {419419+ while (skb_queue_len(&priv->rx_queue) < 32) {420420 skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL);421421 if (!skb) {422422 ret = -ENOMEM;
+2-1
drivers/net/wireless/rtlwifi/base.c
···14371437 /* if we can't recv beacon for 6s, we should14381438 * reconnect this AP14391439 */14401440- if (rtlpriv->link_info.roam_times >= 3) {14401440+ if ((rtlpriv->link_info.roam_times >= 3) &&14411441+ !is_zero_ether_addr(rtlpriv->mac80211.bssid)) {14411442 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,14421443 "AP off, try to reconnect now\n");14431444 rtlpriv->link_info.roam_times = 0;
+11
drivers/net/wireless/rtlwifi/core.c
···4646 "Firmware callback routine entered!\n");4747 complete(&rtlpriv->firmware_loading_complete);4848 if (!firmware) {4949+ if (rtlpriv->cfg->alt_fw_name) {5050+ err = request_firmware(&firmware,5151+ rtlpriv->cfg->alt_fw_name,5252+ rtlpriv->io.dev);5353+ pr_info("Loading alternative firmware %s\n",5454+ rtlpriv->cfg->alt_fw_name);5555+ if (!err)5656+ goto found_alt;5757+ }4958 pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);5059 rtlpriv->max_fw_size = 0;5160 return;5261 }6262+found_alt:5363 if (firmware->size > rtlpriv->max_fw_size) {5464 RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,5565 "Firmware is too big!\n");···194184 rtlpriv->cfg->maps195185 [RTL_IBSS_INT_MASKS]);196186 }187187+ mac->link_state = MAC80211_LINKED;197188 break;198189 case NL80211_IFTYPE_ADHOC:199190 RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
···9191 * Channel flags set by the regulatory control code.9292 *9393 * @IEEE80211_CHAN_DISABLED: This channel is disabled.9494- * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted9595- * on this channel.9696- * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel.9494+ * @IEEE80211_CHAN_NO_IR: do not initiate radiation, this includes9595+ * sending probe requests or beaconing.9796 * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel.9897 * @IEEE80211_CHAN_NO_HT40PLUS: extension channel above this channel9998 * is not permitted.···112113 */113114enum ieee80211_channel_flags {114115 IEEE80211_CHAN_DISABLED = 1<<0,115115- IEEE80211_CHAN_PASSIVE_SCAN = 1<<1,116116- IEEE80211_CHAN_NO_IBSS = 1<<2,116116+ IEEE80211_CHAN_NO_IR = 1<<1,117117+ /* hole at 1<<2 */117118 IEEE80211_CHAN_RADAR = 1<<3,118119 IEEE80211_CHAN_NO_HT40PLUS = 1<<4,119120 IEEE80211_CHAN_NO_HT40MINUS = 1<<5,···19441945};1945194619461947/**19481948+ * struct cfg80211_mgmt_tx_params - mgmt tx parameters19491949+ *19501950+ * This structure provides information needed to transmit a mgmt frame19511951+ *19521952+ * @chan: channel to use19531953+ * @offchan: indicates wether off channel operation is required19541954+ * @wait: duration for ROC19551955+ * @buf: buffer to transmit19561956+ * @len: buffer length19571957+ * @no_cck: don't use cck rates for this frame19581958+ * @dont_wait_for_ack: tells the low level not to wait for an ack19591959+ */19601960+struct cfg80211_mgmt_tx_params {19611961+ struct ieee80211_channel *chan;19621962+ bool offchan;19631963+ unsigned int wait;19641964+ const u8 *buf;19651965+ size_t len;19661966+ bool no_cck;19671967+ bool dont_wait_for_ack;19681968+};19691969+19701970+/**19471971 * struct cfg80211_ops - backend description for wireless configuration19481972 *19491973 * This struct is registered by fullmac card drivers and/or wireless stacks···23642342 u64 cookie);2365234323662344 int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,23672367- struct ieee80211_channel *chan, bool offchan,23682368- unsigned int wait, const u8 *buf, size_t len,23692369- bool no_cck, bool dont_wait_for_ack, u64 *cookie);23452345+ struct cfg80211_mgmt_tx_params *params,23462346+ u64 *cookie);23702347 int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,23712348 struct wireless_dev *wdev,23722349 u64 cookie);···24592438/**24602439 * enum wiphy_flags - wiphy capability flags24612440 *24622462- * @WIPHY_FLAG_CUSTOM_REGULATORY: tells us the driver for this device24632463- * has its own custom regulatory domain and cannot identify the24642464- * ISO / IEC 3166 alpha2 it belongs to. When this is enabled24652465- * we will disregard the first regulatory hint (when the24662466- * initiator is %REGDOM_SET_BY_CORE).24672467- * @WIPHY_FLAG_STRICT_REGULATORY: tells us the driver for this device will24682468- * ignore regulatory domain settings until it gets its own regulatory24692469- * domain via its regulatory_hint() unless the regulatory hint is24702470- * from a country IE. After its gets its own regulatory domain it will24712471- * only allow further regulatory domain settings to further enhance24722472- * compliance. For example if channel 13 and 14 are disabled by this24732473- * regulatory domain no user regulatory domain can enable these channels24742474- * at a later time. This can be used for devices which do not have24752475- * calibration information guaranteed for frequencies or settings24762476- * outside of its regulatory domain. If used in combination with24772477- * WIPHY_FLAG_CUSTOM_REGULATORY the inspected country IE power settings24782478- * will be followed.24792479- * @WIPHY_FLAG_DISABLE_BEACON_HINTS: enable this if your driver needs to ensure24802480- * that passive scan flags and beaconing flags may not be lifted by24812481- * cfg80211 due to regulatory beacon hints. For more information on beacon24822482- * hints read the documenation for regulatory_hint_found_beacon()24832441 * @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this24842442 * wiphy at all24852443 * @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled···24972497 * beaconing mode (AP, IBSS, Mesh, ...).24982498 */24992499enum wiphy_flags {25002500- WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),25012501- WIPHY_FLAG_STRICT_REGULATORY = BIT(1),25022502- WIPHY_FLAG_DISABLE_BEACON_HINTS = BIT(2),25002500+ /* use hole at 0 */25012501+ /* use hole at 1 */25022502+ /* use hole at 2 */25032503 WIPHY_FLAG_NETNS_OK = BIT(3),25042504 WIPHY_FLAG_PS_ON_BY_DEFAULT = BIT(4),25052505 WIPHY_FLAG_4ADDR_AP = BIT(5),···27212721 * @software_iftypes: bitmask of software interface types, these are not27222722 * subject to any restrictions since they are purely managed in SW.27232723 * @flags: wiphy flags, see &enum wiphy_flags27242724+ * @regulatory_flags: wiphy regulatory flags, see27252725+ * &enum ieee80211_regulatory_flags27242726 * @features: features advertised to nl80211, see &enum nl80211_feature_flags.27252727 * @bss_priv_size: each BSS struct has private data allocated with it,27262728 * this variable determines its size···2811280928122810 u16 max_acl_mac_addrs;2813281128142814- u32 flags, features;28122812+ u32 flags, regulatory_flags, features;2815281328162814 u32 ap_sme_capa;28172815···34743472 * custom regulatory domain will be trusted completely and as such previous34753473 * default channel settings will be disregarded. If no rule is found for a34763474 * channel on the regulatory domain the channel will be disabled.34753475+ * Drivers using this for a wiphy should also set the wiphy flag34763476+ * WIPHY_FLAG_CUSTOM_REGULATORY or cfg80211 will set it for the wiphy34773477+ * that called this helper.34773478 */34783479void wiphy_apply_custom_regulatory(struct wiphy *wiphy,34793480 const struct ieee80211_regdomain *regd);···41514146/**41524147 * cfg80211_cac_event - Channel availability check (CAC) event41534148 * @netdev: network device41494149+ * @chandef: chandef for the current channel41544150 * @event: type of event41554151 * @gfp: context flags41564152 *···41604154 * also by full-MAC drivers.41614155 */41624156void cfg80211_cac_event(struct net_device *netdev,41574157+ const struct cfg80211_chan_def *chandef,41634158 enum nl80211_radar_event event, gfp_t gfp);4164415941654160···42864279 * @dev: the device which switched channels42874280 * @chandef: the new channel definition42884281 *42894289- * Acquires wdev_lock, so must only be called from sleepable driver context!42824282+ * Caller must acquire wdev_lock, therefore must only be called from sleepable42834283+ * driver context!42904284 */42914285void cfg80211_ch_switch_notify(struct net_device *dev,42924286 struct cfg80211_chan_def *chandef);
+40
include/net/mac80211.h
···154154 * @IEEE80211_CHANCTX_CHANGE_RADAR: radar detection flag changed155155 * @IEEE80211_CHANCTX_CHANGE_CHANNEL: switched to another operating channel,156156 * this is used only with channel switching with CSA157157+ * @IEEE80211_CHANCTX_CHANGE_MIN_WIDTH: The min required channel width changed157158 */158159enum ieee80211_chanctx_change {159160 IEEE80211_CHANCTX_CHANGE_WIDTH = BIT(0),160161 IEEE80211_CHANCTX_CHANGE_RX_CHAINS = BIT(1),161162 IEEE80211_CHANCTX_CHANGE_RADAR = BIT(2),162163 IEEE80211_CHANCTX_CHANGE_CHANNEL = BIT(3),164164+ IEEE80211_CHANCTX_CHANGE_MIN_WIDTH = BIT(4),163165};164166165167/**···171169 * that contains it is visible in mac80211 only.172170 *173171 * @def: the channel definition172172+ * @min_def: the minimum channel definition currently required.174173 * @rx_chains_static: The number of RX chains that must always be175174 * active on the channel to receive MIMO transmissions176175 * @rx_chains_dynamic: The number of RX chains that must be enabled···183180 */184181struct ieee80211_chanctx_conf {185182 struct cfg80211_chan_def def;183183+ struct cfg80211_chan_def min_def;186184187185 u8 rx_chains_static, rx_chains_dynamic;188186···12331229};1234123012351231/**12321232+ * struct ieee80211_cipher_scheme - cipher scheme12331233+ *12341234+ * This structure contains a cipher scheme information defining12351235+ * the secure packet crypto handling.12361236+ *12371237+ * @cipher: a cipher suite selector12381238+ * @iftype: a cipher iftype bit mask indicating an allowed cipher usage12391239+ * @hdr_len: a length of a security header used the cipher12401240+ * @pn_len: a length of a packet number in the security header12411241+ * @pn_off: an offset of pn from the beginning of the security header12421242+ * @key_idx_off: an offset of key index byte in the security header12431243+ * @key_idx_mask: a bit mask of key_idx bits12441244+ * @key_idx_shift: a bit shift needed to get key_idx12451245+ * key_idx value calculation:12461246+ * (sec_header_base[key_idx_off] & key_idx_mask) >> key_idx_shift12471247+ * @mic_len: a mic length in bytes12481248+ */12491249+struct ieee80211_cipher_scheme {12501250+ u32 cipher;12511251+ u16 iftype;12521252+ u8 hdr_len;12531253+ u8 pn_len;12541254+ u8 pn_off;12551255+ u8 key_idx_off;12561256+ u8 key_idx_mask;12571257+ u8 key_idx_shift;12581258+ u8 mic_len;12591259+};12601260+12611261+/**12361262 * enum set_key_cmd - key command12371263 *12381264 * Used with the set_key() callback in &struct ieee80211_ops, this···16701636 * @uapsd_max_sp_len: maximum number of total buffered frames the WMM AP may16711637 * deliver to a WMM STA during any Service Period triggered by the WMM STA.16721638 * Use IEEE80211_WMM_IE_STA_QOSINFO_SP_* for correct values.16391639+ *16401640+ * @n_cipher_schemes: a size of an array of cipher schemes definitions.16411641+ * @cipher_schemes: a pointer to an array of cipher scheme definitions16421642+ * supported by HW.16731643 */16741644struct ieee80211_hw {16751645 struct ieee80211_conf conf;···17011663 netdev_features_t netdev_features;17021664 u8 uapsd_queues;17031665 u8 uapsd_max_sp_len;16661666+ u8 n_cipher_schemes;16671667+ const struct ieee80211_cipher_scheme *cipher_schemes;17041668};1705166917061670/**
+65-15
include/net/regulatory.h
···3838 *3939 * @rcu_head: RCU head struct used to free the request4040 * @wiphy_idx: this is set if this request's initiator is4141- * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This4242- * can be used by the wireless core to deal with conflicts4343- * and potentially inform users of which devices specifically4444- * cased the conflicts.4141+ * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This4242+ * can be used by the wireless core to deal with conflicts4343+ * and potentially inform users of which devices specifically4444+ * cased the conflicts.4545 * @initiator: indicates who sent this request, could be any of4646- * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)4646+ * of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)4747 * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested4848- * regulatory domain. We have a few special codes:4949- * 00 - World regulatory domain5050- * 99 - built by driver but a specific alpha2 cannot be determined5151- * 98 - result of an intersection between two regulatory domains4848+ * regulatory domain. We have a few special codes:4949+ * 00 - World regulatory domain5050+ * 99 - built by driver but a specific alpha2 cannot be determined5151+ * 98 - result of an intersection between two regulatory domains5252 * 97 - regulatory domain has not yet been configured5353 * @dfs_region: If CRDA responded with a regulatory domain that requires5454 * DFS master operation on a known DFS region (NL80211_DFS_*),···5959 * of hint passed. This could be any of the %NL80211_USER_REG_HINT_*6060 * types.6161 * @intersect: indicates whether the wireless core should intersect6262- * the requested regulatory domain with the presently set regulatory6363- * domain.6262+ * the requested regulatory domain with the presently set regulatory6363+ * domain.6464 * @processed: indicates whether or not this requests has already been6565 * processed. When the last request is processed it means that the6666 * currently regulatory domain set on cfg80211 is updated from···6868 * the last request is not yet processed we must yield until it6969 * is processed before processing any new requests.7070 * @country_ie_checksum: checksum of the last processed and accepted7171- * country IE7171+ * country IE7272 * @country_ie_env: lets us know if the AP is telling us we are outdoor,7373- * indoor, or if it doesn't matter7373+ * indoor, or if it doesn't matter7474 * @list: used to insert into the reg_requests_list linked list7575 */7676struct regulatory_request {···7979 enum nl80211_reg_initiator initiator;8080 enum nl80211_user_reg_hint_type user_reg_hint_type;8181 char alpha2[2];8282- u8 dfs_region;8282+ enum nl80211_dfs_regions dfs_region;8383 bool intersect;8484 bool processed;8585 enum environment_cap country_ie_env;8686 struct list_head list;8787+};8888+8989+/**9090+ * enum ieee80211_regulatory_flags - device regulatory flags9191+ *9292+ * @REGULATORY_CUSTOM_REG: tells us the driver for this device9393+ * has its own custom regulatory domain and cannot identify the9494+ * ISO / IEC 3166 alpha2 it belongs to. When this is enabled9595+ * we will disregard the first regulatory hint (when the9696+ * initiator is %REGDOM_SET_BY_CORE). Drivers that use9797+ * wiphy_apply_custom_regulatory() should have this flag set9898+ * or the regulatory core will set it for the wiphy.9999+ * @REGULATORY_STRICT_REG: tells us that the wiphy for this device100100+ * has regulatory domain that it wishes to be considered as the101101+ * superset for regulatory rules. After this device gets its regulatory102102+ * domain programmed further regulatory hints shall only be considered103103+ * for this device to enhance regulatory compliance, forcing the104104+ * device to only possibly use subsets of the original regulatory105105+ * rules. For example if channel 13 and 14 are disabled by this106106+ * device's regulatory domain no user specified regulatory hint which107107+ * has these channels enabled would enable them for this wiphy,108108+ * the device's original regulatory domain will be trusted as the109109+ * base. You can program the superset of regulatory rules for this110110+ * wiphy with regulatory_hint() for cards programmed with an111111+ * ISO3166-alpha2 country code. wiphys that use regulatory_hint()112112+ * will have their wiphy->regd programmed once the regulatory113113+ * domain is set, and all other regulatory hints will be ignored114114+ * until their own regulatory domain gets programmed.115115+ * @REGULATORY_DISABLE_BEACON_HINTS: enable this if your driver needs to116116+ * ensure that passive scan flags and beaconing flags may not be lifted by117117+ * cfg80211 due to regulatory beacon hints. For more information on beacon118118+ * hints read the documenation for regulatory_hint_found_beacon()119119+ * @REGULATORY_COUNTRY_IE_FOLLOW_POWER: for devices that have a preference120120+ * that even though they may have programmed their own custom power121121+ * setting prior to wiphy registration, they want to ensure their channel122122+ * power settings are updated for this connection with the power settings123123+ * derived from the regulatory domain. The regulatory domain used will be124124+ * based on the ISO3166-alpha2 from country IE provided through125125+ * regulatory_hint_country_ie()126126+ * @REGULATORY_COUNTRY_IE_IGNORE: for devices that have a preference to ignore127127+ * all country IE information processed by the regulatory core. This will128128+ * override %REGULATORY_COUNTRY_IE_FOLLOW_POWER as all country IEs will129129+ * be ignored.130130+ */131131+enum ieee80211_regulatory_flags {132132+ REGULATORY_CUSTOM_REG = BIT(0),133133+ REGULATORY_STRICT_REG = BIT(1),134134+ REGULATORY_DISABLE_BEACON_HINTS = BIT(2),135135+ REGULATORY_COUNTRY_IE_FOLLOW_POWER = BIT(3),136136+ REGULATORY_COUNTRY_IE_IGNORE = BIT(4),87137};8813889139struct ieee80211_freq_range {···157107 struct rcu_head rcu_head;158108 u32 n_reg_rules;159109 char alpha2[2];160160- u8 dfs_region;110110+ enum nl80211_dfs_regions dfs_region;161111 struct ieee80211_reg_rule reg_rules[];162112};163113
+36-11
include/uapi/linux/nl80211.h
···581581 * operation, %NL80211_ATTR_MAC contains the peer MAC address, and582582 * %NL80211_ATTR_REASON_CODE the reason code to be used (only with583583 * %NL80211_TDLS_TEARDOWN).584584- * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.584584+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame. The585585+ * %NL80211_ATTR_TDLS_ACTION attribute determines the type of frame to be586586+ * sent. Public Action codes (802.11-2012 8.1.5.1) will be sent as587587+ * 802.11 management frames, while TDLS action codes (802.11-2012588588+ * 8.5.13.1) will be encapsulated and sent as data frames. The currently589589+ * supported Public Action code is %WLAN_PUB_ACTION_TDLS_DISCOVER_RES590590+ * and the currently supported TDLS actions codes are given in591591+ * &enum ieee80211_tdls_actioncode.585592 *586593 * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP587594 * (or GO) interface (i.e. hostapd) to ask for unexpected frames to···15151508 * to react to radar events, e.g. initiate a channel switch or leave the15161509 * IBSS network.15171510 *15111511+ * @NL80211_ATTR_SUPPORT_5_MHZ: A flag indicating that the device supports15121512+ * 5 MHz channel bandwidth.15131513+ * @NL80211_ATTR_SUPPORT_10_MHZ: A flag indicating that the device supports15141514+ * 10 MHz channel bandwidth.15151515+ *15181516 * @NL80211_ATTR_MAX: highest attribute number currently defined15191517 * @__NL80211_ATTR_AFTER_LAST: internal use15201518 */···18351823 NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,1836182418371825 NL80211_ATTR_HANDLE_DFS,18261826+18271827+ NL80211_ATTR_SUPPORT_5_MHZ,18281828+ NL80211_ATTR_SUPPORT_10_MHZ,1838182918391830 /* add attributes here, update the policy in nl80211.c */18401831···22392224 * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz22402225 * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current22412226 * regulatory domain.22422242- * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is22432243- * permitted on this channel in current regulatory domain.22442244- * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted22452245- * on this channel in current regulatory domain.22272227+ * @NL80211_FREQUENCY_ATTR_NO_IR: no mechanisms that initiate radiation22282228+ * are permitted on this channel, this includes sending probe22292229+ * requests, or modes of operation that require beaconing.22462230 * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory22472231 * on this channel in current regulatory domain.22482232 * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm···22682254 __NL80211_FREQUENCY_ATTR_INVALID,22692255 NL80211_FREQUENCY_ATTR_FREQ,22702256 NL80211_FREQUENCY_ATTR_DISABLED,22712271- NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,22722272- NL80211_FREQUENCY_ATTR_NO_IBSS,22572257+ NL80211_FREQUENCY_ATTR_NO_IR,22582258+ __NL80211_FREQUENCY_ATTR_NO_IBSS,22732259 NL80211_FREQUENCY_ATTR_RADAR,22742260 NL80211_FREQUENCY_ATTR_MAX_TX_POWER,22752261 NL80211_FREQUENCY_ATTR_DFS_STATE,···22852271};2286227222872273#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER22742274+#define NL80211_FREQUENCY_ATTR_PASSIVE_SCAN NL80211_FREQUENCY_ATTR_NO_IR22752275+#define NL80211_FREQUENCY_ATTR_NO_IBSS NL80211_FREQUENCY_ATTR_NO_IR22762276+#define NL80211_FREQUENCY_ATTR_NO_IR NL80211_FREQUENCY_ATTR_NO_IR2288227722892278/**22902279 * enum nl80211_bitrate_attr - bitrate attributes···24302413 * @NL80211_RRF_DFS: DFS support is required to be used24312414 * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links24322415 * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links24332433- * @NL80211_RRF_PASSIVE_SCAN: passive scan is required24342434- * @NL80211_RRF_NO_IBSS: no IBSS is allowed24162416+ * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed,24172417+ * this includes probe requests or modes of operation that require24182418+ * beaconing.24352419 */24362420enum nl80211_reg_rule_flags {24372421 NL80211_RRF_NO_OFDM = 1<<0,···24422424 NL80211_RRF_DFS = 1<<4,24432425 NL80211_RRF_PTP_ONLY = 1<<5,24442426 NL80211_RRF_PTMP_ONLY = 1<<6,24452445- NL80211_RRF_PASSIVE_SCAN = 1<<7,24462446- NL80211_RRF_NO_IBSS = 1<<8,24272427+ NL80211_RRF_NO_IR = 1<<7,24282428+ __NL80211_RRF_NO_IBSS = 1<<8,24472429};24302430+24312431+#define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR24322432+#define NL80211_RRF_NO_IBSS NL80211_RRF_NO_IR24332433+#define NL80211_RRF_NO_IR NL80211_RRF_NO_IR24342434+24352435+/* For backport compatibility with older userspace */24362436+#define NL80211_RRF_NO_IR_ALL (NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)2448243724492438/**24502439 * enum nl80211_dfs_regions - regulatory DFS regions
+80-43
net/mac80211/cfg.c
···133133 struct key_params *params)134134{135135 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);136136+ struct ieee80211_local *local = sdata->local;136137 struct sta_info *sta = NULL;138138+ const struct ieee80211_cipher_scheme *cs = NULL;137139 struct ieee80211_key *key;138140 int err;139141···147145 case WLAN_CIPHER_SUITE_WEP40:148146 case WLAN_CIPHER_SUITE_TKIP:149147 case WLAN_CIPHER_SUITE_WEP104:150150- if (IS_ERR(sdata->local->wep_tx_tfm))148148+ if (IS_ERR(local->wep_tx_tfm))151149 return -EINVAL;152150 break;151151+ case WLAN_CIPHER_SUITE_CCMP:152152+ case WLAN_CIPHER_SUITE_AES_CMAC:153153+ case WLAN_CIPHER_SUITE_GCMP:154154+ break;153155 default:156156+ cs = ieee80211_cs_get(local, params->cipher, sdata->vif.type);154157 break;155158 }156159157160 key = ieee80211_key_alloc(params->cipher, key_idx, params->key_len,158158- params->key, params->seq_len, params->seq);161161+ params->key, params->seq_len, params->seq,162162+ cs);159163 if (IS_ERR(key))160164 return PTR_ERR(key);161165162166 if (pairwise)163167 key->conf.flags |= IEEE80211_KEY_FLAG_PAIRWISE;164168165165- mutex_lock(&sdata->local->sta_mtx);169169+ mutex_lock(&local->sta_mtx);166170167171 if (mac_addr) {168172 if (ieee80211_vif_is_mesh(&sdata->vif))···224216 break;225217 }226218219219+ if (sta)220220+ sta->cipher_scheme = cs;221221+227222 err = ieee80211_key_link(key, sdata, sta);228223229224 out_unlock:230230- mutex_unlock(&sdata->local->sta_mtx);225225+ mutex_unlock(&local->sta_mtx);231226232227 return err;233228}···255244 goto out_unlock;256245257246 if (pairwise)258258- key = key_mtx_dereference(local, sta->ptk);247247+ key = key_mtx_dereference(local, sta->ptk[key_idx]);259248 else260249 key = key_mtx_dereference(local, sta->gtk[key_idx]);261250 } else···302291 goto out;303292304293 if (pairwise)305305- key = rcu_dereference(sta->ptk);294294+ key = rcu_dereference(sta->ptk[key_idx]);306295 else if (key_idx < NUM_DEFAULT_KEYS)307296 key = rcu_dereference(sta->gtk[key_idx]);308297 } else···532521 STATION_INFO_PEER_PM |533522 STATION_INFO_NONPEER_PM;534523535535- sinfo->llid = le16_to_cpu(sta->llid);536536- sinfo->plid = le16_to_cpu(sta->plid);524524+ sinfo->llid = sta->llid;525525+ sinfo->plid = sta->plid;537526 sinfo->plink_state = sta->plink_state;538527 if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) {539528 sinfo->filled |= STATION_INFO_T_OFFSET;···857846 if (!resp || !resp_len)858847 return 1;859848860860- old = rtnl_dereference(sdata->u.ap.probe_resp);849849+ old = sdata_dereference(sdata->u.ap.probe_resp, sdata);861850862851 new = kzalloc(sizeof(struct probe_resp) + resp_len, GFP_KERNEL);863852 if (!new)···881870 int size, err;882871 u32 changed = BSS_CHANGED_BEACON;883872884884- old = rtnl_dereference(sdata->u.ap.beacon);873873+ old = sdata_dereference(sdata->u.ap.beacon, sdata);874874+885875886876 /* Need to have a beacon head if we don't have one yet */887877 if (!params->head && !old)···959947 BSS_CHANGED_P2P_PS;960948 int err;961949962962- old = rtnl_dereference(sdata->u.ap.beacon);950950+ old = sdata_dereference(sdata->u.ap.beacon, sdata);963951 if (old)964952 return -EALREADY;965953···980968 */981969 sdata->control_port_protocol = params->crypto.control_port_ethertype;982970 sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;971971+ sdata->encrypt_headroom = ieee80211_cs_headroom(sdata->local,972972+ ¶ms->crypto,973973+ sdata->vif.type);974974+983975 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {984976 vlan->control_port_protocol =985977 params->crypto.control_port_ethertype;986978 vlan->control_port_no_encrypt =987979 params->crypto.control_port_no_encrypt;980980+ vlan->encrypt_headroom =981981+ ieee80211_cs_headroom(sdata->local,982982+ ¶ms->crypto,983983+ vlan->vif.type);988984 }989985990986 sdata->vif.bss_conf.beacon_int = params->beacon_interval;···1021100110221002 err = drv_start_ap(sdata->local, sdata);10231003 if (err) {10241024- old = rtnl_dereference(sdata->u.ap.beacon);10041004+ old = sdata_dereference(sdata->u.ap.beacon, sdata);10051005+10251006 if (old)10261007 kfree_rcu(old, rcu_head);10271008 RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);···10531032 if (sdata->vif.csa_active)10541033 return -EBUSY;1055103410561056- old = rtnl_dereference(sdata->u.ap.beacon);10351035+ old = sdata_dereference(sdata->u.ap.beacon, sdata);10571036 if (!old)10581037 return -ENOENT;10591038···10711050 struct ieee80211_local *local = sdata->local;10721051 struct beacon_data *old_beacon;10731052 struct probe_resp *old_probe_resp;10531053+ struct cfg80211_chan_def chandef;1074105410751075- old_beacon = rtnl_dereference(sdata->u.ap.beacon);10551055+ old_beacon = sdata_dereference(sdata->u.ap.beacon, sdata);10761056 if (!old_beacon)10771057 return -ENOENT;10781078- old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);10581058+ old_probe_resp = sdata_dereference(sdata->u.ap.probe_resp, sdata);1079105910801060 /* abort any running channel switch */10811061 sdata->vif.csa_active = false;10821082- cancel_work_sync(&sdata->csa_finalize_work);10621062+ kfree(sdata->u.ap.next_beacon);10631063+ sdata->u.ap.next_beacon = NULL;10641064+10831065 cancel_work_sync(&sdata->u.ap.request_smps_work);1084106610851067 /* turn off carrier for this interface and dependent VLANs */···11151091 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);1116109211171093 if (sdata->wdev.cac_started) {10941094+ chandef = sdata->vif.bss_conf.chandef;11181095 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);11191119- cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,10961096+ cfg80211_cac_event(sdata->dev, &chandef,10971097+ NL80211_RADAR_CAC_ABORTED,11201098 GFP_KERNEL);11211099 }11221100···19791953 enum ieee80211_band band;19801954 u32 changed = 0;1981195519821982- if (!rtnl_dereference(sdata->u.ap.beacon))19561956+ if (!sdata_dereference(sdata->u.ap.beacon, sdata))19831957 return -ENOENT;1984195819851959 band = ieee80211_get_sdata_band(sdata);···29892963 struct ieee80211_local *local = sdata->local;29902964 int err, changed = 0;2991296529662966+ sdata_lock(sdata);29672967+ /* AP might have been stopped while waiting for the lock. */29682968+ if (!sdata->vif.csa_active)29692969+ goto unlock;29702970+29922971 if (!ieee80211_sdata_running(sdata))29932993- return;29722972+ goto unlock;2994297329952974 sdata->radar_required = sdata->csa_radar_required;29962996- err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,29972997- &changed);29752975+ err = ieee80211_vif_change_channel(sdata, &changed);29982976 if (WARN_ON(err < 0))29992999- return;29772977+ goto unlock;3000297830012979 if (!local->use_chanctx) {30023002- local->_oper_chandef = local->csa_chandef;29802980+ local->_oper_chandef = sdata->csa_chandef;30032981 ieee80211_hw_config(local, 0);30042982 }3005298330062984 ieee80211_bss_info_change_notify(sdata, changed);3007298529862986+ sdata->vif.csa_active = false;30082987 switch (sdata->vif.type) {30092988 case NL80211_IFTYPE_AP:30102989 err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);30112990 if (err < 0)30123012- return;29912991+ goto unlock;29922992+30132993 changed |= err;30142994 kfree(sdata->u.ap.next_beacon);30152995 sdata->u.ap.next_beacon = NULL;···30292997 case NL80211_IFTYPE_MESH_POINT:30302998 err = ieee80211_mesh_finish_csa(sdata);30312999 if (err < 0)30323032- return;30003000+ goto unlock;30333001 break;30343002#endif30353003 default:30363004 WARN_ON(1);30373037- return;30053005+ goto unlock;30383006 }30393039- sdata->vif.csa_active = false;3040300730413008 ieee80211_wake_queues_by_reason(&sdata->local->hw,30423009 IEEE80211_MAX_QUEUE_MAP,30433010 IEEE80211_QUEUE_STOP_REASON_CSA);3044301130453045- cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);30123012+ cfg80211_ch_switch_notify(sdata->dev, &sdata->csa_chandef);30133013+30143014+unlock:30153015+ sdata_unlock(sdata);30463016}3047301730483018static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,···30563022 struct ieee80211_chanctx *chanctx;30573023 struct ieee80211_if_mesh __maybe_unused *ifmsh;30583024 int err, num_chanctx;30253025+30263026+ lockdep_assert_held(&sdata->wdev.mtx);3059302730603028 if (!list_empty(&local->roc_list) || local->scanning)30613029 return -EBUSY;···31793143 IEEE80211_MAX_QUEUE_MAP,31803144 IEEE80211_QUEUE_STOP_REASON_CSA);3181314531823182- local->csa_chandef = params->chandef;31463146+ sdata->csa_chandef = params->chandef;31833147 sdata->vif.csa_active = true;3184314831853149 ieee80211_bss_info_change_notify(sdata, err);···31893153}3190315431913155static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,31923192- struct ieee80211_channel *chan, bool offchan,31933193- unsigned int wait, const u8 *buf, size_t len,31943194- bool no_cck, bool dont_wait_for_ack, u64 *cookie)31563156+ struct cfg80211_mgmt_tx_params *params,31573157+ u64 *cookie)31953158{31963159 struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);31973160 struct ieee80211_local *local = sdata->local;31983161 struct sk_buff *skb;31993162 struct sta_info *sta;32003200- const struct ieee80211_mgmt *mgmt = (void *)buf;31633163+ const struct ieee80211_mgmt *mgmt = (void *)params->buf;32013164 bool need_offchan = false;32023165 u32 flags;32033166 int ret;3204316732053205- if (dont_wait_for_ack)31683168+ if (params->dont_wait_for_ack)32063169 flags = IEEE80211_TX_CTL_NO_ACK;32073170 else32083171 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |32093172 IEEE80211_TX_CTL_REQ_TX_STATUS;3210317332113211- if (no_cck)31743174+ if (params->no_cck)32123175 flags |= IEEE80211_TX_CTL_NO_CCK_RATE;3213317632143177 switch (sdata->vif.type) {···32553220 /* configurations requiring offchan cannot work if no channel has been32563221 * specified32573222 */32583258- if (need_offchan && !chan)32233223+ if (need_offchan && !params->chan)32593224 return -EINVAL;3260322532613226 mutex_lock(&local->mtx);···32683233 chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);3269323432703235 if (chanctx_conf) {32713271- need_offchan = chan && (chan != chanctx_conf->def.chan);32723272- } else if (!chan) {32363236+ need_offchan = params->chan &&32373237+ (params->chan !=32383238+ chanctx_conf->def.chan);32393239+ } else if (!params->chan) {32733240 ret = -EINVAL;32743241 rcu_read_unlock();32753242 goto out_unlock;···32813244 rcu_read_unlock();32823245 }3283324632843284- if (need_offchan && !offchan) {32473247+ if (need_offchan && !params->offchan) {32853248 ret = -EBUSY;32863249 goto out_unlock;32873250 }3288325132893289- skb = dev_alloc_skb(local->hw.extra_tx_headroom + len);32523252+ skb = dev_alloc_skb(local->hw.extra_tx_headroom + params->len);32903253 if (!skb) {32913254 ret = -ENOMEM;32923255 goto out_unlock;32933256 }32943257 skb_reserve(skb, local->hw.extra_tx_headroom);3295325832963296- memcpy(skb_put(skb, len), buf, len);32593259+ memcpy(skb_put(skb, params->len), params->buf, params->len);3297326032983261 IEEE80211_SKB_CB(skb)->flags = flags;32993262···33133276 local->hw.offchannel_tx_hw_queue;3314327733153278 /* This will handle all kinds of coalescing and immediate TX */33163316- ret = ieee80211_start_roc_work(local, sdata, chan,33173317- wait, cookie, skb,32793279+ ret = ieee80211_start_roc_work(local, sdata, params->chan,32803280+ params->wait, cookie, skb,33183281 IEEE80211_ROC_TYPE_MGMT_TX);33193282 if (ret)33203283 kfree_skb(skb);
+140-1
net/mac80211/chan.c
···99#include "ieee80211_i.h"1010#include "driver-ops.h"11111212+static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)1313+{1414+ switch (sta->bandwidth) {1515+ case IEEE80211_STA_RX_BW_20:1616+ if (sta->ht_cap.ht_supported)1717+ return NL80211_CHAN_WIDTH_20;1818+ else1919+ return NL80211_CHAN_WIDTH_20_NOHT;2020+ case IEEE80211_STA_RX_BW_40:2121+ return NL80211_CHAN_WIDTH_40;2222+ case IEEE80211_STA_RX_BW_80:2323+ return NL80211_CHAN_WIDTH_80;2424+ case IEEE80211_STA_RX_BW_160:2525+ /*2626+ * This applied for both 160 and 80+80. since we use2727+ * the returned value to consider degradation of2828+ * ctx->conf.min_def, we have to make sure to take2929+ * the bigger one (NL80211_CHAN_WIDTH_160).3030+ * Otherwise we might try degrading even when not3131+ * needed, as the max required sta_bw returned (80+80)3232+ * might be smaller than the configured bw (160).3333+ */3434+ return NL80211_CHAN_WIDTH_160;3535+ default:3636+ WARN_ON(1);3737+ return NL80211_CHAN_WIDTH_20;3838+ }3939+}4040+4141+static enum nl80211_chan_width4242+ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)4343+{4444+ enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;4545+ struct sta_info *sta;4646+4747+ rcu_read_lock();4848+ list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) {4949+ if (sdata != sta->sdata &&5050+ !(sta->sdata->bss && sta->sdata->bss == sdata->bss))5151+ continue;5252+5353+ if (!sta->uploaded)5454+ continue;5555+5656+ max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));5757+ }5858+ rcu_read_unlock();5959+6060+ return max_bw;6161+}6262+6363+static enum nl80211_chan_width6464+ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local,6565+ struct ieee80211_chanctx_conf *conf)6666+{6767+ struct ieee80211_sub_if_data *sdata;6868+ enum nl80211_chan_width max_bw = NL80211_CHAN_WIDTH_20_NOHT;6969+7070+ rcu_read_lock();7171+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {7272+ struct ieee80211_vif *vif = &sdata->vif;7373+ enum nl80211_chan_width width = NL80211_CHAN_WIDTH_20_NOHT;7474+7575+ if (!ieee80211_sdata_running(sdata))7676+ continue;7777+7878+ if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)7979+ continue;8080+8181+ switch (vif->type) {8282+ case NL80211_IFTYPE_AP:8383+ case NL80211_IFTYPE_AP_VLAN:8484+ width = ieee80211_get_max_required_bw(sdata);8585+ break;8686+ case NL80211_IFTYPE_P2P_DEVICE:8787+ continue;8888+ case NL80211_IFTYPE_STATION:8989+ case NL80211_IFTYPE_ADHOC:9090+ case NL80211_IFTYPE_WDS:9191+ case NL80211_IFTYPE_MESH_POINT:9292+ width = vif->bss_conf.chandef.width;9393+ break;9494+ case NL80211_IFTYPE_UNSPECIFIED:9595+ case NUM_NL80211_IFTYPES:9696+ case NL80211_IFTYPE_MONITOR:9797+ case NL80211_IFTYPE_P2P_CLIENT:9898+ case NL80211_IFTYPE_P2P_GO:9999+ WARN_ON_ONCE(1);100100+ }101101+ max_bw = max(max_bw, width);102102+ }103103+ rcu_read_unlock();104104+105105+ return max_bw;106106+}107107+108108+/*109109+ * recalc the min required chan width of the channel context, which is110110+ * the max of min required widths of all the interfaces bound to this111111+ * channel context.112112+ */113113+void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,114114+ struct ieee80211_chanctx *ctx)115115+{116116+ enum nl80211_chan_width max_bw;117117+ struct cfg80211_chan_def min_def;118118+119119+ lockdep_assert_held(&local->chanctx_mtx);120120+121121+ /* don't optimize 5MHz, 10MHz, and radar_enabled confs */122122+ if (ctx->conf.def.width == NL80211_CHAN_WIDTH_5 ||123123+ ctx->conf.def.width == NL80211_CHAN_WIDTH_10 ||124124+ ctx->conf.radar_enabled) {125125+ ctx->conf.min_def = ctx->conf.def;126126+ return;127127+ }128128+129129+ max_bw = ieee80211_get_chanctx_max_required_bw(local, &ctx->conf);130130+131131+ /* downgrade chandef up to max_bw */132132+ min_def = ctx->conf.def;133133+ while (min_def.width > max_bw)134134+ ieee80211_chandef_downgrade(&min_def);135135+136136+ if (cfg80211_chandef_identical(&ctx->conf.min_def, &min_def))137137+ return;138138+139139+ ctx->conf.min_def = min_def;140140+ if (!ctx->driver_present)141141+ return;142142+143143+ drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_MIN_WIDTH);144144+}145145+12146static void ieee80211_change_chanctx(struct ieee80211_local *local,13147 struct ieee80211_chanctx *ctx,14148 const struct cfg80211_chan_def *chandef)···1542015521 ctx->conf.def = *chandef;15622 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);2323+ ieee80211_recalc_chanctx_min_def(local, ctx);1572415825 if (!local->use_chanctx) {15926 local->_oper_chandef = *chandef;···22893 ctx->conf.rx_chains_dynamic = 1;22994 ctx->mode = mode;23095 ctx->conf.radar_enabled = ieee80211_is_radar_required(local);9696+ ieee80211_recalc_chanctx_min_def(local, ctx);23197 if (!local->use_chanctx)23298 local->hw.conf.radar_enabled = ctx->conf.radar_enabled;23399···315179 ctx->refcount++;316180317181 ieee80211_recalc_txpower(sdata);182182+ ieee80211_recalc_chanctx_min_def(local, ctx);318183 sdata->vif.bss_conf.idle = false;319184320185 if (sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&···380243 ieee80211_recalc_chanctx_chantype(sdata->local, ctx);381244 ieee80211_recalc_smps_chanctx(local, ctx);382245 ieee80211_recalc_radar_chanctx(local, ctx);246246+ ieee80211_recalc_chanctx_min_def(local, ctx);383247 }384248}385249···549411}550412551413int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,552552- const struct cfg80211_chan_def *chandef,553414 u32 *changed)554415{555416 struct ieee80211_local *local = sdata->local;556417 struct ieee80211_chanctx_conf *conf;557418 struct ieee80211_chanctx *ctx;419419+ const struct cfg80211_chan_def *chandef = &sdata->csa_chandef;558420 int ret;559421 u32 chanctx_changed = 0;560422···594456 ieee80211_recalc_chanctx_chantype(local, ctx);595457 ieee80211_recalc_smps_chanctx(local, ctx);596458 ieee80211_recalc_radar_chanctx(local, ctx);459459+ ieee80211_recalc_chanctx_min_def(local, ctx);597460598461 ret = 0;599462 out:
+168
net/mac80211/debugfs.c
···17171818#define DEBUGFS_FORMAT_BUFFER_SIZE 10019192020+#define TX_LATENCY_BIN_DELIMTER_C ','2121+#define TX_LATENCY_BIN_DELIMTER_S ","2222+#define TX_LATENCY_BINS_DISABLED "enable(bins disabled)\n"2323+#define TX_LATENCY_DISABLED "disable\n"2424+2525+2626+/*2727+ * Display if Tx latency statistics & bins are enabled/disabled2828+ */2929+static ssize_t sta_tx_latency_stat_read(struct file *file,3030+ char __user *userbuf,3131+ size_t count, loff_t *ppos)3232+{3333+ struct ieee80211_local *local = file->private_data;3434+ struct ieee80211_tx_latency_bin_ranges *tx_latency;3535+ char *buf;3636+ int bufsz, i, ret;3737+ int pos = 0;3838+3939+ rcu_read_lock();4040+4141+ tx_latency = rcu_dereference(local->tx_latency);4242+4343+ if (tx_latency && tx_latency->n_ranges) {4444+ bufsz = tx_latency->n_ranges * 15;4545+ buf = kzalloc(bufsz, GFP_ATOMIC);4646+ if (!buf)4747+ goto err;4848+4949+ for (i = 0; i < tx_latency->n_ranges; i++)5050+ pos += scnprintf(buf + pos, bufsz - pos, "%d,",5151+ tx_latency->ranges[i]);5252+ pos += scnprintf(buf + pos, bufsz - pos, "\n");5353+ } else if (tx_latency) {5454+ bufsz = sizeof(TX_LATENCY_BINS_DISABLED) + 1;5555+ buf = kzalloc(bufsz, GFP_ATOMIC);5656+ if (!buf)5757+ goto err;5858+5959+ pos += scnprintf(buf + pos, bufsz - pos, "%s\n",6060+ TX_LATENCY_BINS_DISABLED);6161+ } else {6262+ bufsz = sizeof(TX_LATENCY_DISABLED) + 1;6363+ buf = kzalloc(bufsz, GFP_ATOMIC);6464+ if (!buf)6565+ goto err;6666+6767+ pos += scnprintf(buf + pos, bufsz - pos, "%s\n",6868+ TX_LATENCY_DISABLED);6969+ }7070+7171+ rcu_read_unlock();7272+7373+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);7474+ kfree(buf);7575+7676+ return ret;7777+err:7878+ rcu_read_unlock();7979+ return -ENOMEM;8080+}8181+8282+/*8383+ * Receive input from user regarding Tx latency statistics8484+ * The input should indicate if Tx latency statistics and bins are8585+ * enabled/disabled.8686+ * If bins are enabled input should indicate the amount of different bins and8787+ * their ranges. Each bin will count how many Tx frames transmitted within the8888+ * appropriate latency.8989+ * Legal input is:9090+ * a) "enable(bins disabled)" - to enable only general statistics9191+ * b) "a,b,c,d,...z" - to enable general statistics and bins, where all are9292+ * numbers and a < b < c < d.. < z9393+ * c) "disable" - disable all statistics9494+ * NOTE: must configure Tx latency statistics bins before stations connected.9595+ */9696+9797+static ssize_t sta_tx_latency_stat_write(struct file *file,9898+ const char __user *userbuf,9999+ size_t count, loff_t *ppos)100100+{101101+ struct ieee80211_local *local = file->private_data;102102+ char buf[128] = {};103103+ char *bins = buf;104104+ char *token;105105+ int buf_size, i, alloc_size;106106+ int prev_bin = 0;107107+ int n_ranges = 0;108108+ int ret = count;109109+ struct ieee80211_tx_latency_bin_ranges *tx_latency;110110+111111+ if (sizeof(buf) <= count)112112+ return -EINVAL;113113+ buf_size = count;114114+ if (copy_from_user(buf, userbuf, buf_size))115115+ return -EFAULT;116116+117117+ mutex_lock(&local->sta_mtx);118118+119119+ /* cannot change config once we have stations */120120+ if (local->num_sta)121121+ goto unlock;122122+123123+ tx_latency =124124+ rcu_dereference_protected(local->tx_latency,125125+ lockdep_is_held(&local->sta_mtx));126126+127127+ /* disable Tx statistics */128128+ if (!strcmp(buf, TX_LATENCY_DISABLED)) {129129+ if (!tx_latency)130130+ goto unlock;131131+ rcu_assign_pointer(local->tx_latency, NULL);132132+ synchronize_rcu();133133+ kfree(tx_latency);134134+ goto unlock;135135+ }136136+137137+ /* Tx latency already enabled */138138+ if (tx_latency)139139+ goto unlock;140140+141141+ if (strcmp(TX_LATENCY_BINS_DISABLED, buf)) {142142+ /* check how many bins and between what ranges user requested */143143+ token = buf;144144+ while (*token != '\0') {145145+ if (*token == TX_LATENCY_BIN_DELIMTER_C)146146+ n_ranges++;147147+ token++;148148+ }149149+ n_ranges++;150150+ }151151+152152+ alloc_size = sizeof(struct ieee80211_tx_latency_bin_ranges) +153153+ n_ranges * sizeof(u32);154154+ tx_latency = kzalloc(alloc_size, GFP_ATOMIC);155155+ if (!tx_latency) {156156+ ret = -ENOMEM;157157+ goto unlock;158158+ }159159+ tx_latency->n_ranges = n_ranges;160160+ for (i = 0; i < n_ranges; i++) { /* setting bin ranges */161161+ token = strsep(&bins, TX_LATENCY_BIN_DELIMTER_S);162162+ sscanf(token, "%d", &tx_latency->ranges[i]);163163+ /* bins values should be in ascending order */164164+ if (prev_bin >= tx_latency->ranges[i]) {165165+ ret = -EINVAL;166166+ kfree(tx_latency);167167+ goto unlock;168168+ }169169+ prev_bin = tx_latency->ranges[i];170170+ }171171+ rcu_assign_pointer(local->tx_latency, tx_latency);172172+173173+unlock:174174+ mutex_unlock(&local->sta_mtx);175175+176176+ return ret;177177+}178178+179179+static const struct file_operations stats_tx_latency_ops = {180180+ .write = sta_tx_latency_stat_write,181181+ .read = sta_tx_latency_stat_read,182182+ .open = simple_open,183183+ .llseek = generic_file_llseek,184184+};185185+20186int mac80211_format_buffer(char __user *userbuf, size_t count,21187 loff_t *ppos, char *fmt, ...)22188{···481315 DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);482316 DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);483317 DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);318318+319319+ DEBUGFS_DEVSTATS_ADD(tx_latency);484320}
···728728 u16 sequence_number;729729 __be16 control_port_protocol;730730 bool control_port_no_encrypt;731731+ int encrypt_headroom;731732732733 struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];733734···736735 int csa_counter_offset_beacon;737736 int csa_counter_offset_presp;738737 bool csa_radar_required;738738+ struct cfg80211_chan_def csa_chandef;739739740740 /* used to reconfigure hardware SM PS */741741 struct work_struct recalc_smps;···812810 mutex_unlock(&sdata->wdev.mtx);813811 __release(&sdata->wdev.mtx);814812}813813+814814+#define sdata_dereference(p, sdata) \815815+ rcu_dereference_protected(p, lockdep_is_held(&sdata->wdev.mtx))815816816817static inline void817818sdata_assert_lock(struct ieee80211_sub_if_data *sdata)···900895 bool running;901896};902897#endif898898+899899+/*900900+ * struct ieee80211_tx_latency_bin_ranges - Tx latency statistics bins ranges901901+ *902902+ * Measuring Tx latency statistics. Counts how many Tx frames transmitted in a903903+ * certain latency range (in Milliseconds). Each station that uses these904904+ * ranges will have bins to count the amount of frames received in that range.905905+ * The user can configure the ranges via debugfs.906906+ * If ranges is NULL then Tx latency statistics bins are disabled for all907907+ * stations.908908+ *909909+ * @n_ranges: number of ranges that are taken in account910910+ * @ranges: the ranges that the user requested or NULL if disabled.911911+ */912912+struct ieee80211_tx_latency_bin_ranges {913913+ int n_ranges;914914+ u32 ranges[];915915+};903916904917/**905918 * mac80211 scan flags - currently active scan mode···10711048 struct timer_list sta_cleanup;10721049 int sta_generation;1073105010511051+ /*10521052+ * Tx latency statistics parameters for all stations.10531053+ * Can enable via debugfs (NULL when disabled).10541054+ */10551055+ struct ieee80211_tx_latency_bin_ranges __rcu *tx_latency;10561056+10741057 struct sk_buff_head pending[IEEE80211_MAX_QUEUES];10751058 struct tasklet_struct tx_pending_tasklet;10761059···11221093 enum mac80211_scan_state next_scan_state;11231094 struct delayed_work scan_work;11241095 struct ieee80211_sub_if_data __rcu *scan_sdata;11251125- struct cfg80211_chan_def csa_chandef;11261096 /* For backward compatibility only -- do not use */11271097 struct cfg80211_chan_def _oper_chandef;11281098···17211693int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,17221694 enum ieee80211_smps_mode smps_mode);17231695void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);16961696+void ieee80211_recalc_min_chandef(struct ieee80211_sub_if_data *sdata);1724169717251698size_t ieee80211_ie_split(const u8 *ies, size_t ielen,17261699 const u8 *ids, int n_ids, size_t offset);···17601731/* NOTE: only use ieee80211_vif_change_channel() for channel switch */17611732int __must_check17621733ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,17631763- const struct cfg80211_chan_def *chandef,17641734 u32 *changed);17651735void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);17661736void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata);···17701742 struct ieee80211_chanctx *chanctx);17711743void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,17721744 struct ieee80211_chanctx *chanctx);17451745+void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,17461746+ struct ieee80211_chanctx *ctx);1773174717741748void ieee80211_dfs_cac_timer(unsigned long data);17751749void ieee80211_dfs_cac_timer_work(struct work_struct *work);···17791749void ieee80211_dfs_radar_detected_work(struct work_struct *work);17801750int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,17811751 struct cfg80211_csa_settings *csa_settings);17521752+17531753+bool ieee80211_cs_valid(const struct ieee80211_cipher_scheme *cs);17541754+bool ieee80211_cs_list_valid(const struct ieee80211_cipher_scheme *cs, int n);17551755+const struct ieee80211_cipher_scheme *17561756+ieee80211_cs_get(struct ieee80211_local *local, u32 cipher,17571757+ enum nl80211_iftype iftype);17581758+int ieee80211_cs_headroom(struct ieee80211_local *local,17591759+ struct cfg80211_crypto_settings *crypto,17601760+ enum nl80211_iftype iftype);1782176117831762#ifdef CONFIG_MAC80211_NOINLINE17841763#define debug_noinline noinline
+9-5
net/mac80211/iface.c
···401401 snprintf(sdata->name, IFNAMSIZ, "%s-monitor",402402 wiphy_name(local->hw.wiphy));403403404404+ sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;405405+404406 ieee80211_set_default_queues(sdata);405407406408 ret = drv_add_interface(local, sdata);···751749 u32 hw_reconf_flags = 0;752750 int i, flushed;753751 struct ps_data *ps;752752+ struct cfg80211_chan_def chandef;754753755754 clear_bit(SDATA_STATE_RUNNING, &sdata->state);756755···826823 cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);827824828825 if (sdata->wdev.cac_started) {826826+ chandef = sdata->vif.bss_conf.chandef;829827 WARN_ON(local->suspended);830828 mutex_lock(&local->iflist_mtx);831829 ieee80211_vif_release_channel(sdata);832830 mutex_unlock(&local->iflist_mtx);833833- cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_ABORTED,831831+ cfg80211_cac_event(sdata->dev, &chandef,832832+ NL80211_RADAR_CAC_ABORTED,834833 GFP_KERNEL);835834 }836835···10411036 */10421037static void ieee80211_teardown_sdata(struct ieee80211_sub_if_data *sdata)10431038{10441044- int flushed;10451039 int i;1046104010471041 /* free extra data */···1054105010551051 if (ieee80211_vif_is_mesh(&sdata->vif))10561052 mesh_rmc_free(sdata);10571057-10581058- flushed = sta_info_flush(sdata);10591059- WARN_ON(flushed);10601053}1061105410621055static void ieee80211_uninit(struct net_device *dev)···1271127012721271 sdata->control_port_protocol = cpu_to_be16(ETH_P_PAE);12731272 sdata->control_port_no_encrypt = false;12731273+ sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;1274127412751275 sdata->noack_map = 0;12761276···1686168416871685 sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;16881686 sdata->user_power_level = local->user_power_level;16871687+16881688+ sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;1689168916901690 /* setup type-dependent data */16911691 ieee80211_setup_sdata(sdata, type);
+42-22
net/mac80211/key.c
···260260 int idx;261261 bool defunikey, defmultikey, defmgmtkey;262262263263+ /* caller must provide at least one old/new */264264+ if (WARN_ON(!new && !old))265265+ return;266266+263267 if (new)264268 list_add_tail(&new->list, &sdata->key_list);265269266266- if (sta && pairwise) {267267- rcu_assign_pointer(sta->ptk, new);268268- } else if (sta) {269269- if (old)270270- idx = old->conf.keyidx;271271- else272272- idx = new->conf.keyidx;273273- rcu_assign_pointer(sta->gtk[idx], new);270270+ WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);271271+272272+ if (old)273273+ idx = old->conf.keyidx;274274+ else275275+ idx = new->conf.keyidx;276276+277277+ if (sta) {278278+ if (pairwise) {279279+ rcu_assign_pointer(sta->ptk[idx], new);280280+ sta->ptk_idx = idx;281281+ } else {282282+ rcu_assign_pointer(sta->gtk[idx], new);283283+ sta->gtk_idx = idx;284284+ }274285 } else {275275- WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);276276-277277- if (old)278278- idx = old->conf.keyidx;279279- else280280- idx = new->conf.keyidx;281281-282286 defunikey = old &&283287 old == key_mtx_dereference(sdata->local,284288 sdata->default_unicast_key);···316312 list_del(&old->list);317313}318314319319-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,320320- const u8 *key_data,321321- size_t seq_len, const u8 *seq)315315+struct ieee80211_key *316316+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,317317+ const u8 *key_data,318318+ size_t seq_len, const u8 *seq,319319+ const struct ieee80211_cipher_scheme *cs)322320{323321 struct ieee80211_key *key;324322 int i, j, err;···399393 return ERR_PTR(err);400394 }401395 break;396396+ default:397397+ if (cs) {398398+ size_t len = (seq_len > MAX_PN_LEN) ?399399+ MAX_PN_LEN : seq_len;400400+401401+ key->conf.iv_len = cs->hdr_len;402402+ key->conf.icv_len = cs->mic_len;403403+ for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)404404+ for (j = 0; j < len; j++)405405+ key->u.gen.rx_pn[i][j] =406406+ seq[len - j - 1];407407+ }402408 }403409 memcpy(key->conf.key, key_data, key_len);404410 INIT_LIST_HEAD(&key->list);···493475 mutex_lock(&sdata->local->key_mtx);494476495477 if (sta && pairwise)496496- old_key = key_mtx_dereference(sdata->local, sta->ptk);478478+ old_key = key_mtx_dereference(sdata->local, sta->ptk[idx]);497479 else if (sta)498480 old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);499481 else···643625 list_add(&key->list, &keys);644626 }645627646646- key = key_mtx_dereference(local, sta->ptk);647647- if (key) {628628+ for (i = 0; i < NUM_DEFAULT_KEYS; i++) {629629+ key = key_mtx_dereference(local, sta->ptk[i]);630630+ if (!key)631631+ continue;648632 ieee80211_key_replace(key->sdata, key->sta,649633 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,650634 key, NULL);···897877898878 key = ieee80211_key_alloc(keyconf->cipher, keyconf->keyidx,899879 keyconf->keylen, keyconf->key,900900- 0, NULL);880880+ 0, NULL, NULL);901881 if (IS_ERR(key))902882 return ERR_CAST(key);903883
+10-3
net/mac80211/key.h
···18181919#define NUM_DEFAULT_KEYS 42020#define NUM_DEFAULT_MGMT_KEYS 22121+#define MAX_PN_LEN 1621222223struct ieee80211_local;2324struct ieee80211_sub_if_data;···9493 u32 replays; /* dot11RSNAStatsCMACReplays */9594 u32 icverrors; /* dot11RSNAStatsCMACICVErrors */9695 } aes_cmac;9696+ struct {9797+ /* generic cipher scheme */9898+ u8 rx_pn[IEEE80211_NUM_TIDS + 1][MAX_PN_LEN];9999+ } gen;97100 } u;9810199102 /* number of times this key has been used */···118113 struct ieee80211_key_conf conf;119114};120115121121-struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,122122- const u8 *key_data,123123- size_t seq_len, const u8 *seq);116116+struct ieee80211_key *117117+ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,118118+ const u8 *key_data,119119+ size_t seq_len, const u8 *seq,120120+ const struct ieee80211_cipher_scheme *cs);124121/*125122 * Insert a key into data structures (sdata, sta if necessary)126123 * to make it used, free old key. On failure, also free the new key.
+101-44
net/mac80211/main.c
···651651}652652EXPORT_SYMBOL(ieee80211_alloc_hw);653653654654-int ieee80211_register_hw(struct ieee80211_hw *hw)654654+static int ieee80211_init_cipher_suites(struct ieee80211_local *local)655655{656656- struct ieee80211_local *local = hw_to_local(hw);657657- int result, i;658658- enum ieee80211_band band;659659- int channels, max_bitrates;660660- bool supp_ht, supp_vht;661661- netdev_features_t feature_whitelist;662662- struct cfg80211_chan_def dflt_chandef = {};656656+ bool have_wep = !(IS_ERR(local->wep_tx_tfm) ||657657+ IS_ERR(local->wep_rx_tfm));658658+ bool have_mfp = local->hw.flags & IEEE80211_HW_MFP_CAPABLE;659659+ const struct ieee80211_cipher_scheme *cs = local->hw.cipher_schemes;660660+ int n_suites = 0, r = 0, w = 0;661661+ u32 *suites;663662 static const u32 cipher_suites[] = {664663 /* keep WEP first, it may be removed below */665664 WLAN_CIPHER_SUITE_WEP40,···669670 /* keep last -- depends on hw flags! */670671 WLAN_CIPHER_SUITE_AES_CMAC671672 };673673+674674+ /* Driver specifies the ciphers, we have nothing to do... */675675+ if (local->hw.wiphy->cipher_suites && have_wep)676676+ return 0;677677+678678+ /* Set up cipher suites if driver relies on mac80211 cipher defs */679679+ if (!local->hw.wiphy->cipher_suites && !cs) {680680+ local->hw.wiphy->cipher_suites = cipher_suites;681681+ local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);682682+683683+ if (!have_mfp)684684+ local->hw.wiphy->n_cipher_suites--;685685+686686+ if (!have_wep) {687687+ local->hw.wiphy->cipher_suites += 2;688688+ local->hw.wiphy->n_cipher_suites -= 2;689689+ }690690+691691+ return 0;692692+ }693693+694694+ if (!local->hw.wiphy->cipher_suites) {695695+ /*696696+ * Driver specifies cipher schemes only697697+ * We start counting ciphers defined by schemes, TKIP and CCMP698698+ */699699+ n_suites = local->hw.n_cipher_schemes + 2;700700+701701+ /* check if we have WEP40 and WEP104 */702702+ if (have_wep)703703+ n_suites += 2;704704+705705+ /* check if we have AES_CMAC */706706+ if (have_mfp)707707+ n_suites++;708708+709709+ suites = kmalloc(sizeof(u32) * n_suites, GFP_KERNEL);710710+ if (!suites)711711+ return -ENOMEM;712712+713713+ suites[w++] = WLAN_CIPHER_SUITE_CCMP;714714+ suites[w++] = WLAN_CIPHER_SUITE_TKIP;715715+716716+ if (have_wep) {717717+ suites[w++] = WLAN_CIPHER_SUITE_WEP40;718718+ suites[w++] = WLAN_CIPHER_SUITE_WEP104;719719+ }720720+721721+ if (have_mfp)722722+ suites[w++] = WLAN_CIPHER_SUITE_AES_CMAC;723723+724724+ for (r = 0; r < local->hw.n_cipher_schemes; r++)725725+ suites[w++] = cs[r].cipher;726726+ } else {727727+ /* Driver provides cipher suites, but we need to exclude WEP */728728+ suites = kmemdup(local->hw.wiphy->cipher_suites,729729+ sizeof(u32) * local->hw.wiphy->n_cipher_suites,730730+ GFP_KERNEL);731731+ if (!suites)732732+ return -ENOMEM;733733+734734+ for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {735735+ u32 suite = local->hw.wiphy->cipher_suites[r];736736+737737+ if (suite == WLAN_CIPHER_SUITE_WEP40 ||738738+ suite == WLAN_CIPHER_SUITE_WEP104)739739+ continue;740740+ suites[w++] = suite;741741+ }742742+ }743743+744744+ local->hw.wiphy->cipher_suites = suites;745745+ local->hw.wiphy->n_cipher_suites = w;746746+ local->wiphy_ciphers_allocated = true;747747+748748+ return 0;749749+}750750+751751+int ieee80211_register_hw(struct ieee80211_hw *hw)752752+{753753+ struct ieee80211_local *local = hw_to_local(hw);754754+ int result, i;755755+ enum ieee80211_band band;756756+ int channels, max_bitrates;757757+ bool supp_ht, supp_vht;758758+ netdev_features_t feature_whitelist;759759+ struct cfg80211_chan_def dflt_chandef = {};672760673761 if (hw->flags & IEEE80211_HW_QUEUE_CONTROL &&674762 (local->hw.offchannel_tx_hw_queue == IEEE80211_INVAL_HW_QUEUE ||···937851 if (local->hw.wiphy->max_scan_ie_len)938852 local->hw.wiphy->max_scan_ie_len -= local->scan_ies_len;939853940940- /* Set up cipher suites unless driver already did */941941- if (!local->hw.wiphy->cipher_suites) {942942- local->hw.wiphy->cipher_suites = cipher_suites;943943- local->hw.wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);944944- if (!(local->hw.flags & IEEE80211_HW_MFP_CAPABLE))945945- local->hw.wiphy->n_cipher_suites--;946946- }947947- if (IS_ERR(local->wep_tx_tfm) || IS_ERR(local->wep_rx_tfm)) {948948- if (local->hw.wiphy->cipher_suites == cipher_suites) {949949- local->hw.wiphy->cipher_suites += 2;950950- local->hw.wiphy->n_cipher_suites -= 2;951951- } else {952952- u32 *suites;953953- int r, w = 0;854854+ WARN_ON(!ieee80211_cs_list_valid(local->hw.cipher_schemes,855855+ local->hw.n_cipher_schemes));954856955955- /* Filter out WEP */956956-957957- suites = kmemdup(958958- local->hw.wiphy->cipher_suites,959959- sizeof(u32) * local->hw.wiphy->n_cipher_suites,960960- GFP_KERNEL);961961- if (!suites) {962962- result = -ENOMEM;963963- goto fail_wiphy_register;964964- }965965- for (r = 0; r < local->hw.wiphy->n_cipher_suites; r++) {966966- u32 suite = local->hw.wiphy->cipher_suites[r];967967- if (suite == WLAN_CIPHER_SUITE_WEP40 ||968968- suite == WLAN_CIPHER_SUITE_WEP104)969969- continue;970970- suites[w++] = suite;971971- }972972- local->hw.wiphy->cipher_suites = suites;973973- local->hw.wiphy->n_cipher_suites = w;974974- local->wiphy_ciphers_allocated = true;975975- }976976- }857857+ result = ieee80211_init_cipher_suites(local);858858+ if (result < 0)859859+ goto fail_wiphy_register;977860978861 if (!local->ops->remain_on_channel)979862 local->hw.wiphy->max_remain_on_channel_duration = 5000;···11441089 idr_for_each(&local->ack_status_frames,11451090 ieee80211_free_ack_frame, NULL);11461091 idr_destroy(&local->ack_status_frames);10921092+10931093+ kfree(rcu_access_pointer(local->tx_latency));1147109411481095 wiphy_free(local->hw.wiphy);11491096}
···1919#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \2020 jiffies + HZ * t / 1000))21212222-/* We only need a valid sta if user configured a minimum rssi_threshold. */2323-#define rssi_threshold_check(sta, sdata) \2424- (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\2525- (sta && (s8) -ewma_read(&sta->avg_signal) > \2626- sdata->u.mesh.mshcfg.rssi_threshold))2727-2822enum plink_event {2923 PLINK_UNDEFINED,3024 OPN_ACPT,···55615662static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,5763 enum ieee80211_self_protected_actioncode action,5858- u8 *da, __le16 llid, __le16 plid, __le16 reason);6464+ u8 *da, u16 llid, u16 plid, u16 reason);6565+6666+6767+/* We only need a valid sta if user configured a minimum rssi_threshold. */6868+static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata,6969+ struct sta_info *sta)7070+{7171+ s32 rssi_threshold = sdata->u.mesh.mshcfg.rssi_threshold;7272+ return rssi_threshold == 0 ||7373+ (sta && (s8) -ewma_read(&sta->avg_signal) > rssi_threshold);7474+}59756076/**6177 * mesh_plink_fsm_restart - restart a mesh peer link finite state machine···246242247243 spin_lock_bh(&sta->lock);248244 changed = __mesh_plink_deactivate(sta);249249- sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);245245+ sta->reason = WLAN_REASON_MESH_PEER_CANCELED;250246 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,251247 sta->sta.addr, sta->llid, sta->plid,252248 sta->reason);···257253258254static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,259255 enum ieee80211_self_protected_actioncode action,260260- u8 *da, __le16 llid, __le16 plid, __le16 reason)256256+ u8 *da, u16 llid, u16 plid, u16 reason)261257{262258 struct ieee80211_local *local = sdata->local;263259 struct sk_buff *skb;···283279 2 + 8 + /* peering IE */284280 sdata->u.mesh.ie_len);285281 if (!skb)286286- return -1;282282+ return err;287283 info = IEEE80211_SKB_CB(skb);288284 skb_reserve(skb, local->tx_headroom);289285 mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);···305301 if (action == WLAN_SP_MESH_PEERING_CONFIRM) {306302 /* AID */307303 pos = skb_put(skb, 2);308308- memcpy(pos + 2, &plid, 2);304304+ put_unaligned_le16(plid, pos + 2);309305 }310306 if (ieee80211_add_srates_ie(sdata, skb, true, band) ||311307 ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||···347343 *pos++ = ie_len;348344 memcpy(pos, &peering_proto, 2);349345 pos += 2;350350- memcpy(pos, &llid, 2);346346+ put_unaligned_le16(llid, pos);351347 pos += 2;352348 if (include_plid) {353353- memcpy(pos, &plid, 2);349349+ put_unaligned_le16(plid, pos);354350 pos += 2;355351 }356352 if (action == WLAN_SP_MESH_PEERING_CLOSE) {357357- memcpy(pos, &reason, 2);353353+ put_unaligned_le16(reason, pos);358354 pos += 2;359355 }360356···522518 sta->plink_state == NL80211_PLINK_LISTEN &&523519 sdata->u.mesh.accepting_plinks &&524520 sdata->u.mesh.mshcfg.auto_open_plinks &&525525- rssi_threshold_check(sta, sdata))521521+ rssi_threshold_check(sdata, sta))526522 changed = mesh_plink_open(sta);527523528524 ieee80211_mps_frame_release(sta, elems);···534530static void mesh_plink_timer(unsigned long data)535531{536532 struct sta_info *sta;537537- __le16 llid, plid, reason;533533+ u16 reason = 0;538534 struct ieee80211_sub_if_data *sdata;539535 struct mesh_config *mshcfg;536536+ enum ieee80211_self_protected_actioncode action = 0;540537541538 /*542539 * This STA is valid because sta_info_destroy() will···558553 mpl_dbg(sta->sdata,559554 "Mesh plink timer for %pM fired on state %s\n",560555 sta->sta.addr, mplstates[sta->plink_state]);561561- reason = 0;562562- llid = sta->llid;563563- plid = sta->plid;564556 sdata = sta->sdata;565557 mshcfg = &sdata->u.mesh.mshcfg;566558···576574 rand % sta->plink_timeout;577575 ++sta->plink_retries;578576 mod_plink_timer(sta, sta->plink_timeout);579579- spin_unlock_bh(&sta->lock);580580- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,581581- sta->sta.addr, llid, 0, 0);577577+ action = WLAN_SP_MESH_PEERING_OPEN;582578 break;583579 }584584- reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);580580+ reason = WLAN_REASON_MESH_MAX_RETRIES;585581 /* fall through on else */586582 case NL80211_PLINK_CNF_RCVD:587583 /* confirm timer */588584 if (!reason)589589- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);585585+ reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;590586 sta->plink_state = NL80211_PLINK_HOLDING;591587 mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);592592- spin_unlock_bh(&sta->lock);593593- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,594594- sta->sta.addr, llid, plid, reason);588588+ action = WLAN_SP_MESH_PEERING_CLOSE;595589 break;596590 case NL80211_PLINK_HOLDING:597591 /* holding timer */598592 del_timer(&sta->plink_timer);599593 mesh_plink_fsm_restart(sta);600600- spin_unlock_bh(&sta->lock);601594 break;602595 default:603603- spin_unlock_bh(&sta->lock);604596 break;605597 }598598+ spin_unlock_bh(&sta->lock);599599+ if (action)600600+ mesh_plink_frame_tx(sdata, action, sta->sta.addr,601601+ sta->llid, sta->plid, reason);606602}607603608604static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)···612612 add_timer(&sta->plink_timer);613613}614614615615+static bool llid_in_use(struct ieee80211_sub_if_data *sdata,616616+ u16 llid)617617+{618618+ struct ieee80211_local *local = sdata->local;619619+ bool in_use = false;620620+ struct sta_info *sta;621621+622622+ rcu_read_lock();623623+ list_for_each_entry_rcu(sta, &local->sta_list, list) {624624+ if (!memcmp(&sta->llid, &llid, sizeof(llid))) {625625+ in_use = true;626626+ break;627627+ }628628+ }629629+ rcu_read_unlock();630630+631631+ return in_use;632632+}633633+634634+static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata)635635+{636636+ u16 llid;637637+638638+ do {639639+ get_random_bytes(&llid, sizeof(llid));640640+ /* for mesh PS we still only have the AID range for TIM bits */641641+ llid = (llid % IEEE80211_MAX_AID) + 1;642642+ } while (llid_in_use(sdata, llid));643643+644644+ return llid;645645+}646646+615647u32 mesh_plink_open(struct sta_info *sta)616648{617617- __le16 llid;618649 struct ieee80211_sub_if_data *sdata = sta->sdata;619650 u32 changed;620651···653622 return 0;654623655624 spin_lock_bh(&sta->lock);656656- get_random_bytes(&llid, 2);657657- sta->llid = llid;625625+ sta->llid = mesh_get_new_llid(sdata);658626 if (sta->plink_state != NL80211_PLINK_LISTEN &&659627 sta->plink_state != NL80211_PLINK_BLOCKED) {660628 spin_unlock_bh(&sta->lock);···670640 changed = ieee80211_mps_local_status_update(sdata);671641672642 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,673673- sta->sta.addr, llid, 0, 0);643643+ sta->sta.addr, sta->llid, 0, 0);674644 return changed;675645}676646···686656 return changed;687657}688658659659+static void mesh_plink_close(struct ieee80211_sub_if_data *sdata,660660+ struct sta_info *sta,661661+ enum plink_event event)662662+{663663+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;664664+665665+ u16 reason = (event == CLS_ACPT) ?666666+ WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG;667667+668668+ sta->reason = reason;669669+ sta->plink_state = NL80211_PLINK_HOLDING;670670+ mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);671671+}672672+673673+static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata,674674+ struct sta_info *sta)675675+{676676+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;677677+ u32 changed = 0;678678+679679+ del_timer(&sta->plink_timer);680680+ sta->plink_state = NL80211_PLINK_ESTAB;681681+ changed |= mesh_plink_inc_estab_count(sdata);682682+ changed |= mesh_set_ht_prot_mode(sdata);683683+ changed |= mesh_set_short_slot_time(sdata);684684+ mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr);685685+ ieee80211_mps_sta_status_update(sta);686686+ changed |= ieee80211_mps_set_sta_local_pm(sta, mshcfg->power_mode);687687+ return changed;688688+}689689+690690+/**691691+ * mesh_plink_fsm - step @sta MPM based on @event692692+ *693693+ * @sdata: interface694694+ * @sta: mesh neighbor695695+ * @event: peering event696696+ *697697+ * Return: changed MBSS flags698698+ */699699+static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata,700700+ struct sta_info *sta, enum plink_event event)701701+{702702+ struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;703703+ enum ieee80211_self_protected_actioncode action = 0;704704+ u32 changed = 0;705705+706706+ mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr,707707+ mplstates[sta->plink_state], mplevents[event]);708708+709709+ spin_lock_bh(&sta->lock);710710+ switch (sta->plink_state) {711711+ case NL80211_PLINK_LISTEN:712712+ switch (event) {713713+ case CLS_ACPT:714714+ mesh_plink_fsm_restart(sta);715715+ break;716716+ case OPN_ACPT:717717+ sta->plink_state = NL80211_PLINK_OPN_RCVD;718718+ sta->llid = mesh_get_new_llid(sdata);719719+ mesh_plink_timer_set(sta,720720+ mshcfg->dot11MeshRetryTimeout);721721+722722+ /* set the non-peer mode to active during peering */723723+ changed |= ieee80211_mps_local_status_update(sdata);724724+ action = WLAN_SP_MESH_PEERING_OPEN;725725+ break;726726+ default:727727+ break;728728+ }729729+ break;730730+ case NL80211_PLINK_OPN_SNT:731731+ switch (event) {732732+ case OPN_RJCT:733733+ case CNF_RJCT:734734+ case CLS_ACPT:735735+ mesh_plink_close(sdata, sta, event);736736+ action = WLAN_SP_MESH_PEERING_CLOSE;737737+ break;738738+ case OPN_ACPT:739739+ /* retry timer is left untouched */740740+ sta->plink_state = NL80211_PLINK_OPN_RCVD;741741+ action = WLAN_SP_MESH_PEERING_CONFIRM;742742+ break;743743+ case CNF_ACPT:744744+ sta->plink_state = NL80211_PLINK_CNF_RCVD;745745+ if (!mod_plink_timer(sta,746746+ mshcfg->dot11MeshConfirmTimeout))747747+ sta->ignore_plink_timer = true;748748+ break;749749+ default:750750+ break;751751+ }752752+ break;753753+ case NL80211_PLINK_OPN_RCVD:754754+ switch (event) {755755+ case OPN_RJCT:756756+ case CNF_RJCT:757757+ case CLS_ACPT:758758+ mesh_plink_close(sdata, sta, event);759759+ action = WLAN_SP_MESH_PEERING_CLOSE;760760+ break;761761+ case OPN_ACPT:762762+ action = WLAN_SP_MESH_PEERING_CONFIRM;763763+ break;764764+ case CNF_ACPT:765765+ changed |= mesh_plink_establish(sdata, sta);766766+ break;767767+ default:768768+ break;769769+ }770770+ break;771771+ case NL80211_PLINK_CNF_RCVD:772772+ switch (event) {773773+ case OPN_RJCT:774774+ case CNF_RJCT:775775+ case CLS_ACPT:776776+ mesh_plink_close(sdata, sta, event);777777+ action = WLAN_SP_MESH_PEERING_CLOSE;778778+ break;779779+ case OPN_ACPT:780780+ changed |= mesh_plink_establish(sdata, sta);781781+ action = WLAN_SP_MESH_PEERING_CONFIRM;782782+ break;783783+ default:784784+ break;785785+ }786786+ break;787787+ case NL80211_PLINK_ESTAB:788788+ switch (event) {789789+ case CLS_ACPT:790790+ changed |= __mesh_plink_deactivate(sta);791791+ changed |= mesh_set_ht_prot_mode(sdata);792792+ changed |= mesh_set_short_slot_time(sdata);793793+ mesh_plink_close(sdata, sta, event);794794+ action = WLAN_SP_MESH_PEERING_CLOSE;795795+ break;796796+ case OPN_ACPT:797797+ action = WLAN_SP_MESH_PEERING_CONFIRM;798798+ break;799799+ default:800800+ break;801801+ }802802+ break;803803+ case NL80211_PLINK_HOLDING:804804+ switch (event) {805805+ case CLS_ACPT:806806+ if (del_timer(&sta->plink_timer))807807+ sta->ignore_plink_timer = 1;808808+ mesh_plink_fsm_restart(sta);809809+ break;810810+ case OPN_ACPT:811811+ case CNF_ACPT:812812+ case OPN_RJCT:813813+ case CNF_RJCT:814814+ action = WLAN_SP_MESH_PEERING_CLOSE;815815+ break;816816+ default:817817+ break;818818+ }819819+ break;820820+ default:821821+ /* should not get here, PLINK_BLOCKED is dealt with at the822822+ * beginning of the function823823+ */824824+ break;825825+ }826826+ spin_unlock_bh(&sta->lock);827827+ if (action) {828828+ mesh_plink_frame_tx(sdata, action, sta->sta.addr,829829+ sta->llid, sta->plid, sta->reason);830830+831831+ /* also send confirm in open case */832832+ if (action == WLAN_SP_MESH_PEERING_OPEN) {833833+ mesh_plink_frame_tx(sdata,834834+ WLAN_SP_MESH_PEERING_CONFIRM,835835+ sta->sta.addr, sta->llid,836836+ sta->plid, 0);837837+ }838838+ }839839+840840+ return changed;841841+}842842+843843+/*844844+ * mesh_plink_get_event - get correct MPM event845845+ *846846+ * @sdata: interface847847+ * @sta: peer, leave NULL if processing a frame from a new suitable peer848848+ * @elems: peering management IEs849849+ * @ftype: frame type850850+ * @llid: peer's peer link ID851851+ * @plid: peer's local link ID852852+ *853853+ * Return: new peering event for @sta, but PLINK_UNDEFINED should be treated as854854+ * an error.855855+ */856856+static enum plink_event857857+mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,858858+ struct sta_info *sta,859859+ struct ieee802_11_elems *elems,860860+ enum ieee80211_self_protected_actioncode ftype,861861+ u16 llid, u16 plid)862862+{863863+ enum plink_event event = PLINK_UNDEFINED;864864+ u8 ie_len = elems->peering_len;865865+ bool matches_local;866866+867867+ matches_local = (ftype == WLAN_SP_MESH_PEERING_CLOSE ||868868+ mesh_matches_local(sdata, elems));869869+870870+ /* deny open request from non-matching peer */871871+ if (!matches_local && !sta) {872872+ event = OPN_RJCT;873873+ goto out;874874+ }875875+876876+ if (!sta) {877877+ if (ftype != WLAN_SP_MESH_PEERING_OPEN) {878878+ mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");879879+ goto out;880880+ }881881+ /* ftype == WLAN_SP_MESH_PEERING_OPEN */882882+ if (!mesh_plink_free_count(sdata)) {883883+ mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");884884+ goto out;885885+ }886886+ } else {887887+ if (!test_sta_flag(sta, WLAN_STA_AUTH)) {888888+ mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");889889+ goto out;890890+ }891891+ if (sta->plink_state == NL80211_PLINK_BLOCKED)892892+ goto out;893893+ }894894+895895+ /* new matching peer */896896+ if (!sta) {897897+ event = OPN_ACPT;898898+ goto out;899899+ }900900+901901+ switch (ftype) {902902+ case WLAN_SP_MESH_PEERING_OPEN:903903+ if (!matches_local)904904+ event = OPN_RJCT;905905+ if (!mesh_plink_free_count(sdata) ||906906+ (sta->plid && sta->plid != plid))907907+ event = OPN_IGNR;908908+ else909909+ event = OPN_ACPT;910910+ break;911911+ case WLAN_SP_MESH_PEERING_CONFIRM:912912+ if (!matches_local)913913+ event = CNF_RJCT;914914+ if (!mesh_plink_free_count(sdata) ||915915+ (sta->llid != llid || sta->plid != plid))916916+ event = CNF_IGNR;917917+ else918918+ event = CNF_ACPT;919919+ break;920920+ case WLAN_SP_MESH_PEERING_CLOSE:921921+ if (sta->plink_state == NL80211_PLINK_ESTAB)922922+ /* Do not check for llid or plid. This does not923923+ * follow the standard but since multiple plinks924924+ * per sta are not supported, it is necessary in925925+ * order to avoid a livelock when MP A sees an926926+ * establish peer link to MP B but MP B does not927927+ * see it. This can be caused by a timeout in928928+ * B's peer link establishment or B beign929929+ * restarted.930930+ */931931+ event = CLS_ACPT;932932+ else if (sta->plid != plid)933933+ event = CLS_IGNR;934934+ else if (ie_len == 8 && sta->llid != llid)935935+ event = CLS_IGNR;936936+ else937937+ event = CLS_ACPT;938938+ break;939939+ default:940940+ mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");941941+ break;942942+ }943943+944944+out:945945+ return event;946946+}947947+948948+static void949949+mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata,950950+ struct ieee80211_mgmt *mgmt,951951+ struct ieee802_11_elems *elems)952952+{953953+954954+ struct sta_info *sta;955955+ enum plink_event event;956956+ enum ieee80211_self_protected_actioncode ftype;957957+ u32 changed = 0;958958+ u8 ie_len = elems->peering_len;959959+ __le16 _plid, _llid;960960+ u16 plid, llid = 0;961961+962962+ if (!elems->peering) {963963+ mpl_dbg(sdata,964964+ "Mesh plink: missing necessary peer link ie\n");965965+ return;966966+ }967967+968968+ if (elems->rsn_len &&969969+ sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {970970+ mpl_dbg(sdata,971971+ "Mesh plink: can't establish link with secure peer\n");972972+ return;973973+ }974974+975975+ ftype = mgmt->u.action.u.self_prot.action_code;976976+ if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||977977+ (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||978978+ (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6979979+ && ie_len != 8)) {980980+ mpl_dbg(sdata,981981+ "Mesh plink: incorrect plink ie length %d %d\n",982982+ ftype, ie_len);983983+ return;984984+ }985985+986986+ if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&987987+ (!elems->mesh_id || !elems->mesh_config)) {988988+ mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");989989+ return;990990+ }991991+ /* Note the lines below are correct, the llid in the frame is the plid992992+ * from the point of view of this host.993993+ */994994+ memcpy(&_plid, PLINK_GET_LLID(elems->peering), sizeof(__le16));995995+ plid = le16_to_cpu(_plid);996996+ if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||997997+ (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8)) {998998+ memcpy(&_llid, PLINK_GET_PLID(elems->peering), sizeof(__le16));999999+ llid = le16_to_cpu(_llid);10001000+ }10011001+10021002+ /* WARNING: Only for sta pointer, is dropped & re-acquired */10031003+ rcu_read_lock();10041004+10051005+ sta = sta_info_get(sdata, mgmt->sa);10061006+10071007+ if (ftype == WLAN_SP_MESH_PEERING_OPEN &&10081008+ !rssi_threshold_check(sdata, sta)) {10091009+ mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",10101010+ mgmt->sa);10111011+ goto unlock_rcu;10121012+ }10131013+10141014+ /* Now we will figure out the appropriate event... */10151015+ event = mesh_plink_get_event(sdata, sta, elems, ftype, llid, plid);10161016+10171017+ if (event == OPN_ACPT) {10181018+ rcu_read_unlock();10191019+ /* allocate sta entry if necessary and update info */10201020+ sta = mesh_sta_info_get(sdata, mgmt->sa, elems);10211021+ if (!sta) {10221022+ mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");10231023+ goto unlock_rcu;10241024+ }10251025+ sta->plid = plid;10261026+ } else if (!sta && event == OPN_RJCT) {10271027+ mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,10281028+ mgmt->sa, 0, plid,10291029+ WLAN_REASON_MESH_CONFIG);10301030+ goto unlock_rcu;10311031+ } else if (!sta || event == PLINK_UNDEFINED) {10321032+ /* something went wrong */10331033+ goto unlock_rcu;10341034+ }10351035+10361036+ changed |= mesh_plink_fsm(sdata, sta, event);10371037+10381038+unlock_rcu:10391039+ rcu_read_unlock();10401040+10411041+ if (changed)10421042+ ieee80211_mbss_info_change_notify(sdata, changed);10431043+}68910446901045void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata,6911046 struct ieee80211_mgmt *mgmt, size_t len,6921047 struct ieee80211_rx_status *rx_status)6931048{694694- struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;6951049 struct ieee802_11_elems elems;696696- struct sta_info *sta;697697- enum plink_event event;698698- enum ieee80211_self_protected_actioncode ftype;6991050 size_t baselen;700700- bool matches_local = true;701701- u8 ie_len;7021051 u8 *baseaddr;703703- u32 changed = 0;704704- __le16 plid, llid, reason;70510527061053 /* need action_code, aux */7071054 if (len < IEEE80211_MIN_ACTION_SIZE + 3)···1102695 baselen += 4;1103696 }1104697 ieee802_11_parse_elems(baseaddr, len - baselen, true, &elems);11051105-11061106- if (!elems.peering) {11071107- mpl_dbg(sdata,11081108- "Mesh plink: missing necessary peer link ie\n");11091109- return;11101110- }11111111-11121112- if (elems.rsn_len &&11131113- sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {11141114- mpl_dbg(sdata,11151115- "Mesh plink: can't establish link with secure peer\n");11161116- return;11171117- }11181118-11191119- ftype = mgmt->u.action.u.self_prot.action_code;11201120- ie_len = elems.peering_len;11211121- if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||11221122- (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||11231123- (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 611241124- && ie_len != 8)) {11251125- mpl_dbg(sdata,11261126- "Mesh plink: incorrect plink ie length %d %d\n",11271127- ftype, ie_len);11281128- return;11291129- }11301130-11311131- if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&11321132- (!elems.mesh_id || !elems.mesh_config)) {11331133- mpl_dbg(sdata, "Mesh plink: missing necessary ie\n");11341134- return;11351135- }11361136- /* Note the lines below are correct, the llid in the frame is the plid11371137- * from the point of view of this host.11381138- */11391139- memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);11401140- if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||11411141- (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))11421142- memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);11431143-11441144- /* WARNING: Only for sta pointer, is dropped & re-acquired */11451145- rcu_read_lock();11461146-11471147- sta = sta_info_get(sdata, mgmt->sa);11481148- if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {11491149- mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n");11501150- rcu_read_unlock();11511151- return;11521152- }11531153-11541154- if (ftype == WLAN_SP_MESH_PEERING_OPEN &&11551155- !rssi_threshold_check(sta, sdata)) {11561156- mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n",11571157- mgmt->sa);11581158- rcu_read_unlock();11591159- return;11601160- }11611161-11621162- if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {11631163- mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");11641164- rcu_read_unlock();11651165- return;11661166- }11671167-11681168- if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {11691169- rcu_read_unlock();11701170- return;11711171- }11721172-11731173- /* Now we will figure out the appropriate event... */11741174- event = PLINK_UNDEFINED;11751175- if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&11761176- !mesh_matches_local(sdata, &elems)) {11771177- matches_local = false;11781178- switch (ftype) {11791179- case WLAN_SP_MESH_PEERING_OPEN:11801180- event = OPN_RJCT;11811181- break;11821182- case WLAN_SP_MESH_PEERING_CONFIRM:11831183- event = CNF_RJCT;11841184- break;11851185- default:11861186- break;11871187- }11881188- }11891189-11901190- if (!sta && !matches_local) {11911191- rcu_read_unlock();11921192- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);11931193- llid = 0;11941194- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,11951195- mgmt->sa, llid, plid, reason);11961196- return;11971197- } else if (!sta) {11981198- /* ftype == WLAN_SP_MESH_PEERING_OPEN */11991199- if (!mesh_plink_free_count(sdata)) {12001200- mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");12011201- rcu_read_unlock();12021202- return;12031203- }12041204- event = OPN_ACPT;12051205- } else if (matches_local) {12061206- switch (ftype) {12071207- case WLAN_SP_MESH_PEERING_OPEN:12081208- if (!mesh_plink_free_count(sdata) ||12091209- (sta->plid && sta->plid != plid))12101210- event = OPN_IGNR;12111211- else12121212- event = OPN_ACPT;12131213- break;12141214- case WLAN_SP_MESH_PEERING_CONFIRM:12151215- if (!mesh_plink_free_count(sdata) ||12161216- (sta->llid != llid || sta->plid != plid))12171217- event = CNF_IGNR;12181218- else12191219- event = CNF_ACPT;12201220- break;12211221- case WLAN_SP_MESH_PEERING_CLOSE:12221222- if (sta->plink_state == NL80211_PLINK_ESTAB)12231223- /* Do not check for llid or plid. This does not12241224- * follow the standard but since multiple plinks12251225- * per sta are not supported, it is necessary in12261226- * order to avoid a livelock when MP A sees an12271227- * establish peer link to MP B but MP B does not12281228- * see it. This can be caused by a timeout in12291229- * B's peer link establishment or B beign12301230- * restarted.12311231- */12321232- event = CLS_ACPT;12331233- else if (sta->plid != plid)12341234- event = CLS_IGNR;12351235- else if (ie_len == 7 && sta->llid != llid)12361236- event = CLS_IGNR;12371237- else12381238- event = CLS_ACPT;12391239- break;12401240- default:12411241- mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n");12421242- rcu_read_unlock();12431243- return;12441244- }12451245- }12461246-12471247- if (event == OPN_ACPT) {12481248- rcu_read_unlock();12491249- /* allocate sta entry if necessary and update info */12501250- sta = mesh_sta_info_get(sdata, mgmt->sa, &elems);12511251- if (!sta) {12521252- mpl_dbg(sdata, "Mesh plink: failed to init peer!\n");12531253- rcu_read_unlock();12541254- return;12551255- }12561256- }12571257-12581258- mpl_dbg(sdata, "peer %pM in state %s got event %s\n", mgmt->sa,12591259- mplstates[sta->plink_state], mplevents[event]);12601260- reason = 0;12611261- spin_lock_bh(&sta->lock);12621262- switch (sta->plink_state) {12631263- /* spin_unlock as soon as state is updated at each case */12641264- case NL80211_PLINK_LISTEN:12651265- switch (event) {12661266- case CLS_ACPT:12671267- mesh_plink_fsm_restart(sta);12681268- spin_unlock_bh(&sta->lock);12691269- break;12701270- case OPN_ACPT:12711271- sta->plink_state = NL80211_PLINK_OPN_RCVD;12721272- sta->plid = plid;12731273- get_random_bytes(&llid, 2);12741274- sta->llid = llid;12751275- mesh_plink_timer_set(sta,12761276- mshcfg->dot11MeshRetryTimeout);12771277-12781278- /* set the non-peer mode to active during peering */12791279- changed |= ieee80211_mps_local_status_update(sdata);12801280-12811281- spin_unlock_bh(&sta->lock);12821282- mesh_plink_frame_tx(sdata,12831283- WLAN_SP_MESH_PEERING_OPEN,12841284- sta->sta.addr, llid, 0, 0);12851285- mesh_plink_frame_tx(sdata,12861286- WLAN_SP_MESH_PEERING_CONFIRM,12871287- sta->sta.addr, llid, plid, 0);12881288- break;12891289- default:12901290- spin_unlock_bh(&sta->lock);12911291- break;12921292- }12931293- break;12941294-12951295- case NL80211_PLINK_OPN_SNT:12961296- switch (event) {12971297- case OPN_RJCT:12981298- case CNF_RJCT:12991299- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);13001300- case CLS_ACPT:13011301- if (!reason)13021302- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);13031303- sta->reason = reason;13041304- sta->plink_state = NL80211_PLINK_HOLDING;13051305- if (!mod_plink_timer(sta,13061306- mshcfg->dot11MeshHoldingTimeout))13071307- sta->ignore_plink_timer = true;13081308-13091309- llid = sta->llid;13101310- spin_unlock_bh(&sta->lock);13111311- mesh_plink_frame_tx(sdata,13121312- WLAN_SP_MESH_PEERING_CLOSE,13131313- sta->sta.addr, llid, plid, reason);13141314- break;13151315- case OPN_ACPT:13161316- /* retry timer is left untouched */13171317- sta->plink_state = NL80211_PLINK_OPN_RCVD;13181318- sta->plid = plid;13191319- llid = sta->llid;13201320- spin_unlock_bh(&sta->lock);13211321- mesh_plink_frame_tx(sdata,13221322- WLAN_SP_MESH_PEERING_CONFIRM,13231323- sta->sta.addr, llid, plid, 0);13241324- break;13251325- case CNF_ACPT:13261326- sta->plink_state = NL80211_PLINK_CNF_RCVD;13271327- if (!mod_plink_timer(sta,13281328- mshcfg->dot11MeshConfirmTimeout))13291329- sta->ignore_plink_timer = true;13301330-13311331- spin_unlock_bh(&sta->lock);13321332- break;13331333- default:13341334- spin_unlock_bh(&sta->lock);13351335- break;13361336- }13371337- break;13381338-13391339- case NL80211_PLINK_OPN_RCVD:13401340- switch (event) {13411341- case OPN_RJCT:13421342- case CNF_RJCT:13431343- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);13441344- case CLS_ACPT:13451345- if (!reason)13461346- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);13471347- sta->reason = reason;13481348- sta->plink_state = NL80211_PLINK_HOLDING;13491349- if (!mod_plink_timer(sta,13501350- mshcfg->dot11MeshHoldingTimeout))13511351- sta->ignore_plink_timer = true;13521352-13531353- llid = sta->llid;13541354- spin_unlock_bh(&sta->lock);13551355- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,13561356- sta->sta.addr, llid, plid, reason);13571357- break;13581358- case OPN_ACPT:13591359- llid = sta->llid;13601360- spin_unlock_bh(&sta->lock);13611361- mesh_plink_frame_tx(sdata,13621362- WLAN_SP_MESH_PEERING_CONFIRM,13631363- sta->sta.addr, llid, plid, 0);13641364- break;13651365- case CNF_ACPT:13661366- del_timer(&sta->plink_timer);13671367- sta->plink_state = NL80211_PLINK_ESTAB;13681368- spin_unlock_bh(&sta->lock);13691369- changed |= mesh_plink_inc_estab_count(sdata);13701370- changed |= mesh_set_ht_prot_mode(sdata);13711371- changed |= mesh_set_short_slot_time(sdata);13721372- mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",13731373- sta->sta.addr);13741374- ieee80211_mps_sta_status_update(sta);13751375- changed |= ieee80211_mps_set_sta_local_pm(sta,13761376- mshcfg->power_mode);13771377- break;13781378- default:13791379- spin_unlock_bh(&sta->lock);13801380- break;13811381- }13821382- break;13831383-13841384- case NL80211_PLINK_CNF_RCVD:13851385- switch (event) {13861386- case OPN_RJCT:13871387- case CNF_RJCT:13881388- reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);13891389- case CLS_ACPT:13901390- if (!reason)13911391- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);13921392- sta->reason = reason;13931393- sta->plink_state = NL80211_PLINK_HOLDING;13941394- if (!mod_plink_timer(sta,13951395- mshcfg->dot11MeshHoldingTimeout))13961396- sta->ignore_plink_timer = true;13971397-13981398- llid = sta->llid;13991399- spin_unlock_bh(&sta->lock);14001400- mesh_plink_frame_tx(sdata,14011401- WLAN_SP_MESH_PEERING_CLOSE,14021402- sta->sta.addr, llid, plid, reason);14031403- break;14041404- case OPN_ACPT:14051405- del_timer(&sta->plink_timer);14061406- sta->plink_state = NL80211_PLINK_ESTAB;14071407- spin_unlock_bh(&sta->lock);14081408- changed |= mesh_plink_inc_estab_count(sdata);14091409- changed |= mesh_set_ht_prot_mode(sdata);14101410- changed |= mesh_set_short_slot_time(sdata);14111411- mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",14121412- sta->sta.addr);14131413- mesh_plink_frame_tx(sdata,14141414- WLAN_SP_MESH_PEERING_CONFIRM,14151415- sta->sta.addr, llid, plid, 0);14161416- ieee80211_mps_sta_status_update(sta);14171417- changed |= ieee80211_mps_set_sta_local_pm(sta,14181418- mshcfg->power_mode);14191419- break;14201420- default:14211421- spin_unlock_bh(&sta->lock);14221422- break;14231423- }14241424- break;14251425-14261426- case NL80211_PLINK_ESTAB:14271427- switch (event) {14281428- case CLS_ACPT:14291429- reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);14301430- sta->reason = reason;14311431- changed |= __mesh_plink_deactivate(sta);14321432- sta->plink_state = NL80211_PLINK_HOLDING;14331433- llid = sta->llid;14341434- mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);14351435- spin_unlock_bh(&sta->lock);14361436- changed |= mesh_set_ht_prot_mode(sdata);14371437- changed |= mesh_set_short_slot_time(sdata);14381438- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,14391439- sta->sta.addr, llid, plid, reason);14401440- break;14411441- case OPN_ACPT:14421442- llid = sta->llid;14431443- spin_unlock_bh(&sta->lock);14441444- mesh_plink_frame_tx(sdata,14451445- WLAN_SP_MESH_PEERING_CONFIRM,14461446- sta->sta.addr, llid, plid, 0);14471447- break;14481448- default:14491449- spin_unlock_bh(&sta->lock);14501450- break;14511451- }14521452- break;14531453- case NL80211_PLINK_HOLDING:14541454- switch (event) {14551455- case CLS_ACPT:14561456- if (del_timer(&sta->plink_timer))14571457- sta->ignore_plink_timer = 1;14581458- mesh_plink_fsm_restart(sta);14591459- spin_unlock_bh(&sta->lock);14601460- break;14611461- case OPN_ACPT:14621462- case CNF_ACPT:14631463- case OPN_RJCT:14641464- case CNF_RJCT:14651465- llid = sta->llid;14661466- reason = sta->reason;14671467- spin_unlock_bh(&sta->lock);14681468- mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,14691469- sta->sta.addr, llid, plid, reason);14701470- break;14711471- default:14721472- spin_unlock_bh(&sta->lock);14731473- }14741474- break;14751475- default:14761476- /* should not get here, PLINK_BLOCKED is dealt with at the14771477- * beginning of the function14781478- */14791479- spin_unlock_bh(&sta->lock);14801480- break;14811481- }14821482-14831483- rcu_read_unlock();14841484-14851485- if (changed)14861486- ieee80211_mbss_info_change_notify(sdata, changed);698698+ mesh_process_plink_frame(sdata, mgmt, &elems);1487699}
+1-2
net/mac80211/mesh_ps.c
···576576 int ac, buffer_local = 0;577577 bool has_buffered = false;578578579579- /* TIM map only for LLID <= IEEE80211_MAX_AID */580579 if (sta->plink_state == NL80211_PLINK_ESTAB)581580 has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len,582582- le16_to_cpu(sta->llid) % IEEE80211_MAX_AID);581581+ sta->llid);583582584583 if (has_buffered)585584 mps_dbg(sta->sdata, "%pM indicates buffered frames\n",
+14-14
net/mac80211/mesh_sync.c
···9292 if (stype != IEEE80211_STYPE_BEACON)9393 return;94949595- /* The current tsf is a first approximation for the timestamp9696- * for the received beacon. Further down we try to get a9797- * better value from the rx_status->mactime field if9898- * available. Also we have to call drv_get_tsf() before9999- * entering the rcu-read section.*/100100- t_r = drv_get_tsf(local, sdata);9595+ /*9696+ * Get time when timestamp field was received. If we don't9797+ * have rx timestamps, then use current tsf as an approximation.9898+ * drv_get_tsf() must be called before entering the rcu-read9999+ * section.100100+ */101101+ if (ieee80211_have_rx_timestamp(rx_status))102102+ t_r = ieee80211_calculate_rx_timestamp(local, rx_status,103103+ 24 + 12 +104104+ elems->total_len +105105+ FCS_LEN,106106+ 24);107107+ else108108+ t_r = drv_get_tsf(local, sdata);101109102110 rcu_read_lock();103111 sta = sta_info_get(sdata, mgmt->sa);···124116 sta->sta.addr);125117 goto no_sync;126118 }127127-128128- if (ieee80211_have_rx_timestamp(rx_status))129129- /* time when timestamp field was received */130130- t_r = ieee80211_calculate_rx_timestamp(local, rx_status,131131- 24 + 12 +132132- elems->total_len +133133- FCS_LEN,134134- 24);135119136120 /* Timing offset calculation (see 13.13.2.2.2) */137121 t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
+25-18
net/mac80211/mlme.c
···330330 if (WARN_ON_ONCE(!sta))331331 return -EINVAL;332332333333+ /*334334+ * if bss configuration changed store the new one -335335+ * this may be applicable even if channel is identical336336+ */337337+ ht_opmode = le16_to_cpu(ht_oper->operation_mode);338338+ if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {339339+ *changed |= BSS_CHANGED_HT;340340+ sdata->vif.bss_conf.ht_operation_mode = ht_opmode;341341+ }342342+333343 chan = sdata->vif.bss_conf.chandef.chan;334344 sband = local->hw.wiphy->bands[chan->band];335345···424414 sta->sta.bandwidth = new_sta_bw;425415 rate_control_rate_update(local, sband, sta,426416 IEEE80211_RC_BW_CHANGED);427427- }428428-429429- ht_opmode = le16_to_cpu(ht_oper->operation_mode);430430-431431- /* if bss configuration changed store the new one */432432- if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {433433- *changed |= BSS_CHANGED_HT;434434- sdata->vif.bss_conf.ht_operation_mode = ht_opmode;435417 }436418437419 return 0;···716714 }717715718716 /* if present, add any custom IEs that go before HT */719719- if (assoc_data->ie_len && assoc_data->ie) {717717+ if (assoc_data->ie_len) {720718 static const u8 before_ht[] = {721719 WLAN_EID_SSID,722720 WLAN_EID_SUPP_RATES,···750748 &assoc_data->ap_vht_cap);751749752750 /* if present, add any custom non-vendor IEs that go after HT */753753- if (assoc_data->ie_len && assoc_data->ie) {751751+ if (assoc_data->ie_len) {754752 noffset = ieee80211_ie_split_vendor(assoc_data->ie,755753 assoc_data->ie_len,756754 offset);···781779 }782780783781 /* add any remaining custom (i.e. vendor specific here) IEs */784784- if (assoc_data->ie_len && assoc_data->ie) {782782+ if (assoc_data->ie_len) {785783 noffset = assoc_data->ie_len;786784 pos = skb_put(skb, noffset - offset);787785 memcpy(pos, assoc_data->ie + offset, noffset - offset);···888886 if (!ifmgd->associated)889887 goto out;890888891891- ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,892892- &changed);889889+ ret = ieee80211_vif_change_channel(sdata, &changed);893890 if (ret) {894891 sdata_info(sdata,895892 "vif channel switch failed, disconnecting\n");···898897 }899898900899 if (!local->use_chanctx) {901901- local->_oper_chandef = local->csa_chandef;900900+ local->_oper_chandef = sdata->csa_chandef;902901 /* Call "hw_config" only if doing sw channel switch.903902 * Otherwise update the channel directly904903 */···909908 }910909911910 /* XXX: shouldn't really modify cfg80211-owned data! */912912- ifmgd->associated->channel = local->csa_chandef.chan;911911+ ifmgd->associated->channel = sdata->csa_chandef.chan;913912914913 /* XXX: wait for a beacon first? */915914 ieee80211_wake_queues_by_reason(&local->hw,···10361035 }10371036 mutex_unlock(&local->chanctx_mtx);1038103710391039- local->csa_chandef = csa_ie.chandef;10381038+ sdata->csa_chandef = csa_ie.chandef;1040103910411040 if (csa_ie.mode)10421041 ieee80211_stop_queues_by_reason(&local->hw,···13991398 struct ieee80211_sub_if_data *sdata =14001399 container_of(delayed_work, struct ieee80211_sub_if_data,14011400 dfs_cac_timer_work);14011401+ struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;1402140214031403 ieee80211_vif_release_channel(sdata);14041404-14051405- cfg80211_cac_event(sdata->dev, NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);14041404+ cfg80211_cac_event(sdata->dev, &chandef,14051405+ NL80211_RADAR_CAC_FINISHED,14061406+ GFP_KERNEL);14061407}1407140814081409/* MLME */···1748174517491746 ifmgd->flags = 0;17501747 ieee80211_vif_release_channel(sdata);17481748+17491749+ sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;17511750}1752175117531752void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,···4196419141974192 sdata->control_port_protocol = req->crypto.control_port_ethertype;41984193 sdata->control_port_no_encrypt = req->crypto.control_port_no_encrypt;41944194+ sdata->encrypt_headroom = ieee80211_cs_headroom(local, &req->crypto,41954195+ sdata->vif.type);4199419642004197 /* kick off associate process */42014198
···5454 int r = bitrates[j % 4];5555 p += sprintf(p, " %2u.%1uM", r / 10, r % 10);5656 } else {5757- p += sprintf(p, " MCS%-2u", (mg->streams - 1) *5858- MCS_GROUP_RATES + j);5757+ p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j);5958 }60596160 tp = mr->cur_tp / 10;
+58-32
net/mac80211/rx.c
···638638 return le16_to_cpu(mmie->key_id);639639}640640641641+static int iwl80211_get_cs_keyid(const struct ieee80211_cipher_scheme *cs,642642+ struct sk_buff *skb)643643+{644644+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;645645+ __le16 fc;646646+ int hdrlen;647647+ u8 keyid;648648+649649+ fc = hdr->frame_control;650650+ hdrlen = ieee80211_hdrlen(fc);651651+652652+ if (skb->len < hdrlen + cs->hdr_len)653653+ return -EINVAL;654654+655655+ skb_copy_bits(skb, hdrlen + cs->key_idx_off, &keyid, 1);656656+ keyid &= cs->key_idx_mask;657657+ keyid >>= cs->key_idx_shift;658658+659659+ return keyid;660660+}661661+641662static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)642663{643664 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;···750729 lockdep_assert_held(&tid_agg_rx->reorder_lock);751730752731 while (ieee80211_sn_less(tid_agg_rx->head_seq_num, head_seq_num)) {753753- index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,754754- tid_agg_rx->ssn) %755755- tid_agg_rx->buf_size;732732+ index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;756733 ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,757734 frames);758735 }···776757 lockdep_assert_held(&tid_agg_rx->reorder_lock);777758778759 /* release the buffer until next missing frame */779779- index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,780780- tid_agg_rx->ssn) % tid_agg_rx->buf_size;760760+ index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;781761 if (!tid_agg_rx->reorder_buf[index] &&782762 tid_agg_rx->stored_mpdu_num) {783763 /*···811793 } else while (tid_agg_rx->reorder_buf[index]) {812794 ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,813795 frames);814814- index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,815815- tid_agg_rx->ssn) %816816- tid_agg_rx->buf_size;796796+ index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;817797 }818798819799 if (tid_agg_rx->stored_mpdu_num) {820820- j = index = ieee80211_sn_sub(tid_agg_rx->head_seq_num,821821- tid_agg_rx->ssn) %822822- tid_agg_rx->buf_size;800800+ j = index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;823801824802 for (; j != (index - 1) % tid_agg_rx->buf_size;825803 j = (j + 1) % tid_agg_rx->buf_size) {···875861876862 /* Now the new frame is always in the range of the reordering buffer */877863878878- index = ieee80211_sn_sub(mpdu_seq_num,879879- tid_agg_rx->ssn) % tid_agg_rx->buf_size;864864+ index = mpdu_seq_num % tid_agg_rx->buf_size;880865881866 /* check if we already stored this frame */882867 if (tid_agg_rx->reorder_buf[index]) {···13821369 struct ieee80211_key *sta_ptk = NULL;13831370 int mmie_keyidx = -1;13841371 __le16 fc;13721372+ const struct ieee80211_cipher_scheme *cs = NULL;1385137313861374 /*13871375 * Key selection 101···1420140614211407 /* start without a key */14221408 rx->key = NULL;14231423-14241424- if (rx->sta)14251425- sta_ptk = rcu_dereference(rx->sta->ptk);14261426-14271409 fc = hdr->frame_control;14101410+14111411+ if (rx->sta) {14121412+ int keyid = rx->sta->ptk_idx;14131413+14141414+ if (ieee80211_has_protected(fc) && rx->sta->cipher_scheme) {14151415+ cs = rx->sta->cipher_scheme;14161416+ keyid = iwl80211_get_cs_keyid(cs, rx->skb);14171417+ if (unlikely(keyid < 0))14181418+ return RX_DROP_UNUSABLE;14191419+ }14201420+ sta_ptk = rcu_dereference(rx->sta->ptk[keyid]);14211421+ }1428142214291423 if (!ieee80211_has_protected(fc))14301424 mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);···14941472 return RX_CONTINUE;14951473 } else {14961474 u8 keyid;14751475+14971476 /*14981477 * The device doesn't give us the IV so we won't be14991478 * able to look up the key. That's ok though, we···1510148715111488 hdrlen = ieee80211_hdrlen(fc);1512148915131513- if (rx->skb->len < 8 + hdrlen)15141514- return RX_DROP_UNUSABLE; /* TODO: count this? */14901490+ if (cs) {14911491+ keyidx = iwl80211_get_cs_keyid(cs, rx->skb);1515149215161516- /*15171517- * no need to call ieee80211_wep_get_keyidx,15181518- * it verifies a bunch of things we've done already15191519- */15201520- skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);15211521- keyidx = keyid >> 6;14931493+ if (unlikely(keyidx < 0))14941494+ return RX_DROP_UNUSABLE;14951495+ } else {14961496+ if (rx->skb->len < 8 + hdrlen)14971497+ return RX_DROP_UNUSABLE; /* TODO: count this? */14981498+ /*14991499+ * no need to call ieee80211_wep_get_keyidx,15001500+ * it verifies a bunch of things we've done already15011501+ */15021502+ skb_copy_bits(rx->skb, hdrlen + 3, &keyid, 1);15031503+ keyidx = keyid >> 6;15041504+ }1522150515231506 /* check per-station GTK first, if multicast packet */15241507 if (is_multicast_ether_addr(hdr->addr1) && rx->sta)···15721543 result = ieee80211_crypto_aes_cmac_decrypt(rx);15731544 break;15741545 default:15751575- /*15761576- * We can reach here only with HW-only algorithms15771577- * but why didn't it decrypt the frame?!15781578- */15791579- return RX_DROP_UNUSABLE;15461546+ result = ieee80211_crypto_hw_decrypt(rx);15801547 }1581154815821549 /* the hdr variable is invalid after the decrypt handlers */···20822057 struct ieee80211_sub_if_data *sdata = rx->sdata;20832058 struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);20842059 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;20852085- __le16 reason = cpu_to_le16(WLAN_REASON_MESH_PATH_NOFORWARD);20862060 u16 q, hdrlen;2087206120882062 hdr = (struct ieee80211_hdr *) skb->data;···21892165 } else {21902166 /* unable to resolve next hop */21912167 mesh_path_error_tx(sdata, ifmsh->mshcfg.element_ttl,21922192- fwd_hdr->addr3, 0, reason, fwd_hdr->addr2);21682168+ fwd_hdr->addr3, 0,21692169+ WLAN_REASON_MESH_PATH_NOFORWARD,21702170+ fwd_hdr->addr2);21932171 IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);21942172 kfree_skb(fwd_skb);21952173 return RX_DROP_MONITOR;
+5-5
net/mac80211/scan.c
···526526 ieee80211_hw_config(local, 0);527527528528 if ((req->channels[0]->flags &529529- IEEE80211_CHAN_PASSIVE_SCAN) ||529529+ IEEE80211_CHAN_NO_IR) ||530530 !local->scan_req->n_ssids) {531531 next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;532532 } else {···572572 * TODO: channel switching also consumes quite some time,573573 * add that delay as well to get a better estimation574574 */575575- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN)575575+ if (chan->flags & IEEE80211_CHAN_NO_IR)576576 return IEEE80211_PASSIVE_CHANNEL_TIME;577577 return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;578578}···696696 *697697 * In any case, it is not necessary for a passive scan.698698 */699699- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||699699+ if (chan->flags & IEEE80211_CHAN_NO_IR ||700700 !local->scan_req->n_ssids) {701701 *next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;702702 local->next_scan_state = SCAN_DECISION;···881881 struct ieee80211_channel *tmp_ch =882882 &local->hw.wiphy->bands[band]->channels[i];883883884884- if (tmp_ch->flags & (IEEE80211_CHAN_NO_IBSS |884884+ if (tmp_ch->flags & (IEEE80211_CHAN_NO_IR |885885 IEEE80211_CHAN_DISABLED))886886 continue;887887···895895896896 local->int_scan_req->n_channels = n_ch;897897 } else {898898- if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IBSS |898898+ if (WARN_ON_ONCE(chan->flags & (IEEE80211_CHAN_NO_IR |899899 IEEE80211_CHAN_DISABLED)))900900 goto unlock;901901
+38-2
net/mac80211/sta_info.c
···266266 */267267void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)268268{269269+ int i;270270+269271 if (sta->rate_ctrl)270272 rate_control_free_sta(sta);273273+274274+ if (sta->tx_lat) {275275+ for (i = 0; i < IEEE80211_NUM_TIDS; i++)276276+ kfree(sta->tx_lat[i].bins);277277+ kfree(sta->tx_lat);278278+ }271279272280 sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr);273281···341333 struct ieee80211_local *local = sdata->local;342334 struct sta_info *sta;343335 struct timespec uptime;336336+ struct ieee80211_tx_latency_bin_ranges *tx_latency;344337 int i;345338346339 sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp);···418409 WARN_ON(1);419410 }420411 }412412+413413+ rcu_read_lock();414414+415415+ tx_latency = rcu_dereference(local->tx_latency);416416+ /* init stations Tx latency statistics && TID bins */417417+ if (tx_latency)418418+ sta->tx_lat = kzalloc(IEEE80211_NUM_TIDS *419419+ sizeof(struct ieee80211_tx_latency_stat),420420+ GFP_ATOMIC);421421+422422+ /*423423+ * if Tx latency and bins are enabled and the previous allocation424424+ * succeeded425425+ */426426+ if (tx_latency && tx_latency->n_ranges && sta->tx_lat)427427+ for (i = 0; i < IEEE80211_NUM_TIDS; i++) {428428+ /* size of bins is size of the ranges +1 */429429+ sta->tx_lat[i].bin_count =430430+ tx_latency->n_ranges + 1;431431+ sta->tx_lat[i].bins = kcalloc(sta->tx_lat[i].bin_count,432432+ sizeof(u32),433433+ GFP_ATOMIC);434434+ }435435+436436+ rcu_read_unlock();421437422438 sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);423439···541507542508 set_sta_flag(sta, WLAN_STA_INSERTED);543509510510+ ieee80211_recalc_min_chandef(sdata);544511 ieee80211_sta_debugfs_add(sta);545512 rate_control_add_sta_debugfs(sta);546513···665630#ifdef CONFIG_MAC80211_MESH666631 } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) {667632 ps = &sta->sdata->u.mesh.ps;668668- /* TIM map only for PLID <= IEEE80211_MAX_AID */669669- id = le16_to_cpu(sta->plid) % IEEE80211_MAX_AID;633633+ /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */634634+ id = sta->plid % (IEEE80211_MAX_AID + 1);670635#endif671636 } else {672637 return;···904869905870 rate_control_remove_sta_debugfs(sta);906871 ieee80211_sta_debugfs_remove(sta);872872+ ieee80211_recalc_min_chandef(sdata);907873908874 call_rcu(&sta->rcu_head, free_sta_rcu);909875
+33-5
net/mac80211/sta_info.h
···220220 u8 dialog_token_allocator;221221};222222223223+/*224224+ * struct ieee80211_tx_latency_stat - Tx latency statistics225225+ *226226+ * Measures TX latency and jitter for a station per TID.227227+ *228228+ * @max: worst case latency229229+ * @sum: sum of all latencies230230+ * @counter: amount of Tx frames sent from interface231231+ * @bins: each bin counts how many frames transmitted within a certain232232+ * latency range. when disabled it is NULL.233233+ * @bin_count: amount of bins.234234+ */235235+struct ieee80211_tx_latency_stat {236236+ u32 max;237237+ u32 sum;238238+ u32 counter;239239+ u32 *bins;240240+ u32 bin_count;241241+};223242224243/**225244 * struct sta_info - STA information···250231 * @hnext: hash table linked list pointer251232 * @local: pointer to the global information252233 * @sdata: virtual interface this station belongs to253253- * @ptk: peer key negotiated with this station, if any234234+ * @ptk: peer keys negotiated with this station, if any235235+ * @ptk_idx: last installed peer key index254236 * @gtk: group keys negotiated with this station, if any237237+ * @gtk_idx: last installed group key index255238 * @rate_ctrl: rate control algorithm reference256239 * @rate_ctrl_priv: rate control private per-STA pointer257240 * @last_tx_rate: rate used for last transmit, to report to userspace as···295274 * @tid_seq: per-TID sequence numbers for sending to this STA296275 * @ampdu_mlme: A-MPDU state machine state297276 * @timer_to_tid: identity mapping to ID timers277277+ * @tx_lat: Tx latency statistics298278 * @llid: Local link ID299279 * @plid: Peer link ID300280 * @reason: Cancel reason on PLINK_HOLDING state···325303 * @chain_signal_avg: signal average (per chain)326304 * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for327305 * AP only.306306+ * @cipher_scheme: optional cipher scheme for this station328307 */329308struct sta_info {330309 /* General information, mostly static */···335312 struct ieee80211_local *local;336313 struct ieee80211_sub_if_data *sdata;337314 struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];338338- struct ieee80211_key __rcu *ptk;315315+ struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS];316316+ u8 gtk_idx;317317+ u8 ptk_idx;339318 struct rate_control_ref *rate_ctrl;340319 void *rate_ctrl_priv;341320 spinlock_t lock;···405380 struct sta_ampdu_mlme ampdu_mlme;406381 u8 timer_to_tid[IEEE80211_NUM_TIDS];407382383383+ struct ieee80211_tx_latency_stat *tx_lat;384384+408385#ifdef CONFIG_MAC80211_MESH409386 /*410387 * Mesh peer link attributes411388 * TODO: move to a sub-structure that is referenced with pointer?412389 */413413- __le16 llid;414414- __le16 plid;415415- __le16 reason;390390+ u16 llid;391391+ u16 plid;392392+ u16 reason;416393 u8 plink_retries;417394 bool ignore_plink_timer;418395 enum nl80211_plink_state plink_state;···441414 unsigned int beacon_loss_count;442415443416 enum ieee80211_smps_mode known_smps_mode;417417+ const struct ieee80211_cipher_scheme *cipher_scheme;444418445419 /* keep last! */446420 struct ieee80211_sta sta;
+78
net/mac80211/status.c
···11111212#include <linux/export.h>1313#include <linux/etherdevice.h>1414+#include <linux/time.h>1415#include <net/mac80211.h>1516#include <asm/unaligned.h>1617#include "ieee80211_i.h"···464463}465464466465/*466466+ * Measure Tx frame completion and removal time for Tx latency statistics467467+ * calculation. A single Tx frame latency should be measured from when it468468+ * is entering the Kernel until we receive Tx complete confirmation indication469469+ * and remove the skb.470470+ */471471+static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,472472+ struct sk_buff *skb,473473+ struct sta_info *sta,474474+ struct ieee80211_hdr *hdr)475475+{476476+ ktime_t skb_dprt;477477+ struct timespec dprt_time;478478+ u32 msrmnt;479479+ u16 tid;480480+ u8 *qc;481481+ int i, bin_range_count, bin_count;482482+ u32 *bin_ranges;483483+ __le16 fc;484484+ struct ieee80211_tx_latency_stat *tx_lat;485485+ struct ieee80211_tx_latency_bin_ranges *tx_latency;486486+ ktime_t skb_arv = skb->tstamp;487487+488488+ tx_latency = rcu_dereference(local->tx_latency);489489+490490+ /* assert Tx latency stats are enabled & frame arrived when enabled */491491+ if (!tx_latency || !ktime_to_ns(skb_arv))492492+ return;493493+494494+ fc = hdr->frame_control;495495+496496+ if (!ieee80211_is_data(fc)) /* make sure it is a data frame */497497+ return;498498+499499+ /* get frame tid */500500+ if (ieee80211_is_data_qos(hdr->frame_control)) {501501+ qc = ieee80211_get_qos_ctl(hdr);502502+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;503503+ } else {504504+ tid = 0;505505+ }506506+507507+ tx_lat = &sta->tx_lat[tid];508508+509509+ ktime_get_ts(&dprt_time); /* time stamp completion time */510510+ skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);511511+ msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));512512+513513+ if (tx_lat->max < msrmnt) /* update stats */514514+ tx_lat->max = msrmnt;515515+ tx_lat->counter++;516516+ tx_lat->sum += msrmnt;517517+518518+ if (!tx_lat->bins) /* bins not activated */519519+ return;520520+521521+ /* count how many Tx frames transmitted with the appropriate latency */522522+ bin_range_count = tx_latency->n_ranges;523523+ bin_ranges = tx_latency->ranges;524524+ bin_count = tx_lat->bin_count;525525+526526+ for (i = 0; i < bin_range_count; i++) {527527+ if (msrmnt <= bin_ranges[i]) {528528+ tx_lat->bins[i]++;529529+ break;530530+ }531531+ }532532+ if (i == bin_range_count) /* msrmnt is bigger than the biggest range */533533+ tx_lat->bins[i]++;534534+}535535+536536+/*467537 * Use a static threshold for now, best value to be determined468538 * by testing ...469539 * Should it depend on:···692620693621 if (acked)694622 sta->last_ack_signal = info->status.ack_signal;623623+624624+ /*625625+ * Measure frame removal for tx latency626626+ * statistics calculation627627+ */628628+ ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);695629 }696630697631 rcu_read_unlock();
···120120 return rtnl_dereference(wiphy->regd);121121}122122123123+static const char *reg_dfs_region_str(enum nl80211_dfs_regions dfs_region)124124+{125125+ switch (dfs_region) {126126+ case NL80211_DFS_UNSET:127127+ return "unset";128128+ case NL80211_DFS_FCC:129129+ return "FCC";130130+ case NL80211_DFS_ETSI:131131+ return "ETSI";132132+ case NL80211_DFS_JP:133133+ return "JP";134134+ }135135+ return "Unknown";136136+}137137+123138static void rcu_free_regdom(const struct ieee80211_regdomain *r)124139{125140 if (!r)···178163 REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),179164 /* IEEE 802.11b/g, channels 12..13. */180165 REG_RULE(2467-10, 2472+10, 40, 6, 20,181181- NL80211_RRF_PASSIVE_SCAN |182182- NL80211_RRF_NO_IBSS),166166+ NL80211_RRF_NO_IR),183167 /* IEEE 802.11 channel 14 - Only JP enables184168 * this and for 802.11b only */185169 REG_RULE(2484-10, 2484+10, 20, 6, 20,186186- NL80211_RRF_PASSIVE_SCAN |187187- NL80211_RRF_NO_IBSS |170170+ NL80211_RRF_NO_IR |188171 NL80211_RRF_NO_OFDM),189172 /* IEEE 802.11a, channel 36..48 */190173 REG_RULE(5180-10, 5240+10, 160, 6, 20,191191- NL80211_RRF_PASSIVE_SCAN |192192- NL80211_RRF_NO_IBSS),174174+ NL80211_RRF_NO_IR),193175194176 /* IEEE 802.11a, channel 52..64 - DFS required */195177 REG_RULE(5260-10, 5320+10, 160, 6, 20,196196- NL80211_RRF_PASSIVE_SCAN |197197- NL80211_RRF_NO_IBSS |178178+ NL80211_RRF_NO_IR |198179 NL80211_RRF_DFS),199180200181 /* IEEE 802.11a, channel 100..144 - DFS required */201182 REG_RULE(5500-10, 5720+10, 160, 6, 20,202202- NL80211_RRF_PASSIVE_SCAN |203203- NL80211_RRF_NO_IBSS |183183+ NL80211_RRF_NO_IR |204184 NL80211_RRF_DFS),205185206186 /* IEEE 802.11a, channel 149..165 */207187 REG_RULE(5745-10, 5825+10, 80, 6, 20,208208- NL80211_RRF_PASSIVE_SCAN |209209- NL80211_RRF_NO_IBSS),188188+ NL80211_RRF_NO_IR),210189211190 /* IEEE 802.11ad (60gHz), channels 1..3 */212191 REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0),···217208module_param(ieee80211_regdom, charp, 0444);218209MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");219210211211+static void reg_kfree_last_request(void)212212+{213213+ struct regulatory_request *lr;214214+215215+ lr = get_last_request();216216+217217+ if (lr != &core_request_world && lr)218218+ kfree_rcu(lr, rcu_head);219219+}220220+221221+static void reg_update_last_request(struct regulatory_request *request)222222+{223223+ reg_kfree_last_request();224224+ rcu_assign_pointer(last_request, request);225225+}226226+220227static void reset_regdomains(bool full_reset,221228 const struct ieee80211_regdomain *new_regdom)222229{223230 const struct ieee80211_regdomain *r;224224- struct regulatory_request *lr;225231226232 ASSERT_RTNL();227233···259235 if (!full_reset)260236 return;261237262262- lr = get_last_request();263263- if (lr != &core_request_world && lr)264264- kfree_rcu(lr, rcu_head);265265- rcu_assign_pointer(last_request, &core_request_world);238238+ reg_update_last_request(&core_request_world);266239}267240268241/*···477456 return kobject_uevent(®_pdev->dev.kobj, KOBJ_CHANGE);478457}479458480480-static bool reg_is_valid_request(const char *alpha2)459459+static enum reg_request_treatment460460+reg_call_crda(struct regulatory_request *request)461461+{462462+ if (call_crda(request->alpha2))463463+ return REG_REQ_IGNORE;464464+ return REG_REQ_OK;465465+}466466+467467+bool reg_is_valid_request(const char *alpha2)481468{482469 struct regulatory_request *lr = get_last_request();483470···583554 return true;584555 return false;585556#undef ONE_GHZ_IN_KHZ557557+}558558+559559+/*560560+ * Later on we can perhaps use the more restrictive DFS561561+ * region but we don't have information for that yet so562562+ * for now simply disallow conflicts.563563+ */564564+static enum nl80211_dfs_regions565565+reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,566566+ const enum nl80211_dfs_regions dfs_region2)567567+{568568+ if (dfs_region1 != dfs_region2)569569+ return NL80211_DFS_UNSET;570570+ return dfs_region1;586571}587572588573/*···730687 rd->n_reg_rules = num_rules;731688 rd->alpha2[0] = '9';732689 rd->alpha2[1] = '8';690690+ rd->dfs_region = reg_intersect_dfs_region(rd1->dfs_region,691691+ rd2->dfs_region);733692734693 return rd;735694}···743698static u32 map_regdom_flags(u32 rd_flags)744699{745700 u32 channel_flags = 0;746746- if (rd_flags & NL80211_RRF_PASSIVE_SCAN)747747- channel_flags |= IEEE80211_CHAN_PASSIVE_SCAN;748748- if (rd_flags & NL80211_RRF_NO_IBSS)749749- channel_flags |= IEEE80211_CHAN_NO_IBSS;701701+ if (rd_flags & NL80211_RRF_NO_IR_ALL)702702+ channel_flags |= IEEE80211_CHAN_NO_IR;750703 if (rd_flags & NL80211_RRF_DFS)751704 channel_flags |= IEEE80211_CHAN_RADAR;752705 if (rd_flags & NL80211_RRF_NO_OFDM)···897854 PTR_ERR(reg_rule) == -ERANGE)898855 return;899856900900- REG_DBG_PRINT("Disabling freq %d MHz\n", chan->center_freq);901901- chan->flags |= IEEE80211_CHAN_DISABLED;857857+ if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&858858+ request_wiphy && request_wiphy == wiphy &&859859+ request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {860860+ REG_DBG_PRINT("Disabling freq %d MHz for good\n",861861+ chan->center_freq);862862+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;863863+ chan->flags = chan->orig_flags;864864+ } else {865865+ REG_DBG_PRINT("Disabling freq %d MHz\n",866866+ chan->center_freq);867867+ chan->flags |= IEEE80211_CHAN_DISABLED;868868+ }902869 return;903870 }904871···926873927874 if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&928875 request_wiphy && request_wiphy == wiphy &&929929- request_wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY) {876876+ request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {930877 /*931878 * This guarantees the driver's requested regulatory domain932879 * will always be used as a base for further regulatory···952899 chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);953900 if (chan->orig_mpwr) {954901 /*955955- * Devices that have their own custom regulatory domain956956- * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the957957- * passed country IE power settings.902902+ * Devices that use REGULATORY_COUNTRY_IE_FOLLOW_POWER903903+ * will always follow the passed country IE power settings.958904 */959905 if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&960960- wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&961961- wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)906906+ wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_FOLLOW_POWER)962907 chan->max_power = chan->max_reg_power;963908 else964909 chan->max_power = min(chan->orig_mpwr,···10269751027976static bool wiphy_strict_alpha2_regd(struct wiphy *wiphy)1028977{10291029- if (wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY &&10301030- !(wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY))978978+ if (wiphy->regulatory_flags & REGULATORY_STRICT_REG &&979979+ !(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG))1031980 return true;1032981 return false;1033982}···1045994 }10469951047996 if (initiator == NL80211_REGDOM_SET_BY_CORE &&10481048- wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY) {997997+ wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {1049998 REG_DBG_PRINT("Ignoring regulatory request set by %s "1050999 "since the driver uses its own custom "10511000 "regulatory domain\n",···10831032 return true;1084103310851034 if (lr && lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&10861086- wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)10351035+ wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)10871036 return true;1088103710891038 return false;···11111060 if (!reg_is_world_roaming(wiphy))11121061 return;1113106211141114- if (wiphy->flags & WIPHY_FLAG_DISABLE_BEACON_HINTS)10631063+ if (wiphy->regulatory_flags & REGULATORY_DISABLE_BEACON_HINTS)11151064 return;1116106511171066 chan_before.center_freq = chan->center_freq;11181067 chan_before.flags = chan->flags;1119106811201120- if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {11211121- chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;11221122- channel_changed = true;11231123- }11241124-11251125- if (chan->flags & IEEE80211_CHAN_NO_IBSS) {11261126- chan->flags &= ~IEEE80211_CHAN_NO_IBSS;10691069+ if (chan->flags & IEEE80211_CHAN_NO_IR) {10701070+ chan->flags &= ~IEEE80211_CHAN_NO_IR;11271071 channel_changed = true;11281072 }11291073···12511205 reg_process_ht_flags_band(wiphy, wiphy->bands[band]);12521206}1253120712081208+static void reg_call_notifier(struct wiphy *wiphy,12091209+ struct regulatory_request *request)12101210+{12111211+ if (wiphy->reg_notifier)12121212+ wiphy->reg_notifier(wiphy, request);12131213+}12141214+12541215static void wiphy_update_regulatory(struct wiphy *wiphy,12551216 enum nl80211_reg_initiator initiator)12561217{12571218 enum ieee80211_band band;12581219 struct regulatory_request *lr = get_last_request();1259122012601260- if (ignore_reg_update(wiphy, initiator))12211221+ if (ignore_reg_update(wiphy, initiator)) {12221222+ /*12231223+ * Regulatory updates set by CORE are ignored for custom12241224+ * regulatory cards. Let us notify the changes to the driver,12251225+ * as some drivers used this to restore its orig_* reg domain.12261226+ */12271227+ if (initiator == NL80211_REGDOM_SET_BY_CORE &&12281228+ wiphy->regulatory_flags & REGULATORY_CUSTOM_REG)12291229+ reg_call_notifier(wiphy, lr);12611230 return;12311231+ }1262123212631233 lr->dfs_region = get_cfg80211_regdom()->dfs_region;12641234···1283122112841222 reg_process_beacons(wiphy);12851223 reg_process_ht_flags(wiphy);12861286-12871287- if (wiphy->reg_notifier)12881288- wiphy->reg_notifier(wiphy, lr);12241224+ reg_call_notifier(wiphy, lr);12891225}1290122612911227static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)···12961236 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {12971237 wiphy = &rdev->wiphy;12981238 wiphy_update_regulatory(wiphy, initiator);12991299- /*13001300- * Regulatory updates set by CORE are ignored for custom13011301- * regulatory cards. Let us notify the changes to the driver,13021302- * as some drivers used this to restore its orig_* reg domain.13031303- */13041304- if (initiator == NL80211_REGDOM_SET_BY_CORE &&13051305- wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&13061306- wiphy->reg_notifier)13071307- wiphy->reg_notifier(wiphy, get_last_request());13081239 }13091240}13101241···13141263 if (IS_ERR(reg_rule)) {13151264 REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",13161265 chan->center_freq);13171317- chan->flags = IEEE80211_CHAN_DISABLED;12661266+ chan->orig_flags |= IEEE80211_CHAN_DISABLED;12671267+ chan->flags = chan->orig_flags;13181268 return;13191269 }13201270···13571305 enum ieee80211_band band;13581306 unsigned int bands_set = 0;1359130713081308+ WARN(!(wiphy->regulatory_flags & REGULATORY_CUSTOM_REG),13091309+ "wiphy should have REGULATORY_CUSTOM_REG\n");13101310+ wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;13111311+13601312 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {13611313 if (!wiphy->bands[band])13621314 continue;···13751319 WARN_ON(!bands_set);13761320}13771321EXPORT_SYMBOL(wiphy_apply_custom_regulatory);13781378-13791379-/* This has the logic which determines when a new request13801380- * should be ignored. */13811381-static enum reg_request_treatment13821382-get_reg_request_treatment(struct wiphy *wiphy,13831383- struct regulatory_request *pending_request)13841384-{13851385- struct wiphy *last_wiphy = NULL;13861386- struct regulatory_request *lr = get_last_request();13871387-13881388- /* All initial requests are respected */13891389- if (!lr)13901390- return REG_REQ_OK;13911391-13921392- switch (pending_request->initiator) {13931393- case NL80211_REGDOM_SET_BY_CORE:13941394- return REG_REQ_OK;13951395- case NL80211_REGDOM_SET_BY_COUNTRY_IE:13961396- if (reg_request_cell_base(lr)) {13971397- /* Trust a Cell base station over the AP's country IE */13981398- if (regdom_changes(pending_request->alpha2))13991399- return REG_REQ_IGNORE;14001400- return REG_REQ_ALREADY_SET;14011401- }14021402-14031403- last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);14041404-14051405- if (unlikely(!is_an_alpha2(pending_request->alpha2)))14061406- return -EINVAL;14071407- if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {14081408- if (last_wiphy != wiphy) {14091409- /*14101410- * Two cards with two APs claiming different14111411- * Country IE alpha2s. We could14121412- * intersect them, but that seems unlikely14131413- * to be correct. Reject second one for now.14141414- */14151415- if (regdom_changes(pending_request->alpha2))14161416- return REG_REQ_IGNORE;14171417- return REG_REQ_ALREADY_SET;14181418- }14191419- /*14201420- * Two consecutive Country IE hints on the same wiphy.14211421- * This should be picked up early by the driver/stack14221422- */14231423- if (WARN_ON(regdom_changes(pending_request->alpha2)))14241424- return REG_REQ_OK;14251425- return REG_REQ_ALREADY_SET;14261426- }14271427- return REG_REQ_OK;14281428- case NL80211_REGDOM_SET_BY_DRIVER:14291429- if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {14301430- if (regdom_changes(pending_request->alpha2))14311431- return REG_REQ_OK;14321432- return REG_REQ_ALREADY_SET;14331433- }14341434-14351435- /*14361436- * This would happen if you unplug and plug your card14371437- * back in or if you add a new device for which the previously14381438- * loaded card also agrees on the regulatory domain.14391439- */14401440- if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&14411441- !regdom_changes(pending_request->alpha2))14421442- return REG_REQ_ALREADY_SET;14431443-14441444- return REG_REQ_INTERSECT;14451445- case NL80211_REGDOM_SET_BY_USER:14461446- if (reg_request_cell_base(pending_request))14471447- return reg_ignore_cell_hint(pending_request);14481448-14491449- if (reg_request_cell_base(lr))14501450- return REG_REQ_IGNORE;14511451-14521452- if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)14531453- return REG_REQ_INTERSECT;14541454- /*14551455- * If the user knows better the user should set the regdom14561456- * to their country before the IE is picked up14571457- */14581458- if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&14591459- lr->intersect)14601460- return REG_REQ_IGNORE;14611461- /*14621462- * Process user requests only after previous user/driver/core14631463- * requests have been processed14641464- */14651465- if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||14661466- lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||14671467- lr->initiator == NL80211_REGDOM_SET_BY_USER) &&14681468- regdom_changes(lr->alpha2))14691469- return REG_REQ_IGNORE;14701470-14711471- if (!regdom_changes(pending_request->alpha2))14721472- return REG_REQ_ALREADY_SET;14731473-14741474- return REG_REQ_OK;14751475- }14761476-14771477- return REG_REQ_IGNORE;14781478-}1479132214801323static void reg_set_request_processed(void)14811324{···13961441}1397144213981443/**13991399- * __regulatory_hint - hint to the wireless core a regulatory domain14001400- * @wiphy: if the hint comes from country information from an AP, this14011401- * is required to be set to the wiphy that received the information14021402- * @pending_request: the regulatory request currently being processed14441444+ * reg_process_hint_core - process core regulatory requests14451445+ * @pending_request: a pending core regulatory request14031446 *14041404- * The Wireless subsystem can use this function to hint to the wireless core14051405- * what it believes should be the current regulatory domain.14471447+ * The wireless subsystem can use this function to process14481448+ * a regulatory request issued by the regulatory core.14061449 *14071450 * Returns one of the different reg request treatment values.14081451 */14091452static enum reg_request_treatment14101410-__regulatory_hint(struct wiphy *wiphy,14111411- struct regulatory_request *pending_request)14531453+reg_process_hint_core(struct regulatory_request *core_request)14121454{14131413- const struct ieee80211_regdomain *regd;14141414- bool intersect = false;14151415- enum reg_request_treatment treatment;14161416- struct regulatory_request *lr;1417145514181418- treatment = get_reg_request_treatment(wiphy, pending_request);14561456+ core_request->intersect = false;14571457+ core_request->processed = false;1419145814201420- switch (treatment) {14211421- case REG_REQ_INTERSECT:14221422- if (pending_request->initiator ==14231423- NL80211_REGDOM_SET_BY_DRIVER) {14241424- regd = reg_copy_regd(get_cfg80211_regdom());14251425- if (IS_ERR(regd)) {14261426- kfree(pending_request);14271427- return PTR_ERR(regd);14281428- }14291429- rcu_assign_pointer(wiphy->regd, regd);14301430- }14311431- intersect = true;14321432- break;14331433- case REG_REQ_OK:14341434- break;14351435- default:14361436- /*14371437- * If the regulatory domain being requested by the14381438- * driver has already been set just copy it to the14391439- * wiphy14401440- */14411441- if (treatment == REG_REQ_ALREADY_SET &&14421442- pending_request->initiator == NL80211_REGDOM_SET_BY_DRIVER) {14431443- regd = reg_copy_regd(get_cfg80211_regdom());14441444- if (IS_ERR(regd)) {14451445- kfree(pending_request);14461446- return REG_REQ_IGNORE;14471447- }14481448- treatment = REG_REQ_ALREADY_SET;14491449- rcu_assign_pointer(wiphy->regd, regd);14501450- goto new_request;14511451- }14521452- kfree(pending_request);14531453- return treatment;14541454- }14591459+ reg_update_last_request(core_request);1455146014561456-new_request:14571457- lr = get_last_request();14581458- if (lr != &core_request_world && lr)14591459- kfree_rcu(lr, rcu_head);14611461+ return reg_call_crda(core_request);14621462+}1460146314611461- pending_request->intersect = intersect;14621462- pending_request->processed = false;14631463- rcu_assign_pointer(last_request, pending_request);14641464- lr = pending_request;14641464+static enum reg_request_treatment14651465+__reg_process_hint_user(struct regulatory_request *user_request)14661466+{14671467+ struct regulatory_request *lr = get_last_request();1465146814661466- pending_request = NULL;14691469+ if (reg_request_cell_base(user_request))14701470+ return reg_ignore_cell_hint(user_request);1467147114681468- if (lr->initiator == NL80211_REGDOM_SET_BY_USER) {14691469- user_alpha2[0] = lr->alpha2[0];14701470- user_alpha2[1] = lr->alpha2[1];14711471- }14721472-14731473- /* When r == REG_REQ_INTERSECT we do need to call CRDA */14741474- if (treatment != REG_REQ_OK && treatment != REG_REQ_INTERSECT) {14751475- /*14761476- * Since CRDA will not be called in this case as we already14771477- * have applied the requested regulatory domain before we just14781478- * inform userspace we have processed the request14791479- */14801480- if (treatment == REG_REQ_ALREADY_SET) {14811481- nl80211_send_reg_change_event(lr);14821482- reg_set_request_processed();14831483- }14841484- return treatment;14851485- }14861486-14871487- if (call_crda(lr->alpha2))14721472+ if (reg_request_cell_base(lr))14881473 return REG_REQ_IGNORE;14741474+14751475+ if (lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)14761476+ return REG_REQ_INTERSECT;14771477+ /*14781478+ * If the user knows better the user should set the regdom14791479+ * to their country before the IE is picked up14801480+ */14811481+ if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&14821482+ lr->intersect)14831483+ return REG_REQ_IGNORE;14841484+ /*14851485+ * Process user requests only after previous user/driver/core14861486+ * requests have been processed14871487+ */14881488+ if ((lr->initiator == NL80211_REGDOM_SET_BY_CORE ||14891489+ lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||14901490+ lr->initiator == NL80211_REGDOM_SET_BY_USER) &&14911491+ regdom_changes(lr->alpha2))14921492+ return REG_REQ_IGNORE;14931493+14941494+ if (!regdom_changes(user_request->alpha2))14951495+ return REG_REQ_ALREADY_SET;14961496+14891497 return REG_REQ_OK;14901498}1491149915001500+/**15011501+ * reg_process_hint_user - process user regulatory requests15021502+ * @user_request: a pending user regulatory request15031503+ *15041504+ * The wireless subsystem can use this function to process15051505+ * a regulatory request initiated by userspace.15061506+ *15071507+ * Returns one of the different reg request treatment values.15081508+ */15091509+static enum reg_request_treatment15101510+reg_process_hint_user(struct regulatory_request *user_request)15111511+{15121512+ enum reg_request_treatment treatment;15131513+15141514+ treatment = __reg_process_hint_user(user_request);15151515+ if (treatment == REG_REQ_IGNORE ||15161516+ treatment == REG_REQ_ALREADY_SET) {15171517+ kfree(user_request);15181518+ return treatment;15191519+ }15201520+15211521+ user_request->intersect = treatment == REG_REQ_INTERSECT;15221522+ user_request->processed = false;15231523+15241524+ reg_update_last_request(user_request);15251525+15261526+ user_alpha2[0] = user_request->alpha2[0];15271527+ user_alpha2[1] = user_request->alpha2[1];15281528+15291529+ return reg_call_crda(user_request);15301530+}15311531+15321532+static enum reg_request_treatment15331533+__reg_process_hint_driver(struct regulatory_request *driver_request)15341534+{15351535+ struct regulatory_request *lr = get_last_request();15361536+15371537+ if (lr->initiator == NL80211_REGDOM_SET_BY_CORE) {15381538+ if (regdom_changes(driver_request->alpha2))15391539+ return REG_REQ_OK;15401540+ return REG_REQ_ALREADY_SET;15411541+ }15421542+15431543+ /*15441544+ * This would happen if you unplug and plug your card15451545+ * back in or if you add a new device for which the previously15461546+ * loaded card also agrees on the regulatory domain.15471547+ */15481548+ if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&15491549+ !regdom_changes(driver_request->alpha2))15501550+ return REG_REQ_ALREADY_SET;15511551+15521552+ return REG_REQ_INTERSECT;15531553+}15541554+15551555+/**15561556+ * reg_process_hint_driver - process driver regulatory requests15571557+ * @driver_request: a pending driver regulatory request15581558+ *15591559+ * The wireless subsystem can use this function to process15601560+ * a regulatory request issued by an 802.11 driver.15611561+ *15621562+ * Returns one of the different reg request treatment values.15631563+ */15641564+static enum reg_request_treatment15651565+reg_process_hint_driver(struct wiphy *wiphy,15661566+ struct regulatory_request *driver_request)15671567+{15681568+ const struct ieee80211_regdomain *regd;15691569+ enum reg_request_treatment treatment;15701570+15711571+ treatment = __reg_process_hint_driver(driver_request);15721572+15731573+ switch (treatment) {15741574+ case REG_REQ_OK:15751575+ break;15761576+ case REG_REQ_IGNORE:15771577+ kfree(driver_request);15781578+ return treatment;15791579+ case REG_REQ_INTERSECT:15801580+ /* fall through */15811581+ case REG_REQ_ALREADY_SET:15821582+ regd = reg_copy_regd(get_cfg80211_regdom());15831583+ if (IS_ERR(regd)) {15841584+ kfree(driver_request);15851585+ return REG_REQ_IGNORE;15861586+ }15871587+ rcu_assign_pointer(wiphy->regd, regd);15881588+ }15891589+15901590+15911591+ driver_request->intersect = treatment == REG_REQ_INTERSECT;15921592+ driver_request->processed = false;15931593+15941594+ reg_update_last_request(driver_request);15951595+15961596+ /*15971597+ * Since CRDA will not be called in this case as we already15981598+ * have applied the requested regulatory domain before we just15991599+ * inform userspace we have processed the request16001600+ */16011601+ if (treatment == REG_REQ_ALREADY_SET) {16021602+ nl80211_send_reg_change_event(driver_request);16031603+ reg_set_request_processed();16041604+ return treatment;16051605+ }16061606+16071607+ return reg_call_crda(driver_request);16081608+}16091609+16101610+static enum reg_request_treatment16111611+__reg_process_hint_country_ie(struct wiphy *wiphy,16121612+ struct regulatory_request *country_ie_request)16131613+{16141614+ struct wiphy *last_wiphy = NULL;16151615+ struct regulatory_request *lr = get_last_request();16161616+16171617+ if (reg_request_cell_base(lr)) {16181618+ /* Trust a Cell base station over the AP's country IE */16191619+ if (regdom_changes(country_ie_request->alpha2))16201620+ return REG_REQ_IGNORE;16211621+ return REG_REQ_ALREADY_SET;16221622+ } else {16231623+ if (wiphy->regulatory_flags & REGULATORY_COUNTRY_IE_IGNORE)16241624+ return REG_REQ_IGNORE;16251625+ }16261626+16271627+ if (unlikely(!is_an_alpha2(country_ie_request->alpha2)))16281628+ return -EINVAL;16291629+16301630+ if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE)16311631+ return REG_REQ_OK;16321632+16331633+ last_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);16341634+16351635+ if (last_wiphy != wiphy) {16361636+ /*16371637+ * Two cards with two APs claiming different16381638+ * Country IE alpha2s. We could16391639+ * intersect them, but that seems unlikely16401640+ * to be correct. Reject second one for now.16411641+ */16421642+ if (regdom_changes(country_ie_request->alpha2))16431643+ return REG_REQ_IGNORE;16441644+ return REG_REQ_ALREADY_SET;16451645+ }16461646+ /*16471647+ * Two consecutive Country IE hints on the same wiphy.16481648+ * This should be picked up early by the driver/stack16491649+ */16501650+ if (WARN_ON(regdom_changes(country_ie_request->alpha2)))16511651+ return REG_REQ_OK;16521652+ return REG_REQ_ALREADY_SET;16531653+}16541654+16551655+/**16561656+ * reg_process_hint_country_ie - process regulatory requests from country IEs16571657+ * @country_ie_request: a regulatory request from a country IE16581658+ *16591659+ * The wireless subsystem can use this function to process16601660+ * a regulatory request issued by a country Information Element.16611661+ *16621662+ * Returns one of the different reg request treatment values.16631663+ */16641664+static enum reg_request_treatment16651665+reg_process_hint_country_ie(struct wiphy *wiphy,16661666+ struct regulatory_request *country_ie_request)16671667+{16681668+ enum reg_request_treatment treatment;16691669+16701670+ treatment = __reg_process_hint_country_ie(wiphy, country_ie_request);16711671+16721672+ switch (treatment) {16731673+ case REG_REQ_OK:16741674+ break;16751675+ case REG_REQ_IGNORE:16761676+ /* fall through */16771677+ case REG_REQ_ALREADY_SET:16781678+ kfree(country_ie_request);16791679+ return treatment;16801680+ case REG_REQ_INTERSECT:16811681+ kfree(country_ie_request);16821682+ /*16831683+ * This doesn't happen yet, not sure we16841684+ * ever want to support it for this case.16851685+ */16861686+ WARN_ONCE(1, "Unexpected intersection for country IEs");16871687+ return REG_REQ_IGNORE;16881688+ }16891689+16901690+ country_ie_request->intersect = false;16911691+ country_ie_request->processed = false;16921692+16931693+ reg_update_last_request(country_ie_request);16941694+16951695+ return reg_call_crda(country_ie_request);16961696+}16971697+14921698/* This processes *all* regulatory hints */14931493-static void reg_process_hint(struct regulatory_request *reg_request,14941494- enum nl80211_reg_initiator reg_initiator)16991699+static void reg_process_hint(struct regulatory_request *reg_request)14951700{14961701 struct wiphy *wiphy = NULL;17021702+ enum reg_request_treatment treatment;1497170314981704 if (WARN_ON(!reg_request->alpha2))14991705 return;···16621546 if (reg_request->wiphy_idx != WIPHY_IDX_INVALID)16631547 wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);1664154816651665- if (reg_initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {15491549+ if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER && !wiphy) {16661550 kfree(reg_request);16671551 return;16681552 }1669155316701670- switch (__regulatory_hint(wiphy, reg_request)) {16711671- case REG_REQ_ALREADY_SET:16721672- /* This is required so that the orig_* parameters are saved */16731673- if (wiphy && wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)16741674- wiphy_update_regulatory(wiphy, reg_initiator);15541554+ switch (reg_request->initiator) {15551555+ case NL80211_REGDOM_SET_BY_CORE:15561556+ reg_process_hint_core(reg_request);15571557+ return;15581558+ case NL80211_REGDOM_SET_BY_USER:15591559+ treatment = reg_process_hint_user(reg_request);15601560+ if (treatment == REG_REQ_OK ||15611561+ treatment == REG_REQ_ALREADY_SET)15621562+ return;15631563+ schedule_delayed_work(®_timeout, msecs_to_jiffies(3142));15641564+ return;15651565+ case NL80211_REGDOM_SET_BY_DRIVER:15661566+ treatment = reg_process_hint_driver(wiphy, reg_request);15671567+ break;15681568+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:15691569+ treatment = reg_process_hint_country_ie(wiphy, reg_request);16751570 break;16761571 default:16771677- if (reg_initiator == NL80211_REGDOM_SET_BY_USER)16781678- schedule_delayed_work(®_timeout,16791679- msecs_to_jiffies(3142));16801680- break;15721572+ WARN(1, "invalid initiator %d\n", reg_request->initiator);15731573+ return;16811574 }15751575+15761576+ /* This is required so that the orig_* parameters are saved */15771577+ if (treatment == REG_REQ_ALREADY_SET && wiphy &&15781578+ wiphy->regulatory_flags & REGULATORY_STRICT_REG)15791579+ wiphy_update_regulatory(wiphy, reg_request->initiator);16821580}1683158116841582/*···1726159617271597 spin_unlock(®_requests_lock);1728159817291729- reg_process_hint(reg_request, reg_request->initiator);15991599+ reg_process_hint(reg_request);17301600}1731160117321602/* Processes beacon hints -- this has nothing to do with country IEs */···20181888 world_alpha2[1] = cfg80211_world_regdom->alpha2[1];2019188920201890 list_for_each_entry(rdev, &cfg80211_rdev_list, list) {20212021- if (rdev->wiphy.flags & WIPHY_FLAG_CUSTOM_REGULATORY)18911891+ if (rdev->wiphy.regulatory_flags & REGULATORY_CUSTOM_REG)20221892 restore_custom_reg_settings(&rdev->wiphy);20231893 }20241894···21462016 }21472017}2148201821492149-bool reg_supported_dfs_region(u8 dfs_region)20192019+bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)21502020{21512021 switch (dfs_region) {21522022 case NL80211_DFS_UNSET:···21582028 REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",21592029 dfs_region);21602030 return false;21612161- }21622162-}21632163-21642164-static void print_dfs_region(u8 dfs_region)21652165-{21662166- if (!dfs_region)21672167- return;21682168-21692169- switch (dfs_region) {21702170- case NL80211_DFS_FCC:21712171- pr_info(" DFS Master region FCC");21722172- break;21732173- case NL80211_DFS_ETSI:21742174- pr_info(" DFS Master region ETSI");21752175- break;21762176- case NL80211_DFS_JP:21772177- pr_info(" DFS Master region JP");21782178- break;21792179- default:21802180- pr_info(" DFS Master region Unknown");21812181- break;21822031 }21832032}21842033···21922083 }21932084 }2194208521952195- print_dfs_region(rd->dfs_region);20862086+ pr_info(" DFS Master region: %s", reg_dfs_region_str(rd->dfs_region));21962087 print_rd_rules(rd);21972088}21982089···22022093 print_rd_rules(rd);22032094}2204209522052205-/* Takes ownership of rd only if it doesn't fail */22062206-static int __set_regdom(const struct ieee80211_regdomain *rd)20962096+static int reg_set_rd_core(const struct ieee80211_regdomain *rd)22072097{22082208- const struct ieee80211_regdomain *regd;20982098+ if (!is_world_regdom(rd->alpha2))20992099+ return -EINVAL;21002100+ update_world_regdomain(rd);21012101+ return 0;21022102+}21032103+21042104+static int reg_set_rd_user(const struct ieee80211_regdomain *rd,21052105+ struct regulatory_request *user_request)21062106+{22092107 const struct ieee80211_regdomain *intersected_rd = NULL;22102210- struct wiphy *request_wiphy;22112211- struct regulatory_request *lr = get_last_request();2212210822132213- /* Some basic sanity checks first */22142214-22152215- if (!reg_is_valid_request(rd->alpha2))21092109+ if (is_world_regdom(rd->alpha2))22162110 return -EINVAL;2217211122182218- if (is_world_regdom(rd->alpha2)) {22192219- update_world_regdomain(rd);22202220- return 0;22212221- }22222222-22232223- if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&22242224- !is_unknown_alpha2(rd->alpha2))22252225- return -EINVAL;22262226-22272227- /*22282228- * Lets only bother proceeding on the same alpha2 if the current22292229- * rd is non static (it means CRDA was present and was used last)22302230- * and the pending request came in from a country IE22312231- */22322232- if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {22332233- /*22342234- * If someone else asked us to change the rd lets only bother22352235- * checking if the alpha2 changes if CRDA was already called22362236- */22372237- if (!regdom_changes(rd->alpha2))22382238- return -EALREADY;22392239- }22402240-22412241- /*22422242- * Now lets set the regulatory domain, update all driver channels22432243- * and finally inform them of what we have done, in case they want22442244- * to review or adjust their own settings based on their own22452245- * internal EEPROM data22462246- */21122112+ if (!regdom_changes(rd->alpha2))21132113+ return -EALREADY;2247211422482115 if (!is_valid_rd(rd)) {22492116 pr_err("Invalid regulatory domain detected:\n");···22272142 return -EINVAL;22282143 }2229214422302230- request_wiphy = wiphy_idx_to_wiphy(lr->wiphy_idx);22312231- if (!request_wiphy &&22322232- (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER ||22332233- lr->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) {21452145+ if (!user_request->intersect) {21462146+ reset_regdomains(false, rd);21472147+ return 0;21482148+ }21492149+21502150+ intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());21512151+ if (!intersected_rd)21522152+ return -EINVAL;21532153+21542154+ kfree(rd);21552155+ rd = NULL;21562156+ reset_regdomains(false, intersected_rd);21572157+21582158+ return 0;21592159+}21602160+21612161+static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,21622162+ struct regulatory_request *driver_request)21632163+{21642164+ const struct ieee80211_regdomain *regd;21652165+ const struct ieee80211_regdomain *intersected_rd = NULL;21662166+ const struct ieee80211_regdomain *tmp;21672167+ struct wiphy *request_wiphy;21682168+21692169+ if (is_world_regdom(rd->alpha2))21702170+ return -EINVAL;21712171+21722172+ if (!regdom_changes(rd->alpha2))21732173+ return -EALREADY;21742174+21752175+ if (!is_valid_rd(rd)) {21762176+ pr_err("Invalid regulatory domain detected:\n");21772177+ print_regdomain_info(rd);21782178+ return -EINVAL;21792179+ }21802180+21812181+ request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);21822182+ if (!request_wiphy) {22342183 schedule_delayed_work(®_timeout, 0);22352184 return -ENODEV;22362185 }2237218622382238- if (!lr->intersect) {22392239- if (lr->initiator != NL80211_REGDOM_SET_BY_DRIVER) {22402240- reset_regdomains(false, rd);22412241- return 0;22422242- }22432243-22442244- /*22452245- * For a driver hint, lets copy the regulatory domain the22462246- * driver wanted to the wiphy to deal with conflicts22472247- */22482248-22492249- /*22502250- * Userspace could have sent two replies with only22512251- * one kernel request.22522252- */21872187+ if (!driver_request->intersect) {22532188 if (request_wiphy->regd)22542189 return -EALREADY;22552190···22822177 return 0;22832178 }2284217922852285- /* Intersection requires a bit more work */21802180+ intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());21812181+ if (!intersected_rd)21822182+ return -EINVAL;2286218322872287- if (lr->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {22882288- intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());22892289- if (!intersected_rd)22902290- return -EINVAL;21842184+ /*21852185+ * We can trash what CRDA provided now.21862186+ * However if a driver requested this specific regulatory21872187+ * domain we keep it for its private use21882188+ */21892189+ tmp = get_wiphy_regdom(request_wiphy);21902190+ rcu_assign_pointer(request_wiphy->regd, rd);21912191+ rcu_free_regdom(tmp);2291219222922292- /*22932293- * We can trash what CRDA provided now.22942294- * However if a driver requested this specific regulatory22952295- * domain we keep it for its private use22962296- */22972297- if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER) {22982298- const struct ieee80211_regdomain *tmp;21932193+ rd = NULL;2299219423002300- tmp = get_wiphy_regdom(request_wiphy);23012301- rcu_assign_pointer(request_wiphy->regd, rd);23022302- rcu_free_regdom(tmp);23032303- } else {23042304- kfree(rd);23052305- }21952195+ reset_regdomains(false, intersected_rd);2306219623072307- rd = NULL;23082308-23092309- reset_regdomains(false, intersected_rd);23102310-23112311- return 0;23122312- }23132313-23142314- return -EINVAL;21972197+ return 0;23152198}2316219922002200+static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,22012201+ struct regulatory_request *country_ie_request)22022202+{22032203+ struct wiphy *request_wiphy;22042204+22052205+ if (!is_alpha2_set(rd->alpha2) && !is_an_alpha2(rd->alpha2) &&22062206+ !is_unknown_alpha2(rd->alpha2))22072207+ return -EINVAL;22082208+22092209+ /*22102210+ * Lets only bother proceeding on the same alpha2 if the current22112211+ * rd is non static (it means CRDA was present and was used last)22122212+ * and the pending request came in from a country IE22132213+ */22142214+22152215+ if (!is_valid_rd(rd)) {22162216+ pr_err("Invalid regulatory domain detected:\n");22172217+ print_regdomain_info(rd);22182218+ return -EINVAL;22192219+ }22202220+22212221+ request_wiphy = wiphy_idx_to_wiphy(country_ie_request->wiphy_idx);22222222+ if (!request_wiphy) {22232223+ schedule_delayed_work(®_timeout, 0);22242224+ return -ENODEV;22252225+ }22262226+22272227+ if (country_ie_request->intersect)22282228+ return -EINVAL;22292229+22302230+ reset_regdomains(false, rd);22312231+ return 0;22322232+}2317223323182234/*23192235 * Use this call to set the current regulatory domain. Conflicts with···23462220 struct regulatory_request *lr;23472221 int r;2348222222232223+ if (!reg_is_valid_request(rd->alpha2)) {22242224+ kfree(rd);22252225+ return -EINVAL;22262226+ }22272227+23492228 lr = get_last_request();2350222923512230 /* Note that this doesn't update the wiphys, this is done below */23522352- r = __set_regdom(rd);22312231+ switch (lr->initiator) {22322232+ case NL80211_REGDOM_SET_BY_CORE:22332233+ r = reg_set_rd_core(rd);22342234+ break;22352235+ case NL80211_REGDOM_SET_BY_USER:22362236+ r = reg_set_rd_user(rd, lr);22372237+ break;22382238+ case NL80211_REGDOM_SET_BY_DRIVER:22392239+ r = reg_set_rd_driver(rd, lr);22402240+ break;22412241+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:22422242+ r = reg_set_rd_country_ie(rd, lr);22432243+ break;22442244+ default:22452245+ WARN(1, "invalid initiator %d\n", lr->initiator);22462246+ return -EINVAL;22472247+ }22482248+23532249 if (r) {23542250 if (r == -EALREADY)23552251 reg_set_request_processed();