aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/nl80211.h80
-rw-r--r--include/net/cfg80211.h135
-rw-r--r--net/mac80211/cfg.c2
-rw-r--r--net/wireless/Makefile2
-rw-r--r--net/wireless/core.c16
-rw-r--r--net/wireless/core.h7
-rw-r--r--net/wireless/nl80211.c368
-rw-r--r--net/wireless/nl80211.h13
-rw-r--r--net/wireless/sme.c224
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 */
1209enum nl80211_auth_type { 1279enum 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
1313enum 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 */
621struct 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 */
666struct cfg80211_assoc_request { 687struct 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 */
779struct 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 */
1875void 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 */
1894void 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 */
1910void 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
5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o 5obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o
6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o 6obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o
7 7
8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o 8cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o mlme.o ibss.o sme.o
9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o 9cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o
10cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o 10cfg80211-$(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);
174int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 174int 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 */
178int cfg80211_connect(struct cfg80211_registered_device *rdev,
179 struct net_device *dev,
180 struct cfg80211_connect_params *connect);
181int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
182 struct net_device *dev, u16 reason);
183
177/* internal helpers */ 184/* internal helpers */
178int cfg80211_validate_key_settings(struct key_params *params, int key_idx, 185int 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
3002static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type) 3016static 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; 3021static bool nl80211_valid_wpa_versions(u32 wpa_versions)
3022{
3023 return !(wpa_versions & ~(NL80211_WPA_VERSION_1 |
3024 NL80211_WPA_VERSION_2));
3025}
3026
3027static bool nl80211_valid_akm_suite(u32 akm)
3028{
3029 return akm == WLAN_AKM_SUITE_8021X ||
3030 akm == WLAN_AKM_SUITE_PSK;
3031}
3032
3033static 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
3010static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info) 3043static 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
3122static 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
3089static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) 3184static 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
3163out: 3258out:
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)
3538EXPORT_SYMBOL(cfg80211_testmode_event); 3633EXPORT_SYMBOL(cfg80211_testmode_event);
3539#endif 3634#endif
3540 3635
3636static 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
3711out:
3712 cfg80211_put_dev(drv);
3713 dev_put(dev);
3714unlock_rtnl:
3715 rtnl_unlock();
3716 return err;
3717}
3718
3719static 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
3752out:
3753 cfg80211_put_dev(drv);
3754 dev_put(dev);
3755unlock_rtnl:
3756 rtnl_unlock();
3757 return err;
3758}
3759
3541static struct genl_ops nl80211_ops[] = { 3760static 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};
3763static struct genl_multicast_group nl80211_mlme_mcgrp = { 3994static 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
4311void 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
4354void 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
4394void 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
4080void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, 4434void 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,
31void nl80211_send_assoc_timeout(struct cfg80211_registered_device *rdev, 31void 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);
34void 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);
39void 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);
43void 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
34void 47void
35nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev, 48nl80211_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
16void 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}
80EXPORT_SYMBOL(cfg80211_connect_result);
81
82void 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}
139EXPORT_SYMBOL(cfg80211_roamed);
140
141static 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
174void 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}
179EXPORT_SYMBOL(cfg80211_disconnected);
180
181int 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
208int 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}