summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/cw1200/queue.c8
-rw-r--r--drivers/staging/cw1200/sta.c56
-rw-r--r--drivers/staging/cw1200/wsm.c11
-rw-r--r--drivers/staging/cw1200/wsm.h11
4 files changed, 59 insertions, 27 deletions
diff --git a/drivers/staging/cw1200/queue.c b/drivers/staging/cw1200/queue.c
index f81e46cd4f4..4140981eed1 100644
--- a/drivers/staging/cw1200/queue.c
+++ b/drivers/staging/cw1200/queue.c
@@ -319,7 +319,7 @@ int cw1200_queue_requeue(struct cw1200_queue *queue, u32 packetID)
item->packetID = cw1200_queue_make_packet_id(
queue_generation, queue_id, item_generation, item_id);
wsm->packetID = __cpu_to_le32(item->packetID);
- list_move_tail(&item->head, &queue->queue);
+ list_move(&item->head, &queue->queue);
}
spin_unlock_bh(&queue->lock);
return ret;
@@ -330,8 +330,8 @@ int cw1200_queue_requeue_all(struct cw1200_queue *queue)
struct cw1200_queue_stats *stats = queue->stats;
spin_lock_bh(&queue->lock);
while (!list_empty(&queue->pending)) {
- struct cw1200_queue_item *item = list_first_entry(
- &queue->pending, struct cw1200_queue_item, head);
+ struct cw1200_queue_item *item = list_entry(
+ queue->pending.prev, struct cw1200_queue_item, head);
struct wsm_tx *wsm = (struct wsm_tx *)item->skb->data;
--queue->num_pending;
@@ -347,7 +347,7 @@ int cw1200_queue_requeue_all(struct cw1200_queue *queue)
queue->generation, queue->queue_id,
item->generation, item - queue->pool);
wsm->packetID = __cpu_to_le32(item->packetID);
- list_move_tail(&item->head, &queue->queue);
+ list_move(&item->head, &queue->queue);
}
spin_unlock_bh(&queue->lock);
diff --git a/drivers/staging/cw1200/sta.c b/drivers/staging/cw1200/sta.c
index 9cb801acefb..4923e9dd22f 100644
--- a/drivers/staging/cw1200/sta.c
+++ b/drivers/staging/cw1200/sta.c
@@ -922,31 +922,45 @@ void cw1200_join_work(struct work_struct *work)
struct cw1200_common *priv =
container_of(work, struct cw1200_common, join_work);
const struct wsm_tx *wsm = priv->join_pending_frame;
- const u8 *frame = (u8 *)&wsm[1];
- const u8 *bssid = &frame[4]; /* AP SSID in a 802.11 frame */
+ const struct ieee80211_hdr *frame = (struct ieee80211_hdr *)&wsm[1];
+ const u8 *bssid = &frame->addr1[0]; /* AP SSID in a 802.11 frame */
struct cfg80211_bss *bss;
- const u8 *ssidie;
- const u8 *dtimie;
+ const u8 *ssidie = NULL;
+ const u8 *dtimie = NULL;
const struct ieee80211_tim_ie *tim = NULL;
- u8 queueId = wsm_queue_id_to_linux(wsm->queueId);
+ u8 queueId;
+ bool action;
+
+ BUG_ON(!wsm);
+ BUG_ON(!priv->channel);
+
+ queueId = wsm_queue_id_to_linux(wsm->queueId);
+ action = ieee80211_is_action(frame->frame_control);
+
+ if (unlikely(priv->join_status == CW1200_JOIN_STATUS_STA)) {
+ wsm_lock_tx(priv);
+ cw1200_unjoin_work(&priv->unjoin_work);
+ }
cancel_delayed_work_sync(&priv->join_timeout);
bss = cfg80211_get_bss(priv->hw->wiphy, NULL, bssid, NULL, 0, 0, 0);
- if (!bss) {
+ if (!bss && !action) {
priv->join_pending_frame = NULL;
cw1200_queue_remove(&priv->tx_queue[queueId],
priv, __le32_to_cpu(wsm->packetID));
+ wsm_unlock_tx(priv);
return;
+ } else if (bss) {
+ ssidie = cfg80211_find_ie(WLAN_EID_SSID,
+ bss->information_elements,
+ bss->len_information_elements);
+ dtimie = cfg80211_find_ie(WLAN_EID_TIM,
+ bss->information_elements,
+ bss->len_information_elements);
+ if (dtimie)
+ tim = (struct ieee80211_tim_ie *)&dtimie[2];
}
- ssidie = cfg80211_find_ie(WLAN_EID_SSID,
- bss->information_elements,
- bss->len_information_elements);
- dtimie = cfg80211_find_ie(WLAN_EID_TIM,
- bss->information_elements,
- bss->len_information_elements);
- if (dtimie)
- tim = (struct ieee80211_tim_ie *)&dtimie[2];
mutex_lock(&priv->conf_mutex);
{
@@ -969,9 +983,16 @@ void cw1200_join_work(struct work_struct *work)
join.dtimPeriod);
}
+ if (action) {
+ join.probeForJoin = 0;
+ join.flags |= WSM_JOIN_FLAGS_UNSYNCRONIZED |
+ WSM_JOIN_FLAGS_FORCE;
+ } else {
+ WARN_ON(wsm_set_block_ack_policy(priv,
+ priv->ba_tid_mask, priv->ba_tid_mask));
+ }
+
priv->join_pending_frame = NULL;
- BUG_ON(!wsm);
- BUG_ON(!priv->channel);
join.channelNumber = priv->channel->hw_value;
join.band = (priv->channel->band == IEEE80211_BAND_5GHZ) ?
@@ -989,9 +1010,6 @@ void cw1200_join_work(struct work_struct *work)
wsm_flush_tx(priv);
- WARN_ON(wsm_set_block_ack_policy(priv,
- priv->ba_tid_mask, priv->ba_tid_mask));
-
/* Queue unjoin if not associated in 3 sec. */
queue_delayed_work(priv->workqueue,
&priv->join_timeout, 3 * HZ);
diff --git a/drivers/staging/cw1200/wsm.c b/drivers/staging/cw1200/wsm.c
index 6f40934ed8f..4db5129394e 100644
--- a/drivers/staging/cw1200/wsm.c
+++ b/drivers/staging/cw1200/wsm.c
@@ -1260,7 +1260,14 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
sizeof(priv->join_bssid)))) {
if (ieee80211_is_auth(fctl))
action = doJoin;
- else
+ else if (ieee80211_is_probe_req(fctl))
+ action = doTx;
+ else if (ieee80211_is_action(fctl)) {
+ if (priv->join_status)
+ action = doTx;
+ else
+ action = doJoin;
+ } else
action = doDrop;
}
break;
@@ -1344,8 +1351,6 @@ static bool wsm_handle_tx_data(struct cw1200_common *priv,
* in FW: it can't do RX/TX before "join".
* "Join" here is not an association,
* but just a syncronization between AP and STA.
- * BTW that means device can't receive frames
- * in monitor mode.
* priv->join_status is used only in bh thread and does
* not require protection */
wsm_printk(KERN_DEBUG "[WSM] Issue join command.\n");
diff --git a/drivers/staging/cw1200/wsm.h b/drivers/staging/cw1200/wsm.h
index 8a861f918ad..55792c4b3c8 100644
--- a/drivers/staging/cw1200/wsm.h
+++ b/drivers/staging/cw1200/wsm.h
@@ -284,7 +284,16 @@ struct cw1200_common;
/* Join flags */
/* Unsynchronized */
-#define WSM_JOIN_FLAGS_UNSYNCRONIZED (1)
+#define WSM_JOIN_FLAGS_UNSYNCRONIZED BIT(0)
+/* The BSS owner is a P2P GO */
+#define WSM_JOIN_FLAGS_P2P_GO BIT(1)
+/* Force to join BSS with the BSSID and the
+ * SSID specified without waiting for beacons. The
+ * ProbeForJoin parameter is ignored. */
+#define WSM_JOIN_FLAGS_FORCE BIT(2)
+/* Give probe request/response higher
+ * priority over the BT traffic */
+#define WSM_JOIN_FLAGS_PRIO BIT(3)
/* Key types */
#define WSM_KEY_TYPE_WEP_DEFAULT (0)