[Bug 455] Fix frequent channel change generates firmware fatal error.

Because of the frequent channel change, it is possible that when we are
try to associate with channel 1 (authenticated but not associated).
Another channel change comes at this time, then the driver will issue
disassociate command to the firmware which will cause the fatal error.

It seems that the association/disassociation procedure should not be
interrupted.

The patch attached adds test on STATUS_ASSOCIATING | STATUS_DISASSOCIATING
in ipw_send_cmd(), when ensures that commands will not be sent to firmware
when we are in these two status.

Signed-off-by: Hong Liu <[EMAIL PROTECTED]>
Signed-off-by: Zhu Yi <[EMAIL PROTECTED]>
---
 drivers/net/wireless/ipw2200.c |   31 +++++++++++++++++++++++++------
 1 file changed, 25 insertions(+), 6 deletions(-)
---
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 9ced5b7..4cdb474 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -1884,6 +1884,18 @@ static int ipw_send_cmd(struct ipw_priv 
                return -EAGAIN;
        }
 
+       if (priv->status & STATUS_ASSOCIATING) {
+               IPW_DEBUG_HC("abandon a command while associating\n");
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return -1;
+       }
+
+       if (priv->status & STATUS_DISASSOCIATING) {
+               IPW_DEBUG_HC("abandon a command while disassociating\n");
+               spin_unlock_irqrestore(&priv->lock, flags);
+               return -1;
+       }
+
        priv->status |= STATUS_HCMD_ACTIVE;
 
        if (priv->cmdlog) {
@@ -3671,7 +3683,13 @@ static void ipw_send_disassociate(struct
 {
        int err;
 
-       if (!(priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))) {
+       if (priv->status & STATUS_ASSOCIATING) {
+               IPW_DEBUG_ASSOC("Disassociating while associating.\n");
+               queue_work(priv->workqueue, &priv->disassociate);
+               return;
+       }
+
+       if (!(priv->status & STATUS_ASSOCIATED)) {
                IPW_DEBUG_ASSOC("Disassociating while not associated.\n");
                return;
        }
@@ -3681,9 +3699,6 @@ static void ipw_send_disassociate(struct
                        MAC_ARG(priv->assoc_request.bssid),
                        priv->assoc_request.channel);
 
-       priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
-       priv->status |= STATUS_DISASSOCIATING;
-
        if (quiet)
                priv->assoc_request.assoc_type = HC_DISASSOC_QUIET;
        else
@@ -3695,6 +3710,9 @@ static void ipw_send_disassociate(struct
                return;
        }
 
+       priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
+       priv->status |= STATUS_DISASSOCIATING;
+
 }
 
 static int ipw_disassociate(void *data)
@@ -7625,8 +7643,6 @@ static int ipw_associate_network(struct 
         */
        priv->channel = network->channel;
        memcpy(priv->bssid, network->bssid, ETH_ALEN);
-       priv->status |= STATUS_ASSOCIATING;
-       priv->status &= ~STATUS_SECURITY_UPDATED;
 
        priv->assoc_network = network;
 
@@ -7640,6 +7656,9 @@ static int ipw_associate_network(struct 
                return err;
        }
 
+       priv->status |= STATUS_ASSOCIATING;
+       priv->status &= ~STATUS_SECURITY_UPDATED;
+
        IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
                  escape_essid(priv->essid, priv->essid_len),
                  MAC_ARG(priv->bssid));

-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to