diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-12-11 23:42:49 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 18:06:59 -0500 |
commit | e1258177e437cb8b892622f2b7beedd4701540ac (patch) | |
tree | 35addee654285e88ec1b49526cf3473427500f1e /drivers/net/wireless/libertas/cmdresp.c | |
parent | 06113c1c70349f5f888436ac2af28c707f4602ef (diff) |
libertas: be more careful about command responses matching cur_cmd
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>
Diffstat (limited to 'drivers/net/wireless/libertas/cmdresp.c')
-rw-r--r-- | drivers/net/wireless/libertas/cmdresp.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index bf9941ecc239..53f73c4abdd0 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -611,7 +611,7 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
611 | 611 | ||
612 | default: | 612 | default: |
613 | lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", | 613 | lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n", |
614 | resp->command); | 614 | le16_to_cpu(resp->command)); |
615 | break; | 615 | break; |
616 | } | 616 | } |
617 | lbs_deb_leave(LBS_DEB_HOST); | 617 | lbs_deb_leave(LBS_DEB_HOST); |
@@ -620,17 +620,14 @@ static inline int handle_cmd_response(struct lbs_private *priv, | |||
620 | 620 | ||
621 | int lbs_process_rx_command(struct lbs_private *priv) | 621 | int lbs_process_rx_command(struct lbs_private *priv) |
622 | { | 622 | { |
623 | u16 respcmd; | 623 | uint16_t respcmd, curcmd; |
624 | struct cmd_header *resp; | 624 | struct cmd_header *resp; |
625 | int ret = 0; | 625 | int ret = 0; |
626 | ulong flags; | 626 | unsigned long flags; |
627 | u16 result; | 627 | uint16_t result; |
628 | 628 | ||
629 | lbs_deb_enter(LBS_DEB_HOST); | 629 | lbs_deb_enter(LBS_DEB_HOST); |
630 | 630 | ||
631 | /* Now we got response from FW, cancel the command timer */ | ||
632 | del_timer(&priv->command_timer); | ||
633 | |||
634 | mutex_lock(&priv->lock); | 631 | mutex_lock(&priv->lock); |
635 | spin_lock_irqsave(&priv->driver_lock, flags); | 632 | spin_lock_irqsave(&priv->driver_lock, flags); |
636 | 633 | ||
@@ -640,24 +637,35 @@ int lbs_process_rx_command(struct lbs_private *priv) | |||
640 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 637 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
641 | goto done; | 638 | goto done; |
642 | } | 639 | } |
640 | |||
641 | curcmd = le16_to_cpu(priv->cur_cmd->cmdbuf->command); | ||
642 | |||
643 | resp = priv->cur_cmd->cmdbuf; | 643 | resp = priv->cur_cmd->cmdbuf; |
644 | 644 | ||
645 | respcmd = le16_to_cpu(resp->command); | 645 | respcmd = le16_to_cpu(resp->command); |
646 | result = le16_to_cpu(resp->result); | 646 | result = le16_to_cpu(resp->result); |
647 | 647 | ||
648 | lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n", | 648 | lbs_deb_host("CMD_RESP: response 0x%04x, seq %d, size %d, jiffies %lu\n", |
649 | respcmd, priv->upld_len, jiffies); | 649 | respcmd, le16_to_cpu(resp->seqnum), priv->upld_len, jiffies); |
650 | lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); | 650 | lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", (void *) resp, priv->upld_len); |
651 | 651 | ||
652 | if (!(respcmd & 0x8000)) { | 652 | if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) { |
653 | lbs_deb_host("invalid response!\n"); | 653 | lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n", |
654 | priv->cur_cmd_retcode = -1; | 654 | le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum)); |
655 | __lbs_cleanup_and_insert_cmd(priv, priv->cur_cmd); | ||
656 | priv->cur_cmd = NULL; | ||
657 | spin_unlock_irqrestore(&priv->driver_lock, flags); | 655 | spin_unlock_irqrestore(&priv->driver_lock, flags); |
658 | ret = -1; | 656 | ret = -1; |
659 | goto done; | 657 | goto done; |
660 | } | 658 | } |
659 | if (respcmd != CMD_RET(curcmd) && | ||
660 | respcmd != CMD_802_11_ASSOCIATE && curcmd != CMD_RET_802_11_ASSOCIATE) { | ||
661 | lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd); | ||
662 | spin_unlock_irqrestore(&priv->driver_lock, flags); | ||
663 | ret = -1; | ||
664 | goto done; | ||
665 | } | ||
666 | |||
667 | /* Now we got response from FW, cancel the command timer */ | ||
668 | del_timer(&priv->command_timer); | ||
661 | 669 | ||
662 | /* Store the response code to cur_cmd_retcode. */ | 670 | /* Store the response code to cur_cmd_retcode. */ |
663 | priv->cur_cmd_retcode = result; | 671 | priv->cur_cmd_retcode = result; |