diff options
-rw-r--r-- | include/linux/ieee80211.h | 1 | ||||
-rw-r--r-- | include/linux/nl80211.h | 58 | ||||
-rw-r--r-- | include/net/cfg80211.h | 113 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 140 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 7 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 45 | ||||
-rw-r--r-- | net/mac80211/wext.c | 3 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 255 |
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 | */ | ||
1053 | enum 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 | */ | ||
605 | struct 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 | */ | ||
635 | struct 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 | */ | ||
655 | struct 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 | */ | ||
673 | struct 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 | */ |
654 | struct cfg80211_ops { | 758 | struct 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 | ||
1303 | static 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 | |||
1364 | static 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 | |||
1406 | static 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 | |||
1422 | static 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 | |||
1303 | struct cfg80211_ops mac80211_config_ops = { | 1439 | struct 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 | ||
270 | struct ieee80211_if_managed { | 272 | struct 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 | ||
340 | enum ieee80211_ibss_flags { | 345 | enum 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); |
972 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, | 977 | int 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 | ||
975 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); | 980 | void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); |
976 | void ieee80211_scan_failed(struct ieee80211_local *local); | 981 | void 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 | ||
1956 | int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len) | 1980 | int 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 | ||
2658 | static 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 | |||
2714 | out: | ||
2715 | cfg80211_put_dev(drv); | ||
2716 | dev_put(dev); | ||
2717 | unlock_rtnl: | ||
2718 | rtnl_unlock(); | ||
2719 | return err; | ||
2720 | } | ||
2721 | |||
2722 | static 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 | |||
2776 | out: | ||
2777 | cfg80211_put_dev(drv); | ||
2778 | dev_put(dev); | ||
2779 | unlock_rtnl: | ||
2780 | rtnl_unlock(); | ||
2781 | return err; | ||
2782 | } | ||
2783 | |||
2784 | static 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 | |||
2824 | out: | ||
2825 | cfg80211_put_dev(drv); | ||
2826 | dev_put(dev); | ||
2827 | unlock_rtnl: | ||
2828 | rtnl_unlock(); | ||
2829 | return err; | ||
2830 | } | ||
2831 | |||
2832 | static 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 | |||
2872 | out: | ||
2873 | cfg80211_put_dev(drv); | ||
2874 | dev_put(dev); | ||
2875 | unlock_rtnl: | ||
2876 | rtnl_unlock(); | ||
2877 | return err; | ||
2878 | } | ||
2879 | |||
2649 | static struct genl_ops nl80211_ops[] = { | 2880 | static 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 | }; |
2833 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3088 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
2834 | .name = "mlme", | 3089 | .name = "mlme", |