Commit 6829c878 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211: emulate connect with auth/assoc

This adds code to cfg80211 so that drivers (mac80211 right
now) that don't implement connect but rather auth/assoc can
still be used with the nl80211 connect command. This will
also be necessary for the wext compat code.
Signed-off-by: default avatarSamuel Ortiz <samuel.ortiz@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent b23aa676
...@@ -1209,6 +1209,9 @@ extern void wiphy_unregister(struct wiphy *wiphy); ...@@ -1209,6 +1209,9 @@ extern void wiphy_unregister(struct wiphy *wiphy);
*/ */
extern void wiphy_free(struct wiphy *wiphy); extern void wiphy_free(struct wiphy *wiphy);
/* internal struct */
struct cfg80211_conn;
/** /**
* struct wireless_dev - wireless per-netdev state * struct wireless_dev - wireless per-netdev state
* *
...@@ -1242,9 +1245,10 @@ struct wireless_dev { ...@@ -1242,9 +1245,10 @@ struct wireless_dev {
u8 ssid_len; u8 ssid_len;
enum { enum {
CFG80211_SME_IDLE, CFG80211_SME_IDLE,
CFG80211_SME_CONNECTING, /* ->connect called */ CFG80211_SME_CONNECTING,
CFG80211_SME_CONNECTED, CFG80211_SME_CONNECTED,
} sme_state; } sme_state;
struct cfg80211_conn *conn;
#ifdef CONFIG_WIRELESS_EXT #ifdef CONFIG_WIRELESS_EXT
/* wext data */ /* wext data */
......
...@@ -321,6 +321,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) ...@@ -321,6 +321,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
} }
INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work); INIT_WORK(&drv->rfkill_sync, cfg80211_rfkill_sync_work);
INIT_WORK(&drv->conn_work, cfg80211_conn_work);
/* /*
* Initialize wiphy parameters to IEEE 802.11 MIB default values. * Initialize wiphy parameters to IEEE 802.11 MIB default values.
...@@ -481,6 +482,8 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -481,6 +482,8 @@ void wiphy_unregister(struct wiphy *wiphy)
/* unlock again before freeing */ /* unlock again before freeing */
mutex_unlock(&drv->mtx); mutex_unlock(&drv->mtx);
cancel_work_sync(&drv->conn_work);
cfg80211_debugfs_drv_del(drv); cfg80211_debugfs_drv_del(drv);
/* If this device got a regulatory hint tell core its /* If this device got a regulatory hint tell core its
...@@ -569,6 +572,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, ...@@ -569,6 +572,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
break; break;
} }
break; break;
case NETDEV_DOWN:
kfree(wdev->conn);
wdev->conn = NULL;
break;
case NETDEV_UP: case NETDEV_UP:
#ifdef CONFIG_WIRELESS_EXT #ifdef CONFIG_WIRELESS_EXT
if (wdev->iftype != NL80211_IFTYPE_ADHOC) if (wdev->iftype != NL80211_IFTYPE_ADHOC)
......
...@@ -62,6 +62,8 @@ struct cfg80211_registered_device { ...@@ -62,6 +62,8 @@ struct cfg80211_registered_device {
struct genl_info *testmode_info; struct genl_info *testmode_info;
#endif #endif
struct work_struct conn_work;
#ifdef CONFIG_CFG80211_DEBUGFS #ifdef CONFIG_CFG80211_DEBUGFS
/* Debugfs entries */ /* Debugfs entries */
struct wiphy_debugfsdentries { struct wiphy_debugfsdentries {
...@@ -181,8 +183,14 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev, ...@@ -181,8 +183,14 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
int cfg80211_disconnect(struct cfg80211_registered_device *rdev, int cfg80211_disconnect(struct cfg80211_registered_device *rdev,
struct net_device *dev, u16 reason); struct net_device *dev, u16 reason);
void cfg80211_conn_work(struct work_struct *work);
/* internal helpers */ /* internal helpers */
int cfg80211_validate_key_settings(struct key_params *params, int key_idx, int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
const u8 *mac_addr); const u8 *mac_addr);
void __cfg80211_disconnected(struct net_device *dev, gfp_t gfp, u8 *ie,
size_t ie_len, u16 reason, bool from_ap);
void cfg80211_sme_scan_done(struct net_device *dev);
void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len);
#endif /* __NET_WIRELESS_CORE_H */ #endif /* __NET_WIRELESS_CORE_H */
...@@ -16,58 +16,105 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf ...@@ -16,58 +16,105 @@ void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gf
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_rx_auth(rdev, dev, buf, len, gfp); nl80211_send_rx_auth(rdev, dev, buf, len, gfp);
cfg80211_sme_rx_auth(dev, buf, len);
} }
EXPORT_SYMBOL(cfg80211_send_rx_auth); EXPORT_SYMBOL(cfg80211_send_rx_auth);
void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; u16 status_code;
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
u8 *ie = mgmt->u.assoc_resp.variable;
int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); nl80211_send_rx_assoc(rdev, dev, buf, len, gfp);
cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
status_code, gfp);
} }
EXPORT_SYMBOL(cfg80211_send_rx_assoc); EXPORT_SYMBOL(cfg80211_send_rx_assoc);
void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
nl80211_send_deauth(rdev, dev, buf, len, gfp); nl80211_send_deauth(rdev, dev, buf, len, gfp);
if (wdev->sme_state == CFG80211_SME_CONNECTED) {
u16 reason_code;
bool from_ap;
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
__cfg80211_disconnected(dev, gfp, NULL, 0,
reason_code, from_ap);
wdev->sme_state = CFG80211_SME_IDLE;
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
}
} }
EXPORT_SYMBOL(cfg80211_send_deauth); EXPORT_SYMBOL(cfg80211_send_deauth);
void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
nl80211_send_disassoc(rdev, dev, buf, len, gfp); nl80211_send_disassoc(rdev, dev, buf, len, gfp);
}
EXPORT_SYMBOL(cfg80211_send_disassoc);
static void cfg80211_wext_disconnected(struct net_device *dev) if (wdev->sme_state == CFG80211_SME_CONNECTED) {
{ u16 reason_code;
#ifdef CONFIG_WIRELESS_EXT bool from_ap;
union iwreq_data wrqu;
memset(&wrqu, 0, sizeof(wrqu)); reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
#endif from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0;
__cfg80211_disconnected(dev, gfp, NULL, 0,
reason_code, from_ap);
wdev->sme_state = CFG80211_SME_IDLE;
}
} }
EXPORT_SYMBOL(cfg80211_send_disassoc);
void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_auth_timeout(rdev, dev, addr, gfp); nl80211_send_auth_timeout(rdev, dev, addr, gfp);
cfg80211_wext_disconnected(dev); if (wdev->sme_state == CFG80211_SME_CONNECTING)
cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
wdev->sme_state = CFG80211_SME_IDLE;
} }
EXPORT_SYMBOL(cfg80211_send_auth_timeout); EXPORT_SYMBOL(cfg80211_send_auth_timeout);
void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp)
{ {
struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
nl80211_send_assoc_timeout(rdev, dev, addr, gfp); nl80211_send_assoc_timeout(rdev, dev, addr, gfp);
cfg80211_wext_disconnected(dev); if (wdev->sme_state == CFG80211_SME_CONNECTING)
cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, gfp);
wdev->sme_state = CFG80211_SME_IDLE;
} }
EXPORT_SYMBOL(cfg80211_send_assoc_timeout); EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
......
...@@ -351,12 +351,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, ...@@ -351,12 +351,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
#undef CMD #undef CMD
if (dev->ops->connect) { if (dev->ops->connect || dev->ops->auth) {
i++; i++;
NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT); NLA_PUT_U32(msg, i, NL80211_CMD_CONNECT);
} }
if (dev->ops->disconnect) { if (dev->ops->disconnect || dev->ops->deauth) {
i++; i++;
NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT); NLA_PUT_U32(msg, i, NL80211_CMD_DISCONNECT);
} }
......
...@@ -30,6 +30,13 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted) ...@@ -30,6 +30,13 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted)
WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req); WARN_ON(request != wiphy_to_dev(request->wiphy)->scan_req);
/*
* This must be before sending the other events!
* Otherwise, wpa_supplicant gets completely confused with
* wext events.
*/
cfg80211_sme_scan_done(dev);
if (aborted) if (aborted)
nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev); nl80211_send_scan_aborted(wiphy_to_dev(request->wiphy), dev);
else else
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment