aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwmc3200wifi/cfg80211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/cfg80211.c')
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c378
1 files changed, 371 insertions, 7 deletions
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");