aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2009-03-19 07:39:22 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-03-27 20:13:02 -0400
commit636a5d3625993c5ca59abc81794b9ded93cdb740 (patch)
tree53ee8d522153c36c631f8cb733a6e808c20ef332 /net
parent6039f6d23fe792d615da5449e9fa1c6b43caacf6 (diff)
nl80211: Add MLME primitives to support external SME
This patch adds new nl80211 commands to allow user space to request authentication and association (and also deauthentication and disassociation). The commands are structured to allow separate authentication and association steps, i.e., the interface between kernel and user space is similar to the MLME SAP interface in IEEE 802.11 standard and an user space application takes the role of the SME. The patch introduces MLME-AUTHENTICATE.request, MLME-{,RE}ASSOCIATE.request, MLME-DEAUTHENTICATE.request, and MLME-DISASSOCIATE.request primitives. The authentication and association commands request the actual operations in two steps (assuming the driver supports this; if not, separate authentication step is skipped; this could end up being a separate "connect" command). The initial implementation for mac80211 uses the current net/mac80211/mlme.c for actual sending and processing of management frames and the new nl80211 commands will just stop the current state machine from moving automatically from authentication to association. Future cleanup may move more of the MLME operations into cfg80211. The goal of this design is to provide more control of authentication and association process to user space without having to move the full MLME implementation. This should be enough to allow IEEE 802.11r FT protocol and 802.11s SAE authentication to be implemented. Obviously, this will also bring the extra benefit of not having to use WEXT for association requests with mac80211. An example implementation of a user space SME using the new nl80211 commands is available for wpa_supplicant. This patch is enough to get IEEE 802.11r FT protocol working with over-the-air mechanism (over-the-DS will need additional MLME primitives for handling the FT Action frames). Signed-off-by: Jouni Malinen <j@w1.fi> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/cfg.c140
-rw-r--r--net/mac80211/ieee80211_i.h7
-rw-r--r--net/mac80211/mlme.c45
-rw-r--r--net/mac80211/wext.c3
-rw-r--r--net/wireless/nl80211.c255
5 files changed, 439 insertions, 11 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 58693e52d458..223e536e8426 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1300,6 +1300,142 @@ static int ieee80211_scan(struct wiphy *wiphy,
1300 return ieee80211_request_scan(sdata, req); 1300 return ieee80211_request_scan(sdata, req);
1301} 1301}
1302 1302
1303static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
1304 struct cfg80211_auth_request *req)
1305{
1306 struct ieee80211_sub_if_data *sdata;
1307
1308 if (!netif_running(dev))
1309 return -ENETDOWN;
1310
1311 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1312
1313 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1314 return -EOPNOTSUPP;
1315
1316 switch (req->auth_type) {
1317 case NL80211_AUTHTYPE_OPEN_SYSTEM:
1318 sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_OPEN;
1319 break;
1320 case NL80211_AUTHTYPE_SHARED_KEY:
1321 sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_SHARED_KEY;
1322 break;
1323 case NL80211_AUTHTYPE_FT:
1324 sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_FT;
1325 break;
1326 case NL80211_AUTHTYPE_NETWORK_EAP:
1327 sdata->u.mgd.auth_algs = IEEE80211_AUTH_ALG_LEAP;
1328 break;
1329 default:
1330 return -EOPNOTSUPP;
1331 }
1332
1333 memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN);
1334 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
1335 sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
1336
1337 /* TODO: req->chan */
1338 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
1339
1340 if (req->ssid) {
1341 sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
1342 memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
1343 sdata->u.mgd.ssid_len = req->ssid_len;
1344 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
1345 }
1346
1347 kfree(sdata->u.mgd.sme_auth_ie);
1348 sdata->u.mgd.sme_auth_ie = NULL;
1349 sdata->u.mgd.sme_auth_ie_len = 0;
1350 if (req->ie) {
1351 sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
1352 if (sdata->u.mgd.sme_auth_ie == NULL)
1353 return -ENOMEM;
1354 memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
1355 sdata->u.mgd.sme_auth_ie_len = req->ie_len;
1356 }
1357
1358 sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
1359 sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
1360 ieee80211_sta_req_auth(sdata);
1361 return 0;
1362}
1363
1364static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
1365 struct cfg80211_assoc_request *req)
1366{
1367 struct ieee80211_sub_if_data *sdata;
1368 int ret;
1369
1370 if (!netif_running(dev))
1371 return -ENETDOWN;
1372
1373 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1374
1375 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1376 return -EOPNOTSUPP;
1377
1378 if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 ||
1379 !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
1380 return -ENOLINK; /* not authenticated */
1381
1382 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
1383 sdata->u.mgd.flags |= IEEE80211_STA_BSSID_SET;
1384
1385 /* TODO: req->chan */
1386 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_CHANNEL_SEL;
1387
1388 if (req->ssid) {
1389 sdata->u.mgd.flags |= IEEE80211_STA_SSID_SET;
1390 memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len);
1391 sdata->u.mgd.ssid_len = req->ssid_len;
1392 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
1393 } else
1394 sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
1395
1396 ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
1397 if (ret)
1398 return ret;
1399
1400 sdata->u.mgd.flags |= IEEE80211_STA_EXT_SME;
1401 sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
1402 ieee80211_sta_req_auth(sdata);
1403 return 0;
1404}
1405
1406static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
1407 struct cfg80211_deauth_request *req)
1408{
1409 struct ieee80211_sub_if_data *sdata;
1410
1411 if (!netif_running(dev))
1412 return -ENETDOWN;
1413
1414 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1415 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1416 return -EOPNOTSUPP;
1417
1418 /* TODO: req->ie */
1419 return ieee80211_sta_deauthenticate(sdata, req->reason_code);
1420}
1421
1422static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
1423 struct cfg80211_disassoc_request *req)
1424{
1425 struct ieee80211_sub_if_data *sdata;
1426
1427 if (!netif_running(dev))
1428 return -ENETDOWN;
1429
1430 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1431
1432 if (sdata->vif.type != NL80211_IFTYPE_STATION)
1433 return -EOPNOTSUPP;
1434
1435 /* TODO: req->ie */
1436 return ieee80211_sta_disassociate(sdata, req->reason_code);
1437}
1438
1303struct cfg80211_ops mac80211_config_ops = { 1439struct cfg80211_ops mac80211_config_ops = {
1304 .add_virtual_intf = ieee80211_add_iface, 1440 .add_virtual_intf = ieee80211_add_iface,
1305 .del_virtual_intf = ieee80211_del_iface, 1441 .del_virtual_intf = ieee80211_del_iface,
@@ -1333,4 +1469,8 @@ struct cfg80211_ops mac80211_config_ops = {
1333 .suspend = ieee80211_suspend, 1469 .suspend = ieee80211_suspend,
1334 .resume = ieee80211_resume, 1470 .resume = ieee80211_resume,
1335 .scan = ieee80211_scan, 1471 .scan = ieee80211_scan,
1472 .auth = ieee80211_auth,
1473 .assoc = ieee80211_assoc,
1474 .deauth = ieee80211_deauth,
1475 .disassoc = ieee80211_disassoc,
1336}; 1476};
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ad12c2a03a95..7b96d95f48b1 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -256,6 +256,7 @@ struct mesh_preq_queue {
256#define IEEE80211_STA_TKIP_WEP_USED BIT(14) 256#define IEEE80211_STA_TKIP_WEP_USED BIT(14)
257#define IEEE80211_STA_CSA_RECEIVED BIT(15) 257#define IEEE80211_STA_CSA_RECEIVED BIT(15)
258#define IEEE80211_STA_MFP_ENABLED BIT(16) 258#define IEEE80211_STA_MFP_ENABLED BIT(16)
259#define IEEE80211_STA_EXT_SME BIT(17)
259/* flags for MLME request */ 260/* flags for MLME request */
260#define IEEE80211_STA_REQ_SCAN 0 261#define IEEE80211_STA_REQ_SCAN 0
261#define IEEE80211_STA_REQ_DIRECT_PROBE 1 262#define IEEE80211_STA_REQ_DIRECT_PROBE 1
@@ -266,6 +267,7 @@ struct mesh_preq_queue {
266#define IEEE80211_AUTH_ALG_OPEN BIT(0) 267#define IEEE80211_AUTH_ALG_OPEN BIT(0)
267#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) 268#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
268#define IEEE80211_AUTH_ALG_LEAP BIT(2) 269#define IEEE80211_AUTH_ALG_LEAP BIT(2)
270#define IEEE80211_AUTH_ALG_FT BIT(3)
269 271
270struct ieee80211_if_managed { 272struct ieee80211_if_managed {
271 struct timer_list timer; 273 struct timer_list timer;
@@ -335,6 +337,9 @@ struct ieee80211_if_managed {
335 size_t ie_deauth_len; 337 size_t ie_deauth_len;
336 u8 *ie_disassoc; 338 u8 *ie_disassoc;
337 size_t ie_disassoc_len; 339 size_t ie_disassoc_len;
340
341 u8 *sme_auth_ie;
342 size_t sme_auth_ie_len;
338}; 343};
339 344
340enum ieee80211_ibss_flags { 345enum ieee80211_ibss_flags {
@@ -970,7 +975,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata,
970 struct sk_buff *skb, 975 struct sk_buff *skb,
971 struct ieee80211_rx_status *rx_status); 976 struct ieee80211_rx_status *rx_status);
972int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, 977int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
973 char *ie, size_t len); 978 const char *ie, size_t len);
974 979
975void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); 980void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
976void ieee80211_scan_failed(struct ieee80211_local *local); 981void ieee80211_scan_failed(struct ieee80211_local *local);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6dc7a61bc18b..d1bcc8438772 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -730,6 +730,8 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
730{ 730{
731 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 731 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
732 struct ieee80211_local *local = sdata->local; 732 struct ieee80211_local *local = sdata->local;
733 u8 *ies;
734 size_t ies_len;
733 735
734 ifmgd->auth_tries++; 736 ifmgd->auth_tries++;
735 if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) { 737 if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
@@ -755,7 +757,14 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
755 printk(KERN_DEBUG "%s: authenticate with AP %pM\n", 757 printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
756 sdata->dev->name, ifmgd->bssid); 758 sdata->dev->name, ifmgd->bssid);
757 759
758 ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0, 760 if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
761 ies = ifmgd->sme_auth_ie;
762 ies_len = ifmgd->sme_auth_ie_len;
763 } else {
764 ies = NULL;
765 ies_len = 0;
766 }
767 ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, ies, ies_len,
759 ifmgd->bssid, 0); 768 ifmgd->bssid, 0);
760 ifmgd->auth_transaction = 2; 769 ifmgd->auth_transaction = 2;
761 770
@@ -870,7 +879,8 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)
870 int wep_privacy; 879 int wep_privacy;
871 int privacy_invoked; 880 int privacy_invoked;
872 881
873 if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL)) 882 if (!ifmgd || (ifmgd->flags & (IEEE80211_STA_MIXED_CELL |
883 IEEE80211_STA_EXT_SME)))
874 return 0; 884 return 0;
875 885
876 bss = ieee80211_rx_bss_get(local, ifmgd->bssid, 886 bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
@@ -998,7 +1008,11 @@ static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
998 1008
999 printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name); 1009 printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
1000 ifmgd->flags |= IEEE80211_STA_AUTHENTICATED; 1010 ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;
1001 ieee80211_associate(sdata); 1011 if (ifmgd->flags & IEEE80211_STA_EXT_SME) {
1012 /* Wait for SME to request association */
1013 ifmgd->state = IEEE80211_STA_MLME_DISABLED;
1014 } else
1015 ieee80211_associate(sdata);
1002} 1016}
1003 1017
1004 1018
@@ -1084,6 +1098,7 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
1084 switch (ifmgd->auth_alg) { 1098 switch (ifmgd->auth_alg) {
1085 case WLAN_AUTH_OPEN: 1099 case WLAN_AUTH_OPEN:
1086 case WLAN_AUTH_LEAP: 1100 case WLAN_AUTH_LEAP:
1101 case WLAN_AUTH_FT:
1087 ieee80211_auth_completed(sdata); 1102 ieee80211_auth_completed(sdata);
1088 cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len); 1103 cfg80211_send_rx_auth(sdata->dev, (u8 *) mgmt, len);
1089 break; 1104 break;
@@ -1117,9 +1132,10 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
1117 printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", 1132 printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
1118 sdata->dev->name, reason_code); 1133 sdata->dev->name, reason_code);
1119 1134
1120 if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE || 1135 if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
1121 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE || 1136 (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
1122 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { 1137 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE ||
1138 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)) {
1123 ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE; 1139 ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
1124 mod_timer(&ifmgd->timer, jiffies + 1140 mod_timer(&ifmgd->timer, jiffies +
1125 IEEE80211_RETRY_AUTH_INTERVAL); 1141 IEEE80211_RETRY_AUTH_INTERVAL);
@@ -1150,7 +1166,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
1150 printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", 1166 printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
1151 sdata->dev->name, reason_code); 1167 sdata->dev->name, reason_code);
1152 1168
1153 if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) { 1169 if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
1170 ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {
1154 ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE; 1171 ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
1155 mod_timer(&ifmgd->timer, jiffies + 1172 mod_timer(&ifmgd->timer, jiffies +
1156 IEEE80211_RETRY_AUTH_INTERVAL); 1173 IEEE80211_RETRY_AUTH_INTERVAL);
@@ -1664,6 +1681,8 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)
1664 ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY; 1681 ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY;
1665 else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP) 1682 else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
1666 ifmgd->auth_alg = WLAN_AUTH_LEAP; 1683 ifmgd->auth_alg = WLAN_AUTH_LEAP;
1684 else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_FT)
1685 ifmgd->auth_alg = WLAN_AUTH_FT;
1667 else 1686 else
1668 ifmgd->auth_alg = WLAN_AUTH_OPEN; 1687 ifmgd->auth_alg = WLAN_AUTH_OPEN;
1669 ifmgd->auth_transaction = -1; 1688 ifmgd->auth_transaction = -1;
@@ -1687,7 +1706,8 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
1687 u16 capa_val = WLAN_CAPABILITY_ESS; 1706 u16 capa_val = WLAN_CAPABILITY_ESS;
1688 struct ieee80211_channel *chan = local->oper_channel; 1707 struct ieee80211_channel *chan = local->oper_channel;
1689 1708
1690 if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL | 1709 if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) &&
1710 ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL |
1691 IEEE80211_STA_AUTO_BSSID_SEL | 1711 IEEE80211_STA_AUTO_BSSID_SEL |
1692 IEEE80211_STA_AUTO_CHANNEL_SEL)) { 1712 IEEE80211_STA_AUTO_CHANNEL_SEL)) {
1693 capa_mask |= WLAN_CAPABILITY_PRIVACY; 1713 capa_mask |= WLAN_CAPABILITY_PRIVACY;
@@ -1884,7 +1904,11 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
1884 ieee80211_set_disassoc(sdata, true, true, 1904 ieee80211_set_disassoc(sdata, true, true,
1885 WLAN_REASON_DEAUTH_LEAVING); 1905 WLAN_REASON_DEAUTH_LEAVING);
1886 1906
1887 set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request); 1907 if (!(ifmgd->flags & IEEE80211_STA_EXT_SME) ||
1908 ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
1909 set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
1910 else if (ifmgd->flags & IEEE80211_STA_EXT_SME)
1911 set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
1888 queue_work(local->hw.workqueue, &ifmgd->work); 1912 queue_work(local->hw.workqueue, &ifmgd->work);
1889 } 1913 }
1890} 1914}
@@ -1953,7 +1977,8 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
1953 return ieee80211_sta_commit(sdata); 1977 return ieee80211_sta_commit(sdata);
1954} 1978}
1955 1979
1956int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) 1980int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
1981 const char *ie, size_t len)
1957{ 1982{
1958 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; 1983 struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
1959 1984
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index e55d2834764c..ce21d66b1023 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -137,6 +137,7 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
137 if (ret) 137 if (ret)
138 return ret; 138 return ret;
139 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; 139 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
140 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
140 ieee80211_sta_req_auth(sdata); 141 ieee80211_sta_req_auth(sdata);
141 return 0; 142 return 0;
142 } 143 }
@@ -224,6 +225,7 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
224 if (ret) 225 if (ret)
225 return ret; 226 return ret;
226 227
228 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
227 ieee80211_sta_req_auth(sdata); 229 ieee80211_sta_req_auth(sdata);
228 return 0; 230 return 0;
229 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) 231 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
@@ -287,6 +289,7 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
287 ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data); 289 ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
288 if (ret) 290 if (ret)
289 return ret; 291 return ret;
292 sdata->u.mgd.flags &= ~IEEE80211_STA_EXT_SME;
290 ieee80211_sta_req_auth(sdata); 293 ieee80211_sta_req_auth(sdata);
291 return 0; 294 return 0;
292 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { 295 } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c034c2418cb3..9e1318d1d4bb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -111,6 +111,11 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = {
111 .len = IEEE80211_MAX_DATA_LEN }, 111 .len = IEEE80211_MAX_DATA_LEN },
112 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED }, 112 [NL80211_ATTR_SCAN_FREQUENCIES] = { .type = NLA_NESTED },
113 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED }, 113 [NL80211_ATTR_SCAN_SSIDS] = { .type = NLA_NESTED },
114
115 [NL80211_ATTR_SSID] = { .type = NLA_BINARY,
116 .len = IEEE80211_MAX_SSID_LEN },
117 [NL80211_ATTR_AUTH_TYPE] = { .type = NLA_U32 },
118 [NL80211_ATTR_REASON_CODE] = { .type = NLA_U16 },
114}; 119};
115 120
116/* message building helper */ 121/* message building helper */
@@ -265,6 +270,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
265 CMD(set_mesh_params, SET_MESH_PARAMS); 270 CMD(set_mesh_params, SET_MESH_PARAMS);
266 CMD(change_bss, SET_BSS); 271 CMD(change_bss, SET_BSS);
267 CMD(set_mgmt_extra_ie, SET_MGMT_EXTRA_IE); 272 CMD(set_mgmt_extra_ie, SET_MGMT_EXTRA_IE);
273 CMD(auth, AUTHENTICATE);
274 CMD(assoc, ASSOCIATE);
275 CMD(deauth, DEAUTHENTICATE);
276 CMD(disassoc, DISASSOCIATE);
268 277
269#undef CMD 278#undef CMD
270 nla_nest_end(msg, nl_cmds); 279 nla_nest_end(msg, nl_cmds);
@@ -2646,6 +2655,228 @@ static int nl80211_dump_scan(struct sk_buff *skb,
2646 return err; 2655 return err;
2647} 2656}
2648 2657
2658static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
2659{
2660 struct cfg80211_registered_device *drv;
2661 struct net_device *dev;
2662 struct cfg80211_auth_request req;
2663 struct wiphy *wiphy;
2664 int err;
2665
2666 rtnl_lock();
2667
2668 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2669 if (err)
2670 goto unlock_rtnl;
2671
2672 if (!drv->ops->auth) {
2673 err = -EOPNOTSUPP;
2674 goto out;
2675 }
2676
2677 if (!info->attrs[NL80211_ATTR_MAC]) {
2678 err = -EINVAL;
2679 goto out;
2680 }
2681
2682 wiphy = &drv->wiphy;
2683 memset(&req, 0, sizeof(req));
2684
2685 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2686
2687 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2688 req.chan = ieee80211_get_channel(
2689 wiphy,
2690 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
2691 if (!req.chan) {
2692 err = -EINVAL;
2693 goto out;
2694 }
2695 }
2696
2697 if (info->attrs[NL80211_ATTR_SSID]) {
2698 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2699 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
2700 }
2701
2702 if (info->attrs[NL80211_ATTR_IE]) {
2703 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2704 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2705 }
2706
2707 if (info->attrs[NL80211_ATTR_AUTH_TYPE]) {
2708 req.auth_type =
2709 nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]);
2710 }
2711
2712 err = drv->ops->auth(&drv->wiphy, dev, &req);
2713
2714out:
2715 cfg80211_put_dev(drv);
2716 dev_put(dev);
2717unlock_rtnl:
2718 rtnl_unlock();
2719 return err;
2720}
2721
2722static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
2723{
2724 struct cfg80211_registered_device *drv;
2725 struct net_device *dev;
2726 struct cfg80211_assoc_request req;
2727 struct wiphy *wiphy;
2728 int err;
2729
2730 rtnl_lock();
2731
2732 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2733 if (err)
2734 goto unlock_rtnl;
2735
2736 if (!drv->ops->assoc) {
2737 err = -EOPNOTSUPP;
2738 goto out;
2739 }
2740
2741 if (!info->attrs[NL80211_ATTR_MAC] ||
2742 !info->attrs[NL80211_ATTR_SSID]) {
2743 err = -EINVAL;
2744 goto out;
2745 }
2746
2747 wiphy = &drv->wiphy;
2748 memset(&req, 0, sizeof(req));
2749
2750 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2751
2752 if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
2753 req.chan = ieee80211_get_channel(
2754 wiphy,
2755 nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]));
2756 if (!req.chan) {
2757 err = -EINVAL;
2758 goto out;
2759 }
2760 }
2761
2762 if (nla_len(info->attrs[NL80211_ATTR_SSID]) > IEEE80211_MAX_SSID_LEN) {
2763 err = -EINVAL;
2764 goto out;
2765 }
2766 req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
2767 req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
2768
2769 if (info->attrs[NL80211_ATTR_IE]) {
2770 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2771 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2772 }
2773
2774 err = drv->ops->assoc(&drv->wiphy, dev, &req);
2775
2776out:
2777 cfg80211_put_dev(drv);
2778 dev_put(dev);
2779unlock_rtnl:
2780 rtnl_unlock();
2781 return err;
2782}
2783
2784static int nl80211_deauthenticate(struct sk_buff *skb, struct genl_info *info)
2785{
2786 struct cfg80211_registered_device *drv;
2787 struct net_device *dev;
2788 struct cfg80211_deauth_request req;
2789 struct wiphy *wiphy;
2790 int err;
2791
2792 rtnl_lock();
2793
2794 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2795 if (err)
2796 goto unlock_rtnl;
2797
2798 if (!drv->ops->deauth) {
2799 err = -EOPNOTSUPP;
2800 goto out;
2801 }
2802
2803 if (!info->attrs[NL80211_ATTR_MAC]) {
2804 err = -EINVAL;
2805 goto out;
2806 }
2807
2808 wiphy = &drv->wiphy;
2809 memset(&req, 0, sizeof(req));
2810
2811 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2812
2813 if (info->attrs[NL80211_ATTR_REASON_CODE])
2814 req.reason_code =
2815 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2816
2817 if (info->attrs[NL80211_ATTR_IE]) {
2818 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2819 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2820 }
2821
2822 err = drv->ops->deauth(&drv->wiphy, dev, &req);
2823
2824out:
2825 cfg80211_put_dev(drv);
2826 dev_put(dev);
2827unlock_rtnl:
2828 rtnl_unlock();
2829 return err;
2830}
2831
2832static int nl80211_disassociate(struct sk_buff *skb, struct genl_info *info)
2833{
2834 struct cfg80211_registered_device *drv;
2835 struct net_device *dev;
2836 struct cfg80211_disassoc_request req;
2837 struct wiphy *wiphy;
2838 int err;
2839
2840 rtnl_lock();
2841
2842 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
2843 if (err)
2844 goto unlock_rtnl;
2845
2846 if (!drv->ops->disassoc) {
2847 err = -EOPNOTSUPP;
2848 goto out;
2849 }
2850
2851 if (!info->attrs[NL80211_ATTR_MAC]) {
2852 err = -EINVAL;
2853 goto out;
2854 }
2855
2856 wiphy = &drv->wiphy;
2857 memset(&req, 0, sizeof(req));
2858
2859 req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
2860
2861 if (info->attrs[NL80211_ATTR_REASON_CODE])
2862 req.reason_code =
2863 nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]);
2864
2865 if (info->attrs[NL80211_ATTR_IE]) {
2866 req.ie = nla_data(info->attrs[NL80211_ATTR_IE]);
2867 req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
2868 }
2869
2870 err = drv->ops->disassoc(&drv->wiphy, dev, &req);
2871
2872out:
2873 cfg80211_put_dev(drv);
2874 dev_put(dev);
2875unlock_rtnl:
2876 rtnl_unlock();
2877 return err;
2878}
2879
2649static struct genl_ops nl80211_ops[] = { 2880static struct genl_ops nl80211_ops[] = {
2650 { 2881 {
2651 .cmd = NL80211_CMD_GET_WIPHY, 2882 .cmd = NL80211_CMD_GET_WIPHY,
@@ -2829,6 +3060,30 @@ static struct genl_ops nl80211_ops[] = {
2829 .policy = nl80211_policy, 3060 .policy = nl80211_policy,
2830 .dumpit = nl80211_dump_scan, 3061 .dumpit = nl80211_dump_scan,
2831 }, 3062 },
3063 {
3064 .cmd = NL80211_CMD_AUTHENTICATE,
3065 .doit = nl80211_authenticate,
3066 .policy = nl80211_policy,
3067 .flags = GENL_ADMIN_PERM,
3068 },
3069 {
3070 .cmd = NL80211_CMD_ASSOCIATE,
3071 .doit = nl80211_associate,
3072 .policy = nl80211_policy,
3073 .flags = GENL_ADMIN_PERM,
3074 },
3075 {
3076 .cmd = NL80211_CMD_DEAUTHENTICATE,
3077 .doit = nl80211_deauthenticate,
3078 .policy = nl80211_policy,
3079 .flags = GENL_ADMIN_PERM,
3080 },
3081 {
3082 .cmd = NL80211_CMD_DISASSOCIATE,
3083 .doit = nl80211_disassociate,
3084 .policy = nl80211_policy,
3085 .flags = GENL_ADMIN_PERM,
3086 },
2832}; 3087};
2833static struct genl_multicast_group nl80211_mlme_mcgrp = { 3088static struct genl_multicast_group nl80211_mlme_mcgrp = {
2834 .name = "mlme", 3089 .name = "mlme",