Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 77fdaa12 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

mac80211: rework MLME for multiple authentications



Sit tight. This shakes up the world as you know
it. Let go of your spaghetti tongs, they will no
longer be required, the horrible statemachine in
net/mac80211/mlme.c is no more...

With the cfg80211 SME mac80211 now has much less
to keep track of, but, on the other hand, for FT
it needs to be able to keep track of at least one
authentication being in progress while associated.
So convert from a single state machine to having
small ones for all the different things we need to
do. For real FT it will still need work wrt. PS,
but this should be a good step.

Signed-off-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a7c1cfc9
Loading
Loading
Loading
Loading
+4 −101
Original line number Diff line number Diff line
@@ -1172,122 +1172,25 @@ static int ieee80211_scan(struct wiphy *wiphy,
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
			  struct cfg80211_auth_request *req)
{
	struct ieee80211_sub_if_data *sdata;
	const u8 *ssid;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	switch (req->auth_type) {
	case NL80211_AUTHTYPE_OPEN_SYSTEM:
		sdata->u.mgd.auth_alg = WLAN_AUTH_OPEN;
		break;
	case NL80211_AUTHTYPE_SHARED_KEY:
		sdata->u.mgd.auth_alg = WLAN_AUTH_SHARED_KEY;
		break;
	case NL80211_AUTHTYPE_FT:
		sdata->u.mgd.auth_alg = WLAN_AUTH_FT;
		break;
	case NL80211_AUTHTYPE_NETWORK_EAP:
		sdata->u.mgd.auth_alg = WLAN_AUTH_LEAP;
		break;
	default:
		return -EOPNOTSUPP;
	}

	memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN);

	sdata->local->oper_channel = req->bss->channel;
	ieee80211_hw_config(sdata->local, 0);

	ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
	if (!ssid)
		return -EINVAL;
	sdata->u.mgd.ssid_len = *(ssid + 1);
	memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len);

	kfree(sdata->u.mgd.sme_auth_ie);
	sdata->u.mgd.sme_auth_ie = NULL;
	sdata->u.mgd.sme_auth_ie_len = 0;
	if (req->ie) {
		sdata->u.mgd.sme_auth_ie = kmalloc(req->ie_len, GFP_KERNEL);
		if (sdata->u.mgd.sme_auth_ie == NULL)
			return -ENOMEM;
		memcpy(sdata->u.mgd.sme_auth_ie, req->ie, req->ie_len);
		sdata->u.mgd.sme_auth_ie_len = req->ie_len;
	}

	sdata->u.mgd.state = IEEE80211_STA_MLME_DIRECT_PROBE;
	ieee80211_sta_req_auth(sdata);
	return 0;
	return ieee80211_mgd_auth(IEEE80211_DEV_TO_SUB_IF(dev), req);
}

static int ieee80211_assoc(struct wiphy *wiphy, struct net_device *dev,
			   struct cfg80211_assoc_request *req)
{
	struct ieee80211_sub_if_data *sdata;
	int ret, i;

	sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 ||
	    !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED))
		return -ENOLINK; /* not authenticated */

	sdata->u.mgd.flags &= ~IEEE80211_STA_DISABLE_11N;

	for (i = 0; i < req->crypto.n_ciphers_pairwise; i++)
		if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
		    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104)
			sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N;

	sdata->local->oper_channel = req->bss->channel;
	ieee80211_hw_config(sdata->local, 0);

	ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len);
	if (ret && ret != -EALREADY)
		return ret;

	if (req->use_mfp) {
		sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
		sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
	} else {
		sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
		sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
	}

	if (req->prev_bssid) {
		sdata->u.mgd.flags |= IEEE80211_STA_PREV_BSSID_SET;
		memcpy(sdata->u.mgd.prev_bssid, req->prev_bssid, ETH_ALEN);
	} else
		sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;

	if (req->crypto.control_port)
		sdata->u.mgd.flags |= IEEE80211_STA_CONTROL_PORT;
	else
		sdata->u.mgd.flags &= ~IEEE80211_STA_CONTROL_PORT;

	sdata->u.mgd.state = IEEE80211_STA_MLME_ASSOCIATE;
	ieee80211_sta_req_auth(sdata);
	return 0;
	return ieee80211_mgd_assoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}

static int ieee80211_deauth(struct wiphy *wiphy, struct net_device *dev,
			    struct cfg80211_deauth_request *req)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	/* TODO: req->ie, req->peer_addr */
	return ieee80211_sta_deauthenticate(sdata, req->reason_code);
	return ieee80211_mgd_deauth(IEEE80211_DEV_TO_SUB_IF(dev), req);
}

static int ieee80211_disassoc(struct wiphy *wiphy, struct net_device *dev,
			      struct cfg80211_disassoc_request *req)
{
	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);

	/* TODO: req->ie, req->peer_addr */
	return ieee80211_sta_disassociate(sdata, req->reason_code);
	return ieee80211_mgd_disassoc(IEEE80211_DEV_TO_SUB_IF(dev), req);
}

static int ieee80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+0 −38
Original line number Diff line number Diff line
@@ -95,29 +95,9 @@ IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);

/* STA attributes */
IEEE80211_IF_FILE(state, u.mgd.state, DEC);
IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC);

static ssize_t ieee80211_if_fmt_flags(
	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
{
	return scnprintf(buf, buflen, "%s%s%s%s%s\n",
		 sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
		 sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
		 sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
		 sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
		 sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
}
__IEEE80211_IF_FILE(flags);

/* AP attributes */
IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
@@ -180,18 +160,9 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
	DEBUGFS_ADD(force_unicast_rateidx, sta);
	DEBUGFS_ADD(max_ratectrl_rateidx, sta);

	DEBUGFS_ADD(state, sta);
	DEBUGFS_ADD(bssid, sta);
	DEBUGFS_ADD(prev_bssid, sta);
	DEBUGFS_ADD(ssid_len, sta);
	DEBUGFS_ADD(aid, sta);
	DEBUGFS_ADD(capab, sta);
	DEBUGFS_ADD(extra_ie_len, sta);
	DEBUGFS_ADD(auth_tries, sta);
	DEBUGFS_ADD(assoc_tries, sta);
	DEBUGFS_ADD(auth_alg, sta);
	DEBUGFS_ADD(auth_transaction, sta);
	DEBUGFS_ADD(flags, sta);
}

static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -311,18 +282,9 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata)
	DEBUGFS_DEL(force_unicast_rateidx, sta);
	DEBUGFS_DEL(max_ratectrl_rateidx, sta);

	DEBUGFS_DEL(state, sta);
	DEBUGFS_DEL(bssid, sta);
	DEBUGFS_DEL(prev_bssid, sta);
	DEBUGFS_DEL(ssid_len, sta);
	DEBUGFS_DEL(aid, sta);
	DEBUGFS_DEL(capab, sta);
	DEBUGFS_DEL(extra_ie_len, sta);
	DEBUGFS_DEL(auth_tries, sta);
	DEBUGFS_DEL(assoc_tries, sta);
	DEBUGFS_DEL(auth_alg, sta);
	DEBUGFS_DEL(auth_transaction, sta);
	DEBUGFS_DEL(flags, sta);
}

static void del_ap_files(struct ieee80211_sub_if_data *sdata)
+36 −50
Original line number Diff line number Diff line
@@ -227,11 +227,32 @@ struct mesh_preq_queue {
	u8 flags;
};

enum ieee80211_mgd_state {
	IEEE80211_MGD_STATE_IDLE,
	IEEE80211_MGD_STATE_PROBE,
	IEEE80211_MGD_STATE_AUTH,
	IEEE80211_MGD_STATE_ASSOC,
};

struct ieee80211_mgd_work {
	struct list_head list;
	struct ieee80211_bss *bss;
	int ie_len;
	u8 prev_bssid[ETH_ALEN];
	u8 ssid[IEEE80211_MAX_SSID_LEN];
	u8 ssid_len;
	unsigned long timeout;
	enum ieee80211_mgd_state state;
	u16 auth_alg, auth_transaction;

	int tries;

	/* must be last */
	u8 ie[0]; /* for auth or assoc frame, not probe */
};

/* flags used in struct ieee80211_if_managed.flags */
enum ieee80211_sta_flags {
	IEEE80211_STA_PREV_BSSID_SET	= BIT(0),
	IEEE80211_STA_AUTHENTICATED	= BIT(1),
	IEEE80211_STA_ASSOCIATED	= BIT(2),
	IEEE80211_STA_PROBEREQ_POLL	= BIT(3),
	IEEE80211_STA_CONTROL_PORT	= BIT(4),
	IEEE80211_STA_WMM_ENABLED	= BIT(5),
@@ -243,8 +264,6 @@ enum ieee80211_sta_flags {
/* flags for MLME request */
enum ieee80211_sta_request {
	IEEE80211_STA_REQ_SCAN,
	IEEE80211_STA_REQ_AUTH,
	IEEE80211_STA_REQ_RUN,
};

struct ieee80211_if_managed {
@@ -254,35 +273,17 @@ struct ieee80211_if_managed {
	struct work_struct chswitch_work;
	struct work_struct beacon_loss_work;

	u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
	struct mutex mtx;
	struct ieee80211_bss *associated;
	struct list_head work_list;

	u8 ssid[IEEE80211_MAX_SSID_LEN];
	size_t ssid_len;

	enum {
		IEEE80211_STA_MLME_DISABLED,
		IEEE80211_STA_MLME_DIRECT_PROBE,
		IEEE80211_STA_MLME_AUTHENTICATE,
		IEEE80211_STA_MLME_ASSOCIATE,
		IEEE80211_STA_MLME_ASSOCIATED,
	} state;
	u8 bssid[ETH_ALEN];

	u16 aid;
	u16 capab;
	u8 *extra_ie; /* to be added to the end of AssocReq */
	size_t extra_ie_len;

	/* The last AssocReq/Resp IEs */
	u8 *assocreq_ies, *assocresp_ies;
	size_t assocreq_ies_len, assocresp_ies_len;

	struct sk_buff_head skb_queue;

	int assoc_scan_tries; /* number of scans done pre-association */
	int direct_probe_tries; /* retries for direct probes */
	int auth_tries; /* retries for auth req */
	int assoc_tries; /* retries for assoc req */

	unsigned long timers_running; /* used for quiesce/restart */
	bool powersave; /* powersave requested for this iface */

@@ -292,9 +293,6 @@ struct ieee80211_if_managed {

	unsigned int flags;

	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
	int auth_transaction;

	u32 beacon_crc;

	enum {
@@ -304,10 +302,6 @@ struct ieee80211_if_managed {
	} mfp; /* management frame protection */

	int wmm_last_param_set;

	/* Extra IE data for management frames */
	u8 *sme_auth_ie;
	size_t sme_auth_ie_len;
};

enum ieee80211_ibss_request {
@@ -466,18 +460,9 @@ struct ieee80211_sub_if_data {
	union {
		struct {
			struct dentry *drop_unencrypted;
			struct dentry *state;
			struct dentry *bssid;
			struct dentry *prev_bssid;
			struct dentry *ssid_len;
			struct dentry *aid;
			struct dentry *capab;
			struct dentry *extra_ie_len;
			struct dentry *auth_tries;
			struct dentry *assoc_tries;
			struct dentry *auth_alg;
			struct dentry *auth_transaction;
			struct dentry *flags;
			struct dentry *force_unicast_rateidx;
			struct dentry *max_ratectrl_rateidx;
		} sta;
@@ -928,11 +913,16 @@ extern const struct iw_handler_def ieee80211_iw_handler_def;

/* STA code */
void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
		       struct cfg80211_auth_request *req);
int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
			struct cfg80211_assoc_request *req);
int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
			 struct cfg80211_deauth_request *req);
int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
			   struct cfg80211_disassoc_request *req);
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
					  struct sk_buff *skb);
void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata);
int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
void ieee80211_send_pspoll(struct ieee80211_local *local,
			   struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
@@ -966,8 +956,6 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
void ieee80211_scan_cancel(struct ieee80211_local *local);
ieee80211_rx_result
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb);
int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
			       const char *ie, size_t len);

void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
struct ieee80211_bss *
@@ -983,8 +971,6 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
		     u8 *ssid, u8 ssid_len);
void ieee80211_rx_bss_put(struct ieee80211_local *local,
			  struct ieee80211_bss *bss);
void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
			     int freq, u8 *ssid, u8 ssid_len);

/* interface handling */
int ieee80211_if_add(struct ieee80211_local *local, const char *name,
+2 −26
Original line number Diff line number Diff line
@@ -233,9 +233,6 @@ static int ieee80211_open(struct net_device *dev)
		ieee80211_configure_filter(local);
		netif_addr_unlock_bh(local->mdev);
		break;
	case NL80211_IFTYPE_STATION:
		sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
		/* fall through */
	default:
		conf.vif = &sdata->vif;
		conf.type = sdata->vif.type;
@@ -365,18 +362,6 @@ static int ieee80211_stop(struct net_device *dev)

	rcu_read_unlock();

	/*
	 * Announce that we are leaving the network, in case we are a
	 * station interface type. This must be done before removing
	 * all stations associated with sta_info_flush, otherwise STA
	 * information will be gone and no announce being done.
	 */
	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
		if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED)
			ieee80211_sta_deauthenticate(sdata,
				WLAN_REASON_DEAUTH_LEAVING);
	}

	/*
	 * Remove all stations associated with this interface.
	 *
@@ -462,7 +447,6 @@ static int ieee80211_stop(struct net_device *dev)
		netif_addr_unlock_bh(local->mdev);
		break;
	case NL80211_IFTYPE_STATION:
		memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
		del_timer_sync(&sdata->u.mgd.chswitch_timer);
		del_timer_sync(&sdata->u.mgd.timer);
		/*
@@ -485,10 +469,6 @@ static int ieee80211_stop(struct net_device *dev)
		 */
		synchronize_rcu();
		skb_queue_purge(&sdata->u.mgd.skb_queue);

		kfree(sdata->u.mgd.extra_ie);
		sdata->u.mgd.extra_ie = NULL;
		sdata->u.mgd.extra_ie_len = 0;
		/* fall through */
	case NL80211_IFTYPE_ADHOC:
		if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
@@ -650,11 +630,6 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
			kfree_skb(sdata->u.ibss.presp);
		break;
	case NL80211_IFTYPE_STATION:
		kfree(sdata->u.mgd.extra_ie);
		kfree(sdata->u.mgd.assocreq_ies);
		kfree(sdata->u.mgd.assocresp_ies);
		kfree(sdata->u.mgd.sme_auth_ie);
		break;
	case NL80211_IFTYPE_WDS:
	case NL80211_IFTYPE_AP_VLAN:
	case NL80211_IFTYPE_MONITOR:
@@ -937,7 +912,8 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
			continue;
		/* do not count disabled managed interfaces */
		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
		    sdata->u.mgd.state == IEEE80211_STA_MLME_DISABLED)
		    !sdata->u.mgd.associated &&
		    list_empty(&sdata->u.mgd.work_list))
			continue;
		/* do not count unused IBSS interfaces */
		if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
+700 −632

File changed.

Preview size limit exceeded, changes collapsed.

Loading