aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2009-02-10 10:09:31 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-02-13 13:45:17 -0500
commit572e00122190e3064fa19bd9780b146d2d0f1905 (patch)
treeae8423958dd012af1dca83718b3035f2e75c53ec
parent1fb3606bc5864c64c78ce4e1751e5382a9a5aa84 (diff)
mac80211: use ps-poll when dynamic power save mode is disabled
When a directed tim bit is set, mac80211 currently disables power save ands sends a null frame to the AP. But if dynamic power save is disabled, mac80211 will not enable power save ever gain. Fix this by adding ps-poll functionality to mac80211. When a directed tim bit is set, mac80211 sends a ps-poll frame to the AP and checks for the more data bit in the returned data frames. Using ps-poll is slower than waking up with null frame, but it's saves more power in cases where the traffic is low. Userspace can control if either ps-poll or null wakeup method is used by enabling and disabling dynamic power save. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/mlme.c54
-rw-r--r--net/mac80211/rx.c34
3 files changed, 88 insertions, 3 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5a1f19ad43c8..67bd5220cf40 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -728,6 +728,7 @@ struct ieee80211_local {
728 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ 728 unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */
729 729
730 bool powersave; 730 bool powersave;
731 bool pspolling;
731 struct work_struct dynamic_ps_enable_work; 732 struct work_struct dynamic_ps_enable_work;
732 struct work_struct dynamic_ps_disable_work; 733 struct work_struct dynamic_ps_disable_work;
733 struct timer_list dynamic_ps_timer; 734 struct timer_list dynamic_ps_timer;
@@ -921,6 +922,8 @@ u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
921 enum ieee80211_band band); 922 enum ieee80211_band band);
922void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, 923void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
923 u8 *ssid, size_t ssid_len); 924 u8 *ssid, size_t ssid_len);
925void ieee80211_send_pspoll(struct ieee80211_local *local,
926 struct ieee80211_sub_if_data *sdata);
924 927
925/* scan/BSS handling */ 928/* scan/BSS handling */
926int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, 929int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 05c8d13d39b6..169f10c51042 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -511,6 +511,39 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
511 ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED); 511 ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
512} 512}
513 513
514void ieee80211_send_pspoll(struct ieee80211_local *local,
515 struct ieee80211_sub_if_data *sdata)
516{
517 struct ieee80211_if_sta *ifsta = &sdata->u.sta;
518 struct ieee80211_pspoll *pspoll;
519 struct sk_buff *skb;
520 u16 fc;
521
522 skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*pspoll));
523 if (!skb) {
524 printk(KERN_DEBUG "%s: failed to allocate buffer for "
525 "pspoll frame\n", sdata->dev->name);
526 return;
527 }
528 skb_reserve(skb, local->hw.extra_tx_headroom);
529
530 pspoll = (struct ieee80211_pspoll *) skb_put(skb, sizeof(*pspoll));
531 memset(pspoll, 0, sizeof(*pspoll));
532 fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
533 pspoll->frame_control = cpu_to_le16(fc);
534 pspoll->aid = cpu_to_le16(ifsta->aid);
535
536 /* aid in PS-Poll has its two MSBs each set to 1 */
537 pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
538
539 memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN);
540 memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
541
542 ieee80211_tx_skb(sdata, skb, 0);
543
544 return;
545}
546
514/* MLME */ 547/* MLME */
515static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, 548static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
516 struct ieee80211_bss *bss) 549 struct ieee80211_bss *bss)
@@ -1868,9 +1901,24 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
1868 directed_tim = ieee80211_check_tim(&elems, ifsta->aid); 1901 directed_tim = ieee80211_check_tim(&elems, ifsta->aid);
1869 1902
1870 if (directed_tim) { 1903 if (directed_tim) {
1871 local->hw.conf.flags &= ~IEEE80211_CONF_PS; 1904 if (local->hw.conf.dynamic_ps_timeout > 0) {
1872 ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); 1905 local->hw.conf.flags &= ~IEEE80211_CONF_PS;
1873 ieee80211_send_nullfunc(local, sdata, 0); 1906 ieee80211_hw_config(local,
1907 IEEE80211_CONF_CHANGE_PS);
1908 ieee80211_send_nullfunc(local, sdata, 0);
1909 } else {
1910 local->pspolling = true;
1911
1912 /*
1913 * Here is assumed that the driver will be
1914 * able to send ps-poll frame and receive a
1915 * response even though power save mode is
1916 * enabled, but some drivers might require
1917 * to disable power save here. This needs
1918 * to be investigated.
1919 */
1920 ieee80211_send_pspoll(local, sdata);
1921 }
1874 } 1922 }
1875 } 1923 }
1876 1924
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8e8ddbfcd236..0e030d3fbdec 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -731,6 +731,39 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
731 return result; 731 return result;
732} 732}
733 733
734static ieee80211_rx_result debug_noinline
735ieee80211_rx_h_check_more_data(struct ieee80211_rx_data *rx)
736{
737 struct ieee80211_local *local;
738 struct ieee80211_hdr *hdr;
739 struct sk_buff *skb;
740
741 local = rx->local;
742 skb = rx->skb;
743 hdr = (struct ieee80211_hdr *) skb->data;
744
745 if (!local->pspolling)
746 return RX_CONTINUE;
747
748 if (!ieee80211_has_fromds(hdr->frame_control))
749 /* this is not from AP */
750 return RX_CONTINUE;
751
752 if (!ieee80211_is_data(hdr->frame_control))
753 return RX_CONTINUE;
754
755 if (!ieee80211_has_moredata(hdr->frame_control)) {
756 /* AP has no more frames buffered for us */
757 local->pspolling = false;
758 return RX_CONTINUE;
759 }
760
761 /* more data bit is set, let's request a new frame from the AP */
762 ieee80211_send_pspoll(local, rx->sdata);
763
764 return RX_CONTINUE;
765}
766
734static void ap_sta_ps_start(struct sta_info *sta) 767static void ap_sta_ps_start(struct sta_info *sta)
735{ 768{
736 struct ieee80211_sub_if_data *sdata = sta->sdata; 769 struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -1987,6 +2020,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata,
1987 CALL_RXH(ieee80211_rx_h_passive_scan) 2020 CALL_RXH(ieee80211_rx_h_passive_scan)
1988 CALL_RXH(ieee80211_rx_h_check) 2021 CALL_RXH(ieee80211_rx_h_check)
1989 CALL_RXH(ieee80211_rx_h_decrypt) 2022 CALL_RXH(ieee80211_rx_h_decrypt)
2023 CALL_RXH(ieee80211_rx_h_check_more_data)
1990 CALL_RXH(ieee80211_rx_h_sta_process) 2024 CALL_RXH(ieee80211_rx_h_sta_process)
1991 CALL_RXH(ieee80211_rx_h_defragment) 2025 CALL_RXH(ieee80211_rx_h_defragment)
1992 CALL_RXH(ieee80211_rx_h_ps_poll) 2026 CALL_RXH(ieee80211_rx_h_ps_poll)