staging: brcm80211: bugfix for div by zero in minstrel_ht_tx_status
authorRoland Vossen <rvossen@broadcom.com>
Tue, 12 Apr 2011 12:34:41 +0000 (14:34 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 3 Jun 2011 00:32:10 +0000 (09:32 +0900)
commit e9c661e08c2a6015c1b7cba1cecefa27a089df71 upstream.

Caused by brcmsmac.ko suppling a 0 value to Mac80211. Mac80211 subsequently
divides by this number. Bug only occurred on AMPDU traffic. This is a fix
for https://bugzilla.kernel.org/show_bug.cgi?id=32032, titled
'Divide error in minstrel_ht_tx_status followed by hang', reported by
Wouter Cloetens.

Signed-off-by: Roland Vossen <rvossen@broadcom.com>
Reviewed-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c

index f008659..f7bff4e 100644 (file)
@@ -1123,21 +1123,12 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                ini->txretry[index] = 0;
 
                                /* ampdu_ack_len: number of acked aggregated frames */
                                ini->txretry[index] = 0;
 
                                /* ampdu_ack_len: number of acked aggregated frames */
-                               /* ampdu_ack_map: block ack bit map for the aggregation */
                                /* ampdu_len: number of aggregated frames */
                                rate_status(wlc, tx_info, txs, mcs);
                                tx_info->flags |= IEEE80211_TX_STAT_ACK;
                                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
                                /* ampdu_len: number of aggregated frames */
                                rate_status(wlc, tx_info, txs, mcs);
                                tx_info->flags |= IEEE80211_TX_STAT_ACK;
                                tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
-
-                               /* XXX TODO: Make these accurate. */
                                tx_info->status.ampdu_ack_len =
                                tx_info->status.ampdu_ack_len =
-                                   (txs->
-                                    status & TX_STATUS_FRM_RTX_MASK) >>
-                                   TX_STATUS_FRM_RTX_SHIFT;
-                               tx_info->status.ampdu_len =
-                                   (txs->
-                                    status & TX_STATUS_FRM_RTX_MASK) >>
-                                   TX_STATUS_FRM_RTX_SHIFT;
+                                       tx_info->status.ampdu_len = 1;
 
                                skb_pull(p, D11_PHY_HDR_LEN);
                                skb_pull(p, D11_TXH_LEN);
 
                                skb_pull(p, D11_PHY_HDR_LEN);
                                skb_pull(p, D11_TXH_LEN);
@@ -1163,6 +1154,8 @@ wlc_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                /* Retry timeout */
                                ini->tx_in_transit--;
                                ieee80211_tx_info_clear_status(tx_info);
                                /* Retry timeout */
                                ini->tx_in_transit--;
                                ieee80211_tx_info_clear_status(tx_info);
+                               tx_info->status.ampdu_ack_len = 0;
+                               tx_info->status.ampdu_len = 1;
                                tx_info->flags |=
                                    IEEE80211_TX_STAT_AMPDU_NO_BACK;
                                skb_pull(p, D11_PHY_HDR_LEN);
                                tx_info->flags |=
                                    IEEE80211_TX_STAT_AMPDU_NO_BACK;
                                skb_pull(p, D11_PHY_HDR_LEN);