diff --git a/sys/contrib/dev/athk/ath.h b/sys/contrib/dev/athk/ath.h index f083fb9038c3..90869e6d28da 100644 --- a/sys/contrib/dev/athk/ath.h +++ b/sys/contrib/dev/athk/ath.h @@ -1,335 +1,340 @@ /* * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef ATH_H #define ATH_H #include #include #include #include #include +#if defined(__FreeBSD__) +#include +#endif /* * The key cache is used for h/w cipher state and also for * tracking station state such as the current tx antenna. * We also setup a mapping table between key cache slot indices * and station state to short-circuit node lookups on rx. * Different parts have different size key caches. We handle * up to ATH_KEYMAX entries (could dynamically allocate state). */ #define ATH_KEYMAX 128 /* max key cache size we handle */ struct ath_ani { bool caldone; unsigned int longcal_timer; unsigned int shortcal_timer; unsigned int resetcal_timer; unsigned int checkani_timer; struct timer_list timer; }; struct ath_cycle_counters { u32 cycles; u32 rx_busy; u32 rx_frame; u32 tx_frame; }; enum ath_device_state { ATH_HW_UNAVAILABLE, ATH_HW_INITIALIZED, }; enum ath_op_flags { ATH_OP_INVALID, ATH_OP_BEACONS, ATH_OP_ANI_RUN, ATH_OP_PRIM_STA_VIF, ATH_OP_HW_RESET, ATH_OP_SCANNING, ATH_OP_MULTI_CHANNEL, ATH_OP_WOW_ENABLED, }; enum ath_bus_type { ATH_PCI, ATH_AHB, ATH_USB, }; struct reg_dmn_pair_mapping { u16 reg_domain; u16 reg_5ghz_ctl; u16 reg_2ghz_ctl; }; struct ath_regulatory { char alpha2[2]; enum nl80211_dfs_regions region; u16 country_code; u16 max_power_level; u16 current_rd; int16_t power_limit; struct reg_dmn_pair_mapping *regpair; }; enum ath_crypt_caps { ATH_CRYPT_CAP_CIPHER_AESCCM = BIT(0), ATH_CRYPT_CAP_MIC_COMBINED = BIT(1), }; struct ath_keyval { u8 kv_type; u8 kv_pad; u16 kv_len; - u8 kv_val[16]; /* TK */ - u8 kv_mic[8]; /* Michael MIC key */ - u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware - * supports both MIC keys in the same key cache entry; - * in that case, kv_mic is the RX key) */ + struct_group(kv_values, + u8 kv_val[16]; /* TK */ + u8 kv_mic[8]; /* Michael MIC key */ + u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware + * supports both MIC keys in the same key cache entry; + * in that case, kv_mic is the RX key) */ + ); }; enum ath_cipher { ATH_CIPHER_WEP = 0, ATH_CIPHER_AES_OCB = 1, ATH_CIPHER_AES_CCM = 2, ATH_CIPHER_CKIP = 3, ATH_CIPHER_TKIP = 4, ATH_CIPHER_CLR = 5, ATH_CIPHER_MIC = 127 }; /** * struct ath_ops - Register read/write operations * * @read: Register read * @multi_read: Multiple register read * @write: Register write * @enable_write_buffer: Enable multiple register writes * @write_flush: flush buffered register writes and disable buffering */ struct ath_ops { unsigned int (*read)(void *, u32 reg_offset); void (*multi_read)(void *, u32 *addr, u32 *val, u16 count); void (*write)(void *, u32 val, u32 reg_offset); void (*enable_write_buffer)(void *); void (*write_flush) (void *); u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr); void (*enable_rmw_buffer)(void *); void (*rmw_flush) (void *); }; struct ath_common; struct ath_bus_ops; struct ath_ps_ops { void (*wakeup)(struct ath_common *common); void (*restore)(struct ath_common *common); }; struct ath_common { void *ah; void *priv; struct ieee80211_hw *hw; int debug_mask; enum ath_device_state state; unsigned long op_flags; struct ath_ani ani; u16 cachelsz; u16 curaid; u8 macaddr[ETH_ALEN]; u8 curbssid[ETH_ALEN] __aligned(2); u8 bssidmask[ETH_ALEN]; u32 rx_bufsize; u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX); enum ath_crypt_caps crypt_caps; unsigned int clockrate; spinlock_t cc_lock; struct ath_cycle_counters cc_ani; struct ath_cycle_counters cc_survey; struct ath_regulatory regulatory; struct ath_regulatory reg_world_copy; const struct ath_ops *ops; const struct ath_bus_ops *bus_ops; const struct ath_ps_ops *ps_ops; bool btcoex_enabled; bool disable_ani; bool bt_ant_diversity; int last_rssi; struct ieee80211_supported_band sbands[NUM_NL80211_BANDS]; }; static inline const struct ath_ps_ops *ath_ps_ops(struct ath_common *common) { return common->ps_ops; } struct sk_buff *ath_rxbuf_alloc(struct ath_common *common, u32 len, gfp_t gfp_mask); bool ath_is_mybeacon(struct ath_common *common, struct ieee80211_hdr *hdr); void ath_hw_setbssidmask(struct ath_common *common); void ath_key_delete(struct ath_common *common, u8 hw_key_idx); int ath_key_config(struct ath_common *common, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); bool ath_hw_keyreset(struct ath_common *common, u16 entry); bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac); void ath_hw_cycle_counters_update(struct ath_common *common); int32_t ath_hw_get_listen_time(struct ath_common *common); __printf(3, 4) void ath_printk(const char *level, const struct ath_common *common, const char *fmt, ...); #define ath_emerg(common, fmt, ...) \ ath_printk(KERN_EMERG, common, fmt, ##__VA_ARGS__) #define ath_alert(common, fmt, ...) \ ath_printk(KERN_ALERT, common, fmt, ##__VA_ARGS__) #define ath_crit(common, fmt, ...) \ ath_printk(KERN_CRIT, common, fmt, ##__VA_ARGS__) #define ath_err(common, fmt, ...) \ ath_printk(KERN_ERR, common, fmt, ##__VA_ARGS__) #define ath_warn(common, fmt, ...) \ ath_printk(KERN_WARNING, common, fmt, ##__VA_ARGS__) #define ath_notice(common, fmt, ...) \ ath_printk(KERN_NOTICE, common, fmt, ##__VA_ARGS__) #define ath_info(common, fmt, ...) \ ath_printk(KERN_INFO, common, fmt, ##__VA_ARGS__) /** * enum ath_debug_level - atheros wireless debug level * * @ATH_DBG_RESET: reset processing * @ATH_DBG_QUEUE: hardware queue management * @ATH_DBG_EEPROM: eeprom processing * @ATH_DBG_CALIBRATE: periodic calibration * @ATH_DBG_INTERRUPT: interrupt processing * @ATH_DBG_REGULATORY: regulatory processing * @ATH_DBG_ANI: adaptive noise immunitive processing * @ATH_DBG_XMIT: basic xmit operation * @ATH_DBG_BEACON: beacon handling * @ATH_DBG_CONFIG: configuration of the hardware * @ATH_DBG_FATAL: fatal errors, this is the default, DBG_DEFAULT * @ATH_DBG_PS: power save processing * @ATH_DBG_HWTIMER: hardware timer handling * @ATH_DBG_BTCOEX: bluetooth coexistance * @ATH_DBG_BSTUCK: stuck beacons * @ATH_DBG_MCI: Message Coexistence Interface, a private protocol * used exclusively for WLAN-BT coexistence starting from * AR9462. * @ATH_DBG_DFS: radar datection * @ATH_DBG_WOW: Wake on Wireless * @ATH_DBG_DYNACK: dynack handling * @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan * @ATH_DBG_ANY: enable all debugging * * The debug level is used to control the amount and type of debugging output * we want to see. Each driver has its own method for enabling debugging and * modifying debug level states -- but this is typically done through a * module parameter 'debug' along with a respective 'debug' debugfs file * entry. */ enum ATH_DEBUG { ATH_DBG_RESET = 0x00000001, ATH_DBG_QUEUE = 0x00000002, ATH_DBG_EEPROM = 0x00000004, ATH_DBG_CALIBRATE = 0x00000008, ATH_DBG_INTERRUPT = 0x00000010, ATH_DBG_REGULATORY = 0x00000020, ATH_DBG_ANI = 0x00000040, ATH_DBG_XMIT = 0x00000080, ATH_DBG_BEACON = 0x00000100, ATH_DBG_CONFIG = 0x00000200, ATH_DBG_FATAL = 0x00000400, ATH_DBG_PS = 0x00000800, ATH_DBG_BTCOEX = 0x00001000, ATH_DBG_WMI = 0x00002000, ATH_DBG_BSTUCK = 0x00004000, ATH_DBG_MCI = 0x00008000, ATH_DBG_DFS = 0x00010000, ATH_DBG_WOW = 0x00020000, ATH_DBG_CHAN_CTX = 0x00040000, ATH_DBG_DYNACK = 0x00080000, ATH_DBG_SPECTRAL_SCAN = 0x00100000, ATH_DBG_ANY = 0xffffffff }; #define ATH_DBG_DEFAULT (ATH_DBG_FATAL) #define ATH_DBG_MAX_LEN 512 #ifdef CONFIG_ATH_DEBUG #define ath_dbg(common, dbg_mask, fmt, ...) \ do { \ if ((common)->debug_mask & ATH_DBG_##dbg_mask) \ ath_printk(KERN_DEBUG, common, fmt, ##__VA_ARGS__); \ } while (0) #define ATH_DBG_WARN(foo, arg...) WARN(foo, arg) #define ATH_DBG_WARN_ON_ONCE(foo) WARN_ON_ONCE(foo) #else static inline __attribute__ ((format (printf, 3, 4))) void _ath_dbg(struct ath_common *common, enum ATH_DEBUG dbg_mask, const char *fmt, ...) { } #define ath_dbg(common, dbg_mask, fmt, ...) \ _ath_dbg(common, ATH_DBG_##dbg_mask, fmt, ##__VA_ARGS__) #define ATH_DBG_WARN(foo, arg...) do {} while (0) #define ATH_DBG_WARN_ON_ONCE(foo) ({ \ int __ret_warn_once = !!(foo); \ unlikely(__ret_warn_once); \ }) #endif /* CONFIG_ATH_DEBUG */ /** Returns string describing opmode, or NULL if unknown mode. */ #ifdef CONFIG_ATH_DEBUG const char *ath_opmode_to_string(enum nl80211_iftype opmode); #else static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) { return "UNKNOWN"; } #endif extern const char *ath_bus_type_strings[]; static inline const char *ath_bus_type_to_string(enum ath_bus_type bustype) { return ath_bus_type_strings[bustype]; } #endif /* ATH_H */ diff --git a/sys/contrib/dev/athk/hw.c b/sys/contrib/dev/athk/hw.c index b53ebb3ac9a2..85955572a705 100644 --- a/sys/contrib/dev/athk/hw.c +++ b/sys/contrib/dev/athk/hw.c @@ -1,190 +1,190 @@ /* * Copyright (c) 2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "ath.h" #include "reg.h" #define REG_READ (common->ops->read) #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) /** * ath_hw_setbssidmask - filter out bssids we listen * * @common: the ath_common struct for the device. * * BSSID masking is a method used by AR5212 and newer hardware to inform PCU * which bits of the interface's MAC address should be looked at when trying * to decide which packets to ACK. In station mode and AP mode with a single * BSS every bit matters since we lock to only one BSS. In AP mode with * multiple BSSes (virtual interfaces) not every bit matters because hw must * accept frames for all BSSes and so we tweak some bits of our mac address * in order to have multiple BSSes. * * NOTE: This is a simple filter and does *not* filter out all * relevant frames. Some frames that are not for us might get ACKed from us * by PCU because they just match the mask. * * When handling multiple BSSes you can get the BSSID mask by computing the * set of ~ ( MAC XOR BSSID ) for all bssids we handle. * * When you do this you are essentially computing the common bits of all your * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with * the MAC address to obtain the relevant bits and compare the result with * (frame's BSSID & mask) to see if they match. * - * Simple example: on your card you have have two BSSes you have created with + * Simple example: on your card you have two BSSes you have created with * BSSID-01 and BSSID-02. Lets assume BSSID-01 will not use the MAC address. * There is another BSSID-03 but you are not part of it. For simplicity's sake, * assuming only 4 bits for a mac address and for BSSIDs you can then have: * * \ * MAC: 0001 | * BSSID-01: 0100 | --> Belongs to us * BSSID-02: 1001 | * / * ------------------- * BSSID-03: 0110 | --> External * ------------------- * * Our bssid_mask would then be: * * On loop iteration for BSSID-01: * ~(0001 ^ 0100) -> ~(0101) * -> 1010 * bssid_mask = 1010 * * On loop iteration for BSSID-02: * bssid_mask &= ~(0001 ^ 1001) * bssid_mask = (1010) & ~(0001 ^ 1001) * bssid_mask = (1010) & ~(1000) * bssid_mask = (1010) & (0111) * bssid_mask = 0010 * * A bssid_mask of 0010 means "only pay attention to the second least * significant bit". This is because its the only bit common * amongst the MAC and all BSSIDs we support. To findout what the real * common bit is we can simply "&" the bssid_mask now with any BSSID we have * or our MAC address (we assume the hardware uses the MAC address). * * Now, suppose there's an incoming frame for BSSID-03: * * IFRAME-01: 0110 * * An easy eye-inspeciton of this already should tell you that this frame * will not pass our check. This is because the bssid_mask tells the * hardware to only look at the second least significant bit and the * common bit amongst the MAC and BSSIDs is 0, this frame has the 2nd LSB * as 1, which does not match 0. * * So with IFRAME-01 we *assume* the hardware will do: * * allow = (IFRAME-01 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; * --> allow = (0110 & 0010) == (0010 & 0001) ? 1 : 0; * --> allow = (0010) == 0000 ? 1 : 0; * --> allow = 0 * * Lets now test a frame that should work: * * IFRAME-02: 0001 (we should allow) * * allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0; * --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0; * --> allow = (0000) == (0000) * --> allow = 1 * * Other examples: * * IFRAME-03: 0100 --> allowed * IFRAME-04: 1001 --> allowed * IFRAME-05: 1101 --> allowed but its not for us!!! * */ void ath_hw_setbssidmask(struct ath_common *common) { void *ah = common->ah; u32 id1; REG_WRITE(ah, AR_STA_ID0, get_unaligned_le32(common->macaddr)); id1 = REG_READ(ah, AR_STA_ID1) & ~AR_STA_ID1_SADH_MASK; id1 |= get_unaligned_le16(common->macaddr + 4); REG_WRITE(ah, AR_STA_ID1, id1); REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(common->bssidmask)); REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(common->bssidmask + 4)); } EXPORT_SYMBOL(ath_hw_setbssidmask); /** * ath_hw_cycle_counters_update - common function to update cycle counters * * @common: the ath_common struct for the device. * * This function is used to update all cycle counters in one place. * It has to be called while holding common->cc_lock! */ void ath_hw_cycle_counters_update(struct ath_common *common) { u32 cycles, busy, rx, tx; void *ah = common->ah; /* freeze */ REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC); /* read */ cycles = REG_READ(ah, AR_CCCNT); busy = REG_READ(ah, AR_RCCNT); rx = REG_READ(ah, AR_RFCNT); tx = REG_READ(ah, AR_TFCNT); /* clear */ REG_WRITE(ah, AR_CCCNT, 0); REG_WRITE(ah, AR_RFCNT, 0); REG_WRITE(ah, AR_RCCNT, 0); REG_WRITE(ah, AR_TFCNT, 0); /* unfreeze */ REG_WRITE(ah, AR_MIBC, 0); /* update all cycle counters here */ common->cc_ani.cycles += cycles; common->cc_ani.rx_busy += busy; common->cc_ani.rx_frame += rx; common->cc_ani.tx_frame += tx; common->cc_survey.cycles += cycles; common->cc_survey.rx_busy += busy; common->cc_survey.rx_frame += rx; common->cc_survey.tx_frame += tx; } EXPORT_SYMBOL(ath_hw_cycle_counters_update); int32_t ath_hw_get_listen_time(struct ath_common *common) { struct ath_cycle_counters *cc = &common->cc_ani; int32_t listen_time; listen_time = (cc->cycles - cc->rx_frame - cc->tx_frame) / (common->clockrate * 1000); memset(cc, 0, sizeof(*cc)); return listen_time; } EXPORT_SYMBOL(ath_hw_get_listen_time); diff --git a/sys/contrib/dev/athk/key.c b/sys/contrib/dev/athk/key.c index 61b59a804e30..b7b61d4f02ba 100644 --- a/sys/contrib/dev/athk/key.c +++ b/sys/contrib/dev/athk/key.c @@ -1,618 +1,618 @@ /* * Copyright (c) 2009 Atheros Communications Inc. * Copyright (c) 2010 Bruno Randolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "ath.h" #include "reg.h" #define REG_READ (common->ops->read) #define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg) #define ENABLE_REGWRITE_BUFFER(_ah) \ if (common->ops->enable_write_buffer) \ common->ops->enable_write_buffer((_ah)); #define REGWRITE_BUFFER_FLUSH(_ah) \ if (common->ops->write_flush) \ common->ops->write_flush((_ah)); #define IEEE80211_WEP_NKID 4 /* number of key ids */ /************************/ /* Key Cache Management */ /************************/ bool ath_hw_keyreset(struct ath_common *common, u16 entry) { u32 keyType; void *ah = common->ah; if (entry >= common->keymax) { ath_err(common, "keyreset: keycache entry %u out of range\n", entry); return false; } keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); if (keyType == AR_KEYTABLE_TYPE_TKIP) { u16 micentry = entry + 64; REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); } } REGWRITE_BUFFER_FLUSH(ah); return true; } EXPORT_SYMBOL(ath_hw_keyreset); bool ath_hw_keysetmac(struct ath_common *common, u16 entry, const u8 *mac) { u32 macHi, macLo; u32 unicast_flag = AR_KEYTABLE_VALID; void *ah = common->ah; if (entry >= common->keymax) { ath_err(common, "keysetmac: keycache entry %u out of range\n", entry); return false; } if (mac != NULL) { /* * AR_KEYTABLE_VALID indicates that the address is a unicast * address, which must match the transmitter address for * decrypting frames. * Not setting this bit allows the hardware to use the key * for multicast frame decryption. */ if (mac[0] & 0x01) unicast_flag = 0; macLo = get_unaligned_le32(mac); macHi = get_unaligned_le16(mac + 4); macLo >>= 1; macLo |= (macHi & 1) << 31; macHi >>= 1; } else { macLo = macHi = 0; } ENABLE_REGWRITE_BUFFER(ah); REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag); REGWRITE_BUFFER_FLUSH(ah); return true; } EXPORT_SYMBOL(ath_hw_keysetmac); static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry, const struct ath_keyval *k, const u8 *mac) { void *ah = common->ah; u32 key0, key1, key2, key3, key4; u32 keyType; if (entry >= common->keymax) { ath_err(common, "set-entry: keycache entry %u out of range\n", entry); return false; } switch (k->kv_type) { case ATH_CIPHER_AES_OCB: keyType = AR_KEYTABLE_TYPE_AES; break; case ATH_CIPHER_AES_CCM: if (!(common->crypt_caps & ATH_CRYPT_CAP_CIPHER_AESCCM)) { ath_dbg(common, ANY, "AES-CCM not supported by this mac rev\n"); return false; } keyType = AR_KEYTABLE_TYPE_CCM; break; case ATH_CIPHER_TKIP: keyType = AR_KEYTABLE_TYPE_TKIP; if (entry + 64 >= common->keymax) { ath_dbg(common, ANY, "entry %u inappropriate for TKIP\n", entry); return false; } break; case ATH_CIPHER_WEP: if (k->kv_len < WLAN_KEY_LEN_WEP40) { ath_dbg(common, ANY, "WEP key length %u too small\n", k->kv_len); return false; } if (k->kv_len <= WLAN_KEY_LEN_WEP40) keyType = AR_KEYTABLE_TYPE_40; else if (k->kv_len <= WLAN_KEY_LEN_WEP104) keyType = AR_KEYTABLE_TYPE_104; else keyType = AR_KEYTABLE_TYPE_128; break; case ATH_CIPHER_CLR: keyType = AR_KEYTABLE_TYPE_CLR; break; default: ath_err(common, "cipher %u not supported\n", k->kv_type); return false; } key0 = get_unaligned_le32(k->kv_val + 0); key1 = get_unaligned_le16(k->kv_val + 4); key2 = get_unaligned_le32(k->kv_val + 6); key3 = get_unaligned_le16(k->kv_val + 10); key4 = get_unaligned_le32(k->kv_val + 12); if (k->kv_len <= WLAN_KEY_LEN_WEP104) key4 &= 0xff; /* * Note: Key cache registers access special memory area that requires * two 32-bit writes to actually update the values in the internal * memory. Consequently, the exact order and pairs used here must be * maintained. */ if (keyType == AR_KEYTABLE_TYPE_TKIP) { u16 micentry = entry + 64; /* * Write inverted key[47:0] first to avoid Michael MIC errors * on frames that could be sent or received at the same time. * The correct key will be written in the end once everything * else is ready. */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); /* Write key[95:48] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); /* Write key[127:96] and key type */ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { /* * TKIP uses two key cache entries: * Michael MIC TX/RX keys in the same key cache entry * (idx = main index + 64): * key0 [31:0] = RX key [31:0] * key1 [15:0] = TX key [31:16] * key1 [31:16] = reserved * key2 [31:0] = RX key [63:32] * key3 [15:0] = TX key [15:0] * key3 [31:16] = reserved * key4 [31:0] = TX key [63:32] */ u32 mic0, mic1, mic2, mic3, mic4; mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; mic4 = get_unaligned_le32(k->kv_txmic + 4); ENABLE_REGWRITE_BUFFER(ah); /* Write RX[31:0] and TX[31:16] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); /* Write RX[63:32] and TX[15:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); /* Write TX[63:32] and keyType(reserved) */ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); REGWRITE_BUFFER_FLUSH(ah); } else { /* * TKIP uses four key cache entries (two for group * keys): * Michael MIC TX/RX keys are in different key cache * entries (idx = main index + 64 for TX and * main index + 32 + 96 for RX): * key0 [31:0] = TX/RX MIC key [31:0] * key1 [31:0] = reserved * key2 [31:0] = TX/RX MIC key [63:32] * key3 [31:0] = reserved * key4 [31:0] = reserved * * Upper layer code will call this function separately * for TX and RX keys when these registers offsets are * used. */ u32 mic0, mic2; mic0 = get_unaligned_le32(k->kv_mic + 0); mic2 = get_unaligned_le32(k->kv_mic + 4); ENABLE_REGWRITE_BUFFER(ah); /* Write MIC key[31:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); /* Write MIC key[63:32] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); /* Write TX[63:32] and keyType(reserved) */ REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), AR_KEYTABLE_TYPE_CLR); REGWRITE_BUFFER_FLUSH(ah); } ENABLE_REGWRITE_BUFFER(ah); /* MAC address registers are reserved for the MIC entry */ REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); /* * Write the correct (un-inverted) key[47:0] last to enable * TKIP now that all other registers are set with correct * values. */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); REGWRITE_BUFFER_FLUSH(ah); } else { ENABLE_REGWRITE_BUFFER(ah); /* Write key[47:0] */ REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); /* Write key[95:48] */ REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); /* Write key[127:96] and key type */ REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); REGWRITE_BUFFER_FLUSH(ah); /* Write MAC address for the entry */ (void) ath_hw_keysetmac(common, entry, mac); } return true; } static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key, struct ath_keyval *hk, const u8 *addr, bool authenticator) { const u8 *key_rxmic; const u8 *key_txmic; key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; if (addr == NULL) { /* * Group key installation - only two key cache entries are used * regardless of splitmic capability since group key is only * used either for TX or RX. */ if (authenticator) { memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic)); } else { memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic)); } return ath_hw_set_keycache_entry(common, keyix, hk, addr); } if (common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) { /* TX and RX keys share the same key cache entry. */ memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); return ath_hw_set_keycache_entry(common, keyix, hk, addr); } /* Separate key cache entries for TX and RX */ /* TX key goes at first index, RX key at +32. */ memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); if (!ath_hw_set_keycache_entry(common, keyix, hk, NULL)) { /* TX MIC entry failed. No need to proceed further */ ath_err(common, "Setting TX MIC Key Failed\n"); return 0; } memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); /* XXX delete tx key on failure? */ return ath_hw_set_keycache_entry(common, keyix + 32, hk, addr); } static int ath_reserve_key_cache_slot_tkip(struct ath_common *common) { int i; for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { if (test_bit(i, common->keymap) || test_bit(i + 64, common->keymap)) continue; /* At least one part of TKIP key allocated */ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED) && (test_bit(i + 32, common->keymap) || test_bit(i + 64 + 32, common->keymap))) continue; /* At least one part of TKIP key allocated */ /* Found a free slot for a TKIP key */ return i; } return -1; } static int ath_reserve_key_cache_slot(struct ath_common *common, u32 cipher) { int i; if (cipher == WLAN_CIPHER_SUITE_TKIP) return ath_reserve_key_cache_slot_tkip(common); /* First, try to find slots that would not be available for TKIP. */ if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) { if (!test_bit(i, common->keymap) && (test_bit(i + 32, common->keymap) || test_bit(i + 64, common->keymap) || test_bit(i + 64 + 32, common->keymap))) return i; if (!test_bit(i + 32, common->keymap) && (test_bit(i, common->keymap) || test_bit(i + 64, common->keymap) || test_bit(i + 64 + 32, common->keymap))) return i + 32; if (!test_bit(i + 64, common->keymap) && (test_bit(i , common->keymap) || test_bit(i + 32, common->keymap) || test_bit(i + 64 + 32, common->keymap))) return i + 64; if (!test_bit(i + 64 + 32, common->keymap) && (test_bit(i, common->keymap) || test_bit(i + 32, common->keymap) || test_bit(i + 64, common->keymap))) return i + 64 + 32; } } else { for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) { if (!test_bit(i, common->keymap) && test_bit(i + 64, common->keymap)) return i; if (test_bit(i, common->keymap) && !test_bit(i + 64, common->keymap)) return i + 64; } } /* No partially used TKIP slots, pick any available slot */ for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) { /* Do not allow slots that could be needed for TKIP group keys * to be used. This limitation could be removed if we know that * TKIP will not be used. */ if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) continue; if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) continue; if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) continue; } if (!test_bit(i, common->keymap)) return i; /* Found a free slot for a key */ } /* No free slot found */ return -1; } /* * Configure encryption in the HW. */ int ath_key_config(struct ath_common *common, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) { struct ath_keyval hk; const u8 *mac = NULL; u8 gmac[ETH_ALEN]; int ret = 0; int idx; memset(&hk, 0, sizeof(hk)); switch (key->cipher) { case 0: hk.kv_type = ATH_CIPHER_CLR; break; case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: hk.kv_type = ATH_CIPHER_WEP; break; case WLAN_CIPHER_SUITE_TKIP: hk.kv_type = ATH_CIPHER_TKIP; break; case WLAN_CIPHER_SUITE_CCMP: hk.kv_type = ATH_CIPHER_AES_CCM; break; default: return -EOPNOTSUPP; } hk.kv_len = key->keylen; if (key->keylen) - memcpy(hk.kv_val, key->key, key->keylen); + memcpy(&hk.kv_values, key->key, key->keylen); if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { switch (vif->type) { case NL80211_IFTYPE_AP: memcpy(gmac, vif->addr, ETH_ALEN); gmac[0] |= 0x01; mac = gmac; idx = ath_reserve_key_cache_slot(common, key->cipher); break; case NL80211_IFTYPE_ADHOC: if (!sta) { idx = key->keyidx; break; } memcpy(gmac, sta->addr, ETH_ALEN); gmac[0] |= 0x01; mac = gmac; idx = ath_reserve_key_cache_slot(common, key->cipher); break; default: idx = key->keyidx; break; } } else if (key->keyidx) { if (WARN_ON(!sta)) return -EOPNOTSUPP; mac = sta->addr; if (vif->type != NL80211_IFTYPE_AP) { /* Only keyidx 0 should be used with unicast key, but * allow this for client mode for now. */ idx = key->keyidx; } else return -EIO; } else { if (WARN_ON(!sta)) return -EOPNOTSUPP; mac = sta->addr; idx = ath_reserve_key_cache_slot(common, key->cipher); } if (idx < 0) return -ENOSPC; /* no free key cache entries */ if (key->cipher == WLAN_CIPHER_SUITE_TKIP) ret = ath_setkey_tkip(common, idx, key->key, &hk, mac, vif->type == NL80211_IFTYPE_AP); else ret = ath_hw_set_keycache_entry(common, idx, &hk, mac); if (!ret) return -EIO; set_bit(idx, common->keymap); if (key->cipher == WLAN_CIPHER_SUITE_CCMP) set_bit(idx, common->ccmp_keymap); if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { set_bit(idx + 64, common->keymap); set_bit(idx, common->tkip_keymap); set_bit(idx + 64, common->tkip_keymap); if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { set_bit(idx + 32, common->keymap); set_bit(idx + 64 + 32, common->keymap); set_bit(idx + 32, common->tkip_keymap); set_bit(idx + 64 + 32, common->tkip_keymap); } } return idx; } EXPORT_SYMBOL(ath_key_config); /* * Delete Key. */ void ath_key_delete(struct ath_common *common, u8 hw_key_idx) { /* Leave CCMP and TKIP (main key) configured to avoid disabling * encryption for potentially pending frames already in a TXQ with the * keyix pointing to this key entry. Instead, only clear the MAC address * to prevent RX processing from using this key cache entry. */ if (test_bit(hw_key_idx, common->ccmp_keymap) || test_bit(hw_key_idx, common->tkip_keymap)) ath_hw_keysetmac(common, hw_key_idx, NULL); else ath_hw_keyreset(common, hw_key_idx); if (hw_key_idx < IEEE80211_WEP_NKID) return; clear_bit(hw_key_idx, common->keymap); clear_bit(hw_key_idx, common->ccmp_keymap); if (!test_bit(hw_key_idx, common->tkip_keymap)) return; clear_bit(hw_key_idx + 64, common->keymap); clear_bit(hw_key_idx, common->tkip_keymap); clear_bit(hw_key_idx + 64, common->tkip_keymap); if (!(common->crypt_caps & ATH_CRYPT_CAP_MIC_COMBINED)) { ath_hw_keyreset(common, hw_key_idx + 32); clear_bit(hw_key_idx + 32, common->keymap); clear_bit(hw_key_idx + 64 + 32, common->keymap); clear_bit(hw_key_idx + 32, common->tkip_keymap); clear_bit(hw_key_idx + 64 + 32, common->tkip_keymap); } } EXPORT_SYMBOL(ath_key_delete); diff --git a/sys/contrib/dev/athk/regd.c b/sys/contrib/dev/athk/regd.c index b2400e2417a5..f15e7bd690b5 100644 --- a/sys/contrib/dev/athk/regd.c +++ b/sys/contrib/dev/athk/regd.c @@ -1,812 +1,812 @@ /* * Copyright (c) 2008-2009 Atheros Communications Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include "regd.h" #include "regd_common.h" static int __ath_regd_init(struct ath_regulatory *reg); /* * This is a set of common rules used by our world regulatory domains. * We have 12 world regulatory domains. To save space we consolidate * the regulatory domains in 5 structures by frequency and change * the flags on our reg_notifier() on a case by case basis. */ /* Only these channels all allow active scan on all world regulatory domains */ #define ATH_2GHZ_CH01_11 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) /* We enable active scan on these a case by case basis by regulatory domain */ #define ATH_2GHZ_CH12_13 REG_RULE(2467-10, 2472+10, 40, 0, 20,\ NL80211_RRF_NO_IR) #define ATH_2GHZ_CH14 REG_RULE(2484-10, 2484+10, 40, 0, 20,\ NL80211_RRF_NO_IR | \ NL80211_RRF_NO_OFDM) /* We allow IBSS on these on a case by case basis by regulatory domain */ #define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ NL80211_RRF_NO_IR) #define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ NL80211_RRF_NO_IR) #define ATH_5GHZ_5725_5850 REG_RULE(5725-10, 5850+10, 80, 0, 30,\ NL80211_RRF_NO_IR) #define ATH_2GHZ_ALL ATH_2GHZ_CH01_11, \ ATH_2GHZ_CH12_13, \ ATH_2GHZ_CH14 #define ATH_5GHZ_ALL ATH_5GHZ_5150_5350, \ ATH_5GHZ_5470_5850 /* This one skips what we call "mid band" */ #define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \ ATH_5GHZ_5725_5850 /* Can be used for: * 0x60, 0x61, 0x62 */ static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { .n_reg_rules = 5, .alpha2 = "99", .reg_rules = { ATH_2GHZ_ALL, ATH_5GHZ_ALL, } }; /* Can be used by 0x63 and 0x65 */ static const struct ieee80211_regdomain ath_world_regdom_63_65 = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { ATH_2GHZ_CH01_11, ATH_2GHZ_CH12_13, ATH_5GHZ_NO_MIDBAND, } }; /* Can be used by 0x64 only */ static const struct ieee80211_regdomain ath_world_regdom_64 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { ATH_2GHZ_CH01_11, ATH_5GHZ_NO_MIDBAND, } }; /* Can be used by 0x66 and 0x69 */ static const struct ieee80211_regdomain ath_world_regdom_66_69 = { .n_reg_rules = 3, .alpha2 = "99", .reg_rules = { ATH_2GHZ_CH01_11, ATH_5GHZ_ALL, } }; /* Can be used by 0x67, 0x68, 0x6A and 0x6C */ static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { .n_reg_rules = 4, .alpha2 = "99", .reg_rules = { ATH_2GHZ_CH01_11, ATH_2GHZ_CH12_13, ATH_5GHZ_ALL, } }; static bool dynamic_country_user_possible(struct ath_regulatory *reg) { if (IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) return true; switch (reg->country_code) { case CTRY_UNITED_STATES: case CTRY_JAPAN1: case CTRY_JAPAN2: case CTRY_JAPAN3: case CTRY_JAPAN4: case CTRY_JAPAN5: case CTRY_JAPAN6: case CTRY_JAPAN7: case CTRY_JAPAN8: case CTRY_JAPAN9: case CTRY_JAPAN10: case CTRY_JAPAN11: case CTRY_JAPAN12: case CTRY_JAPAN13: case CTRY_JAPAN14: case CTRY_JAPAN15: case CTRY_JAPAN16: case CTRY_JAPAN17: case CTRY_JAPAN18: case CTRY_JAPAN19: case CTRY_JAPAN20: case CTRY_JAPAN21: case CTRY_JAPAN22: case CTRY_JAPAN23: case CTRY_JAPAN24: case CTRY_JAPAN25: case CTRY_JAPAN26: case CTRY_JAPAN27: case CTRY_JAPAN28: case CTRY_JAPAN29: case CTRY_JAPAN30: case CTRY_JAPAN31: case CTRY_JAPAN32: case CTRY_JAPAN33: case CTRY_JAPAN34: case CTRY_JAPAN35: case CTRY_JAPAN36: case CTRY_JAPAN37: case CTRY_JAPAN38: case CTRY_JAPAN39: case CTRY_JAPAN40: case CTRY_JAPAN41: case CTRY_JAPAN42: case CTRY_JAPAN43: case CTRY_JAPAN44: case CTRY_JAPAN45: case CTRY_JAPAN46: case CTRY_JAPAN47: case CTRY_JAPAN48: case CTRY_JAPAN49: case CTRY_JAPAN50: case CTRY_JAPAN51: case CTRY_JAPAN52: case CTRY_JAPAN53: case CTRY_JAPAN54: case CTRY_JAPAN55: case CTRY_JAPAN56: case CTRY_JAPAN57: case CTRY_JAPAN58: case CTRY_JAPAN59: return false; } return true; } static bool ath_reg_dyn_country_user_allow(struct ath_regulatory *reg) { if (!IS_ENABLED(CONFIG_ATH_REG_DYNAMIC_USER_REG_HINTS)) return false; if (!dynamic_country_user_possible(reg)) return false; return true; } static inline bool is_wwr_sku(u16 regd) { return ((regd & COUNTRY_ERD_FLAG) != COUNTRY_ERD_FLAG) && (((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) || (regd == WORLD)); } static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) { return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; } bool ath_is_world_regd(struct ath_regulatory *reg) { return is_wwr_sku(ath_regd_get_eepromRD(reg)); } EXPORT_SYMBOL(ath_is_world_regd); static const struct ieee80211_regdomain *ath_default_world_regdomain(void) { /* this is the most restrictive */ return &ath_world_regdom_64; } static const struct ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg) { switch (reg->regpair->reg_domain) { case 0x60: case 0x61: case 0x62: return &ath_world_regdom_60_61_62; case 0x63: case 0x65: return &ath_world_regdom_63_65; case 0x64: return &ath_world_regdom_64; case 0x66: case 0x69: return &ath_world_regdom_66_69; case 0x67: case 0x68: case 0x6A: case 0x6C: return &ath_world_regdom_67_68_6A_6C; default: WARN_ON(1); return ath_default_world_regdomain(); } } bool ath_is_49ghz_allowed(u16 regdomain) { /* possibly more */ return regdomain == MKK9_MKKC; } EXPORT_SYMBOL(ath_is_49ghz_allowed); /* Frequency is one where radar detection is required */ static bool ath_is_radar_freq(u16 center_freq, struct ath_regulatory *reg) { if (reg->country_code == CTRY_INDIA) return (center_freq >= 5500 && center_freq <= 5700); return (center_freq >= 5260 && center_freq <= 5700); } static void ath_force_clear_no_ir_chan(struct wiphy *wiphy, struct ieee80211_channel *ch) { const struct ieee80211_reg_rule *reg_rule; reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(ch->center_freq)); if (IS_ERR(reg_rule)) return; if (!(reg_rule->flags & NL80211_RRF_NO_IR)) if (ch->flags & IEEE80211_CHAN_NO_IR) ch->flags &= ~IEEE80211_CHAN_NO_IR; } static void ath_force_clear_no_ir_freq(struct wiphy *wiphy, u16 center_freq) { struct ieee80211_channel *ch; ch = ieee80211_get_channel(wiphy, center_freq); if (!ch) return; ath_force_clear_no_ir_chan(wiphy, ch); } static void ath_force_no_ir_chan(struct ieee80211_channel *ch) { ch->flags |= IEEE80211_CHAN_NO_IR; } static void ath_force_no_ir_freq(struct wiphy *wiphy, u16 center_freq) { struct ieee80211_channel *ch; ch = ieee80211_get_channel(wiphy, center_freq); if (!ch) return; ath_force_no_ir_chan(ch); } static void __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, struct ath_regulatory *reg, enum nl80211_reg_initiator initiator, struct ieee80211_channel *ch) { if (ath_is_radar_freq(ch->center_freq, reg) || (ch->flags & IEEE80211_CHAN_RADAR)) return; switch (initiator) { case NL80211_REGDOM_SET_BY_COUNTRY_IE: ath_force_clear_no_ir_chan(wiphy, ch); break; case NL80211_REGDOM_SET_BY_USER: if (ath_reg_dyn_country_user_allow(reg)) ath_force_clear_no_ir_chan(wiphy, ch); break; default: if (ch->beacon_found) ch->flags &= ~IEEE80211_CHAN_NO_IR; } } /* * These exception rules do not apply radar frequencies. * * - We enable initiating radiation if the country IE says its fine: * - If no country IE has been processed and a we determine we have * received a beacon on a channel we can enable initiating radiation. */ static void ath_reg_apply_beaconing_flags(struct wiphy *wiphy, struct ath_regulatory *reg, enum nl80211_reg_initiator initiator) { enum nl80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i; for (band = 0; band < NUM_NL80211_BANDS; band++) { if (!wiphy->bands[band]) continue; sband = wiphy->bands[band]; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; __ath_reg_apply_beaconing_flags(wiphy, reg, initiator, ch); } } } /** * ath_reg_apply_ir_flags() * @wiphy: the wiphy to use * @reg: regulatory structure - used for country selection * @initiator: the regulatory hint initiator * * If no country IE has been received always enable passive scan * and no-ibss on these channels. This is only done for specific * regulatory SKUs. * * If a country IE has been received check its rule for this * channel first before enabling active scan. The passive scan * would have been enforced by the initial processing of our * custom regulatory domain. */ static void ath_reg_apply_ir_flags(struct wiphy *wiphy, struct ath_regulatory *reg, enum nl80211_reg_initiator initiator) { struct ieee80211_supported_band *sband; sband = wiphy->bands[NL80211_BAND_2GHZ]; if (!sband) return; switch(initiator) { case NL80211_REGDOM_SET_BY_COUNTRY_IE: ath_force_clear_no_ir_freq(wiphy, 2467); ath_force_clear_no_ir_freq(wiphy, 2472); break; case NL80211_REGDOM_SET_BY_USER: if (!ath_reg_dyn_country_user_allow(reg)) break; ath_force_clear_no_ir_freq(wiphy, 2467); ath_force_clear_no_ir_freq(wiphy, 2472); break; default: ath_force_no_ir_freq(wiphy, 2467); ath_force_no_ir_freq(wiphy, 2472); } } /* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ static void ath_reg_apply_radar_flags(struct wiphy *wiphy, struct ath_regulatory *reg) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; unsigned int i; if (!wiphy->bands[NL80211_BAND_5GHZ]) return; sband = wiphy->bands[NL80211_BAND_5GHZ]; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; if (!ath_is_radar_freq(ch->center_freq, reg)) continue; /* We always enable radar detection/DFS on this * frequency range. Additionally we also apply on * this frequency range: * - If STA mode does not yet have DFS supports disable * active scanning * - If adhoc mode does not support DFS yet then * disable adhoc in the frequency. * - If AP mode does not yet support radar detection/DFS * do not allow AP mode */ if (!(ch->flags & IEEE80211_CHAN_DISABLED)) ch->flags |= IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IR; } } static void ath_reg_apply_world_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ath_regulatory *reg) { switch (reg->regpair->reg_domain) { case 0x60: case 0x63: case 0x66: case 0x67: case 0x6C: ath_reg_apply_beaconing_flags(wiphy, reg, initiator); break; case 0x68: ath_reg_apply_beaconing_flags(wiphy, reg, initiator); ath_reg_apply_ir_flags(wiphy, reg, initiator); break; default: if (ath_reg_dyn_country_user_allow(reg)) ath_reg_apply_beaconing_flags(wiphy, reg, initiator); } } u16 ath_regd_find_country_by_name(char *alpha2) { unsigned int i; for (i = 0; i < ARRAY_SIZE(allCountries); i++) { if (!memcmp(allCountries[i].isoName, alpha2, 2)) return allCountries[i].countryCode; } return -1; } EXPORT_SYMBOL(ath_regd_find_country_by_name); static int __ath_reg_dyn_country(struct wiphy *wiphy, struct ath_regulatory *reg, struct regulatory_request *request) { u16 country_code; if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE && !ath_is_world_regd(reg)) return -EINVAL; country_code = ath_regd_find_country_by_name(request->alpha2); if (country_code == (u16) -1) return -EINVAL; reg->current_rd = COUNTRY_ERD_FLAG; reg->current_rd |= country_code; __ath_regd_init(reg); ath_reg_apply_world_flags(wiphy, request->initiator, reg); return 0; } static void ath_reg_dyn_country(struct wiphy *wiphy, struct ath_regulatory *reg, struct regulatory_request *request) { if (__ath_reg_dyn_country(wiphy, reg, request)) return; printk(KERN_DEBUG "ath: regdomain 0x%0x " "dynamically updated by %s\n", reg->current_rd, reg_initiator_name(request->initiator)); } void ath_reg_notifier_apply(struct wiphy *wiphy, struct regulatory_request *request, struct ath_regulatory *reg) { struct ath_common *common = container_of(reg, struct ath_common, regulatory); /* We always apply this */ ath_reg_apply_radar_flags(wiphy, reg); /* * This would happen when we have sent a custom regulatory request * a world regulatory domain and the scheduler hasn't yet processed * any pending requests in the queue. */ if (!request) return; reg->region = request->dfs_region; switch (request->initiator) { case NL80211_REGDOM_SET_BY_CORE: /* * If common->reg_world_copy is world roaming it means we *were* * world roaming... so we now have to restore that data. */ if (!ath_is_world_regd(&common->reg_world_copy)) break; memcpy(reg, &common->reg_world_copy, sizeof(struct ath_regulatory)); break; case NL80211_REGDOM_SET_BY_DRIVER: break; case NL80211_REGDOM_SET_BY_USER: if (ath_reg_dyn_country_user_allow(reg)) ath_reg_dyn_country(wiphy, reg, request); break; case NL80211_REGDOM_SET_BY_COUNTRY_IE: ath_reg_dyn_country(wiphy, reg, request); break; } } EXPORT_SYMBOL(ath_reg_notifier_apply); static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg) { u16 rd = ath_regd_get_eepromRD(reg); int i; if (rd & COUNTRY_ERD_FLAG) { /* EEPROM value is a country code */ u16 cc = rd & ~COUNTRY_ERD_FLAG; printk(KERN_DEBUG "ath: EEPROM indicates we should expect " "a country code\n"); for (i = 0; i < ARRAY_SIZE(allCountries); i++) if (allCountries[i].countryCode == cc) return true; } else { /* EEPROM value is a regpair value */ if (rd != CTRY_DEFAULT) printk(KERN_DEBUG "ath: EEPROM indicates we " "should expect a direct regpair map\n"); for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) if (regDomainPairs[i].reg_domain == rd) return true; } printk(KERN_DEBUG "ath: invalid regulatory domain/country code 0x%x\n", rd); return false; } /* EEPROM country code to regpair mapping */ static struct country_code_to_enum_rd* ath_regd_find_country(u16 countryCode) { int i; for (i = 0; i < ARRAY_SIZE(allCountries); i++) { if (allCountries[i].countryCode == countryCode) return &allCountries[i]; } return NULL; } /* EEPROM rd code to regpair mapping */ static struct country_code_to_enum_rd* ath_regd_find_country_by_rd(int regdmn) { int i; for (i = 0; i < ARRAY_SIZE(allCountries); i++) { if (allCountries[i].regDmnEnum == regdmn) return &allCountries[i]; } return NULL; } /* Returns the map of the EEPROM set RD to a country code */ static u16 ath_regd_get_default_country(u16 rd) { if (rd & COUNTRY_ERD_FLAG) { struct country_code_to_enum_rd *country = NULL; u16 cc = rd & ~COUNTRY_ERD_FLAG; country = ath_regd_find_country(cc); if (country != NULL) return cc; } return CTRY_DEFAULT; } static struct reg_dmn_pair_mapping* ath_get_regpair(int regdmn) { int i; if (regdmn == NO_ENUMRD) return NULL; for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++) { if (regDomainPairs[i].reg_domain == regdmn) return ®DomainPairs[i]; } return NULL; } static int ath_regd_init_wiphy(struct ath_regulatory *reg, struct wiphy *wiphy, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)) { const struct ieee80211_regdomain *regd; wiphy->reg_notifier = reg_notifier; wiphy->regulatory_flags |= REGULATORY_STRICT_REG | REGULATORY_CUSTOM_REG; if (ath_is_world_regd(reg)) { /* * Anything applied here (prior to wiphy registration) gets * saved on the wiphy orig_* parameters */ regd = ath_world_regdomain(reg); wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_FOLLOW_POWER; } else { /* * This gets applied in the case of the absence of CRDA, * it's our own custom world regulatory domain, similar to * cfg80211's but we enable passive scanning. */ regd = ath_default_world_regdomain(); } wiphy_apply_custom_regulatory(wiphy, regd); ath_reg_apply_radar_flags(wiphy, reg); ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); return 0; } /* * Some users have reported their EEPROM programmed with - * 0x8000 or 0x0 set, this is not a supported regulatory - * domain but since we have more than one user with it we - * need a solution for them. We default to 0x64, which is - * the default Atheros world regulatory domain. + * 0x8000 set, this is not a supported regulatory domain + * but since we have more than one user with it we need + * a solution for them. We default to 0x64, which is the + * default Atheros world regulatory domain. */ static void ath_regd_sanitize(struct ath_regulatory *reg) { - if (reg->current_rd != COUNTRY_ERD_FLAG && reg->current_rd != 0) + if (reg->current_rd != COUNTRY_ERD_FLAG) return; printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n"); reg->current_rd = 0x64; } static int __ath_regd_init(struct ath_regulatory *reg) { struct country_code_to_enum_rd *country = NULL; u16 regdmn; if (!reg) return -EINVAL; ath_regd_sanitize(reg); printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd); if (!ath_regd_is_eeprom_valid(reg)) { pr_err("Invalid EEPROM contents\n"); return -EINVAL; } regdmn = ath_regd_get_eepromRD(reg); reg->country_code = ath_regd_get_default_country(regdmn); if (reg->country_code == CTRY_DEFAULT && regdmn == CTRY_DEFAULT) { printk(KERN_DEBUG "ath: EEPROM indicates default " "country code should be used\n"); reg->country_code = CTRY_UNITED_STATES; } if (reg->country_code == CTRY_DEFAULT) { country = NULL; } else { printk(KERN_DEBUG "ath: doing EEPROM country->regdmn " "map search\n"); country = ath_regd_find_country(reg->country_code); if (country == NULL) { printk(KERN_DEBUG "ath: no valid country maps found for " "country code: 0x%0x\n", reg->country_code); return -EINVAL; } else { regdmn = country->regDmnEnum; printk(KERN_DEBUG "ath: country maps to " "regdmn code: 0x%0x\n", regdmn); } } reg->regpair = ath_get_regpair(regdmn); if (!reg->regpair) { printk(KERN_DEBUG "ath: " "No regulatory domain pair found, cannot continue\n"); return -EINVAL; } if (!country) country = ath_regd_find_country_by_rd(regdmn); if (country) { reg->alpha2[0] = country->isoName[0]; reg->alpha2[1] = country->isoName[1]; } else { reg->alpha2[0] = '0'; reg->alpha2[1] = '0'; } printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n", reg->alpha2[0], reg->alpha2[1]); printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n", reg->regpair->reg_domain); return 0; } int ath_regd_init(struct ath_regulatory *reg, struct wiphy *wiphy, void (*reg_notifier)(struct wiphy *wiphy, struct regulatory_request *request)) { struct ath_common *common = container_of(reg, struct ath_common, regulatory); int r; r = __ath_regd_init(reg); if (r) return r; if (ath_is_world_regd(reg)) memcpy(&common->reg_world_copy, reg, sizeof(struct ath_regulatory)); ath_regd_init_wiphy(reg, wiphy, reg_notifier); return 0; } EXPORT_SYMBOL(ath_regd_init); u32 ath_regd_get_band_ctl(struct ath_regulatory *reg, enum nl80211_band band) { if (!reg->regpair || (reg->country_code == CTRY_DEFAULT && is_wwr_sku(ath_regd_get_eepromRD(reg)))) { return SD_NO_CTL; } if (ath_regd_get_eepromRD(reg) == CTRY_DEFAULT) { switch (reg->region) { case NL80211_DFS_FCC: return CTL_FCC; case NL80211_DFS_ETSI: return CTL_ETSI; case NL80211_DFS_JP: return CTL_MKK; default: break; } } switch (band) { case NL80211_BAND_2GHZ: return reg->regpair->reg_2ghz_ctl; case NL80211_BAND_5GHZ: return reg->regpair->reg_5ghz_ctl; default: return NO_CTL; } } EXPORT_SYMBOL(ath_regd_get_band_ctl); diff --git a/sys/contrib/dev/athk/spectral_common.h b/sys/contrib/dev/athk/spectral_common.h index e14f374f97d4..fe187c1fbeb0 100644 --- a/sys/contrib/dev/athk/spectral_common.h +++ b/sys/contrib/dev/athk/spectral_common.h @@ -1,129 +1,129 @@ /* * Copyright (c) 2013 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef SPECTRAL_COMMON_H #define SPECTRAL_COMMON_H #define SPECTRAL_HT20_NUM_BINS 56 #define SPECTRAL_HT20_40_NUM_BINS 128 /* TODO: could possibly be 512, but no samples this large * could be acquired so far. */ #define SPECTRAL_ATH10K_MAX_NUM_BINS 256 /* FFT sample format given to userspace via debugfs. * * Please keep the type/length at the front position and change * other fields after adding another sample type * * TODO: this might need rework when switching to nl80211-based * interface. */ enum ath_fft_sample_type { ATH_FFT_SAMPLE_HT20 = 1, ATH_FFT_SAMPLE_HT20_40, ATH_FFT_SAMPLE_ATH10K, ATH_FFT_SAMPLE_ATH11K }; struct fft_sample_tlv { u8 type; /* see ath_fft_sample */ __be16 length; /* type dependent data follows */ } __packed; struct fft_sample_ht20 { struct fft_sample_tlv tlv; u8 max_exp; __be16 freq; s8 rssi; s8 noise; __be16 max_magnitude; u8 max_index; u8 bitmap_weight; __be64 tsf; u8 data[SPECTRAL_HT20_NUM_BINS]; } __packed; struct fft_sample_ht20_40 { struct fft_sample_tlv tlv; u8 channel_type; __be16 freq; s8 lower_rssi; s8 upper_rssi; __be64 tsf; s8 lower_noise; s8 upper_noise; __be16 lower_max_magnitude; __be16 upper_max_magnitude; u8 lower_max_index; u8 upper_max_index; u8 lower_bitmap_weight; u8 upper_bitmap_weight; u8 max_exp; u8 data[SPECTRAL_HT20_40_NUM_BINS]; } __packed; struct fft_sample_ath10k { struct fft_sample_tlv tlv; u8 chan_width_mhz; __be16 freq1; __be16 freq2; __be16 noise; __be16 max_magnitude; __be16 total_gain_db; __be16 base_pwr_db; __be64 tsf; s8 max_index; u8 rssi; u8 relpwr_db; u8 avgpwr_db; u8 max_exp; - u8 data[0]; + u8 data[]; } __packed; struct fft_sample_ath11k { struct fft_sample_tlv tlv; u8 chan_width_mhz; s8 max_index; u8 max_exp; __be16 freq1; __be16 freq2; __be16 max_magnitude; __be16 rssi; __be32 tsf; __be32 noise; - u8 data[0]; + u8 data[]; } __packed; #endif /* SPECTRAL_COMMON_H */ diff --git a/sys/contrib/dev/athk/trace.h b/sys/contrib/dev/athk/trace.h index ba711644d27e..9935cf475b6d 100644 --- a/sys/contrib/dev/athk/trace.h +++ b/sys/contrib/dev/athk/trace.h @@ -1,71 +1,68 @@ /* * Copyright (c) 2014 Qualcomm Atheros, Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #if !defined(_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_H #include #include "ath.h" #undef TRACE_SYSTEM #define TRACE_SYSTEM ath #if !defined(CONFIG_ATH_TRACEPOINTS) #undef TRACE_EVENT #define TRACE_EVENT(name, proto, ...) static inline void trace_ ## name(proto) {} #endif /* CONFIG_ATH_TRACEPOINTS */ TRACE_EVENT(ath_log, TP_PROTO(struct wiphy *wiphy, struct va_format *vaf), TP_ARGS(wiphy, vaf), TP_STRUCT__entry( __string(device, wiphy_name(wiphy)) __string(driver, KBUILD_MODNAME) - __dynamic_array(char, msg, ATH_DBG_MAX_LEN) + __vstring(msg, vaf->fmt, vaf->va) ), TP_fast_assign( __assign_str(device, wiphy_name(wiphy)); __assign_str(driver, KBUILD_MODNAME); - WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), - ATH_DBG_MAX_LEN, - vaf->fmt, - *vaf->va) >= ATH_DBG_MAX_LEN); + __assign_vstr(msg, vaf->fmt, vaf->va); ), TP_printk( "%s %s %s", __get_str(driver), __get_str(device), __get_str(msg) ) ); #endif /* _TRACE_H || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace /* This part must be outside protection */ #include