diff options
author | Eliad Peller <eliad@wizery.com> | 2011-10-11 07:52:25 -0400 |
---|---|---|
committer | Luciano Coelho <coelho@ti.com> | 2011-10-11 15:24:51 -0400 |
commit | 0f1680147ce2509383e053fa843020e0e9f3c6ce (patch) | |
tree | 575a9799f14fa4c129c7725d2725845926145b9f /drivers/net/wireless/wl12xx | |
parent | ccb62000d5e92772b6d5c2acce2f56263886ed89 (diff) |
wl12xx: handle injected packets
Injected packets are sent with no vif, causing the wl12xx
to NULL-dereference in multiple places.
Furthermore, injected packets are currently not sent at all,
as system_hlid doesn't belong to any specific role, so
wl1271_skb_dequeue() never return its packets.
Handle both these problems.
Reported-by: Luciano Coelho <coelho@ti.com>
Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Luciano Coelho <coelho@ti.com>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r-- | drivers/net/wireless/wl12xx/main.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/wl12xx/tx.c | 27 |
2 files changed, 18 insertions, 16 deletions
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c index a2d16933ccb0..f76be5ad8ab0 100644 --- a/drivers/net/wireless/wl12xx/main.c +++ b/drivers/net/wireless/wl12xx/main.c | |||
@@ -1477,11 +1477,14 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1477 | struct wl1271 *wl = hw->priv; | 1477 | struct wl1271 *wl = hw->priv; |
1478 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 1478 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
1479 | struct ieee80211_vif *vif = info->control.vif; | 1479 | struct ieee80211_vif *vif = info->control.vif; |
1480 | struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); | 1480 | struct wl12xx_vif *wlvif = NULL; |
1481 | unsigned long flags; | 1481 | unsigned long flags; |
1482 | int q, mapping; | 1482 | int q, mapping; |
1483 | u8 hlid; | 1483 | u8 hlid; |
1484 | 1484 | ||
1485 | if (vif) | ||
1486 | wlvif = wl12xx_vif_to_data(vif); | ||
1487 | |||
1485 | mapping = skb_get_queue_mapping(skb); | 1488 | mapping = skb_get_queue_mapping(skb); |
1486 | q = wl1271_tx_get_queue(mapping); | 1489 | q = wl1271_tx_get_queue(mapping); |
1487 | 1490 | ||
@@ -1491,7 +1494,7 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
1491 | 1494 | ||
1492 | /* queue the packet */ | 1495 | /* queue the packet */ |
1493 | if (hlid == WL12XX_INVALID_LINK_ID || | 1496 | if (hlid == WL12XX_INVALID_LINK_ID || |
1494 | !test_bit(hlid, wlvif->links_map)) { | 1497 | (wlvif && !test_bit(hlid, wlvif->links_map))) { |
1495 | wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); | 1498 | wl1271_debug(DEBUG_TX, "DROP skb hlid %d q %d", hlid, q); |
1496 | dev_kfree_skb(skb); | 1499 | dev_kfree_skb(skb); |
1497 | goto out; | 1500 | goto out; |
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c index 27a45e1459c4..c7ad4f5976c5 100644 --- a/drivers/net/wireless/wl12xx/tx.c +++ b/drivers/net/wireless/wl12xx/tx.c | |||
@@ -185,7 +185,7 @@ u8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
185 | { | 185 | { |
186 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 186 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
187 | 187 | ||
188 | if (wl12xx_is_dummy_packet(wl, skb)) | 188 | if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) |
189 | return wl->system_hlid; | 189 | return wl->system_hlid; |
190 | 190 | ||
191 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) | 191 | if (wlvif->bss_type == BSS_TYPE_AP_BSS) |
@@ -264,7 +264,8 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
264 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); | 264 | ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); |
265 | wl->tx_allocated_pkts[ac]++; | 265 | wl->tx_allocated_pkts[ac]++; |
266 | 266 | ||
267 | if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS && | 267 | if (!is_dummy && wlvif && |
268 | wlvif->bss_type == BSS_TYPE_AP_BSS && | ||
268 | test_bit(hlid, wlvif->ap.sta_hlid_map)) | 269 | test_bit(hlid, wlvif->ap.sta_hlid_map)) |
269 | wl->links[hlid].allocated_pkts++; | 270 | wl->links[hlid].allocated_pkts++; |
270 | 271 | ||
@@ -307,7 +308,7 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
307 | desc->start_time = cpu_to_le32(hosttime - wl->time_offset); | 308 | desc->start_time = cpu_to_le32(hosttime - wl->time_offset); |
308 | 309 | ||
309 | is_dummy = wl12xx_is_dummy_packet(wl, skb); | 310 | is_dummy = wl12xx_is_dummy_packet(wl, skb); |
310 | if (is_dummy || wlvif->bss_type != BSS_TYPE_AP_BSS) | 311 | if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) |
311 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); | 312 | desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); |
312 | else | 313 | else |
313 | desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); | 314 | desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); |
@@ -326,14 +327,14 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
326 | TX_HW_ATTR_SESSION_COUNTER; | 327 | TX_HW_ATTR_SESSION_COUNTER; |
327 | 328 | ||
328 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; | 329 | tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; |
329 | } else { | 330 | } else if (wlvif) { |
330 | /* configure the tx attributes */ | 331 | /* configure the tx attributes */ |
331 | tx_attr = wlvif->session_counter << | 332 | tx_attr = wlvif->session_counter << |
332 | TX_HW_ATTR_OFST_SESSION_COUNTER; | 333 | TX_HW_ATTR_OFST_SESSION_COUNTER; |
333 | } | 334 | } |
334 | 335 | ||
335 | desc->hlid = hlid; | 336 | desc->hlid = hlid; |
336 | if (is_dummy) | 337 | if (is_dummy || !wlvif) |
337 | rate_idx = 0; | 338 | rate_idx = 0; |
338 | else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { | 339 | else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { |
339 | /* if the packets are destined for AP (have a STA entry) | 340 | /* if the packets are destined for AP (have a STA entry) |
@@ -446,7 +447,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, | |||
446 | 447 | ||
447 | wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); | 448 | wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); |
448 | 449 | ||
449 | if (!is_dummy && wlvif->bss_type == BSS_TYPE_AP_BSS) { | 450 | if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { |
450 | wl1271_tx_ap_update_inconnection_sta(wl, skb); | 451 | wl1271_tx_ap_update_inconnection_sta(wl, skb); |
451 | wl1271_tx_regulate_link(wl, wlvif, hlid); | 452 | wl1271_tx_regulate_link(wl, wlvif, hlid); |
452 | } | 453 | } |
@@ -623,6 +624,9 @@ static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) | |||
623 | } | 624 | } |
624 | } | 625 | } |
625 | 626 | ||
627 | if (!skb) | ||
628 | skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); | ||
629 | |||
626 | if (!skb && | 630 | if (!skb && |
627 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { | 631 | test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { |
628 | int q; | 632 | int q; |
@@ -716,19 +720,14 @@ void wl1271_tx_work_locked(struct wl1271 *wl) | |||
716 | return; | 720 | return; |
717 | 721 | ||
718 | while ((skb = wl1271_skb_dequeue(wl))) { | 722 | while ((skb = wl1271_skb_dequeue(wl))) { |
723 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
719 | bool has_data = false; | 724 | bool has_data = false; |
720 | 725 | ||
721 | wlvif = NULL; | 726 | wlvif = NULL; |
722 | if (!wl12xx_is_dummy_packet(wl, skb)) { | 727 | if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) |
723 | struct ieee80211_tx_info *info; | 728 | wlvif = wl12xx_vif_to_data(info->control.vif); |
724 | struct ieee80211_vif *vif; | ||
725 | 729 | ||
726 | info = IEEE80211_SKB_CB(skb); | ||
727 | vif = info->control.vif; | ||
728 | wlvif = wl12xx_vif_to_data(vif); | ||
729 | } | ||
730 | has_data = wlvif && wl1271_tx_is_data_present(skb); | 730 | has_data = wlvif && wl1271_tx_is_data_present(skb); |
731 | |||
732 | ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); | 731 | ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); |
733 | if (ret == -EAGAIN) { | 732 | if (ret == -EAGAIN) { |
734 | /* | 733 | /* |