On Wednesday 28 February 2007 16:09, Jouni Malinen wrote: > Why bother with PS Poll in this case? Just send data::nullfunc with PS > Poll flag cleared. That will make the AP deliver all buffered frames (if > any). Didn't think of it. :) Here's a version that does that: -- d80211: switch STA interfaces to PS mode during scan From: Michael Wu <flamingice@xxxxxxxxxxxx> This makes scans switch STA interfaces into PS mode so the AP queues frames destined for us while we are scanning. This is achieved by sending a nullfunc data frame with the PS mode bit set before scanning commences, and a PS poll frame after scanning is completed. Signed-off-by: Michael Wu <flamingice@xxxxxxxxxxxx> --- include/linux/ieee80211.h | 7 ++++++ net/mac80211/ieee80211_sta.c | 51 +++++++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 4379b1d..836bde2 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -203,6 +203,13 @@ struct ieee80211_cts { __u8 ra[6]; } __attribute__ ((packed)); +struct ieee80211_ps_poll { + __le16 frame_control; + __le16 aid; + __u8 bssid[6]; + __u8 ta[6]; +} __attribute__ ((packed)); + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 280b24f..747662d 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2523,6 +2523,37 @@ int ieee80211_sta_set_bssid(struct net_d } +static void ieee80211_send_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int powersave) +{ + struct sk_buff *skb; + struct ieee80211_hdr *nullfunc; + u16 fc; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "frame\n", sdata->dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(nullfunc, 0, 24); + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS; + if (powersave) + fc |= IEEE80211_FCTL_PM; + nullfunc->frame_control = cpu_to_le16(fc); + memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); + + ieee80211_sta_tx(sdata->dev, skb, 0); +} + + void ieee80211_scan_completed(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); @@ -2544,10 +2575,12 @@ void ieee80211_scan_completed(struct iee spin_lock_bh(&local->sub_if_lock); list_for_each_entry(sdata, &local->sub_if_list, list) { - netif_wake_queue(sdata->dev); - - if (sdata->type == IEEE80211_IF_TYPE_STA) + if (sdata->type == IEEE80211_IF_TYPE_STA) { + if (sdata->u.sta.associated) + ieee80211_send_nullfunc(local, sdata, 0); ieee80211_sta_timer((unsigned long)&sdata->u.sta); + } + netif_wake_queue(sdata->dev); } spin_unlock_bh(&local->sub_if_lock); @@ -2667,9 +2700,6 @@ static int ieee80211_sta_start_scan(stru * ResultCode: SUCCESS, INVALID_PARAMETERS */ - /* TODO: if assoc, move to power save mode for the duration of the - * scan */ - if (local->sta_scanning) { if (local->scan_dev == dev) return 0; @@ -2691,8 +2721,12 @@ static int ieee80211_sta_start_scan(stru local->sta_scanning = 1; spin_lock_bh(&local->sub_if_lock); - list_for_each_entry(sdata, &local->sub_if_list, list) + list_for_each_entry(sdata, &local->sub_if_list, list) { netif_stop_queue(sdata->dev); + if (sdata->type == IEEE80211_IF_TYPE_STA && + sdata->u.sta.associated) + ieee80211_send_nullfunc(local, sdata, 1); + } spin_unlock_bh(&local->sub_if_lock); if (ssid) { @@ -2706,7 +2740,8 @@ static int ieee80211_sta_start_scan(stru list); local->scan_channel_idx = 0; local->scan_dev = dev; - schedule_delayed_work(&local->scan_work, 0); + /* TODO: start scan as soon as all nullfunc frames are ACKed */ + schedule_delayed_work(&local->scan_work, IEEE80211_CHANNEL_TIME); return 0; }
Attachment:
pgpT2AHXP4cNg.pgp
Description: PGP signature