aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-01 15:26:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:51 -0400
commitf21293549f60f88c74fcb9944737f11048896dc4 (patch)
treed4a00663f87816c0c742e74d7b2c9bad31a18816
parent6829c878ecd24ff0ae41b4668c7e9d0f11b66942 (diff)
cfg80211: managed mode wext compatibility
This adds code to make it possible to use the cfg80211 connect() API with wireless extensions, and because the previous patch added emulation of that API with auth() and assoc(), by extension also supports wext on that. At the same time, removes code from mac80211 for wext, but doesn't yet clean up mac80211's mlme code more. Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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);