diff options
-rw-r--r-- | include/linux/nl80211.h | 5 | ||||
-rw-r--r-- | include/net/cfg80211.h | 18 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 9 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 8 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 11 | ||||
-rw-r--r-- | net/mac80211/util.c | 16 | ||||
-rw-r--r-- | net/mac80211/wep.c | 6 | ||||
-rw-r--r-- | net/mac80211/wep.h | 3 | ||||
-rw-r--r-- | net/wireless/core.c | 11 | ||||
-rw-r--r-- | net/wireless/core.h | 32 | ||||
-rw-r--r-- | net/wireless/ibss.c | 79 | ||||
-rw-r--r-- | net/wireless/mlme.c | 16 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 170 | ||||
-rw-r--r-- | net/wireless/sme.c | 97 | ||||
-rw-r--r-- | net/wireless/util.c | 41 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 163 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 30 |
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 | */ |
651 | struct cfg80211_auth_request { | 654 | struct 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 | */ |
731 | struct cfg80211_ibss_params { | 738 | struct 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 | */ |
759 | struct cfg80211_connect_params { | 770 | struct 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 | */ |
1224 | extern void wiphy_free(struct wiphy *wiphy); | 1237 | extern void wiphy_free(struct wiphy *wiphy); |
1225 | 1238 | ||
1226 | /* internal struct */ | 1239 | /* internal structs */ |
1227 | struct cfg80211_conn; | 1240 | struct cfg80211_conn; |
1228 | struct cfg80211_internal_bss; | 1241 | struct cfg80211_internal_bss; |
1242 | struct 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 | ||
63 | static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | 63 | static 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 | ||
1094 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 1098 | void 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); |
1098 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 1102 | int 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); |
1100 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 1104 | void 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 */ |
36 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; | 37 | void *mac80211_wiphy_privid = &mac80211_wiphy_privid; |
@@ -804,12 +805,13 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
804 | 805 | ||
805 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | 806 | void 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 | ||
841 | int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | 847 | int 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 | */ |
147 | static int ieee80211_wep_encrypt(struct ieee80211_local *local, | 147 | int 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); | |||
20 | void ieee80211_wep_free(struct ieee80211_local *local); | 20 | void ieee80211_wep_free(struct ieee80211_local *local); |
21 | void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 21 | void 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); |
23 | int ieee80211_wep_encrypt(struct ieee80211_local *local, | ||
24 | struct sk_buff *skb, | ||
25 | const u8 *key, int keylen, int keyidx); | ||
23 | int ieee80211_wep_decrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, | 26 | int 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); |
25 | bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); | 28 | bool 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 | ||
241 | struct 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 */ |
243 | extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); | 249 | extern 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 */ |
257 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 263 | int __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); | ||
260 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 267 | int 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); | ||
263 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | 271 | void cfg80211_clear_ibss(struct net_device *dev, bool nowext); |
264 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 272 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
265 | struct net_device *dev, bool nowext); | 273 | struct net_device *dev, bool nowext); |
266 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); | 274 | void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid); |
275 | int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | ||
276 | struct wireless_dev *wdev); | ||
267 | 277 | ||
268 | /* MLME */ | 278 | /* MLME */ |
269 | int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 279 | int __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); | ||
276 | int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, | 287 | int 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); | ||
281 | int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | 293 | int __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 */ |
311 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 323 | int __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); | ||
314 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 327 | int 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); | ||
317 | int __cfg80211_disconnect(struct cfg80211_registered_device *rdev, | 331 | int __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, | |||
323 | void __cfg80211_roamed(struct wireless_dev *wdev, const u8 *bssid, | 337 | void __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); |
340 | int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | ||
341 | struct wireless_dev *wdev); | ||
326 | 342 | ||
327 | void cfg80211_conn_work(struct work_struct *work); | 343 | void cfg80211_conn_work(struct work_struct *work); |
328 | 344 | ||
329 | /* internal helpers */ | 345 | /* internal helpers */ |
330 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | 346 | int 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); |
332 | void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | 349 | void __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); | |||
335 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 352 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
336 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); | 353 | void cfg80211_sme_disassoc(struct net_device *dev, int idx); |
337 | void __cfg80211_scan_done(struct work_struct *wk); | 354 | void __cfg80211_scan_done(struct work_struct *wk); |
355 | void 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 | ||
72 | int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 74 | int __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 | ||
98 | int cfg80211_join_ibss(struct cfg80211_registered_device *rdev, | 106 | int 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, | |||
112 | static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext) | 121 | static 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 |
175 | static int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev, | 197 | int 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 | ||
223 | int cfg80211_ibss_wext_siwfreq(struct net_device *dev, | 264 | int 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 */ |
271 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwfreq); | 316 | EXPORT_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 */ |
339 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwessid); | 388 | EXPORT_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 */ |
420 | EXPORT_SYMBOL_GPL(cfg80211_ibss_wext_siwap); | 473 | EXPORT_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 */ |
139 | static struct nla_policy | 139 | static struct nla_policy |
140 | nl80211_key_policy[NL80211_KEY_MAX + 1] __read_mostly = { | 140 | nl80211_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 | ||
307 | static struct cfg80211_cached_keys * | ||
308 | nl80211_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 | |||
358 | static 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 | |||
308 | static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | 384 | static 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) | |||
1235 | static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info) | 1316 | static 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 | ||
3224 | out: | 3329 | out: |
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 | ||
3576 | out: | 3693 | out: |
3577 | cfg80211_unlock_rdev(rdev); | 3694 | cfg80211_unlock_rdev(rdev); |
3578 | dev_put(dev); | 3695 | dev_put(dev); |
3579 | unlock_rtnl: | 3696 | unlock_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 | ||
3815 | out: | 3945 | out: |
3816 | cfg80211_unlock_rdev(rdev); | 3946 | cfg80211_unlock_rdev(rdev); |
3817 | dev_put(dev); | 3947 | dev_put(dev); |
3818 | unlock_rtnl: | 3948 | unlock_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 | ||
393 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 402 | void 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 | ||
581 | int __cfg80211_connect(struct cfg80211_registered_device *rdev, | 599 | int __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 | ||
683 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 724 | int 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 | ||
144 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | 144 | int 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 | } |
525 | EXPORT_SYMBOL(ieee80211_bss_get_ie); | 534 | EXPORT_SYMBOL(ieee80211_bss_get_ie); |
535 | |||
536 | void 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 | } |
454 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); | 454 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); |
455 | 455 | ||
456 | static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev, | 456 | static 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 | |||
557 | static 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 | ||
521 | int cfg80211_wext_siwencode(struct net_device *dev, | 572 | int 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 | } |
657 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); | 721 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext); |
658 | 722 | ||
659 | struct giwencode_cookie { | ||
660 | size_t buflen; | ||
661 | char *keybuf; | ||
662 | }; | ||
663 | |||
664 | static 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 | |||
677 | int cfg80211_wext_giwencode(struct net_device *dev, | 723 | int 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 | } |
720 | EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode); | 759 | EXPORT_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 | ||
13 | static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, | 13 | int 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 | } |