summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Tarnyagin <dmitry.tarnyagin@stericsson.com>2011-07-25 15:19:51 +0200
committerPhilippe LANGLAIS <philippe.langlais@stericsson.com>2011-10-13 09:48:35 +0200
commit7156b971c227804a27a824427d9de8c04f3527c5 (patch)
tree878d35b6bd993ea83ba5e2577764adff9725768e
parentcfb080ee289b8ac17d24f7a9e1f12ea63de7daac (diff)
cw1200: Off-channel sending of action frames is implemented.
Action frames sending is required for P2P group negotiation. Due to firmware limitation TXing is possible only when device is "joined" (logically linked) to the AP. Join with "force" flag is used for sending action frames. Change-Id: Ic52b181f4b22d527dda27d0185b1ecc4ba488efe Signed-off-by: Dmitry Tarnyagin <dmitry.tarnyagin@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/27775 Reviewed-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Tested-by: Bartosz MARKOWSKI <bartosz.markowski@tieto.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/33489 Reviewed-by: Philippe LANGLAIS <philippe.langlais@stericsson.com>
-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)