aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-08 08:22:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-24 15:05:09 -0400
commitfffd0934b9390f34bec45762192b7edd3b12b4b5 (patch)
treed9779803763261f5795fe39a402d79c4220a3a22
parentb9454e83cac42fcdc90bfbfba479132bd6629455 (diff)
cfg80211: rework key operation
This reworks the key operation in cfg80211, and now only allows, from userspace, configuring keys (via nl80211) after the connection has been established (in managed mode), the IBSS been joined (in IBSS mode), at any time (in AP[_VLAN] modes) or never for all the other modes. In order to do shared key authentication correctly, it is now possible to give a WEP key to the AUTH command. To configure static WEP keys, these are given to the CONNECT or IBSS_JOIN command directly, for a userspace SME it is assumed it will configure it properly after the connection has been established. Since mac80211 used to check the default key in IBSS mode to see whether or not the network is protected, it needs an update in that area, as well as an update to make use of the WEP key passed to auth() for shared key authentication. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--include/linux/nl80211.h5
-rw-r--r--include/net/cfg80211.h18
-rw-r--r--net/mac80211/ibss.c9
-rw-r--r--net/mac80211/ieee80211_i.h8
-rw-r--r--net/mac80211/mlme.c11
-rw-r--r--net/mac80211/util.c16
-rw-r--r--net/mac80211/wep.c6
-rw-r--r--net/mac80211/wep.h3
-rw-r--r--net/wireless/core.c11
-rw-r--r--net/wireless/core.h32
-rw-r--r--net/wireless/ibss.c79
-rw-r--r--net/wireless/mlme.c16
-rw-r--r--net/wireless/nl80211.c170
-rw-r--r--net/wireless/sme.c97
-rw-r--r--net/wireless/util.c41
-rw-r--r--net/wireless/wext-compat.c163
-rw-r--r--net/wireless/wext-sme.c30
17 files changed, 554 insertions, 161 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 48e0913c2209..b043b78dd2c3 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -569,6 +569,9 @@ enum nl80211_commands {
569 * 569 *
570 * @NL80211_ATTR_KEY: key information in a nested attribute with 570 * @NL80211_ATTR_KEY: key information in a nested attribute with
571 * %NL80211_KEY_* sub-attributes 571 * %NL80211_KEY_* sub-attributes
572 * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
573 * and join_ibss(), key information is in a nested attribute each
574 * with %NL80211_KEY_* sub-attributes
572 * 575 *
573 * @NL80211_ATTR_MAX: highest attribute number currently defined 576 * @NL80211_ATTR_MAX: highest attribute number currently defined
574 * @__NL80211_ATTR_AFTER_LAST: internal use 577 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -696,6 +699,7 @@ enum nl80211_attrs {
696 NL80211_ATTR_PREV_BSSID, 699 NL80211_ATTR_PREV_BSSID,
697 700
698 NL80211_ATTR_KEY, 701 NL80211_ATTR_KEY,
702 NL80211_ATTR_KEYS,
699 703
700 /* add attributes here, update the policy in nl80211.c */ 704 /* add attributes here, update the policy in nl80211.c */
701 705
@@ -726,6 +730,7 @@ enum nl80211_attrs {
726#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS 730#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
727#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES 731#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
728#define NL80211_ATTR_KEY NL80211_ATTR_KEY 732#define NL80211_ATTR_KEY NL80211_ATTR_KEY
733#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
729 734
730#define NL80211_MAX_SUPP_RATES 32 735#define NL80211_MAX_SUPP_RATES 32
731#define NL80211_MAX_SUPP_REG_RULES 32 736#define NL80211_MAX_SUPP_REG_RULES 32
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 83c2c727d71e..65a5cbcb5d14 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -647,12 +647,17 @@ struct cfg80211_crypto_settings {
647 * @auth_type: Authentication type (algorithm) 647 * @auth_type: Authentication type (algorithm)
648 * @ie: Extra IEs to add to Authentication frame or %NULL 648 * @ie: Extra IEs to add to Authentication frame or %NULL
649 * @ie_len: Length of ie buffer in octets 649 * @ie_len: Length of ie buffer in octets
650 * @key_len: length of WEP key for shared key authentication
651 * @key_idx: index of WEP key for shared key authentication
652 * @key: WEP key for shared key authentication
650 */ 653 */
651struct cfg80211_auth_request { 654struct cfg80211_auth_request {
652 struct cfg80211_bss *bss; 655 struct cfg80211_bss *bss;
653 const u8 *ie; 656 const u8 *ie;
654 size_t ie_len; 657 size_t ie_len;
655 enum nl80211_auth_type auth_type; 658 enum nl80211_auth_type auth_type;
659 const u8 *key;
660 u8 key_len, key_idx;
656}; 661};
657 662
658/** 663/**
@@ -727,6 +732,8 @@ struct cfg80211_disassoc_request {
727 * @ie: information element(s) to include in the beacon 732 * @ie: information element(s) to include in the beacon
728 * @ie_len: length of that 733 * @ie_len: length of that
729 * @beacon_interval: beacon interval to use 734 * @beacon_interval: beacon interval to use
735 * @privacy: this is a protected network, keys will be configured
736 * after joining
730 */ 737 */
731struct cfg80211_ibss_params { 738struct cfg80211_ibss_params {
732 u8 *ssid; 739 u8 *ssid;
@@ -736,6 +743,7 @@ struct cfg80211_ibss_params {
736 u8 ssid_len, ie_len; 743 u8 ssid_len, ie_len;
737 u16 beacon_interval; 744 u16 beacon_interval;
738 bool channel_fixed; 745 bool channel_fixed;
746 bool privacy;
739}; 747};
740 748
741/** 749/**
@@ -755,6 +763,9 @@ struct cfg80211_ibss_params {
755 * @assoc_ie_len: Length of assoc_ie in octets 763 * @assoc_ie_len: Length of assoc_ie in octets
756 * @privacy: indicates whether privacy-enabled APs should be used 764 * @privacy: indicates whether privacy-enabled APs should be used
757 * @crypto: crypto settings 765 * @crypto: crypto settings
766 * @key_len: length of WEP key for shared key authentication
767 * @key_idx: index of WEP key for shared key authentication
768 * @key: WEP key for shared key authentication
758 */ 769 */
759struct cfg80211_connect_params { 770struct cfg80211_connect_params {
760 struct ieee80211_channel *channel; 771 struct ieee80211_channel *channel;
@@ -766,6 +777,8 @@ struct cfg80211_connect_params {
766 size_t ie_len; 777 size_t ie_len;
767 bool privacy; 778 bool privacy;
768 struct cfg80211_crypto_settings crypto; 779 struct cfg80211_crypto_settings crypto;
780 const u8 *key;
781 u8 key_len, key_idx;
769}; 782};
770 783
771/** 784/**
@@ -1223,9 +1236,10 @@ extern void wiphy_unregister(struct wiphy *wiphy);
1223 */ 1236 */
1224extern void wiphy_free(struct wiphy *wiphy); 1237extern void wiphy_free(struct wiphy *wiphy);
1225 1238
1226/* internal struct */ 1239/* internal structs */
1227struct cfg80211_conn; 1240struct cfg80211_conn;
1228struct cfg80211_internal_bss; 1241struct cfg80211_internal_bss;
1242struct cfg80211_cached_keys;
1229 1243
1230#define MAX_AUTH_BSSES 4 1244#define MAX_AUTH_BSSES 4
1231 1245
@@ -1267,6 +1281,7 @@ struct wireless_dev {
1267 CFG80211_SME_CONNECTED, 1281 CFG80211_SME_CONNECTED,
1268 } sme_state; 1282 } sme_state;
1269 struct cfg80211_conn *conn; 1283 struct cfg80211_conn *conn;
1284 struct cfg80211_cached_keys *connect_keys;
1270 1285
1271 struct list_head event_list; 1286 struct list_head event_list;
1272 spinlock_t event_lock; 1287 spinlock_t event_lock;
@@ -1280,6 +1295,7 @@ struct wireless_dev {
1280 struct { 1295 struct {
1281 struct cfg80211_ibss_params ibss; 1296 struct cfg80211_ibss_params ibss;
1282 struct cfg80211_connect_params connect; 1297 struct cfg80211_connect_params connect;
1298 struct cfg80211_cached_keys *keys;
1283 u8 *ie; 1299 u8 *ie;
1284 size_t ie_len; 1300 size_t ie_len;
1285 u8 bssid[ETH_ALEN]; 1301 u8 bssid[ETH_ALEN];
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 15d5a53b59a8..8e2220000e5c 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -57,7 +57,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
57 */ 57 */
58 if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1) 58 if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
59 ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0, 59 ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
60 sdata->u.ibss.bssid, 0); 60 sdata->u.ibss.bssid, NULL, 0, 0);
61} 61}
62 62
63static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, 63static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
@@ -494,7 +494,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
494 494
495 capability = WLAN_CAPABILITY_IBSS; 495 capability = WLAN_CAPABILITY_IBSS;
496 496
497 if (sdata->default_key) 497 if (ifibss->privacy)
498 capability |= WLAN_CAPABILITY_PRIVACY; 498 capability |= WLAN_CAPABILITY_PRIVACY;
499 else 499 else
500 sdata->drop_unencrypted = 0; 500 sdata->drop_unencrypted = 0;
@@ -524,9 +524,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
524 return; 524 return;
525 525
526 capability = WLAN_CAPABILITY_IBSS; 526 capability = WLAN_CAPABILITY_IBSS;
527 if (sdata->default_key) 527 if (ifibss->privacy)
528 capability |= WLAN_CAPABILITY_PRIVACY; 528 capability |= WLAN_CAPABILITY_PRIVACY;
529
530 if (ifibss->fixed_bssid) 529 if (ifibss->fixed_bssid)
531 bssid = ifibss->bssid; 530 bssid = ifibss->bssid;
532 if (ifibss->fixed_channel) 531 if (ifibss->fixed_channel)
@@ -872,6 +871,8 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
872 } else 871 } else
873 sdata->u.ibss.fixed_bssid = false; 872 sdata->u.ibss.fixed_bssid = false;
874 873
874 sdata->u.ibss.privacy = params->privacy;
875
875 sdata->vif.bss_conf.beacon_int = params->beacon_interval; 876 sdata->vif.bss_conf.beacon_int = params->beacon_interval;
876 877
877 sdata->u.ibss.channel = params->channel; 878 sdata->u.ibss.channel = params->channel;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 327aabc07abe..06b3411530f2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -247,6 +247,9 @@ struct ieee80211_mgd_work {
247 247
248 int tries; 248 int tries;
249 249
250 u8 key[WLAN_KEY_LEN_WEP104];
251 u8 key_len, key_idx;
252
250 /* must be last */ 253 /* must be last */
251 u8 ie[0]; /* for auth or assoc frame, not probe */ 254 u8 ie[0]; /* for auth or assoc frame, not probe */
252}; 255};
@@ -321,6 +324,7 @@ struct ieee80211_if_ibss {
321 324
322 bool fixed_bssid; 325 bool fixed_bssid;
323 bool fixed_channel; 326 bool fixed_channel;
327 bool privacy;
324 328
325 u8 bssid[ETH_ALEN]; 329 u8 bssid[ETH_ALEN];
326 u8 ssid[IEEE80211_MAX_SSID_LEN]; 330 u8 ssid[IEEE80211_MAX_SSID_LEN];
@@ -1093,8 +1097,8 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
1093 1097
1094void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 1098void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
1095 u16 transaction, u16 auth_alg, 1099 u16 transaction, u16 auth_alg,
1096 u8 *extra, size_t extra_len, 1100 u8 *extra, size_t extra_len, const u8 *bssid,
1097 const u8 *bssid, int encrypt); 1101 const u8 *key, u8 key_len, u8 key_idx);
1098int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 1102int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
1099 const u8 *ie, size_t ie_len); 1103 const u8 *ie, size_t ie_len);
1100void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 1104void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index c9db9646025b..8e4a60497bba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -954,7 +954,7 @@ ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
954 sdata->dev->name, wk->bss->cbss.bssid, wk->tries); 954 sdata->dev->name, wk->bss->cbss.bssid, wk->tries);
955 955
956 ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len, 956 ieee80211_send_auth(sdata, 1, wk->auth_alg, wk->ie, wk->ie_len,
957 wk->bss->cbss.bssid, 0); 957 wk->bss->cbss.bssid, NULL, 0, 0);
958 wk->auth_transaction = 2; 958 wk->auth_transaction = 2;
959 959
960 wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT; 960 wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
@@ -1176,7 +1176,8 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
1176 return; 1176 return;
1177 ieee80211_send_auth(sdata, 3, wk->auth_alg, 1177 ieee80211_send_auth(sdata, 3, wk->auth_alg,
1178 elems.challenge - 2, elems.challenge_len + 2, 1178 elems.challenge - 2, elems.challenge_len + 2,
1179 wk->bss->cbss.bssid, 1); 1179 wk->bss->cbss.bssid,
1180 wk->key, wk->key_len, wk->key_idx);
1180 wk->auth_transaction = 4; 1181 wk->auth_transaction = 4;
1181} 1182}
1182 1183
@@ -2175,6 +2176,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
2175 wk->ie_len = req->ie_len; 2176 wk->ie_len = req->ie_len;
2176 } 2177 }
2177 2178
2179 if (req->key && req->key_len) {
2180 wk->key_len = req->key_len;
2181 wk->key_idx = req->key_idx;
2182 memcpy(wk->key, req->key, req->key_len);
2183 }
2184
2178 ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); 2185 ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
2179 memcpy(wk->ssid, ssid + 2, ssid[1]); 2186 memcpy(wk->ssid, ssid + 2, ssid[1]);
2180 wk->ssid_len = ssid[1]; 2187 wk->ssid_len = ssid[1];
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 915e77769312..dbf66b52d38c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -31,6 +31,7 @@
31#include "mesh.h" 31#include "mesh.h"
32#include "wme.h" 32#include "wme.h"
33#include "led.h" 33#include "led.h"
34#include "wep.h"
34 35
35/* privid for wiphys to determine whether they belong to us or not */ 36/* privid for wiphys to determine whether they belong to us or not */
36void *mac80211_wiphy_privid = &mac80211_wiphy_privid; 37void *mac80211_wiphy_privid = &mac80211_wiphy_privid;
@@ -804,12 +805,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
804 805
805void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, 806void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
806 u16 transaction, u16 auth_alg, 807 u16 transaction, u16 auth_alg,
807 u8 *extra, size_t extra_len, 808 u8 *extra, size_t extra_len, const u8 *bssid,
808 const u8 *bssid, int encrypt) 809 const u8 *key, u8 key_len, u8 key_idx)
809{ 810{
810 struct ieee80211_local *local = sdata->local; 811 struct ieee80211_local *local = sdata->local;
811 struct sk_buff *skb; 812 struct sk_buff *skb;
812 struct ieee80211_mgmt *mgmt; 813 struct ieee80211_mgmt *mgmt;
814 int err;
813 815
814 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 816 skb = dev_alloc_skb(local->hw.extra_tx_headroom +
815 sizeof(*mgmt) + 6 + extra_len); 817 sizeof(*mgmt) + 6 + extra_len);
@@ -824,8 +826,6 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
824 memset(mgmt, 0, 24 + 6); 826 memset(mgmt, 0, 24 + 6);
825 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | 827 mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
826 IEEE80211_STYPE_AUTH); 828 IEEE80211_STYPE_AUTH);
827 if (encrypt)
828 mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
829 memcpy(mgmt->da, bssid, ETH_ALEN); 829 memcpy(mgmt->da, bssid, ETH_ALEN);
830 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); 830 memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
831 memcpy(mgmt->bssid, bssid, ETH_ALEN); 831 memcpy(mgmt->bssid, bssid, ETH_ALEN);
@@ -835,7 +835,13 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
835 if (extra) 835 if (extra)
836 memcpy(skb_put(skb, extra_len), extra, extra_len); 836 memcpy(skb_put(skb, extra_len), extra, extra_len);
837 837
838 ieee80211_tx_skb(sdata, skb, encrypt); 838 if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
839 mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
840 err = ieee80211_wep_encrypt(local, skb, key, key_len, key_idx);
841 WARN_ON(err);
842 }
843
844 ieee80211_tx_skb(sdata, skb, 0);
839} 845}
840 846
841int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, 847int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c
index 4fafb2d27c84..8a980f136941 100644
--- a/net/mac80211/wep.c
+++ b/net/mac80211/wep.c
@@ -144,9 +144,9 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
144 * 144 *
145 * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) 145 * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data))
146 */ 146 */
147static int ieee80211_wep_encrypt(struct ieee80211_local *local, 147int ieee80211_wep_encrypt(struct ieee80211_local *local,
148 struct sk_buff *skb, 148 struct sk_buff *skb,
149 const u8 *key, int keylen, int keyidx) 149 const u8 *key, int keylen, int keyidx)
150{ 150{
151 u8 *iv; 151 u8 *iv;
152 size_t len; 152 size_t len;
diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h
index 85219ded8703..fe29d7e5759f 100644
--- a/net/mac80211/wep.h
+++ b/net/mac80211/wep.h
@@ -20,6 +20,9 @@ int ieee80211_wep_init(struct ieee80211_local *local);
20void ieee80211_wep_free(struct ieee80211_local *local); 20void ieee80211_wep_free(struct ieee80211_local *local);
21void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, 21void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
22 size_t klen, u8 *data, size_t data_len); 22 size_t klen, u8 *data, size_t data_len);
23int ieee80211_wep_encrypt(struct ieee80211_local *local,
24 struct sk_buff *skb,
25 const u8 *key, int keylen, int keyidx);
23int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, 26int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key,
24 size_t klen, u8 *data, size_t data_len); 27 size_t klen, u8 *data, size_t data_len);
25bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); 28bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 1a78b3c70cf2..97cc5968b7d6 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -666,14 +666,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
666 wdev_lock(wdev); 666 wdev_lock(wdev);
667 switch (wdev->iftype) { 667 switch (wdev->iftype) {
668 case NL80211_IFTYPE_ADHOC: 668 case NL80211_IFTYPE_ADHOC:
669 if (wdev->wext.ibss.ssid_len) 669 cfg80211_ibss_wext_join(rdev, wdev);
670 __cfg80211_join_ibss(rdev, dev,
671 &wdev->wext.ibss);
672 break; 670 break;
673 case NL80211_IFTYPE_STATION: 671 case NL80211_IFTYPE_STATION:
674 if (wdev->wext.connect.ssid_len) 672 cfg80211_mgd_wext_connect(rdev, wdev);
675 __cfg80211_connect(rdev, dev,
676 &wdev->wext.connect);
677 break; 673 break;
678 default: 674 default:
679 break; 675 break;
@@ -690,6 +686,9 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
690 } 686 }
691 mutex_unlock(&rdev->devlist_mtx); 687 mutex_unlock(&rdev->devlist_mtx);
692 mutex_destroy(&wdev->mtx); 688 mutex_destroy(&wdev->mtx);
689#ifdef CONFIG_WIRELESS_EXT
690 kfree(wdev->wext.keys);
691#endif
693 break; 692 break;
694 case NETDEV_PRE_UP: 693 case NETDEV_PRE_UP:
695 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) 694 if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
diff --git a/net/wireless/core.h b/net/wireless/core.h
index e46cd6eb61d7..2ec8ddbe57de 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -238,6 +238,12 @@ struct cfg80211_event {
238 }; 238 };
239}; 239};
240 240
241struct cfg80211_cached_keys {
242 struct key_params params[6];
243 u8 data[6][WLAN_MAX_KEY_LEN];
244 int def, defmgmt;
245};
246
241 247
242/* free object */ 248/* free object */
243extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); 249extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -256,14 +262,18 @@ void cfg80211_bss_age(struct cfg80211_registered_device *dev,
256/* IBSS */ 262/* IBSS */
257int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 263int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
258 struct net_device *dev, 264 struct net_device *dev,
259 struct cfg80211_ibss_params *params); 265 struct cfg80211_ibss_params *params,
266 struct cfg80211_cached_keys *connkeys);
260int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 267int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
261 struct net_device *dev, 268 struct net_device *dev,
262 struct cfg80211_ibss_params *params); 269 struct cfg80211_ibss_params *params,
270 struct cfg80211_cached_keys *connkeys);
263void cfg80211_clear_ibss(struct net_device *dev, bool nowext); 271void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
264int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 272int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
265 struct net_device *dev, bool nowext); 273 struct net_device *dev, bool nowext);
266void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); 274void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid);
275int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
276 struct wireless_dev *wdev);
267 277
268/* MLME */ 278/* MLME */
269int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 279int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
@@ -272,12 +282,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
272 enum nl80211_auth_type auth_type, 282 enum nl80211_auth_type auth_type,
273 const u8 *bssid, 283 const u8 *bssid,
274 const u8 *ssid, int ssid_len, 284 const u8 *ssid, int ssid_len,
275 const u8 *ie, int ie_len); 285 const u8 *ie, int ie_len,
286 const u8 *key, int key_len, int key_idx);
276int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 287int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
277 struct net_device *dev, struct ieee80211_channel *chan, 288 struct net_device *dev, struct ieee80211_channel *chan,
278 enum nl80211_auth_type auth_type, const u8 *bssid, 289 enum nl80211_auth_type auth_type, const u8 *bssid,
279 const u8 *ssid, int ssid_len, 290 const u8 *ssid, int ssid_len,
280 const u8 *ie, int ie_len); 291 const u8 *ie, int ie_len,
292 const u8 *key, int key_len, int key_idx);
281int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 293int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
282 struct net_device *dev, 294 struct net_device *dev,
283 struct ieee80211_channel *chan, 295 struct ieee80211_channel *chan,
@@ -310,10 +322,12 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
310/* SME */ 322/* SME */
311int __cfg80211_connect(struct cfg80211_registered_device *rdev, 323int __cfg80211_connect(struct cfg80211_registered_device *rdev,
312 struct net_device *dev, 324 struct net_device *dev,
313 struct cfg80211_connect_params *connect); 325 struct cfg80211_connect_params *connect,
326 struct cfg80211_cached_keys *connkeys);
314int cfg80211_connect(struct cfg80211_registered_device *rdev, 327int cfg80211_connect(struct cfg80211_registered_device *rdev,
315 struct net_device *dev, 328 struct net_device *dev,
316 struct cfg80211_connect_params *connect); 329 struct cfg80211_connect_params *connect,
330 struct cfg80211_cached_keys *connkeys);
317int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, 331int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
318 struct net_device *dev, u16 reason, 332 struct net_device *dev, u16 reason,
319 bool wextev); 333 bool wextev);
@@ -323,11 +337,14 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
323void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, 337void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid,
324 const u8 *req_ie, size_t req_ie_len, 338 const u8 *req_ie, size_t req_ie_len,
325 const u8 *resp_ie, size_t resp_ie_len); 339 const u8 *resp_ie, size_t resp_ie_len);
340int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
341 struct wireless_dev *wdev);
326 342
327void cfg80211_conn_work(struct work_struct *work); 343void cfg80211_conn_work(struct work_struct *work);
328 344
329/* internal helpers */ 345/* internal helpers */
330int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 346int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
347 struct key_params *params, int key_idx,
331 const u8 *mac_addr); 348 const u8 *mac_addr);
332void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, 349void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
333 size_t ie_len, u16 reason, bool from_ap); 350 size_t ie_len, u16 reason, bool from_ap);
@@ -335,5 +352,6 @@ void cfg80211_sme_scan_done(struct net_device *dev);
335void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 352void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
336void cfg80211_sme_disassoc(struct net_device *dev, int idx); 353void cfg80211_sme_disassoc(struct net_device *dev, int idx);
337void __cfg80211_scan_done(struct work_struct *wk); 354void __cfg80211_scan_done(struct work_struct *wk);
355void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
338 356
339#endif /* __NET_WIRELESS_CORE_H */ 357#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 99ef9364b7e8..9394e78cd11f 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -39,6 +39,8 @@ void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid)
39 cfg80211_hold_bss(bss_from_pub(bss)); 39 cfg80211_hold_bss(bss_from_pub(bss));
40 wdev->current_bss = bss_from_pub(bss); 40 wdev->current_bss = bss_from_pub(bss);
41 41
42 cfg80211_upload_connect_keys(wdev);
43
42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, 44 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid,
43 GFP_KERNEL); 45 GFP_KERNEL);
44#ifdef CONFIG_WIRELESS_EXT 46#ifdef CONFIG_WIRELESS_EXT
@@ -71,7 +73,8 @@ EXPORT_SYMBOL(cfg80211_ibss_joined);
71 73
72int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 74int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
73 struct net_device *dev, 75 struct net_device *dev,
74 struct cfg80211_ibss_params *params) 76 struct cfg80211_ibss_params *params,
77 struct cfg80211_cached_keys *connkeys)
75{ 78{
76 struct wireless_dev *wdev = dev->ieee80211_ptr; 79 struct wireless_dev *wdev = dev->ieee80211_ptr;
77 int err; 80 int err;
@@ -81,13 +84,18 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
81 if (wdev->ssid_len) 84 if (wdev->ssid_len)
82 return -EALREADY; 85 return -EALREADY;
83 86
87 if (WARN_ON(wdev->connect_keys))
88 kfree(wdev->connect_keys);
89 wdev->connect_keys = connkeys;
90
84#ifdef CONFIG_WIRELESS_EXT 91#ifdef CONFIG_WIRELESS_EXT
85 wdev->wext.ibss.channel = params->channel; 92 wdev->wext.ibss.channel = params->channel;
86#endif 93#endif
87 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); 94 err = rdev->ops->join_ibss(&rdev->wiphy, dev, params);
88 95 if (err) {
89 if (err) 96 wdev->connect_keys = NULL;
90 return err; 97 return err;
98 }
91 99
92 memcpy(wdev->ssid, params->ssid, params->ssid_len); 100 memcpy(wdev->ssid, params->ssid, params->ssid_len);
93 wdev->ssid_len = params->ssid_len; 101 wdev->ssid_len = params->ssid_len;
@@ -97,13 +105,14 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
97 105
98int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, 106int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
99 struct net_device *dev, 107 struct net_device *dev,
100 struct cfg80211_ibss_params *params) 108 struct cfg80211_ibss_params *params,
109 struct cfg80211_cached_keys *connkeys)
101{ 110{
102 struct wireless_dev *wdev = dev->ieee80211_ptr; 111 struct wireless_dev *wdev = dev->ieee80211_ptr;
103 int err; 112 int err;
104 113
105 wdev_lock(wdev); 114 wdev_lock(wdev);
106 err = __cfg80211_join_ibss(rdev, dev, params); 115 err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
107 wdev_unlock(wdev); 116 wdev_unlock(wdev);
108 117
109 return err; 118 return err;
@@ -112,9 +121,22 @@ int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
112static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) 121static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
113{ 122{
114 struct wireless_dev *wdev = dev->ieee80211_ptr; 123 struct wireless_dev *wdev = dev->ieee80211_ptr;
124 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
125 int i;
115 126
116 ASSERT_WDEV_LOCK(wdev); 127 ASSERT_WDEV_LOCK(wdev);
117 128
129 kfree(wdev->connect_keys);
130 wdev->connect_keys = NULL;
131
132 /*
133 * Delete all the keys ... pairwise keys can't really
134 * exist any more anyway, but default keys might.
135 */
136 if (rdev->ops->del_key)
137 for (i = 0; i < 6; i++)
138 rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
139
118 if (wdev->current_bss) { 140 if (wdev->current_bss) {
119 cfg80211_unhold_bss(wdev->current_bss); 141 cfg80211_unhold_bss(wdev->current_bss);
120 cfg80211_put_bss(&wdev->current_bss->pub); 142 cfg80211_put_bss(&wdev->current_bss->pub);
@@ -172,11 +194,14 @@ int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
172} 194}
173 195
174#ifdef CONFIG_WIRELESS_EXT 196#ifdef CONFIG_WIRELESS_EXT
175static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, 197int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
176 struct wireless_dev *wdev) 198 struct wireless_dev *wdev)
177{ 199{
200 struct cfg80211_cached_keys *ck = NULL;
178 enum ieee80211_band band; 201 enum ieee80211_band band;
179 int i; 202 int i, err;
203
204 ASSERT_WDEV_LOCK(wdev);
180 205
181 if (!wdev->wext.ibss.beacon_interval) 206 if (!wdev->wext.ibss.beacon_interval)
182 wdev->wext.ibss.beacon_interval = 100; 207 wdev->wext.ibss.beacon_interval = 100;
@@ -216,8 +241,24 @@ static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
216 if (!netif_running(wdev->netdev)) 241 if (!netif_running(wdev->netdev))
217 return 0; 242 return 0;
218 243
219 return cfg80211_join_ibss(wiphy_to_dev(wdev->wiphy), 244 if (wdev->wext.keys)
220 wdev->netdev, &wdev->wext.ibss); 245 wdev->wext.keys->def = wdev->wext.default_key;
246
247 wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
248
249 if (wdev->wext.keys) {
250 ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
251 if (!ck)
252 return -ENOMEM;
253 for (i = 0; i < 6; i++)
254 ck->params[i].key = ck->data[i];
255 }
256 err = __cfg80211_join_ibss(rdev, wdev->netdev,
257 &wdev->wext.ibss, ck);
258 if (err)
259 kfree(ck);
260
261 return err;
221} 262}
222 263
223int cfg80211_ibss_wext_siwfreq(struct net_device *dev, 264int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
@@ -265,7 +306,11 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
265 wdev->wext.ibss.channel_fixed = false; 306 wdev->wext.ibss.channel_fixed = false;
266 } 307 }
267 308
268 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 309 wdev_lock(wdev);
310 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
311 wdev_unlock(wdev);
312
313 return err;
269} 314}
270/* temporary symbol - mark GPL - in the future the handler won't be */ 315/* temporary symbol - mark GPL - in the future the handler won't be */
271EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); 316EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq);
@@ -333,7 +378,11 @@ int cfg80211_ibss_wext_siwessid(struct net_device *dev,
333 memcpy(wdev->wext.ibss.ssid, ssid, len); 378 memcpy(wdev->wext.ibss.ssid, ssid, len);
334 wdev->wext.ibss.ssid_len = len; 379 wdev->wext.ibss.ssid_len = len;
335 380
336 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 381 wdev_lock(wdev);
382 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
383 wdev_unlock(wdev);
384
385 return err;
337} 386}
338/* temporary symbol - mark GPL - in the future the handler won't be */ 387/* temporary symbol - mark GPL - in the future the handler won't be */
339EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); 388EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid);
@@ -414,7 +463,11 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
414 } else 463 } else
415 wdev->wext.ibss.bssid = NULL; 464 wdev->wext.ibss.bssid = NULL;
416 465
417 return cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev); 466 wdev_lock(wdev);
467 err = cfg80211_ibss_wext_join(wiphy_to_dev(wdev->wiphy), wdev);
468 wdev_unlock(wdev);
469
470 return err;
418} 471}
419/* temporary symbol - mark GPL - in the future the handler won't be */ 472/* temporary symbol - mark GPL - in the future the handler won't be */
420EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); 473EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 1b2ca1fea7a1..8e4ce2fdf862 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -328,7 +328,8 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
328 enum nl80211_auth_type auth_type, 328 enum nl80211_auth_type auth_type,
329 const u8 *bssid, 329 const u8 *bssid,
330 const u8 *ssid, int ssid_len, 330 const u8 *ssid, int ssid_len,
331 const u8 *ie, int ie_len) 331 const u8 *ie, int ie_len,
332 const u8 *key, int key_len, int key_idx)
332{ 333{
333 struct wireless_dev *wdev = dev->ieee80211_ptr; 334 struct wireless_dev *wdev = dev->ieee80211_ptr;
334 struct cfg80211_auth_request req; 335 struct cfg80211_auth_request req;
@@ -337,6 +338,10 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
337 338
338 ASSERT_WDEV_LOCK(wdev); 339 ASSERT_WDEV_LOCK(wdev);
339 340
341 if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
342 if (!key || !key_len || key_idx < 0 || key_idx > 4)
343 return -EINVAL;
344
340 if (wdev->current_bss && 345 if (wdev->current_bss &&
341 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) 346 memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
342 return -EALREADY; 347 return -EALREADY;
@@ -359,6 +364,9 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
359 req.auth_type = auth_type; 364 req.auth_type = auth_type;
360 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 365 req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
361 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 366 WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
367 req.key = key;
368 req.key_len = key_len;
369 req.key_idx = key_idx;
362 if (!req.bss) 370 if (!req.bss)
363 return -ENOENT; 371 return -ENOENT;
364 372
@@ -396,13 +404,15 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
396 struct net_device *dev, struct ieee80211_channel *chan, 404 struct net_device *dev, struct ieee80211_channel *chan,
397 enum nl80211_auth_type auth_type, const u8 *bssid, 405 enum nl80211_auth_type auth_type, const u8 *bssid,
398 const u8 *ssid, int ssid_len, 406 const u8 *ssid, int ssid_len,
399 const u8 *ie, int ie_len) 407 const u8 *ie, int ie_len,
408 const u8 *key, int key_len, int key_idx)
400{ 409{
401 int err; 410 int err;
402 411
403 wdev_lock(dev->ieee80211_ptr); 412 wdev_lock(dev->ieee80211_ptr);
404 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 413 err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
405 ssid, ssid_len, ie, ie_len); 414 ssid, ssid_len, ie, ie_len,
415 key, key_len, key_idx);
406 wdev_unlock(dev->ieee80211_ptr); 416 wdev_unlock(dev->ieee80211_ptr);
407 417
408 return err; 418 return err;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 50cf59316292..45c5f9c8e51b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -138,8 +138,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
138/* policy for the attributes */ 138/* policy for the attributes */
139static struct nla_policy 139static struct nla_policy
140nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { 140nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = {
141 [NL80211_KEY_DATA] = { .type = NLA_BINARY, 141 [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
142 .len = WLAN_MAX_KEY_LEN },
143 [NL80211_KEY_IDX] = { .type = NLA_U8 }, 142 [NL80211_KEY_IDX] = { .type = NLA_U8 },
144 [NL80211_KEY_CIPHER] = { .type = NLA_U32 }, 143 [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
145 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 }, 144 [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
@@ -305,6 +304,83 @@ static int nl80211_parse_key(struct genl_info *info, struct key_parse *k)
305 return 0; 304 return 0;
306} 305}
307 306
307static struct cfg80211_cached_keys *
308nl80211_parse_connkeys(struct cfg80211_registered_device *rdev,
309 struct nlattr *keys)
310{
311 struct key_parse parse;
312 struct nlattr *key;
313 struct cfg80211_cached_keys *result;
314 int rem, err, def = 0;
315
316 result = kzalloc(sizeof(*result), GFP_KERNEL);
317 if (!result)
318 return ERR_PTR(-ENOMEM);
319
320 result->def = -1;
321 result->defmgmt = -1;
322
323 nla_for_each_nested(key, keys, rem) {
324 memset(&parse, 0, sizeof(parse));
325 parse.idx = -1;
326
327 err = nl80211_parse_key_new(key, &parse);
328 if (err)
329 goto error;
330 err = -EINVAL;
331 if (!parse.p.key)
332 goto error;
333 if (parse.idx < 0 || parse.idx > 4)
334 goto error;
335 if (parse.def) {
336 if (def)
337 goto error;
338 def = 1;
339 result->def = parse.idx;
340 } else if (parse.defmgmt)
341 goto error;
342 err = cfg80211_validate_key_settings(rdev, &parse.p,
343 parse.idx, NULL);
344 if (err)
345 goto error;
346 result->params[parse.idx].cipher = parse.p.cipher;
347 result->params[parse.idx].key_len = parse.p.key_len;
348 result->params[parse.idx].key = result->data[parse.idx];
349 memcpy(result->data[parse.idx], parse.p.key, parse.p.key_len);
350 }
351
352 return result;
353 error:
354 kfree(result);
355 return ERR_PTR(err);
356}
357
358static int nl80211_key_allowed(struct wireless_dev *wdev)
359{
360 ASSERT_WDEV_LOCK(wdev);
361
362 if (!netif_running(wdev->netdev))
363 return -ENETDOWN;
364
365 switch (wdev->iftype) {
366 case NL80211_IFTYPE_AP:
367 case NL80211_IFTYPE_AP_VLAN:
368 break;
369 case NL80211_IFTYPE_ADHOC:
370 if (!wdev->current_bss)
371 return -ENOLINK;
372 break;
373 case NL80211_IFTYPE_STATION:
374 if (wdev->sme_state != CFG80211_SME_CONNECTED)
375 return -ENOLINK;
376 break;
377 default:
378 return -EINVAL;
379 }
380
381 return 0;
382}
383
308static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, 384static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
309 struct cfg80211_registered_device *dev) 385 struct cfg80211_registered_device *dev)
310{ 386{
@@ -1212,7 +1288,11 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1212 goto out; 1288 goto out;
1213 } 1289 }
1214 1290
1215 err = func(&rdev->wiphy, dev, key.idx); 1291 wdev_lock(dev->ieee80211_ptr);
1292 err = nl80211_key_allowed(dev->ieee80211_ptr);
1293 if (!err)
1294 err = func(&rdev->wiphy, dev, key.idx);
1295
1216#ifdef CONFIG_WIRELESS_EXT 1296#ifdef CONFIG_WIRELESS_EXT
1217 if (!err) { 1297 if (!err) {
1218 if (func == rdev->ops->set_default_key) 1298 if (func == rdev->ops->set_default_key)
@@ -1221,6 +1301,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1221 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx; 1301 dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
1222 } 1302 }
1223#endif 1303#endif
1304 wdev_unlock(dev->ieee80211_ptr);
1224 1305
1225 out: 1306 out:
1226 cfg80211_unlock_rdev(rdev); 1307 cfg80211_unlock_rdev(rdev);
@@ -1235,7 +1316,7 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1235static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) 1316static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
1236{ 1317{
1237 struct cfg80211_registered_device *rdev; 1318 struct cfg80211_registered_device *rdev;
1238 int err, i; 1319 int err;
1239 struct net_device *dev; 1320 struct net_device *dev;
1240 struct key_parse key; 1321 struct key_parse key;
1241 u8 *mac_addr = NULL; 1322 u8 *mac_addr = NULL;
@@ -1250,29 +1331,28 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
1250 if (info->attrs[NL80211_ATTR_MAC]) 1331 if (info->attrs[NL80211_ATTR_MAC])
1251 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1332 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1252 1333
1253 if (cfg80211_validate_key_settings(&key.p, key.idx, mac_addr))
1254 return -EINVAL;
1255
1256 rtnl_lock(); 1334 rtnl_lock();
1257 1335
1258 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); 1336 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
1259 if (err) 1337 if (err)
1260 goto unlock_rtnl; 1338 goto unlock_rtnl;
1261 1339
1262 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) 1340 if (!rdev->ops->add_key) {
1263 if (key.p.cipher == rdev->wiphy.cipher_suites[i]) 1341 err = -EOPNOTSUPP;
1264 break;
1265 if (i == rdev->wiphy.n_cipher_suites) {
1266 err = -EINVAL;
1267 goto out; 1342 goto out;
1268 } 1343 }
1269 1344
1270 if (!rdev->ops->add_key) { 1345 if (cfg80211_validate_key_settings(rdev, &key.p, key.idx, mac_addr)) {
1271 err = -EOPNOTSUPP; 1346 err = -EINVAL;
1272 goto out; 1347 goto out;
1273 } 1348 }
1274 1349
1275 err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx, mac_addr, &key.p); 1350 wdev_lock(dev->ieee80211_ptr);
1351 err = nl80211_key_allowed(dev->ieee80211_ptr);
1352 if (!err)
1353 err = rdev->ops->add_key(&rdev->wiphy, dev, key.idx,
1354 mac_addr, &key.p);
1355 wdev_unlock(dev->ieee80211_ptr);
1276 1356
1277 out: 1357 out:
1278 cfg80211_unlock_rdev(rdev); 1358 cfg80211_unlock_rdev(rdev);
@@ -1309,7 +1389,10 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1309 goto out; 1389 goto out;
1310 } 1390 }
1311 1391
1312 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr); 1392 wdev_lock(dev->ieee80211_ptr);
1393 err = nl80211_key_allowed(dev->ieee80211_ptr);
1394 if (!err)
1395 err = rdev->ops->del_key(&rdev->wiphy, dev, key.idx, mac_addr);
1313 1396
1314#ifdef CONFIG_WIRELESS_EXT 1397#ifdef CONFIG_WIRELESS_EXT
1315 if (!err) { 1398 if (!err) {
@@ -1319,6 +1402,7 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1319 dev->ieee80211_ptr->wext.default_mgmt_key = -1; 1402 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
1320 } 1403 }
1321#endif 1404#endif
1405 wdev_unlock(dev->ieee80211_ptr);
1322 1406
1323 out: 1407 out:
1324 cfg80211_unlock_rdev(rdev); 1408 cfg80211_unlock_rdev(rdev);
@@ -3159,6 +3243,7 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3159 const u8 *bssid, *ssid, *ie = NULL; 3243 const u8 *bssid, *ssid, *ie = NULL;
3160 int err, ssid_len, ie_len = 0; 3244 int err, ssid_len, ie_len = 0;
3161 enum nl80211_auth_type auth_type; 3245 enum nl80211_auth_type auth_type;
3246 struct key_parse key;
3162 3247
3163 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3248 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
3164 return -EINVAL; 3249 return -EINVAL;
@@ -3175,6 +3260,25 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3175 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 3260 if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
3176 return -EINVAL; 3261 return -EINVAL;
3177 3262
3263 err = nl80211_parse_key(info, &key);
3264 if (err)
3265 return err;
3266
3267 if (key.idx >= 0) {
3268 if (!key.p.key || !key.p.key_len)
3269 return -EINVAL;
3270 if ((key.p.cipher != WLAN_CIPHER_SUITE_WEP40 ||
3271 key.p.key_len != WLAN_KEY_LEN_WEP40) &&
3272 (key.p.cipher != WLAN_CIPHER_SUITE_WEP104 ||
3273 key.p.key_len != WLAN_KEY_LEN_WEP104))
3274 return -EINVAL;
3275 if (key.idx > 4)
3276 return -EINVAL;
3277 } else {
3278 key.p.key_len = 0;
3279 key.p.key = NULL;
3280 }
3281
3178 rtnl_lock(); 3282 rtnl_lock();
3179 3283
3180 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev); 3284 err = get_rdev_dev_by_info_ifindex(info->attrs, &rdev, &dev);
@@ -3219,7 +3323,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
3219 } 3323 }
3220 3324
3221 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, 3325 err = cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
3222 ssid, ssid_len, ie, ie_len); 3326 ssid, ssid_len, ie, ie_len,
3327 key.p.key, key.p.key_len, key.idx);
3223 3328
3224out: 3329out:
3225 cfg80211_unlock_rdev(rdev); 3330 cfg80211_unlock_rdev(rdev);
@@ -3506,6 +3611,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3506 struct net_device *dev; 3611 struct net_device *dev;
3507 struct cfg80211_ibss_params ibss; 3612 struct cfg80211_ibss_params ibss;
3508 struct wiphy *wiphy; 3613 struct wiphy *wiphy;
3614 struct cfg80211_cached_keys *connkeys = NULL;
3509 int err; 3615 int err;
3510 3616
3511 memset(&ibss, 0, sizeof(ibss)); 3617 memset(&ibss, 0, sizeof(ibss));
@@ -3570,13 +3676,26 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
3570 } 3676 }
3571 3677
3572 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED]; 3678 ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
3679 ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
3680
3681 if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
3682 connkeys = nl80211_parse_connkeys(rdev,
3683 info->attrs[NL80211_ATTR_KEYS]);
3684 if (IS_ERR(connkeys)) {
3685 err = PTR_ERR(connkeys);
3686 connkeys = NULL;
3687 goto out;
3688 }
3689 }
3573 3690
3574 err = cfg80211_join_ibss(rdev, dev, &ibss); 3691 err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
3575 3692
3576out: 3693out:
3577 cfg80211_unlock_rdev(rdev); 3694 cfg80211_unlock_rdev(rdev);
3578 dev_put(dev); 3695 dev_put(dev);
3579unlock_rtnl: 3696unlock_rtnl:
3697 if (err)
3698 kfree(connkeys);
3580 rtnl_unlock(); 3699 rtnl_unlock();
3581 return err; 3700 return err;
3582} 3701}
@@ -3746,6 +3865,7 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
3746 struct net_device *dev; 3865 struct net_device *dev;
3747 struct cfg80211_connect_params connect; 3866 struct cfg80211_connect_params connect;
3748 struct wiphy *wiphy; 3867 struct wiphy *wiphy;
3868 struct cfg80211_cached_keys *connkeys = NULL;
3749 int err; 3869 int err;
3750 3870
3751 memset(&connect, 0, sizeof(connect)); 3871 memset(&connect, 0, sizeof(connect));
@@ -3810,12 +3930,24 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
3810 } 3930 }
3811 } 3931 }
3812 3932
3813 err = cfg80211_connect(rdev, dev, &connect); 3933 if (connect.privacy && info->attrs[NL80211_ATTR_KEYS]) {
3934 connkeys = nl80211_parse_connkeys(rdev,
3935 info->attrs[NL80211_ATTR_KEYS]);
3936 if (IS_ERR(connkeys)) {
3937 err = PTR_ERR(connkeys);
3938 connkeys = NULL;
3939 goto out;
3940 }
3941 }
3942
3943 err = cfg80211_connect(rdev, dev, &connect, connkeys);
3814 3944
3815out: 3945out:
3816 cfg80211_unlock_rdev(rdev); 3946 cfg80211_unlock_rdev(rdev);
3817 dev_put(dev); 3947 dev_put(dev);
3818unlock_rtnl: 3948unlock_rtnl:
3949 if (err)
3950 kfree(connkeys);
3819 rtnl_unlock(); 3951 rtnl_unlock();
3820 return err; 3952 return err;
3821} 3953}
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 79ca56cbfd36..d635a99dba51 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -125,7 +125,9 @@ static int cfg80211_conn_do_work(struct wireless_dev *wdev)
125 params->channel, params->auth_type, 125 params->channel, params->auth_type,
126 params->bssid, 126 params->bssid,
127 params->ssid, params->ssid_len, 127 params->ssid, params->ssid_len,
128 NULL, 0); 128 NULL, 0,
129 params->key, params->key_len,
130 params->key_idx);
129 case CFG80211_CONN_ASSOCIATE_NEXT: 131 case CFG80211_CONN_ASSOCIATE_NEXT:
130 BUG_ON(!rdev->ops->assoc); 132 BUG_ON(!rdev->ops->assoc);
131 wdev->conn->state = CFG80211_CONN_ASSOCIATING; 133 wdev->conn->state = CFG80211_CONN_ASSOCIATING;
@@ -279,8 +281,12 @@ void cfg80211_sme_rx_auth(struct net_device *dev,
279 /* select automatically between only open, shared, leap */ 281 /* select automatically between only open, shared, leap */
280 switch (wdev->conn->params.auth_type) { 282 switch (wdev->conn->params.auth_type) {
281 case NL80211_AUTHTYPE_OPEN_SYSTEM: 283 case NL80211_AUTHTYPE_OPEN_SYSTEM:
282 wdev->conn->params.auth_type = 284 if (wdev->connect_keys)
283 NL80211_AUTHTYPE_SHARED_KEY; 285 wdev->conn->params.auth_type =
286 NL80211_AUTHTYPE_SHARED_KEY;
287 else
288 wdev->conn->params.auth_type =
289 NL80211_AUTHTYPE_NETWORK_EAP;
284 break; 290 break;
285 case NL80211_AUTHTYPE_SHARED_KEY: 291 case NL80211_AUTHTYPE_SHARED_KEY:
286 wdev->conn->params.auth_type = 292 wdev->conn->params.auth_type =
@@ -353,10 +359,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
353#endif 359#endif
354 360
355 if (status == WLAN_STATUS_SUCCESS && 361 if (status == WLAN_STATUS_SUCCESS &&
356 wdev->sme_state == CFG80211_SME_IDLE) { 362 wdev->sme_state == CFG80211_SME_IDLE)
357 wdev->sme_state = CFG80211_SME_CONNECTED; 363 goto success;
358 return;
359 }
360 364
361 if (wdev->sme_state != CFG80211_SME_CONNECTING) 365 if (wdev->sme_state != CFG80211_SME_CONNECTING)
362 return; 366 return;
@@ -370,24 +374,29 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
370 if (wdev->conn) 374 if (wdev->conn)
371 wdev->conn->state = CFG80211_CONN_IDLE; 375 wdev->conn->state = CFG80211_CONN_IDLE;
372 376
373 if (status == WLAN_STATUS_SUCCESS) { 377 if (status != WLAN_STATUS_SUCCESS) {
374 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
375 wdev->ssid, wdev->ssid_len,
376 WLAN_CAPABILITY_ESS,
377 WLAN_CAPABILITY_ESS);
378
379 if (WARN_ON(!bss))
380 return;
381
382 cfg80211_hold_bss(bss_from_pub(bss));
383 wdev->current_bss = bss_from_pub(bss);
384
385 wdev->sme_state = CFG80211_SME_CONNECTED;
386 } else {
387 wdev->sme_state = CFG80211_SME_IDLE; 378 wdev->sme_state = CFG80211_SME_IDLE;
388 kfree(wdev->conn); 379 kfree(wdev->conn);
389 wdev->conn = NULL; 380 wdev->conn = NULL;
381 kfree(wdev->connect_keys);
382 wdev->connect_keys = NULL;
383 return;
390 } 384 }
385
386 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
387 wdev->ssid, wdev->ssid_len,
388 WLAN_CAPABILITY_ESS,
389 WLAN_CAPABILITY_ESS);
390
391 if (WARN_ON(!bss))
392 return;
393
394 cfg80211_hold_bss(bss_from_pub(bss));
395 wdev->current_bss = bss_from_pub(bss);
396
397 success:
398 wdev->sme_state = CFG80211_SME_CONNECTED;
399 cfg80211_upload_connect_keys(wdev);
391} 400}
392 401
393void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 402void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
@@ -516,6 +525,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
516 size_t ie_len, u16 reason, bool from_ap) 525 size_t ie_len, u16 reason, bool from_ap)
517{ 526{
518 struct wireless_dev *wdev = dev->ieee80211_ptr; 527 struct wireless_dev *wdev = dev->ieee80211_ptr;
528 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
529 int i;
519#ifdef CONFIG_WIRELESS_EXT 530#ifdef CONFIG_WIRELESS_EXT
520 union iwreq_data wrqu; 531 union iwreq_data wrqu;
521#endif 532#endif
@@ -543,8 +554,15 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
543 wdev->conn = NULL; 554 wdev->conn = NULL;
544 } 555 }
545 556
546 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, 557 nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
547 reason, ie, ie_len, from_ap); 558
559 /*
560 * Delete all the keys ... pairwise keys can't really
561 * exist any more anyway, but default keys might.
562 */
563 if (rdev->ops->del_key)
564 for (i = 0; i < 6; i++)
565 rdev->ops->del_key(wdev->wiphy, dev, i, NULL);
548 566
549#ifdef CONFIG_WIRELESS_EXT 567#ifdef CONFIG_WIRELESS_EXT
550 memset(&wrqu, 0, sizeof(wrqu)); 568 memset(&wrqu, 0, sizeof(wrqu));
@@ -580,7 +598,8 @@ EXPORT_SYMBOL(cfg80211_disconnected);
580 598
581int __cfg80211_connect(struct cfg80211_registered_device *rdev, 599int __cfg80211_connect(struct cfg80211_registered_device *rdev,
582 struct net_device *dev, 600 struct net_device *dev,
583 struct cfg80211_connect_params *connect) 601 struct cfg80211_connect_params *connect,
602 struct cfg80211_cached_keys *connkeys)
584{ 603{
585 struct wireless_dev *wdev = dev->ieee80211_ptr; 604 struct wireless_dev *wdev = dev->ieee80211_ptr;
586 int err; 605 int err;
@@ -590,6 +609,24 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
590 if (wdev->sme_state != CFG80211_SME_IDLE) 609 if (wdev->sme_state != CFG80211_SME_IDLE)
591 return -EALREADY; 610 return -EALREADY;
592 611
612 if (WARN_ON(wdev->connect_keys)) {
613 kfree(wdev->connect_keys);
614 wdev->connect_keys = NULL;
615 }
616
617 if (connkeys && connkeys->def >= 0) {
618 int idx;
619
620 idx = connkeys->def;
621 /* If given a WEP key we may need it for shared key auth */
622 if (connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP40 ||
623 connkeys->params[idx].cipher == WLAN_CIPHER_SUITE_WEP104) {
624 connect->key_idx = idx;
625 connect->key = connkeys->params[idx].key;
626 connect->key_len = connkeys->params[idx].key_len;
627 }
628 }
629
593 if (!rdev->ops->connect) { 630 if (!rdev->ops->connect) {
594 if (!rdev->ops->auth || !rdev->ops->assoc) 631 if (!rdev->ops->auth || !rdev->ops->assoc)
595 return -EOPNOTSUPP; 632 return -EOPNOTSUPP;
@@ -640,6 +677,7 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
640 cfg80211_get_conn_bss(wdev); 677 cfg80211_get_conn_bss(wdev);
641 678
642 wdev->sme_state = CFG80211_SME_CONNECTING; 679 wdev->sme_state = CFG80211_SME_CONNECTING;
680 wdev->connect_keys = connkeys;
643 681
644 /* we're good if we have both BSSID and channel */ 682 /* we're good if we have both BSSID and channel */
645 if (wdev->conn->params.bssid && wdev->conn->params.channel) { 683 if (wdev->conn->params.bssid && wdev->conn->params.channel) {
@@ -662,13 +700,16 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
662 kfree(wdev->conn); 700 kfree(wdev->conn);
663 wdev->conn = NULL; 701 wdev->conn = NULL;
664 wdev->sme_state = CFG80211_SME_IDLE; 702 wdev->sme_state = CFG80211_SME_IDLE;
703 wdev->connect_keys = NULL;
665 } 704 }
666 705
667 return err; 706 return err;
668 } else { 707 } else {
669 wdev->sme_state = CFG80211_SME_CONNECTING; 708 wdev->sme_state = CFG80211_SME_CONNECTING;
709 wdev->connect_keys = connkeys;
670 err = rdev->ops->connect(&rdev->wiphy, dev, connect); 710 err = rdev->ops->connect(&rdev->wiphy, dev, connect);
671 if (err) { 711 if (err) {
712 wdev->connect_keys = NULL;
672 wdev->sme_state = CFG80211_SME_IDLE; 713 wdev->sme_state = CFG80211_SME_IDLE;
673 return err; 714 return err;
674 } 715 }
@@ -682,12 +723,13 @@ int __cfg80211_connect(struct cfg80211_registered_device *rdev,
682 723
683int cfg80211_connect(struct cfg80211_registered_device *rdev, 724int cfg80211_connect(struct cfg80211_registered_device *rdev,
684 struct net_device *dev, 725 struct net_device *dev,
685 struct cfg80211_connect_params *connect) 726 struct cfg80211_connect_params *connect,
727 struct cfg80211_cached_keys *connkeys)
686{ 728{
687 int err; 729 int err;
688 730
689 wdev_lock(dev->ieee80211_ptr); 731 wdev_lock(dev->ieee80211_ptr);
690 err = __cfg80211_connect(rdev, dev, connect); 732 err = __cfg80211_connect(rdev, dev, connect, connkeys);
691 wdev_unlock(dev->ieee80211_ptr); 733 wdev_unlock(dev->ieee80211_ptr);
692 734
693 return err; 735 return err;
@@ -704,6 +746,9 @@ int __cfg80211_disconnect(struct cfg80211_registered_device *rdev,
704 if (wdev->sme_state == CFG80211_SME_IDLE) 746 if (wdev->sme_state == CFG80211_SME_IDLE)
705 return -EINVAL; 747 return -EINVAL;
706 748
749 kfree(wdev->connect_keys);
750 wdev->connect_keys = NULL;
751
707 if (!rdev->ops->disconnect) { 752 if (!rdev->ops->disconnect) {
708 if (!rdev->ops->deauth) 753 if (!rdev->ops->deauth)
709 return -EOPNOTSUPP; 754 return -EOPNOTSUPP;
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 28f8f96801d4..4bab380a1204 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -141,9 +141,12 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
141 set_mandatory_flags_band(wiphy->bands[band], band); 141 set_mandatory_flags_band(wiphy->bands[band], band);
142} 142}
143 143
144int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 144int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
145 struct key_params *params, int key_idx,
145 const u8 *mac_addr) 146 const u8 *mac_addr)
146{ 147{
148 int i;
149
147 if (key_idx > 5) 150 if (key_idx > 5)
148 return -EINVAL; 151 return -EINVAL;
149 152
@@ -197,6 +200,12 @@ int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
197 } 200 }
198 } 201 }
199 202
203 for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
204 if (params->cipher == rdev->wiphy.cipher_suites[i])
205 break;
206 if (i == rdev->wiphy.n_cipher_suites)
207 return -EINVAL;
208
200 return 0; 209 return 0;
201} 210}
202 211
@@ -523,3 +532,33 @@ const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
523 return NULL; 532 return NULL;
524} 533}
525EXPORT_SYMBOL(ieee80211_bss_get_ie); 534EXPORT_SYMBOL(ieee80211_bss_get_ie);
535
536void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
537{
538 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
539 struct net_device *dev = wdev->netdev;
540 int i;
541
542 if (!wdev->connect_keys)
543 return;
544
545 for (i = 0; i < 6; i++) {
546 if (!wdev->connect_keys->params[i].cipher)
547 continue;
548 if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
549 &wdev->connect_keys->params[i]))
550 printk(KERN_ERR "%s: failed to set key %d\n",
551 dev->name, i);
552 if (wdev->connect_keys->def == i)
553 if (rdev->ops->set_default_key(wdev->wiphy, dev, i))
554 printk(KERN_ERR "%s: failed to set defkey %d\n",
555 dev->name, i);
556 if (wdev->connect_keys->defmgmt == i)
557 if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
558 printk(KERN_ERR "%s: failed to set mgtdef %d\n",
559 dev->name, i);
560 }
561
562 kfree(wdev->connect_keys);
563 wdev->connect_keys = NULL;
564}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index 5088d89a30fc..5d0176338539 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -453,15 +453,32 @@ int cfg80211_wext_giwretry(struct net_device *dev,
453} 453}
454EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); 454EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
455 455
456static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, 456static int __cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
457 struct net_device *dev, const u8 *addr, 457 struct net_device *dev, const u8 *addr,
458 bool remove, bool tx_key, int idx, 458 bool remove, bool tx_key, int idx,
459 struct key_params *params) 459 struct key_params *params)
460{ 460{
461 struct wireless_dev *wdev = dev->ieee80211_ptr; 461 struct wireless_dev *wdev = dev->ieee80211_ptr;
462 int err; 462 int err, i;
463
464 if (!wdev->wext.keys) {
465 wdev->wext.keys = kzalloc(sizeof(*wdev->wext.keys),
466 GFP_KERNEL);
467 if (!wdev->wext.keys)
468 return -ENOMEM;
469 for (i = 0; i < 6; i++)
470 wdev->wext.keys->params[i].key =
471 wdev->wext.keys->data[i];
472 }
473
474 if (wdev->iftype != NL80211_IFTYPE_ADHOC &&
475 wdev->iftype != NL80211_IFTYPE_STATION)
476 return -EOPNOTSUPP;
463 477
464 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { 478 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
479 if (!wdev->current_bss)
480 return -ENOLINK;
481
465 if (!rdev->ops->set_default_mgmt_key) 482 if (!rdev->ops->set_default_mgmt_key)
466 return -EOPNOTSUPP; 483 return -EOPNOTSUPP;
467 484
@@ -471,8 +488,14 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
471 return -EINVAL; 488 return -EINVAL;
472 489
473 if (remove) { 490 if (remove) {
474 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr); 491 err = 0;
492 if (wdev->current_bss)
493 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
475 if (!err) { 494 if (!err) {
495 if (!addr) {
496 wdev->wext.keys->params[idx].key_len = 0;
497 wdev->wext.keys->params[idx].cipher = 0;
498 }
476 if (idx == wdev->wext.default_key) 499 if (idx == wdev->wext.default_key)
477 wdev->wext.default_key = -1; 500 wdev->wext.default_key = -1;
478 else if (idx == wdev->wext.default_mgmt_key) 501 else if (idx == wdev->wext.default_mgmt_key)
@@ -486,36 +509,64 @@ static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
486 return 0; 509 return 0;
487 510
488 return err; 511 return err;
489 } else { 512 }
490 if (addr)
491 tx_key = false;
492 513
493 if (cfg80211_validate_key_settings(params, idx, addr)) 514 if (addr)
494 return -EINVAL; 515 tx_key = false;
495 516
517 if (cfg80211_validate_key_settings(rdev, params, idx, addr))
518 return -EINVAL;
519
520 err = 0;
521 if (wdev->current_bss)
496 err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params); 522 err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
497 if (err) 523 if (err)
498 return err; 524 return err;
525
526 if (!addr) {
527 wdev->wext.keys->params[idx] = *params;
528 memcpy(wdev->wext.keys->data[idx],
529 params->key, params->key_len);
530 wdev->wext.keys->params[idx].key =
531 wdev->wext.keys->data[idx];
532 }
499 533
500 if (tx_key || (!addr && wdev->wext.default_key == -1)) { 534 if (params->cipher != WLAN_CIPHER_SUITE_AES_CMAC &&
535 (tx_key || (!addr && wdev->wext.default_key == -1))) {
536 if (wdev->current_bss)
501 err = rdev->ops->set_default_key(&rdev->wiphy, 537 err = rdev->ops->set_default_key(&rdev->wiphy,
502 dev, idx); 538 dev, idx);
503 if (!err) 539 if (!err)
504 wdev->wext.default_key = idx; 540 wdev->wext.default_key = idx;
505 return err; 541 return err;
506 } 542 }
507 543
508 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC && 544 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
509 (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) { 545 (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
546 if (wdev->current_bss)
510 err = rdev->ops->set_default_mgmt_key(&rdev->wiphy, 547 err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
511 dev, idx); 548 dev, idx);
512 if (!err) 549 if (!err)
513 wdev->wext.default_mgmt_key = idx; 550 wdev->wext.default_mgmt_key = idx;
514 return err; 551 return err;
515 }
516
517 return 0;
518 } 552 }
553
554 return 0;
555}
556
557static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
558 struct net_device *dev, const u8 *addr,
559 bool remove, bool tx_key, int idx,
560 struct key_params *params)
561{
562 int err;
563
564 wdev_lock(dev->ieee80211_ptr);
565 err = __cfg80211_set_encryption(rdev, dev, addr, remove,
566 tx_key, idx, params);
567 wdev_unlock(dev->ieee80211_ptr);
568
569 return err;
519} 570}
520 571
521int cfg80211_wext_siwencode(struct net_device *dev, 572int cfg80211_wext_siwencode(struct net_device *dev,
@@ -528,6 +579,10 @@ int cfg80211_wext_siwencode(struct net_device *dev,
528 bool remove = false; 579 bool remove = false;
529 struct key_params params; 580 struct key_params params;
530 581
582 if (wdev->iftype != NL80211_IFTYPE_STATION &&
583 wdev->iftype != NL80211_IFTYPE_ADHOC)
584 return -EOPNOTSUPP;
585
531 /* no use -- only MFP (set_default_mgmt_key) is optional */ 586 /* no use -- only MFP (set_default_mgmt_key) is optional */
532 if (!rdev->ops->del_key || 587 if (!rdev->ops->del_key ||
533 !rdev->ops->add_key || 588 !rdev->ops->add_key ||
@@ -548,9 +603,14 @@ int cfg80211_wext_siwencode(struct net_device *dev,
548 remove = true; 603 remove = true;
549 else if (erq->length == 0) { 604 else if (erq->length == 0) {
550 /* No key data - just set the default TX key index */ 605 /* No key data - just set the default TX key index */
551 err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx); 606 err = 0;
607 wdev_lock(wdev);
608 if (wdev->current_bss)
609 err = rdev->ops->set_default_key(&rdev->wiphy,
610 dev, idx);
552 if (!err) 611 if (!err)
553 wdev->wext.default_key = idx; 612 wdev->wext.default_key = idx;
613 wdev_unlock(wdev);
554 return err; 614 return err;
555 } 615 }
556 616
@@ -583,6 +643,10 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
583 struct key_params params; 643 struct key_params params;
584 u32 cipher; 644 u32 cipher;
585 645
646 if (wdev->iftype != NL80211_IFTYPE_STATION &&
647 wdev->iftype != NL80211_IFTYPE_ADHOC)
648 return -EOPNOTSUPP;
649
586 /* no use -- only MFP (set_default_mgmt_key) is optional */ 650 /* no use -- only MFP (set_default_mgmt_key) is optional */
587 if (!rdev->ops->del_key || 651 if (!rdev->ops->del_key ||
588 !rdev->ops->add_key || 652 !rdev->ops->add_key ||
@@ -656,37 +720,15 @@ int cfg80211_wext_siwencodeext(struct net_device *dev,
656} 720}
657EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); 721EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
658 722
659struct giwencode_cookie {
660 size_t buflen;
661 char *keybuf;
662};
663
664static void giwencode_get_key_cb(void *cookie, struct key_params *params)
665{
666 struct giwencode_cookie *data = cookie;
667
668 if (!params->key) {
669 data->buflen = 0;
670 return;
671 }
672
673 data->buflen = min_t(size_t, data->buflen, params->key_len);
674 memcpy(data->keybuf, params->key, data->buflen);
675}
676
677int cfg80211_wext_giwencode(struct net_device *dev, 723int cfg80211_wext_giwencode(struct net_device *dev,
678 struct iw_request_info *info, 724 struct iw_request_info *info,
679 struct iw_point *erq, char *keybuf) 725 struct iw_point *erq, char *keybuf)
680{ 726{
681 struct wireless_dev *wdev = dev->ieee80211_ptr; 727 struct wireless_dev *wdev = dev->ieee80211_ptr;
682 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 728 int idx;
683 int idx, err;
684 struct giwencode_cookie data = {
685 .keybuf = keybuf,
686 .buflen = erq->length,
687 };
688 729
689 if (!rdev->ops->get_key) 730 if (wdev->iftype != NL80211_IFTYPE_STATION &&
731 wdev->iftype != NL80211_IFTYPE_ADHOC)
690 return -EOPNOTSUPP; 732 return -EOPNOTSUPP;
691 733
692 idx = erq->flags & IW_ENCODE_INDEX; 734 idx = erq->flags & IW_ENCODE_INDEX;
@@ -701,21 +743,18 @@ int cfg80211_wext_giwencode(struct net_device *dev,
701 743
702 erq->flags = idx + 1; 744 erq->flags = idx + 1;
703 745
704 err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data, 746 if (!wdev->wext.keys || !wdev->wext.keys->params[idx].cipher) {
705 giwencode_get_key_cb);
706 if (!err) {
707 erq->length = data.buflen;
708 erq->flags |= IW_ENCODE_ENABLED;
709 return 0;
710 }
711
712 if (err == -ENOENT) {
713 erq->flags |= IW_ENCODE_DISABLED; 747 erq->flags |= IW_ENCODE_DISABLED;
714 erq->length = 0; 748 erq->length = 0;
715 return 0; 749 return 0;
716 } 750 }
717 751
718 return err; 752 erq->length = min_t(size_t, erq->length,
753 wdev->wext.keys->params[idx].key_len);
754 memcpy(keybuf, wdev->wext.keys->params[idx].key, erq->length);
755 erq->flags |= IW_ENCODE_ENABLED;
756
757 return 0;
719} 758}
720EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); 759EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
721 760
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 6f75aaa7f795..c33ea9a5de78 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -10,10 +10,11 @@
10#include <net/cfg80211.h> 10#include <net/cfg80211.h>
11#include "nl80211.h" 11#include "nl80211.h"
12 12
13static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, 13int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *wdev) 14 struct wireless_dev *wdev)
15{ 15{
16 int err; 16 struct cfg80211_cached_keys *ck = NULL;
17 int err, i;
17 18
18 ASSERT_RDEV_LOCK(rdev); 19 ASSERT_RDEV_LOCK(rdev);
19 ASSERT_WDEV_LOCK(wdev); 20 ASSERT_WDEV_LOCK(wdev);
@@ -25,10 +26,25 @@ static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
25 wdev->wext.connect.ie_len = wdev->wext.ie_len; 26 wdev->wext.connect.ie_len = wdev->wext.ie_len;
26 wdev->wext.connect.privacy = wdev->wext.default_key != -1; 27 wdev->wext.connect.privacy = wdev->wext.default_key != -1;
27 28
28 err = 0; 29 if (wdev->wext.keys) {
29 if (wdev->wext.connect.ssid_len != 0) 30 wdev->wext.keys->def = wdev->wext.default_key;
30 err = __cfg80211_connect(rdev, wdev->netdev, 31 wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key;
31 &wdev->wext.connect); 32 }
33
34 if (!wdev->wext.connect.ssid_len)
35 return 0;
36
37 if (wdev->wext.keys) {
38 ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
39 if (!ck)
40 return -ENOMEM;
41 for (i = 0; i < 6; i++)
42 ck->params[i].key = ck->data[i];
43 }
44 err = __cfg80211_connect(rdev, wdev->netdev,
45 &wdev->wext.connect, ck);
46 if (err)
47 kfree(ck);
32 48
33 return err; 49 return err;
34} 50}