]> err.no Git - linux-2.6/commitdiff
libertas: be more careful about command responses matching cur_cmd
authorDavid Woodhouse <dwmw2@infradead.org>
Wed, 12 Dec 2007 04:42:49 +0000 (23:42 -0500)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:06:59 +0000 (15:06 -0800)
Especially in the light of OLPC trac #5461, in which the firmware starts
sending us seemingly random command responses which bear little relation
to the command we sent it.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/main.c

index 1cb42dc90010802ff3f023be9fd1b5586aa9db77..5ddb46a477a4c505d215e78a2e4f2426516f2b7a 100644 (file)
@@ -1216,8 +1216,8 @@ static int DownloadcommandToStation(struct lbs_private *priv,
        cmdsize = le16_to_cpu(cmd->size);
        command = le16_to_cpu(cmd->command);
 
-       lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
-                   command, cmdsize, jiffies);
+       lbs_deb_host("DNLD_CMD: command 0x%04x, seq %d, size %d, jiffies %lu\n",
+                    command, le16_to_cpu(cmd->seqnum), cmdsize, jiffies);
        lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", (void *) cmdnode->cmdbuf, cmdsize);
 
        cmdnode->cmdwaitqwoken = 0;
index bf9941ecc23960d561fd35847373bea7f884a908..53f73c4abdd0a28b63b2d1686de9c8c6b43be853 100644 (file)
@@ -611,7 +611,7 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 
        default:
                lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
-                           resp->command);
+                            le16_to_cpu(resp->command));
                break;
        }
        lbs_deb_leave(LBS_DEB_HOST);
@@ -620,17 +620,14 @@ static inline int handle_cmd_response(struct lbs_private *priv,
 
 int lbs_process_rx_command(struct lbs_private *priv)
 {
-       u16 respcmd;
+       uint16_t respcmd, curcmd;
        struct cmd_header *resp;
        int ret = 0;
-       ulong flags;
-       u16 result;
+       unsigned long flags;
+       uint16_t result;
 
        lbs_deb_enter(LBS_DEB_HOST);
 
-       /* Now we got response from FW, cancel the command timer */
-       del_timer(&priv->command_timer);
-
        mutex_lock(&priv->lock);
        spin_lock_irqsave(&priv->driver_lock, flags);
 
@@ -640,24 +637,35 @@ int lbs_process_rx_command(struct lbs_private *priv)
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                goto done;
        }
+
+       curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command);
+
        resp = priv->cur_cmd->cmdbuf;
 
        respcmd = le16_to_cpu(resp->command);
        result = le16_to_cpu(resp->result);
 
-       lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
-               respcmd, priv->upld_len, jiffies);
+       lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n",
+                    respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies);
        lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len);
 
-       if (!(respcmd & 0x8000)) {
-               lbs_deb_host("invalid response!\n");
-               priv->cur_cmd_retcode = -1;
-               __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd);
-               priv->cur_cmd = NULL;
+       if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
+               lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
+                           le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
                spin_unlock_irqrestore(&priv->driver_lock, flags);
                ret = -1;
                goto done;
        }
+       if (respcmd != CMD_RET(curcmd) &&
+           respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) {
+               lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
+               spin_unlock_irqrestore(&priv->driver_lock, flags);
+               ret = -1;
+               goto done;
+       }
+
+       /* Now we got response from FW, cancel the command timer */
+       del_timer(&priv->command_timer);
 
        /* Store the response code to cur_cmd_retcode. */
        priv->cur_cmd_retcode = result;
index 02192e8a15ea1a9a2a04663565a885d4fbb9efea..6b8ac62e6f9aca50fbcd8c0716019dc836962079 100644 (file)
@@ -643,6 +643,7 @@ static inline void process_cmdrequest(int recvlength, u8 *recvbuff,
        /* take care of cur_cmd = NULL case by reading the
         * data to clear the interrupt */
        if (!priv->cur_cmd) {
+               lbs_deb_hex(LBS_DEB_HOST, "Unsolicited CMD_RESP", (void *) recvbuff + MESSAGE_HEADER_LEN, priv->upld_len);
                cmdbuf = priv->upld_buf;
                priv->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
        } else
index bb685ac8e15e15bb519fb7bc2d7eaf9d5528bce3..cdf5934aaf8bafc7cb4cc60790eb25223bfd1a91 100644 (file)
@@ -893,7 +893,7 @@ static void command_timer_fn(unsigned long data)
                return;
        }
 
-       lbs_deb_fw("command_timer_fn fired, cmd %x\n", node->cmdbuf->command);
+       lbs_pr_info("command %x timed out\n", le16_to_cpu(node->cmdbuf->command));
 
        if (!priv->fw_ready)
                return;