summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/wl12xx/tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/wl12xx/tx.c')
-rw-r--r--drivers/net/wireless/wl12xx/tx.c75
1 files changed, 55 insertions, 20 deletions
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index afc8505..75222a6 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -215,13 +215,29 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
else
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
- /* configure the tx attributes */
- tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-
/* queue (we use same identifiers for tid's and ac's */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
desc->tid = ac;
+ if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+ /*
+ * FW expects the dummy packet to have an invalid session id -
+ * any session id that is different than the one set in the join
+ */
+ tx_attr = ((~wl->session_counter) <<
+ TX_HW_ATTR_OFST_SESSION_COUNTER) &
+ TX_HW_ATTR_SESSION_COUNTER;
+
+ tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
+
+ /* Dummy packets require the TID to be management */
+ desc->tid = WL1271_TID_MGMT;
+ } else {
+ /* configure the tx attributes */
+ tx_attr =
+ wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+ }
+
if (wl->bss_type != BSS_TYPE_AP_BSS) {
desc->aid = hlid;
@@ -587,6 +603,12 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
+ if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+ dev_kfree_skb(skb);
+ wl1271_free_tx_id(wl, id);
+ return;
+ }
+
/* update the TX status info */
if (result->status == TX_SUCCESS) {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
@@ -716,10 +738,15 @@ void wl1271_tx_reset(struct wl1271 *wl)
while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
skb);
- info = IEEE80211_SKB_CB(skb);
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- ieee80211_tx_status(wl->hw, skb);
+
+ if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+ dev_kfree_skb(skb);
+ } else {
+ info = IEEE80211_SKB_CB(skb);
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ ieee80211_tx_status(wl->hw, skb);
+ }
}
}
}
@@ -740,21 +767,29 @@ void wl1271_tx_reset(struct wl1271 *wl)
wl1271_free_tx_id(wl, i);
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
- /* Remove private headers before passing the skb to mac80211 */
- info = IEEE80211_SKB_CB(skb);
- skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
- if (info->control.hw_key &&
- info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
- int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data,
- hdrlen);
- skb_pull(skb, WL1271_TKIP_IV_SPACE);
- }
+ if (skb->pkt_type == TX_PKT_TYPE_DUMMY_REQ) {
+ dev_kfree_skb(skb);
+ } else {
+ /*
+ * Remove private headers before passing the skb to
+ * mac80211
+ */
+ info = IEEE80211_SKB_CB(skb);
+ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+ if (info->control.hw_key &&
+ info->control.hw_key->cipher ==
+ WLAN_CIPHER_SUITE_TKIP) {
+ int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ memmove(skb->data + WL1271_TKIP_IV_SPACE,
+ skb->data, hdrlen);
+ skb_pull(skb, WL1271_TKIP_IV_SPACE);
+ }
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
- ieee80211_tx_status(wl->hw, skb);
+ ieee80211_tx_status(wl->hw, skb);
+ }
}
}