aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/ieee80211.h1
-rw-r--r--include/linux/nl80211.h58
-rw-r--r--include/net/cfg80211.h113
-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
8 files changed, 601 insertions, 21 deletions
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 382387e75b89..4b501b48ce86 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -867,6 +867,7 @@ struct ieee80211_ht_info {
867/* Authentication algorithms */ 867/* Authentication algorithms */
868#define WLAN_AUTH_OPEN 0 868#define WLAN_AUTH_OPEN 0
869#define WLAN_AUTH_SHARED_KEY 1 869#define WLAN_AUTH_SHARED_KEY 1
870#define WLAN_AUTH_FT 2
870#define WLAN_AUTH_LEAP 128 871#define WLAN_AUTH_LEAP 128
871 872
872#define WLAN_AUTH_CHALLENGE_LEN 128 873#define WLAN_AUTH_CHALLENGE_LEN 128
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 5ce68ae8314e..9685eaab40a9 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -161,24 +161,37 @@
161 * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on 161 * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
162 * to (%NL80211_ATTR_REG_ALPHA2). 162 * to (%NL80211_ATTR_REG_ALPHA2).
163 * 163 *
164 * @NL80211_CMD_AUTHENTICATE: authentication notification (on the "mlme" 164 * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
165 * multicast group). This event reports reception of an Authentication 165 * This command is used both as a command (request to authenticate) and
166 * as an event on the "mlme" multicast group indicating completion of the
167 * authentication process.
168 * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
169 * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
170 * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
171 * the SSID (mainly for association, but is included in authentication
172 * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
173 * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
174 * is used to specify the authentication type. %NL80211_ATTR_IE is used to
175 * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
176 * to be added to the frame.
177 * When used as an event, this reports reception of an Authentication
166 * frame in station and IBSS modes when the local MLME processed the 178 * frame in station and IBSS modes when the local MLME processed the
167 * frame, i.e., it was for the local STA and was received in correct 179 * frame, i.e., it was for the local STA and was received in correct
168 * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the 180 * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
169 * MLME SAP interface (kernel providing MLME, userspace SME). The 181 * MLME SAP interface (kernel providing MLME, userspace SME). The
170 * included NL80211_ATTR_FRAME attribute contains the management frame 182 * included NL80211_ATTR_FRAME attribute contains the management frame
171 * (including both the header and frame body, but not FCS). 183 * (including both the header and frame body, but not FCS).
172 * @NL80211_CMD_ASSOCIATE: association notification; like 184 * @NL80211_CMD_ASSOCIATE: association request and notification; like
173 * NL80211_CMD_AUTHENTICATE but for Association Response and Reassociation 185 * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
174 * Response frames (similar to MLME-ASSOCIATE.confirm or 186 * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
175 * MLME-REASSOCIATE.confirm primitives). 187 * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
176 * @NL80211_CMD_DEAUTHENTICATE: deauthentication notification; like 188 * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
177 * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to 189 * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
178 * MLME-DEAUTHENTICATE.indication primitive). 190 * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
179 * @NL80211_CMD_DISASSOCIATE: disassociation notification; like 191 * primitives).
192 * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
180 * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to 193 * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
181 * MLME-DISASSOCIATE.indication primitive). 194 * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
182 * 195 *
183 * @NL80211_CMD_MAX: highest used command number 196 * @NL80211_CMD_MAX: highest used command number
184 * @__NL80211_CMD_AFTER_LAST: internal use 197 * @__NL80211_CMD_AFTER_LAST: internal use
@@ -383,6 +396,11 @@ enum nl80211_commands {
383 * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header 396 * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
384 * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and 397 * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
385 * NL80211_CMD_ASSOCIATE events 398 * NL80211_CMD_ASSOCIATE events
399 * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
400 * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
401 * represented as a u32
402 * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
403 * %NL80211_CMD_DISASSOCIATE, u16
386 * 404 *
387 * @NL80211_ATTR_MAX: highest attribute number currently defined 405 * @NL80211_ATTR_MAX: highest attribute number currently defined
388 * @__NL80211_ATTR_AFTER_LAST: internal use 406 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -464,6 +482,9 @@ enum nl80211_attrs {
464 NL80211_ATTR_SUPPORTED_COMMANDS, 482 NL80211_ATTR_SUPPORTED_COMMANDS,
465 483
466 NL80211_ATTR_FRAME, 484 NL80211_ATTR_FRAME,
485 NL80211_ATTR_SSID,
486 NL80211_ATTR_AUTH_TYPE,
487 NL80211_ATTR_REASON_CODE,
467 488
468 /* add attributes here, update the policy in nl80211.c */ 489 /* add attributes here, update the policy in nl80211.c */
469 490
@@ -485,6 +506,9 @@ enum nl80211_attrs {
485#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR 506#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
486#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE 507#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
487#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME 508#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
509#define NL80211_ATTR_SSID NL80211_ATTR_SSID
510#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
511#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
488 512
489#define NL80211_MAX_SUPP_RATES 32 513#define NL80211_MAX_SUPP_RATES 32
490#define NL80211_MAX_SUPP_REG_RULES 32 514#define NL80211_MAX_SUPP_REG_RULES 32
@@ -1018,4 +1042,18 @@ enum nl80211_bss {
1018 NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1 1042 NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
1019}; 1043};
1020 1044
1045/**
1046 * enum nl80211_auth_type - AuthenticationType
1047 *
1048 * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
1049 * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
1050 * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
1051 * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
1052 */
1053enum nl80211_auth_type {
1054 NL80211_AUTHTYPE_OPEN_SYSTEM,
1055 NL80211_AUTHTYPE_SHARED_KEY,
1056 NL80211_AUTHTYPE_FT,
1057 NL80211_AUTHTYPE_NETWORK_EAP,
1058};
1021#endif /* __LINUX_NL80211_H */ 1059#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ad44016021b1..0da9a55881a1 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -579,6 +579,105 @@ struct cfg80211_bss {
579}; 579};
580 580
581/** 581/**
582 * struct cfg80211_auth_request - Authentication request data
583 *
584 * This structure provides information needed to complete IEEE 802.11
585 * authentication.
586 * NOTE: This structure will likely change when more code from mac80211 is
587 * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
588 * Before using this in a driver that does not use mac80211, it would be better
589 * to check the status of that work and better yet, volunteer to work on it.
590 *
591 * @chan: The channel to use or %NULL if not specified (auto-select based on
592 * scan results)
593 * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case);
594 * this field is required to be present; if the driver wants to help with
595 * BSS selection, it should use (yet to be added) MLME event to allow user
596 * space SME to be notified of roaming candidate, so that the SME can then
597 * use the authentication request with the recommended BSSID and whatever
598 * other data may be needed for authentication/association
599 * @ssid: SSID or %NULL if not yet available
600 * @ssid_len: Length of ssid in octets
601 * @auth_type: Authentication type (algorithm)
602 * @ie: Extra IEs to add to Authentication frame or %NULL
603 * @ie_len: Length of ie buffer in octets
604 */
605struct cfg80211_auth_request {
606 struct ieee80211_channel *chan;
607 u8 *peer_addr;
608 const u8 *ssid;
609 size_t ssid_len;
610 enum nl80211_auth_type auth_type;
611 const u8 *ie;
612 size_t ie_len;
613};
614
615/**
616 * struct cfg80211_assoc_request - (Re)Association request data
617 *
618 * This structure provides information needed to complete IEEE 802.11
619 * (re)association.
620 * NOTE: This structure will likely change when more code from mac80211 is
621 * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too.
622 * Before using this in a driver that does not use mac80211, it would be better
623 * to check the status of that work and better yet, volunteer to work on it.
624 *
625 * @chan: The channel to use or %NULL if not specified (auto-select based on
626 * scan results)
627 * @peer_addr: The address of the peer STA (AP BSSID); this field is required
628 * to be present and the STA must be in State 2 (authenticated) with the
629 * peer STA
630 * @ssid: SSID
631 * @ssid_len: Length of ssid in octets
632 * @ie: Extra IEs to add to (Re)Association Request frame or %NULL
633 * @ie_len: Length of ie buffer in octets
634 */
635struct cfg80211_assoc_request {
636 struct ieee80211_channel *chan;
637 u8 *peer_addr;
638 const u8 *ssid;
639 size_t ssid_len;
640 const u8 *ie;
641 size_t ie_len;
642};
643
644/**
645 * struct cfg80211_deauth_request - Deauthentication request data
646 *
647 * This structure provides information needed to complete IEEE 802.11
648 * deauthentication.
649 *
650 * @peer_addr: The address of the peer STA (AP BSSID); this field is required
651 * to be present and the STA must be authenticated with the peer STA
652 * @ie: Extra IEs to add to Deauthentication frame or %NULL
653 * @ie_len: Length of ie buffer in octets
654 */
655struct cfg80211_deauth_request {
656 u8 *peer_addr;
657 u16 reason_code;
658 const u8 *ie;
659 size_t ie_len;
660};
661
662/**
663 * struct cfg80211_disassoc_request - Disassociation request data
664 *
665 * This structure provides information needed to complete IEEE 802.11
666 * disassocation.
667 *
668 * @peer_addr: The address of the peer STA (AP BSSID); this field is required
669 * to be present and the STA must be associated with the peer STA
670 * @ie: Extra IEs to add to Disassociation frame or %NULL
671 * @ie_len: Length of ie buffer in octets
672 */
673struct cfg80211_disassoc_request {
674 u8 *peer_addr;
675 u16 reason_code;
676 const u8 *ie;
677 size_t ie_len;
678};
679
680/**
582 * struct cfg80211_ops - backend description for wireless configuration 681 * struct cfg80211_ops - backend description for wireless configuration
583 * 682 *
584 * This struct is registered by fullmac card drivers and/or wireless stacks 683 * This struct is registered by fullmac card drivers and/or wireless stacks
@@ -650,6 +749,11 @@ struct cfg80211_bss {
650 * the driver, and will be valid until passed to cfg80211_scan_done(). 749 * the driver, and will be valid until passed to cfg80211_scan_done().
651 * For scan results, call cfg80211_inform_bss(); you can call this outside 750 * For scan results, call cfg80211_inform_bss(); you can call this outside
652 * the scan/scan_done bracket too. 751 * the scan/scan_done bracket too.
752 *
753 * @auth: Request to authenticate with the specified peer
754 * @assoc: Request to (re)associate with the specified peer
755 * @deauth: Request to deauthenticate from the specified peer
756 * @disassoc: Request to disassociate from the specified peer
653 */ 757 */
654struct cfg80211_ops { 758struct cfg80211_ops {
655 int (*suspend)(struct wiphy *wiphy); 759 int (*suspend)(struct wiphy *wiphy);
@@ -730,6 +834,15 @@ struct cfg80211_ops {
730 834
731 int (*scan)(struct wiphy *wiphy, struct net_device *dev, 835 int (*scan)(struct wiphy *wiphy, struct net_device *dev,
732 struct cfg80211_scan_request *request); 836 struct cfg80211_scan_request *request);
837
838 int (*auth)(struct wiphy *wiphy, struct net_device *dev,
839 struct cfg80211_auth_request *req);
840 int (*assoc)(struct wiphy *wiphy, struct net_device *dev,
841 struct cfg80211_assoc_request *req);
842 int (*deauth)(struct wiphy *wiphy, struct net_device *dev,
843 struct cfg80211_deauth_request *req);
844 int (*disassoc)(struct wiphy *wiphy, struct net_device *dev,
845 struct cfg80211_disassoc_request *req);
733}; 846};
734 847
735/* temporary wext handlers */ 848/* temporary wext handlers */
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",