diff options
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 41 | ||||
-rw-r--r-- | net/mac80211/scan.c | 2 | ||||
-rw-r--r-- | net/mac80211/wext.c | 13 |
4 files changed, 53 insertions, 6 deletions
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 5f8ad885a48a..117718bd96ec 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -987,6 +987,9 @@ u64 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
987 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); | 987 | void ieee80211_dynamic_ps_enable_work(struct work_struct *work); |
988 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); | 988 | void ieee80211_dynamic_ps_disable_work(struct work_struct *work); |
989 | void ieee80211_dynamic_ps_timer(unsigned long data); | 989 | void ieee80211_dynamic_ps_timer(unsigned long data); |
990 | void ieee80211_send_nullfunc(struct ieee80211_local *local, | ||
991 | struct ieee80211_sub_if_data *sdata, | ||
992 | int powersave); | ||
990 | 993 | ||
991 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, | 994 | void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, |
992 | enum queue_stop_reason reason); | 995 | enum queue_stop_reason reason); |
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); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index f5c7c3371929..a2caeed57f4e 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -395,7 +395,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | |||
395 | return RX_QUEUED; | 395 | return RX_QUEUED; |
396 | } | 396 | } |
397 | 397 | ||
398 | static void ieee80211_send_nullfunc(struct ieee80211_local *local, | 398 | void ieee80211_send_nullfunc(struct ieee80211_local *local, |
399 | struct ieee80211_sub_if_data *sdata, | 399 | struct ieee80211_sub_if_data *sdata, |
400 | int powersave) | 400 | int powersave) |
401 | { | 401 | { |
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 8568f1e7266f..48fc6b9a62a4 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c | |||
@@ -871,12 +871,17 @@ set: | |||
871 | mod_timer(&local->dynamic_ps_timer, jiffies + | 871 | mod_timer(&local->dynamic_ps_timer, jiffies + |
872 | msecs_to_jiffies(local->dynamic_ps_timeout)); | 872 | msecs_to_jiffies(local->dynamic_ps_timeout)); |
873 | else { | 873 | else { |
874 | if (local->powersave) | 874 | if (local->powersave) { |
875 | ieee80211_send_nullfunc(local, sdata, 1); | ||
875 | conf->flags |= IEEE80211_CONF_PS; | 876 | conf->flags |= IEEE80211_CONF_PS; |
876 | else | 877 | ret = ieee80211_hw_config(local, |
878 | IEEE80211_CONF_CHANGE_PS); | ||
879 | } else { | ||
877 | conf->flags &= ~IEEE80211_CONF_PS; | 880 | conf->flags &= ~IEEE80211_CONF_PS; |
878 | ret = ieee80211_hw_config(local, | 881 | ret = ieee80211_hw_config(local, |
879 | IEEE80211_CONF_CHANGE_PS); | 882 | IEEE80211_CONF_CHANGE_PS); |
883 | ieee80211_send_nullfunc(local, sdata, 0); | ||
884 | } | ||
880 | } | 885 | } |
881 | } | 886 | } |
882 | 887 | ||