diff options
author | Roland Vossen <rvossen@broadcom.com> | 2011-03-10 11:35:06 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-03-14 11:44:02 -0700 |
commit | 0bf97bb1cff7204111c479c899dae30823314761 (patch) | |
tree | 377f4588342d49b0ef533827e7ae8fa9d10eab48 /drivers/staging/brcm80211 | |
parent | 0789b0033112e301f086f99bd15c7d67c051a51e (diff) |
staging: brcm80211: bugfix for NULL scb ptr dereference
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>
Diffstat (limited to 'drivers/staging/brcm80211')
-rw-r--r-- | drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c index 7f8790d9b817..26dd9b6a8757 100644 --- a/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c +++ b/drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c @@ -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); } |