Don't free pending_assoc_req in the association worker, keep it
as is. Free pending_assoc_req at adapter removal time. That way
we always have an already filled-in assoc_req for reassociation.

When we get a MAC level event saying that we've been
de-associated, use the alredy filled in association record to
make a new scan and re-associate.

Also moved wlan_postpone_association_work() and
wlan_cancel_association_work() from a *.h file to the sole user,
into wext.h. Renamed them to libertas_XXX as well.

Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de>
---

I've marked this patch as RFC so that I can get comments on it.

* I'm not sure when to totally clear the assoc req, maybe at
  "ifconfig eth0 down" time?  Maybe it's not needed at all, e.g.
  if "iwconfig eth1 key XXX" sets the key and and
  "ethconfig eth1 key off" completely removes the key in the
  assoc-req, but I haven't checked this yet.

* maybe I should rename "pending_assoc_req" into
  "current_assoc_req" as well?

 drivers/net/wireless/libertas/assoc.c   |    2 -
 drivers/net/wireless/libertas/assoc.h   |   20 +-------------
 drivers/net/wireless/libertas/cmdresp.c |    6 ++++
 drivers/net/wireless/libertas/main.c    |   15 +++++-----
 drivers/net/wireless/libertas/wext.c    |   46 ++++++++++++++++++++-----------
 5 files changed, 45 insertions(+), 44 deletions(-)

diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index ffeec2f..f785b79 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -486,7 +486,6 @@ void libertas_association_worker(struct work_struct *work)
 
 	mutex_lock(&adapter->lock);
 	assoc_req = adapter->pending_assoc_req;
-	adapter->pending_assoc_req = NULL;
 	adapter->in_progress_assoc_req = assoc_req;
 	mutex_unlock(&adapter->lock);
 
@@ -654,7 +653,6 @@ out:
 	mutex_lock(&adapter->lock);
 	adapter->in_progress_assoc_req = NULL;
 	mutex_unlock(&adapter->lock);
-	kfree(assoc_req);
 
 done:
 	lbs_deb_leave(LBS_DEB_ASSOC);
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 5e9c31f..929c9af 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -11,22 +11,4 @@ struct assoc_request * wlan_get_association_request(wlan_adapter *adapter);
 
 void libertas_sync_channel(struct work_struct *work);
 
-#define ASSOC_DELAY (HZ / 2)
-static inline void wlan_postpone_association_work(wlan_private *priv)
-{
-	if (priv->adapter->surpriseremoved)
-		return;
-	cancel_delayed_work(&priv->assoc_work);
-	queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
-}
-
-static inline void wlan_cancel_association_work(wlan_private *priv)
-{
-	cancel_delayed_work(&priv->assoc_work);
-	if (priv->adapter->pending_assoc_req) {
-		kfree(priv->adapter->pending_assoc_req);
-		priv->adapter->pending_assoc_req = NULL;
-	}
-}
-
-#endif /* _WLAN_ASSOC_H */
+#endif
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 93bf63b..e29c46a 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -79,6 +79,12 @@ void libertas_mac_event_disconnected(wlan_private * priv)
 		lbs_deb_cmd("disconnected, so exit PS mode\n");
 		libertas_ps_wakeup(priv, 0);
 	}
+
+	if (adapter->pending_assoc_req) {
+		cancel_delayed_work(&priv->assoc_work);
+		queue_delayed_work(priv->assoc_thread, &priv->assoc_work, HZ / 4);
+	}
+
 	lbs_deb_leave(LBS_DEB_CMD);
 }
 
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 9ccc952..3002d26 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -394,11 +394,17 @@ static int libertas_open(struct net_device *dev)
 static int libertas_dev_close(struct net_device *dev)
 {
 	wlan_private *priv = dev->priv;
+	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
-	netif_carrier_off(priv->dev);
+	mutex_lock(&adapter->lock);
 	priv->open = 0;
+	adapter->connect_status = LIBERTAS_DISCONNECTED;
+	kfree(adapter->pending_assoc_req);
+	adapter->pending_assoc_req = NULL;
+	mutex_unlock(&adapter->lock);
+	netif_carrier_off(priv->dev);
 
 	lbs_deb_leave(LBS_DEB_NET);
 	return 0;
@@ -947,15 +953,10 @@ static void libertas_free_adapter(wlan_private * priv)
 		return;
 	}
 
-	lbs_deb_fw("free command buffer\n");
 	libertas_free_cmd_buffer(priv);
-
-	lbs_deb_fw("free command_timer\n");
 	del_timer(&adapter->command_timer);
-
-	lbs_deb_fw("free scan results table\n");
 	kfree(adapter->networks);
-	adapter->networks = NULL;
+	kfree(adapter->pending_assoc_req);
 
 	/* Free the adapter object itself */
 	lbs_deb_fw("free adapter\n");
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 5922321..fe88b8a 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -21,6 +21,20 @@
 #include "assoc.h"
 
 
+static inline void libertas_postpone_association_work(wlan_private *priv)
+{
+	if (priv->adapter->surpriseremoved)
+		return;
+	cancel_delayed_work(&priv->assoc_work);
+	queue_delayed_work(priv->assoc_thread, &priv->assoc_work, HZ / 2);
+}
+
+static inline void libertas_cancel_association_work(wlan_private *priv)
+{
+	cancel_delayed_work(&priv->assoc_work);
+}
+
+
 /**
  *  @brief Convert mw value to dbm value
  *
@@ -1024,9 +1038,9 @@ static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info,
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 	mutex_unlock(&adapter->lock);
 
@@ -1125,11 +1139,11 @@ static int wlan_set_mode(struct net_device *dev,
 	assoc_req = wlan_get_association_request(adapter);
 	if (!assoc_req) {
 		ret = -ENOMEM;
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	} else {
 		assoc_req->mode = *uwrq;
 		set_bit(ASSOC_FLAG_MODE, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 		lbs_deb_wext("Switching to mode: 0x%x\n", *uwrq);
 	}
 	mutex_unlock(&adapter->lock);
@@ -1410,9 +1424,9 @@ static int wlan_set_encode(struct net_device *dev,
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 	mutex_unlock(&adapter->lock);
 
@@ -1654,9 +1668,9 @@ static int wlan_set_encodeext(struct net_device *dev,
 
 out:
 	if (ret == 0) {
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 	mutex_unlock(&adapter->lock);
 
@@ -1701,9 +1715,9 @@ static int wlan_set_genie(struct net_device *dev,
 out:
 	if (ret == 0) {
 		set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	} else {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 	mutex_unlock(&adapter->lock);
 
@@ -1830,9 +1844,9 @@ out:
 	if (ret == 0) {
 		if (updated)
 			set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	} else if (ret != -EOPNOTSUPP) {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 	mutex_unlock(&adapter->lock);
 
@@ -2018,13 +2032,13 @@ out:
 			memcpy(&assoc_req->ssid, &ssid, IW_ESSID_MAX_SIZE);
 			assoc_req->ssid_len = ssid_len;
 			set_bit(ASSOC_FLAG_SSID, &assoc_req->flags);
-			wlan_postpone_association_work(priv);
+			libertas_postpone_association_work(priv);
 		}
 	}
 
 	/* Cancel the association request if there was an error */
 	if (ret != 0) {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 	}
 
 	mutex_unlock(&adapter->lock);
@@ -2062,13 +2076,13 @@ static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info,
 	/* Get or create the current association request */
 	assoc_req = wlan_get_association_request(adapter);
 	if (!assoc_req) {
-		wlan_cancel_association_work(priv);
+		libertas_cancel_association_work(priv);
 		ret = -ENOMEM;
 	} else {
 		/* Copy the BSSID to the association request */
 		memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN);
 		set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags);
-		wlan_postpone_association_work(priv);
+		libertas_postpone_association_work(priv);
 	}
 
 	mutex_unlock(&adapter->lock);
-- 
1.5.2.1


