aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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",