aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Kconfig1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/Makefile2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c378
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c195
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h7
-rw-r--r--drivers/net/wireless/iwmc3200wifi/eeprom.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/fw.c21
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c16
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h39
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c45
-rw-r--r--drivers/net/wireless/iwmc3200wifi/netdev.c28
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c132
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.c10
-rw-r--r--drivers/net/wireless/iwmc3200wifi/sdio.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h8
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c723
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
2 tristate "Intel Wireless Multicomm 3200 WiFi driver" 2 tristate "Intel Wireless Multicomm 3200 WiFi driver"
3 depends on MMC && WLAN_80211 && EXPERIMENTAL 3 depends on MMC && WLAN_80211 && EXPERIMENTAL
4 depends on CFG80211 4 depends on CFG80211
5 select WIRELESS_EXT
6 select FW_LOADER 5 select FW_LOADER
7 help 6 help
8 The Intel Wireless Multicomm 3200 hardware is a combo 7 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 @@
1obj-$(CONFIG_IWM) := iwmc3200wifi.o 1obj-$(CONFIG_IWM) := iwmc3200wifi.o
2iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o 2iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o
3iwmc3200wifi-objs += commands.o wext.o cfg80211.o eeprom.o 3iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o
4 4
5iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o 5iwmc3200wifi-$(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 @@
23 23
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/netdevice.h> 25#include <linux/netdevice.h>
26#include <linux/etherdevice.h>
26#include <linux/wireless.h> 27#include <linux/wireless.h>
27#include <linux/ieee80211.h> 28#include <linux/ieee80211.h>
28#include <net/cfg80211.h> 29#include <net/cfg80211.h>
@@ -130,6 +131,133 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
130 .n_bitrates = iwm_a_rates_size, 131 .n_bitrates = iwm_a_rates_size,
131}; 132};
132 133
134static int iwm_key_init(struct iwm_key *key, u8 key_index,
135 const u8 *mac_addr, struct key_params *params)
136{
137 key->hdr.key_idx = key_index;
138 if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
139 key->hdr.multicast = 1;
140 memset(key->hdr.mac, 0xff, ETH_ALEN);
141 } else {
142 key->hdr.multicast = 0;
143 memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
144 }
145
146 if (params) {
147 if (params->key_len > WLAN_MAX_KEY_LEN ||
148 params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
149 return -EINVAL;
150
151 key->cipher = params->cipher;
152 key->key_len = params->key_len;
153 key->seq_len = params->seq_len;
154 memcpy(key->key, params->key, key->key_len);
155 memcpy(key->seq, params->seq, key->seq_len);
156 }
157
158 return 0;
159}
160
161static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
162 u8 key_index, const u8 *mac_addr,
163 struct key_params *params)
164{
165 struct iwm_priv *iwm = ndev_to_iwm(ndev);
166 struct iwm_key *key = &iwm->keys[key_index];
167 int ret;
168
169 IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
170
171 memset(key, 0, sizeof(struct iwm_key));
172 ret = iwm_key_init(key, key_index, mac_addr, params);
173 if (ret < 0) {
174 IWM_ERR(iwm, "Invalid key_params\n");
175 return ret;
176 }
177
178 return iwm_set_key(iwm, 0, key);
179}
180
181static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
182 u8 key_index, const u8 *mac_addr, void *cookie,
183 void (*callback)(void *cookie,
184 struct key_params*))
185{
186 struct iwm_priv *iwm = ndev_to_iwm(ndev);
187 struct iwm_key *key = &iwm->keys[key_index];
188 struct key_params params;
189
190 IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
191
192 memset(&params, 0, sizeof(params));
193
194 params.cipher = key->cipher;
195 params.key_len = key->key_len;
196 params.seq_len = key->seq_len;
197 params.seq = key->seq;
198 params.key = key->key;
199
200 callback(cookie, &params);
201
202 return key->key_len ? 0 : -ENOENT;
203}
204
205
206static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
207 u8 key_index, const u8 *mac_addr)
208{
209 struct iwm_priv *iwm = ndev_to_iwm(ndev);
210 struct iwm_key *key = &iwm->keys[key_index];
211
212 if (!iwm->keys[key_index].key_len) {
213 IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
214 return 0;
215 }
216
217 if (key_index == iwm->default_key)
218 iwm->default_key = -1;
219
220 return iwm_set_key(iwm, 1, key);
221}
222
223static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
224 struct net_device *ndev,
225 u8 key_index)
226{
227 struct iwm_priv *iwm = ndev_to_iwm(ndev);
228
229 IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
230
231 if (!iwm->keys[key_index].key_len) {
232 IWM_ERR(iwm, "Key %d not used\n", key_index);
233 return -EINVAL;
234 }
235
236 iwm->default_key = key_index;
237
238 return iwm_set_tx_key(iwm, key_index);
239}
240
241int iwm_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
242 u8 *mac, struct station_info *sinfo)
243{
244 struct iwm_priv *iwm = ndev_to_iwm(ndev);
245
246 if (memcmp(mac, iwm->bssid, ETH_ALEN))
247 return -ENOENT;
248
249 sinfo->filled |= STATION_INFO_TX_BITRATE;
250 sinfo->txrate.legacy = iwm->rate * 10;
251
252 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
253 sinfo->filled |= STATION_INFO_SIGNAL;
254 sinfo->signal = iwm->wstats.qual.level;
255 }
256
257 return 0;
258}
259
260
133int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) 261int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
134{ 262{
135 struct wiphy *wiphy = iwm_to_wiphy(iwm); 263 struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -167,20 +295,15 @@ int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
167 return 0; 295 return 0;
168} 296}
169 297
170static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex, 298static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
299 struct net_device *ndev,
171 enum nl80211_iftype type, u32 *flags, 300 enum nl80211_iftype type, u32 *flags,
172 struct vif_params *params) 301 struct vif_params *params)
173{ 302{
174 struct net_device *ndev;
175 struct wireless_dev *wdev; 303 struct wireless_dev *wdev;
176 struct iwm_priv *iwm; 304 struct iwm_priv *iwm;
177 u32 old_mode; 305 u32 old_mode;
178 306
179 /* we're under RTNL */
180 ndev = __dev_get_by_index(&init_net, ifindex);
181 if (!ndev)
182 return -ENODEV;
183
184 wdev = ndev->ieee80211_ptr; 307 wdev = ndev->ieee80211_ptr;
185 iwm = ndev_to_iwm(ndev); 308 iwm = ndev_to_iwm(ndev);
186 old_mode = iwm->conf.mode; 309 old_mode = iwm->conf.mode;
@@ -329,12 +452,250 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
329 return 0; 452 return 0;
330} 453}
331 454
455static int iwm_set_auth_type(struct iwm_priv *iwm,
456 enum nl80211_auth_type sme_auth_type)
457{
458 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
459
460 switch (sme_auth_type) {
461 case NL80211_AUTHTYPE_AUTOMATIC:
462 case NL80211_AUTHTYPE_OPEN_SYSTEM:
463 IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n");
464 *auth_type = UMAC_AUTH_TYPE_OPEN;
465 break;
466 case NL80211_AUTHTYPE_SHARED_KEY:
467 if (iwm->umac_profile->sec.flags &
468 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
469 IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n");
470 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
471 } else {
472 IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n");
473 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
474 }
475
476 break;
477 default:
478 IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type);
479 return -ENOTSUPP;
480 }
481
482 return 0;
483}
484
485static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version)
486{
487 IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version);
488
489 if (!wpa_version) {
490 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
491 return 0;
492 }
493
494 if (wpa_version & NL80211_WPA_VERSION_2)
495 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
496
497 if (wpa_version & NL80211_WPA_VERSION_1)
498 iwm->umac_profile->sec.flags |= UMAC_SEC_FLG_WPA_ON_MSK;
499
500 return 0;
501}
502
503static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast)
504{
505 u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
506 &iwm->umac_profile->sec.mcast_cipher;
507
508 if (!cipher) {
509 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
510 return 0;
511 }
512
513 IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm',
514 cipher);
515
516 switch (cipher) {
517 case IW_AUTH_CIPHER_NONE:
518 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
519 break;
520 case WLAN_CIPHER_SUITE_WEP40:
521 *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
522 break;
523 case WLAN_CIPHER_SUITE_WEP104:
524 *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
525 break;
526 case WLAN_CIPHER_SUITE_TKIP:
527 *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
528 break;
529 case WLAN_CIPHER_SUITE_CCMP:
530 *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
531 break;
532 default:
533 IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
534 return -ENOTSUPP;
535 }
536
537 return 0;
538}
539
540static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt)
541{
542 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
543
544 IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
545
546 if (key_mgt == WLAN_AKM_SUITE_8021X)
547 *auth_type = UMAC_AUTH_TYPE_8021X;
548 else if (key_mgt == WLAN_AKM_SUITE_PSK) {
549 if (iwm->umac_profile->sec.flags &
550 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
551 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
552 else
553 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
554 } else {
555 IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
556 return -EINVAL;
557 }
558
559 return 0;
560}
561
562
563static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
564 struct cfg80211_connect_params *sme)
565{
566 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
567 struct ieee80211_channel *chan = sme->channel;
568 int ret;
569
570 if (!test_bit(IWM_STATUS_READY, &iwm->status))
571 return -EIO;
572
573 if (!sme->ssid)
574 return -EINVAL;
575
576 if (chan)
577 iwm->channel =
578 ieee80211_frequency_to_channel(chan->center_freq);
579
580 iwm->umac_profile->ssid.ssid_len = sme->ssid_len;
581 memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len);
582
583 if (sme->bssid) {
584 IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid);
585 memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN);
586 iwm->umac_profile->bss_num = 1;
587 } else {
588 memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
589 iwm->umac_profile->bss_num = 0;
590 }
591
592 ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions);
593 if (ret < 0)
594 return ret;
595
596 ret = iwm_set_auth_type(iwm, sme->auth_type);
597 if (ret < 0)
598 return ret;
599
600 if (sme->crypto.n_ciphers_pairwise) {
601 ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0],
602 true);
603 if (ret < 0)
604 return ret;
605 }
606
607 ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false);
608 if (ret < 0)
609 return ret;
610
611 if (sme->crypto.n_akm_suites) {
612 ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]);
613 if (ret < 0)
614 return ret;
615 }
616
617 return iwm_send_mlme_profile(iwm);
618}
619
620static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
621 u16 reason_code)
622{
623 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
624
625 IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active);
626
627 if (iwm->umac_profile_active)
628 return iwm_invalidate_mlme_profile(iwm);
629
630 return 0;
631}
632
633static int iwm_cfg80211_set_txpower(struct wiphy *wiphy,
634 enum tx_power_setting type, int dbm)
635{
636 switch (type) {
637 case TX_POWER_AUTOMATIC:
638 return 0;
639 default:
640 return -EOPNOTSUPP;
641 }
642
643 return 0;
644}
645
646static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
647{
648 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
649
650 *dbm = iwm->txpower;
651
652 return 0;
653}
654
655static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy,
656 struct net_device *dev,
657 bool enabled, int timeout)
658{
659 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
660 u32 power_index;
661
662 if (enabled)
663 power_index = IWM_POWER_INDEX_DEFAULT;
664 else
665 power_index = IWM_POWER_INDEX_MIN;
666
667 if (power_index == iwm->conf.power_index)
668 return 0;
669
670 iwm->conf.power_index = power_index;
671
672 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
673 CFG_POWER_INDEX, iwm->conf.power_index);
674}
675
332static struct cfg80211_ops iwm_cfg80211_ops = { 676static struct cfg80211_ops iwm_cfg80211_ops = {
333 .change_virtual_intf = iwm_cfg80211_change_iface, 677 .change_virtual_intf = iwm_cfg80211_change_iface,
678 .add_key = iwm_cfg80211_add_key,
679 .get_key = iwm_cfg80211_get_key,
680 .del_key = iwm_cfg80211_del_key,
681 .set_default_key = iwm_cfg80211_set_default_key,
682 .get_station = iwm_cfg80211_get_station,
334 .scan = iwm_cfg80211_scan, 683 .scan = iwm_cfg80211_scan,
335 .set_wiphy_params = iwm_cfg80211_set_wiphy_params, 684 .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
685 .connect = iwm_cfg80211_connect,
686 .disconnect = iwm_cfg80211_disconnect,
336 .join_ibss = iwm_cfg80211_join_ibss, 687 .join_ibss = iwm_cfg80211_join_ibss,
337 .leave_ibss = iwm_cfg80211_leave_ibss, 688 .leave_ibss = iwm_cfg80211_leave_ibss,
689 .set_tx_power = iwm_cfg80211_set_txpower,
690 .get_tx_power = iwm_cfg80211_get_txpower,
691 .set_power_mgmt = iwm_cfg80211_set_power_mgmt,
692};
693
694static const u32 cipher_suites[] = {
695 WLAN_CIPHER_SUITE_WEP40,
696 WLAN_CIPHER_SUITE_WEP104,
697 WLAN_CIPHER_SUITE_TKIP,
698 WLAN_CIPHER_SUITE_CCMP,
338}; 699};
339 700
340struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) 701struct 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)
379 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; 740 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
380 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; 741 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
381 742
743 wdev->wiphy->cipher_suites = cipher_suites;
744 wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
745
382 ret = wiphy_register(wdev->wiphy); 746 ret = wiphy_register(wdev->wiphy);
383 if (ret < 0) { 747 if (ret < 0) {
384 dev_err(dev, "Couldn't register wiphy device\n"); 748 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,
70int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, 70int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size,
71 bool resp) 71 bool resp)
72{ 72{
73 struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload;
73 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; 74 struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT;
74 struct iwm_umac_cmd umac_cmd; 75 struct iwm_umac_cmd umac_cmd;
76 int ret;
77 u8 oid = hdr->oid;
75 78
76 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; 79 umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER;
77 umac_cmd.resp = resp; 80 umac_cmd.resp = resp;
78 81
79 return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, 82 ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd,
80 payload, payload_size); 83 payload, payload_size);
84
85 if (resp) {
86 ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue,
87 test_and_clear_bit(oid, &iwm->wifi_ntfy[0]),
88 3 * HZ);
89
90 return ret ? 0 : -EBUSY;
91 }
92
93 return ret;
81} 94}
82 95
83static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = 96static 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] =
106 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, 119 {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS},
107 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, 120 {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS},
108 {5, 5, 0, COEX_CALIBRATION_FLAGS}, 121 {5, 5, 0, COEX_CALIBRATION_FLAGS},
109 {4, 4, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, 122 {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS},
110 {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS}, 123 {5, 4, 0, COEX_CONNECTION_ESTAB_FLAGS},
111 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, 124 {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS},
112 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, 125 {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS},
@@ -332,8 +345,7 @@ int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key,
332 return ret; 345 return ret;
333} 346}
334 347
335int iwm_send_umac_config(struct iwm_priv *iwm, 348int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags)
336 __le32 reset_flags)
337{ 349{
338 int ret; 350 int ret;
339 351
@@ -361,6 +373,12 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
361 return ret; 373 return ret;
362 374
363 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 375 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
376 CFG_WIRELESS_MODE,
377 iwm->conf.wireless_mode);
378 if (ret < 0)
379 return ret;
380
381 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
364 CFG_COEX_MODE, iwm->conf.coexist_mode); 382 CFG_COEX_MODE, iwm->conf.coexist_mode);
365 if (ret < 0) 383 if (ret < 0)
366 return ret; 384 return ret;
@@ -402,7 +420,7 @@ int iwm_send_umac_config(struct iwm_priv *iwm,
402 return ret; 420 return ret;
403 421
404 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, 422 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
405 CFG_PM_CTRL_FLAGS, 0x30001); 423 CFG_PM_CTRL_FLAGS, 0x1);
406 if (ret < 0) 424 if (ret < 0)
407 return ret; 425 return ret;
408 426
@@ -462,8 +480,10 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
462 target_cmd.eop = 1; 480 target_cmd.eop = 1;
463 481
464 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); 482 ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL);
465 if (ret < 0) 483 if (ret < 0) {
466 IWM_ERR(iwm, "Couldn't send READ command\n"); 484 IWM_ERR(iwm, "Couldn't send READ command\n");
485 return ret;
486 }
467 487
468 /* When succeding, the send_target routine returns the seq number */ 488 /* When succeding, the send_target routine returns the seq number */
469 seq_num = ret; 489 seq_num = ret;
@@ -483,7 +503,7 @@ static int iwm_target_read(struct iwm_priv *iwm, __le32 address,
483 503
484 kfree(cmd); 504 kfree(cmd);
485 505
486 return ret; 506 return 0;
487} 507}
488 508
489int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) 509int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
@@ -493,7 +513,7 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
493 513
494 ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), 514 ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR),
495 mac_align, sizeof(mac_align)); 515 mac_align, sizeof(mac_align));
496 if (ret < 0) 516 if (ret)
497 return ret; 517 return ret;
498 518
499 if (is_valid_ether_addr(mac_align)) 519 if (is_valid_ether_addr(mac_align))
@@ -507,22 +527,6 @@ int iwm_read_mac(struct iwm_priv *iwm, u8 *mac)
507 return 0; 527 return 0;
508} 528}
509 529
510int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
511{
512 struct iwm_umac_tx_key_id tx_key_id;
513
514 if (!iwm->default_key || !iwm->default_key->in_use)
515 return -EINVAL;
516
517 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
518 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
519 sizeof(struct iwm_umac_wifi_if));
520
521 tx_key_id.key_idx = key_idx;
522
523 return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
524}
525
526static int iwm_check_profile(struct iwm_priv *iwm) 530static int iwm_check_profile(struct iwm_priv *iwm)
527{ 531{
528 if (!iwm->umac_profile_active) 532 if (!iwm->umac_profile_active)
@@ -556,10 +560,35 @@ static int iwm_check_profile(struct iwm_priv *iwm)
556 return 0; 560 return 0;
557} 561}
558 562
559int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, 563int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
560 struct iwm_key *key)
561{ 564{
565 struct iwm_umac_tx_key_id tx_key_id;
562 int ret; 566 int ret;
567
568 ret = iwm_check_profile(iwm);
569 if (ret < 0)
570 return ret;
571
572 /* UMAC only allows to set default key for WEP and auth type is
573 * NOT 802.1X or RSNA. */
574 if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 &&
575 iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) ||
576 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X ||
577 iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK)
578 return 0;
579
580 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
581 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
582 sizeof(struct iwm_umac_wifi_if));
583
584 tx_key_id.key_idx = key_idx;
585
586 return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1);
587}
588
589int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
590{
591 int ret = 0;
563 u8 cmd[64], *sta_addr, *key_data, key_len; 592 u8 cmd[64], *sta_addr, *key_data, key_len;
564 s8 key_idx; 593 s8 key_idx;
565 u16 cmd_size = 0; 594 u16 cmd_size = 0;
@@ -569,15 +598,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
569 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; 598 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
570 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; 599 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
571 600
572 if (set_tx_key)
573 iwm->default_key = key;
574
575 /*
576 * We check if our current profile is valid.
577 * If not, we dont push the key, we just cache them,
578 * so that with the next siwsessid call, the keys
579 * will be actually pushed.
580 */
581 if (!remove) { 601 if (!remove) {
582 ret = iwm_check_profile(iwm); 602 ret = iwm_check_profile(iwm);
583 if (ret < 0) 603 if (ret < 0)
@@ -590,8 +610,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
590 key_idx = key->hdr.key_idx; 610 key_idx = key->hdr.key_idx;
591 611
592 if (!remove) { 612 if (!remove) {
593 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", 613 u8 auth_type = iwm->umac_profile->sec.auth_type;
594 key_idx, set_tx_key); 614
615 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
595 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); 616 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
596 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", 617 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
597 key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); 618 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,
603 iwm->umac_profile->sec.auth_type, 624 iwm->umac_profile->sec.auth_type,
604 iwm->umac_profile->sec.flags); 625 iwm->umac_profile->sec.flags);
605 626
606 switch (key->alg) { 627 switch (key->cipher) {
607 case UMAC_CIPHER_TYPE_WEP_40: 628 case WLAN_CIPHER_SUITE_WEP40:
608 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; 629 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
609 wep40->hdr.buf_size = 630 wep40->hdr.buf_size =
610 cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - 631 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,
613 memcpy(&wep40->key_hdr, key_hdr, 634 memcpy(&wep40->key_hdr, key_hdr,
614 sizeof(struct iwm_umac_key_hdr)); 635 sizeof(struct iwm_umac_key_hdr));
615 memcpy(wep40->key, key_data, key_len); 636 memcpy(wep40->key, key_data, key_len);
616 wep40->static_key = 1; 637 wep40->static_key =
638 !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
639 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
617 640
618 cmd_size = sizeof(struct iwm_umac_key_wep40); 641 cmd_size = sizeof(struct iwm_umac_key_wep40);
619 break; 642 break;
620 643
621 case UMAC_CIPHER_TYPE_WEP_104: 644 case WLAN_CIPHER_SUITE_WEP104:
622 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; 645 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
623 wep104->hdr.buf_size = 646 wep104->hdr.buf_size =
624 cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - 647 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,
627 memcpy(&wep104->key_hdr, key_hdr, 650 memcpy(&wep104->key_hdr, key_hdr,
628 sizeof(struct iwm_umac_key_hdr)); 651 sizeof(struct iwm_umac_key_hdr));
629 memcpy(wep104->key, key_data, key_len); 652 memcpy(wep104->key, key_data, key_len);
630 wep104->static_key = 1; 653 wep104->static_key =
654 !!((auth_type != UMAC_AUTH_TYPE_8021X) &&
655 (auth_type != UMAC_AUTH_TYPE_RSNA_PSK));
631 656
632 cmd_size = sizeof(struct iwm_umac_key_wep104); 657 cmd_size = sizeof(struct iwm_umac_key_wep104);
633 break; 658 break;
634 659
635 case UMAC_CIPHER_TYPE_CCMP: 660 case WLAN_CIPHER_SUITE_CCMP:
636 key_hdr->key_idx++; 661 key_hdr->key_idx++;
637 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; 662 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
638 ccmp->hdr.buf_size = 663 ccmp->hdr.buf_size =
@@ -644,13 +669,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
644 669
645 memcpy(ccmp->key, key_data, key_len); 670 memcpy(ccmp->key, key_data, key_len);
646 671
647 if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) 672 if (key->seq_len)
648 memcpy(ccmp->iv_count, key->rx_seq, 6); 673 memcpy(ccmp->iv_count, key->seq, key->seq_len);
649 674
650 cmd_size = sizeof(struct iwm_umac_key_ccmp); 675 cmd_size = sizeof(struct iwm_umac_key_ccmp);
651 break; 676 break;
652 677
653 case UMAC_CIPHER_TYPE_TKIP: 678 case WLAN_CIPHER_SUITE_TKIP:
654 key_hdr->key_idx++; 679 key_hdr->key_idx++;
655 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; 680 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
656 tkip->hdr.buf_size = 681 tkip->hdr.buf_size =
@@ -667,8 +692,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
667 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, 692 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
668 IWM_TKIP_MIC_SIZE); 693 IWM_TKIP_MIC_SIZE);
669 694
670 if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) 695 if (key->seq_len)
671 memcpy(ccmp->iv_count, key->rx_seq, 6); 696 memcpy(ccmp->iv_count, key->seq, key->seq_len);
672 697
673 cmd_size = sizeof(struct iwm_umac_key_tkip); 698 cmd_size = sizeof(struct iwm_umac_key_tkip);
674 break; 699 break;
@@ -677,8 +702,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
677 return -ENOTSUPP; 702 return -ENOTSUPP;
678 } 703 }
679 704
680 if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || 705 if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
681 (key->alg == UMAC_CIPHER_TYPE_TKIP)) 706 (key->cipher == WLAN_CIPHER_SUITE_CCMP))
682 /* 707 /*
683 * UGLY_UGLY_UGLY 708 * UGLY_UGLY_UGLY
684 * Copied HACK from the MWG driver. 709 * Copied HACK from the MWG driver.
@@ -689,23 +714,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
689 schedule_timeout_interruptible(usecs_to_jiffies(300)); 714 schedule_timeout_interruptible(usecs_to_jiffies(300));
690 715
691 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); 716 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
692 if (ret < 0)
693 goto err;
694
695 /*
696 * We need a default key only if it is set and
697 * if we're doing WEP.
698 */
699 if (iwm->default_key == key &&
700 ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
701 (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
702 ret = iwm_set_tx_key(iwm, key_idx);
703 if (ret < 0)
704 goto err;
705 }
706 } else { 717 } else {
707 struct iwm_umac_key_remove key_remove; 718 struct iwm_umac_key_remove key_remove;
708 719
720 IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
721
709 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; 722 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
710 key_remove.hdr.buf_size = 723 key_remove.hdr.buf_size =
711 cpu_to_le16(sizeof(struct iwm_umac_key_remove) - 724 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,
716 ret = iwm_send_wifi_if_cmd(iwm, &key_remove, 729 ret = iwm_send_wifi_if_cmd(iwm, &key_remove,
717 sizeof(struct iwm_umac_key_remove), 730 sizeof(struct iwm_umac_key_remove),
718 1); 731 1);
719 if (ret < 0) 732 if (ret)
720 return ret; 733 return ret;
721 734
722 iwm->keys[key_idx].in_use = 0; 735 iwm->keys[key_idx].key_len = 0;
723 } 736 }
724 737
725 return 0;
726
727 err:
728 kfree(key);
729 return ret; 738 return ret;
730} 739}
731 740
732 741
733int iwm_send_mlme_profile(struct iwm_priv *iwm) 742int iwm_send_mlme_profile(struct iwm_priv *iwm)
734{ 743{
735 int ret, i; 744 int ret;
736 struct iwm_umac_profile profile; 745 struct iwm_umac_profile profile;
737 746
738 memcpy(&profile, iwm->umac_profile, sizeof(profile)); 747 memcpy(&profile, iwm->umac_profile, sizeof(profile));
@@ -742,45 +751,18 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
742 sizeof(struct iwm_umac_wifi_if)); 751 sizeof(struct iwm_umac_wifi_if));
743 752
744 ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); 753 ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1);
745 if (ret < 0) { 754 if (ret) {
746 IWM_ERR(iwm, "Send profile command failed\n"); 755 IWM_ERR(iwm, "Send profile command failed\n");
747 return ret; 756 return ret;
748 } 757 }
749 758
750 /* Wait for the profile to be active */
751 ret = wait_event_interruptible_timeout(iwm->mlme_queue,
752 iwm->umac_profile_active == 1,
753 3 * HZ);
754 if (!ret)
755 return -EBUSY;
756
757
758 for (i = 0; i < IWM_NUM_KEYS; i++)
759 if (iwm->keys[i].in_use) {
760 int default_key = 0;
761 struct iwm_key *key = &iwm->keys[i];
762
763 if (key == iwm->default_key)
764 default_key = 1;
765
766 /* Wait for the profile before sending the keys */
767 wait_event_interruptible_timeout(iwm->mlme_queue,
768 (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
769 test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
770 3 * HZ);
771
772 ret = iwm_set_key(iwm, 0, default_key, key);
773 if (ret < 0)
774 return ret;
775 }
776
777 return 0; 759 return 0;
778} 760}
779 761
780int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) 762int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
781{ 763{
782 int ret;
783 struct iwm_umac_invalidate_profile invalid; 764 struct iwm_umac_invalidate_profile invalid;
765 int ret;
784 766
785 invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; 767 invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE;
786 invalid.hdr.buf_size = 768 invalid.hdr.buf_size =
@@ -790,16 +772,13 @@ int iwm_invalidate_mlme_profile(struct iwm_priv *iwm)
790 invalid.reason = WLAN_REASON_UNSPECIFIED; 772 invalid.reason = WLAN_REASON_UNSPECIFIED;
791 773
792 ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); 774 ret = iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1);
793 if (ret < 0) 775 if (ret)
794 return ret; 776 return ret;
795 777
796 ret = wait_event_interruptible_timeout(iwm->mlme_queue, 778 ret = wait_event_interruptible_timeout(iwm->mlme_queue,
797 (iwm->umac_profile_active == 0), 779 (iwm->umac_profile_active == 0), 2 * HZ);
798 2 * HZ);
799 if (!ret)
800 return -EBUSY;
801 780
802 return 0; 781 return ret ? 0 : -EBUSY;
803} 782}
804 783
805int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) 784int 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,
882 } 861 }
883 862
884 ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); 863 ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0);
885 if (ret < 0) { 864 if (ret) {
886 IWM_ERR(iwm, "Couldn't send scan request\n"); 865 IWM_ERR(iwm, "Couldn't send scan request\n");
887 return ret; 866 return ret;
888 } 867 }
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 {
106 CFG_TLC_SPATIAL_STREAM_SUPPORTED, 106 CFG_TLC_SPATIAL_STREAM_SUPPORTED,
107 CFG_TLC_RETRY_PER_RATE, 107 CFG_TLC_RETRY_PER_RATE,
108 CFG_TLC_RETRY_PER_HT_RATE, 108 CFG_TLC_RETRY_PER_HT_RATE,
109 CFG_TLC_FIXED_RATE, 109 CFG_TLC_FIXED_MCS,
110 CFG_TLC_FIXED_RATE_FLAGS,
111 CFG_TLC_CONTROL_FLAGS, 110 CFG_TLC_CONTROL_FLAGS,
112 CFG_TLC_SR_MIN_FAIL, 111 CFG_TLC_SR_MIN_FAIL,
113 CFG_TLC_SR_MIN_PASS, 112 CFG_TLC_SR_MIN_PASS,
@@ -232,6 +231,7 @@ struct iwm_umac_cmd_get_channel_list {
232/* Wireless mode */ 231/* Wireless mode */
233#define WIRELESS_MODE_11A 0x1 232#define WIRELESS_MODE_11A 0x1
234#define WIRELESS_MODE_11G 0x2 233#define WIRELESS_MODE_11G 0x2
234#define WIRELESS_MODE_11N 0x4
235 235
236#define UMAC_PROFILE_EX_IE_REQUIRED 0x1 236#define UMAC_PROFILE_EX_IE_REQUIRED 0x1
237#define UMAC_PROFILE_QOS_ALLOWED 0x2 237#define UMAC_PROFILE_QOS_ALLOWED 0x2
@@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
406int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); 406int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
407int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); 407int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
408int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); 408int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
409int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, 409int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
410 struct iwm_key *key);
411int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); 410int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
412int iwm_send_umac_channel_list(struct iwm_priv *iwm); 411int iwm_send_umac_channel_list(struct iwm_priv *iwm);
413int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, 412int 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)
156 return -ENOMEM; 156 return -ENOMEM;
157 157
158 for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { 158 for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) {
159#ifdef CONFIG_IWM_B0_HW_SUPPORT
160 if (iwm->conf.hw_b0 && (i >= IWM_EEPROM_INDIRECT_OFFSET))
161 break;
162#endif
163 ret = iwm_eeprom_read(iwm, i); 159 ret = iwm_eeprom_read(iwm, i);
164 if (ret < 0) { 160 if (ret < 0) {
165 IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", 161 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)
275 */ 275 */
276int iwm_load_fw(struct iwm_priv *iwm) 276int iwm_load_fw(struct iwm_priv *iwm)
277{ 277{
278 unsigned long init_calib_map, periodic_calib_map;
278 int ret; 279 int ret;
279 280
280 /* We first start downloading the UMAC */ 281 /* We first start downloading the UMAC */
@@ -315,23 +316,19 @@ int iwm_load_fw(struct iwm_priv *iwm)
315 return ret; 316 return ret;
316 } 317 }
317 318
318#ifdef CONFIG_IWM_B0_HW_SUPPORT 319 init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK;
319 if (iwm->conf.hw_b0) { 320 periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map);
320 clear_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map); 321
321 clear_bit(PHY_CALIBRATE_RX_IQ_CMD,
322 &iwm->conf.periodic_calib_map);
323 }
324#endif
325 /* Read RX IQ calibration result from EEPROM */ 322 /* Read RX IQ calibration result from EEPROM */
326 if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->conf.init_calib_map)) { 323 if (test_bit(PHY_CALIBRATE_RX_IQ_CMD, &init_calib_map)) {
327 iwm_store_rxiq_calib_result(iwm); 324 iwm_store_rxiq_calib_result(iwm);
328 set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); 325 set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map);
329 } 326 }
330 327
331 iwm_send_prio_table(iwm); 328 iwm_send_prio_table(iwm);
332 iwm_send_init_calib_cfg(iwm, iwm->conf.init_calib_map); 329 iwm_send_init_calib_cfg(iwm, init_calib_map);
333 330
334 while (iwm->calib_done_map != iwm->conf.init_calib_map) { 331 while (iwm->calib_done_map != init_calib_map) {
335 ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, 332 ret = iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION,
336 IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); 333 IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT);
337 if (ret) { 334 if (ret) {
@@ -340,7 +337,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
340 } 337 }
341 IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " 338 IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: "
342 "0x%lx, requested calibrations: 0x%lx\n", 339 "0x%lx, requested calibrations: 0x%lx\n",
343 iwm->calib_done_map, iwm->conf.init_calib_map); 340 iwm->calib_done_map, init_calib_map);
344 } 341 }
345 342
346 /* Handle LMAC CALIBRATION_COMPLETE notification */ 343 /* Handle LMAC CALIBRATION_COMPLETE notification */
@@ -378,7 +375,7 @@ int iwm_load_fw(struct iwm_priv *iwm)
378 375
379 iwm_send_prio_table(iwm); 376 iwm_send_prio_table(iwm);
380 iwm_send_calib_results(iwm); 377 iwm_send_calib_results(iwm);
381 iwm_send_periodic_calib_cfg(iwm, iwm->conf.periodic_calib_map); 378 iwm_send_periodic_calib_cfg(iwm, periodic_calib_map);
382 379
383 return 0; 380 return 0;
384 381
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 @@
105#include "umac.h" 105#include "umac.h"
106#include "debug.h" 106#include "debug.h"
107 107
108static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm, 108static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
109 struct iwm_nonwifi_cmd *cmd, 109 struct iwm_nonwifi_cmd *cmd,
110 struct iwm_udma_nonwifi_cmd *udma_cmd) 110 struct iwm_udma_nonwifi_cmd *udma_cmd)
111{ 111{
112 INIT_LIST_HEAD(&cmd->pending); 112 INIT_LIST_HEAD(&cmd->pending);
113 113
@@ -118,7 +118,7 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
118 cmd->seq_num = iwm->nonwifi_seq_num; 118 cmd->seq_num = iwm->nonwifi_seq_num;
119 udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); 119 udma_cmd->seq_num = cpu_to_le16(cmd->seq_num);
120 120
121 cmd->seq_num = iwm->nonwifi_seq_num++; 121 iwm->nonwifi_seq_num++;
122 iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; 122 iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX;
123 123
124 if (udma_cmd->resp) 124 if (udma_cmd->resp)
@@ -130,6 +130,8 @@ static void iwm_nonwifi_cmd_init(struct iwm_priv *iwm,
130 cmd->buf.len = 0; 130 cmd->buf.len = 0;
131 131
132 memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); 132 memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd));
133
134 return cmd->seq_num;
133} 135}
134 136
135u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) 137u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm)
@@ -369,7 +371,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
369 const void *payload) 371 const void *payload)
370{ 372{
371 struct iwm_nonwifi_cmd *cmd; 373 struct iwm_nonwifi_cmd *cmd;
372 int ret; 374 int ret, seq_num;
373 375
374 cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); 376 cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL);
375 if (!cmd) { 377 if (!cmd) {
@@ -377,7 +379,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
377 return -ENOMEM; 379 return -ENOMEM;
378 } 380 }
379 381
380 iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); 382 seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd);
381 383
382 if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || 384 if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE ||
383 cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { 385 cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) {
@@ -393,7 +395,7 @@ int iwm_hal_send_target_cmd(struct iwm_priv *iwm,
393 if (ret < 0) 395 if (ret < 0)
394 return ret; 396 return ret;
395 397
396 return cmd->seq_num; 398 return seq_num;
397} 399}
398 400
399static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, 401static 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 @@
52#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" 52#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation"
53#define IWM_AUTHOR "<ilw@linux.intel.com>" 53#define IWM_AUTHOR "<ilw@linux.intel.com>"
54 54
55#define CONFIG_IWM_B0_HW_SUPPORT 1
56
57#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX 55#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX
58#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA 56#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA
59#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW 57#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW
@@ -65,8 +63,7 @@
65 63
66struct iwm_conf { 64struct iwm_conf {
67 u32 sdio_ior_timeout; 65 u32 sdio_ior_timeout;
68 unsigned long init_calib_map; 66 unsigned long calib_map;
69 unsigned long periodic_calib_map;
70 bool reset_on_fatal_err; 67 bool reset_on_fatal_err;
71 bool auto_connect; 68 bool auto_connect;
72 bool wimax_not_present; 69 bool wimax_not_present;
@@ -87,9 +84,6 @@ struct iwm_conf {
87 u8 ibss_channel; 84 u8 ibss_channel;
88 85
89 u8 mac_addr[ETH_ALEN]; 86 u8 mac_addr[ETH_ALEN];
90#ifdef CONFIG_IWM_B0_HW_SUPPORT
91 bool hw_b0;
92#endif
93}; 87};
94 88
95enum { 89enum {
@@ -162,13 +156,11 @@ struct iwm_umac_key_hdr {
162 156
163struct iwm_key { 157struct iwm_key {
164 struct iwm_umac_key_hdr hdr; 158 struct iwm_umac_key_hdr hdr;
165 u8 in_use; 159 u32 cipher;
166 u8 alg; 160 u8 key[WLAN_MAX_KEY_LEN];
167 u32 flags; 161 u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
168 u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; 162 int key_len;
169 u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; 163 int seq_len;
170 u8 key_len;
171 u8 key[32];
172}; 164};
173 165
174#define IWM_RX_ID_HASH 0xff 166#define IWM_RX_ID_HASH 0xff
@@ -186,10 +178,6 @@ struct iwm_key {
186#define IWM_STATUS_ASSOCIATING 3 178#define IWM_STATUS_ASSOCIATING 3
187#define IWM_STATUS_ASSOCIATED 4 179#define IWM_STATUS_ASSOCIATED 4
188 180
189#define IWM_RADIO_RFKILL_OFF 0
190#define IWM_RADIO_RFKILL_HW 1
191#define IWM_RADIO_RFKILL_SW 2
192
193struct iwm_tx_queue { 181struct iwm_tx_queue {
194 int id; 182 int id;
195 struct sk_buff_head queue; 183 struct sk_buff_head queue;
@@ -223,7 +211,6 @@ struct iwm_priv {
223 struct iwm_conf conf; 211 struct iwm_conf conf;
224 212
225 unsigned long status; 213 unsigned long status;
226 unsigned long radio;
227 214
228 struct list_head pending_notif; 215 struct list_head pending_notif;
229 wait_queue_head_t notif_queue; 216 wait_queue_head_t notif_queue;
@@ -242,6 +229,7 @@ struct iwm_priv {
242 u8 bssid[ETH_ALEN]; 229 u8 bssid[ETH_ALEN];
243 u8 channel; 230 u8 channel;
244 u16 rate; 231 u16 rate;
232 u32 txpower;
245 233
246 struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; 234 struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM];
247 struct list_head bss_list; 235 struct list_head bss_list;
@@ -276,7 +264,10 @@ struct iwm_priv {
276 struct iwm_tx_queue txq[IWM_TX_QUEUES]; 264 struct iwm_tx_queue txq[IWM_TX_QUEUES];
277 265
278 struct iwm_key keys[IWM_NUM_KEYS]; 266 struct iwm_key keys[IWM_NUM_KEYS];
279 struct iwm_key *default_key; 267 s8 default_key;
268
269 DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
270 wait_queue_head_t wifi_ntfy_queue;
280 271
281 wait_queue_head_t mlme_queue; 272 wait_queue_head_t mlme_queue;
282 273
@@ -289,7 +280,11 @@ struct iwm_priv {
289 struct timer_list watchdog; 280 struct timer_list watchdog;
290 struct work_struct reset_worker; 281 struct work_struct reset_worker;
291 struct mutex mutex; 282 struct mutex mutex;
292 struct rfkill *rfkill; 283
284 u8 *req_ie;
285 int req_ie_len;
286 u8 *resp_ie;
287 int resp_ie_len;
293 288
294 char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); 289 char private[0] __attribute__((__aligned__(NETDEV_ALIGN)));
295}; 290};
@@ -311,8 +306,6 @@ static inline void *iwm_private(struct iwm_priv *iwm)
311#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) 306#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb))
312#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) 307#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb)
313 308
314extern const struct iw_handler_def iwm_iw_handler_def;
315
316void *iwm_if_alloc(int sizeof_bus, struct device *dev, 309void *iwm_if_alloc(int sizeof_bus, struct device *dev,
317 struct iwm_if_ops *if_ops); 310 struct iwm_if_ops *if_ops);
318void iwm_if_free(struct iwm_priv *iwm); 311void 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 {
396 CALIBRATION_CMD_NUM, 396 CALIBRATION_CMD_NUM,
397}; 397};
398 398
399#define IWM_CALIB_MAP_INIT_MSK 0xFFFF
400#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16)
401#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24)
402
399struct iwm_lmac_calib_hdr { 403struct iwm_lmac_calib_hdr {
400 u8 opcode; 404 u8 opcode;
401 u8 first_grp; 405 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 @@
53static struct iwm_conf def_iwm_conf = { 53static struct iwm_conf def_iwm_conf = {
54 54
55 .sdio_ior_timeout = 5000, 55 .sdio_ior_timeout = 5000,
56 .init_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | 56 .calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
57 BIT(PHY_CALIBRATE_LO_CMD) |
58 BIT(PHY_CALIBRATE_TX_IQ_CMD) |
59 BIT(PHY_CALIBRATE_RX_IQ_CMD),
60 .periodic_calib_map = BIT(PHY_CALIBRATE_DC_CMD) |
61 BIT(PHY_CALIBRATE_LO_CMD) | 57 BIT(PHY_CALIBRATE_LO_CMD) |
62 BIT(PHY_CALIBRATE_TX_IQ_CMD) | 58 BIT(PHY_CALIBRATE_TX_IQ_CMD) |
63 BIT(PHY_CALIBRATE_RX_IQ_CMD) | 59 BIT(PHY_CALIBRATE_RX_IQ_CMD) |
@@ -191,6 +187,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
191 INIT_LIST_HEAD(&iwm->pending_notif); 187 INIT_LIST_HEAD(&iwm->pending_notif);
192 init_waitqueue_head(&iwm->notif_queue); 188 init_waitqueue_head(&iwm->notif_queue);
193 init_waitqueue_head(&iwm->nonwifi_queue); 189 init_waitqueue_head(&iwm->nonwifi_queue);
190 init_waitqueue_head(&iwm->wifi_ntfy_queue);
194 init_waitqueue_head(&iwm->mlme_queue); 191 init_waitqueue_head(&iwm->mlme_queue);
195 memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); 192 memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf));
196 spin_lock_init(&iwm->tx_credit.lock); 193 spin_lock_init(&iwm->tx_credit.lock);
@@ -229,7 +226,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
229 for (i = 0; i < IWM_NUM_KEYS; i++) 226 for (i = 0; i < IWM_NUM_KEYS; i++)
230 memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); 227 memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
231 228
232 iwm->default_key = NULL; 229 iwm->default_key = -1;
233 230
234 init_timer(&iwm->watchdog); 231 init_timer(&iwm->watchdog);
235 iwm->watchdog.function = iwm_watchdog; 232 iwm->watchdog.function = iwm_watchdog;
@@ -500,6 +497,13 @@ void iwm_link_off(struct iwm_priv *iwm)
500 memset(wstats, 0, sizeof(struct iw_statistics)); 497 memset(wstats, 0, sizeof(struct iw_statistics));
501 wstats->qual.updated = IW_QUAL_ALL_INVALID; 498 wstats->qual.updated = IW_QUAL_ALL_INVALID;
502 499
500 kfree(iwm->req_ie);
501 iwm->req_ie = NULL;
502 iwm->req_ie_len = 0;
503 kfree(iwm->resp_ie);
504 iwm->resp_ie = NULL;
505 iwm->resp_ie_len = 0;
506
503 del_timer_sync(&iwm->watchdog); 507 del_timer_sync(&iwm->watchdog);
504} 508}
505 509
@@ -518,13 +522,6 @@ static int iwm_channels_init(struct iwm_priv *iwm)
518{ 522{
519 int ret; 523 int ret;
520 524
521#ifdef CONFIG_IWM_B0_HW_SUPPORT
522 if (iwm->conf.hw_b0) {
523 IWM_INFO(iwm, "Workaround EEPROM channels for B0 hardware\n");
524 return 0;
525 }
526#endif
527
528 ret = iwm_send_umac_channel_list(iwm); 525 ret = iwm_send_umac_channel_list(iwm);
529 if (ret) { 526 if (ret) {
530 IWM_ERR(iwm, "Send channel list failed\n"); 527 IWM_ERR(iwm, "Send channel list failed\n");
@@ -642,19 +639,10 @@ int __iwm_up(struct iwm_priv *iwm)
642 } 639 }
643 } 640 }
644 641
645 iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
646 GFP_KERNEL);
647 if (!iwm->umac_profile) {
648 IWM_ERR(iwm, "Couldn't alloc memory for profile\n");
649 goto err_fw;
650 }
651
652 iwm_init_default_profile(iwm, iwm->umac_profile);
653
654 ret = iwm_channels_init(iwm); 642 ret = iwm_channels_init(iwm);
655 if (ret < 0) { 643 if (ret < 0) {
656 IWM_ERR(iwm, "Couldn't init channels\n"); 644 IWM_ERR(iwm, "Couldn't init channels\n");
657 goto err_profile; 645 goto err_fw;
658 } 646 }
659 647
660 /* Set the READY bit to indicate interface is brought up successfully */ 648 /* Set the READY bit to indicate interface is brought up successfully */
@@ -662,10 +650,6 @@ int __iwm_up(struct iwm_priv *iwm)
662 650
663 return 0; 651 return 0;
664 652
665 err_profile:
666 kfree(iwm->umac_profile);
667 iwm->umac_profile = NULL;
668
669 err_fw: 653 err_fw:
670 iwm_eeprom_exit(iwm); 654 iwm_eeprom_exit(iwm);
671 655
@@ -704,11 +688,10 @@ int __iwm_down(struct iwm_priv *iwm)
704 clear_bit(IWM_STATUS_READY, &iwm->status); 688 clear_bit(IWM_STATUS_READY, &iwm->status);
705 689
706 iwm_eeprom_exit(iwm); 690 iwm_eeprom_exit(iwm);
707 kfree(iwm->umac_profile);
708 iwm->umac_profile = NULL;
709 iwm_bss_list_clean(iwm); 691 iwm_bss_list_clean(iwm);
710 692 iwm_init_default_profile(iwm, iwm->umac_profile);
711 iwm->default_key = NULL; 693 iwm->umac_profile_active = false;
694 iwm->default_key = -1;
712 iwm->core_enabled = 0; 695 iwm->core_enabled = 0;
713 696
714 ret = iwm_bus_disable(iwm); 697 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 @@
48#include <linux/netdevice.h> 48#include <linux/netdevice.h>
49 49
50#include "iwm.h" 50#include "iwm.h"
51#include "commands.h"
51#include "cfg80211.h" 52#include "cfg80211.h"
52#include "debug.h" 53#include "debug.h"
53 54
54static int iwm_open(struct net_device *ndev) 55static int iwm_open(struct net_device *ndev)
55{ 56{
56 struct iwm_priv *iwm = ndev_to_iwm(ndev); 57 struct iwm_priv *iwm = ndev_to_iwm(ndev);
57 int ret = 0;
58
59 if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
60 ret = iwm_up(iwm);
61 58
62 return ret; 59 return iwm_up(iwm);
63} 60}
64 61
65static int iwm_stop(struct net_device *ndev) 62static int iwm_stop(struct net_device *ndev)
66{ 63{
67 struct iwm_priv *iwm = ndev_to_iwm(ndev); 64 struct iwm_priv *iwm = ndev_to_iwm(ndev);
68 int ret = 0;
69
70 if (!test_bit(IWM_RADIO_RFKILL_SW, &iwm->radio))
71 ret = iwm_down(iwm);
72 65
73 return ret; 66 return iwm_down(iwm);
74} 67}
75 68
76/* 69/*
@@ -128,13 +121,24 @@ void *iwm_if_alloc(int sizeof_bus, struct device *dev,
128 } 121 }
129 122
130 ndev->netdev_ops = &iwm_netdev_ops; 123 ndev->netdev_ops = &iwm_netdev_ops;
131 ndev->wireless_handlers = &iwm_iw_handler_def;
132 ndev->ieee80211_ptr = wdev; 124 ndev->ieee80211_ptr = wdev;
133 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); 125 SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
134 wdev->netdev = ndev; 126 wdev->netdev = ndev;
135 127
128 iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile),
129 GFP_KERNEL);
130 if (!iwm->umac_profile) {
131 dev_err(dev, "Couldn't alloc memory for profile\n");
132 goto out_profile;
133 }
134
135 iwm_init_default_profile(iwm, iwm->umac_profile);
136
136 return iwm; 137 return iwm;
137 138
139 out_profile:
140 free_netdev(ndev);
141
138 out_priv: 142 out_priv:
139 iwm_priv_deinit(iwm); 143 iwm_priv_deinit(iwm);
140 144
@@ -150,6 +154,8 @@ void iwm_if_free(struct iwm_priv *iwm)
150 154
151 free_netdev(iwm_to_ndev(iwm)); 155 free_netdev(iwm_to_ndev(iwm));
152 iwm_priv_deinit(iwm); 156 iwm_priv_deinit(iwm);
157 kfree(iwm->umac_profile);
158 iwm->umac_profile = NULL;
153 iwm_wdev_free(iwm); 159 iwm_wdev_free(iwm);
154} 160}
155 161
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,
102 error = (struct iwm_umac_notif_error *)buf; 102 error = (struct iwm_umac_notif_error *)buf;
103 fw_err = &error->err; 103 fw_err = &error->err;
104 104
105
106 IWM_ERR(iwm, "%cMAC FW ERROR:\n", 105 IWM_ERR(iwm, "%cMAC FW ERROR:\n",
107 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); 106 (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U');
108 IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); 107 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,
143 unsigned long buf_size, 142 unsigned long buf_size,
144 struct iwm_wifi_cmd *cmd) 143 struct iwm_wifi_cmd *cmd)
145{ 144{
145 struct wiphy *wiphy = iwm_to_wiphy(iwm);
146 struct iwm_umac_notif_init_complete *init_complete = 146 struct iwm_umac_notif_init_complete *init_complete =
147 (struct iwm_umac_notif_init_complete *)(buf); 147 (struct iwm_umac_notif_init_complete *)(buf);
148 u16 status = le16_to_cpu(init_complete->status); 148 u16 status = le16_to_cpu(init_complete->status);
149 bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR);
149 150
150 if (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR) { 151 if (blocked)
151 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); 152 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n");
152 set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); 153 else
153 } else {
154 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); 154 IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n");
155 clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio); 155
156 } 156 wiphy_rfkill_set_hw_state(wiphy, blocked);
157 157
158 return 0; 158 return 0;
159} 159}
@@ -218,17 +218,17 @@ static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf,
218 (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 218 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
219 hdr = (struct iwm_umac_wifi_in_hdr *)buf; 219 hdr = (struct iwm_umac_wifi_in_hdr *)buf;
220 220
221 IWM_DBG_NTF(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); 221 IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size);
222 222
223 IWM_DBG_NTF(iwm, DBG, "Seqnum: %d\n", 223 IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n",
224 le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); 224 le16_to_cpu(hdr->sw_hdr.cmd.seq_num));
225 IWM_DBG_NTF(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); 225 IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt);
226 IWM_DBG_NTF(iwm, DBG, "\tRetry cnt: %d\n", 226 IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n",
227 le16_to_cpu(tx_resp->retry_cnt)); 227 le16_to_cpu(tx_resp->retry_cnt));
228 IWM_DBG_NTF(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); 228 IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl));
229 IWM_DBG_NTF(iwm, DBG, "\tByte cnt: %d\n", 229 IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n",
230 le16_to_cpu(tx_resp->byte_cnt)); 230 le16_to_cpu(tx_resp->byte_cnt));
231 IWM_DBG_NTF(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); 231 IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status));
232 232
233 return 0; 233 return 0;
234} 234}
@@ -418,8 +418,8 @@ static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf,
418 if (IS_ERR(ticket_node)) 418 if (IS_ERR(ticket_node))
419 return PTR_ERR(ticket_node); 419 return PTR_ERR(ticket_node);
420 420
421 IWM_DBG_NTF(iwm, DBG, "TICKET RELEASE(%d)\n", 421 IWM_DBG_RX(iwm, DBG, "TICKET RELEASE(%d)\n",
422 ticket->id); 422 ticket->id);
423 list_add_tail(&ticket_node->node, &iwm->rx_tickets); 423 list_add_tail(&ticket_node->node, &iwm->rx_tickets);
424 424
425 /* 425 /*
@@ -454,15 +454,15 @@ static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf,
454 u16 id, buf_offset; 454 u16 id, buf_offset;
455 u32 packet_size; 455 u32 packet_size;
456 456
457 IWM_DBG_NTF(iwm, DBG, "\n"); 457 IWM_DBG_RX(iwm, DBG, "\n");
458 458
459 wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; 459 wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf;
460 id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); 460 id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num);
461 buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); 461 buf_offset = sizeof(struct iwm_umac_wifi_in_hdr);
462 packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); 462 packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr);
463 463
464 IWM_DBG_NTF(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", 464 IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n",
465 wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); 465 wifi_hdr->sw_hdr.cmd.cmd, id, packet_size);
466 IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); 466 IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id);
467 IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); 467 IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size);
468 468
@@ -503,13 +503,10 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
503{ 503{
504 struct iwm_umac_notif_assoc_complete *complete = 504 struct iwm_umac_notif_assoc_complete *complete =
505 (struct iwm_umac_notif_assoc_complete *)buf; 505 (struct iwm_umac_notif_assoc_complete *)buf;
506 union iwreq_data wrqu;
507 506
508 IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", 507 IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n",
509 complete->bssid, complete->status); 508 complete->bssid, complete->status);
510 509
511 memset(&wrqu, 0, sizeof(wrqu));
512
513 clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status); 510 clear_bit(IWM_STATUS_ASSOCIATING, &iwm->status);
514 511
515 switch (le32_to_cpu(complete->status)) { 512 switch (le32_to_cpu(complete->status)) {
@@ -520,7 +517,14 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
520 517
521 iwm_link_on(iwm); 518 iwm_link_on(iwm);
522 519
523 memcpy(wrqu.ap_addr.sa_data, complete->bssid, ETH_ALEN); 520 if (iwm->conf.mode == UMAC_MODE_IBSS)
521 goto ibss;
522
523 cfg80211_connect_result(iwm_to_ndev(iwm),
524 complete->bssid,
525 iwm->req_ie, iwm->req_ie_len,
526 iwm->resp_ie, iwm->resp_ie_len,
527 WLAN_STATUS_SUCCESS, GFP_KERNEL);
524 break; 528 break;
525 case UMAC_ASSOC_COMPLETE_FAILURE: 529 case UMAC_ASSOC_COMPLETE_FAILURE:
526 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); 530 clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status);
@@ -528,18 +532,22 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
528 iwm->channel = 0; 532 iwm->channel = 0;
529 533
530 iwm_link_off(iwm); 534 iwm_link_off(iwm);
535
536 if (iwm->conf.mode == UMAC_MODE_IBSS)
537 goto ibss;
538
539 cfg80211_connect_result(iwm_to_ndev(iwm), complete->bssid,
540 NULL, 0, NULL, 0,
541 WLAN_STATUS_UNSPECIFIED_FAILURE,
542 GFP_KERNEL);
531 default: 543 default:
532 break; 544 break;
533 } 545 }
534 546
535 if (iwm->conf.mode == UMAC_MODE_IBSS) { 547 return 0;
536 cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
537 return 0;
538 }
539
540 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
541 wireless_send_event(iwm_to_ndev(iwm), SIOCGIWAP, &wrqu, NULL);
542 548
549 ibss:
550 cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL);
543 return 0; 551 return 0;
544} 552}
545 553
@@ -769,37 +777,46 @@ static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf,
769 unsigned long buf_size, struct iwm_wifi_cmd *cmd) 777 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
770{ 778{
771 struct iwm_umac_notif_mgt_frame *mgt_frame = 779 struct iwm_umac_notif_mgt_frame *mgt_frame =
772 (struct iwm_umac_notif_mgt_frame *)buf; 780 (struct iwm_umac_notif_mgt_frame *)buf;
773 struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; 781 struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame;
774 u8 *ie; 782 u8 *ie;
775 unsigned int event;
776 union iwreq_data wrqu;
777 783
778 IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, 784 IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame,
779 le16_to_cpu(mgt_frame->len)); 785 le16_to_cpu(mgt_frame->len));
780 786
781 if (ieee80211_is_assoc_req(mgt->frame_control)) { 787 if (ieee80211_is_assoc_req(mgt->frame_control)) {
782 ie = mgt->u.assoc_req.variable;; 788 ie = mgt->u.assoc_req.variable;;
783 event = IWEVASSOCREQIE; 789 iwm->req_ie_len =
790 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
791 kfree(iwm->req_ie);
792 iwm->req_ie = kmemdup(mgt->u.assoc_req.variable,
793 iwm->req_ie_len, GFP_KERNEL);
784 } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { 794 } else if (ieee80211_is_reassoc_req(mgt->frame_control)) {
785 ie = mgt->u.reassoc_req.variable;; 795 ie = mgt->u.reassoc_req.variable;;
786 event = IWEVASSOCREQIE; 796 iwm->req_ie_len =
797 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
798 kfree(iwm->req_ie);
799 iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable,
800 iwm->req_ie_len, GFP_KERNEL);
787 } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { 801 } else if (ieee80211_is_assoc_resp(mgt->frame_control)) {
788 ie = mgt->u.assoc_resp.variable;; 802 ie = mgt->u.assoc_resp.variable;;
789 event = IWEVASSOCRESPIE; 803 iwm->resp_ie_len =
804 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
805 kfree(iwm->resp_ie);
806 iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable,
807 iwm->resp_ie_len, GFP_KERNEL);
790 } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { 808 } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) {
791 ie = mgt->u.reassoc_resp.variable;; 809 ie = mgt->u.reassoc_resp.variable;;
792 event = IWEVASSOCRESPIE; 810 iwm->resp_ie_len =
811 le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
812 kfree(iwm->resp_ie);
813 iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable,
814 iwm->resp_ie_len, GFP_KERNEL);
793 } else { 815 } else {
794 IWM_ERR(iwm, "Unsupported management frame"); 816 IWM_ERR(iwm, "Unsupported management frame");
795 return 0; 817 return 0;
796 } 818 }
797 819
798 wrqu.data.length = le16_to_cpu(mgt_frame->len) - (ie - (u8 *)mgt);
799
800 IWM_HEXDUMP(iwm, DBG, MLME, "EVT: ", ie, wrqu.data.length);
801 wireless_send_event(iwm_to_ndev(iwm), event, &wrqu, ie);
802
803 return 0; 820 return 0;
804} 821}
805 822
@@ -875,6 +892,7 @@ static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf,
875 /* UMAC passes rate info multiplies by 2 */ 892 /* UMAC passes rate info multiplies by 2 */
876 iwm->rate = max_rate >> 1; 893 iwm->rate = max_rate >> 1;
877 } 894 }
895 iwm->txpower = le32_to_cpu(stats->tx_power);
878 896
879 wstats->status = 0; 897 wstats->status = 0;
880 898
@@ -922,13 +940,6 @@ static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf,
922 if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) 940 if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN)
923 return -EINVAL; 941 return -EINVAL;
924 942
925#ifdef CONFIG_IWM_B0_HW_SUPPORT
926 if (hdr_offset == IWM_EEPROM_SKU_CAP_OFF) {
927 if (eeprom_proxy->buf[0] == 0xff)
928 iwm->conf.hw_b0 = 1;
929 }
930#endif
931
932 switch (hdr_type) { 943 switch (hdr_type) {
933 case IWM_UMAC_CMD_EEPROM_TYPE_READ: 944 case IWM_UMAC_CMD_EEPROM_TYPE_READ:
934 memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); 945 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,
993 (struct iwm_umac_wifi_if *)cmd->buf.payload; 1004 (struct iwm_umac_wifi_if *)cmd->buf.payload;
994 1005
995 IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " 1006 IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: "
996 "oid is %d\n", hdr->oid); 1007 "oid is 0x%x\n", hdr->oid);
1008
1009 if (hdr->oid <= WIFI_IF_NTFY_MAX) {
1010 set_bit(hdr->oid, &iwm->wifi_ntfy[0]);
1011 wake_up_interruptible(&iwm->wifi_ntfy_queue);
1012 } else
1013 return -EINVAL;
997 1014
998 switch (hdr->oid) { 1015 switch (hdr->oid) {
999 case UMAC_WIFI_IF_CMD_SET_PROFILE: 1016 case UMAC_WIFI_IF_CMD_SET_PROFILE:
1000 iwm->umac_profile_active = 1; 1017 iwm->umac_profile_active = 1;
1001 wake_up_interruptible(&iwm->mlme_queue);
1002 break; 1018 break;
1003 default: 1019 default:
1004 break; 1020 break;
@@ -1010,6 +1026,7 @@ static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf,
1010static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, 1026static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
1011 unsigned long buf_size, struct iwm_wifi_cmd *cmd) 1027 unsigned long buf_size, struct iwm_wifi_cmd *cmd)
1012{ 1028{
1029 struct wiphy *wiphy = iwm_to_wiphy(iwm);
1013 struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) 1030 struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *)
1014 (buf + sizeof(struct iwm_umac_wifi_in_hdr)); 1031 (buf + sizeof(struct iwm_umac_wifi_in_hdr));
1015 u32 flags = le32_to_cpu(state->flags); 1032 u32 flags = le32_to_cpu(state->flags);
@@ -1018,10 +1035,7 @@ static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf,
1018 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", 1035 flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF",
1019 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); 1036 flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF");
1020 1037
1021 if (flags & IWM_CARD_STATE_HW_DISABLED) 1038 wiphy_rfkill_set_hw_state(wiphy, flags & IWM_CARD_STATE_HW_DISABLED);
1022 set_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
1023 else
1024 clear_bit(IWM_RADIO_RFKILL_HW, &iwm->radio);
1025 1039
1026 return 0; 1040 return 0;
1027} 1041}
@@ -1362,13 +1376,13 @@ static void iwm_rx_process_packet(struct iwm_priv *iwm,
1362 1376
1363 skb->dev = iwm_to_ndev(iwm); 1377 skb->dev = iwm_to_ndev(iwm);
1364 skb->protocol = eth_type_trans(skb, ndev); 1378 skb->protocol = eth_type_trans(skb, ndev);
1365 skb->ip_summed = CHECKSUM_UNNECESSARY; 1379 skb->ip_summed = CHECKSUM_NONE;
1366 memset(skb->cb, 0, sizeof(skb->cb)); 1380 memset(skb->cb, 0, sizeof(skb->cb));
1367 1381
1368 ndev->stats.rx_packets++; 1382 ndev->stats.rx_packets++;
1369 ndev->stats.rx_bytes += skb->len; 1383 ndev->stats.rx_bytes += skb->len;
1370 1384
1371 if (netif_rx(skb) == NET_RX_DROP) { 1385 if (netif_rx_ni(skb) == NET_RX_DROP) {
1372 IWM_ERR(iwm, "Packet dropped\n"); 1386 IWM_ERR(iwm, "Packet dropped\n");
1373 ndev->stats.rx_dropped++; 1387 ndev->stats.rx_dropped++;
1374 } 1388 }
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 @@
65#include <linux/kernel.h> 65#include <linux/kernel.h>
66#include <linux/netdevice.h> 66#include <linux/netdevice.h>
67#include <linux/debugfs.h> 67#include <linux/debugfs.h>
68#include <linux/mmc/sdio_ids.h>
68#include <linux/mmc/sdio.h> 69#include <linux/mmc/sdio.h>
69#include <linux/mmc/sdio_func.h> 70#include <linux/mmc/sdio_func.h>
70 71
@@ -492,7 +493,8 @@ static void iwm_sdio_remove(struct sdio_func *func)
492} 493}
493 494
494static const struct sdio_device_id iwm_sdio_ids[] = { 495static const struct sdio_device_id iwm_sdio_ids[] = {
495 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, SDIO_DEVICE_ID_IWM) }, 496 { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL,
497 SDIO_DEVICE_ID_INTEL_IWMC3200WIFI) },
496 { /* end: all zeroes */ }, 498 { /* end: all zeroes */ },
497}; 499};
498MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); 500MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids);
@@ -506,11 +508,7 @@ static struct sdio_driver iwm_sdio_driver = {
506 508
507static int __init iwm_sdio_init_module(void) 509static int __init iwm_sdio_init_module(void)
508{ 510{
509 int ret; 511 return sdio_register_driver(&iwm_sdio_driver);
510
511 ret = sdio_register_driver(&iwm_sdio_driver);
512
513 return ret;
514} 512}
515 513
516static void __exit iwm_sdio_exit_module(void) 514static 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 @@
39#ifndef __IWM_SDIO_H__ 39#ifndef __IWM_SDIO_H__
40#define __IWM_SDIO_H__ 40#define __IWM_SDIO_H__
41 41
42#define SDIO_VENDOR_ID_INTEL 0x89
43#define SDIO_DEVICE_ID_IWM 0x1403
44
45#define IWM_SDIO_DATA_ADDR 0x0 42#define IWM_SDIO_DATA_ADDR 0x0
46#define IWM_SDIO_INTR_ENABLE_ADDR 0x14 43#define IWM_SDIO_INTR_ENABLE_ADDR 0x14
47#define IWM_SDIO_INTR_STATUS_ADDR 0x13 44#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 {
495#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 495#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8
496#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 496#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9
497 497
498#define WIFI_IF_NTFY_MAX 0xff
499
498/* Notification structures */ 500/* Notification structures */
499struct iwm_umac_notif_wifi_if { 501struct iwm_umac_notif_wifi_if {
500 struct iwm_umac_wifi_in_hdr hdr; 502 struct iwm_umac_wifi_in_hdr hdr;
@@ -613,6 +615,7 @@ struct iwm_umac_notif_alive {
613} __attribute__ ((packed)); 615} __attribute__ ((packed));
614 616
615struct iwm_umac_notif_init_complete { 617struct iwm_umac_notif_init_complete {
618 struct iwm_umac_wifi_in_hdr hdr;
616 __le16 status; 619 __le16 status;
617 __le16 reserved; 620 __le16 reserved;
618} __attribute__ ((packed)); 621} __attribute__ ((packed));
@@ -641,6 +644,11 @@ struct iwm_fw_error_hdr {
641 __le32 umac_status; 644 __le32 umac_status;
642 __le32 lmac_status; 645 __le32 lmac_status;
643 __le32 sdio_status; 646 __le32 sdio_status;
647 __le32 dbm_sample_ctrl;
648 __le32 dbm_buf_base;
649 __le32 dbm_buf_end;
650 __le32 dbm_buf_write_ptr;
651 __le32 dbm_buf_cycle_cnt;
644} __attribute__ ((packed)); 652} __attribute__ ((packed));
645 653
646struct iwm_umac_notif_error { 654struct 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 @@
1/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/netdevice.h>
26#include <linux/wireless.h>
27#include <linux/if_arp.h>
28#include <linux/etherdevice.h>
29#include <net/cfg80211.h>
30#include <net/iw_handler.h>
31
32#include "iwm.h"
33#include "umac.h"
34#include "commands.h"
35#include "debug.h"
36
37static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
38{
39 struct iwm_priv *iwm = ndev_to_iwm(dev);
40 struct iw_statistics *wstats = &iwm->wstats;
41
42 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
43 memset(wstats, 0, sizeof(struct iw_statistics));
44 wstats->qual.updated = IW_QUAL_ALL_INVALID;
45 }
46
47 return wstats;
48}
49
50static int iwm_wext_siwfreq(struct net_device *dev,
51 struct iw_request_info *info,
52 struct iw_freq *freq, char *extra)
53{
54 struct iwm_priv *iwm = ndev_to_iwm(dev);
55
56 if (freq->flags == IW_FREQ_AUTO)
57 return 0;
58
59 /* frequency/channel can only be set in IBSS mode */
60 if (iwm->conf.mode != UMAC_MODE_IBSS)
61 return -EOPNOTSUPP;
62
63 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
64}
65
66static int iwm_wext_giwfreq(struct net_device *dev,
67 struct iw_request_info *info,
68 struct iw_freq *freq, char *extra)
69{
70 struct iwm_priv *iwm = ndev_to_iwm(dev);
71
72 if (iwm->conf.mode == UMAC_MODE_IBSS)
73 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
74
75 freq->e = 0;
76 freq->m = iwm->channel;
77
78 return 0;
79}
80
81static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
82 struct sockaddr *ap_addr, char *extra)
83{
84 struct iwm_priv *iwm = ndev_to_iwm(dev);
85
86 if (iwm->conf.mode == UMAC_MODE_IBSS)
87 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
88
89 if (!test_bit(IWM_STATUS_READY, &iwm->status))
90 return -EIO;
91
92 if (is_zero_ether_addr(ap_addr->sa_data) ||
93 is_broadcast_ether_addr(ap_addr->sa_data)) {
94 IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
95 iwm->umac_profile->bssid[0]);
96 memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
97 iwm->umac_profile->bss_num = 0;
98 } else {
99 IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
100 ap_addr->sa_data);
101 memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
102 ETH_ALEN);
103 iwm->umac_profile->bss_num = 1;
104 }
105
106 if (iwm->umac_profile_active) {
107 if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
108 return 0;
109
110 iwm_invalidate_mlme_profile(iwm);
111 }
112
113 if (iwm->umac_profile->ssid.ssid_len)
114 return iwm_send_mlme_profile(iwm);
115
116 return 0;
117}
118
119static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
120 struct sockaddr *ap_addr, char *extra)
121{
122 struct iwm_priv *iwm = ndev_to_iwm(dev);
123
124 switch (iwm->conf.mode) {
125 case UMAC_MODE_IBSS:
126 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
127 case UMAC_MODE_BSS:
128 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
129 ap_addr->sa_family = ARPHRD_ETHER;
130 memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
131 } else
132 memset(&ap_addr->sa_data, 0, ETH_ALEN);
133 break;
134 default:
135 return -EOPNOTSUPP;
136 }
137
138 return 0;
139}
140
141static int iwm_wext_siwessid(struct net_device *dev,
142 struct iw_request_info *info,
143 struct iw_point *data, char *ssid)
144{
145 struct iwm_priv *iwm = ndev_to_iwm(dev);
146 size_t len = data->length;
147 int ret;
148
149 if (iwm->conf.mode == UMAC_MODE_IBSS)
150 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
151
152 if (!test_bit(IWM_STATUS_READY, &iwm->status))
153 return -EIO;
154
155 if (len > 0 && ssid[len - 1] == '\0')
156 len--;
157
158 if (iwm->umac_profile_active) {
159 if (iwm->umac_profile->ssid.ssid_len == len &&
160 !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
161 return 0;
162
163 ret = iwm_invalidate_mlme_profile(iwm);
164 if (ret < 0) {
165 IWM_ERR(iwm, "Couldn't invalidate profile\n");
166 return ret;
167 }
168 }
169
170 iwm->umac_profile->ssid.ssid_len = len;
171 memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
172
173 return iwm_send_mlme_profile(iwm);
174}
175
176static int iwm_wext_giwessid(struct net_device *dev,
177 struct iw_request_info *info,
178 struct iw_point *data, char *ssid)
179{
180 struct iwm_priv *iwm = ndev_to_iwm(dev);
181
182 if (iwm->conf.mode == UMAC_MODE_IBSS)
183 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
184
185 if (!test_bit(IWM_STATUS_READY, &iwm->status))
186 return -EIO;
187
188 data->length = iwm->umac_profile->ssid.ssid_len;
189 if (data->length) {
190 memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
191 data->flags = 1;
192 } else
193 data->flags = 0;
194
195 return 0;
196}
197
198static struct iwm_key *
199iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
200 struct iw_encode_ext *ext, u8 alg)
201{
202 struct iwm_key *key = &iwm->keys[key_idx];
203
204 memset(key, 0, sizeof(struct iwm_key));
205 memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
206 key->hdr.key_idx = key_idx;
207 if (is_broadcast_ether_addr(ext->addr.sa_data))
208 key->hdr.multicast = 1;
209
210 key->in_use = in_use;
211 key->flags = ext->ext_flags;
212 key->alg = alg;
213 key->key_len = ext->key_len;
214 memcpy(key->key, ext->key, ext->key_len);
215
216 return key;
217}
218
219static int iwm_wext_giwrate(struct net_device *dev,
220 struct iw_request_info *info,
221 struct iw_param *rate, char *extra)
222{
223 struct iwm_priv *iwm = ndev_to_iwm(dev);
224
225 rate->value = iwm->rate * 1000000;
226
227 return 0;
228}
229
230static int iwm_wext_siwencode(struct net_device *dev,
231 struct iw_request_info *info,
232 struct iw_point *erq, char *key_buf)
233{
234 struct iwm_priv *iwm = ndev_to_iwm(dev);
235 struct iwm_key *uninitialized_var(key);
236 int idx, i, uninitialized_var(alg), remove = 0, ret;
237
238 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
239 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
240
241 if (!iwm->umac_profile) {
242 IWM_ERR(iwm, "UMAC profile not allocated yet\n");
243 return -ENODEV;
244 }
245
246 if (erq->length == WLAN_KEY_LEN_WEP40) {
247 alg = UMAC_CIPHER_TYPE_WEP_40;
248 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
249 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
250 } else if (erq->length == WLAN_KEY_LEN_WEP104) {
251 alg = UMAC_CIPHER_TYPE_WEP_104;
252 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
253 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
254 }
255
256 if (erq->flags & IW_ENCODE_RESTRICTED)
257 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
258 else
259 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
260
261 idx = erq->flags & IW_ENCODE_INDEX;
262 if (idx == 0) {
263 if (iwm->default_key)
264 for (i = 0; i < IWM_NUM_KEYS; i++) {
265 if (iwm->default_key == &iwm->keys[i]) {
266 idx = i;
267 break;
268 }
269 }
270 else
271 iwm->default_key = &iwm->keys[idx];
272 } else if (idx < 1 || idx > 4) {
273 return -EINVAL;
274 } else
275 idx--;
276
277 if (erq->flags & IW_ENCODE_DISABLED)
278 remove = 1;
279 else if (erq->length == 0) {
280 if (!iwm->keys[idx].in_use)
281 return -EINVAL;
282 iwm->default_key = &iwm->keys[idx];
283 }
284
285 if (erq->length) {
286 key = &iwm->keys[idx];
287 memset(key, 0, sizeof(struct iwm_key));
288 memset(key->hdr.mac, 0xff, ETH_ALEN);
289 key->hdr.key_idx = idx;
290 key->hdr.multicast = 1;
291 key->in_use = !remove;
292 key->alg = alg;
293 key->key_len = erq->length;
294 memcpy(key->key, key_buf, erq->length);
295
296 IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
297 idx, !!iwm->default_key);
298 }
299
300 if (remove) {
301 if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
302 int j;
303 for (j = 0; j < IWM_NUM_KEYS; j++)
304 if (iwm->keys[j].in_use) {
305 struct iwm_key *k = &iwm->keys[j];
306
307 k->in_use = 0;
308 ret = iwm_set_key(iwm, remove, 0, k);
309 if (ret < 0)
310 return ret;
311 }
312
313 iwm->umac_profile->sec.ucast_cipher =
314 UMAC_CIPHER_TYPE_NONE;
315 iwm->umac_profile->sec.mcast_cipher =
316 UMAC_CIPHER_TYPE_NONE;
317 iwm->umac_profile->sec.auth_type =
318 UMAC_AUTH_TYPE_OPEN;
319
320 return 0;
321 } else {
322 key->in_use = 0;
323 return iwm_set_key(iwm, remove, 0, key);
324 }
325 }
326
327 /*
328 * If we havent set a profile yet, we cant set keys.
329 * Keys will be pushed after we're associated.
330 */
331 if (!iwm->umac_profile_active)
332 return 0;
333
334 /*
335 * If there is a current active profile, but no
336 * default key, it's not worth trying to associate again.
337 */
338 if (!iwm->default_key)
339 return 0;
340
341 /*
342 * Here we have an active profile, but a key setting changed.
343 * We thus have to invalidate the current profile, and push the
344 * new one. Keys will be pushed when association takes place.
345 */
346 ret = iwm_invalidate_mlme_profile(iwm);
347 if (ret < 0) {
348 IWM_ERR(iwm, "Couldn't invalidate profile\n");
349 return ret;
350 }
351
352 return iwm_send_mlme_profile(iwm);
353}
354
355static int iwm_wext_giwencode(struct net_device *dev,
356 struct iw_request_info *info,
357 struct iw_point *erq, char *key)
358{
359 struct iwm_priv *iwm = ndev_to_iwm(dev);
360 int idx, i;
361
362 idx = erq->flags & IW_ENCODE_INDEX;
363 if (idx < 1 || idx > 4) {
364 idx = -1;
365 if (!iwm->default_key) {
366 erq->length = 0;
367 erq->flags |= IW_ENCODE_NOKEY;
368 return 0;
369 } else
370 for (i = 0; i < IWM_NUM_KEYS; i++) {
371 if (iwm->default_key == &iwm->keys[i]) {
372 idx = i;
373 break;
374 }
375 }
376 if (idx < 0)
377 return -EINVAL;
378 } else
379 idx--;
380
381 erq->flags = idx + 1;
382
383 if (!iwm->keys[idx].in_use) {
384 erq->length = 0;
385 erq->flags |= IW_ENCODE_DISABLED;
386 return 0;
387 }
388
389 memcpy(key, iwm->keys[idx].key,
390 min_t(int, erq->length, iwm->keys[idx].key_len));
391 erq->length = iwm->keys[idx].key_len;
392 erq->flags |= IW_ENCODE_ENABLED;
393
394 if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
395 switch (iwm->umac_profile->sec.auth_type) {
396 case UMAC_AUTH_TYPE_OPEN:
397 erq->flags |= IW_ENCODE_OPEN;
398 break;
399 default:
400 erq->flags |= IW_ENCODE_RESTRICTED;
401 break;
402 }
403 }
404
405 return 0;
406}
407
408static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
409{
410 if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
411 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
412 else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
413 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
414 else
415 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
416
417 return 0;
418}
419
420static int iwm_wext_siwpower(struct net_device *dev,
421 struct iw_request_info *info,
422 struct iw_param *wrq, char *extra)
423{
424 struct iwm_priv *iwm = ndev_to_iwm(dev);
425 u32 power_index;
426
427 if (wrq->disabled) {
428 power_index = IWM_POWER_INDEX_MIN;
429 goto set;
430 } else
431 power_index = IWM_POWER_INDEX_DEFAULT;
432
433 switch (wrq->flags & IW_POWER_MODE) {
434 case IW_POWER_ON:
435 case IW_POWER_MODE:
436 case IW_POWER_ALL_R:
437 break;
438 default:
439 return -EINVAL;
440 }
441
442 set:
443 if (power_index == iwm->conf.power_index)
444 return 0;
445
446 iwm->conf.power_index = power_index;
447
448 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
449 CFG_POWER_INDEX, iwm->conf.power_index);
450}
451
452static int iwm_wext_giwpower(struct net_device *dev,
453 struct iw_request_info *info,
454 union iwreq_data *wrqu, char *extra)
455{
456 struct iwm_priv *iwm = ndev_to_iwm(dev);
457
458 wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
459
460 return 0;
461}
462
463static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
464{
465 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
466
467 if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
468 *auth_type = UMAC_AUTH_TYPE_8021X;
469 else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
470 if (iwm->umac_profile->sec.flags &
471 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
472 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
473 else
474 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
475 } else {
476 IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
477 return -EINVAL;
478 }
479
480 return 0;
481}
482
483static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
484{
485 u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
486 &iwm->umac_profile->sec.mcast_cipher;
487
488 switch (cipher) {
489 case IW_AUTH_CIPHER_NONE:
490 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
491 break;
492 case IW_AUTH_CIPHER_WEP40:
493 *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
494 break;
495 case IW_AUTH_CIPHER_TKIP:
496 *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
497 break;
498 case IW_AUTH_CIPHER_CCMP:
499 *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
500 break;
501 case IW_AUTH_CIPHER_WEP104:
502 *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
503 break;
504 default:
505 IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
506 return -ENOTSUPP;
507 }
508
509 return 0;
510}
511
512static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
513{
514 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
515
516 switch (auth_alg) {
517 case IW_AUTH_ALG_OPEN_SYSTEM:
518 *auth_type = UMAC_AUTH_TYPE_OPEN;
519 break;
520 case IW_AUTH_ALG_SHARED_KEY:
521 if (iwm->umac_profile->sec.flags &
522 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
523 if (*auth_type == UMAC_AUTH_TYPE_8021X)
524 return -EINVAL;
525 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
526 } else {
527 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
528 }
529 break;
530 case IW_AUTH_ALG_LEAP:
531 default:
532 IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
533 return -ENOTSUPP;
534 }
535
536 return 0;
537}
538
539static int iwm_wext_siwauth(struct net_device *dev,
540 struct iw_request_info *info,
541 struct iw_param *data, char *extra)
542{
543 struct iwm_priv *iwm = ndev_to_iwm(dev);
544 int ret;
545
546 if ((data->flags) &
547 (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
548 IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
549 /* We need to invalidate the current profile */
550 if (iwm->umac_profile_active) {
551 ret = iwm_invalidate_mlme_profile(iwm);
552 if (ret < 0) {
553 IWM_ERR(iwm, "Couldn't invalidate profile\n");
554 return ret;
555 }
556 }
557 }
558
559 switch (data->flags & IW_AUTH_INDEX) {
560 case IW_AUTH_WPA_VERSION:
561 return iwm_set_wpa_version(iwm, data->value);
562 break;
563 case IW_AUTH_CIPHER_PAIRWISE:
564 return iwm_set_cipher(iwm, data->value, 1);
565 break;
566 case IW_AUTH_CIPHER_GROUP:
567 return iwm_set_cipher(iwm, data->value, 0);
568 break;
569 case IW_AUTH_KEY_MGMT:
570 return iwm_set_key_mgt(iwm, data->value);
571 break;
572 case IW_AUTH_80211_AUTH_ALG:
573 return iwm_set_auth_alg(iwm, data->value);
574 break;
575 default:
576 return -ENOTSUPP;
577 }
578
579 return 0;
580}
581
582static int iwm_wext_giwauth(struct net_device *dev,
583 struct iw_request_info *info,
584 struct iw_param *data, char *extra)
585{
586 return 0;
587}
588
589static int iwm_wext_siwencodeext(struct net_device *dev,
590 struct iw_request_info *info,
591 struct iw_point *erq, char *extra)
592{
593 struct iwm_priv *iwm = ndev_to_iwm(dev);
594 struct iwm_key *key;
595 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
596 int uninitialized_var(alg), idx, i, remove = 0;
597
598 IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
599 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
600 IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
601 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
602 IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
603
604 switch (ext->alg) {
605 case IW_ENCODE_ALG_NONE:
606 remove = 1;
607 break;
608 case IW_ENCODE_ALG_WEP:
609 if (ext->key_len == WLAN_KEY_LEN_WEP40)
610 alg = UMAC_CIPHER_TYPE_WEP_40;
611 else if (ext->key_len == WLAN_KEY_LEN_WEP104)
612 alg = UMAC_CIPHER_TYPE_WEP_104;
613 else {
614 IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
615 return -EINVAL;
616 }
617
618 break;
619 case IW_ENCODE_ALG_TKIP:
620 alg = UMAC_CIPHER_TYPE_TKIP;
621 break;
622 case IW_ENCODE_ALG_CCMP:
623 alg = UMAC_CIPHER_TYPE_CCMP;
624 break;
625 default:
626 return -EOPNOTSUPP;
627 }
628
629 idx = erq->flags & IW_ENCODE_INDEX;
630
631 if (idx == 0) {
632 if (iwm->default_key)
633 for (i = 0; i < IWM_NUM_KEYS; i++) {
634 if (iwm->default_key == &iwm->keys[i]) {
635 idx = i;
636 break;
637 }
638 }
639 } else if (idx < 1 || idx > 4) {
640 return -EINVAL;
641 } else
642 idx--;
643
644 if (erq->flags & IW_ENCODE_DISABLED)
645 remove = 1;
646 else if ((erq->length == 0) ||
647 (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
648 iwm->default_key = &iwm->keys[idx];
649 if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
650 return iwm_set_tx_key(iwm, idx);
651 }
652
653 key = iwm_key_init(iwm, idx, !remove, ext, alg);
654
655 return iwm_set_key(iwm, remove, !iwm->default_key, key);
656}
657
658static const iw_handler iwm_handlers[] =
659{
660 (iw_handler) NULL, /* SIOCSIWCOMMIT */
661 (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
662 (iw_handler) NULL, /* SIOCSIWNWID */
663 (iw_handler) NULL, /* SIOCGIWNWID */
664 (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
665 (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
666 (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
667 (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
668 (iw_handler) NULL, /* SIOCSIWSENS */
669 (iw_handler) NULL, /* SIOCGIWSENS */
670 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
671 (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
672 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
673 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
674 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
675 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
676 (iw_handler) NULL, /* SIOCSIWSPY */
677 (iw_handler) NULL, /* SIOCGIWSPY */
678 (iw_handler) NULL, /* SIOCSIWTHRSPY */
679 (iw_handler) NULL, /* SIOCGIWTHRSPY */
680 (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
681 (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
682 (iw_handler) NULL, /* SIOCSIWMLME */
683 (iw_handler) NULL, /* SIOCGIWAPLIST */
684 (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
685 (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
686 (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
687 (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
688 (iw_handler) NULL, /* SIOCSIWNICKN */
689 (iw_handler) NULL, /* SIOCGIWNICKN */
690 (iw_handler) NULL, /* -- hole -- */
691 (iw_handler) NULL, /* -- hole -- */
692 (iw_handler) NULL, /* SIOCSIWRATE */
693 (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
694 (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
695 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
696 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
697 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
698 (iw_handler) NULL, /* SIOCSIWTXPOW */
699 (iw_handler) NULL, /* SIOCGIWTXPOW */
700 (iw_handler) NULL, /* SIOCSIWRETRY */
701 (iw_handler) NULL, /* SIOCGIWRETRY */
702 (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
703 (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
704 (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
705 (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
706 (iw_handler) NULL, /* -- hole -- */
707 (iw_handler) NULL, /* -- hole -- */
708 (iw_handler) NULL, /* SIOCSIWGENIE */
709 (iw_handler) NULL, /* SIOCGIWGENIE */
710 (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
711 (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
712 (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
713 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
714 (iw_handler) NULL, /* SIOCSIWPMKSA */
715 (iw_handler) NULL, /* -- hole -- */
716};
717
718const struct iw_handler_def iwm_iw_handler_def = {
719 .num_standard = ARRAY_SIZE(iwm_handlers),
720 .standard = (iw_handler *) iwm_handlers,
721 .get_wireless_stats = iwm_get_wireless_stats,
722};
723