Skip to contentSkip to conversation

station management & auth/assoc redesign

PATCH In review Johannes Berg 3 participants 17 messages Jan 20, 2012 – Feb 3, 2012

Subsystems (3)
lore
Share & tools
lore

Johannes Berg

author maintainer
#0 lore raw

cover station management & auth/assoc redesign

This is the combination series of the station management and auth/assoc redesign patches.

Together, they give drivers more flexibility as to when to add the station entry to the device for connections. The auth/assoc redesign also simplifies the connection establishment process.

Combined diffstat:

 Documentation/DocBook/80211.tmpl |    1 
 include/net/cfg80211.h           |   53 -
 include/net/mac80211.h           |   30 
 net/mac80211/Makefile            |    4 
 net/mac80211/cfg.c               |    6 
 net/mac80211/debugfs_sta.c       |    4 
 net/mac80211/driver-ops.h        |   35 
 net/mac80211/driver-trace.h      |   32 
 net/mac80211/ieee80211_i.h       |   77 +-
 net/mac80211/iface.c             |    4 
 net/mac80211/key.c               |   38 -
 net/mac80211/main.c              |   13 
 net/mac80211/mlme.c              | 1412 +++++++++++++++++++++++++++------------
 net/mac80211/pm.c                |   23 
 net/mac80211/rate.c              |    2 
 net/mac80211/rate.h              |    1 
 net/mac80211/rx.c                |   22 
 net/mac80211/sta_info.c          |  274 +++----
 net/mac80211/sta_info.h          |   42 -
 net/mac80211/util.c              |   23 
 net/mac80211/work.c              |  815 ----------------------
 net/wireless/core.h              |   14 
 net/wireless/mlme.c              |  322 +-------
 net/wireless/nl80211.c           |   18 
 net/wireless/scan.c              |   12 
 net/wireless/sme.c               |   41 -
 26 files changed, 1453 insertions(+), 1865 deletions(-)

johannes

author maintainer
#1 lore raw

PATCH 1/11 mac80211: move managed mode station state modification

From: Johannes Berg <[email protected]>

Move the station state modification right before insert, this just makes the current code more readable (you can tell that it's before insertion looking at a single screenful of code) right now, but some upcoming changes will require this.

---
 net/mac80211/mlme.c |   28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
net/mac80211/mlme.c +14 -14
@@ -1587,20 +1587,6 @@ static bool ieee80211_assoc_success(stru
 		return false;
 	}
 
-	err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
-	if (!err)
-		err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
-	if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
-		err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
-	if (err) {
-		printk(KERN_DEBUG
-		       "%s: failed to move station %pM to desired state\n",
-		       sdata->name, sta->sta.addr);
-		WARN_ON(__sta_info_destroy(sta));
-		mutex_unlock(&sdata->local->sta_mtx);
-		return false;
-	}
-
 	rates = 0;
 	basic_rates = 0;
 	sband = local->hw.wiphy->bands[wk->chan->band];
@@ -1648,6 +1634,20 @@ static bool ieee80211_assoc_success(stru
 	if (elems.wmm_param)
 		set_sta_flag(sta, WLAN_STA_WME);
 
+	err = sta_info_move_state(sta, IEEE80211_STA_AUTH);
+	if (!err)
+		err = sta_info_move_state(sta, IEEE80211_STA_ASSOC);
+	if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT))
+		err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED);
+	if (err) {
+		printk(KERN_DEBUG
+		       "%s: failed to move station %pM to desired state\n",
+		       sdata->name, sta->sta.addr);
+		WARN_ON(__sta_info_destroy(sta));
+		mutex_unlock(&sdata->local->sta_mtx);
+		return false;
+	}
+
 	/* sta_info_reinsert will also unlock the mutex lock */
 	err = sta_info_reinsert(sta);
 	sta = NULL;
author maintainer
#2 lore raw

PATCH 2/11 mac80211: simplify AP_VLAN handling

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Setting keys and updating TKIP keys must use the BSS sdata (not AP_VLAN), so we translate. Move the translation into driver-ops wrappers instead of having it inline in the code to simplify the normal code flow.

The same can be done for sta_add/remove which already does the translation in the wrapper.

---
 net/mac80211/driver-ops.h |    2 ++
 net/mac80211/key.c        |    8 --------
 net/mac80211/pm.c         |   11 ++---------
 net/mac80211/sta_info.c   |    8 +-------
 net/mac80211/util.c       |   11 ++---------
 5 files changed, 7 insertions(+), 33 deletions(-)
net/mac80211/driver-ops.h +2 -0
@@ -253,6 +253,7 @@ static inline int drv_set_key(struct iee
 
 	might_sleep();
 
+	sdata = get_bss_sdata(sdata);
 	check_sdata_in_driver(sdata);
 
 	trace_drv_set_key(local, cmd, sdata, sta, key);
@@ -272,6 +273,7 @@ static inline void drv_update_tkip_key(s
 	if (sta)
 		ista = &sta->sta;
 
+	sdata = get_bss_sdata(sdata);
 	check_sdata_in_driver(sdata);
 
 	trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
net/mac80211/key.c +0 -8
@@ -123,9 +123,6 @@ static int ieee80211_key_enable_hw_accel
 		 */
 		if (!(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE))
 			goto out_unsupported;
-		sdata = container_of(sdata->bss,
-				     struct ieee80211_sub_if_data,
-				     u.ap);
 	}
 
 	ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
@@ -187,11 +184,6 @@ static void ieee80211_key_disable_hw_acc
 	      (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
 		increment_tailroom_need_count(sdata);
 
-	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-		sdata = container_of(sdata->bss,
-				     struct ieee80211_sub_if_data,
-				     u.ap);
-
 	ret = drv_set_key(key->local, DISABLE_KEY, sdata,
 			  sta, &key->conf);
 
net/mac80211/pm.c +2 -9
@@ -97,15 +97,8 @@ int __ieee80211_suspend(struct ieee80211
 	/* tear down aggregation sessions and remove STAs */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->uploaded) {
-			sdata = sta->sdata;
-			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-				sdata = container_of(sdata->bss,
-					     struct ieee80211_sub_if_data,
-					     u.ap);
-
-			drv_sta_remove(local, sdata, &sta->sta);
-		}
+		if (sta->uploaded)
+			drv_sta_remove(local, sta->sdata, &sta->sta);
 
 		mesh_plink_quiesce(sta);
 	}
net/mac80211/sta_info.c +1 -7
@@ -775,14 +775,8 @@ int __must_check __sta_info_destroy(stru
 		}
 	}
 
-	if (sta->uploaded) {
-		if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-			sdata = container_of(sdata->bss,
-					     struct ieee80211_sub_if_data,
-					     u.ap);
+	if (sta->uploaded)
 		drv_sta_remove(local, sdata, &sta->sta);
-		sdata = sta->sdata;
-	}
 
 	/*
 	 * At this point, after we wait for an RCU grace period,
net/mac80211/util.c +2 -9
@@ -1184,15 +1184,8 @@ int ieee80211_reconfig(struct ieee80211_
 	/* add STAs back */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->uploaded) {
-			sdata = sta->sdata;
-			if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
-				sdata = container_of(sdata->bss,
-					     struct ieee80211_sub_if_data,
-					     u.ap);
-
-			WARN_ON(drv_sta_add(local, sdata, &sta->sta));
-		}
+		if (sta->uploaded)
+			WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta));
 	}
 	mutex_unlock(&local->sta_mtx);
 
author maintainer
#3 lore raw

PATCH 3/11 mac80211: dont program keys for stations not uploaded

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

If a station couldn't be uploaded to the driver but is still kept (only in IBSS mode) we still shouldn't try to program the keys for it into hardware; fix this bug by skipping the key upload in this case.

---
 net/mac80211/key.c |   30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)
net/mac80211/key.c +14 -16
@@ -54,14 +54,6 @@ static void assert_key_lock(struct ieee8
 	lockdep_assert_held(&local->key_mtx);
 }
 
-static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
-{
-	if (key->sta)
-		return &key->sta->sta;
-
-	return NULL;
-}
-
 static void increment_tailroom_need_count(struct ieee80211_sub_if_data *sdata)
 {
 	/*
@@ -95,7 +87,7 @@ static void increment_tailroom_need_coun
 static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_sta *sta;
+	struct sta_info *sta;
 	int ret;
 
 	might_sleep();
@@ -105,7 +97,7 @@ static int ieee80211_key_enable_hw_accel
 
 	assert_key_lock(key->local);
 
-	sta = get_sta_for_key(key);
+	sta = key->sta;
 
 	/*
 	 * If this is a per-STA GTK, check if it
@@ -115,6 +107,9 @@ static int ieee80211_key_enable_hw_accel
 	    !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
 		goto out_unsupported;
 
+	if (sta && !sta->uploaded)
+		goto out_unsupported;
+
 	sdata = key->sdata;
 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
 		/*
@@ -125,7 +120,8 @@ static int ieee80211_key_enable_hw_accel
 			goto out_unsupported;
 	}
 
-	ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
+	ret = drv_set_key(key->local, SET_KEY, sdata,
+			  sta ? &sta->sta : NULL, &key->conf);
 
 	if (!ret) {
 		key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
@@ -144,7 +140,8 @@ static int ieee80211_key_enable_hw_accel
 	if (ret != -ENOSPC && ret != -EOPNOTSUPP)
 		wiphy_err(key->local->hw.wiphy,
 			  "failed to set key (%d, %pM) to hardware (%d)\n",
-			  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+			  key->conf.keyidx,
+			  sta ? sta->sta.addr : bcast_addr, ret);
 
  out_unsupported:
 	switch (key->conf.cipher) {
@@ -163,7 +160,7 @@ static int ieee80211_key_enable_hw_accel
 static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
 {
 	struct ieee80211_sub_if_data *sdata;
-	struct ieee80211_sta *sta;
+	struct sta_info *sta;
 	int ret;
 
 	might_sleep();
@@ -176,7 +173,7 @@ static void ieee80211_key_disable_hw_acc
 	if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
 		return;
 
-	sta = get_sta_for_key(key);
+	sta = key->sta;
 	sdata = key->sdata;
 
 	if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
@@ -185,12 +182,13 @@ static void ieee80211_key_disable_hw_acc
 		increment_tailroom_need_count(sdata);
 
 	ret = drv_set_key(key->local, DISABLE_KEY, sdata,
-			  sta, &key->conf);
+			  sta ? &sta->sta : NULL, &key->conf);
 
 	if (ret)
 		wiphy_err(key->local->hw.wiphy,
 			  "failed to remove key (%d, %pM) from hardware (%d)\n",
-			  key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
+			  key->conf.keyidx,
+			  sta ? sta->sta.addr : bcast_addr, ret);
 
 	key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
 }
author maintainer
#4 lore raw

PATCH 4/11 mac80211: add NOTEXIST station state

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

This will be used by drivers later if they need to have stations inserted all the time, in mac80211 has no purpose, is never used and sta_state starts out in NONE.

---
 net/mac80211/sta_info.c |    2 ++
 net/mac80211/sta_info.h |    1 +
 2 files changed, 3 insertions(+)
net/mac80211/sta_info.h +1 -0
@@ -77,6 +77,7 @@ enum ieee80211_sta_info_flags {
 
 enum ieee80211_sta_state {
 	/* NOTE: These need to be ordered correctly! */
+	IEEE80211_STA_NOTEXIST,
 	IEEE80211_STA_NONE,
 	IEEE80211_STA_AUTH,
 	IEEE80211_STA_ASSOC,
net/mac80211/sta_info.c +2 -0
@@ -293,6 +293,8 @@ struct sta_info *sta_info_alloc(struct i
 	sta->sdata = sdata;
 	sta->last_rx = jiffies;
 
+	sta->sta_state = IEEE80211_STA_NONE;
+
 	do_posix_clock_monotonic_gettime(&uptime);
 	sta->last_connected = uptime.tv_sec;
 	ewma_init(&sta->avg_signal, 1024, 8);
author maintainer
#5 lore raw

PATCH 5/11 mac80211: add sta_state callback

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

(based on Eliad's patch)

Add a callback to notify the low-level driver whenever the state of a station changes. The driver is only notified when the station is actually in the mac80211 hash table, not for pre-insert state transitions.

To allow the driver to replace sta_add/remove calls with this, call extra transitions with the NOTEXIST state.

This callback can fail, so we need to be careful in handling it when a station is inserted, particularly in the IBSS case where we still keep the station entry around for mac80211 purposes.

---
v2: call drv_sta_state() within the sta addition process (thanks Johannes) Johannes:
v3: - call drv_sta_state() in suspend
- introduce NOTEXIST state
- don't put old state into driver visible data but pass it to the callback -- also fixes a reconfig bug
- make exclusive (forbid having sta_add/remove and sta_state)
- allow drv_sta_state() to fail and unwind initial addition if it does
v4: - handle updates correctly when state change fails

 include/net/mac80211.h      |   30 ++++++++++++
 net/mac80211/driver-ops.h   |   22 +++++++++
 net/mac80211/driver-trace.h |   32 +++++++++++++
 net/mac80211/main.c         |    3 +
 net/mac80211/pm.c           |   10 +++-
 net/mac80211/sta_info.c     |  106 ++++++++++++++++++++++++++++++++++++--------
 net/mac80211/sta_info.h     |    9 ---
 net/mac80211/util.c         |   10 +++-
 8 files changed, 194 insertions(+), 28 deletions(-)
include/net/mac80211.h +30 -0
@@ -982,6 +982,25 @@ enum set_key_cmd {
 };
 
 /**
+ * enum ieee80211_sta_state - station state
+ *
+ * @IEEE80211_STA_NOTEXIST: station doesn't exist at all,
+ *	this is a special state for add/remove transitions
+ * @IEEE80211_STA_NONE: station exists without special state
+ * @IEEE80211_STA_AUTH: station is authenticated
+ * @IEEE80211_STA_ASSOC: station is associated
+ * @IEEE80211_STA_AUTHORIZED: station is authorized (802.1X)
+ */
+enum ieee80211_sta_state {
+	/* NOTE: These need to be ordered correctly! */
+	IEEE80211_STA_NOTEXIST,
+	IEEE80211_STA_NONE,
+	IEEE80211_STA_AUTH,
+	IEEE80211_STA_ASSOC,
+	IEEE80211_STA_AUTHORIZED,
+};
+
+/**
  * struct ieee80211_sta - station table entry
  *
  * A station table entry represents a station we are possibly
@@ -1974,6 +1993,13 @@ enum ieee80211_frame_release_type {
  *	in AP mode, this callback will not be called when the flag
  *	%IEEE80211_HW_AP_LINK_PS is set. Must be atomic.
  *
+ * @sta_state: Notifies low level driver about state transition of a
+ *	station (which can be the AP, a client, IBSS/WDS/mesh peer etc.)
+ *	This callback is mutually exclusive with @sta_add/@sta_remove.
+ *	It must not fail for down transitions but may fail for transitions
+ *	up the list of states.
+ *	The callback can sleep.
+ *
  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max),
  *	bursting) for a hardware TX queue.
  *	Returns a negative error code on failure.
@@ -2193,6 +2219,10 @@ struct ieee80211_ops {
 			  struct ieee80211_sta *sta);
 	void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			enum sta_notify_cmd, struct ieee80211_sta *sta);
+	int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			 struct ieee80211_sta *sta,
+			 enum ieee80211_sta_state old_state,
+			 enum ieee80211_sta_state new_state);
 	int (*conf_tx)(struct ieee80211_hw *hw,
 		       struct ieee80211_vif *vif, u16 queue,
 		       const struct ieee80211_tx_queue_params *params);
net/mac80211/driver-ops.h +22 -0
@@ -478,6 +478,28 @@ static inline void drv_sta_remove(struct
 	trace_drv_return_void(local);
 }
 
+static inline __must_check
+int drv_sta_state(struct ieee80211_local *local,
+		  struct ieee80211_sub_if_data *sdata,
+		  struct sta_info *sta,
+		  enum ieee80211_sta_state old_state,
+		  enum ieee80211_sta_state new_state)
+{
+	int ret = 0;
+
+	might_sleep();
+
+	sdata = get_bss_sdata(sdata);
+	check_sdata_in_driver(sdata);
+
+	trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
+	if (local->ops->sta_state)
+		ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
+					    old_state, new_state);
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
 static inline int drv_conf_tx(struct ieee80211_local *local,
 			      struct ieee80211_sub_if_data *sdata, u16 queue,
 			      const struct ieee80211_tx_queue_params *params)
net/mac80211/driver-trace.h +32 -0
@@ -635,6 +635,38 @@ TRACE_EVENT(drv_sta_notify,
 	)
 );
 
+TRACE_EVENT(drv_sta_state,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 struct ieee80211_sta *sta,
+		 enum ieee80211_sta_state old_state,
+		 enum ieee80211_sta_state new_state),
+
+	TP_ARGS(local, sdata, sta, old_state, new_state),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		STA_ENTRY
+		__field(u32, old_state)
+		__field(u32, new_state)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		STA_ASSIGN;
+		__entry->old_state = old_state;
+		__entry->new_state = new_state;
+	),
+
+	TP_printk(
+		LOCAL_PR_FMT  VIF_PR_FMT  STA_PR_FMT " state: %d->%d",
+		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG,
+		__entry->old_state, __entry->new_state
+	)
+);
+
 TRACE_EVENT(drv_sta_add,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
net/mac80211/sta_info.c +89 -17

162 lines not on this page · raw message

net/mac80211/util.c +9 -1
@@ -1184,8 +1184,16 @@ int ieee80211_reconfig(struct ieee80211_
 	/* add STAs back */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->uploaded)
+		if (sta->uploaded) {
+			enum ieee80211_sta_state state;
+
 			WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta));
+
+			for (state = IEEE80211_STA_NOTEXIST;
+			     state < sta->sta_state - 1; state++)
+				WARN_ON(drv_sta_state(local, sta->sdata, sta,
+						      state, state + 1));
+		}
 	}
 	mutex_unlock(&local->sta_mtx);
 
net/mac80211/main.c +3 -0
@@ -534,6 +534,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	int priv_size, i;
 	struct wiphy *wiphy;
 
+	if (WARN_ON(ops->sta_state && (ops->sta_add || ops->sta_remove)))
+		return NULL;
+
 	/* Ensure 32-byte alignment of our private data and hw private data.
 	 * We use the wiphy priv data for both our ieee80211_local and for
 	 * the driver's private data
net/mac80211/sta_info.h +0 -9
@@ -75,15 +75,6 @@ enum ieee80211_sta_info_flags {
 	WLAN_STA_INSERTED,
 };
 
-enum ieee80211_sta_state {
-	/* NOTE: These need to be ordered correctly! */
-	IEEE80211_STA_NOTEXIST,
-	IEEE80211_STA_NONE,
-	IEEE80211_STA_AUTH,
-	IEEE80211_STA_ASSOC,
-	IEEE80211_STA_AUTHORIZED,
-};
-
 #define STA_TID_NUM 16
 #define ADDBA_RESP_INTERVAL HZ
 #define HT_AGG_MAX_RETRIES		15
net/mac80211/pm.c +9 -1
@@ -97,9 +97,17 @@ int __ieee80211_suspend(struct ieee80211
 	/* tear down aggregation sessions and remove STAs */
 	mutex_lock(&local->sta_mtx);
 	list_for_each_entry(sta, &local->sta_list, list) {
-		if (sta->uploaded)
+		if (sta->uploaded) {
+			enum ieee80211_sta_state state;
+
 			drv_sta_remove(local, sta->sdata, &sta->sta);
 
+			state = sta->sta_state;
+			for (; state > IEEE80211_STA_NOTEXIST; state--)
+				WARN_ON(drv_sta_state(local, sdata, sta,
+						      state, state - 1));
+		}
+
 		mesh_plink_quiesce(sta);
 	}
 	mutex_unlock(&local->sta_mtx);
author maintainer
#6 lore raw

PATCH 6/11 mac80211: implement sta_add/sta_remove in sta_state

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Instead of maintaining separate sta_add/sta_remove callsites, implement it in sta_state when the driver has no sta_state implementation.

The only behavioural change this should cause is in secure mesh mode: with this the station entries will only be created after the stations are set to AUTH. Given which drivers support mesh, this seems to not be a problem.

---
 net/mac80211/driver-ops.h |   11 ++++++++++-
 net/mac80211/pm.c         |    2 --
 net/mac80211/sta_info.c   |   23 +++++++++--------------
 net/mac80211/util.c       |    2 --
 4 files changed, 19 insertions(+), 19 deletions(-)
net/mac80211/sta_info.c +9 -14
@@ -365,7 +365,12 @@ static int sta_info_insert_drv_state(str
 	}
 
 	if (!err) {
-		sta->uploaded = true;
+		/*
+		 * Drivers using legacy sta_add/sta_remove callbacks only
+		 * get uploaded set to true after sta_add is called.
+		 */
+		if (!local->ops->sta_add)
+			sta->uploaded = true;
 		return 0;
 	}
 
@@ -417,18 +422,9 @@ static int sta_info_insert_finish(struct
 
 	if (!sta->dummy || dummy_reinsert) {
 		/* notify driver */
-		err = drv_sta_add(local, sdata, &sta->sta);
-		if (err) {
-			if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
-				goto out_err;
-			printk(KERN_DEBUG "%s: failed to add IBSS STA %pM to "
-					  "driver (%d) - keeping it anyway.\n",
-			       sdata->name, sta->sta.addr, err);
-		} else {
-			err = sta_info_insert_drv_state(local, sdata, sta);
-			if (err)
-				goto out_err;
-		}
+		err = sta_info_insert_drv_state(local, sdata, sta);
+		if (err)
+			goto out_err;
 	}
 
 	if (!dummy_reinsert) {
@@ -813,7 +809,6 @@ int __must_check __sta_info_destroy(stru
 	}
 
 	if (sta->uploaded) {
-		drv_sta_remove(local, sdata, &sta->sta);
 		ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE,
 				    IEEE80211_STA_NOTEXIST);
 		WARN_ON_ONCE(ret != 0);
net/mac80211/util.c +0 -2
@@ -1187,8 +1187,6 @@ int ieee80211_reconfig(struct ieee80211_
 		if (sta->uploaded) {
 			enum ieee80211_sta_state state;
 
-			WARN_ON(drv_sta_add(local, sta->sdata, &sta->sta));
-
 			for (state = IEEE80211_STA_NOTEXIST;
 			     state < sta->sta_state - 1; state++)
 				WARN_ON(drv_sta_state(local, sta->sdata, sta,
net/mac80211/pm.c +0 -2
@@ -100,8 +100,6 @@ int __ieee80211_suspend(struct ieee80211
 		if (sta->uploaded) {
 			enum ieee80211_sta_state state;
 
-			drv_sta_remove(local, sta->sdata, &sta->sta);
-
 			state = sta->sta_state;
 			for (; state > IEEE80211_STA_NOTEXIST; state--)
 				WARN_ON(drv_sta_state(local, sdata, sta,
net/mac80211/driver-ops.h +10 -1
@@ -493,9 +493,18 @@ int drv_sta_state(struct ieee80211_local
 	check_sdata_in_driver(sdata);
 
 	trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state);
-	if (local->ops->sta_state)
+	if (local->ops->sta_state) {
 		ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta,
 					    old_state, new_state);
+	} else if (old_state == IEEE80211_STA_AUTH &&
+		   new_state == IEEE80211_STA_ASSOC) {
+		ret = drv_sta_add(local, sdata, &sta->sta);
+		if (ret == 0)
+			sta->uploaded = true;
+	} else if (old_state == IEEE80211_STA_ASSOC &&
+		   new_state == IEEE80211_STA_AUTH) {
+		drv_sta_remove(local, sdata, &sta->sta);
+	}
 	trace_drv_return_int(local, ret);
 	return ret;
 }
author maintainer
#7 lore raw

PATCH 7/11 mac80211: call rate control only after init

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

There are situations where we don't have the necessary rate control information yet for station entries, e.g. when associating. This currently doesn't really happen due to the dummy station handling; explicitly disabling rate control when it's not initialised will allow us to remove dummy stations.

---
 net/mac80211/debugfs_sta.c |    4 ++--
 net/mac80211/rate.c        |    2 +-
 net/mac80211/rate.h        |    1 +
 net/mac80211/sta_info.h    |    2 ++
 4 files changed, 6 insertions(+), 3 deletions(-)
net/mac80211/debugfs_sta.c +2 -2
@@ -63,7 +63,7 @@ static ssize_t sta_flags_read(struct fil
 	test_sta_flag(sta, WLAN_STA_##flg) ? #flg "\n" : ""
 
 	int res = scnprintf(buf, sizeof(buf),
-			    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+			    "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
 			    TEST(AUTH), TEST(ASSOC), TEST(PS_STA),
 			    TEST(PS_DRIVER), TEST(AUTHORIZED),
 			    TEST(SHORT_PREAMBLE),
@@ -71,7 +71,7 @@ static ssize_t sta_flags_read(struct fil
 			    TEST(MFP), TEST(BLOCK_BA), TEST(PSPOLL),
 			    TEST(UAPSD), TEST(SP), TEST(TDLS_PEER),
 			    TEST(TDLS_PEER_AUTH), TEST(4ADDR_EVENT),
-			    TEST(INSERTED));
+			    TEST(INSERTED), TEST(RATE_CONTROL));
 #undef TEST
 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
 }
net/mac80211/rate.c +1 -1
@@ -332,7 +332,7 @@ void rate_control_get_rate(struct ieee80
 	int i;
 	u32 mask;
 
-	if (sta) {
+	if (sta && test_sta_flag(sta, WLAN_STA_RATE_CONTROL)) {
 		ista = &sta->sta;
 		priv_sta = sta->rate_ctrl_priv;
 	}
net/mac80211/rate.h +1 -0
@@ -58,6 +58,7 @@ static inline void rate_control_rate_ini
 	sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
 	ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
+	set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
 }
 
 static inline void rate_control_rate_update(struct ieee80211_local *local,
net/mac80211/sta_info.h +2 -0
@@ -53,6 +53,7 @@
  *	reply to other uAPSD trigger frames or PS-Poll.
  * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
  * @WLAN_STA_INSERTED: This station is inserted into the hash table.
+ * @WLAN_STA_RATE_CONTROL: rate control was initialized for this station.
  */
 enum ieee80211_sta_info_flags {
 	WLAN_STA_AUTH,
@@ -73,6 +74,7 @@ enum ieee80211_sta_info_flags {
 	WLAN_STA_SP,
 	WLAN_STA_4ADDR_EVENT,
 	WLAN_STA_INSERTED,
+	WLAN_STA_RATE_CONTROL,
 };
 
 #define STA_TID_NUM 16
author maintainer
#8 lore raw

PATCH 8/11 mac80211: remove dummy STA support

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

The dummy STA support was added because I didn't want to change the driver API at the time. Now that we have state transitions triggering station add/remove in the driver, we only call add once a station reaches ASSOCIATED, so we can remove the dummy station stuff again.

While at it, tighten the RX check and accept only port control (EAP) frames from the AP station if it's not associated yet -- in other cases there's no race.

---
 net/mac80211/mlme.c     |   15 +----
 net/mac80211/rx.c       |   13 +++-
 net/mac80211/sta_info.c |  135 ++++++++----------------------------------------
 net/mac80211/sta_info.h |   30 ----------
 4 files changed, 38 insertions(+), 155 deletions(-)
net/mac80211/sta_info.h +1 -29
@@ -267,8 +267,6 @@ struct sta_ampdu_mlme {
  * @dead: set to true when sta is unlinked
  * @uploaded: set to true when sta is uploaded to the driver
  * @lost_packets: number of consecutive lost packets
- * @dummy: indicate a dummy station created for receiving
- *	EAP frames before association
  * @sta: station information we share with the driver
  * @sta_state: duplicates information about station state (for debug)
  * @beacon_loss_count: number of times beacon loss has triggered
@@ -366,9 +364,6 @@ struct sta_info {
 	unsigned int lost_packets;
 	unsigned int beacon_loss_count;
 
-	/* should be right in front of sta to be in the same cache line */
-	bool dummy;
-
 	/* keep last! */
 	struct ieee80211_sta sta;
 };
@@ -470,15 +465,9 @@ rcu_dereference_protected_tid_tx(struct
 struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
 			      const u8 *addr);
 
-struct sta_info *sta_info_get_rx(struct ieee80211_sub_if_data *sdata,
-			      const u8 *addr);
-
 struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
 				  const u8 *addr);
 
-struct sta_info *sta_info_get_bss_rx(struct ieee80211_sub_if_data *sdata,
-				  const u8 *addr);
-
 static inline
 void for_each_sta_info_type_check(struct ieee80211_local *local,
 				  const u8 *addr,
@@ -487,23 +476,7 @@ void for_each_sta_info_type_check(struct
 {
 }
 
-#define for_each_sta_info(local, _addr, _sta, nxt) 			\
-	for (	/* initialise loop */					\
-		_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
-		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;	\
-		/* typecheck */						\
-		for_each_sta_info_type_check(local, (_addr), _sta, nxt),\
-		/* continue condition */				\
-		_sta;							\
-		/* advance loop */					\
-		_sta = nxt,						\
-		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL	\
-	     )								\
-	/* run code only if address matches and it's not a dummy sta */	\
-	if (memcmp(_sta->sta.addr, (_addr), ETH_ALEN) == 0 &&		\
-		!_sta->dummy)
-
-#define for_each_sta_info_rx(local, _addr, _sta, nxt)			\
+#define for_each_sta_info(local, _addr, _sta, nxt)			\
 	for (	/* initialise loop */					\
 		_sta = rcu_dereference(local->sta_hash[STA_HASH(_addr)]),\
 		nxt = _sta ? rcu_dereference(_sta->hnext) : NULL;	\
@@ -542,7 +515,6 @@ void sta_info_free(struct ieee80211_loca
  */
 int sta_info_insert(struct sta_info *sta);
 int sta_info_insert_rcu(struct sta_info *sta) __acquires(RCU);
-int sta_info_reinsert(struct sta_info *sta);
 
 int __must_check __sta_info_destroy(struct sta_info *sta);
 int sta_info_destroy_addr(struct ieee80211_sub_if_data *sdata,
net/mac80211/sta_info.c +25 -110

185 lines not on this page · raw message

net/mac80211/mlme.c +3 -12
@@ -1581,7 +1581,7 @@ static bool ieee80211_assoc_success(stru
 	 * station info was already allocated and inserted before
 	 * the association and should be available to us
 	 */
-	sta = sta_info_get_rx(sdata, cbss->bssid);
+	sta = sta_info_get(sdata, cbss->bssid);
 	if (WARN_ON(!sta)) {
 		mutex_unlock(&sdata->local->sta_mtx);
 		return false;
@@ -1648,14 +1648,7 @@ static bool ieee80211_assoc_success(stru
 		return false;
 	}
 
-	/* sta_info_reinsert will also unlock the mutex lock */
-	err = sta_info_reinsert(sta);
-	sta = NULL;
-	if (err) {
-		printk(KERN_DEBUG "%s: failed to insert STA entry for"
-		       " the AP (error %d)\n", sdata->name, err);
-		return false;
-	}
+	mutex_unlock(&sdata->local->sta_mtx);
 
 	/*
 	 * Always handle WMM once after association regardless
@@ -2536,12 +2529,10 @@ static int ieee80211_pre_assoc(struct ie
 	if (!sta)
 		return -ENOMEM;
 
-	sta->dummy = true;
-
 	err = sta_info_insert(sta);
 	sta = NULL;
 	if (err) {
-		printk(KERN_DEBUG "%s: failed to insert Dummy STA entry for"
+		printk(KERN_DEBUG "%s: failed to insert STA entry for"
 		       " the AP (error %d)\n", sdata->name, err);
 		return err;
 	}
net/mac80211/rx.c +9 -4
@@ -859,7 +859,12 @@ ieee80211_rx_h_check(struct ieee80211_rx
 		     rx->sdata->vif.type != NL80211_IFTYPE_ADHOC &&
 		     rx->sdata->vif.type != NL80211_IFTYPE_WDS &&
 		     (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) {
-		if (rx->sta && rx->sta->dummy &&
+		/*
+		 * accept port control frames from the AP even when it's not
+		 * yet marked ASSOC to prevent a race where we don't set the
+		 * assoc bit quickly enough before it sends the first frame
+		 */
+		if (rx->sta && rx->sdata->vif.type == NL80211_IFTYPE_STATION &&
 		    ieee80211_is_data_present(hdr->frame_control)) {
 			u16 ethertype;
 			u8 *payload;
@@ -2953,7 +2958,7 @@ static void __ieee80211_rx_handle_packet
 	if (ieee80211_is_data(fc)) {
 		prev_sta = NULL;
 
-		for_each_sta_info_rx(local, hdr->addr2, sta, tmp) {
+		for_each_sta_info(local, hdr->addr2, sta, tmp) {
 			if (!prev_sta) {
 				prev_sta = sta;
 				continue;
@@ -2997,7 +3002,7 @@ static void __ieee80211_rx_handle_packet
 			continue;
 		}
 
-		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+		rx.sta = sta_info_get_bss(prev, hdr->addr2);
 		rx.sdata = prev;
 		ieee80211_prepare_and_rx_handle(&rx, skb, false);
 
@@ -3005,7 +3010,7 @@ static void __ieee80211_rx_handle_packet
 	}
 
 	if (prev) {
-		rx.sta = sta_info_get_bss_rx(prev, hdr->addr2);
+		rx.sta = sta_info_get_bss(prev, hdr->addr2);
 		rx.sdata = prev;
 
 		if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
author maintainer
#9 lore raw

PATCH 9/11 cfg80211: stop tracking authenticated state

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

To track authenticated state seems to have been a design mistake in cfg80211. It is possible to have out of band authentication (FT), tracking multiple authentications caused more problems than it ever helped, and the implementation in mac80211 is too complex.

Remove all this complexity, and let userspace do whatever it wants to, mac80211 can deal with that just fine. Association is still tracked of course, but authentication no longer is. Local auth state changes are thus no longer of value, so ignore them completely.

This will also help implement SAE -- asking the driver to do an authentication is now almost equivalent to sending an authentication frame, with the exception of shared key authentication which is still handled completely.

---
 Documentation/DocBook/80211.tmpl |    1 
 include/net/cfg80211.h           |   39 +---
 net/mac80211/mlme.c              |   23 --
 net/wireless/core.h              |    9 -
 net/wireless/mlme.c              |  322 ++++++---------------------------------
 net/wireless/nl80211.c           |   18 --
 net/wireless/sme.c               |   41 ----
 7 files changed, 91 insertions(+), 362 deletions(-)
include/net/cfg80211.h +11 -28
@@ -1036,10 +1036,6 @@ const u8 *ieee80211_bss_get_ie(struct cf
  * @key_len: length of WEP key for shared key authentication
  * @key_idx: index of WEP key for shared key authentication
  * @key: WEP key for shared key authentication
- * @local_state_change: This is a request for a local state only, i.e., no
- *	Authentication frame is to be transmitted and authentication state is
- *	to be changed without having to wait for a response from the peer STA
- *	(AP).
  */
 struct cfg80211_auth_request {
 	struct cfg80211_bss *bss;
@@ -1048,7 +1044,6 @@ struct cfg80211_auth_request {
 	enum nl80211_auth_type auth_type;
 	const u8 *key;
 	u8 key_len, key_idx;
-	bool local_state_change;
 };
 
 /**
@@ -1065,7 +1060,11 @@ enum cfg80211_assoc_req_flags {
  *
  * This structure provides information needed to complete IEEE 802.11
  * (re)association.
- * @bss: The BSS to associate with.
+ * @bss: The BSS to associate with. If the call is successful the driver
+ *	is given a reference that it must release, normally via a call to
+ *	cfg80211_send_rx_assoc(), or, if association timed out, with a
+ *	call to cfg80211_put_bss() (in addition to calling
+ *	cfg80211_send_assoc_timeout())
  * @ie: Extra IEs to add to (Re)Association Request frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @use_mfp: Use management frame protection (IEEE 802.11w) in this association
@@ -1093,19 +1092,16 @@ struct cfg80211_assoc_request {
  * This structure provides information needed to complete IEEE 802.11
  * deauthentication.
  *
- * @bss: the BSS to deauthenticate from
+ * @bssid: the BSSID of the BSS to deauthenticate from
  * @ie: Extra IEs to add to Deauthentication frame or %NULL
  * @ie_len: Length of ie buffer in octets
  * @reason_code: The reason code for the deauthentication
- * @local_state_change: This is a request for a local state only, i.e., no
- *	Deauthentication frame is to be transmitted.
  */
 struct cfg80211_deauth_request {
-	struct cfg80211_bss *bss;
+	const u8 *bssid;
 	const u8 *ie;
 	size_t ie_len;
 	u16 reason_code;
-	bool local_state_change;
 };
 
 /**
@@ -2198,8 +2194,6 @@ struct cfg80211_conn;
 struct cfg80211_internal_bss;
 struct cfg80211_cached_keys;
 
-#define MAX_AUTH_BSSES		4
-
 /**
  * struct wireless_dev - wireless per-netdev state
  *
@@ -2263,8 +2257,6 @@ struct wireless_dev {
 	struct list_head event_list;
 	spinlock_t event_lock;
 
-	struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES];
-	struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES];
 	struct cfg80211_internal_bss *current_bss; /* associated / joined */
 	struct ieee80211_channel *channel;
 
@@ -2756,20 +2748,10 @@ void cfg80211_send_rx_auth(struct net_de
 void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr);
 
 /**
- * __cfg80211_auth_canceled - notify cfg80211 that authentication was canceled
- * @dev: network device
- * @addr: The MAC address of the device with which the authentication timed out
- *
- * When a pending authentication had no action yet, the driver may decide
- * to not send a deauth frame, but in that case must calls this function
- * to tell cfg80211 about this decision. It is only valid to call this
- * function within the deauth() callback.
- */
-void __cfg80211_auth_canceled(struct net_device *dev, const u8 *addr);
-
-/**
  * cfg80211_send_rx_assoc - notification of processed association
  * @dev: network device
+ * @bss: the BSS struct association was requested for, the struct reference
+ *	is owned by cfg80211 after this call
  * @buf: (re)association response frame (header + body)
  * @len: length of the frame data
  *
@@ -2778,7 +2760,8 @@ void __cfg80211_auth_canceled(struct net
  * function or cfg80211_send_assoc_timeout() to indicate the result of
  * cfg80211_ops::assoc() call. This function may sleep.
  */
-void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len);
+void cfg80211_send_rx_assoc(struct net_device *dev, struct cfg80211_bss *bss,
+			    const u8 *buf, size_t len);
 
 /**
  * cfg80211_send_assoc_timeout - notification of timed out association
Documentation/DocBook/80211.tmpl +0 -1
@@ -144,7 +144,6 @@ MISSING
 !Finclude/net/cfg80211.h cfg80211_pmksa
 !Finclude/net/cfg80211.h cfg80211_send_rx_auth
 !Finclude/net/cfg80211.h cfg80211_send_auth_timeout
-!Finclude/net/cfg80211.h __cfg80211_auth_canceled
 !Finclude/net/cfg80211.h cfg80211_send_rx_assoc
 !Finclude/net/cfg80211.h cfg80211_send_assoc_timeout
 !Finclude/net/cfg80211.h cfg80211_send_deauth
net/mac80211/mlme.c +8 -15
@@ -2459,9 +2459,6 @@ int ieee80211_mgd_auth(struct ieee80211_
 	struct ieee80211_work *wk;
 	u16 auth_alg;
 
-	if (req->local_state_change)
-		return 0; /* no need to update mac80211 state */
-
 	switch (req->auth_type) {
 	case NL80211_AUTHTYPE_OPEN_SYSTEM:
 		auth_alg = WLAN_AUTH_OPEN;
@@ -2593,7 +2590,7 @@ static enum work_done_result ieee80211_a
 		sta_info_destroy_addr(wk->sdata, cbss->bssid);
 	}
 
-	cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
+	cfg80211_send_rx_assoc(wk->sdata->dev, cbss, skb->data, skb->len);
  destroy:
 	if (wk->assoc.synced)
 		drv_finish_tx_sync(local, wk->sdata, wk->filter_ta,
@@ -2750,13 +2747,12 @@ int ieee80211_mgd_deauth(struct ieee8021
 {
 	struct ieee80211_local *local = sdata->local;
 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
-	u8 bssid[ETH_ALEN];
 	bool assoc_bss = false;
 
 	mutex_lock(&ifmgd->mtx);
 
-	memcpy(bssid, req->bss->bssid, ETH_ALEN);
-	if (ifmgd->associated == req->bss) {
+	if (ifmgd->associated &&
+	    memcmp(ifmgd->associated->bssid, req->bssid, ETH_ALEN) == 0) {
 		ieee80211_set_disassoc(sdata, false, true);
 		mutex_unlock(&ifmgd->mtx);
 		assoc_bss = true;
@@ -2777,7 +2773,7 @@ int ieee80211_mgd_deauth(struct ieee8021
 			    tmp->type != IEEE80211_WORK_ASSOC_BEACON_WAIT)
 				continue;
 
-			if (memcmp(req->bss->bssid, tmp->filter_ta, ETH_ALEN))
+			if (memcmp(req->bssid, tmp->filter_ta, ETH_ALEN))
 				continue;
 
 			not_auth_yet = tmp->type == IEEE80211_WORK_DIRECT_PROBE;
@@ -2811,18 +2807,15 @@ int ieee80211_mgd_deauth(struct ieee8021
 		 * frame, and if it's IDLE we have completed the auth
 		 * process already.
 		 */
-		if (not_auth_yet) {
-			__cfg80211_auth_canceled(sdata->dev, bssid);
+		if (not_auth_yet)
 			return 0;
-		}
 	}
 
 	printk(KERN_DEBUG "%s: deauthenticating from %pM by local choice (reason=%d)\n",
-	       sdata->name, bssid, req->reason_code);
+	       sdata->name, req->bssid, req->reason_code);
 
-	ieee80211_send_deauth_disassoc(sdata, bssid, IEEE80211_STYPE_DEAUTH,
-				       req->reason_code, cookie,
-				       !req->local_state_change);
+	ieee80211_send_deauth_disassoc(sdata, req->bssid, IEEE80211_STYPE_DEAUTH,
+				       req->reason_code, cookie, true);
 	if (assoc_bss)
 		sta_info_flush(sdata->local, sdata);
 
net/wireless/core.h +4 -5
@@ -325,15 +325,13 @@ int __cfg80211_mlme_auth(struct cfg80211
 			 const u8 *bssid,
 			 const u8 *ssid, int ssid_len,
 			 const u8 *ie, int ie_len,
-			 const u8 *key, int key_len, int key_idx,
-			 bool local_state_change);
+			 const u8 *key, int key_len, int key_idx);
 int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
 		       struct net_device *dev, struct ieee80211_channel *chan,
 		       enum nl80211_auth_type auth_type, const u8 *bssid,
 		       const u8 *ssid, int ssid_len,
 		       const u8 *ie, int ie_len,
-		       const u8 *key, int key_len, int key_idx,
-		       bool local_state_change);
+		       const u8 *key, int key_len, int key_idx);
 int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev,
 			  struct ieee80211_channel *chan,
@@ -421,7 +419,8 @@ void __cfg80211_disconnected(struct net_
 			     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);
-void cfg80211_sme_disassoc(struct net_device *dev, int idx);
+void cfg80211_sme_disassoc(struct net_device *dev,
+			   struct cfg80211_internal_bss *bss);
 void __cfg80211_scan_done(struct work_struct *wk);
 void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
 void __cfg80211_sched_scan_results(struct work_struct *wk);
net/wireless/mlme.c +53 -269

494 lines not on this page · raw message

net/wireless/nl80211.c +8 -10
@@ -4078,7 +4078,6 @@ static int nl80211_send_bss(struct sk_bu
 	struct cfg80211_bss *res = &intbss->pub;
 	void *hdr;
 	struct nlattr *bss;
-	int i;
 
 	ASSERT_WDEV_LOCK(wdev);
 
@@ -4131,13 +4130,6 @@ static int nl80211_send_bss(struct sk_bu
 		if (intbss == wdev->current_bss)
 			NLA_PUT_U32(msg, NL80211_BSS_STATUS,
 				    NL80211_BSS_STATUS_ASSOCIATED);
-		else for (i = 0; i < MAX_AUTH_BSSES; i++) {
-			if (intbss != wdev->auth_bsses[i])
-				continue;
-			NLA_PUT_U32(msg, NL80211_BSS_STATUS,
-				    NL80211_BSS_STATUS_AUTHENTICATED);
-			break;
-		}
 		break;
 	case NL80211_IFTYPE_ADHOC:
 		if (intbss == wdev->current_bss)
@@ -4405,10 +4397,16 @@ static int nl80211_authenticate(struct s
 
 	local_state_change = !!info->attrs[NL80211_ATTR_LOCAL_STATE_CHANGE];
 
+	/*
+	 * Since we no longer track auth state, ignore
+	 * requests to only change local state.
+	 */
+	if (local_state_change)
+		return 0;
+
 	return cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
 				  ssid, ssid_len, ie, ie_len,
-				  key.p.key, key.p.key_len, key.idx,
-				  local_state_change);
+				  key.p.key, key.p.key_len, key.idx);
 }
 
 static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
net/wireless/sme.c +7 -34

74 lines not on this page · raw message

author maintainer
#10 lore raw

PATCH 10/11 cfg80211: export cfg80211_ref_bss

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

This is needed by mac80211 to keep a reference
to a BSS alive for the auth process. Remove the
old version of cfg80211_ref_bss() since it's
not actually used.

---
 include/net/cfg80211.h |   14 ++++++++++++++
 net/wireless/core.h    |    5 -----
 net/wireless/scan.c    |   12 ++++++++++++
 3 files changed, 26 insertions(+), 5 deletions(-)
include/net/cfg80211.h +14 -0
@@ -2711,6 +2711,20 @@ struct cfg80211_bss *cfg80211_get_mesh(s
 				       struct ieee80211_channel *channel,
 				       const u8 *meshid, size_t meshidlen,
 				       const u8 *meshcfg);
+/**
+ * cfg80211_ref_bss - reference BSS struct
+ * @bss: the BSS struct to reference
+ *
+ * Increments the refcount of the given BSS struct.
+ */
+void cfg80211_ref_bss(struct cfg80211_bss *bss);
+
+/**
+ * cfg80211_put_bss - unref BSS struct
+ * @bss: the BSS struct
+ *
+ * Decrements the refcount of the given BSS struct.
+ */
 void cfg80211_put_bss(struct cfg80211_bss *bss);
 
 /**
net/wireless/core.h +0 -5
@@ -144,11 +144,6 @@ static inline struct cfg80211_internal_b
 	return container_of(pub, struct cfg80211_internal_bss, pub);
 }
 
-static inline void cfg80211_ref_bss(struct cfg80211_internal_bss *bss)
-{
-	kref_get(&bss->ref);
-}
-
 static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
 {
 	atomic_inc(&bss->hold);
net/wireless/scan.c +12 -0
@@ -861,6 +861,18 @@ cfg80211_inform_bss_frame(struct wiphy *
 }
 EXPORT_SYMBOL(cfg80211_inform_bss_frame);
 
+void cfg80211_ref_bss(struct cfg80211_bss *pub)
+{
+	struct cfg80211_internal_bss *bss;
+
+	if (!pub)
+		return;
+
+	bss = container_of(pub, struct cfg80211_internal_bss, pub);
+	kref_get(&bss->ref);
+}
+EXPORT_SYMBOL(cfg80211_ref_bss);
+
 void cfg80211_put_bss(struct cfg80211_bss *pub)
 {
 	struct cfg80211_internal_bss *bss;
author maintainer
#11 lore raw

PATCH 11/11 mac80211: redesign auth/assoc

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

This is the second part of the auth/assoc redesign, the mac80211 part. This moves the auth/assoc code out of the work abstraction and into the MLME, so that we don't flip channels all the time etc.

The only downside is that when we are associated, we need to drop the association in order to create a connection to another AP, but for most drivers this is actually desirable and the ability to do was never used by any applications. If we want to implement resource reservation with FT-OTA, we'd probably best do it with explicit R-O-C in wpa_s.

---
 net/mac80211/Makefile      |    4 
 net/mac80211/cfg.c         |    6 
 net/mac80211/ieee80211_i.h |   77 +-
 net/mac80211/iface.c       |    4 
 net/mac80211/main.c        |   10 
 net/mac80211/mlme.c        | 1346 +++++++++++++++++++++++++++++++++------------
 net/mac80211/rx.c          |    9 
 net/mac80211/work.c        |  815 ---------------------------
 8 files changed, 1041 insertions(+), 1230 deletions(-)
net/mac80211/ieee80211_i.h +41 -36
@@ -280,10 +280,6 @@ struct mesh_preq_queue {
 
 enum ieee80211_work_type {
 	IEEE80211_WORK_ABORT,
-	IEEE80211_WORK_DIRECT_PROBE,
-	IEEE80211_WORK_AUTH,
-	IEEE80211_WORK_ASSOC_BEACON_WAIT,
-	IEEE80211_WORK_ASSOC,
 	IEEE80211_WORK_REMAIN_ON_CHANNEL,
 	IEEE80211_WORK_OFFCHANNEL_TX,
 };
@@ -316,36 +312,10 @@ struct ieee80211_work {
 	unsigned long timeout;
 	enum ieee80211_work_type type;
 
-	u8 filter_ta[ETH_ALEN];
-
 	bool started;
 
 	union {
 		struct {
-			int tries;
-			u16 algorithm, transaction;
-			u8 ssid[IEEE80211_MAX_SSID_LEN];
-			u8 ssid_len;
-			u8 key[WLAN_KEY_LEN_WEP104];
-			u8 key_len, key_idx;
-			bool privacy;
-			bool synced;
-		} probe_auth;
-		struct {
-			struct cfg80211_bss *bss;
-			const u8 *supp_rates;
-			const u8 *ht_information_ie;
-			enum ieee80211_smps_mode smps;
-			int tries;
-			u16 capability;
-			u8 prev_bssid[ETH_ALEN];
-			u8 ssid[IEEE80211_MAX_SSID_LEN];
-			u8 ssid_len;
-			u8 supp_rates_len;
-			bool wmm_used, use_11n, uapsd_used;
-			bool synced;
-		} assoc;
-		struct {
 			u32 duration;
 		} remain;
 		struct {
@@ -355,9 +325,8 @@ struct ieee80211_work {
 		} offchan_tx;
 	};
 
-	int ie_len;
-	/* must be last */
-	u8 ie[0];
+	size_t data_len;
+	u8 data[];
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -373,6 +342,43 @@ enum ieee80211_sta_flags {
 	IEEE80211_STA_RESET_SIGNAL_AVE	= BIT(9),
 };
 
+struct ieee80211_mgd_auth_data {
+	struct cfg80211_bss *bss;
+	unsigned long timeout;
+	int tries;
+	u16 algorithm, expected_transaction;
+
+	u8 key[WLAN_KEY_LEN_WEP104];
+	u8 key_len, key_idx;
+	bool synced;
+	bool done;
+
+	size_t ie_len;
+	u8 ie[];
+};
+
+struct ieee80211_mgd_assoc_data {
+	struct cfg80211_bss *bss;
+	const u8 *supp_rates;
+	const u8 *ht_information_ie;
+
+	unsigned long timeout;
+	int tries;
+
+	u16 capability;
+	u8 prev_bssid[ETH_ALEN];
+	u8 ssid[IEEE80211_MAX_SSID_LEN];
+	u8 ssid_len;
+	u8 supp_rates_len;
+	bool wmm_used, uapsd_used;
+	bool have_beacon;
+	bool sent_assoc;
+	bool synced;
+
+	size_t ie_len;
+	u8 ie[];
+};
+
 struct ieee80211_if_managed {
 	struct timer_list timer;
 	struct timer_list conn_mon_timer;
@@ -389,6 +395,8 @@ struct ieee80211_if_managed {
 
 	struct mutex mtx;
 	struct cfg80211_bss *associated;
+	struct ieee80211_mgd_auth_data *auth_data;
+	struct ieee80211_mgd_assoc_data *assoc_data;
 
 	u8 bssid[ETH_ALEN];
 
@@ -769,7 +777,6 @@ struct ieee80211_local {
 	struct list_head work_list;
 	struct timer_list work_timer;
 	struct work_struct work_work;
-	struct sk_buff_head work_skb_queue;
 
 	/*
 	 * private workqueue to mac80211. mac80211 makes this accessible
@@ -1436,8 +1443,6 @@ void ieee80211_work_init(struct ieee8021
 void ieee80211_add_work(struct ieee80211_work *wk);
 void free_work(struct ieee80211_work *wk);
 void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata);
-ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata,
-					   struct sk_buff *skb);
 int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata,
 				   struct ieee80211_channel *chan,
 				   enum nl80211_channel_type channel_type,
net/mac80211/mlme.c +988 -358

1,617 lines not on this page · raw message

net/mac80211/rx.c +3 -6
@@ -2488,14 +2488,9 @@ static ieee80211_rx_result debug_noinlin
 ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
 {
 	struct ieee80211_sub_if_data *sdata = rx->sdata;
-	ieee80211_rx_result rxs;
 	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
 	__le16 stype;
 
-	rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb);
-	if (rxs != RX_CONTINUE)
-		return rxs;
-
 	stype = mgmt->frame_control & cpu_to_le16(IEEE80211_FCTL_STYPE);
 
 	if (!ieee80211_vif_is_mesh(&sdata->vif) &&
@@ -2504,10 +2499,13 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
 		return RX_DROP_MONITOR;
 
 	switch (stype) {
+	case cpu_to_le16(IEEE80211_STYPE_AUTH):
 	case cpu_to_le16(IEEE80211_STYPE_BEACON):
 	case cpu_to_le16(IEEE80211_STYPE_PROBE_RESP):
 		/* process for all: mesh, mlme, ibss */
 		break;
+	case cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP):
+	case cpu_to_le16(IEEE80211_STYPE_REASSOC_RESP):
 	case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
 	case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
 		if (is_multicast_ether_addr(mgmt->da) &&
@@ -2519,7 +2517,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_
 			return RX_DROP_MONITOR;
 		break;
 	case cpu_to_le16(IEEE80211_STYPE_PROBE_REQ):
-	case cpu_to_le16(IEEE80211_STYPE_AUTH):
 		/* process only for ibss */
 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
 			return RX_DROP_MONITOR;
net/mac80211/work.c +0 -815

872 lines not on this page · raw message

net/mac80211/Makefile +2 -2
@@ -9,7 +9,7 @@ mac80211-y := \
 	scan.o offchannel.o \
 	ht.o agg-tx.o agg-rx.o \
 	ibss.o \
-	mlme.o work.o \
+	work.o \
 	iface.o \
 	rate.o \
 	michael.o \
@@ -25,7 +25,7 @@ mac80211-y := \
 	wme.o \
 	event.o \
 	chan.o \
-	driver-trace.o
+	driver-trace.o mlme.o
 
 mac80211-$(CONFIG_MAC80211_LEDS) += led.o
 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
net/mac80211/cfg.c +3 -3
@@ -2018,7 +2018,7 @@ ieee80211_offchan_tx_done(struct ieee802
 	if (wk->offchan_tx.wait && !wk->offchan_tx.status)
 		cfg80211_mgmt_tx_status(wk->sdata->dev,
 					(unsigned long) wk->offchan_tx.frame,
-					wk->ie, wk->ie_len, false, GFP_KERNEL);
+					wk->data, wk->data_len, false, GFP_KERNEL);
 
 	return WORK_DONE_DESTROY;
 }
@@ -2169,8 +2169,8 @@ static int ieee80211_mgmt_tx(struct wiph
 	wk->done = ieee80211_offchan_tx_done;
 	wk->offchan_tx.frame = skb;
 	wk->offchan_tx.wait = wait;
-	wk->ie_len = len;
-	memcpy(wk->ie, buf, len);
+	wk->data_len = len;
+	memcpy(wk->data, buf, len);
 
 	ieee80211_add_work(wk);
 	return 0;
net/mac80211/iface.c +3 -1
@@ -1303,7 +1303,9 @@ u32 __ieee80211_recalc_idle(struct ieee8
 
 		/* do not count disabled managed interfaces */
 		if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-		    !sdata->u.mgd.associated) {
+		    !sdata->u.mgd.associated &&
+		    !sdata->u.mgd.auth_data &&
+		    !sdata->u.mgd.assoc_data) {
 			sdata->vif.bss_conf.idle = true;
 			continue;
 		}
net/mac80211/main.c +1 -9
@@ -198,15 +198,7 @@ void ieee80211_bss_info_change_notify(st
 		return;
 
 	if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-		/*
-		 * While not associated, claim a BSSID of all-zeroes
-		 * so that drivers don't do any weird things with the
-		 * BSSID at that time.
-		 */
-		if (sdata->vif.bss_conf.assoc)
-			sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
-		else
-			sdata->vif.bss_conf.bssid = zero;
+		sdata->vif.bss_conf.bssid = sdata->u.mgd.bssid;
 	} else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
 		sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid;
 	else if (sdata->vif.type == NL80211_IFTYPE_AP)
#12 lore raw
In reply to Johannes Berg
Quoted 8 lines · Johannes Berg

This is the combination series of the station management and auth/assoc redesign patches.

Together, they give drivers more flexibility as to when to add the station entry to the device for connections. The auth/assoc redesign also simplifies the connection establishment process.

is this patchset going to get applied soon?
(no rush, i just noticed that newer patches were already applied)

thanks,
Eliad.

author maintainer
#13 lore raw
Quoted 5 lines · Eliad Peller
Quoted 3 lines · Johannes Berg

This is the combination series of the station management and auth/assoc redesign patches.

Quoted 7 lines
Quoted 5 lines

Together, they give drivers more flexibility as to when to add the station entry to the device for connections. The auth/assoc redesign also simplifies the connection establishment process.

is this patchset going to get applied soon?
(no rush, i just noticed that newer patches were already applied)

I haven't kept track, and I have no idea why it wouldn't be?

johannes

#14 lore raw
Quoted 11 lines · Johannes Berg
Quoted 10 lines · Eliad Peller
Quoted 8 lines · Johannes Berg

This is the combination series of the station management and auth/assoc redesign patches.

Together, they give drivers more flexibility as to when to add the station entry to the device for connections. The auth/assoc redesign also simplifies the connection establishment process.

Quoted 4 lines
Quoted 2 lines

is this patchset going to get applied soon?
(no rush, i just noticed that newer patches were already applied)

I haven't kept track, and I have no idea why it wouldn't be?

The patches didn't apply. I haven't taken the time yet to work it out.

If you would like to repost a patchset that applies cleanly on top of the current base, that would probably speed it up. :-)

John

Signature · 2 lines
John W. Linville		Someday the world will need a hero, and you
[email protected]			might be all we have.  Be ready.
author maintainer
#15 lore raw
Quoted 4 lines · John W. Linville

The patches didn't apply. I haven't taken the time yet to work it out.

If you would like to repost a patchset that applies cleanly on top of the current base, that would probably speed it up. :-)

Oh ok, sure, I can do that tonight.

johannes

author maintainer
#16 lore raw
In reply to John W. Linville
Quoted 6 lines · John W. Linville
Quoted 1 line

I haven't kept track, and I have no idea why it wouldn't be?

The patches didn't apply. I haven't taken the time yet to work it out.

If you would like to repost a patchset that applies cleanly on top of the current base, that would probably speed it up. :-)

Ok, so ... you're going to run into issues either way. The reason they don't apply to wireless-next is that I created them on top of wireless-testing, and that has

commit bc4934bc61d0a11fd62c5187ff83645628f8be8b

Author: Johannes Berg <[email protected]>
Date:   Wed Jan 18 14:10:25 2012 +0100

mac80211: fix work removal on deauth request

which my patches are diffed against. I could rediff them against wireless-next, but then you're going to run into merge issues when you try to merge that back -- it may be easier to put the commit above into wireless-next as well to avoid this?

In any case, let me know what you want me to do -- it may have to wait a bit as I'm travelling back home tomorrow, only to leave again on Sunday for more travel.

johannes