diff options
author | Vivek Natarajan <vivek.natraj@gmail.com> | 2008-12-23 21:39:02 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 15:58:49 -0500 |
commit | a97b77b90decf27a86ac40ea53a741ffb5ead21a (patch) | |
tree | 4c5f61d6df51613fdde42ce7d9eb76b352ed2141 /net/mac80211/mlme.c | |
parent | 869717fbe43eb831cbebd03a9a66a4a4c3b406a9 (diff) |
mac80211: Enhancements to dynamic power save.
This patch enables mac80211 to send a null frame and also to
check for tim in the beacon if dynamic power save is enabled.
Signed-off-by: Vivek Natarajan <vnatarajan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r-- | net/mac80211/mlme.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index b3c99d3c61ba..599a42172a16 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -575,6 +575,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, | |||
575 | } | 575 | } |
576 | } | 576 | } |
577 | 577 | ||
578 | static bool check_tim(struct ieee802_11_elems *elems, u16 aid, bool *is_mc) | ||
579 | { | ||
580 | u8 mask; | ||
581 | u8 index, indexn1, indexn2; | ||
582 | struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *) elems->tim; | ||
583 | |||
584 | aid &= 0x3fff; | ||
585 | index = aid / 8; | ||
586 | mask = 1 << (aid & 7); | ||
587 | |||
588 | if (tim->bitmap_ctrl & 0x01) | ||
589 | *is_mc = true; | ||
590 | |||
591 | indexn1 = tim->bitmap_ctrl & 0xfe; | ||
592 | indexn2 = elems->tim_len + indexn1 - 4; | ||
593 | |||
594 | if (index < indexn1 || index > indexn2) | ||
595 | return false; | ||
596 | |||
597 | index -= indexn1; | ||
598 | |||
599 | return !!(tim->virtual_map[index] & mask); | ||
600 | } | ||
601 | |||
578 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, | 602 | static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, |
579 | u16 capab, bool erp_valid, u8 erp) | 603 | u16 capab, bool erp_valid, u8 erp) |
580 | { | 604 | { |
@@ -757,6 +781,7 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
757 | mod_timer(&local->dynamic_ps_timer, jiffies + | 781 | mod_timer(&local->dynamic_ps_timer, jiffies + |
758 | msecs_to_jiffies(local->dynamic_ps_timeout)); | 782 | msecs_to_jiffies(local->dynamic_ps_timeout)); |
759 | else { | 783 | else { |
784 | ieee80211_send_nullfunc(local, sdata, 1); | ||
760 | conf->flags |= IEEE80211_CONF_PS; | 785 | conf->flags |= IEEE80211_CONF_PS; |
761 | ieee80211_hw_config(local, | 786 | ieee80211_hw_config(local, |
762 | IEEE80211_CONF_CHANGE_PS); | 787 | IEEE80211_CONF_CHANGE_PS); |
@@ -1720,7 +1745,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1720 | struct ieee802_11_elems elems; | 1745 | struct ieee802_11_elems elems; |
1721 | struct ieee80211_local *local = sdata->local; | 1746 | struct ieee80211_local *local = sdata->local; |
1722 | u32 changed = 0; | 1747 | u32 changed = 0; |
1723 | bool erp_valid; | 1748 | bool erp_valid, directed_tim, is_mc = false; |
1724 | u8 erp_value = 0; | 1749 | u8 erp_value = 0; |
1725 | 1750 | ||
1726 | /* Process beacon from the current BSS */ | 1751 | /* Process beacon from the current BSS */ |
@@ -1743,6 +1768,18 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, | |||
1743 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, | 1768 | ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, |
1744 | elems.wmm_param_len); | 1769 | elems.wmm_param_len); |
1745 | 1770 | ||
1771 | if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS)) { | ||
1772 | directed_tim = check_tim(&elems, ifsta->aid, &is_mc); | ||
1773 | |||
1774 | if (directed_tim || is_mc) { | ||
1775 | if (local->hw.conf.flags && IEEE80211_CONF_PS) { | ||
1776 | local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||
1777 | ieee80211_hw_config(local, | ||
1778 | IEEE80211_CONF_CHANGE_PS); | ||
1779 | ieee80211_send_nullfunc(local, sdata, 0); | ||
1780 | } | ||
1781 | } | ||
1782 | } | ||
1746 | 1783 | ||
1747 | if (elems.erp_info && elems.erp_info_len >= 1) { | 1784 | if (elems.erp_info && elems.erp_info_len >= 1) { |
1748 | erp_valid = true; | 1785 | erp_valid = true; |
@@ -2631,10 +2668,12 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work) | |||
2631 | struct ieee80211_local *local = | 2668 | struct ieee80211_local *local = |
2632 | container_of(work, struct ieee80211_local, | 2669 | container_of(work, struct ieee80211_local, |
2633 | dynamic_ps_enable_work); | 2670 | dynamic_ps_enable_work); |
2671 | struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||
2634 | 2672 | ||
2635 | if (local->hw.conf.flags & IEEE80211_CONF_PS) | 2673 | if (local->hw.conf.flags & IEEE80211_CONF_PS) |
2636 | return; | 2674 | return; |
2637 | 2675 | ||
2676 | ieee80211_send_nullfunc(local, sdata, 1); | ||
2638 | local->hw.conf.flags |= IEEE80211_CONF_PS; | 2677 | local->hw.conf.flags |= IEEE80211_CONF_PS; |
2639 | 2678 | ||
2640 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | 2679 | ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); |