aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorSamuel Ortiz <samuel.ortiz@intel.com>2009-06-15 15:59:52 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 14:57:51 -0400
commit13e0fe70960e95cdea89b71aa3d046ec71efac8c (patch)
tree3cb98cc48285bac0b368f5ff2f3a97bad15cefc4 /drivers/net/wireless
parenta70742f167424bab794ca74b9e99b598b358bb7d (diff)
iwmc3200wifi: cfg80211 key hooks implemetation
This patch implements the new cfg80211 privacy related hooks: add/get/set_key and the set_default_key one. With this implementation we can now call the wext-compat *encode* routines and reduce our own wext code. Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c172
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c72
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h14
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/wext.c286
6 files changed, 219 insertions, 332 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index bc89b1ef0cad..739bd9b0ddea 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,173 @@ 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_reset_profile(struct iwm_priv *iwm)
162{
163 int ret;
164
165 if (!iwm->umac_profile_active)
166 return 0;
167
168 /*
169 * If there is a current active profile, but no
170 * default key, it's not worth trying to associate again.
171 */
172 if (iwm->default_key < 0)
173 return 0;
174
175 /*
176 * Here we have an active profile, but a key setting changed.
177 * We thus have to invalidate the current profile, and push the
178 * new one. Keys will be pushed when association takes place.
179 */
180 ret = iwm_invalidate_mlme_profile(iwm);
181 if (ret < 0) {
182 IWM_ERR(iwm, "Couldn't invalidate profile\n");
183 return ret;
184 }
185
186 return iwm_send_mlme_profile(iwm);
187}
188
189static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
190 u8 key_index, const u8 *mac_addr,
191 struct key_params *params)
192{
193 struct iwm_priv *iwm = ndev_to_iwm(ndev);
194 struct iwm_key *key = &iwm->keys[key_index];
195 int ret;
196
197 IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
198
199 memset(key, 0, sizeof(struct iwm_key));
200 ret = iwm_key_init(key, key_index, mac_addr, params);
201 if (ret < 0) {
202 IWM_ERR(iwm, "Invalid key_params\n");
203 return ret;
204 }
205
206 /*
207 * The WEP keys can be set before or after setting the essid.
208 * We need to handle both cases by simply pushing the keys after
209 * we send the profile.
210 * If the profile is not set yet (i.e. we're pushing keys before
211 * the essid), we set the cipher appropriately.
212 * If the profile is set, we havent associated yet because our
213 * cipher was incorrectly set. So we invalidate and send the
214 * profile again.
215 */
216 if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
217 key->cipher == WLAN_CIPHER_SUITE_WEP104) {
218 u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
219 u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;
220
221 IWM_DBG_WEXT(iwm, DBG, "WEP key\n");
222
223 if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
224 *ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
225 if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
226 *ucast_cipher = *mcast_cipher =
227 UMAC_CIPHER_TYPE_WEP_104;
228
229 return iwm_reset_profile(iwm);
230 }
231
232 return iwm_set_key(iwm, 0, key);
233}
234
235static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
236 u8 key_index, const u8 *mac_addr, void *cookie,
237 void (*callback)(void *cookie,
238 struct key_params*))
239{
240 struct iwm_priv *iwm = ndev_to_iwm(ndev);
241 struct iwm_key *key = &iwm->keys[key_index];
242 struct key_params params;
243
244 IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);
245
246 memset(&params, 0, sizeof(params));
247
248 params.cipher = key->cipher;
249 params.key_len = key->key_len;
250 params.seq_len = key->seq_len;
251 params.seq = key->seq;
252 params.key = key->key;
253
254 callback(cookie, &params);
255
256 return key->key_len ? 0 : -ENOENT;
257}
258
259
260static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
261 u8 key_index, const u8 *mac_addr)
262{
263 struct iwm_priv *iwm = ndev_to_iwm(ndev);
264 struct iwm_key *key = &iwm->keys[key_index];
265
266 if (!iwm->keys[key_index].key_len) {
267 IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
268 return 0;
269 }
270
271 if (key_index == iwm->default_key)
272 iwm->default_key = -1;
273
274 return iwm_set_key(iwm, 1, key);
275}
276
277static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
278 struct net_device *ndev,
279 u8 key_index)
280{
281 struct iwm_priv *iwm = ndev_to_iwm(ndev);
282 int ret;
283
284 IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
285
286 if (!iwm->keys[key_index].key_len) {
287 IWM_ERR(iwm, "Key %d not used\n", key_index);
288 return -EINVAL;
289 }
290
291 ret = iwm_set_tx_key(iwm, key_index);
292 if (ret < 0)
293 return ret;
294
295 iwm->default_key = key_index;
296
297 return iwm_reset_profile(iwm);
298}
299
300
133int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) 301int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
134{ 302{
135 struct wiphy *wiphy = iwm_to_wiphy(iwm); 303 struct wiphy *wiphy = iwm_to_wiphy(iwm);
@@ -326,6 +494,10 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
326 494
327static struct cfg80211_ops iwm_cfg80211_ops = { 495static struct cfg80211_ops iwm_cfg80211_ops = {
328 .change_virtual_intf = iwm_cfg80211_change_iface, 496 .change_virtual_intf = iwm_cfg80211_change_iface,
497 .add_key = iwm_cfg80211_add_key,
498 .get_key = iwm_cfg80211_get_key,
499 .del_key = iwm_cfg80211_del_key,
500 .set_default_key = iwm_cfg80211_set_default_key,
329 .scan = iwm_cfg80211_scan, 501 .scan = iwm_cfg80211_scan,
330 .set_wiphy_params = iwm_cfg80211_set_wiphy_params, 502 .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
331 .join_ibss = iwm_cfg80211_join_ibss, 503 .join_ibss = iwm_cfg80211_join_ibss,
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 337a884f52df..145f6f5ae747 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -524,9 +524,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
524{ 524{
525 struct iwm_umac_tx_key_id tx_key_id; 525 struct iwm_umac_tx_key_id tx_key_id;
526 526
527 if (!iwm->default_key || !iwm->default_key->in_use)
528 return -EINVAL;
529
530 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; 527 tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
531 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - 528 tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
532 sizeof(struct iwm_umac_wifi_if)); 529 sizeof(struct iwm_umac_wifi_if));
@@ -569,10 +566,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
569 return 0; 566 return 0;
570} 567}
571 568
572int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key, 569int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
573 struct iwm_key *key)
574{ 570{
575 int ret; 571 int ret = 0;
576 u8 cmd[64], *sta_addr, *key_data, key_len; 572 u8 cmd[64], *sta_addr, *key_data, key_len;
577 s8 key_idx; 573 s8 key_idx;
578 u16 cmd_size = 0; 574 u16 cmd_size = 0;
@@ -582,9 +578,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
582 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; 578 struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
583 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; 579 struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;
584 580
585 if (set_tx_key)
586 iwm->default_key = key;
587
588 /* 581 /*
589 * We check if our current profile is valid. 582 * We check if our current profile is valid.
590 * If not, we dont push the key, we just cache them, 583 * If not, we dont push the key, we just cache them,
@@ -603,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
603 key_idx = key->hdr.key_idx; 596 key_idx = key->hdr.key_idx;
604 597
605 if (!remove) { 598 if (!remove) {
606 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n", 599 IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
607 key_idx, set_tx_key);
608 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); 600 IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
609 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", 601 IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
610 key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); 602 key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
@@ -616,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
616 iwm->umac_profile->sec.auth_type, 608 iwm->umac_profile->sec.auth_type,
617 iwm->umac_profile->sec.flags); 609 iwm->umac_profile->sec.flags);
618 610
619 switch (key->alg) { 611 switch (key->cipher) {
620 case UMAC_CIPHER_TYPE_WEP_40: 612 case WLAN_CIPHER_SUITE_WEP40:
621 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; 613 wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
622 wep40->hdr.buf_size = 614 wep40->hdr.buf_size =
623 cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - 615 cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
@@ -631,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
631 cmd_size = sizeof(struct iwm_umac_key_wep40); 623 cmd_size = sizeof(struct iwm_umac_key_wep40);
632 break; 624 break;
633 625
634 case UMAC_CIPHER_TYPE_WEP_104: 626 case WLAN_CIPHER_SUITE_WEP104:
635 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; 627 wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
636 wep104->hdr.buf_size = 628 wep104->hdr.buf_size =
637 cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - 629 cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
@@ -645,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
645 cmd_size = sizeof(struct iwm_umac_key_wep104); 637 cmd_size = sizeof(struct iwm_umac_key_wep104);
646 break; 638 break;
647 639
648 case UMAC_CIPHER_TYPE_CCMP: 640 case WLAN_CIPHER_SUITE_CCMP:
649 key_hdr->key_idx++; 641 key_hdr->key_idx++;
650 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; 642 ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
651 ccmp->hdr.buf_size = 643 ccmp->hdr.buf_size =
@@ -657,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
657 649
658 memcpy(ccmp->key, key_data, key_len); 650 memcpy(ccmp->key, key_data, key_len);
659 651
660 if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) 652 if (key->seq_len)
661 memcpy(ccmp->iv_count, key->rx_seq, 6); 653 memcpy(ccmp->iv_count, key->seq, key->seq_len);
662 654
663 cmd_size = sizeof(struct iwm_umac_key_ccmp); 655 cmd_size = sizeof(struct iwm_umac_key_ccmp);
664 break; 656 break;
665 657
666 case UMAC_CIPHER_TYPE_TKIP: 658 case WLAN_CIPHER_SUITE_TKIP:
667 key_hdr->key_idx++; 659 key_hdr->key_idx++;
668 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; 660 tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
669 tkip->hdr.buf_size = 661 tkip->hdr.buf_size =
@@ -680,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
680 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, 672 key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
681 IWM_TKIP_MIC_SIZE); 673 IWM_TKIP_MIC_SIZE);
682 674
683 if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID) 675 if (key->seq_len)
684 memcpy(ccmp->iv_count, key->rx_seq, 6); 676 memcpy(ccmp->iv_count, key->seq, key->seq_len);
685 677
686 cmd_size = sizeof(struct iwm_umac_key_tkip); 678 cmd_size = sizeof(struct iwm_umac_key_tkip);
687 break; 679 break;
@@ -690,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
690 return -ENOTSUPP; 682 return -ENOTSUPP;
691 } 683 }
692 684
693 if ((key->alg == UMAC_CIPHER_TYPE_CCMP) || 685 if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
694 (key->alg == UMAC_CIPHER_TYPE_TKIP)) 686 (key->cipher == WLAN_CIPHER_SUITE_CCMP))
695 /* 687 /*
696 * UGLY_UGLY_UGLY 688 * UGLY_UGLY_UGLY
697 * Copied HACK from the MWG driver. 689 * Copied HACK from the MWG driver.
@@ -702,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
702 schedule_timeout_interruptible(usecs_to_jiffies(300)); 694 schedule_timeout_interruptible(usecs_to_jiffies(300));
703 695
704 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); 696 ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
705 if (ret < 0)
706 goto err;
707
708 /*
709 * We need a default key only if it is set and
710 * if we're doing WEP.
711 */
712 if (iwm->default_key == key &&
713 ((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
714 (key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
715 ret = iwm_set_tx_key(iwm, key_idx);
716 if (ret < 0)
717 goto err;
718 }
719 } else { 697 } else {
720 struct iwm_umac_key_remove key_remove; 698 struct iwm_umac_key_remove key_remove;
721 699
700 IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);
701
722 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; 702 key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
723 key_remove.hdr.buf_size = 703 key_remove.hdr.buf_size =
724 cpu_to_le16(sizeof(struct iwm_umac_key_remove) - 704 cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
@@ -732,13 +712,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
732 if (ret < 0) 712 if (ret < 0)
733 return ret; 713 return ret;
734 714
735 iwm->keys[key_idx].in_use = 0; 715 iwm->keys[key_idx].key_len = 0;
736 } 716 }
737 717
738 return 0;
739
740 err:
741 kfree(key);
742 return ret; 718 return ret;
743} 719}
744 720
@@ -761,22 +737,24 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
761 } 737 }
762 738
763 for (i = 0; i < IWM_NUM_KEYS; i++) 739 for (i = 0; i < IWM_NUM_KEYS; i++)
764 if (iwm->keys[i].in_use) { 740 if (iwm->keys[i].key_len) {
765 int default_key = 0;
766 struct iwm_key *key = &iwm->keys[i]; 741 struct iwm_key *key = &iwm->keys[i];
767 742
768 if (key == iwm->default_key)
769 default_key = 1;
770
771 /* Wait for the profile before sending the keys */ 743 /* Wait for the profile before sending the keys */
772 wait_event_interruptible_timeout(iwm->mlme_queue, 744 wait_event_interruptible_timeout(iwm->mlme_queue,
773 (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) || 745 (test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
774 test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)), 746 test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
775 3 * HZ); 747 3 * HZ);
776 748
777 ret = iwm_set_key(iwm, 0, default_key, key); 749 ret = iwm_set_key(iwm, 0, key);
778 if (ret < 0) 750 if (ret < 0)
779 return ret; 751 return ret;
752
753 if (iwm->default_key == i) {
754 ret = iwm_set_tx_key(iwm, i);
755 if (ret < 0)
756 return ret;
757 }
780 } 758 }
781 759
782 return 0; 760 return 0;
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 36b13a130595..3510df8ff391 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -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/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index d8d4ae2d91b0..90b05d999635 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -162,13 +162,11 @@ struct iwm_umac_key_hdr {
162 162
163struct iwm_key { 163struct iwm_key {
164 struct iwm_umac_key_hdr hdr; 164 struct iwm_umac_key_hdr hdr;
165 u8 in_use; 165 u32 cipher;
166 u8 alg; 166 u8 key[WLAN_MAX_KEY_LEN];
167 u32 flags; 167 u8 seq[IW_ENCODE_SEQ_MAX_SIZE];
168 u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; 168 int key_len;
169 u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; 169 int seq_len;
170 u8 key_len;
171 u8 key[32];
172}; 170};
173 171
174#define IWM_RX_ID_HASH 0xff 172#define IWM_RX_ID_HASH 0xff
@@ -276,7 +274,7 @@ struct iwm_priv {
276 struct iwm_tx_queue txq[IWM_TX_QUEUES]; 274 struct iwm_tx_queue txq[IWM_TX_QUEUES];
277 275
278 struct iwm_key keys[IWM_NUM_KEYS]; 276 struct iwm_key keys[IWM_NUM_KEYS];
279 struct iwm_key *default_key; 277 s8 default_key;
280 278
281 DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); 279 DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX);
282 wait_queue_head_t wifi_ntfy_queue; 280 wait_queue_head_t wifi_ntfy_queue;
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index 844872213a12..7f56c06a53db 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -230,7 +230,7 @@ int iwm_priv_init(struct iwm_priv *iwm)
230 for (i = 0; i < IWM_NUM_KEYS; i++) 230 for (i = 0; i < IWM_NUM_KEYS; i++)
231 memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); 231 memset(&iwm->keys[i], 0, sizeof(struct iwm_key));
232 232
233 iwm->default_key = NULL; 233 iwm->default_key = -1;
234 234
235 init_timer(&iwm->watchdog); 235 init_timer(&iwm->watchdog);
236 iwm->watchdog.function = iwm_watchdog; 236 iwm->watchdog.function = iwm_watchdog;
@@ -709,7 +709,7 @@ int __iwm_down(struct iwm_priv *iwm)
709 iwm->umac_profile = NULL; 709 iwm->umac_profile = NULL;
710 iwm_bss_list_clean(iwm); 710 iwm_bss_list_clean(iwm);
711 711
712 iwm->default_key = NULL; 712 iwm->default_key = -1;
713 iwm->core_enabled = 0; 713 iwm->core_enabled = 0;
714 714
715 ret = iwm_bus_disable(iwm); 715 ret = iwm_bus_disable(iwm);
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c
index 889194931b4e..3062f37bbe95 100644
--- a/drivers/net/wireless/iwmc3200wifi/wext.c
+++ b/drivers/net/wireless/iwmc3200wifi/wext.c
@@ -84,6 +84,8 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
84 struct iwm_priv *iwm = ndev_to_iwm(dev); 84 struct iwm_priv *iwm = ndev_to_iwm(dev);
85 int ret; 85 int ret;
86 86
87 IWM_DBG_WEXT(iwm, DBG, "Set BSSID: %pM\n", ap_addr->sa_data);
88
87 if (iwm->conf.mode == UMAC_MODE_IBSS) 89 if (iwm->conf.mode == UMAC_MODE_IBSS)
88 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); 90 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
89 91
@@ -116,8 +118,7 @@ static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
116 */ 118 */
117 if (is_zero_ether_addr(ap_addr->sa_data)) { 119 if (is_zero_ether_addr(ap_addr->sa_data)) {
118 for (i = 0; i < IWM_NUM_KEYS; i++) 120 for (i = 0; i < IWM_NUM_KEYS; i++)
119 iwm->keys[i].in_use = 0; 121 iwm->keys[i].key_len = 0;
120
121 } 122 }
122 123
123 ret = iwm_invalidate_mlme_profile(iwm); 124 ret = iwm_invalidate_mlme_profile(iwm);
@@ -163,6 +164,8 @@ static int iwm_wext_siwessid(struct net_device *dev,
163 size_t len = data->length; 164 size_t len = data->length;
164 int ret; 165 int ret;
165 166
167 IWM_DBG_WEXT(iwm, DBG, "Set ESSID: >%s<\n", ssid);
168
166 if (iwm->conf.mode == UMAC_MODE_IBSS) 169 if (iwm->conf.mode == UMAC_MODE_IBSS)
167 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); 170 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
168 171
@@ -212,27 +215,6 @@ static int iwm_wext_giwessid(struct net_device *dev,
212 return 0; 215 return 0;
213} 216}
214 217
215static struct iwm_key *
216iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
217 struct iw_encode_ext *ext, u8 alg)
218{
219 struct iwm_key *key = &iwm->keys[key_idx];
220
221 memset(key, 0, sizeof(struct iwm_key));
222 memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
223 key->hdr.key_idx = key_idx;
224 if (is_broadcast_ether_addr(ext->addr.sa_data))
225 key->hdr.multicast = 1;
226
227 key->in_use = in_use;
228 key->flags = ext->ext_flags;
229 key->alg = alg;
230 key->key_len = ext->key_len;
231 memcpy(key->key, ext->key, ext->key_len);
232
233 return key;
234}
235
236static int iwm_wext_giwrate(struct net_device *dev, 218static int iwm_wext_giwrate(struct net_device *dev,
237 struct iw_request_info *info, 219 struct iw_request_info *info,
238 struct iw_param *rate, char *extra) 220 struct iw_param *rate, char *extra)
@@ -244,184 +226,6 @@ static int iwm_wext_giwrate(struct net_device *dev,
244 return 0; 226 return 0;
245} 227}
246 228
247static int iwm_wext_siwencode(struct net_device *dev,
248 struct iw_request_info *info,
249 struct iw_point *erq, char *key_buf)
250{
251 struct iwm_priv *iwm = ndev_to_iwm(dev);
252 struct iwm_key *uninitialized_var(key);
253 int idx, i, uninitialized_var(alg), remove = 0, ret;
254
255 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
256 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
257
258 if (!iwm->umac_profile) {
259 IWM_ERR(iwm, "UMAC profile not allocated yet\n");
260 return -ENODEV;
261 }
262
263 if (erq->length == WLAN_KEY_LEN_WEP40) {
264 alg = UMAC_CIPHER_TYPE_WEP_40;
265 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
266 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
267 } else if (erq->length == WLAN_KEY_LEN_WEP104) {
268 alg = UMAC_CIPHER_TYPE_WEP_104;
269 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
270 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
271 }
272
273 if (erq->flags & IW_ENCODE_RESTRICTED)
274 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
275 else
276 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
277
278 idx = erq->flags & IW_ENCODE_INDEX;
279 if (idx == 0) {
280 if (iwm->default_key)
281 for (i = 0; i < IWM_NUM_KEYS; i++) {
282 if (iwm->default_key == &iwm->keys[i]) {
283 idx = i;
284 break;
285 }
286 }
287 else
288 iwm->default_key = &iwm->keys[idx];
289 } else if (idx < 1 || idx > 4) {
290 return -EINVAL;
291 } else
292 idx--;
293
294 if (erq->flags & IW_ENCODE_DISABLED)
295 remove = 1;
296 else if (erq->length == 0) {
297 if (!iwm->keys[idx].in_use)
298 return -EINVAL;
299 iwm->default_key = &iwm->keys[idx];
300 }
301
302 if (erq->length) {
303 key = &iwm->keys[idx];
304 memset(key, 0, sizeof(struct iwm_key));
305 memset(key->hdr.mac, 0xff, ETH_ALEN);
306 key->hdr.key_idx = idx;
307 key->hdr.multicast = 1;
308 key->in_use = !remove;
309 key->alg = alg;
310 key->key_len = erq->length;
311 memcpy(key->key, key_buf, erq->length);
312
313 IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
314 idx, !!iwm->default_key);
315 }
316
317 if (remove) {
318 if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
319 int j;
320 for (j = 0; j < IWM_NUM_KEYS; j++)
321 if (iwm->keys[j].in_use) {
322 struct iwm_key *k = &iwm->keys[j];
323
324 k->in_use = 0;
325 ret = iwm_set_key(iwm, remove, 0, k);
326 if (ret < 0)
327 return ret;
328 }
329
330 iwm->umac_profile->sec.ucast_cipher =
331 UMAC_CIPHER_TYPE_NONE;
332 iwm->umac_profile->sec.mcast_cipher =
333 UMAC_CIPHER_TYPE_NONE;
334 iwm->umac_profile->sec.auth_type =
335 UMAC_AUTH_TYPE_OPEN;
336
337 return 0;
338 } else {
339 key->in_use = 0;
340 return iwm_set_key(iwm, remove, 0, key);
341 }
342 }
343
344 /*
345 * If we havent set a profile yet, we cant set keys.
346 * Keys will be pushed after we're associated.
347 */
348 if (!iwm->umac_profile_active)
349 return 0;
350
351 /*
352 * If there is a current active profile, but no
353 * default key, it's not worth trying to associate again.
354 */
355 if (!iwm->default_key)
356 return 0;
357
358 /*
359 * Here we have an active profile, but a key setting changed.
360 * We thus have to invalidate the current profile, and push the
361 * new one. Keys will be pushed when association takes place.
362 */
363 ret = iwm_invalidate_mlme_profile(iwm);
364 if (ret < 0) {
365 IWM_ERR(iwm, "Couldn't invalidate profile\n");
366 return ret;
367 }
368
369 return iwm_send_mlme_profile(iwm);
370}
371
372static int iwm_wext_giwencode(struct net_device *dev,
373 struct iw_request_info *info,
374 struct iw_point *erq, char *key)
375{
376 struct iwm_priv *iwm = ndev_to_iwm(dev);
377 int idx, i;
378
379 idx = erq->flags & IW_ENCODE_INDEX;
380 if (idx < 1 || idx > 4) {
381 idx = -1;
382 if (!iwm->default_key) {
383 erq->length = 0;
384 erq->flags |= IW_ENCODE_NOKEY;
385 return 0;
386 } else
387 for (i = 0; i < IWM_NUM_KEYS; i++) {
388 if (iwm->default_key == &iwm->keys[i]) {
389 idx = i;
390 break;
391 }
392 }
393 if (idx < 0)
394 return -EINVAL;
395 } else
396 idx--;
397
398 erq->flags = idx + 1;
399
400 if (!iwm->keys[idx].in_use) {
401 erq->length = 0;
402 erq->flags |= IW_ENCODE_DISABLED;
403 return 0;
404 }
405
406 memcpy(key, iwm->keys[idx].key,
407 min_t(int, erq->length, iwm->keys[idx].key_len));
408 erq->length = iwm->keys[idx].key_len;
409 erq->flags |= IW_ENCODE_ENABLED;
410
411 if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
412 switch (iwm->umac_profile->sec.auth_type) {
413 case UMAC_AUTH_TYPE_OPEN:
414 erq->flags |= IW_ENCODE_OPEN;
415 break;
416 default:
417 erq->flags |= IW_ENCODE_RESTRICTED;
418 break;
419 }
420 }
421
422 return 0;
423}
424
425static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) 229static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
426{ 230{
427 if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) 231 if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
@@ -481,6 +285,8 @@ static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
481{ 285{
482 u8 *auth_type = &iwm->umac_profile->sec.auth_type; 286 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
483 287
288 IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt);
289
484 if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) 290 if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
485 *auth_type = UMAC_AUTH_TYPE_8021X; 291 *auth_type = UMAC_AUTH_TYPE_8021X;
486 else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { 292 else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
@@ -530,6 +336,8 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
530{ 336{
531 u8 *auth_type = &iwm->umac_profile->sec.auth_type; 337 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
532 338
339 IWM_DBG_WEXT(iwm, DBG, "auth_alg: 0x%x\n", auth_alg);
340
533 switch (auth_alg) { 341 switch (auth_alg) {
534 case IW_AUTH_ALG_OPEN_SYSTEM: 342 case IW_AUTH_ALG_OPEN_SYSTEM:
535 *auth_type = UMAC_AUTH_TYPE_OPEN; 343 *auth_type = UMAC_AUTH_TYPE_OPEN;
@@ -541,6 +349,7 @@ static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
541 return -EINVAL; 349 return -EINVAL;
542 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; 350 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
543 } else { 351 } else {
352 IWM_DBG_WEXT(iwm, DBG, "WEP shared key\n");
544 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; 353 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
545 } 354 }
546 break; 355 break;
@@ -603,75 +412,6 @@ static int iwm_wext_giwauth(struct net_device *dev,
603 return 0; 412 return 0;
604} 413}
605 414
606static int iwm_wext_siwencodeext(struct net_device *dev,
607 struct iw_request_info *info,
608 struct iw_point *erq, char *extra)
609{
610 struct iwm_priv *iwm = ndev_to_iwm(dev);
611 struct iwm_key *key;
612 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
613 int uninitialized_var(alg), idx, i, remove = 0;
614
615 IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
616 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
617 IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
618 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
619 IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
620
621 switch (ext->alg) {
622 case IW_ENCODE_ALG_NONE:
623 remove = 1;
624 break;
625 case IW_ENCODE_ALG_WEP:
626 if (ext->key_len == WLAN_KEY_LEN_WEP40)
627 alg = UMAC_CIPHER_TYPE_WEP_40;
628 else if (ext->key_len == WLAN_KEY_LEN_WEP104)
629 alg = UMAC_CIPHER_TYPE_WEP_104;
630 else {
631 IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
632 return -EINVAL;
633 }
634
635 break;
636 case IW_ENCODE_ALG_TKIP:
637 alg = UMAC_CIPHER_TYPE_TKIP;
638 break;
639 case IW_ENCODE_ALG_CCMP:
640 alg = UMAC_CIPHER_TYPE_CCMP;
641 break;
642 default:
643 return -EOPNOTSUPP;
644 }
645
646 idx = erq->flags & IW_ENCODE_INDEX;
647
648 if (idx == 0) {
649 if (iwm->default_key)
650 for (i = 0; i < IWM_NUM_KEYS; i++) {
651 if (iwm->default_key == &iwm->keys[i]) {
652 idx = i;
653 break;
654 }
655 }
656 } else if (idx < 1 || idx > 4) {
657 return -EINVAL;
658 } else
659 idx--;
660
661 if (erq->flags & IW_ENCODE_DISABLED)
662 remove = 1;
663 else if ((erq->length == 0) ||
664 (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
665 iwm->default_key = &iwm->keys[idx];
666 if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
667 return iwm_set_tx_key(iwm, idx);
668 }
669
670 key = iwm_key_init(iwm, idx, !remove, ext, alg);
671
672 return iwm_set_key(iwm, remove, !iwm->default_key, key);
673}
674
675static const iw_handler iwm_handlers[] = 415static const iw_handler iwm_handlers[] =
676{ 416{
677 (iw_handler) NULL, /* SIOCSIWCOMMIT */ 417 (iw_handler) NULL, /* SIOCSIWCOMMIT */
@@ -716,8 +456,8 @@ static const iw_handler iwm_handlers[] =
716 (iw_handler) NULL, /* SIOCGIWTXPOW */ 456 (iw_handler) NULL, /* SIOCGIWTXPOW */
717 (iw_handler) NULL, /* SIOCSIWRETRY */ 457 (iw_handler) NULL, /* SIOCSIWRETRY */
718 (iw_handler) NULL, /* SIOCGIWRETRY */ 458 (iw_handler) NULL, /* SIOCGIWRETRY */
719 (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ 459 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
720 (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ 460 (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
721 (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ 461 (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
722 (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ 462 (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
723 (iw_handler) NULL, /* -- hole -- */ 463 (iw_handler) NULL, /* -- hole -- */
@@ -726,7 +466,7 @@ static const iw_handler iwm_handlers[] =
726 (iw_handler) NULL, /* SIOCGIWGENIE */ 466 (iw_handler) NULL, /* SIOCGIWGENIE */
727 (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ 467 (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
728 (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ 468 (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
729 (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ 469 (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
730 (iw_handler) NULL, /* SIOCGIWENCODEEXT */ 470 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
731 (iw_handler) NULL, /* SIOCSIWPMKSA */ 471 (iw_handler) NULL, /* SIOCSIWPMKSA */
732 (iw_handler) NULL, /* -- hole -- */ 472 (iw_handler) NULL, /* -- hole -- */