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

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
Loading
Loading
Loading
Loading
+5 −1
Original line number Original line Diff line number Diff line
@@ -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 {
	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 */
+7 −0
Original line number Original line Diff line number Diff line
@@ -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)
	/* 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,
			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)
+8 −0
Original line number Original line Diff line number Diff line
@@ -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,
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 */
+63 −16
Original line number Original line Diff line number Diff line
@@ -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);


+2 −2
Original line number Original line Diff line number Diff line
@@ -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);
	}
	}
Loading