aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Ortiz <sameo@linux.intel.com>2009-07-01 15:26:54 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:51 -0400
commitb23aa676ab9d54469cda9f7151f51a2851c6f36e (patch)
treedd4af5fa38dbfec362ded1d655ed584bbcf60a53
parent6a669e65c5ec393a650362874e13f7d3365a7827 (diff)
cfg80211: connect/disconnect API
This patch introduces the cfg80211 connect/disconnect API. The goal here is to run the AUTH and ASSOC steps in one call. This is needed for some fullmac cards that run both steps directly from the target, after the host driver sends a connect command. Additionally, all the new crypto parameters for connect() are now also valid for associate() -- although associate requires the IEs to be used, the information can be useful for drivers and should be given. Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-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}