staging: brcm80211: bugfix for NULL scb ptr dereference
authorRoland Vossen <rvossen@broadcom.com>
Thu, 10 Mar 2011 10:35:06 +0000 (11:35 +0100)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 14 Mar 2011 18:44:02 +0000 (11:44 -0700)
The driver uses a struct called 'scb', this struct is primarily used for AMPDU
functionality and is embedded in struct ieee80211_sta. To increase driver
robustness, the case in which this scb pointer is NULL is now handled graceful.
This paves the way for the next patch in this series.

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 7f8790d9b817c6f3dba8304dfe48e0de20540338..26dd9b6a8757ad6d228dc63496b8b9365f927b93 100644 (file)
@@ -900,13 +900,7 @@ wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
 
        tx_info = IEEE80211_SKB_CB(p);
        ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
-       ASSERT(scb);
-       ASSERT(scb->magic == SCB_MAGIC);
        ASSERT(txs->status & TX_STATUS_AMPDU);
-       scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
-       ASSERT(scb_ampdu);
-       ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
-       ASSERT(ini->scb == scb);
 
        /* BMAC_NOTE: For the split driver, second level txstatus comes later
         * So if the ACK was received then wait for the second level else just
@@ -930,7 +924,33 @@ wlc_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
                s2 = R_REG(&wlc->regs->frmtxstatus2);
        }
 
-       wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
+       if (likely(scb)) {
+               ASSERT(scb->magic == SCB_MAGIC);
+               scb_ampdu = SCB_AMPDU_CUBBY(ampdu, scb);
+               ASSERT(scb_ampdu);
+               ini = SCB_AMPDU_INI(scb_ampdu, p->priority);
+               ASSERT(ini->scb == scb);
+               wlc_ampdu_dotxstatus_complete(ampdu, scb, p, txs, s1, s2);
+       } else {
+               /* loop through all pkts and free */
+               u8 queue = txs->frameid & TXFID_QUEUE_MASK;
+               d11txh_t *txh;
+               u16 mcl;
+               while (p) {
+                       tx_info = IEEE80211_SKB_CB(p);
+                       txh = (d11txh_t *) p->data;
+                       mcl = le16_to_cpu(txh->MacTxControlLow);
+                       ASSERT(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
+                       pkt_buf_free_skb(p);
+                       /* break out if last packet of ampdu */
+                       if (((mcl & TXC_AMPDU_MASK) >> TXC_AMPDU_SHIFT) ==
+                           TXC_AMPDU_LAST)
+                               break;
+                       p = GETNEXTTXP(wlc, queue);
+                       ASSERT(p != NULL);
+               }
+               wlc_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
+       }
        wlc_ampdu_txflowcontrol(wlc, scb_ampdu, ini);
 }