public inbox for linux-wireless@vger.kernel.org
 help / color / mirror / Atom feed
* p54 problem with PS
@ 2009-04-15 19:24 Johannes Berg
  2009-04-16 19:57 ` Christian Lamparter
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2009-04-15 19:24 UTC (permalink / raw)
  To: linux-wireless; +Cc: Christian Lamparter


[-- Attachment #1.1: Type: text/plain, Size: 516 bytes --]

Right after associating, the AP sends us the EAPOL frame. We miss that
frame, due to a race condition (we add the STA info for the AP a little
too late and drop the frame because we don't know who it is from).

The AP of course retries the frame, a little later, but p54 misses the
TIM bit -- see the ps.pkt file.

We should probably make that race window smaller somehow (stop the
tasklet that is processing RX while processing assoc frames maybe?) but
this is clearly foremost a p54 problem.

johannes

[-- Attachment #1.2: ps.pkt --]
[-- Type: application/octet-stream, Size: 8286 bytes --]

[-- Attachment #1.3: nops.pkt --]
[-- Type: application/octet-stream, Size: 11484 bytes --]

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: p54 problem with PS
  2009-04-15 19:24 p54 problem with PS Johannes Berg
@ 2009-04-16 19:57 ` Christian Lamparter
  2009-04-16 20:18   ` Johannes Berg
  0 siblings, 1 reply; 6+ messages in thread
From: Christian Lamparter @ 2009-04-16 19:57 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

[-- Attachment #1: Type: text/plain, Size: 1602 bytes --]

On Wednesday 15 April 2009 21:24:55 Johannes Berg wrote:
> Right after associating, the AP sends us the EAPOL frame. We miss that
> frame, due to a race condition (we add the STA info for the AP a little
> too late and drop the frame because we don't know who it is from).
> 
> The AP of course retries the frame, a little later, but p54 misses the
> TIM bit -- see the ps.pkt file.
> 
> We should probably make that race window smaller somehow (stop the
> tasklet that is processing RX while processing assoc frames maybe?) but
> this is clearly foremost a p54 problem.

Well, I guess I figured out what's wrong: the hw spec.
So this patch might work on PCI & USB, but could break SPI devices.

Johannes, can you please test the attached patch?

BTW: there might be two problems:
1. if the timeout is too low the device might be fast enough to go into ps:
  -  either before sending a probe request
   (firmware reports tx_status TX_PSM, so the frame wasn't sent at all)
  - or the AP got the request and responded... 
    But the frame was lost, because probe responds are not buffered...

2. there was something wrong in ieee80211_rx_mgmt_beacon
    Sometimes the TIM was parsed, but thanks to
    local->hw.conf.dynamic_ps_timeout == 0
    mac80211 didn't issue a wakeup => so no data => disconnect

    But this bug maybe comes from the old RFCs from yesterday,
    as I didn't tried the final version yet...

Oh and one question:
Some time ago, I found some useful function that converted beacon_int TUs <-> msec,
do we still have them somewhere around and I'm just (temp) blind ?

Regards,
	Chr

[-- Attachment #2: p54ps-test.diff --]
[-- Type: text/x-patch, Size: 1677 bytes --]

diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index d6354fa..482071b 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -181,6 +181,7 @@ struct p54_common {
 	u32 tsf_low32, tsf_high32;
 	u32 basic_rate_mask;
 	u16 aid;
+	unsigned long beacon_timeout_guard;
 	struct sk_buff *cached_beacon;
 
 	/* cryptographic engine information */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index ad2503a..0bd5e73 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -1058,7 +1058,8 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
 			wiphy_name(dev->wiphy), freq);
 		break;
 	case P54_TRAP_NO_BEACON:
-		if (priv->vif)
+		if (time_after(priv->beacon_timeout_guard, jiffies) &&
+		    priv->vif)
 			ieee80211_beacon_loss(priv->vif);
 		break;
 	case P54_TRAP_SCAN:
@@ -1941,10 +1942,12 @@ static int p54_set_ps(struct ieee80211_hw *dev)
 	u16 mode;
 	int i;
 
-	if (dev->conf.flags & IEEE80211_CONF_PS)
+	if (dev->conf.flags & IEEE80211_CONF_PS) {
 		mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
 		       P54_PSM_CHECKSUM | P54_PSM_MCBC;
-	else
+		priv->beacon_timeout_guard = jiffies + msecs_to_jiffies(
+						priv->hw->conf.beacon_int);
+	} else
 		mode = P54_PSM_CAM;
 
 	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
@@ -1963,8 +1966,8 @@ static int p54_set_ps(struct ieee80211_hw *dev)
 
 	psm->beacon_rssi_skip_max = 200;
 	psm->rssi_delta_threshold = 0;
-	psm->nr = 10;
-	psm->exclude[0] = 0;
+	psm->nr = 1;
+	psm->exclude[0] = WLAN_EID_TIM;
 
 	priv->tx(dev, skb);
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: p54 problem with PS
  2009-04-16 19:57 ` Christian Lamparter
@ 2009-04-16 20:18   ` Johannes Berg
  2009-04-17 11:56     ` Christian Lamparter
  0 siblings, 1 reply; 6+ messages in thread
From: Johannes Berg @ 2009-04-16 20:18 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Kalle Valo

[-- Attachment #1: Type: text/plain, Size: 1285 bytes --]


> Well, I guess I figured out what's wrong: the hw spec.
> So this patch might work on PCI & USB, but could break SPI devices.

Heh.

> Johannes, can you please test the attached patch?
> 
> BTW: there might be two problems:
> 1. if the timeout is too low the device might be fast enough to go into ps:
>   -  either before sending a probe request
>    (firmware reports tx_status TX_PSM, so the frame wasn't sent at all)
>   - or the AP got the request and responded... 
>     But the frame was lost, because probe responds are not buffered...

?

> 2. there was something wrong in ieee80211_rx_mgmt_beacon
>     Sometimes the TIM was parsed, but thanks to
>     local->hw.conf.dynamic_ps_timeout == 0
>     mac80211 didn't issue a wakeup => so no data => disconnect
> 
>     But this bug maybe comes from the old RFCs from yesterday,
>     as I didn't tried the final version yet...

I didn't change that -- Kalle did that, see the comment there. I guess
we need to change that then.

> Oh and one question:
> Some time ago, I found some useful function that converted beacon_int TUs <-> msec,
> do we still have them somewhere around and I'm just (temp) blind ?

I just added TU -> msec in one of my patches to include/linux/ieee8021.h

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: p54 problem with PS
  2009-04-16 20:18   ` Johannes Berg
@ 2009-04-17 11:56     ` Christian Lamparter
  2009-04-17 12:08       ` Johannes Berg
  2009-04-17 12:12       ` Johannes Berg
  0 siblings, 2 replies; 6+ messages in thread
From: Christian Lamparter @ 2009-04-17 11:56 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless, Kalle Valo

[-- Attachment #1: Type: text/plain, Size: 280 bytes --]

On Thursday 16 April 2009 22:18:24 Johannes Berg wrote:
> 
> > Well, I guess I figured out what's wrong: the hw spec.
> > So this patch might work on PCI & USB, but could break SPI devices.
> 
> Heh.
> 
> > Johannes, can you please test the attached patch?
> > 

updated version.

[-- Attachment #2: p54ps-3.diff --]
[-- Type: text/x-patch, Size: 5282 bytes --]

diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 7fda1a9..1e999aa 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -181,6 +181,8 @@ struct p54_common {
 	u32 tsf_low32, tsf_high32;
 	u32 basic_rate_mask;
 	u16 aid;
+	bool allow_ps_filtering;
+	unsigned long beacon_timeout_guard;
 	struct sk_buff *cached_beacon;
 
 	/* cryptographic engine information */
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 716c8a0..2c98904 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -739,6 +739,61 @@ static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi)
 			 priv->rssical_db[band].add) / 4;
 }
 
+static u8 *p54_find_ie_elem(u8 elem, u8 *ie, u8 *end)
+{
+	while (ie < end) {
+		if (ie + 2 + ie[1] > end)
+			return NULL;
+
+		if (ie[0] == elem)
+			return ie;
+
+		ie += 2 + ie[1];
+	}
+
+	return NULL;
+}
+
+static int p54_set_ps(struct ieee80211_hw *dev);
+
+static void p54_rx_ps_workaround(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_common *priv = dev->priv;
+	struct ieee80211_mgmt *mgmt = (void *)skb->data;
+	struct ieee80211_tim_ie *tim;
+	u8 *pos, *end, *ie;
+
+	if (skb->len <= sizeof(mgmt))
+		return ;
+
+	if (!ieee80211_is_beacon(mgmt->frame_control))
+		return ;
+
+	if (compare_ether_addr(priv->bssid, mgmt->bssid))
+		return ;
+
+	pos = (u8 *)mgmt->u.beacon.variable;
+	end = skb->data + skb->len;
+	ie = p54_find_ie_elem(WLAN_EID_TIM, pos, end);
+	if (!ie)
+		return ;
+
+	tim = (void *) &ie[2];
+	if (ieee80211_check_tim(tim, ie[1], priv->aid)) {
+		/*
+		 * disable powersave management, as long as
+		 * our TIM is set in the beacon
+		 * else we would miss PS-POLL frames
+		 */
+
+		priv->allow_ps_filtering = false;
+		p54_set_ps(dev);
+	} else {
+		priv->allow_ps_filtering = true;
+		p54_set_ps(dev);
+	}
+}
+
 static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 {
 	struct p54_common *priv = dev->priv;
@@ -794,6 +846,10 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
 	skb_pull(skb, header_len);
 	skb_trim(skb, le16_to_cpu(hdr->len));
 
+	/* workaround for checksumming bug */
+	if (unlikely(dev->conf.flags & IEEE80211_CONF_PS))
+		p54_rx_ps_workaround(dev, skb);
+
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
 	queue_delayed_work(dev->workqueue, &priv->work,
@@ -1076,7 +1132,11 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb)
 			wiphy_name(dev->wiphy), freq);
 		break;
 	case P54_TRAP_NO_BEACON:
-		if (priv->vif)
+		if (time_before(priv->beacon_timeout_guard, jiffies))
+			printk(KERN_INFO "Fake beacon loss\n");
+
+		if (time_after(priv->beacon_timeout_guard, jiffies) &&
+		    priv->vif)
 			ieee80211_beacon_loss(priv->vif);
 		break;
 	case P54_TRAP_SCAN:
@@ -1959,10 +2019,14 @@ static int p54_set_ps(struct ieee80211_hw *dev)
 	u16 mode;
 	int i;
 
-	if (dev->conf.flags & IEEE80211_CONF_PS)
+	if (dev->conf.flags & IEEE80211_CONF_PS &&
+	    priv->allow_ps_filtering) {
 		mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
 		       P54_PSM_CHECKSUM | P54_PSM_MCBC;
-	else
+
+		priv->beacon_timeout_guard = jiffies + usecs_to_jiffies(
+			ieee80211_tu_to_usec(priv->hw->conf.beacon_int));
+	} else
 		mode = P54_PSM_CAM;
 
 	skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
@@ -1981,8 +2045,8 @@ static int p54_set_ps(struct ieee80211_hw *dev)
 
 	psm->beacon_rssi_skip_max = 200;
 	psm->rssi_delta_threshold = 0;
-	psm->nr = 10;
-	psm->exclude[0] = 0;
+	psm->nr = 1;
+	psm->exclude[0] = WLAN_EID_TIM;
 
 	priv->tx(dev, skb);
 
@@ -1998,42 +2062,38 @@ static int p54_beacon_tim(struct sk_buff *skb)
 	 */
 
 	struct ieee80211_mgmt *mgmt = (void *)skb->data;
-	u8 *pos, *end;
+	u8 *pos, *end, *tim_ie, *next;
+	u8 dtim_period, dtim_len;
 
 	if (skb->len <= sizeof(mgmt))
 		return -EINVAL;
 
 	pos = (u8 *)mgmt->u.beacon.variable;
 	end = skb->data + skb->len;
-	while (pos < end) {
-		if (pos + 2 + pos[1] > end)
-			return -EINVAL;
+	tim_ie = p54_find_ie_elem(WLAN_EID_TIM, pos, end);
+	if (!tim_ie)
+		return 0;
 
-		if (pos[0] == WLAN_EID_TIM) {
-			u8 dtim_len = pos[1];
-			u8 dtim_period = pos[3];
-			u8 *next = pos + 2 + dtim_len;
+	if (tim_ie[1] < 3)
+		return -EINVAL;
 
-			if (dtim_len < 3)
-				return -EINVAL;
+	dtim_len = tim_ie[1];
+	dtim_period = tim_ie[3];
+	next = pos + 2 + dtim_len;
 
-			memmove(pos, next, end - next);
+	memmove(pos, next, end - next);
 
-			if (dtim_len > 3)
-				skb_trim(skb, skb->len - (dtim_len - 3));
+	if (dtim_len > 3)
+		skb_trim(skb, skb->len - (dtim_len - 3));
 
-			pos = end - (dtim_len + 2);
+	pos = end - (dtim_len + 2);
 
-			/* add the dummy at the end */
-			pos[0] = WLAN_EID_TIM;
-			pos[1] = 3;
-			pos[2] = 0;
-			pos[3] = dtim_period;
-			pos[4] = 0;
-			return 0;
-		}
-		pos += 2 + pos[1];
-	}
+	/* add the dummy at the end */
+	pos[0] = WLAN_EID_TIM;
+	pos[1] = 3;
+	pos[2] = 0;
+	pos[3] = dtim_period;
+	pos[4] = 0;
 	return 0;
 }
 
@@ -2093,6 +2153,8 @@ static int p54_start(struct ieee80211_hw *dev)
 
 	queue_delayed_work(dev->workqueue, &priv->work, 0);
 
+	priv->allow_ps_filtering = true;
+	priv->beacon_timeout_guard = jiffies;
 	priv->softled_state = 0;
 	err = p54_set_leds(dev);
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: p54 problem with PS
  2009-04-17 11:56     ` Christian Lamparter
@ 2009-04-17 12:08       ` Johannes Berg
  2009-04-17 12:12       ` Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-04-17 12:08 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Kalle Valo

[-- Attachment #1: Type: text/plain, Size: 433 bytes --]

On Fri, 2009-04-17 at 13:56 +0200, Christian Lamparter wrote:
> On Thursday 16 April 2009 22:18:24 Johannes Berg wrote:
> > 
> > > Well, I guess I figured out what's wrong: the hw spec.
> > > So this patch might work on PCI & USB, but could break SPI devices.
> > 
> > Heh.
> > 
> > > Johannes, can you please test the attached patch?
> > > 
> 
> updated version.

Loads of "Fake beacon loss" but works. :)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: p54 problem with PS
  2009-04-17 11:56     ` Christian Lamparter
  2009-04-17 12:08       ` Johannes Berg
@ 2009-04-17 12:12       ` Johannes Berg
  1 sibling, 0 replies; 6+ messages in thread
From: Johannes Berg @ 2009-04-17 12:12 UTC (permalink / raw)
  To: Christian Lamparter; +Cc: linux-wireless, Kalle Valo

[-- Attachment #1: Type: text/plain, Size: 224 bytes --]

On Fri, 2009-04-17 at 13:56 +0200, Christian Lamparter wrote:

> +       priv->beacon_timeout_guard = jiffies;

I wonder if you shouldn't do this when CONF_PS is (first?) enabled
instead? Or add_interface?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2009-04-17 12:13 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-15 19:24 p54 problem with PS Johannes Berg
2009-04-16 19:57 ` Christian Lamparter
2009-04-16 20:18   ` Johannes Berg
2009-04-17 11:56     ` Christian Lamparter
2009-04-17 12:08       ` Johannes Berg
2009-04-17 12:12       ` Johannes Berg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox