diff options
author | Kalle Valo <kalle.valo@nokia.com> | 2009-02-10 10:09:31 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-02-13 13:45:17 -0500 |
commit | 572e00122190e3064fa19bd9780b146d2d0f1905 (patch) | |
tree | ae8423958dd012af1dca83718b3035f2e75c53ec /net | |
parent | 1fb3606bc5864c64c78ce4e1751e5382a9a5aa84 (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>
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 54 | ||||
-rw-r--r-- | net/mac80211/rx.c | 34 |
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); |
922 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | 923 | void 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); |
925 | void ieee80211_send_pspoll(struct ieee80211_local *local, | ||
926 | struct ieee80211_sub_if_data *sdata); | ||
924 | 927 | ||
925 | /* scan/BSS handling */ | 928 | /* scan/BSS handling */ |
926 | int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, | 929 | int 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 | ||
514 | void 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 */ |
515 | static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | 548 | static 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 | ||
734 | static ieee80211_rx_result debug_noinline | ||
735 | ieee80211_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 | |||
734 | static void ap_sta_ps_start(struct sta_info *sta) | 767 | static 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) |