wl1251: enable tx path in monitor mode if necessary for packet injection
[pandora-kernel.git] / drivers / net / wireless / wl1251 / tx.c
index 28121c5..b4761b6 100644 (file)
@@ -28,6 +28,7 @@
 #include "tx.h"
 #include "ps.h"
 #include "io.h"
+#include "event.h"
 
 static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
 {
@@ -50,7 +51,7 @@ static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
                return false;
 }
 
-static int wl1251_tx_path_status(struct wl1251 *wl)
+int wl1251_tx_path_status(struct wl1251 *wl)
 {
        u32 status, addr, data_out_count;
        bool busy;
@@ -277,8 +278,28 @@ static void wl1251_tx_trigger(struct wl1251 *wl)
                TX_STATUS_DATA_OUT_COUNT_MASK;
 }
 
+static void enable_tx_for_packet_injection(struct wl1251 *wl)
+{
+       int ret;
+
+       ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel,
+                             wl->beacon_int, wl->dtim_period);
+       if (ret < 0) {
+               wl1251_warning("join failed");
+               return;
+       }
+
+       ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100);
+       if (ret < 0) {
+               wl1251_warning("join timeout");
+               return;
+       }
+
+       wl->joined = true;
+}
+
 /* caller must hold wl->mutex */
-static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
+int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info;
        int ret = 0;
@@ -287,6 +308,9 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
        info = IEEE80211_SKB_CB(skb);
 
        if (info->control.hw_key) {
+               if (unlikely(wl->monitor_present))
+                       return -EINVAL;
+
                idx = info->control.hw_key->hw_key_idx;
                if (unlikely(wl->default_key != idx)) {
                        ret = wl1251_acx_default_key(wl, idx);
@@ -295,6 +319,10 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
                }
        }
 
+       /* Enable tx path in monitor mode for packet injection */
+       if ((wl->vif == NULL) && !wl->joined)
+               enable_tx_for_packet_injection(wl);
+
        ret = wl1251_tx_path_status(wl);
        if (ret < 0)
                return ret;
@@ -523,6 +551,7 @@ void wl1251_tx_complete(struct wl1251 *wl)
        }
 
        wl->next_tx_complete = result_index;
+       wl->last_io_jiffies = jiffies;
 }
 
 /* caller must hold wl->mutex */