Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 159070
b: refs/heads/master
c: e0f114e
h: refs/heads/master
v: v3
  • Loading branch information
Christian Lamparter authored and John W. Linville committed Jul 24, 2009
1 parent 30f7082 commit 8de4b51
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 33 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0a2b8bb24d4eb67788edd71d1ef8aa86c2e17e0f
refs/heads/master: e0f114e82e3781087a0ad0e92c94ff0d55012c1a
7 changes: 4 additions & 3 deletions trunk/drivers/net/wireless/p54/fwio.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,8 @@ int p54_set_ps(struct p54_common *priv)
unsigned int i;
u16 mode;

if (priv->hw->conf.flags & IEEE80211_CONF_PS)
if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
!priv->powersave_override)
mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
P54_PSM_CHECKSUM | P54_PSM_MCBC;
else
Expand All @@ -607,8 +608,8 @@ int p54_set_ps(struct p54_common *priv)

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;

p54_tx(priv, skb);
return 0;
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/net/wireless/p54/lmac.h
Original file line number Diff line number Diff line change
Expand Up @@ -548,4 +548,7 @@ int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
int p54_download_eeprom(struct p54_common *priv, void *buf,
u16 offset, u16 len);

/* utility */
u8 *p54_find_ie(struct sk_buff *skb, u8 ie);

#endif /* LMAC_H */
77 changes: 48 additions & 29 deletions trunk/drivers/net/wireless/p54/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,51 +65,64 @@ static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
return p54_update_beacon_tim(priv, sta->aid, set);
}

static int p54_beacon_format_ie_tim(struct sk_buff *skb)
u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
{
/*
* the good excuse for this mess is ... the firmware.
* The dummy TIM MUST be at the end of the beacon frame,
* because it'll be overwritten!
*/

struct ieee80211_mgmt *mgmt = (void *)skb->data;
u8 *pos, *end;

if (skb->len <= sizeof(mgmt))
return -EINVAL;
return NULL;

pos = (u8 *)mgmt->u.beacon.variable;
end = skb->data + skb->len;
while (pos < end) {
if (pos + 2 + pos[1] > end)
return -EINVAL;
return NULL;

if (pos[0] == WLAN_EID_TIM) {
u8 dtim_len = pos[1];
u8 dtim_period = pos[3];
u8 *next = pos + 2 + dtim_len;
if (pos[0] == ie)
return pos;

if (dtim_len < 3)
return -EINVAL;
pos += 2 + pos[1];
}
return NULL;
}

memmove(pos, next, end - next);
static int p54_beacon_format_ie_tim(struct sk_buff *skb)
{
/*
* the good excuse for this mess is ... the firmware.
* The dummy TIM MUST be at the end of the beacon frame,
* because it'll be overwritten!
*/
u8 *tim;
u8 dtim_len;
u8 dtim_period;
u8 *next;

if (dtim_len > 3)
skb_trim(skb, skb->len - (dtim_len - 3));
tim = p54_find_ie(skb, WLAN_EID_TIM);
if (!tim)
return 0;

pos = end - (dtim_len + 2);
dtim_len = tim[1];
dtim_period = tim[3];
next = tim + 2 + dtim_len;

if (dtim_len < 3)
return -EINVAL;

memmove(tim, next, skb_tail_pointer(skb) - next);
tim = skb_tail_pointer(skb) - (dtim_len + 2);

/* add the dummy at the end */
tim[0] = WLAN_EID_TIM;
tim[1] = 3;
tim[2] = 0;
tim[3] = dtim_period;
tim[4] = 0;

if (dtim_len > 3)
skb_trim(skb, skb->len - (dtim_len - 3));

/* 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];
}
return 0;
}

Expand Down Expand Up @@ -384,6 +397,9 @@ static void p54_bss_info_changed(struct ieee80211_hw *dev,
priv->wakeup_timer = info->beacon_int *
info->dtim_period * 5;
p54_setup_mac(priv);
} else {
priv->wakeup_timer = 500;
priv->aid = 0;
}
}

Expand Down Expand Up @@ -517,6 +533,9 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
skb_queue_head_init(&priv->tx_pending);
dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_PS_NULLFUNC_STACK |
IEEE80211_HW_BEACON_FILTER |
IEEE80211_HW_NOISE_DBM;

dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/wireless/p54/p54.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ struct p54_common {
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
u16 aid;
bool powersave_override;
__le32 beacon_req_id;

/* cryptographic engine information */
Expand Down
42 changes: 42 additions & 0 deletions trunk/drivers/net/wireless/p54/txrx.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,45 @@ static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
priv->rssical_db[band].add) / 4;
}

/*
* Even if the firmware is capable of dealing with incoming traffic,
* while dozing, we have to prepared in case mac80211 uses PS-POLL
* to retrieve outstanding frames from our AP.
* (see comment in net/mac80211/mlme.c @ line 1993)
*/
static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (void *) skb->data;
struct ieee80211_tim_ie *tim_ie;
u8 *tim;
u8 tim_len;
bool new_psm;

/* only beacons have a TIM IE */
if (!ieee80211_is_beacon(hdr->frame_control))
return;

if (!priv->aid)
return;

/* only consider beacons from the associated BSSID */
if (compare_ether_addr(hdr->addr3, priv->bssid))
return;

tim = p54_find_ie(skb, WLAN_EID_TIM);
if (!tim)
return;

tim_len = tim[1];
tim_ie = (struct ieee80211_tim_ie *) &tim[2];

new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
if (new_psm != priv->powersave_override) {
priv->powersave_override = new_psm;
p54_set_ps(priv);
}
}

static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
{
struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
Expand Down Expand Up @@ -340,6 +379,9 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)

skb_pull(skb, header_len);
skb_trim(skb, le16_to_cpu(hdr->len));
if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
p54_pspoll_workaround(priv, skb);

ieee80211_rx_irqsafe(priv->hw, skb);

queue_delayed_work(priv->hw->workqueue, &priv->work,
Expand Down

0 comments on commit 8de4b51

Please sign in to comment.