diff options
author | Christian Lamparter <chunkeey@web.de> | 2008-12-09 15:07:50 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-12-12 14:02:15 -0500 |
commit | 59651e89187293e88863891b821c7379391ef75c (patch) | |
tree | 1551075914e98552269c83c25ef15be30f59c651 /drivers/net/wireless/p54 | |
parent | b7a530d82cb36bb43901c196039b0fccee3ffcc3 (diff) |
p54: fix oops on faulty devices
This patch fixes an oops when the devices suddenly starts
to receive martian data frames.
bug reference:
http://marc.info/?l=linux-wireless&m=122872280317635&w=2
Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54')
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index fac6b416e9e9..a4e99b02af02 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c | |||
@@ -540,6 +540,14 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
540 | size_t header_len = sizeof(*hdr); | 540 | size_t header_len = sizeof(*hdr); |
541 | u32 tsf32; | 541 | u32 tsf32; |
542 | 542 | ||
543 | /* | ||
544 | * If the device is in a unspecified state we have to | ||
545 | * ignore all data frames. Else we could end up with a | ||
546 | * nasty crash. | ||
547 | */ | ||
548 | if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) | ||
549 | return 0; | ||
550 | |||
543 | if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { | 551 | if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { |
544 | if (priv->filter_flags & FIF_FCSFAIL) | 552 | if (priv->filter_flags & FIF_FCSFAIL) |
545 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; | 553 | rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; |
@@ -608,6 +616,12 @@ void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) | |||
608 | if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) | 616 | if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) |
609 | return; | 617 | return; |
610 | 618 | ||
619 | /* | ||
620 | * don't try to free an already unlinked skb | ||
621 | */ | ||
622 | if (unlikely((!skb->next) || (!skb->prev))) | ||
623 | return; | ||
624 | |||
611 | spin_lock_irqsave(&priv->tx_queue.lock, flags); | 625 | spin_lock_irqsave(&priv->tx_queue.lock, flags); |
612 | info = IEEE80211_SKB_CB(skb); | 626 | info = IEEE80211_SKB_CB(skb); |
613 | range = (void *)info->rate_driver_data; | 627 | range = (void *)info->rate_driver_data; |
@@ -1695,19 +1709,18 @@ static void p54_stop(struct ieee80211_hw *dev) | |||
1695 | struct sk_buff *skb; | 1709 | struct sk_buff *skb; |
1696 | 1710 | ||
1697 | mutex_lock(&priv->conf_mutex); | 1711 | mutex_lock(&priv->conf_mutex); |
1712 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||
1698 | del_timer(&priv->stats_timer); | 1713 | del_timer(&priv->stats_timer); |
1699 | p54_free_skb(dev, priv->cached_stats); | 1714 | p54_free_skb(dev, priv->cached_stats); |
1700 | priv->cached_stats = NULL; | 1715 | priv->cached_stats = NULL; |
1701 | if (priv->cached_beacon) | 1716 | if (priv->cached_beacon) |
1702 | p54_tx_cancel(dev, priv->cached_beacon); | 1717 | p54_tx_cancel(dev, priv->cached_beacon); |
1703 | 1718 | ||
1719 | priv->stop(dev); | ||
1704 | while ((skb = skb_dequeue(&priv->tx_queue))) | 1720 | while ((skb = skb_dequeue(&priv->tx_queue))) |
1705 | kfree_skb(skb); | 1721 | kfree_skb(skb); |
1706 | |||
1707 | priv->cached_beacon = NULL; | 1722 | priv->cached_beacon = NULL; |
1708 | priv->stop(dev); | ||
1709 | priv->tsf_high32 = priv->tsf_low32 = 0; | 1723 | priv->tsf_high32 = priv->tsf_low32 = 0; |
1710 | priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||
1711 | mutex_unlock(&priv->conf_mutex); | 1724 | mutex_unlock(&priv->conf_mutex); |
1712 | } | 1725 | } |
1713 | 1726 | ||