diff options
-rw-r--r-- | include/linux/nl80211.h | 80 | ||||
-rw-r--r-- | include/net/cfg80211.h | 135 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/wireless/Makefile | 2 | ||||
-rw-r--r-- | net/wireless/core.c | 16 | ||||
-rw-r--r-- | net/wireless/core.h | 7 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 368 | ||||
-rw-r--r-- | net/wireless/nl80211.h | 13 | ||||
-rw-r--r-- | net/wireless/sme.c | 224 |
9 files changed, 829 insertions, 18 deletions
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 651b18839088..b34c17f52f3e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h | |||
@@ -246,6 +246,22 @@ | |||
246 | * to identify the device, and the TESTDATA blob attribute to pass through | 246 | * to identify the device, and the TESTDATA blob attribute to pass through |
247 | * to the driver. | 247 | * to the driver. |
248 | * | 248 | * |
249 | * @NL80211_CMD_CONNECT: connection request and notification; this command | ||
250 | * requests to connect to a specified network but without separating | ||
251 | * auth and assoc steps. For this, you need to specify the SSID in a | ||
252 | * %NL80211_ATTR_SSID attribute, and can optionally specify the association | ||
253 | * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC, | ||
254 | * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT. | ||
255 | * It is also sent as an event, with the BSSID and response IEs when the | ||
256 | * connection is established or failed to be established. This can be | ||
257 | * determined by the STATUS_CODE attribute. | ||
258 | * @NL80211_CMD_ROAM: request that the card roam (currently not implemented), | ||
259 | * sent as an event when the card/driver roamed by itself. | ||
260 | * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify | ||
261 | * userspace that a connection was dropped by the AP or due to other | ||
262 | * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and | ||
263 | * %NL80211_ATTR_REASON_CODE attributes are used. | ||
264 | * | ||
249 | * @NL80211_CMD_MAX: highest used command number | 265 | * @NL80211_CMD_MAX: highest used command number |
250 | * @__NL80211_CMD_AFTER_LAST: internal use | 266 | * @__NL80211_CMD_AFTER_LAST: internal use |
251 | */ | 267 | */ |
@@ -316,6 +332,10 @@ enum nl80211_commands { | |||
316 | 332 | ||
317 | NL80211_CMD_TESTMODE, | 333 | NL80211_CMD_TESTMODE, |
318 | 334 | ||
335 | NL80211_CMD_CONNECT, | ||
336 | NL80211_CMD_ROAM, | ||
337 | NL80211_CMD_DISCONNECT, | ||
338 | |||
319 | /* add new commands above here */ | 339 | /* add new commands above here */ |
320 | 340 | ||
321 | /* used to define NL80211_CMD_MAX below */ | 341 | /* used to define NL80211_CMD_MAX below */ |
@@ -520,6 +540,30 @@ enum nl80211_commands { | |||
520 | * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. | 540 | * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. |
521 | * We recommend using nested, driver-specific attributes within this. | 541 | * We recommend using nested, driver-specific attributes within this. |
522 | * | 542 | * |
543 | * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT | ||
544 | * event was due to the AP disconnecting the station, and not due to | ||
545 | * a local disconnect request. | ||
546 | * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT | ||
547 | * event (u16) | ||
548 | * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating | ||
549 | * that protected APs should be used. | ||
550 | * | ||
551 | * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to | ||
552 | * indicate which unicast key ciphers will be used with the connection | ||
553 | * (an array of u32). | ||
554 | * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate | ||
555 | * which group key cipher will be used with the connection (a u32). | ||
556 | * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate | ||
557 | * which WPA version(s) the AP we want to associate with is using | ||
558 | * (a u32 with flags from &enum nl80211_wpa_versions). | ||
559 | * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate | ||
560 | * which key management algorithm(s) to use (an array of u32). | ||
561 | * | ||
562 | * @NL80211_ATTR_REQ_IE: (Re)association request information elements as | ||
563 | * sent out by the card, for ROAM and successful CONNECT events. | ||
564 | * @NL80211_ATTR_RESP_IE: (Re)association response information elements as | ||
565 | * sent by peer, for ROAM and successful CONNECT events. | ||
566 | * | ||
523 | * @NL80211_ATTR_MAX: highest attribute number currently defined | 567 | * @NL80211_ATTR_MAX: highest attribute number currently defined |
524 | * @__NL80211_ATTR_AFTER_LAST: internal use | 568 | * @__NL80211_ATTR_AFTER_LAST: internal use |
525 | */ | 569 | */ |
@@ -630,6 +674,19 @@ enum nl80211_attrs { | |||
630 | 674 | ||
631 | NL80211_ATTR_TESTDATA, | 675 | NL80211_ATTR_TESTDATA, |
632 | 676 | ||
677 | NL80211_ATTR_PRIVACY, | ||
678 | |||
679 | NL80211_ATTR_DISCONNECTED_BY_AP, | ||
680 | NL80211_ATTR_STATUS_CODE, | ||
681 | |||
682 | NL80211_ATTR_CIPHER_SUITES_PAIRWISE, | ||
683 | NL80211_ATTR_CIPHER_SUITE_GROUP, | ||
684 | NL80211_ATTR_WPA_VERSIONS, | ||
685 | NL80211_ATTR_AKM_SUITES, | ||
686 | |||
687 | NL80211_ATTR_REQ_IE, | ||
688 | NL80211_ATTR_RESP_IE, | ||
689 | |||
633 | /* add attributes here, update the policy in nl80211.c */ | 690 | /* add attributes here, update the policy in nl80211.c */ |
634 | 691 | ||
635 | __NL80211_ATTR_AFTER_LAST, | 692 | __NL80211_ATTR_AFTER_LAST, |
@@ -640,6 +697,7 @@ enum nl80211_attrs { | |||
640 | * Allow user space programs to use #ifdef on new attributes by defining them | 697 | * Allow user space programs to use #ifdef on new attributes by defining them |
641 | * here | 698 | * here |
642 | */ | 699 | */ |
700 | #define NL80211_CMD_CONNECT NL80211_CMD_CONNECT | ||
643 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY | 701 | #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY |
644 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES | 702 | #define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES |
645 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS | 703 | #define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS |
@@ -653,6 +711,10 @@ enum nl80211_attrs { | |||
653 | #define NL80211_ATTR_SSID NL80211_ATTR_SSID | 711 | #define NL80211_ATTR_SSID NL80211_ATTR_SSID |
654 | #define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE | 712 | #define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE |
655 | #define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE | 713 | #define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE |
714 | #define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE | ||
715 | #define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP | ||
716 | #define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS | ||
717 | #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES | ||
656 | 718 | ||
657 | #define NL80211_MAX_SUPP_RATES 32 | 719 | #define NL80211_MAX_SUPP_RATES 32 |
658 | #define NL80211_MAX_SUPP_REG_RULES 32 | 720 | #define NL80211_MAX_SUPP_REG_RULES 32 |
@@ -661,6 +723,9 @@ enum nl80211_attrs { | |||
661 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 | 723 | #define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24 |
662 | #define NL80211_HT_CAPABILITY_LEN 26 | 724 | #define NL80211_HT_CAPABILITY_LEN 26 |
663 | 725 | ||
726 | #define NL80211_MAX_NR_CIPHER_SUITES 5 | ||
727 | #define NL80211_MAX_NR_AKM_SUITES 2 | ||
728 | |||
664 | /** | 729 | /** |
665 | * enum nl80211_iftype - (virtual) interface types | 730 | * enum nl80211_iftype - (virtual) interface types |
666 | * | 731 | * |
@@ -1205,12 +1270,22 @@ enum nl80211_bss { | |||
1205 | * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) | 1270 | * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only) |
1206 | * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) | 1271 | * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r) |
1207 | * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) | 1272 | * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP) |
1273 | * @__NL80211_AUTHTYPE_NUM: internal | ||
1274 | * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm | ||
1275 | * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by | ||
1276 | * trying multiple times); this is invalid in netlink -- leave out | ||
1277 | * the attribute for this on CONNECT commands. | ||
1208 | */ | 1278 | */ |
1209 | enum nl80211_auth_type { | 1279 | enum nl80211_auth_type { |
1210 | NL80211_AUTHTYPE_OPEN_SYSTEM, | 1280 | NL80211_AUTHTYPE_OPEN_SYSTEM, |
1211 | NL80211_AUTHTYPE_SHARED_KEY, | 1281 | NL80211_AUTHTYPE_SHARED_KEY, |
1212 | NL80211_AUTHTYPE_FT, | 1282 | NL80211_AUTHTYPE_FT, |
1213 | NL80211_AUTHTYPE_NETWORK_EAP, | 1283 | NL80211_AUTHTYPE_NETWORK_EAP, |
1284 | |||
1285 | /* keep last */ | ||
1286 | __NL80211_AUTHTYPE_NUM, | ||
1287 | NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1, | ||
1288 | NL80211_AUTHTYPE_AUTOMATIC | ||
1214 | }; | 1289 | }; |
1215 | 1290 | ||
1216 | /** | 1291 | /** |
@@ -1235,4 +1310,9 @@ enum nl80211_mfp { | |||
1235 | NL80211_MFP_REQUIRED, | 1310 | NL80211_MFP_REQUIRED, |
1236 | }; | 1311 | }; |
1237 | 1312 | ||
1313 | enum nl80211_wpa_versions { | ||
1314 | NL80211_WPA_VERSION_1 = 1 << 0, | ||
1315 | NL80211_WPA_VERSION_2 = 1 << 1, | ||
1316 | }; | ||
1317 | |||
1238 | #endif /* __LINUX_NL80211_H */ | 1318 | #endif /* __LINUX_NL80211_H */ |
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 885d4e5bc4b5..68e11321ed74 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h | |||
@@ -605,6 +605,30 @@ struct cfg80211_bss { | |||
605 | }; | 605 | }; |
606 | 606 | ||
607 | /** | 607 | /** |
608 | * struct cfg80211_crypto_settings - Crypto settings | ||
609 | * @wpa_versions: indicates which, if any, WPA versions are enabled | ||
610 | * (from enum nl80211_wpa_versions) | ||
611 | * @cipher_group: group key cipher suite (or 0 if unset) | ||
612 | * @n_ciphers_pairwise: number of AP supported unicast ciphers | ||
613 | * @ciphers_pairwise: unicast key cipher suites | ||
614 | * @n_akm_suites: number of AKM suites | ||
615 | * @akm_suites: AKM suites | ||
616 | * @control_port: Whether user space controls IEEE 802.1X port, i.e., | ||
617 | * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is | ||
618 | * required to assume that the port is unauthorized until authorized by | ||
619 | * user space. Otherwise, port is marked authorized by default. | ||
620 | */ | ||
621 | struct cfg80211_crypto_settings { | ||
622 | u32 wpa_versions; | ||
623 | u32 cipher_group; | ||
624 | int n_ciphers_pairwise; | ||
625 | u32 ciphers_pairwise[NL80211_MAX_NR_CIPHER_SUITES]; | ||
626 | int n_akm_suites; | ||
627 | u32 akm_suites[NL80211_MAX_NR_AKM_SUITES]; | ||
628 | bool control_port; | ||
629 | }; | ||
630 | |||
631 | /** | ||
608 | * struct cfg80211_auth_request - Authentication request data | 632 | * struct cfg80211_auth_request - Authentication request data |
609 | * | 633 | * |
610 | * This structure provides information needed to complete IEEE 802.11 | 634 | * This structure provides information needed to complete IEEE 802.11 |
@@ -658,10 +682,7 @@ struct cfg80211_auth_request { | |||
658 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL | 682 | * @ie: Extra IEs to add to (Re)Association Request frame or %NULL |
659 | * @ie_len: Length of ie buffer in octets | 683 | * @ie_len: Length of ie buffer in octets |
660 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association | 684 | * @use_mfp: Use management frame protection (IEEE 802.11w) in this association |
661 | * @control_port: Whether user space controls IEEE 802.1X port, i.e., | 685 | * @crypto: crypto settings |
662 | * sets/clears %NL80211_STA_FLAG_AUTHORIZED. If true, the driver is | ||
663 | * required to assume that the port is unauthorized until authorized by | ||
664 | * user space. Otherwise, port is marked authorized by default. | ||
665 | */ | 686 | */ |
666 | struct cfg80211_assoc_request { | 687 | struct cfg80211_assoc_request { |
667 | struct ieee80211_channel *chan; | 688 | struct ieee80211_channel *chan; |
@@ -671,7 +692,7 @@ struct cfg80211_assoc_request { | |||
671 | const u8 *ie; | 692 | const u8 *ie; |
672 | size_t ie_len; | 693 | size_t ie_len; |
673 | bool use_mfp; | 694 | bool use_mfp; |
674 | bool control_port; | 695 | struct cfg80211_crypto_settings crypto; |
675 | }; | 696 | }; |
676 | 697 | ||
677 | /** | 698 | /** |
@@ -738,6 +759,36 @@ struct cfg80211_ibss_params { | |||
738 | }; | 759 | }; |
739 | 760 | ||
740 | /** | 761 | /** |
762 | * struct cfg80211_connect_params - Connection parameters | ||
763 | * | ||
764 | * This structure provides information needed to complete IEEE 802.11 | ||
765 | * authentication and association. | ||
766 | * | ||
767 | * @channel: The channel to use or %NULL if not specified (auto-select based | ||
768 | * on scan results) | ||
769 | * @bssid: The AP BSSID or %NULL if not specified (auto-select based on scan | ||
770 | * results) | ||
771 | * @ssid: SSID | ||
772 | * @ssid_len: Length of ssid in octets | ||
773 | * @auth_type: Authentication type (algorithm) | ||
774 | * @assoc_ie: IEs for association request | ||
775 | * @assoc_ie_len: Length of assoc_ie in octets | ||
776 | * @privacy: indicates whether privacy-enabled APs should be used | ||
777 | * @crypto: crypto settings | ||
778 | */ | ||
779 | struct cfg80211_connect_params { | ||
780 | struct ieee80211_channel *channel; | ||
781 | u8 *bssid; | ||
782 | u8 *ssid; | ||
783 | size_t ssid_len; | ||
784 | enum nl80211_auth_type auth_type; | ||
785 | u8 *ie; | ||
786 | size_t ie_len; | ||
787 | bool privacy; | ||
788 | struct cfg80211_crypto_settings crypto; | ||
789 | }; | ||
790 | |||
791 | /** | ||
741 | * enum wiphy_params_flags - set_wiphy_params bitfield values | 792 | * enum wiphy_params_flags - set_wiphy_params bitfield values |
742 | * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed | 793 | * WIPHY_PARAM_RETRY_SHORT: wiphy->retry_short has changed |
743 | * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed | 794 | * WIPHY_PARAM_RETRY_LONG: wiphy->retry_long has changed |
@@ -841,6 +892,12 @@ enum tx_power_setting { | |||
841 | * @deauth: Request to deauthenticate from the specified peer | 892 | * @deauth: Request to deauthenticate from the specified peer |
842 | * @disassoc: Request to disassociate from the specified peer | 893 | * @disassoc: Request to disassociate from the specified peer |
843 | * | 894 | * |
895 | * @connect: Connect to the ESS with the specified parameters. When connected, | ||
896 | * call cfg80211_connect_result() with status code %WLAN_STATUS_SUCCESS. | ||
897 | * If the connection fails for some reason, call cfg80211_connect_result() | ||
898 | * with the status from the AP. | ||
899 | * @disconnect: Disconnect from the BSS/ESS. | ||
900 | * | ||
844 | * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call | 901 | * @join_ibss: Join the specified IBSS (or create if necessary). Once done, call |
845 | * cfg80211_ibss_joined(), also call that function when changing BSSID due | 902 | * cfg80211_ibss_joined(), also call that function when changing BSSID due |
846 | * to a merge. | 903 | * to a merge. |
@@ -946,6 +1003,11 @@ struct cfg80211_ops { | |||
946 | int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, | 1003 | int (*disassoc)(struct wiphy *wiphy, struct net_device *dev, |
947 | struct cfg80211_disassoc_request *req); | 1004 | struct cfg80211_disassoc_request *req); |
948 | 1005 | ||
1006 | int (*connect)(struct wiphy *wiphy, struct net_device *dev, | ||
1007 | struct cfg80211_connect_params *sme); | ||
1008 | int (*disconnect)(struct wiphy *wiphy, struct net_device *dev, | ||
1009 | u16 reason_code); | ||
1010 | |||
949 | int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, | 1011 | int (*join_ibss)(struct wiphy *wiphy, struct net_device *dev, |
950 | struct cfg80211_ibss_params *params); | 1012 | struct cfg80211_ibss_params *params); |
951 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); | 1013 | int (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev); |
@@ -1174,10 +1236,15 @@ struct wireless_dev { | |||
1174 | struct list_head list; | 1236 | struct list_head list; |
1175 | struct net_device *netdev; | 1237 | struct net_device *netdev; |
1176 | 1238 | ||
1177 | /* currently used for IBSS - might be rearranged in the future */ | 1239 | /* currently used for IBSS and SME - might be rearranged later */ |
1178 | struct cfg80211_bss *current_bss; | 1240 | struct cfg80211_bss *current_bss; |
1179 | u8 ssid[IEEE80211_MAX_SSID_LEN]; | 1241 | u8 ssid[IEEE80211_MAX_SSID_LEN]; |
1180 | u8 ssid_len; | 1242 | u8 ssid_len; |
1243 | enum { | ||
1244 | CFG80211_SME_IDLE, | ||
1245 | CFG80211_SME_CONNECTING, /* ->connect called */ | ||
1246 | CFG80211_SME_CONNECTED, | ||
1247 | } sme_state; | ||
1181 | 1248 | ||
1182 | #ifdef CONFIG_WIRELESS_EXT | 1249 | #ifdef CONFIG_WIRELESS_EXT |
1183 | /* wext data */ | 1250 | /* wext data */ |
@@ -1788,4 +1855,60 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp); | |||
1788 | #define CFG80211_TESTMODE_CMD(cmd) | 1855 | #define CFG80211_TESTMODE_CMD(cmd) |
1789 | #endif | 1856 | #endif |
1790 | 1857 | ||
1858 | /** | ||
1859 | * cfg80211_connect_result - notify cfg80211 of connection result | ||
1860 | * | ||
1861 | * @dev: network device | ||
1862 | * @bssid: the BSSID of the AP | ||
1863 | * @req_ie: association request IEs (maybe be %NULL) | ||
1864 | * @req_ie_len: association request IEs length | ||
1865 | * @resp_ie: association response IEs (may be %NULL) | ||
1866 | * @resp_ie_len: assoc response IEs length | ||
1867 | * @status: status code, 0 for successful connection, use | ||
1868 | * %WLAN_STATUS_UNSPECIFIED_FAILURE if your device cannot give you | ||
1869 | * the real status code for failures. | ||
1870 | * @gfp: allocation flags | ||
1871 | * | ||
1872 | * It should be called by the underlying driver whenever connect() has | ||
1873 | * succeeded. | ||
1874 | */ | ||
1875 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
1876 | const u8 *req_ie, size_t req_ie_len, | ||
1877 | const u8 *resp_ie, size_t resp_ie_len, | ||
1878 | u16 status, gfp_t gfp); | ||
1879 | |||
1880 | /** | ||
1881 | * cfg80211_roamed - notify cfg80211 of roaming | ||
1882 | * | ||
1883 | * @dev: network device | ||
1884 | * @bssid: the BSSID of the new AP | ||
1885 | * @req_ie: association request IEs (maybe be %NULL) | ||
1886 | * @req_ie_len: association request IEs length | ||
1887 | * @resp_ie: association response IEs (may be %NULL) | ||
1888 | * @resp_ie_len: assoc response IEs length | ||
1889 | * @gfp: allocation flags | ||
1890 | * | ||
1891 | * It should be called by the underlying driver whenever it roamed | ||
1892 | * from one AP to another while connected. | ||
1893 | */ | ||
1894 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | ||
1895 | const u8 *req_ie, size_t req_ie_len, | ||
1896 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); | ||
1897 | |||
1898 | /** | ||
1899 | * cfg80211_disconnected - notify cfg80211 that connection was dropped | ||
1900 | * | ||
1901 | * @dev: network device | ||
1902 | * @ie: information elements of the deauth/disassoc frame (may be %NULL) | ||
1903 | * @ie_len: length of IEs | ||
1904 | * @reason: reason code for the disconnection, set it to 0 if unknown | ||
1905 | * @gfp: allocation flags | ||
1906 | * | ||
1907 | * After it calls this function, the driver should enter an idle state | ||
1908 | * and not try to connect to any AP any more. | ||
1909 | */ | ||
1910 | void cfg80211_disconnected(struct net_device *dev, u16 reason, | ||
1911 | u8 *ie, size_t ie_len, gfp_t gfp); | ||
1912 | |||
1913 | |||
1791 | #endif /* __NET_CFG80211_H */ | 1914 | #endif /* __NET_CFG80211_H */ |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c34c1a41019a..03de4024597a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1262,7 +1262,7 @@ static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev, | |||
1262 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; | 1262 | sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED; |
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | if (req->control_port) | 1265 | if (req->crypto.control_port) |
1266 | sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; | 1266 | sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT; |
1267 | else | 1267 | else |
1268 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; | 1268 | sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT; |
diff --git a/net/wireless/Makefile b/net/wireless/Makefile index f78c4832a9ca..750c08e31b10 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile | |||
@@ -5,7 +5,7 @@ obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o | |||
5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o | 5 | obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o |
6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o | 6 | obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o |
7 | 7 | ||
8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o | 8 | cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o |
9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o | 9 | cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o |
10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o | 10 | cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o |
11 | 11 | ||
diff --git a/net/wireless/core.c b/net/wireless/core.c index d41b7412b212..314e00f70e3b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -546,6 +546,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
546 | "symlink to netdev!\n"); | 546 | "symlink to netdev!\n"); |
547 | } | 547 | } |
548 | wdev->netdev = dev; | 548 | wdev->netdev = dev; |
549 | wdev->sme_state = CFG80211_SME_IDLE; | ||
549 | #ifdef CONFIG_WIRELESS_EXT | 550 | #ifdef CONFIG_WIRELESS_EXT |
550 | wdev->wext.default_key = -1; | 551 | wdev->wext.default_key = -1; |
551 | wdev->wext.default_mgmt_key = -1; | 552 | wdev->wext.default_mgmt_key = -1; |
@@ -553,11 +554,20 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
553 | mutex_unlock(&rdev->devlist_mtx); | 554 | mutex_unlock(&rdev->devlist_mtx); |
554 | break; | 555 | break; |
555 | case NETDEV_GOING_DOWN: | 556 | case NETDEV_GOING_DOWN: |
556 | if (wdev->iftype != NL80211_IFTYPE_ADHOC) | ||
557 | break; | ||
558 | if (!wdev->ssid_len) | 557 | if (!wdev->ssid_len) |
559 | break; | 558 | break; |
560 | cfg80211_leave_ibss(rdev, dev, true); | 559 | |
560 | switch (wdev->iftype) { | ||
561 | case NL80211_IFTYPE_ADHOC: | ||
562 | cfg80211_leave_ibss(rdev, dev, true); | ||
563 | break; | ||
564 | case NL80211_IFTYPE_STATION: | ||
565 | cfg80211_disconnect(rdev, dev, | ||
566 | WLAN_REASON_DEAUTH_LEAVING); | ||
567 | break; | ||
568 | default: | ||
569 | break; | ||
570 | } | ||
561 | break; | 571 | break; |
562 | case NETDEV_UP: | 572 | case NETDEV_UP: |
563 | #ifdef CONFIG_WIRELESS_EXT | 573 | #ifdef CONFIG_WIRELESS_EXT |
diff --git a/net/wireless/core.h b/net/wireless/core.h index bc084b68865c..f93f96f85d2b 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -174,6 +174,13 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | |||
174 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 174 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, |
175 | struct net_device *dev, bool nowext); | 175 | struct net_device *dev, bool nowext); |
176 | 176 | ||
177 | /* SME */ | ||
178 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | ||
179 | struct net_device *dev, | ||
180 | struct cfg80211_connect_params *connect); | ||
181 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
182 | struct net_device *dev, u16 reason); | ||
183 | |||
177 | /* internal helpers */ | 184 | /* internal helpers */ |
178 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, | 185 | int cfg80211_validate_key_settings(struct key_params *params, int key_idx, |
179 | const u8 *mac_addr); | 186 | const u8 *mac_addr); |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index bb8de268a6bf..89dd3793e03c 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -128,6 +128,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | |||
128 | .len = sizeof(struct nl80211_sta_flag_update), | 128 | .len = sizeof(struct nl80211_sta_flag_update), |
129 | }, | 129 | }, |
130 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, | 130 | [NL80211_ATTR_CONTROL_PORT] = { .type = NLA_FLAG }, |
131 | [NL80211_ATTR_PRIVACY] = { .type = NLA_FLAG }, | ||
132 | [NL80211_ATTR_CIPHER_SUITE_GROUP] = { .type = NLA_U32 }, | ||
133 | [NL80211_ATTR_WPA_VERSIONS] = { .type = NLA_U32 }, | ||
131 | }; | 134 | }; |
132 | 135 | ||
133 | /* IE validation */ | 136 | /* IE validation */ |
@@ -347,6 +350,17 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | |||
347 | CMD(join_ibss, JOIN_IBSS); | 350 | CMD(join_ibss, JOIN_IBSS); |
348 | 351 | ||
349 | #undef CMD | 352 | #undef CMD |
353 | |||
354 | if (dev->ops->connect) { | ||
355 | i++; | ||
356 | NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); | ||
357 | } | ||
358 | |||
359 | if (dev->ops->disconnect) { | ||
360 | i++; | ||
361 | NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); | ||
362 | } | ||
363 | |||
350 | nla_nest_end(msg, nl_cmds); | 364 | nla_nest_end(msg, nl_cmds); |
351 | 365 | ||
352 | return genlmsg_end(msg, hdr); | 366 | return genlmsg_end(msg, hdr); |
@@ -3001,12 +3015,31 @@ static int nl80211_dump_scan(struct sk_buff *skb, | |||
3001 | 3015 | ||
3002 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) | 3016 | static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) |
3003 | { | 3017 | { |
3004 | return auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM || | 3018 | return auth_type <= NL80211_AUTHTYPE_MAX; |
3005 | auth_type == NL80211_AUTHTYPE_SHARED_KEY || | 3019 | } |
3006 | auth_type == NL80211_AUTHTYPE_FT || | 3020 | |
3007 | auth_type == NL80211_AUTHTYPE_NETWORK_EAP; | 3021 | static bool nl80211_valid_wpa_versions(u32 wpa_versions) |
3022 | { | ||
3023 | return !(wpa_versions & ~(NL80211_WPA_VERSION_1 | | ||
3024 | NL80211_WPA_VERSION_2)); | ||
3025 | } | ||
3026 | |||
3027 | static bool nl80211_valid_akm_suite(u32 akm) | ||
3028 | { | ||
3029 | return akm == WLAN_AKM_SUITE_8021X || | ||
3030 | akm == WLAN_AKM_SUITE_PSK; | ||
3031 | } | ||
3032 | |||
3033 | static bool nl80211_valid_cipher_suite(u32 cipher) | ||
3034 | { | ||
3035 | return cipher == WLAN_CIPHER_SUITE_WEP40 || | ||
3036 | cipher == WLAN_CIPHER_SUITE_WEP104 || | ||
3037 | cipher == WLAN_CIPHER_SUITE_TKIP || | ||
3038 | cipher == WLAN_CIPHER_SUITE_CCMP || | ||
3039 | cipher == WLAN_CIPHER_SUITE_AES_CMAC; | ||
3008 | } | 3040 | } |
3009 | 3041 | ||
3042 | |||
3010 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) | 3043 | static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) |
3011 | { | 3044 | { |
3012 | struct cfg80211_registered_device *drv; | 3045 | struct cfg80211_registered_device *drv; |
@@ -3086,6 +3119,68 @@ unlock_rtnl: | |||
3086 | return err; | 3119 | return err; |
3087 | } | 3120 | } |
3088 | 3121 | ||
3122 | static int nl80211_crypto_settings(struct genl_info *info, | ||
3123 | struct cfg80211_crypto_settings *settings) | ||
3124 | { | ||
3125 | settings->control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | ||
3126 | |||
3127 | if (info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]) { | ||
3128 | void *data; | ||
3129 | int len, i; | ||
3130 | |||
3131 | data = nla_data(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); | ||
3132 | len = nla_len(info->attrs[NL80211_ATTR_CIPHER_SUITES_PAIRWISE]); | ||
3133 | settings->n_ciphers_pairwise = len / sizeof(u32); | ||
3134 | |||
3135 | if (len % sizeof(u32)) | ||
3136 | return -EINVAL; | ||
3137 | |||
3138 | if (settings->n_ciphers_pairwise > NL80211_MAX_NR_CIPHER_SUITES) | ||
3139 | return -EINVAL; | ||
3140 | |||
3141 | memcpy(settings->ciphers_pairwise, data, len); | ||
3142 | |||
3143 | for (i = 0; i < settings->n_ciphers_pairwise; i++) | ||
3144 | if (!nl80211_valid_cipher_suite( | ||
3145 | settings->ciphers_pairwise[i])) | ||
3146 | return -EINVAL; | ||
3147 | } | ||
3148 | |||
3149 | if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) { | ||
3150 | settings->cipher_group = | ||
3151 | nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]); | ||
3152 | if (!nl80211_valid_cipher_suite(settings->cipher_group)) | ||
3153 | return -EINVAL; | ||
3154 | } | ||
3155 | |||
3156 | if (info->attrs[NL80211_ATTR_WPA_VERSIONS]) { | ||
3157 | settings->wpa_versions = | ||
3158 | nla_get_u32(info->attrs[NL80211_ATTR_WPA_VERSIONS]); | ||
3159 | if (!nl80211_valid_wpa_versions(settings->wpa_versions)) | ||
3160 | return -EINVAL; | ||
3161 | } | ||
3162 | |||
3163 | if (info->attrs[NL80211_ATTR_AKM_SUITES]) { | ||
3164 | void *data; | ||
3165 | int len, i; | ||
3166 | |||
3167 | data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]); | ||
3168 | len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]); | ||
3169 | settings->n_akm_suites = len / sizeof(u32); | ||
3170 | |||
3171 | if (len % sizeof(u32)) | ||
3172 | return -EINVAL; | ||
3173 | |||
3174 | memcpy(settings->akm_suites, data, len); | ||
3175 | |||
3176 | for (i = 0; i < settings->n_ciphers_pairwise; i++) | ||
3177 | if (!nl80211_valid_akm_suite(settings->akm_suites[i])) | ||
3178 | return -EINVAL; | ||
3179 | } | ||
3180 | |||
3181 | return 0; | ||
3182 | } | ||
3183 | |||
3089 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3184 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) |
3090 | { | 3185 | { |
3091 | struct cfg80211_registered_device *drv; | 3186 | struct cfg80211_registered_device *drv; |
@@ -3156,9 +3251,9 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3156 | } | 3251 | } |
3157 | } | 3252 | } |
3158 | 3253 | ||
3159 | req.control_port = info->attrs[NL80211_ATTR_CONTROL_PORT]; | 3254 | err = nl80211_crypto_settings(info, &req.crypto); |
3160 | 3255 | if (!err) | |
3161 | err = drv->ops->assoc(&drv->wiphy, dev, &req); | 3256 | err = drv->ops->assoc(&drv->wiphy, dev, &req); |
3162 | 3257 | ||
3163 | out: | 3258 | out: |
3164 | cfg80211_put_dev(drv); | 3259 | cfg80211_put_dev(drv); |
@@ -3538,6 +3633,130 @@ void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp) | |||
3538 | EXPORT_SYMBOL(cfg80211_testmode_event); | 3633 | EXPORT_SYMBOL(cfg80211_testmode_event); |
3539 | #endif | 3634 | #endif |
3540 | 3635 | ||
3636 | static int nl80211_connect(struct sk_buff *skb, struct genl_info *info) | ||
3637 | { | ||
3638 | struct cfg80211_registered_device *drv; | ||
3639 | struct net_device *dev; | ||
3640 | struct cfg80211_connect_params connect; | ||
3641 | struct wiphy *wiphy; | ||
3642 | int err; | ||
3643 | |||
3644 | memset(&connect, 0, sizeof(connect)); | ||
3645 | |||
3646 | if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) | ||
3647 | return -EINVAL; | ||
3648 | |||
3649 | if (!info->attrs[NL80211_ATTR_SSID] || | ||
3650 | !nla_len(info->attrs[NL80211_ATTR_SSID])) | ||
3651 | return -EINVAL; | ||
3652 | |||
3653 | if (info->attrs[NL80211_ATTR_AUTH_TYPE]) { | ||
3654 | connect.auth_type = | ||
3655 | nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); | ||
3656 | if (!nl80211_valid_auth_type(connect.auth_type)) | ||
3657 | return -EINVAL; | ||
3658 | } else | ||
3659 | connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC; | ||
3660 | |||
3661 | connect.privacy = info->attrs[NL80211_ATTR_PRIVACY]; | ||
3662 | |||
3663 | err = nl80211_crypto_settings(info, &connect.crypto); | ||
3664 | if (err) | ||
3665 | return err; | ||
3666 | rtnl_lock(); | ||
3667 | |||
3668 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3669 | if (err) | ||
3670 | goto unlock_rtnl; | ||
3671 | |||
3672 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3673 | err = -EOPNOTSUPP; | ||
3674 | goto out; | ||
3675 | } | ||
3676 | |||
3677 | if (!netif_running(dev)) { | ||
3678 | err = -ENETDOWN; | ||
3679 | goto out; | ||
3680 | } | ||
3681 | |||
3682 | wiphy = &drv->wiphy; | ||
3683 | |||
3684 | connect.bssid = NULL; | ||
3685 | connect.channel = NULL; | ||
3686 | connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM; | ||
3687 | |||
3688 | if (info->attrs[NL80211_ATTR_MAC]) | ||
3689 | connect.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); | ||
3690 | connect.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); | ||
3691 | connect.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); | ||
3692 | |||
3693 | if (info->attrs[NL80211_ATTR_IE]) { | ||
3694 | connect.ie = nla_data(info->attrs[NL80211_ATTR_IE]); | ||
3695 | connect.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); | ||
3696 | } | ||
3697 | |||
3698 | if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { | ||
3699 | connect.channel = | ||
3700 | ieee80211_get_channel(wiphy, | ||
3701 | nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); | ||
3702 | if (!connect.channel || | ||
3703 | connect.channel->flags & IEEE80211_CHAN_DISABLED) { | ||
3704 | err = -EINVAL; | ||
3705 | goto out; | ||
3706 | } | ||
3707 | } | ||
3708 | |||
3709 | err = cfg80211_connect(drv, dev, &connect); | ||
3710 | |||
3711 | out: | ||
3712 | cfg80211_put_dev(drv); | ||
3713 | dev_put(dev); | ||
3714 | unlock_rtnl: | ||
3715 | rtnl_unlock(); | ||
3716 | return err; | ||
3717 | } | ||
3718 | |||
3719 | static int nl80211_disconnect(struct sk_buff *skb, struct genl_info *info) | ||
3720 | { | ||
3721 | struct cfg80211_registered_device *drv; | ||
3722 | struct net_device *dev; | ||
3723 | int err; | ||
3724 | u16 reason; | ||
3725 | |||
3726 | if (!info->attrs[NL80211_ATTR_REASON_CODE]) | ||
3727 | reason = WLAN_REASON_DEAUTH_LEAVING; | ||
3728 | else | ||
3729 | reason = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); | ||
3730 | |||
3731 | if (reason == 0) | ||
3732 | return -EINVAL; | ||
3733 | |||
3734 | rtnl_lock(); | ||
3735 | |||
3736 | err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); | ||
3737 | if (err) | ||
3738 | goto unlock_rtnl; | ||
3739 | |||
3740 | if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION) { | ||
3741 | err = -EOPNOTSUPP; | ||
3742 | goto out; | ||
3743 | } | ||
3744 | |||
3745 | if (!netif_running(dev)) { | ||
3746 | err = -ENETDOWN; | ||
3747 | goto out; | ||
3748 | } | ||
3749 | |||
3750 | err = cfg80211_disconnect(drv, dev, reason); | ||
3751 | |||
3752 | out: | ||
3753 | cfg80211_put_dev(drv); | ||
3754 | dev_put(dev); | ||
3755 | unlock_rtnl: | ||
3756 | rtnl_unlock(); | ||
3757 | return err; | ||
3758 | } | ||
3759 | |||
3541 | static struct genl_ops nl80211_ops[] = { | 3760 | static struct genl_ops nl80211_ops[] = { |
3542 | { | 3761 | { |
3543 | .cmd = NL80211_CMD_GET_WIPHY, | 3762 | .cmd = NL80211_CMD_GET_WIPHY, |
@@ -3759,6 +3978,18 @@ static struct genl_ops nl80211_ops[] = { | |||
3759 | .flags = GENL_ADMIN_PERM, | 3978 | .flags = GENL_ADMIN_PERM, |
3760 | }, | 3979 | }, |
3761 | #endif | 3980 | #endif |
3981 | { | ||
3982 | .cmd = NL80211_CMD_CONNECT, | ||
3983 | .doit = nl80211_connect, | ||
3984 | .policy = nl80211_policy, | ||
3985 | .flags = GENL_ADMIN_PERM, | ||
3986 | }, | ||
3987 | { | ||
3988 | .cmd = NL80211_CMD_DISCONNECT, | ||
3989 | .doit = nl80211_disconnect, | ||
3990 | .policy = nl80211_policy, | ||
3991 | .flags = GENL_ADMIN_PERM, | ||
3992 | }, | ||
3762 | }; | 3993 | }; |
3763 | static struct genl_multicast_group nl80211_mlme_mcgrp = { | 3994 | static struct genl_multicast_group nl80211_mlme_mcgrp = { |
3764 | .name = "mlme", | 3995 | .name = "mlme", |
@@ -4077,6 +4308,129 @@ void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | |||
4077 | addr, gfp); | 4308 | addr, gfp); |
4078 | } | 4309 | } |
4079 | 4310 | ||
4311 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | ||
4312 | struct net_device *netdev, const u8 *bssid, | ||
4313 | const u8 *req_ie, size_t req_ie_len, | ||
4314 | const u8 *resp_ie, size_t resp_ie_len, | ||
4315 | u16 status, gfp_t gfp) | ||
4316 | { | ||
4317 | struct sk_buff *msg; | ||
4318 | void *hdr; | ||
4319 | |||
4320 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
4321 | if (!msg) | ||
4322 | return; | ||
4323 | |||
4324 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_CONNECT); | ||
4325 | if (!hdr) { | ||
4326 | nlmsg_free(msg); | ||
4327 | return; | ||
4328 | } | ||
4329 | |||
4330 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
4331 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
4332 | if (bssid) | ||
4333 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
4334 | NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status); | ||
4335 | if (req_ie) | ||
4336 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); | ||
4337 | if (resp_ie) | ||
4338 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | ||
4339 | |||
4340 | if (genlmsg_end(msg, hdr) < 0) { | ||
4341 | nlmsg_free(msg); | ||
4342 | return; | ||
4343 | } | ||
4344 | |||
4345 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
4346 | return; | ||
4347 | |||
4348 | nla_put_failure: | ||
4349 | genlmsg_cancel(msg, hdr); | ||
4350 | nlmsg_free(msg); | ||
4351 | |||
4352 | } | ||
4353 | |||
4354 | void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | ||
4355 | struct net_device *netdev, const u8 *bssid, | ||
4356 | const u8 *req_ie, size_t req_ie_len, | ||
4357 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | ||
4358 | { | ||
4359 | struct sk_buff *msg; | ||
4360 | void *hdr; | ||
4361 | |||
4362 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
4363 | if (!msg) | ||
4364 | return; | ||
4365 | |||
4366 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_ROAM); | ||
4367 | if (!hdr) { | ||
4368 | nlmsg_free(msg); | ||
4369 | return; | ||
4370 | } | ||
4371 | |||
4372 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
4373 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
4374 | NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid); | ||
4375 | if (req_ie) | ||
4376 | NLA_PUT(msg, NL80211_ATTR_REQ_IE, req_ie_len, req_ie); | ||
4377 | if (resp_ie) | ||
4378 | NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie); | ||
4379 | |||
4380 | if (genlmsg_end(msg, hdr) < 0) { | ||
4381 | nlmsg_free(msg); | ||
4382 | return; | ||
4383 | } | ||
4384 | |||
4385 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
4386 | return; | ||
4387 | |||
4388 | nla_put_failure: | ||
4389 | genlmsg_cancel(msg, hdr); | ||
4390 | nlmsg_free(msg); | ||
4391 | |||
4392 | } | ||
4393 | |||
4394 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | ||
4395 | struct net_device *netdev, u16 reason, | ||
4396 | u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp) | ||
4397 | { | ||
4398 | struct sk_buff *msg; | ||
4399 | void *hdr; | ||
4400 | |||
4401 | msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||
4402 | if (!msg) | ||
4403 | return; | ||
4404 | |||
4405 | hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DISCONNECT); | ||
4406 | if (!hdr) { | ||
4407 | nlmsg_free(msg); | ||
4408 | return; | ||
4409 | } | ||
4410 | |||
4411 | NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||
4412 | NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||
4413 | if (from_ap && reason) | ||
4414 | NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason); | ||
4415 | if (from_ap) | ||
4416 | NLA_PUT_FLAG(msg, NL80211_ATTR_DISCONNECTED_BY_AP); | ||
4417 | if (ie) | ||
4418 | NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie); | ||
4419 | |||
4420 | if (genlmsg_end(msg, hdr) < 0) { | ||
4421 | nlmsg_free(msg); | ||
4422 | return; | ||
4423 | } | ||
4424 | |||
4425 | genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp); | ||
4426 | return; | ||
4427 | |||
4428 | nla_put_failure: | ||
4429 | genlmsg_cancel(msg, hdr); | ||
4430 | nlmsg_free(msg); | ||
4431 | |||
4432 | } | ||
4433 | |||
4080 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | 4434 | void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, |
4081 | struct net_device *netdev, const u8 *bssid, | 4435 | struct net_device *netdev, const u8 *bssid, |
4082 | gfp_t gfp) | 4436 | gfp_t gfp) |
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 662c216e8d4f..cf3708b48c29 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h | |||
@@ -31,6 +31,19 @@ void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, | |||
31 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, | 31 | void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, |
32 | struct net_device *netdev, | 32 | struct net_device *netdev, |
33 | const u8 *addr, gfp_t gfp); | 33 | const u8 *addr, gfp_t gfp); |
34 | void nl80211_send_connect_result(struct cfg80211_registered_device *rdev, | ||
35 | struct net_device *netdev, const u8 *bssid, | ||
36 | const u8 *req_ie, size_t req_ie_len, | ||
37 | const u8 *resp_ie, size_t resp_ie_len, | ||
38 | u16 status, gfp_t gfp); | ||
39 | void nl80211_send_roamed(struct cfg80211_registered_device *rdev, | ||
40 | struct net_device *netdev, const u8 *bssid, | ||
41 | const u8 *req_ie, size_t req_ie_len, | ||
42 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp); | ||
43 | void nl80211_send_disconnected(struct cfg80211_registered_device *rdev, | ||
44 | struct net_device *netdev, u16 reason, | ||
45 | u8 *ie, size_t ie_len, bool from_ap, gfp_t gfp); | ||
46 | |||
34 | void | 47 | void |
35 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, | 48 | nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, |
36 | struct net_device *netdev, const u8 *addr, | 49 | struct net_device *netdev, const u8 *addr, |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c new file mode 100644 index 000000000000..fc117031d0bb --- /dev/null +++ b/net/wireless/sme.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * SME code for cfg80211's connect emulation. | ||
3 | * | ||
4 | * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * Copyright (C) 2009 Intel Corporation. All rights reserved. | ||
6 | */ | ||
7 | |||
8 | #include <linux/etherdevice.h> | ||
9 | #include <linux/if_arp.h> | ||
10 | #include <linux/workqueue.h> | ||
11 | #include <net/cfg80211.h> | ||
12 | #include <net/rtnetlink.h> | ||
13 | #include "nl80211.h" | ||
14 | |||
15 | |||
16 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | ||
17 | const u8 *req_ie, size_t req_ie_len, | ||
18 | const u8 *resp_ie, size_t resp_ie_len, | ||
19 | u16 status, gfp_t gfp) | ||
20 | { | ||
21 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
22 | struct cfg80211_bss *bss; | ||
23 | #ifdef CONFIG_WIRELESS_EXT | ||
24 | union iwreq_data wrqu; | ||
25 | #endif | ||
26 | |||
27 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | ||
28 | return; | ||
29 | |||
30 | if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTING)) | ||
31 | return; | ||
32 | |||
33 | if (wdev->current_bss) { | ||
34 | cfg80211_unhold_bss(wdev->current_bss); | ||
35 | cfg80211_put_bss(wdev->current_bss); | ||
36 | wdev->current_bss = NULL; | ||
37 | } | ||
38 | |||
39 | if (status == WLAN_STATUS_SUCCESS) { | ||
40 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | ||
41 | wdev->ssid, wdev->ssid_len, | ||
42 | WLAN_CAPABILITY_ESS, | ||
43 | WLAN_CAPABILITY_ESS); | ||
44 | |||
45 | if (WARN_ON(!bss)) | ||
46 | return; | ||
47 | |||
48 | cfg80211_hold_bss(bss); | ||
49 | wdev->current_bss = bss; | ||
50 | |||
51 | wdev->sme_state = CFG80211_SME_CONNECTED; | ||
52 | } else { | ||
53 | wdev->sme_state = CFG80211_SME_IDLE; | ||
54 | } | ||
55 | |||
56 | nl80211_send_connect_result(wiphy_to_dev(wdev->wiphy), dev, bssid, | ||
57 | req_ie, req_ie_len, resp_ie, resp_ie_len, | ||
58 | status, gfp); | ||
59 | |||
60 | #ifdef CONFIG_WIRELESS_EXT | ||
61 | if (req_ie && status == WLAN_STATUS_SUCCESS) { | ||
62 | memset(&wrqu, 0, sizeof(wrqu)); | ||
63 | wrqu.data.length = req_ie_len; | ||
64 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); | ||
65 | } | ||
66 | |||
67 | if (resp_ie && status == WLAN_STATUS_SUCCESS) { | ||
68 | memset(&wrqu, 0, sizeof(wrqu)); | ||
69 | wrqu.data.length = resp_ie_len; | ||
70 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); | ||
71 | } | ||
72 | |||
73 | memset(&wrqu, 0, sizeof(wrqu)); | ||
74 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
75 | if (bssid) | ||
76 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
77 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | ||
78 | #endif | ||
79 | } | ||
80 | EXPORT_SYMBOL(cfg80211_connect_result); | ||
81 | |||
82 | void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | ||
83 | const u8 *req_ie, size_t req_ie_len, | ||
84 | const u8 *resp_ie, size_t resp_ie_len, gfp_t gfp) | ||
85 | { | ||
86 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
87 | struct cfg80211_bss *bss; | ||
88 | #ifdef CONFIG_WIRELESS_EXT | ||
89 | union iwreq_data wrqu; | ||
90 | #endif | ||
91 | |||
92 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | ||
93 | return; | ||
94 | |||
95 | if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) | ||
96 | return; | ||
97 | |||
98 | /* internal error -- how did we get to CONNECTED w/o BSS? */ | ||
99 | if (WARN_ON(!wdev->current_bss)) { | ||
100 | return; | ||
101 | } | ||
102 | |||
103 | cfg80211_unhold_bss(wdev->current_bss); | ||
104 | cfg80211_put_bss(wdev->current_bss); | ||
105 | wdev->current_bss = NULL; | ||
106 | |||
107 | bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, | ||
108 | wdev->ssid, wdev->ssid_len, | ||
109 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | ||
110 | |||
111 | if (WARN_ON(!bss)) | ||
112 | return; | ||
113 | |||
114 | cfg80211_hold_bss(bss); | ||
115 | wdev->current_bss = bss; | ||
116 | |||
117 | nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, | ||
118 | req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); | ||
119 | |||
120 | #ifdef CONFIG_WIRELESS_EXT | ||
121 | if (req_ie) { | ||
122 | memset(&wrqu, 0, sizeof(wrqu)); | ||
123 | wrqu.data.length = req_ie_len; | ||
124 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, req_ie); | ||
125 | } | ||
126 | |||
127 | if (resp_ie) { | ||
128 | memset(&wrqu, 0, sizeof(wrqu)); | ||
129 | wrqu.data.length = resp_ie_len; | ||
130 | wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, resp_ie); | ||
131 | } | ||
132 | |||
133 | memset(&wrqu, 0, sizeof(wrqu)); | ||
134 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
135 | memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN); | ||
136 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | ||
137 | #endif | ||
138 | } | ||
139 | EXPORT_SYMBOL(cfg80211_roamed); | ||
140 | |||
141 | static void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, | ||
142 | u8 *ie, size_t ie_len, u16 reason, | ||
143 | bool from_ap) | ||
144 | { | ||
145 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
146 | #ifdef CONFIG_WIRELESS_EXT | ||
147 | union iwreq_data wrqu; | ||
148 | #endif | ||
149 | |||
150 | if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) | ||
151 | return; | ||
152 | |||
153 | if (WARN_ON(wdev->sme_state != CFG80211_SME_CONNECTED)) | ||
154 | return; | ||
155 | |||
156 | if (wdev->current_bss) { | ||
157 | cfg80211_unhold_bss(wdev->current_bss); | ||
158 | cfg80211_put_bss(wdev->current_bss); | ||
159 | } | ||
160 | |||
161 | wdev->current_bss = NULL; | ||
162 | wdev->sme_state = CFG80211_SME_IDLE; | ||
163 | |||
164 | nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, | ||
165 | reason, ie, ie_len, from_ap, gfp); | ||
166 | |||
167 | #ifdef CONFIG_WIRELESS_EXT | ||
168 | memset(&wrqu, 0, sizeof(wrqu)); | ||
169 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
170 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | ||
171 | #endif | ||
172 | } | ||
173 | |||
174 | void cfg80211_disconnected(struct net_device *dev, u16 reason, | ||
175 | u8 *ie, size_t ie_len, gfp_t gfp) | ||
176 | { | ||
177 | __cfg80211_disconnected(dev, reason, ie, ie_len, true, gfp); | ||
178 | } | ||
179 | EXPORT_SYMBOL(cfg80211_disconnected); | ||
180 | |||
181 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | ||
182 | struct net_device *dev, | ||
183 | struct cfg80211_connect_params *connect) | ||
184 | { | ||
185 | int err; | ||
186 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
187 | |||
188 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
189 | return -EALREADY; | ||
190 | |||
191 | if (!rdev->ops->connect) { | ||
192 | return -EOPNOTSUPP; | ||
193 | } else { | ||
194 | wdev->sme_state = CFG80211_SME_CONNECTING; | ||
195 | err = rdev->ops->connect(&rdev->wiphy, dev, connect); | ||
196 | if (err) { | ||
197 | wdev->sme_state = CFG80211_SME_IDLE; | ||
198 | return err; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | memcpy(wdev->ssid, connect->ssid, connect->ssid_len); | ||
203 | wdev->ssid_len = connect->ssid_len; | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | int cfg80211_disconnect(struct cfg80211_registered_device *rdev, | ||
209 | struct net_device *dev, u16 reason) | ||
210 | { | ||
211 | int err; | ||
212 | |||
213 | if (!rdev->ops->disconnect) { | ||
214 | return -EOPNOTSUPP; | ||
215 | } else { | ||
216 | err = rdev->ops->disconnect(&rdev->wiphy, dev, reason); | ||
217 | if (err) | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | __cfg80211_disconnected(dev, 0, NULL, 0, false, GFP_KERNEL); | ||
222 | |||
223 | return 0; | ||
224 | } | ||