aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h36
-rw-r--r--net/mac80211/mlme.c69
-rw-r--r--net/mac80211/wext.c215
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c23
-rw-r--r--net/wireless/core.h3
-rw-r--r--net/wireless/nl80211.c2
-rw-r--r--net/wireless/sme.c55
-rw-r--r--net/wireless/wext-compat.c229
-rw-r--r--net/wireless/wext-sme.c329
10 files changed, 625 insertions, 338 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 24fab439d415..07085216532d 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1253,8 +1253,14 @@ struct wireless_dev {
1253#ifdef CONFIG_WIRELESS_EXT 1253#ifdef CONFIG_WIRELESS_EXT
1254 /* wext data */ 1254 /* wext data */
1255 struct { 1255 struct {
1256 struct cfg80211_ibss_params ibss; 1256 union {
1257 struct cfg80211_ibss_params ibss;
1258 struct cfg80211_connect_params connect;
1259 };
1260 u8 *ie;
1261 size_t ie_len;
1257 u8 bssid[ETH_ALEN]; 1262 u8 bssid[ETH_ALEN];
1263 u8 ssid[IEEE80211_MAX_SSID_LEN];
1258 s8 default_key, default_mgmt_key; 1264 s8 default_key, default_mgmt_key;
1259 } wext; 1265 } wext;
1260#endif 1266#endif
@@ -1535,6 +1541,34 @@ int cfg80211_ibss_wext_giwap(struct net_device *dev,
1535 struct iw_request_info *info, 1541 struct iw_request_info *info,
1536 struct sockaddr *ap_addr, char *extra); 1542 struct sockaddr *ap_addr, char *extra);
1537 1543
1544int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
1545 struct iw_request_info *info,
1546 struct iw_freq *freq, char *extra);
1547int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
1548 struct iw_request_info *info,
1549 struct iw_freq *freq, char *extra);
1550int cfg80211_mgd_wext_siwessid(struct net_device *dev,
1551 struct iw_request_info *info,
1552 struct iw_point *data, char *ssid);
1553int cfg80211_mgd_wext_giwessid(struct net_device *dev,
1554 struct iw_request_info *info,
1555 struct iw_point *data, char *ssid);
1556int cfg80211_mgd_wext_siwap(struct net_device *dev,
1557 struct iw_request_info *info,
1558 struct sockaddr *ap_addr, char *extra);
1559int cfg80211_mgd_wext_giwap(struct net_device *dev,
1560 struct iw_request_info *info,
1561 struct sockaddr *ap_addr, char *extra);
1562int cfg80211_wext_siwgenie(struct net_device *dev,
1563 struct iw_request_info *info,
1564 struct iw_point *data, char *extra);
1565int cfg80211_wext_siwauth(struct net_device *dev,
1566 struct iw_request_info *info,
1567 struct iw_param *data, char *extra);
1568int cfg80211_wext_giwauth(struct net_device *dev,
1569 struct iw_request_info *info,
1570 struct iw_param *data, char *extra);
1571
1538struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy, 1572struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
1539 struct iw_freq *freq); 1573 struct iw_freq *freq);
1540 1574
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 58135a5096af..fbb93a70ddc7 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -870,70 +870,6 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
870 return changed; 870 return changed;
871} 871}
872 872
873static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)
874{
875 union iwreq_data wrqu;
876
877 memset(&wrqu, 0, sizeof(wrqu));
878 if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)
879 memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);
880 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
881 wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
882}
883
884static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
885{
886 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
887 char *buf;
888 size_t len;
889 int i;
890 union iwreq_data wrqu;
891
892 if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
893 return;
894
895 buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
896 ifmgd->assocresp_ies_len), GFP_KERNEL);
897 if (!buf)
898 return;
899
900 len = sprintf(buf, "ASSOCINFO(");
901 if (ifmgd->assocreq_ies) {
902 len += sprintf(buf + len, "ReqIEs=");
903 for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
904 len += sprintf(buf + len, "%02x",
905 ifmgd->assocreq_ies[i]);
906 }
907 }
908 if (ifmgd->assocresp_ies) {
909 if (ifmgd->assocreq_ies)
910 len += sprintf(buf + len, " ");
911 len += sprintf(buf + len, "RespIEs=");
912 for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
913 len += sprintf(buf + len, "%02x",
914 ifmgd->assocresp_ies[i]);
915 }
916 }
917 len += sprintf(buf + len, ")");
918
919 if (len > IW_CUSTOM_MAX) {
920 len = sprintf(buf, "ASSOCRESPIE=");
921 for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
922 len += sprintf(buf + len, "%02x",
923 ifmgd->assocresp_ies[i]);
924 }
925 }
926
927 if (len <= IW_CUSTOM_MAX) {
928 memset(&wrqu, 0, sizeof(wrqu));
929 wrqu.data.length = len;
930 wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf);
931 }
932
933 kfree(buf);
934}
935
936
937static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, 873static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
938 u32 bss_info_changed) 874 u32 bss_info_changed)
939{ 875{
@@ -966,7 +902,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
966 902
967 ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET; 903 ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
968 memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN); 904 memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
969 ieee80211_sta_send_associnfo(sdata);
970 905
971 ifmgd->last_probe = jiffies; 906 ifmgd->last_probe = jiffies;
972 ieee80211_led_assoc(local, 1); 907 ieee80211_led_assoc(local, 1);
@@ -993,8 +928,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
993 928
994 netif_tx_start_all_queues(sdata->dev); 929 netif_tx_start_all_queues(sdata->dev);
995 netif_carrier_on(sdata->dev); 930 netif_carrier_on(sdata->dev);
996
997 ieee80211_sta_send_apinfo(sdata);
998} 931}
999 932
1000static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata) 933static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
@@ -1147,8 +1080,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
1147 changed |= BSS_CHANGED_ASSOC; 1080 changed |= BSS_CHANGED_ASSOC;
1148 sdata->vif.bss_conf.assoc = false; 1081 sdata->vif.bss_conf.assoc = false;
1149 1082
1150 ieee80211_sta_send_apinfo(sdata);
1151
1152 if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) { 1083 if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
1153 ifmgd->state = IEEE80211_STA_MLME_DISABLED; 1084 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1154 ieee80211_rx_bss_remove(sdata, ifmgd->bssid, 1085 ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 1da81f456744..d4e61dc903e8 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -27,29 +27,6 @@
27#include "aes_ccm.h" 27#include "aes_ccm.h"
28 28
29 29
30static int ieee80211_ioctl_siwgenie(struct net_device *dev,
31 struct iw_request_info *info,
32 struct iw_point *data, char *extra)
33{
34 struct ieee80211_sub_if_data *sdata;
35
36 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
37
38 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
39 int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
40 if (ret && ret != -EALREADY)
41 return ret;
42 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
43 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
44 sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
45 if (ret != -EALREADY)
46 ieee80211_sta_req_auth(sdata);
47 return 0;
48 }
49
50 return -EOPNOTSUPP;
51}
52
53static int ieee80211_ioctl_siwfreq(struct net_device *dev, 30static int ieee80211_ioctl_siwfreq(struct net_device *dev,
54 struct iw_request_info *info, 31 struct iw_request_info *info,
55 struct iw_freq *freq, char *extra) 32 struct iw_freq *freq, char *extra)
@@ -61,16 +38,13 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
61 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 38 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
62 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); 39 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
63 else if (sdata->vif.type == NL80211_IFTYPE_STATION) 40 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
64 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; 41 return cfg80211_mgd_wext_siwfreq(dev, info, freq, extra);
65 42
66 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ 43 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
67 if (freq->e == 0) { 44 if (freq->e == 0) {
68 if (freq->m < 0) { 45 if (freq->m < 0)
69 if (sdata->vif.type == NL80211_IFTYPE_STATION) 46 return -EINVAL;
70 sdata->u.mgd.flags |= 47 else
71 IEEE80211_STA_AUTO_CHANNEL_SEL;
72 return 0;
73 } else
74 chan = ieee80211_get_channel(local->hw.wiphy, 48 chan = ieee80211_get_channel(local->hw.wiphy,
75 ieee80211_channel_to_frequency(freq->m)); 49 ieee80211_channel_to_frequency(freq->m));
76 } else { 50 } else {
@@ -95,9 +69,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev,
95 if (local->oper_channel == chan) 69 if (local->oper_channel == chan)
96 return 0; 70 return 0;
97 71
98 if (sdata->vif.type == NL80211_IFTYPE_STATION)
99 ieee80211_sta_req_auth(sdata);
100
101 local->oper_channel = chan; 72 local->oper_channel = chan;
102 local->oper_channel_type = NL80211_CHAN_NO_HT; 73 local->oper_channel_type = NL80211_CHAN_NO_HT;
103 ieee80211_hw_config(local, 0); 74 ieee80211_hw_config(local, 0);
@@ -115,6 +86,8 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev,
115 86
116 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 87 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
117 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); 88 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
89 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
90 return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
118 91
119 freq->m = local->oper_channel->center_freq; 92 freq->m = local->oper_channel->center_freq;
120 freq->e = 6; 93 freq->e = 6;
@@ -128,31 +101,11 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
128 struct iw_point *data, char *ssid) 101 struct iw_point *data, char *ssid)
129{ 102{
130 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); 103 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
131 size_t len = data->length;
132 int ret;
133 104
134 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 105 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
135 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); 106 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
136 107 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
137 /* iwconfig uses nul termination in SSID.. */ 108 return cfg80211_mgd_wext_siwessid(dev, info, data, ssid);
138 if (len > 0 && ssid[len - 1] == '\0')
139 len--;
140
141 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
142 if (data->flags)
143 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
144 else
145 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
146
147 ret = ieee80211_sta_set_ssid(sdata, ssid, len);
148 if (ret)
149 return ret;
150
151 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
152 sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
153 ieee80211_sta_req_auth(sdata);
154 return 0;
155 }
156 109
157 return -EOPNOTSUPP; 110 return -EOPNOTSUPP;
158} 111}
@@ -162,23 +115,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
162 struct iw_request_info *info, 115 struct iw_request_info *info,
163 struct iw_point *data, char *ssid) 116 struct iw_point *data, char *ssid)
164{ 117{
165 size_t len;
166 struct ieee80211_sub_if_data *sdata; 118 struct ieee80211_sub_if_data *sdata;
167 119
168 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 120 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
169 121
170 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 122 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
171 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); 123 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
172 124 else if (sdata->vif.type == NL80211_IFTYPE_STATION)
173 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 125 return cfg80211_mgd_wext_giwessid(dev, info, data, ssid);
174 int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
175 if (res == 0) {
176 data->length = len;
177 data->flags = 1;
178 } else
179 data->flags = 0;
180 return res;
181 }
182 126
183 return -EOPNOTSUPP; 127 return -EOPNOTSUPP;
184} 128}
@@ -193,24 +137,10 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
193 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 137 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
194 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); 138 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
195 139
196 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 140 if (sdata->vif.type == NL80211_IFTYPE_STATION)
197 int ret; 141 return cfg80211_mgd_wext_siwap(dev, info, ap_addr, extra);
198 142
199 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) 143 if (sdata->vif.type == NL80211_IFTYPE_WDS) {
200 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
201 IEEE80211_STA_AUTO_CHANNEL_SEL;
202 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
203 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
204 else
205 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
206 ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
207 if (ret)
208 return ret;
209 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
210 sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;
211 ieee80211_sta_req_auth(sdata);
212 return 0;
213 } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
214 /* 144 /*
215 * If it is necessary to update the WDS peer address 145 * If it is necessary to update the WDS peer address
216 * while the interface is running, then we need to do 146 * while the interface is running, then we need to do
@@ -240,14 +170,10 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
240 if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 170 if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
241 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); 171 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
242 172
243 if (sdata->vif.type == NL80211_IFTYPE_STATION) { 173 if (sdata->vif.type == NL80211_IFTYPE_STATION)
244 if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) { 174 return cfg80211_mgd_wext_giwap(dev, info, ap_addr, extra);
245 ap_addr->sa_family = ARPHRD_ETHER; 175
246 memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN); 176 if (sdata->vif.type == NL80211_IFTYPE_WDS) {
247 } else
248 memset(&ap_addr->sa_data, 0, ETH_ALEN);
249 return 0;
250 } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
251 ap_addr->sa_family = ARPHRD_ETHER; 177 ap_addr->sa_family = ARPHRD_ETHER;
252 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); 178 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
253 return 0; 179 return 0;
@@ -395,85 +321,6 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev,
395 return 0; 321 return 0;
396} 322}
397 323
398static int ieee80211_ioctl_siwauth(struct net_device *dev,
399 struct iw_request_info *info,
400 struct iw_param *data, char *extra)
401{
402 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
403 int ret = 0;
404
405 switch (data->flags & IW_AUTH_INDEX) {
406 case IW_AUTH_WPA_VERSION:
407 case IW_AUTH_CIPHER_GROUP:
408 case IW_AUTH_WPA_ENABLED:
409 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
410 case IW_AUTH_KEY_MGMT:
411 case IW_AUTH_CIPHER_GROUP_MGMT:
412 break;
413 case IW_AUTH_CIPHER_PAIRWISE:
414 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
415 if (data->value & (IW_AUTH_CIPHER_WEP40 |
416 IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
417 sdata->u.mgd.flags |=
418 IEEE80211_STA_TKIP_WEP_USED;
419 else
420 sdata->u.mgd.flags &=
421 ~IEEE80211_STA_TKIP_WEP_USED;
422 }
423 break;
424 case IW_AUTH_DROP_UNENCRYPTED:
425 sdata->drop_unencrypted = !!data->value;
426 break;
427 case IW_AUTH_PRIVACY_INVOKED:
428 if (sdata->vif.type != NL80211_IFTYPE_STATION)
429 ret = -EINVAL;
430 else {
431 sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
432 /*
433 * Privacy invoked by wpa_supplicant, store the
434 * value and allow associating to a protected
435 * network without having a key up front.
436 */
437 if (data->value)
438 sdata->u.mgd.flags |=
439 IEEE80211_STA_PRIVACY_INVOKED;
440 }
441 break;
442 case IW_AUTH_80211_AUTH_ALG:
443 if (sdata->vif.type == NL80211_IFTYPE_STATION)
444 sdata->u.mgd.auth_algs = data->value;
445 else
446 ret = -EOPNOTSUPP;
447 break;
448 case IW_AUTH_MFP:
449 if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
450 ret = -EOPNOTSUPP;
451 break;
452 }
453 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
454 switch (data->value) {
455 case IW_AUTH_MFP_DISABLED:
456 sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
457 break;
458 case IW_AUTH_MFP_OPTIONAL:
459 sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
460 break;
461 case IW_AUTH_MFP_REQUIRED:
462 sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
463 break;
464 default:
465 ret = -EINVAL;
466 }
467 } else
468 ret = -EOPNOTSUPP;
469 break;
470 default:
471 ret = -EOPNOTSUPP;
472 break;
473 }
474 return ret;
475}
476
477/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ 324/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
478static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) 325static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
479{ 326{
@@ -541,28 +388,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
541 return wstats; 388 return wstats;
542} 389}
543 390
544static int ieee80211_ioctl_giwauth(struct net_device *dev,
545 struct iw_request_info *info,
546 struct iw_param *data, char *extra)
547{
548 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
549 int ret = 0;
550
551 switch (data->flags & IW_AUTH_INDEX) {
552 case IW_AUTH_80211_AUTH_ALG:
553 if (sdata->vif.type == NL80211_IFTYPE_STATION)
554 data->value = sdata->u.mgd.auth_algs;
555 else
556 ret = -EOPNOTSUPP;
557 break;
558 default:
559 ret = -EOPNOTSUPP;
560 break;
561 }
562 return ret;
563}
564
565
566/* Structures to export the Wireless Handlers */ 391/* Structures to export the Wireless Handlers */
567 392
568static const iw_handler ieee80211_handler[] = 393static const iw_handler ieee80211_handler[] =
@@ -615,10 +440,10 @@ static const iw_handler ieee80211_handler[] =
615 (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ 440 (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
616 (iw_handler) NULL, /* -- hole -- */ 441 (iw_handler) NULL, /* -- hole -- */
617 (iw_handler) NULL, /* -- hole -- */ 442 (iw_handler) NULL, /* -- hole -- */
618 (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ 443 (iw_handler) cfg80211_wext_siwgenie, /* SIOCSIWGENIE */
619 (iw_handler) NULL, /* SIOCGIWGENIE */ 444 (iw_handler) NULL, /* SIOCGIWGENIE */
620 (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ 445 (iw_handler) cfg80211_wext_siwauth, /* SIOCSIWAUTH */
621 (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ 446 (iw_handler) cfg80211_wext_giwauth, /* SIOCGIWAUTH */
622 (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */ 447 (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
623 (iw_handler) NULL, /* SIOCGIWENCODEEXT */ 448 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
624 (iw_handler) NULL, /* SIOCSIWPMKSA */ 449 (iw_handler) NULL, /* SIOCSIWPMKSA */
diff --git a/net/wireless/Makefile b/net/wireless/Makefile
index 750c08e31b10..d74cc77fa57a 100644
--- a/net/wireless/Makefile
+++ b/net/wireless/Makefile
@@ -7,6 +7,6 @@ obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o wext-sme.o
11 11
12ccflags-y += -D__CHECK_ENDIAN__ 12ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/wireless/core.c b/net/wireless/core.c
index a0a679704612..e2f80dd0e4a6 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -553,6 +553,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
553#ifdef CONFIG_WIRELESS_EXT 553#ifdef CONFIG_WIRELESS_EXT
554 wdev->wext.default_key = -1; 554 wdev->wext.default_key = -1;
555 wdev->wext.default_mgmt_key = -1; 555 wdev->wext.default_mgmt_key = -1;
556 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
556#endif 557#endif
557 mutex_unlock(&rdev->devlist_mtx); 558 mutex_unlock(&rdev->devlist_mtx);
558 break; 559 break;
@@ -565,8 +566,13 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
565 cfg80211_leave_ibss(rdev, dev, true); 566 cfg80211_leave_ibss(rdev, dev, true);
566 break; 567 break;
567 case NL80211_IFTYPE_STATION: 568 case NL80211_IFTYPE_STATION:
569#ifdef CONFIG_WIRELESS_EXT
570 kfree(wdev->wext.ie);
571 wdev->wext.ie = NULL;
572 wdev->wext.ie_len = 0;
573#endif
568 cfg80211_disconnect(rdev, dev, 574 cfg80211_disconnect(rdev, dev,
569 WLAN_REASON_DEAUTH_LEAVING); 575 WLAN_REASON_DEAUTH_LEAVING, true);
570 break; 576 break;
571 default: 577 default:
572 break; 578 break;
@@ -578,11 +584,20 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
578 break; 584 break;
579 case NETDEV_UP: 585 case NETDEV_UP:
580#ifdef CONFIG_WIRELESS_EXT 586#ifdef CONFIG_WIRELESS_EXT
581 if (wdev->iftype != NL80211_IFTYPE_ADHOC) 587 switch (wdev->iftype) {
588 case NL80211_IFTYPE_ADHOC:
589 if (wdev->wext.ibss.ssid_len)
590 cfg80211_join_ibss(rdev, dev,
591 &wdev->wext.ibss);
582 break; 592 break;
583 if (!wdev->wext.ibss.ssid_len) 593 case NL80211_IFTYPE_STATION:
594 if (wdev->wext.connect.ssid_len)
595 cfg80211_connect(rdev, dev,
596 &wdev->wext.connect);
597 break;
598 default:
584 break; 599 break;
585 cfg80211_join_ibss(rdev, dev, &wdev->wext.ibss); 600 }
586#endif 601#endif
587 break; 602 break;
588 case NETDEV_UNREGISTER: 603 case NETDEV_UNREGISTER:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 2c0f64252f3d..5209acb0ff7e 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -181,7 +181,8 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
181 struct net_device *dev, 181 struct net_device *dev,
182 struct cfg80211_connect_params *connect); 182 struct cfg80211_connect_params *connect);
183int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 183int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
184 struct net_device *dev, u16 reason); 184 struct net_device *dev, u16 reason,
185 bool wextev);
185 186
186void cfg80211_conn_work(struct work_struct *work); 187void cfg80211_conn_work(struct work_struct *work);
187 188
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 89aa9e781d10..0008144b354b 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -3747,7 +3747,7 @@ static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info)
3747 goto out; 3747 goto out;
3748 } 3748 }
3749 3749
3750 err = cfg80211_disconnect(drv, dev, reason); 3750 err = cfg80211_disconnect(drv, dev, reason, true);
3751 3751
3752out: 3752out:
3753 cfg80211_put_dev(drv); 3753 cfg80211_put_dev(drv);
diff --git a/net/wireless/sme.c b/net/wireless/sme.c
index 3abb04729873..f272ebf94303 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -273,10 +273,10 @@ void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
273 } 273 }
274} 274}
275 275
276void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, 276static void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
277 const u8 *req_ie, size_t req_ie_len, 277 const u8 *req_ie, size_t req_ie_len,
278 const u8 *resp_ie, size_t resp_ie_len, 278 const u8 *resp_ie, size_t resp_ie_len,
279 u16 status, gfp_t gfp) 279 u16 status, bool wextev, gfp_t gfp)
280{ 280{
281 struct wireless_dev *wdev = dev->ieee80211_ptr; 281 struct wireless_dev *wdev = dev->ieee80211_ptr;
282 struct cfg80211_bss *bss; 282 struct cfg80211_bss *bss;
@@ -321,25 +321,36 @@ void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
321 status, gfp); 321 status, gfp);
322 322
323#ifdef CONFIG_WIRELESS_EXT 323#ifdef CONFIG_WIRELESS_EXT
324 if (req_ie && status == WLAN_STATUS_SUCCESS) { 324 if (wextev) {
325 memset(&wrqu, 0, sizeof(wrqu)); 325 if (req_ie && status == WLAN_STATUS_SUCCESS) {
326 wrqu.data.length = req_ie_len; 326 memset(&wrqu, 0, sizeof(wrqu));
327 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); 327 wrqu.data.length = req_ie_len;
328 } 328 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie);
329 }
330
331 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
332 memset(&wrqu, 0, sizeof(wrqu));
333 wrqu.data.length = resp_ie_len;
334 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie);
335 }
329 336
330 if (resp_ie && status == WLAN_STATUS_SUCCESS) {
331 memset(&wrqu, 0, sizeof(wrqu)); 337 memset(&wrqu, 0, sizeof(wrqu));
332 wrqu.data.length = resp_ie_len; 338 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
333 wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); 339 if (bssid && status == WLAN_STATUS_SUCCESS)
340 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
341 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
334 } 342 }
335
336 memset(&wrqu, 0, sizeof(wrqu));
337 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
338 if (bssid && status == WLAN_STATUS_SUCCESS)
339 memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
340 wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
341#endif 343#endif
342} 344}
345
346void cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
347 const u8 *req_ie, size_t req_ie_len,
348 const u8 *resp_ie, size_t resp_ie_len,
349 u16 status, gfp_t gfp)
350{
351 bool wextev = status == WLAN_STATUS_SUCCESS;
352 __cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, resp_ie, resp_ie_len, status, wextev, gfp);
353}
343EXPORT_SYMBOL(cfg80211_connect_result); 354EXPORT_SYMBOL(cfg80211_connect_result);
344 355
345void cfg80211_roamed(struct net_device *dev, const u8 *bssid, 356void cfg80211_roamed(struct net_device *dev, const u8 *bssid,
@@ -540,7 +551,7 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
540} 551}
541 552
542int cfg80211_disconnect(struct cfg80211_registered_device *rdev, 553int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
543 struct net_device *dev, u16 reason) 554 struct net_device *dev, u16 reason, bool wextev)
544{ 555{
545 struct wireless_dev *wdev = dev->ieee80211_ptr; 556 struct wireless_dev *wdev = dev->ieee80211_ptr;
546 int err; 557 int err;
@@ -585,9 +596,9 @@ int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
585 if (wdev->sme_state == CFG80211_SME_CONNECTED) 596 if (wdev->sme_state == CFG80211_SME_CONNECTED)
586 __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false); 597 __cfg80211_disconnected(dev, GFP_KERNEL, NULL, 0, 0, false);
587 else if (wdev->sme_state == CFG80211_SME_CONNECTING) 598 else if (wdev->sme_state == CFG80211_SME_CONNECTING)
588 cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0, 599 __cfg80211_connect_result(dev, NULL, NULL, 0, NULL, 0,
589 WLAN_STATUS_UNSPECIFIED_FAILURE, 600 WLAN_STATUS_UNSPECIFIED_FAILURE,
590 GFP_KERNEL); 601 wextev, GFP_KERNEL);
591 602
592 return 0; 603 return 0;
593} 604}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index cae3b52fba7f..02f052fc1808 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -261,50 +261,6 @@ int cfg80211_wext_giwrange(struct net_device *dev,
261} 261}
262EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange); 262EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
263 263
264int cfg80211_wext_siwmlme(struct net_device *dev,
265 struct iw_request_info *info,
266 struct iw_point *data, char *extra)
267{
268 struct wireless_dev *wdev = dev->ieee80211_ptr;
269 struct iw_mlme *mlme = (struct iw_mlme *)extra;
270 struct cfg80211_registered_device *rdev;
271 union {
272 struct cfg80211_disassoc_request disassoc;
273 struct cfg80211_deauth_request deauth;
274 } cmd;
275
276 if (!wdev)
277 return -EOPNOTSUPP;
278
279 rdev = wiphy_to_dev(wdev->wiphy);
280
281 if (wdev->iftype != NL80211_IFTYPE_STATION)
282 return -EINVAL;
283
284 if (mlme->addr.sa_family != ARPHRD_ETHER)
285 return -EINVAL;
286
287 memset(&cmd, 0, sizeof(cmd));
288
289 switch (mlme->cmd) {
290 case IW_MLME_DEAUTH:
291 if (!rdev->ops->deauth)
292 return -EOPNOTSUPP;
293 cmd.deauth.peer_addr = mlme->addr.sa_data;
294 cmd.deauth.reason_code = mlme->reason_code;
295 return rdev->ops->deauth(wdev->wiphy, dev, &cmd.deauth);
296 case IW_MLME_DISASSOC:
297 if (!rdev->ops->disassoc)
298 return -EOPNOTSUPP;
299 cmd.disassoc.peer_addr = mlme->addr.sa_data;
300 cmd.disassoc.reason_code = mlme->reason_code;
301 return rdev->ops->disassoc(wdev->wiphy, dev, &cmd.disassoc);
302 default:
303 return -EOPNOTSUPP;
304 }
305}
306EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);
307
308 264
309/** 265/**
310 * cfg80211_wext_freq - get wext frequency for non-"auto" 266 * cfg80211_wext_freq - get wext frequency for non-"auto"
@@ -846,3 +802,188 @@ int cfg80211_wext_giwtxpower(struct net_device *dev,
846 return 0; 802 return 0;
847} 803}
848EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower); 804EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
805
806static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
807 s32 auth_alg)
808{
809 int nr_alg = 0;
810
811 if (!auth_alg)
812 return -EINVAL;
813
814 if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM |
815 IW_AUTH_ALG_SHARED_KEY |
816 IW_AUTH_ALG_LEAP))
817 return -EINVAL;
818
819 if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) {
820 nr_alg++;
821 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
822 }
823
824 if (auth_alg & IW_AUTH_ALG_SHARED_KEY) {
825 nr_alg++;
826 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY;
827 }
828
829 if (auth_alg & IW_AUTH_ALG_LEAP) {
830 nr_alg++;
831 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP;
832 }
833
834 if (nr_alg > 1)
835 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
836
837 return 0;
838}
839
840static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
841{
842 wdev->wext.connect.crypto.wpa_versions = 0;
843
844 if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
845 IW_AUTH_WPA_VERSION_WPA2))
846 return -EINVAL;
847
848 if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
849 wdev->wext.connect.crypto.wpa_versions |=
850 NL80211_WPA_VERSION_1;
851
852 if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2)
853 wdev->wext.connect.crypto.wpa_versions |=
854 NL80211_WPA_VERSION_2;
855
856 return 0;
857}
858
859int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
860{
861 wdev->wext.connect.crypto.cipher_group = 0;
862
863 if (cipher & IW_AUTH_CIPHER_WEP40)
864 wdev->wext.connect.crypto.cipher_group =
865 WLAN_CIPHER_SUITE_WEP40;
866 else if (cipher & IW_AUTH_CIPHER_WEP104)
867 wdev->wext.connect.crypto.cipher_group =
868 WLAN_CIPHER_SUITE_WEP104;
869 else if (cipher & IW_AUTH_CIPHER_TKIP)
870 wdev->wext.connect.crypto.cipher_group =
871 WLAN_CIPHER_SUITE_TKIP;
872 else if (cipher & IW_AUTH_CIPHER_CCMP)
873 wdev->wext.connect.crypto.cipher_group =
874 WLAN_CIPHER_SUITE_CCMP;
875 else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
876 wdev->wext.connect.crypto.cipher_group =
877 WLAN_CIPHER_SUITE_AES_CMAC;
878 else
879 return -EINVAL;
880
881 return 0;
882}
883
884int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
885{
886 int nr_ciphers = 0;
887 u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
888
889 if (cipher & IW_AUTH_CIPHER_WEP40) {
890 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40;
891 nr_ciphers++;
892 }
893
894 if (cipher & IW_AUTH_CIPHER_WEP104) {
895 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104;
896 nr_ciphers++;
897 }
898
899 if (cipher & IW_AUTH_CIPHER_TKIP) {
900 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP;
901 nr_ciphers++;
902 }
903
904 if (cipher & IW_AUTH_CIPHER_CCMP) {
905 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP;
906 nr_ciphers++;
907 }
908
909 if (cipher & IW_AUTH_CIPHER_AES_CMAC) {
910 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC;
911 nr_ciphers++;
912 }
913
914 BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
915
916 wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
917
918 return 0;
919}
920
921
922int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
923{
924 int nr_akm_suites = 0;
925
926 if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
927 IW_AUTH_KEY_MGMT_PSK))
928 return -EINVAL;
929
930 if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
931 wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
932 WLAN_AKM_SUITE_8021X;
933 nr_akm_suites++;
934 }
935
936 if (key_mgt & IW_AUTH_KEY_MGMT_PSK) {
937 wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
938 WLAN_AKM_SUITE_PSK;
939 nr_akm_suites++;
940 }
941
942 wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
943
944 return 0;
945}
946
947int cfg80211_wext_siwauth(struct net_device *dev,
948 struct iw_request_info *info,
949 struct iw_param *data, char *extra)
950{
951 struct wireless_dev *wdev = dev->ieee80211_ptr;
952
953 if (wdev->iftype != NL80211_IFTYPE_STATION)
954 return -EOPNOTSUPP;
955
956 switch (data->flags & IW_AUTH_INDEX) {
957 case IW_AUTH_PRIVACY_INVOKED:
958 wdev->wext.connect.privacy = data->value;
959 return 0;
960 case IW_AUTH_WPA_VERSION:
961 return cfg80211_set_wpa_version(wdev, data->value);
962 case IW_AUTH_CIPHER_GROUP:
963 return cfg80211_set_cipher_group(wdev, data->value);
964 case IW_AUTH_KEY_MGMT:
965 return cfg80211_set_key_mgt(wdev, data->value);
966 case IW_AUTH_CIPHER_PAIRWISE:
967 return cfg80211_set_cipher_pairwise(wdev, data->value);
968 case IW_AUTH_80211_AUTH_ALG:
969 return cfg80211_set_auth_alg(wdev, data->value);
970 case IW_AUTH_WPA_ENABLED:
971 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
972 case IW_AUTH_DROP_UNENCRYPTED:
973 case IW_AUTH_MFP:
974 return 0;
975 default:
976 return -EOPNOTSUPP;
977 }
978}
979EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth);
980
981int cfg80211_wext_giwauth(struct net_device *dev,
982 struct iw_request_info *info,
983 struct iw_param *data, char *extra)
984{
985 /* XXX: what do we need? */
986
987 return -EOPNOTSUPP;
988}
989EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
new file mode 100644
index 000000000000..3b531d572b69
--- /dev/null
+++ b/net/wireless/wext-sme.c
@@ -0,0 +1,329 @@
1/*
2 * cfg80211 wext compat for managed mode.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/etherdevice.h>
9#include <linux/if_arp.h>
10#include <net/cfg80211.h>
11#include "nl80211.h"
12
13static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *wdev)
15{
16 int err;
17
18 if (!netif_running(wdev->netdev))
19 return 0;
20
21 wdev->wext.connect.ie = wdev->wext.ie;
22 wdev->wext.connect.ie_len = wdev->wext.ie_len;
23 wdev->wext.connect.privacy = wdev->wext.default_key != -1;
24
25 err = 0;
26 if (wdev->wext.connect.ssid_len != 0)
27 err = cfg80211_connect(rdev, wdev->netdev,
28 &wdev->wext.connect);
29
30 return err;
31}
32
33int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
34 struct iw_request_info *info,
35 struct iw_freq *freq, char *extra)
36{
37 struct wireless_dev *wdev = dev->ieee80211_ptr;
38 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
39 struct ieee80211_channel *chan;
40 int err;
41
42 /* call only for station! */
43 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
44 return -EINVAL;
45
46 chan = cfg80211_wext_freq(wdev->wiphy, freq);
47 if (chan && IS_ERR(chan))
48 return PTR_ERR(chan);
49
50 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
51 return -EINVAL;
52
53 if (wdev->wext.connect.channel == chan)
54 return 0;
55
56 if (wdev->sme_state != CFG80211_SME_IDLE) {
57 bool event = true;
58 /* if SSID set, we'll try right again, avoid event */
59 if (wdev->wext.connect.ssid_len)
60 event = false;
61 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
62 dev, WLAN_REASON_DEAUTH_LEAVING,
63 event);
64 if (err)
65 return err;
66 }
67
68 wdev->wext.connect.channel = chan;
69
70 /* SSID is not set, we just want to switch channel */
71 if (wdev->wext.connect.ssid_len && chan) {
72 if (!rdev->ops->set_channel)
73 return -EOPNOTSUPP;
74
75 return rdev->ops->set_channel(wdev->wiphy, chan,
76 NL80211_CHAN_NO_HT);
77 }
78
79 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
80}
81/* temporary symbol - mark GPL - in the future the handler won't be */
82EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
83
84int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
85 struct iw_request_info *info,
86 struct iw_freq *freq, char *extra)
87{
88 struct wireless_dev *wdev = dev->ieee80211_ptr;
89 struct ieee80211_channel *chan = NULL;
90
91 /* call only for station! */
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return -EINVAL;
94
95 if (wdev->current_bss)
96 chan = wdev->current_bss->channel;
97 else if (wdev->wext.connect.channel)
98 chan = wdev->wext.connect.channel;
99
100 if (chan) {
101 freq->m = chan->center_freq;
102 freq->e = 6;
103 return 0;
104 }
105
106 /* no channel if not joining */
107 return -EINVAL;
108}
109/* temporary symbol - mark GPL - in the future the handler won't be */
110EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq);
111
112int cfg80211_mgd_wext_siwessid(struct net_device *dev,
113 struct iw_request_info *info,
114 struct iw_point *data, char *ssid)
115{
116 struct wireless_dev *wdev = dev->ieee80211_ptr;
117 size_t len = data->length;
118 int err;
119
120 /* call only for station! */
121 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
122 return -EINVAL;
123
124 if (!data->flags)
125 len = 0;
126
127 /* iwconfig uses nul termination in SSID.. */
128 if (len > 0 && ssid[len - 1] == '\0')
129 len--;
130
131 if (wdev->wext.connect.ssid && len &&
132 len == wdev->wext.connect.ssid_len &&
133 memcmp(wdev->wext.connect.ssid, ssid, len))
134 return 0;
135
136 if (wdev->sme_state != CFG80211_SME_IDLE) {
137 bool event = true;
138 /* if SSID set now, we'll try to connect, avoid event */
139 if (len)
140 event = false;
141 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
142 dev, WLAN_REASON_DEAUTH_LEAVING,
143 event);
144 if (err)
145 return err;
146 }
147
148 wdev->wext.connect.ssid = wdev->wext.ssid;
149 memcpy(wdev->wext.ssid, ssid, len);
150 wdev->wext.connect.ssid_len = len;
151
152 wdev->wext.connect.crypto.control_port = false;
153
154 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
155}
156/* temporary symbol - mark GPL - in the future the handler won't be */
157EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
158
159int cfg80211_mgd_wext_giwessid(struct net_device *dev,
160 struct iw_request_info *info,
161 struct iw_point *data, char *ssid)
162{
163 struct wireless_dev *wdev = dev->ieee80211_ptr;
164
165 /* call only for station! */
166 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
167 return -EINVAL;
168
169 data->flags = 0;
170
171 if (wdev->ssid_len) {
172 data->flags = 1;
173 data->length = wdev->ssid_len;
174 memcpy(ssid, wdev->ssid, data->length);
175 } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
176 data->flags = 1;
177 data->length = wdev->wext.connect.ssid_len;
178 memcpy(ssid, wdev->wext.connect.ssid, data->length);
179 } else
180 data->flags = 0;
181
182 return 0;
183}
184/* temporary symbol - mark GPL - in the future the handler won't be */
185EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid);
186
187int cfg80211_mgd_wext_siwap(struct net_device *dev,
188 struct iw_request_info *info,
189 struct sockaddr *ap_addr, char *extra)
190{
191 struct wireless_dev *wdev = dev->ieee80211_ptr;
192 u8 *bssid = ap_addr->sa_data;
193 int err;
194
195 /* call only for station! */
196 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
197 return -EINVAL;
198
199 if (ap_addr->sa_family != ARPHRD_ETHER)
200 return -EINVAL;
201
202 /* automatic mode */
203 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
204 bssid = NULL;
205
206 /* both automatic */
207 if (!bssid && !wdev->wext.connect.bssid)
208 return 0;
209
210 /* fixed already - and no change */
211 if (wdev->wext.connect.bssid && bssid &&
212 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
213 return 0;
214
215 if (wdev->sme_state != CFG80211_SME_IDLE) {
216 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
217 dev, WLAN_REASON_DEAUTH_LEAVING,
218 false);
219 if (err)
220 return err;
221 }
222
223 if (bssid) {
224 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
225 wdev->wext.connect.bssid = wdev->wext.bssid;
226 } else
227 wdev->wext.connect.bssid = NULL;
228
229 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
230}
231/* temporary symbol - mark GPL - in the future the handler won't be */
232EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
233
234int cfg80211_mgd_wext_giwap(struct net_device *dev,
235 struct iw_request_info *info,
236 struct sockaddr *ap_addr, char *extra)
237{
238 struct wireless_dev *wdev = dev->ieee80211_ptr;
239
240 /* call only for station! */
241 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
242 return -EINVAL;
243
244 ap_addr->sa_family = ARPHRD_ETHER;
245
246 if (wdev->current_bss)
247 memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN);
248 else if (wdev->wext.connect.bssid)
249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
250 else
251 memset(ap_addr->sa_data, 0, ETH_ALEN);
252
253 return 0;
254}
255/* temporary symbol - mark GPL - in the future the handler won't be */
256EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap);
257
258int cfg80211_wext_siwgenie(struct net_device *dev,
259 struct iw_request_info *info,
260 struct iw_point *data, char *extra)
261{
262 struct wireless_dev *wdev = dev->ieee80211_ptr;
263 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
264 u8 *ie = extra;
265 int ie_len = data->length, err;
266
267 if (wdev->iftype != NL80211_IFTYPE_STATION)
268 return -EOPNOTSUPP;
269
270 if (!ie_len)
271 ie = NULL;
272
273 /* no change */
274 if (wdev->wext.ie_len == ie_len &&
275 memcmp(wdev->wext.ie, ie, ie_len) == 0)
276 return 0;
277
278 if (ie_len) {
279 ie = kmemdup(extra, ie_len, GFP_KERNEL);
280 if (!ie)
281 return -ENOMEM;
282 } else
283 ie = NULL;
284
285 kfree(wdev->wext.ie);
286 wdev->wext.ie = ie;
287 wdev->wext.ie_len = ie_len;
288
289 if (wdev->sme_state != CFG80211_SME_IDLE) {
290 err = cfg80211_disconnect(rdev, dev,
291 WLAN_REASON_DEAUTH_LEAVING, false);
292 if (err)
293 return err;
294 }
295
296 /* userspace better not think we'll reconnect */
297 return 0;
298}
299EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
300
301int cfg80211_wext_siwmlme(struct net_device *dev,
302 struct iw_request_info *info,
303 struct iw_point *data, char *extra)
304{
305 struct wireless_dev *wdev = dev->ieee80211_ptr;
306 struct iw_mlme *mlme = (struct iw_mlme *)extra;
307 struct cfg80211_registered_device *rdev;
308
309 if (!wdev)
310 return -EOPNOTSUPP;
311
312 rdev = wiphy_to_dev(wdev->wiphy);
313
314 if (wdev->iftype != NL80211_IFTYPE_STATION)
315 return -EINVAL;
316
317 if (mlme->addr.sa_family != ARPHRD_ETHER)
318 return -EINVAL;
319
320 switch (mlme->cmd) {
321 case IW_MLME_DEAUTH:
322 case IW_MLME_DISASSOC:
323 return cfg80211_disconnect(rdev, dev, mlme->reason_code,
324 true);
325 default:
326 return -EOPNOTSUPP;
327 }
328}
329EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);