diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/Kconfig | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/cfg80211.c | 378 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/commands.c | 195 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/commands.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/eeprom.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/fw.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/hal.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/iwm.h | 39 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/lmac.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/main.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/netdev.c | 28 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/rx.c | 132 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/sdio.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/sdio.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/umac.h | 8 | ||||
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/wext.c | 723 |
17 files changed, 616 insertions, 1000 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig index 030401d367d3..c62da435285a 100644 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ b/drivers/net/wireless/iwmc3200wifi/Kconfig @@ -2,7 +2,6 @@ config IWM tristate "Intel Wireless Multicomm 3200 WiFi driver" depends on MMC && WLAN_80211 && EXPERIMENTAL depends on CFG80211 - select WIRELESS_EXT select FW_LOADER help The Intel Wireless Multicomm 3200 hardware is a combo diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile index 927f022545c1..d34291b652d3 100644 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ b/drivers/net/wireless/iwmc3200wifi/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_IWM) := iwmc3200wifi.o iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o +iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c index 96f714e6e12b..a6e852f4f92c 100644 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/netdevice.h> +#include <linux/etherdevice.h> #include <linux/wireless.h> #include <linux/ieee80211.h> #include <net/cfg80211.h> @@ -130,6 +131,133 @@ static struct ieee80211_supported_band iwm_band_5ghz = { .n_bitrates = iwm_a_rates_size, }; +static int iwm_key_init(struct iwm_key *key, u8 key_index, + const u8 *mac_addr, struct key_params *params) +{ + key->hdr.key_idx = key_index; + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + key->hdr.multicast = 1; + memset(key->hdr.mac, 0xff, ETH_ALEN); + } else { + key->hdr.multicast = 0; + memcpy(key->hdr.mac, mac_addr, ETH_ALEN); + } + + if (params) { + if (params->key_len > WLAN_MAX_KEY_LEN || + params->seq_len > IW_ENCODE_SEQ_MAX_SIZE) + return -EINVAL; + + key->cipher = params->cipher; + key->key_len = params->key_len; + key->seq_len = params->seq_len; + memcpy(key->key, params->key, key->key_len); + memcpy(key->seq, params->seq, key->seq_len); + } + + return 0; +} + +static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, + struct key_params *params) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + int ret; + + IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr); + + memset(key, 0, sizeof(struct iwm_key)); + ret = iwm_key_init(key, key_index, mac_addr, params); + if (ret < 0) { + IWM_ERR(iwm, "Invalid key_params\n"); + return ret; + } + + return iwm_set_key(iwm, 0, key); +} + +static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params*)) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + struct key_params params; + + IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); + + memset(¶ms, 0, sizeof(params)); + + params.cipher = key->cipher; + params.key_len = key->key_len; + params.seq_len = key->seq_len; + params.seq = key->seq; + params.key = key->key; + + callback(cookie, ¶ms); + + return key->key_len ? 0 : -ENOENT; +} + + +static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, + u8 key_index, const u8 *mac_addr) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + struct iwm_key *key = &iwm->keys[key_index]; + + if (!iwm->keys[key_index].key_len) { + IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index); + return 0; + } + + if (key_index == iwm->default_key) + iwm->default_key = -1; + + return iwm_set_key(iwm, 1, key); +} + +static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + + IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); + + if (!iwm->keys[key_index].key_len) { + IWM_ERR(iwm, "Key %d not used\n", key_index); + return -EINVAL; + } + + iwm->default_key = key_index; + + return iwm_set_tx_key(iwm, key_index); +} + +int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, + u8 *mac, struct station_info *sinfo) +{ + struct iwm_priv *iwm = ndev_to_iwm(ndev); + + if (memcmp(mac, iwm->bssid, ETH_ALEN)) + return -ENOENT; + + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = iwm->rate * 10; + + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = iwm->wstats.qual.level; + } + + return 0; +} + + int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) { struct wiphy *wiphy = iwm_to_wiphy(iwm); @@ -167,20 +295,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) return 0; } -static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, +static int iwm_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, enum nl80211_iftype type, u32 *flags, struct vif_params *params) { - struct net_device *ndev; struct wireless_dev *wdev; struct iwm_priv *iwm; u32 old_mode; - /* we're under RTNL */ - ndev = __dev_get_by_index(&init_net, ifindex); - if (!ndev) - return -ENODEV; - wdev = ndev->ieee80211_ptr; iwm = ndev_to_iwm(ndev); old_mode = iwm->conf.mode; @@ -329,12 +452,250 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return 0; } +static int iwm_set_auth_type(struct iwm_priv *iwm, + enum nl80211_auth_type sme_auth_type) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (sme_auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + case NL80211_AUTHTYPE_OPEN_SYSTEM: + IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n"); + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n"); + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + + break; + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) +{ + IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version); + + if (!wpa_version) { + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + return 0; + } + + if (wpa_version & NL80211_WPA_VERSION_2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + + if (wpa_version & NL80211_WPA_VERSION_1) + iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK; + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + if (!cipher) { + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + return 0; + } + + IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm', + cipher); + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case WLAN_CIPHER_SUITE_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case WLAN_CIPHER_SUITE_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + case WLAN_CIPHER_SUITE_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); + + if (key_mgt == WLAN_AKM_SUITE_8021X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == WLAN_AKM_SUITE_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + + +static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + struct ieee80211_channel *chan = sme->channel; + int ret; + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (!sme->ssid) + return -EINVAL; + + if (chan) + iwm->channel = + ieee80211_frequency_to_channel(chan->center_freq); + + iwm->umac_profile->ssid.ssid_len = sme->ssid_len; + memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len); + + if (sme->bssid) { + IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid); + memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } else { + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } + + ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); + if (ret < 0) + return ret; + + ret = iwm_set_auth_type(iwm, sme->auth_type); + if (ret < 0) + return ret; + + if (sme->crypto.n_ciphers_pairwise) { + ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0], + true); + if (ret < 0) + return ret; + } + + ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false); + if (ret < 0) + return ret; + + if (sme->crypto.n_akm_suites) { + ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]); + if (ret < 0) + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + u16 reason_code) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); + + if (iwm->umac_profile_active) + return iwm_invalidate_mlme_profile(iwm); + + return 0; +} + +static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, + enum tx_power_setting type, int dbm) +{ + switch (type) { + case TX_POWER_AUTOMATIC: + return 0; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + + *dbm = iwm->txpower; + + return 0; +} + +static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool enabled, int timeout) +{ + struct iwm_priv *iwm = wiphy_to_iwm(wiphy); + u32 power_index; + + if (enabled) + power_index = IWM_POWER_INDEX_DEFAULT; + else + power_index = IWM_POWER_INDEX_MIN; + + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + static struct cfg80211_ops iwm_cfg80211_ops = { .change_virtual_intf = iwm_cfg80211_change_iface, + .add_key = iwm_cfg80211_add_key, + .get_key = iwm_cfg80211_get_key, + .del_key = iwm_cfg80211_del_key, + .set_default_key = iwm_cfg80211_set_default_key, + .get_station = iwm_cfg80211_get_station, .scan = iwm_cfg80211_scan, .set_wiphy_params = iwm_cfg80211_set_wiphy_params, + .connect = iwm_cfg80211_connect, + .disconnect = iwm_cfg80211_disconnect, .join_ibss = iwm_cfg80211_join_ibss, .leave_ibss = iwm_cfg80211_leave_ibss, + .set_tx_power = iwm_cfg80211_set_txpower, + .get_tx_power = iwm_cfg80211_get_txpower, + .set_power_mgmt = iwm_cfg80211_set_power_mgmt, +}; + +static const u32 cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, }; struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) @@ -379,6 +740,9 @@ struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wdev->wiphy->cipher_suites = cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); + ret = wiphy_register(wdev->wiphy); if (ret < 0) { dev_err(dev, "Couldn't register wiphy device\n"); diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c index e2334d123599..a68a2aff3c1e 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ b/drivers/net/wireless/iwmc3200wifi/commands.c @@ -70,14 +70,27 @@ static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, bool resp) { + struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; struct iwm_umac_cmd umac_cmd; + int ret; + u8 oid = hdr->oid; umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; umac_cmd.resp = resp; - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, - payload, payload_size); + ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, + payload, payload_size); + + if (resp) { + ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, + test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), + 3 * HZ); + + return ret ? 0 : -EBUSY; + } + + return ret; } static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = @@ -106,7 +119,7 @@ static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, {5, 5, 0, COEX_CALIBRATION_FLAGS}, - {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, + {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, @@ -332,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, return ret; } -int iwm_send_umac_config(struct iwm_priv *iwm, - __le32 reset_flags) +int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) { int ret; @@ -361,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm, return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_WIRELESS_MODE, + iwm->conf.wireless_mode); + if (ret < 0) + return ret; + + ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, CFG_COEX_MODE, iwm->conf.coexist_mode); if (ret < 0) return ret; @@ -402,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm, return ret; ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_CTRL_FLAGS, 0x30001); + CFG_PM_CTRL_FLAGS, 0x1); if (ret < 0) return ret; @@ -462,8 +480,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, target_cmd.eop = 1; ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); - if (ret < 0) + if (ret < 0) { IWM_ERR(iwm, "Couldn't send READ command\n"); + return ret; + } /* When succeding, the send_target routine returns the seq number */ seq_num = ret; @@ -483,7 +503,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address, kfree(cmd); - return ret; + return 0; } int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) @@ -493,7 +513,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), mac_align, sizeof(mac_align)); - if (ret < 0) + if (ret) return ret; if (is_valid_ether_addr(mac_align)) @@ -507,22 +527,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) return 0; } -int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) -{ - struct iwm_umac_tx_key_id tx_key_id; - - if (!iwm->default_key || !iwm->default_key->in_use) - return -EINVAL; - - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; - tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - - sizeof(struct iwm_umac_wifi_if)); - - tx_key_id.key_idx = key_idx; - - return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); -} - static int iwm_check_profile(struct iwm_priv *iwm) { if (!iwm->umac_profile_active) @@ -556,10 +560,35 @@ static int iwm_check_profile(struct iwm_priv *iwm) return 0; } -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key) +int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) { + struct iwm_umac_tx_key_id tx_key_id; int ret; + + ret = iwm_check_profile(iwm); + if (ret < 0) + return ret; + + /* UMAC only allows to set default key for WEP and auth type is + * NOT 802.1X or RSNA. */ + if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && + iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || + iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) + return 0; + + tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; + tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - + sizeof(struct iwm_umac_wifi_if)); + + tx_key_id.key_idx = key_idx; + + return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); +} + +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) +{ + int ret = 0; u8 cmd[64], *sta_addr, *key_data, key_len; s8 key_idx; u16 cmd_size = 0; @@ -569,15 +598,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - if (set_tx_key) - iwm->default_key = key; - - /* - * We check if our current profile is valid. - * If not, we dont push the key, we just cache them, - * so that with the next siwsessid call, the keys - * will be actually pushed. - */ if (!remove) { ret = iwm_check_profile(iwm); if (ret < 0) @@ -590,8 +610,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_idx = key->hdr.key_idx; if (!remove) { - IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", - key_idx, set_tx_key); + u8 auth_type = iwm->umac_profile->sec.auth_type; + + IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); @@ -603,8 +624,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, iwm->umac_profile->sec.auth_type, iwm->umac_profile->sec.flags); - switch (key->alg) { - case UMAC_CIPHER_TYPE_WEP_40: + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; wep40->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - @@ -613,12 +634,14 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, memcpy(&wep40->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep40->key, key_data, key_len); - wep40->static_key = 1; + wep40->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep40); break; - case UMAC_CIPHER_TYPE_WEP_104: + case WLAN_CIPHER_SUITE_WEP104: wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; wep104->hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - @@ -627,12 +650,14 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, memcpy(&wep104->key_hdr, key_hdr, sizeof(struct iwm_umac_key_hdr)); memcpy(wep104->key, key_data, key_len); - wep104->static_key = 1; + wep104->static_key = + !!((auth_type != UMAC_AUTH_TYPE_8021X) && + (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); cmd_size = sizeof(struct iwm_umac_key_wep104); break; - case UMAC_CIPHER_TYPE_CCMP: + case WLAN_CIPHER_SUITE_CCMP: key_hdr->key_idx++; ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; ccmp->hdr.buf_size = @@ -644,13 +669,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, memcpy(ccmp->key, key_data, key_len); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_ccmp); break; - case UMAC_CIPHER_TYPE_TKIP: + case WLAN_CIPHER_SUITE_TKIP: key_hdr->key_idx++; tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; tkip->hdr.buf_size = @@ -667,8 +692,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, IWM_TKIP_MIC_SIZE); - if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) - memcpy(ccmp->iv_count, key->rx_seq, 6); + if (key->seq_len) + memcpy(ccmp->iv_count, key->seq, key->seq_len); cmd_size = sizeof(struct iwm_umac_key_tkip); break; @@ -677,8 +702,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, return -ENOTSUPP; } - if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || - (key->alg == UMAC_CIPHER_TYPE_TKIP)) + if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || + (key->cipher == WLAN_CIPHER_SUITE_CCMP)) /* * UGLY_UGLY_UGLY * Copied HACK from the MWG driver. @@ -689,23 +714,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, schedule_timeout_interruptible(usecs_to_jiffies(300)); ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); - if (ret < 0) - goto err; - - /* - * We need a default key only if it is set and - * if we're doing WEP. - */ - if (iwm->default_key == key && - ((key->alg == UMAC_CIPHER_TYPE_WEP_40) || - (key->alg == UMAC_CIPHER_TYPE_WEP_104))) { - ret = iwm_set_tx_key(iwm, key_idx); - if (ret < 0) - goto err; - } } else { struct iwm_umac_key_remove key_remove; + IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); + key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; key_remove.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_key_remove) - @@ -716,23 +729,19 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, ret = iwm_send_wifi_if_cmd(iwm, &key_remove, sizeof(struct iwm_umac_key_remove), 1); - if (ret < 0) + if (ret) return ret; - iwm->keys[key_idx].in_use = 0; + iwm->keys[key_idx].key_len = 0; } - return 0; - - err: - kfree(key); return ret; } int iwm_send_mlme_profile(struct iwm_priv *iwm) { - int ret, i; + int ret; struct iwm_umac_profile profile; memcpy(&profile, iwm->umac_profile, sizeof(profile)); @@ -742,45 +751,18 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm) sizeof(struct iwm_umac_wifi_if)); ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Send profile command failed\n"); return ret; } - /* Wait for the profile to be active */ - ret = wait_event_interruptible_timeout(iwm->mlme_queue, - iwm->umac_profile_active == 1, - 3 * HZ); - if (!ret) - return -EBUSY; - - - for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].in_use) { - int default_key = 0; - struct iwm_key *key = &iwm->keys[i]; - - if (key == iwm->default_key) - default_key = 1; - - /* Wait for the profile before sending the keys */ - wait_event_interruptible_timeout(iwm->mlme_queue, - (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || - test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), - 3 * HZ); - - ret = iwm_set_key(iwm, 0, default_key, key); - if (ret < 0) - return ret; - } - return 0; } int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) { - int ret; struct iwm_umac_invalidate_profile invalid; + int ret; invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; invalid.hdr.buf_size = @@ -790,16 +772,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) invalid.reason = WLAN_REASON_UNSPECIFIED; ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); - if (ret < 0) + if (ret) return ret; ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), - 2 * HZ); - if (!ret) - return -EBUSY; + (iwm->umac_profile_active == 0), 2 * HZ); - return 0; + return ret ? 0 : -EBUSY; } int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) @@ -882,7 +861,7 @@ int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, } ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); - if (ret < 0) { + if (ret) { IWM_ERR(iwm, "Couldn't send scan request\n"); return ret; } diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h index 36b13a130595..e24d5b633997 100644 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ b/drivers/net/wireless/iwmc3200wifi/commands.h @@ -106,8 +106,7 @@ enum { CFG_TLC_SPATIAL_STREAM_SUPPORTED, CFG_TLC_RETRY_PER_RATE, CFG_TLC_RETRY_PER_HT_RATE, - CFG_TLC_FIXED_RATE, - CFG_TLC_FIXED_RATE_FLAGS, + CFG_TLC_FIXED_MCS, CFG_TLC_CONTROL_FLAGS, CFG_TLC_SR_MIN_FAIL, CFG_TLC_SR_MIN_PASS, @@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list { /* Wireless mode */ #define WIRELESS_MODE_11A 0x1 #define WIRELESS_MODE_11G 0x2 +#define WIRELESS_MODE_11N 0x4 #define UMAC_PROFILE_EX_IE_REQUIRED 0x1 #define UMAC_PROFILE_QOS_ALLOWED 0x2 @@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm); int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); -int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, - struct iwm_key *key); +int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); int iwm_send_umac_channel_list(struct iwm_priv *iwm); int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c index 0f34b84fd2eb..365910fbe01e 100644 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ b/drivers/net/wireless/iwmc3200wifi/eeprom.c @@ -156,10 +156,6 @@ int iwm_eeprom_init(struct iwm_priv *iwm) return -ENOMEM; for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET)) - break; -#endif ret = iwm_eeprom_read(iwm, i); if (ret < 0) { IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index ec1a15a5a0e4..0f32cab9ced4 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -275,6 +275,7 @@ static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) */ int iwm_load_fw(struct iwm_priv *iwm) { + unsigned long init_calib_map, periodic_calib_map; int ret; /* We first start downloading the UMAC */ @@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm) return ret; } -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); - clear_bit(PHY_CALIBRATE_RX_IQ_CMD, - &iwm->conf.periodic_calib_map); - } -#endif + init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; + periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); + /* Read RX IQ calibration result from EEPROM */ - if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { + if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) { iwm_store_rxiq_calib_result(iwm); set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); } iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); + iwm_send_init_calib_cfg(iwm, init_calib_map); - while (iwm->calib_done_map != iwm->conf.init_calib_map) { + while (iwm->calib_done_map != init_calib_map) { ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); if (ret) { @@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm) } IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " "0x%lx, requested calibrations: 0x%lx\n", - iwm->calib_done_map, iwm->conf.init_calib_map); + iwm->calib_done_map, init_calib_map); } /* Handle LMAC CALIBRATION_COMPLETE notification */ @@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm) iwm_send_prio_table(iwm); iwm_send_calib_results(iwm); - iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); + iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); return 0; diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c index ee127fe4f43f..c430418248b4 100644 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ b/drivers/net/wireless/iwmc3200wifi/hal.c @@ -105,9 +105,9 @@ #include "umac.h" #include "debug.h" -static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, - struct iwm_nonwifi_cmd *cmd, - struct iwm_udma_nonwifi_cmd *udma_cmd) +static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm, + struct iwm_nonwifi_cmd *cmd, + struct iwm_udma_nonwifi_cmd *udma_cmd) { INIT_LIST_HEAD(&cmd->pending); @@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->seq_num = iwm->nonwifi_seq_num; udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); - cmd->seq_num = iwm->nonwifi_seq_num++; + iwm->nonwifi_seq_num++; iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; if (udma_cmd->resp) @@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, cmd->buf.len = 0; memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); + + return cmd->seq_num; } u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) @@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, const void *payload) { struct iwm_nonwifi_cmd *cmd; - int ret; + int ret, seq_num; cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); if (!cmd) { @@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, return -ENOMEM; } - iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); + seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { @@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm, if (ret < 0) return ret; - return cmd->seq_num; + return seq_num; } static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h index 77c339f8516c..7a51bc340fda 100644 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ b/drivers/net/wireless/iwmc3200wifi/iwm.h @@ -52,8 +52,6 @@ #define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" #define IWM_AUTHOR "<ilw@linux.intel.com>" -#define CONFIG_IWM_B0_HW_SUPPORT 1 - #define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX #define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA #define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW @@ -65,8 +63,7 @@ struct iwm_conf { u32 sdio_ior_timeout; - unsigned long init_calib_map; - unsigned long periodic_calib_map; + unsigned long calib_map; bool reset_on_fatal_err; bool auto_connect; bool wimax_not_present; @@ -87,9 +84,6 @@ struct iwm_conf { u8 ibss_channel; u8 mac_addr[ETH_ALEN]; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - bool hw_b0; -#endif }; enum { @@ -162,13 +156,11 @@ struct iwm_umac_key_hdr { struct iwm_key { struct iwm_umac_key_hdr hdr; - u8 in_use; - u8 alg; - u32 flags; - u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; - u8 key_len; - u8 key[32]; + u32 cipher; + u8 key[WLAN_MAX_KEY_LEN]; + u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; + int key_len; + int seq_len; }; #define IWM_RX_ID_HASH 0xff @@ -186,10 +178,6 @@ struct iwm_key { #define IWM_STATUS_ASSOCIATING 3 #define IWM_STATUS_ASSOCIATED 4 -#define IWM_RADIO_RFKILL_OFF 0 -#define IWM_RADIO_RFKILL_HW 1 -#define IWM_RADIO_RFKILL_SW 2 - struct iwm_tx_queue { int id; struct sk_buff_head queue; @@ -223,7 +211,6 @@ struct iwm_priv { struct iwm_conf conf; unsigned long status; - unsigned long radio; struct list_head pending_notif; wait_queue_head_t notif_queue; @@ -242,6 +229,7 @@ struct iwm_priv { u8 bssid[ETH_ALEN]; u8 channel; u16 rate; + u32 txpower; struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; struct list_head bss_list; @@ -276,7 +264,10 @@ struct iwm_priv { struct iwm_tx_queue txq[IWM_TX_QUEUES]; struct iwm_key keys[IWM_NUM_KEYS]; - struct iwm_key *default_key; + s8 default_key; + + DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); + wait_queue_head_t wifi_ntfy_queue; wait_queue_head_t mlme_queue; @@ -289,7 +280,11 @@ struct iwm_priv { struct timer_list watchdog; struct work_struct reset_worker; struct mutex mutex; - struct rfkill *rfkill; + + u8 *req_ie; + int req_ie_len; + u8 *resp_ie; + int resp_ie_len; char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); }; @@ -311,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm) #define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) #define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) -extern const struct iw_handler_def iwm_iw_handler_def; - void *iwm_if_alloc(int sizeof_bus, struct device *dev, struct iwm_if_ops *if_ops); void iwm_if_free(struct iwm_priv *iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h index db2e5eea1895..19213e165f5f 100644 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ b/drivers/net/wireless/iwmc3200wifi/lmac.h @@ -396,6 +396,10 @@ enum { CALIBRATION_CMD_NUM, }; +#define IWM_CALIB_MAP_INIT_MSK 0xFFFF +#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) +#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) + struct iwm_lmac_calib_hdr { u8 opcode; u8 first_grp; diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c index 8be206d58222..cf2574442b57 100644 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ b/drivers/net/wireless/iwmc3200wifi/main.c @@ -53,11 +53,7 @@ static struct iwm_conf def_iwm_conf = { .sdio_ior_timeout = 5000, - .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | - BIT(PHY_CALIBRATE_LO_CMD) | - BIT(PHY_CALIBRATE_TX_IQ_CMD) | - BIT(PHY_CALIBRATE_RX_IQ_CMD), - .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | + .calib_map = BIT(PHY_CALIBRATE_DC_CMD) | BIT(PHY_CALIBRATE_LO_CMD) | BIT(PHY_CALIBRATE_TX_IQ_CMD) | BIT(PHY_CALIBRATE_RX_IQ_CMD) | @@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm) INIT_LIST_HEAD(&iwm->pending_notif); init_waitqueue_head(&iwm->notif_queue); init_waitqueue_head(&iwm->nonwifi_queue); + init_waitqueue_head(&iwm->wifi_ntfy_queue); init_waitqueue_head(&iwm->mlme_queue); memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); spin_lock_init(&iwm->tx_credit.lock); @@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm) for (i = 0; i < IWM_NUM_KEYS; i++) memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); - iwm->default_key = NULL; + iwm->default_key = -1; init_timer(&iwm->watchdog); iwm->watchdog.function = iwm_watchdog; @@ -500,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm) memset(wstats, 0, sizeof(struct iw_statistics)); wstats->qual.updated = IW_QUAL_ALL_INVALID; + kfree(iwm->req_ie); + iwm->req_ie = NULL; + iwm->req_ie_len = 0; + kfree(iwm->resp_ie); + iwm->resp_ie = NULL; + iwm->resp_ie_len = 0; + del_timer_sync(&iwm->watchdog); } @@ -518,13 +522,6 @@ static int iwm_channels_init(struct iwm_priv *iwm) { int ret; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (iwm->conf.hw_b0) { - IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n"); - return 0; - } -#endif - ret = iwm_send_umac_channel_list(iwm); if (ret) { IWM_ERR(iwm, "Send channel list failed\n"); @@ -642,19 +639,10 @@ int __iwm_up(struct iwm_priv *iwm) } } - iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), - GFP_KERNEL); - if (!iwm->umac_profile) { - IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); - goto err_fw; - } - - iwm_init_default_profile(iwm, iwm->umac_profile); - ret = iwm_channels_init(iwm); if (ret < 0) { IWM_ERR(iwm, "Couldn't init channels\n"); - goto err_profile; + goto err_fw; } /* Set the READY bit to indicate interface is brought up successfully */ @@ -662,10 +650,6 @@ int __iwm_up(struct iwm_priv *iwm) return 0; - err_profile: - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; - err_fw: iwm_eeprom_exit(iwm); @@ -704,11 +688,10 @@ int __iwm_down(struct iwm_priv *iwm) clear_bit(IWM_STATUS_READY, &iwm->status); iwm_eeprom_exit(iwm); - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; iwm_bss_list_clean(iwm); - - iwm->default_key = NULL; + iwm_init_default_profile(iwm, iwm->umac_profile); + iwm->umac_profile_active = false; + iwm->default_key = -1; iwm->core_enabled = 0; ret = iwm_bus_disable(iwm); diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c index bf294e41753b..35ec006c2d2c 100644 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ b/drivers/net/wireless/iwmc3200wifi/netdev.c @@ -48,29 +48,22 @@ #include <linux/netdevice.h> #include "iwm.h" +#include "commands.h" #include "cfg80211.h" #include "debug.h" static int iwm_open(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_up(iwm); - return ret; + return iwm_up(iwm); } static int iwm_stop(struct net_device *ndev) { struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret = 0; - - if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio)) - ret = iwm_down(iwm); - return ret; + return iwm_down(iwm); } /* @@ -128,13 +121,24 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev, } ndev->netdev_ops = &iwm_netdev_ops; - ndev->wireless_handlers = &iwm_iw_handler_def; ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; + iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), + GFP_KERNEL); + if (!iwm->umac_profile) { + dev_err(dev, "Couldn't alloc memory for profile\n"); + goto out_profile; + } + + iwm_init_default_profile(iwm, iwm->umac_profile); + return iwm; + out_profile: + free_netdev(ndev); + out_priv: iwm_priv_deinit(iwm); @@ -150,6 +154,8 @@ void iwm_if_free(struct iwm_priv *iwm) free_netdev(iwm_to_ndev(iwm)); iwm_priv_deinit(iwm); + kfree(iwm->umac_profile); + iwm->umac_profile = NULL; iwm_wdev_free(iwm); } diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c index d73cf96c6dc6..86079a187eef 100644 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ b/drivers/net/wireless/iwmc3200wifi/rx.c @@ -102,7 +102,6 @@ static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, error = (struct iwm_umac_notif_error *)buf; fw_err = &error->err; - IWM_ERR(iwm, "%cMAC FW ERROR:\n", (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); @@ -143,17 +142,18 @@ static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_umac_notif_init_complete *init_complete = (struct iwm_umac_notif_init_complete *)(buf); u16 status = le16_to_cpu(init_complete->status); + bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); - if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { + if (blocked) IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } else { + else IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - } + + wiphy_rfkill_set_hw_state(wiphy, blocked); return 0; } @@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, (buf + sizeof(struct iwm_umac_wifi_in_hdr)); hdr = (struct iwm_umac_wifi_in_hdr *)buf; - IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); + IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); - IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", - le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); - IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); - IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", - le16_to_cpu(tx_resp->retry_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); - IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", - le16_to_cpu(tx_resp->byte_cnt)); - IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); + IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", + le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); + IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); + IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", + le16_to_cpu(tx_resp->retry_cnt)); + IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); + IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", + le16_to_cpu(tx_resp->byte_cnt)); + IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); return 0; } @@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, if (IS_ERR(ticket_node)) return PTR_ERR(ticket_node); - IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", - ticket->id); + IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n", + ticket->id); list_add_tail(&ticket_node->node, &iwm->rx_tickets); /* @@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, u16 id, buf_offset; u32 packet_size; - IWM_DBG_NTF(iwm, DBG, "\n"); + IWM_DBG_RX(iwm, DBG, "\n"); wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); - IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", - wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); + IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", + wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); @@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, { struct iwm_umac_notif_assoc_complete *complete = (struct iwm_umac_notif_assoc_complete *)buf; - union iwreq_data wrqu; IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", complete->bssid, complete->status); - memset(&wrqu, 0, sizeof(wrqu)); - clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); switch (le32_to_cpu(complete->status)) { @@ -520,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm_link_on(iwm); - memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + + cfg80211_connect_result(iwm_to_ndev(iwm), + complete->bssid, + iwm->req_ie, iwm->req_ie_len, + iwm->resp_ie, iwm->resp_ie_len, + WLAN_STATUS_SUCCESS, GFP_KERNEL); break; case UMAC_ASSOC_COMPLETE_FAILURE: clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); @@ -528,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, iwm->channel = 0; iwm_link_off(iwm); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + goto ibss; + + cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid, + NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); default: break; } - if (iwm->conf.mode == UMAC_MODE_IBSS) { - cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); - return 0; - } - - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL); + return 0; + ibss: + cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); return 0; } @@ -769,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { struct iwm_umac_notif_mgt_frame *mgt_frame = - (struct iwm_umac_notif_mgt_frame *)buf; + (struct iwm_umac_notif_mgt_frame *)buf; struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; u8 *ie; - unsigned int event; - union iwreq_data wrqu; IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, le16_to_cpu(mgt_frame->len)); if (ieee80211_is_assoc_req(mgt->frame_control)) { ie = mgt->u.assoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { ie = mgt->u.reassoc_req.variable;; - event = IWEVASSOCREQIE; + iwm->req_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->req_ie); + iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, + iwm->req_ie_len, GFP_KERNEL); } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { ie = mgt->u.assoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { ie = mgt->u.reassoc_resp.variable;; - event = IWEVASSOCRESPIE; + iwm->resp_ie_len = + le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); + kfree(iwm->resp_ie); + iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, + iwm->resp_ie_len, GFP_KERNEL); } else { IWM_ERR(iwm, "Unsupported management frame"); return 0; } - wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt); - - IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length); - wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie); - return 0; } @@ -875,6 +892,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, /* UMAC passes rate info multiplies by 2 */ iwm->rate = max_rate >> 1; } + iwm->txpower = le32_to_cpu(stats->tx_power); wstats->status = 0; @@ -922,13 +940,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) return -EINVAL; -#ifdef CONFIG_IWM_B0_HW_SUPPORT - if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) { - if (eeprom_proxy->buf[0] == 0xff) - iwm->conf.hw_b0 = 1; - } -#endif - switch (hdr_type) { case IWM_UMAC_CMD_EEPROM_TYPE_READ: memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); @@ -993,12 +1004,17 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, (struct iwm_umac_wifi_if *)cmd->buf.payload; IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " - "oid is %d\n", hdr->oid); + "oid is 0x%x\n", hdr->oid); + + if (hdr->oid <= WIFI_IF_NTFY_MAX) { + set_bit(hdr->oid, &iwm->wifi_ntfy[0]); + wake_up_interruptible(&iwm->wifi_ntfy_queue); + } else + return -EINVAL; switch (hdr->oid) { case UMAC_WIFI_IF_CMD_SET_PROFILE: iwm->umac_profile_active = 1; - wake_up_interruptible(&iwm->mlme_queue); break; default: break; @@ -1010,6 +1026,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, struct iwm_wifi_cmd *cmd) { + struct wiphy *wiphy = iwm_to_wiphy(iwm); struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) (buf + sizeof(struct iwm_umac_wifi_in_hdr)); u32 flags = le32_to_cpu(state->flags); @@ -1018,10 +1035,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); - if (flags & IWM_CARD_STATE_HW_DISABLED) - set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); - else - clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); + wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED); return 0; } @@ -1362,13 +1376,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm, skb->dev = iwm_to_ndev(iwm); skb->protocol = eth_type_trans(skb, ndev); - skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->ip_summed = CHECKSUM_NONE; memset(skb->cb, 0, sizeof(skb->cb)); ndev->stats.rx_packets++; ndev->stats.rx_bytes += skb->len; - if (netif_rx(skb) == NET_RX_DROP) { + if (netif_rx_ni(skb) == NET_RX_DROP) { IWM_ERR(iwm, "Packet dropped\n"); ndev->stats.rx_dropped++; } diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c index 916681837fd2..8b1de84003ca 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ b/drivers/net/wireless/iwmc3200wifi/sdio.c @@ -65,6 +65,7 @@ #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/debugfs.h> +#include <linux/mmc/sdio_ids.h> #include <linux/mmc/sdio.h> #include <linux/mmc/sdio_func.h> @@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func) } static const struct sdio_device_id iwm_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, + SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) }, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); @@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = { static int __init iwm_sdio_init_module(void) { - int ret; - - ret = sdio_register_driver(&iwm_sdio_driver); - - return ret; + return sdio_register_driver(&iwm_sdio_driver); } static void __exit iwm_sdio_exit_module(void) diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h index b3c156b08dda..aab6b6892e45 100644 --- a/drivers/net/wireless/iwmc3200wifi/sdio.h +++ b/drivers/net/wireless/iwmc3200wifi/sdio.h @@ -39,9 +39,6 @@ #ifndef __IWM_SDIO_H__ #define __IWM_SDIO_H__ -#define SDIO_VENDOR_ID_INTEL 0x89 -#define SDIO_DEVICE_ID_IWM 0x1403 - #define IWM_SDIO_DATA_ADDR 0x0 #define IWM_SDIO_INTR_ENABLE_ADDR 0x14 #define IWM_SDIO_INTR_STATUS_ADDR 0x13 diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h index 4a95cce1f0a6..c5a14ae3160a 100644 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ b/drivers/net/wireless/iwmc3200wifi/umac.h @@ -495,6 +495,8 @@ struct iwm_fw_alive_hdr { #define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 #define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 +#define WIFI_IF_NTFY_MAX 0xff + /* Notification structures */ struct iwm_umac_notif_wifi_if { struct iwm_umac_wifi_in_hdr hdr; @@ -613,6 +615,7 @@ struct iwm_umac_notif_alive { } __attribute__ ((packed)); struct iwm_umac_notif_init_complete { + struct iwm_umac_wifi_in_hdr hdr; __le16 status; __le16 reserved; } __attribute__ ((packed)); @@ -641,6 +644,11 @@ struct iwm_fw_error_hdr { __le32 umac_status; __le32 lmac_status; __le32 sdio_status; + __le32 dbm_sample_ctrl; + __le32 dbm_buf_base; + __le32 dbm_buf_end; + __le32 dbm_buf_write_ptr; + __le32 dbm_buf_cycle_cnt; } __attribute__ ((packed)); struct iwm_umac_notif_error { diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c deleted file mode 100644 index 584c94d0f399..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/wext.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <linux/if_arp.h> -#include <linux/etherdevice.h> -#include <net/cfg80211.h> -#include <net/iw_handler.h> - -#include "iwm.h" -#include "umac.h" -#include "commands.h" -#include "debug.h" - -static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iw_statistics *wstats = &iwm->wstats; - - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - memset(wstats, 0, sizeof(struct iw_statistics)); - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } - - return wstats; -} - -static int iwm_wext_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - if (freq->flags == IW_FREQ_AUTO) - return 0; - - /* frequency/channel can only be set in IBSS mode */ - if (iwm->conf.mode != UMAC_MODE_IBSS) - return -EOPNOTSUPP; - - return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); -} - -static int iwm_wext_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - if (iwm->conf.mode == UMAC_MODE_IBSS) - return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); - - freq->e = 0; - freq->m = iwm->channel; - - return 0; -} - -static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - if (iwm->conf.mode == UMAC_MODE_IBSS) - return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (is_zero_ether_addr(ap_addr->sa_data) || - is_broadcast_ether_addr(ap_addr->sa_data)) { - IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", - iwm->umac_profile->bssid[0]); - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); - iwm->umac_profile->bss_num = 0; - } else { - IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", - ap_addr->sa_data); - memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, - ETH_ALEN); - iwm->umac_profile->bss_num = 1; - } - - if (iwm->umac_profile_active) { - if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) - return 0; - - iwm_invalidate_mlme_profile(iwm); - } - - if (iwm->umac_profile->ssid.ssid_len) - return iwm_send_mlme_profile(iwm); - - return 0; -} - -static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - switch (iwm->conf.mode) { - case UMAC_MODE_IBSS: - return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); - case UMAC_MODE_BSS: - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); - } else - memset(&ap_addr->sa_data, 0, ETH_ALEN); - break; - default: - return -EOPNOTSUPP; - } - - return 0; -} - -static int iwm_wext_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - size_t len = data->length; - int ret; - - if (iwm->conf.mode == UMAC_MODE_IBSS) - return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (len > 0 && ssid[len - 1] == '\0') - len--; - - if (iwm->umac_profile_active) { - if (iwm->umac_profile->ssid.ssid_len == len && - !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) - return 0; - - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - } - - iwm->umac_profile->ssid.ssid_len = len; - memcpy(iwm->umac_profile->ssid.ssid, ssid, len); - - return iwm_send_mlme_profile(iwm); -} - -static int iwm_wext_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - if (iwm->conf.mode == UMAC_MODE_IBSS) - return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - data->length = iwm->umac_profile->ssid.ssid_len; - if (data->length) { - memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); - data->flags = 1; - } else - data->flags = 0; - - return 0; -} - -static struct iwm_key * -iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, - struct iw_encode_ext *ext, u8 alg) -{ - struct iwm_key *key = &iwm->keys[key_idx]; - - memset(key, 0, sizeof(struct iwm_key)); - memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); - key->hdr.key_idx = key_idx; - if (is_broadcast_ether_addr(ext->addr.sa_data)) - key->hdr.multicast = 1; - - key->in_use = in_use; - key->flags = ext->ext_flags; - key->alg = alg; - key->key_len = ext->key_len; - memcpy(key->key, ext->key, ext->key_len); - - return key; -} - -static int iwm_wext_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - rate->value = iwm->rate * 1000000; - - return 0; -} - -static int iwm_wext_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key_buf) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *uninitialized_var(key); - int idx, i, uninitialized_var(alg), remove = 0, ret; - - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - - if (!iwm->umac_profile) { - IWM_ERR(iwm, "UMAC profile not allocated yet\n"); - return -ENODEV; - } - - if (erq->length == WLAN_KEY_LEN_WEP40) { - alg = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; - } else if (erq->length == WLAN_KEY_LEN_WEP104) { - alg = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; - iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; - } - - if (erq->flags & IW_ENCODE_RESTRICTED) - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - else - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - else - iwm->default_key = &iwm->keys[idx]; - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - if (!iwm->keys[idx].in_use) - return -EINVAL; - iwm->default_key = &iwm->keys[idx]; - } - - if (erq->length) { - key = &iwm->keys[idx]; - memset(key, 0, sizeof(struct iwm_key)); - memset(key->hdr.mac, 0xff, ETH_ALEN); - key->hdr.key_idx = idx; - key->hdr.multicast = 1; - key->in_use = !remove; - key->alg = alg; - key->key_len = erq->length; - memcpy(key->key, key_buf, erq->length); - - IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", - idx, !!iwm->default_key); - } - - if (remove) { - if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { - int j; - for (j = 0; j < IWM_NUM_KEYS; j++) - if (iwm->keys[j].in_use) { - struct iwm_key *k = &iwm->keys[j]; - - k->in_use = 0; - ret = iwm_set_key(iwm, remove, 0, k); - if (ret < 0) - return ret; - } - - iwm->umac_profile->sec.ucast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.mcast_cipher = - UMAC_CIPHER_TYPE_NONE; - iwm->umac_profile->sec.auth_type = - UMAC_AUTH_TYPE_OPEN; - - return 0; - } else { - key->in_use = 0; - return iwm_set_key(iwm, remove, 0, key); - } - } - - /* - * If we havent set a profile yet, we cant set keys. - * Keys will be pushed after we're associated. - */ - if (!iwm->umac_profile_active) - return 0; - - /* - * If there is a current active profile, but no - * default key, it's not worth trying to associate again. - */ - if (!iwm->default_key) - return 0; - - /* - * Here we have an active profile, but a key setting changed. - * We thus have to invalidate the current profile, and push the - * new one. Keys will be pushed when association takes place. - */ - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - - return iwm_send_mlme_profile(iwm); -} - -static int iwm_wext_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int idx, i; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!iwm->default_key) { - erq->length = 0; - erq->flags |= IW_ENCODE_NOKEY; - return 0; - } else - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!iwm->keys[idx].in_use) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, iwm->keys[idx].key, - min_t(int, erq->length, iwm->keys[idx].key_len)); - erq->length = iwm->keys[idx].key_len; - erq->flags |= IW_ENCODE_ENABLED; - - if (iwm->umac_profile->mode == UMAC_MODE_BSS) { - switch (iwm->umac_profile->sec.auth_type) { - case UMAC_AUTH_TYPE_OPEN: - erq->flags |= IW_ENCODE_OPEN; - break; - default: - erq->flags |= IW_ENCODE_RESTRICTED; - break; - } - } - - return 0; -} - -static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) -{ - if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; - else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; - else - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; - - return 0; -} - -static int iwm_wext_siwpower(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *wrq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - u32 power_index; - - if (wrq->disabled) { - power_index = IWM_POWER_INDEX_MIN; - goto set; - } else - power_index = IWM_POWER_INDEX_DEFAULT; - - switch (wrq->flags & IW_POWER_MODE) { - case IW_POWER_ON: - case IW_POWER_MODE: - case IW_POWER_ALL_R: - break; - default: - return -EINVAL; - } - - set: - if (power_index == iwm->conf.power_index) - return 0; - - iwm->conf.power_index = power_index; - - return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_POWER_INDEX, iwm->conf.power_index); -} - -static int iwm_wext_giwpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - - wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); - - return 0; -} - -static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) - *auth_type = UMAC_AUTH_TYPE_8021X; - else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - else - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } else { - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); - return -EINVAL; - } - - return 0; -} - -static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) -{ - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : - &iwm->umac_profile->sec.mcast_cipher; - - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - *profile_cipher = UMAC_CIPHER_TYPE_NONE; - break; - case IW_AUTH_CIPHER_WEP40: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; - break; - case IW_AUTH_CIPHER_TKIP: - *profile_cipher = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_AUTH_CIPHER_CCMP: - *profile_cipher = UMAC_CIPHER_TYPE_CCMP; - break; - case IW_AUTH_CIPHER_WEP104: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; - break; - default: - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - switch (auth_alg) { - case IW_AUTH_ALG_OPEN_SYSTEM: - *auth_type = UMAC_AUTH_TYPE_OPEN; - break; - case IW_AUTH_ALG_SHARED_KEY: - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { - if (*auth_type == UMAC_AUTH_TYPE_8021X) - return -EINVAL; - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - } else { - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } - break; - case IW_AUTH_ALG_LEAP: - default: - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_wext_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - int ret; - - if ((data->flags) & - (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | - IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { - /* We need to invalidate the current profile */ - if (iwm->umac_profile_active) { - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - } - } - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - return iwm_set_wpa_version(iwm, data->value); - break; - case IW_AUTH_CIPHER_PAIRWISE: - return iwm_set_cipher(iwm, data->value, 1); - break; - case IW_AUTH_CIPHER_GROUP: - return iwm_set_cipher(iwm, data->value, 0); - break; - case IW_AUTH_KEY_MGMT: - return iwm_set_key_mgt(iwm, data->value); - break; - case IW_AUTH_80211_AUTH_ALG: - return iwm_set_auth_alg(iwm, data->value); - break; - default: - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_wext_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - return 0; -} - -static int iwm_wext_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct iwm_priv *iwm = ndev_to_iwm(dev); - struct iwm_key *key; - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); - IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); - IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); - IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); - IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - if (ext->key_len == WLAN_KEY_LEN_WEP40) - alg = UMAC_CIPHER_TYPE_WEP_40; - else if (ext->key_len == WLAN_KEY_LEN_WEP104) - alg = UMAC_CIPHER_TYPE_WEP_104; - else { - IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); - return -EINVAL; - } - - break; - case IW_ENCODE_ALG_TKIP: - alg = UMAC_CIPHER_TYPE_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = UMAC_CIPHER_TYPE_CCMP; - break; - default: - return -EOPNOTSUPP; - } - - idx = erq->flags & IW_ENCODE_INDEX; - - if (idx == 0) { - if (iwm->default_key) - for (i = 0; i < IWM_NUM_KEYS; i++) { - if (iwm->default_key == &iwm->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) { - return -EINVAL; - } else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if ((erq->length == 0) || - (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { - iwm->default_key = &iwm->keys[idx]; - if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) - return iwm_set_tx_key(iwm, idx); - } - - key = iwm_key_init(iwm, idx, !remove, ext, alg); - - return iwm_set_key(iwm, remove, !iwm->default_key, key); -} - -static const iw_handler iwm_handlers[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ - (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ - (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ - (iw_handler) NULL, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ - (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ - (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ - (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWRATE */ - (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ - (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ - (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ - (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) NULL, /* SIOCSIWTXPOW */ - (iw_handler) NULL, /* SIOCGIWTXPOW */ - (iw_handler) NULL, /* SIOCSIWRETRY */ - (iw_handler) NULL, /* SIOCGIWRETRY */ - (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ - (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ - (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ - (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ - (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ - (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def iwm_iw_handler_def = { - .num_standard = ARRAY_SIZE(iwm_handlers), - .standard = (iw_handler *) iwm_handlers, - .get_wireless_stats = iwm_get_wireless_stats, -}; - |