diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-3945.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 18 |
4 files changed, 46 insertions, 19 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 269b9889e39e..f5d75288bd27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c | |||
@@ -548,6 +548,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
548 | u16 len = le16_to_cpu(rx_hdr->len); | 548 | u16 len = le16_to_cpu(rx_hdr->len); |
549 | struct sk_buff *skb; | 549 | struct sk_buff *skb; |
550 | int ret; | 550 | int ret; |
551 | __le16 fc = hdr->frame_control; | ||
551 | 552 | ||
552 | /* We received data from the HW, so stop the watchdog */ | 553 | /* We received data from the HW, so stop the watchdog */ |
553 | if (unlikely(len + IWL39_RX_FRAME_SIZE > | 554 | if (unlikely(len + IWL39_RX_FRAME_SIZE > |
@@ -580,9 +581,9 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
580 | /* mac80211 currently doesn't support paged SKB. Convert it to | 581 | /* mac80211 currently doesn't support paged SKB. Convert it to |
581 | * linear SKB for management frame and data frame requires | 582 | * linear SKB for management frame and data frame requires |
582 | * software decryption or software defragementation. */ | 583 | * software decryption or software defragementation. */ |
583 | if (ieee80211_is_mgmt(hdr->frame_control) || | 584 | if (ieee80211_is_mgmt(fc) || |
584 | ieee80211_has_protected(hdr->frame_control) || | 585 | ieee80211_has_protected(fc) || |
585 | ieee80211_has_morefrags(hdr->frame_control) || | 586 | ieee80211_has_morefrags(fc) || |
586 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) | 587 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) |
587 | ret = skb_linearize(skb); | 588 | ret = skb_linearize(skb); |
588 | else | 589 | else |
@@ -594,11 +595,15 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
594 | goto out; | 595 | goto out; |
595 | } | 596 | } |
596 | 597 | ||
597 | iwl_update_stats(priv, false, hdr->frame_control, len); | 598 | /* |
599 | * XXX: We cannot touch the page and its virtual memory (pkt) after | ||
600 | * here. It might have already been freed by the above skb change. | ||
601 | */ | ||
598 | 602 | ||
603 | iwl_update_stats(priv, false, fc, len); | ||
599 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 604 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
600 | ieee80211_rx(priv->hw, skb); | ||
601 | 605 | ||
606 | ieee80211_rx(priv->hw, skb); | ||
602 | out: | 607 | out: |
603 | priv->alloc_rxb_page--; | 608 | priv->alloc_rxb_page--; |
604 | rxb->page = NULL; | 609 | rxb->page = NULL; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index a34acb7e44c3..0d3886505205 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -814,8 +814,8 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
814 | if (priv->rx_handlers[pkt->hdr.cmd]) { | 814 | if (priv->rx_handlers[pkt->hdr.cmd]) { |
815 | IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, | 815 | IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, |
816 | i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); | 816 | i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); |
817 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | ||
818 | priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; | 817 | priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; |
818 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | ||
819 | } else { | 819 | } else { |
820 | /* No handling needed */ | 820 | /* No handling needed */ |
821 | IWL_DEBUG_RX(priv, | 821 | IWL_DEBUG_RX(priv, |
@@ -824,11 +824,18 @@ void iwl_rx_handle(struct iwl_priv *priv) | |||
824 | pkt->hdr.cmd); | 824 | pkt->hdr.cmd); |
825 | } | 825 | } |
826 | 826 | ||
827 | /* | ||
828 | * XXX: After here, we should always check rxb->page | ||
829 | * against NULL before touching it or its virtual | ||
830 | * memory (pkt). Because some rx_handler might have | ||
831 | * already taken or freed the pages. | ||
832 | */ | ||
833 | |||
827 | if (reclaim) { | 834 | if (reclaim) { |
828 | /* Invoke any callbacks, transfer the buffer to caller, | 835 | /* Invoke any callbacks, transfer the buffer to caller, |
829 | * and fire off the (possibly) blocking iwl_send_cmd() | 836 | * and fire off the (possibly) blocking iwl_send_cmd() |
830 | * as we reclaim the driver command queue */ | 837 | * as we reclaim the driver command queue */ |
831 | if (rxb && rxb->page) | 838 | if (rxb->page) |
832 | iwl_tx_cmd_complete(priv, rxb); | 839 | iwl_tx_cmd_complete(priv, rxb); |
833 | else | 840 | else |
834 | IWL_WARN(priv, "Claim null rxb?\n"); | 841 | IWL_WARN(priv, "Claim null rxb?\n"); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index cfc31ae4712b..e5339c9ad13e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -241,6 +241,7 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) | |||
241 | struct iwl_rx_mem_buffer *rxb; | 241 | struct iwl_rx_mem_buffer *rxb; |
242 | struct page *page; | 242 | struct page *page; |
243 | unsigned long flags; | 243 | unsigned long flags; |
244 | gfp_t gfp_mask = priority; | ||
244 | 245 | ||
245 | while (1) { | 246 | while (1) { |
246 | spin_lock_irqsave(&rxq->lock, flags); | 247 | spin_lock_irqsave(&rxq->lock, flags); |
@@ -251,13 +252,13 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority) | |||
251 | spin_unlock_irqrestore(&rxq->lock, flags); | 252 | spin_unlock_irqrestore(&rxq->lock, flags); |
252 | 253 | ||
253 | if (rxq->free_count > RX_LOW_WATERMARK) | 254 | if (rxq->free_count > RX_LOW_WATERMARK) |
254 | priority |= __GFP_NOWARN; | 255 | gfp_mask |= __GFP_NOWARN; |
255 | 256 | ||
256 | if (priv->hw_params.rx_page_order > 0) | 257 | if (priv->hw_params.rx_page_order > 0) |
257 | priority |= __GFP_COMP; | 258 | gfp_mask |= __GFP_COMP; |
258 | 259 | ||
259 | /* Alloc a new receive buffer */ | 260 | /* Alloc a new receive buffer */ |
260 | page = alloc_pages(priority, priv->hw_params.rx_page_order); | 261 | page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); |
261 | if (!page) { | 262 | if (!page) { |
262 | if (net_ratelimit()) | 263 | if (net_ratelimit()) |
263 | IWL_DEBUG_INFO(priv, "alloc_pages failed, " | 264 | IWL_DEBUG_INFO(priv, "alloc_pages failed, " |
@@ -922,6 +923,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
922 | { | 923 | { |
923 | struct sk_buff *skb; | 924 | struct sk_buff *skb; |
924 | int ret = 0; | 925 | int ret = 0; |
926 | __le16 fc = hdr->frame_control; | ||
925 | 927 | ||
926 | /* We only process data packets if the interface is open */ | 928 | /* We only process data packets if the interface is open */ |
927 | if (unlikely(!priv->is_open)) { | 929 | if (unlikely(!priv->is_open)) { |
@@ -946,9 +948,9 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
946 | /* mac80211 currently doesn't support paged SKB. Convert it to | 948 | /* mac80211 currently doesn't support paged SKB. Convert it to |
947 | * linear SKB for management frame and data frame requires | 949 | * linear SKB for management frame and data frame requires |
948 | * software decryption or software defragementation. */ | 950 | * software decryption or software defragementation. */ |
949 | if (ieee80211_is_mgmt(hdr->frame_control) || | 951 | if (ieee80211_is_mgmt(fc) || |
950 | ieee80211_has_protected(hdr->frame_control) || | 952 | ieee80211_has_protected(fc) || |
951 | ieee80211_has_morefrags(hdr->frame_control) || | 953 | ieee80211_has_morefrags(fc) || |
952 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) | 954 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG) |
953 | ret = skb_linearize(skb); | 955 | ret = skb_linearize(skb); |
954 | else | 956 | else |
@@ -960,7 +962,12 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | |||
960 | goto out; | 962 | goto out; |
961 | } | 963 | } |
962 | 964 | ||
963 | iwl_update_stats(priv, false, hdr->frame_control, len); | 965 | /* |
966 | * XXX: We cannot touch the page and its virtual memory (hdr) after | ||
967 | * here. It might have already been freed by the above skb change. | ||
968 | */ | ||
969 | |||
970 | iwl_update_stats(priv, false, fc, len); | ||
964 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | 971 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); |
965 | 972 | ||
966 | ieee80211_rx(priv->hw, skb); | 973 | ieee80211_rx(priv->hw, skb); |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5977a57a234c..8b08bdc10bc9 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -1124,6 +1124,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) | |||
1124 | struct iwl_rx_mem_buffer *rxb; | 1124 | struct iwl_rx_mem_buffer *rxb; |
1125 | struct page *page; | 1125 | struct page *page; |
1126 | unsigned long flags; | 1126 | unsigned long flags; |
1127 | gfp_t gfp_mask = priority; | ||
1127 | 1128 | ||
1128 | while (1) { | 1129 | while (1) { |
1129 | spin_lock_irqsave(&rxq->lock, flags); | 1130 | spin_lock_irqsave(&rxq->lock, flags); |
@@ -1135,13 +1136,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority) | |||
1135 | spin_unlock_irqrestore(&rxq->lock, flags); | 1136 | spin_unlock_irqrestore(&rxq->lock, flags); |
1136 | 1137 | ||
1137 | if (rxq->free_count > RX_LOW_WATERMARK) | 1138 | if (rxq->free_count > RX_LOW_WATERMARK) |
1138 | priority |= __GFP_NOWARN; | 1139 | gfp_mask |= __GFP_NOWARN; |
1139 | 1140 | ||
1140 | if (priv->hw_params.rx_page_order > 0) | 1141 | if (priv->hw_params.rx_page_order > 0) |
1141 | priority |= __GFP_COMP; | 1142 | gfp_mask |= __GFP_COMP; |
1142 | 1143 | ||
1143 | /* Alloc a new receive buffer */ | 1144 | /* Alloc a new receive buffer */ |
1144 | page = alloc_pages(priority, priv->hw_params.rx_page_order); | 1145 | page = alloc_pages(gfp_mask, priv->hw_params.rx_page_order); |
1145 | if (!page) { | 1146 | if (!page) { |
1146 | if (net_ratelimit()) | 1147 | if (net_ratelimit()) |
1147 | IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); | 1148 | IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n"); |
@@ -1410,8 +1411,8 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
1410 | if (priv->rx_handlers[pkt->hdr.cmd]) { | 1411 | if (priv->rx_handlers[pkt->hdr.cmd]) { |
1411 | IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, | 1412 | IWL_DEBUG_RX(priv, "r = %d, i = %d, %s, 0x%02x\n", r, i, |
1412 | get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); | 1413 | get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); |
1413 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | ||
1414 | priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; | 1414 | priv->isr_stats.rx_handlers[pkt->hdr.cmd]++; |
1415 | priv->rx_handlers[pkt->hdr.cmd] (priv, rxb); | ||
1415 | } else { | 1416 | } else { |
1416 | /* No handling needed */ | 1417 | /* No handling needed */ |
1417 | IWL_DEBUG_RX(priv, | 1418 | IWL_DEBUG_RX(priv, |
@@ -1420,11 +1421,18 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) | |||
1420 | pkt->hdr.cmd); | 1421 | pkt->hdr.cmd); |
1421 | } | 1422 | } |
1422 | 1423 | ||
1424 | /* | ||
1425 | * XXX: After here, we should always check rxb->page | ||
1426 | * against NULL before touching it or its virtual | ||
1427 | * memory (pkt). Because some rx_handler might have | ||
1428 | * already taken or freed the pages. | ||
1429 | */ | ||
1430 | |||
1423 | if (reclaim) { | 1431 | if (reclaim) { |
1424 | /* Invoke any callbacks, transfer the buffer to caller, | 1432 | /* Invoke any callbacks, transfer the buffer to caller, |
1425 | * and fire off the (possibly) blocking iwl_send_cmd() | 1433 | * and fire off the (possibly) blocking iwl_send_cmd() |
1426 | * as we reclaim the driver command queue */ | 1434 | * as we reclaim the driver command queue */ |
1427 | if (rxb && rxb->page) | 1435 | if (rxb->page) |
1428 | iwl_tx_cmd_complete(priv, rxb); | 1436 | iwl_tx_cmd_complete(priv, rxb); |
1429 | else | 1437 | else |
1430 | IWL_WARN(priv, "Claim null rxb?\n"); | 1438 | IWL_WARN(priv, "Claim null rxb?\n"); |