diff options
-rw-r--r-- | include/net/mac80211.h | 54 | ||||
-rw-r--r-- | net/mac80211/rx.c | 27 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 3 | ||||
-rw-r--r-- | net/mac80211/status.c | 4 |
4 files changed, 84 insertions, 4 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d6b0045788ce..0396cecd1d62 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -1069,6 +1069,13 @@ enum ieee80211_tkip_key_type { | |||
1069 | * to decrypt group addressed frames, then IBSS RSN support is still | 1069 | * to decrypt group addressed frames, then IBSS RSN support is still |
1070 | * possible but software crypto will be used. Advertise the wiphy flag | 1070 | * possible but software crypto will be used. Advertise the wiphy flag |
1071 | * only in that case. | 1071 | * only in that case. |
1072 | * | ||
1073 | * @IEEE80211_HW_AP_LINK_PS: When operating in AP mode the device | ||
1074 | * autonomously manages the PS status of connected stations. When | ||
1075 | * this flag is set mac80211 will not trigger PS mode for connected | ||
1076 | * stations based on the PM bit of incoming frames. | ||
1077 | * Use ieee80211_start_ps()/ieee8021_end_ps() to manually configure | ||
1078 | * the PS mode of connected stations. | ||
1072 | */ | 1079 | */ |
1073 | enum ieee80211_hw_flags { | 1080 | enum ieee80211_hw_flags { |
1074 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, | 1081 | IEEE80211_HW_HAS_RATE_CONTROL = 1<<0, |
@@ -1093,6 +1100,7 @@ enum ieee80211_hw_flags { | |||
1093 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, | 1100 | IEEE80211_HW_CONNECTION_MONITOR = 1<<19, |
1094 | IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, | 1101 | IEEE80211_HW_SUPPORTS_CQM_RSSI = 1<<20, |
1095 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, | 1102 | IEEE80211_HW_SUPPORTS_PER_STA_GTK = 1<<21, |
1103 | IEEE80211_HW_AP_LINK_PS = 1<<22, | ||
1096 | }; | 1104 | }; |
1097 | 1105 | ||
1098 | /** | 1106 | /** |
@@ -1701,7 +1709,9 @@ enum ieee80211_ampdu_mlme_action { | |||
1701 | * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. | 1709 | * station, AP, IBSS/WDS/mesh peer etc. This callback can sleep. |
1702 | * | 1710 | * |
1703 | * @sta_notify: Notifies low level driver about power state transition of an | 1711 | * @sta_notify: Notifies low level driver about power state transition of an |
1704 | * associated station, AP, IBSS/WDS/mesh peer etc. Must be atomic. | 1712 | * associated station, AP, IBSS/WDS/mesh peer etc. For a VIF operating |
1713 | * in AP mode, this callback will not be called when the flag | ||
1714 | * %IEEE80211_HW_AP_LINK_PS is set. Must be atomic. | ||
1705 | * | 1715 | * |
1706 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | 1716 | * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), |
1707 | * bursting) for a hardware TX queue. | 1717 | * bursting) for a hardware TX queue. |
@@ -2131,6 +2141,48 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw, | |||
2131 | local_bh_enable(); | 2141 | local_bh_enable(); |
2132 | } | 2142 | } |
2133 | 2143 | ||
2144 | /** | ||
2145 | * ieee80211_sta_ps_transition - PS transition for connected sta | ||
2146 | * | ||
2147 | * When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS | ||
2148 | * flag set, use this function to inform mac80211 about a connected station | ||
2149 | * entering/leaving PS mode. | ||
2150 | * | ||
2151 | * This function may not be called in IRQ context or with softirqs enabled. | ||
2152 | * | ||
2153 | * Calls to this function for a single hardware must be synchronized against | ||
2154 | * each other. | ||
2155 | * | ||
2156 | * The function returns -EINVAL when the requested PS mode is already set. | ||
2157 | * | ||
2158 | * @sta: currently connected sta | ||
2159 | * @start: start or stop PS | ||
2160 | */ | ||
2161 | int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start); | ||
2162 | |||
2163 | /** | ||
2164 | * ieee80211_sta_ps_transition_ni - PS transition for connected sta | ||
2165 | * (in process context) | ||
2166 | * | ||
2167 | * Like ieee80211_sta_ps_transition() but can be called in process context | ||
2168 | * (internally disables bottom halves). Concurrent call restriction still | ||
2169 | * applies. | ||
2170 | * | ||
2171 | * @sta: currently connected sta | ||
2172 | * @start: start or stop PS | ||
2173 | */ | ||
2174 | static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, | ||
2175 | bool start) | ||
2176 | { | ||
2177 | int ret; | ||
2178 | |||
2179 | local_bh_disable(); | ||
2180 | ret = ieee80211_sta_ps_transition(sta, start); | ||
2181 | local_bh_enable(); | ||
2182 | |||
2183 | return ret; | ||
2184 | } | ||
2185 | |||
2134 | /* | 2186 | /* |
2135 | * The TX headroom reserved by mac80211 for its own tx_status functions. | 2187 | * The TX headroom reserved by mac80211 for its own tx_status functions. |
2136 | * This is enough for the radiotap header. | 2188 | * This is enough for the radiotap header. |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7185c9316be2..d78d6fc333d2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1105,7 +1105,8 @@ static void ap_sta_ps_start(struct sta_info *sta) | |||
1105 | 1105 | ||
1106 | atomic_inc(&sdata->bss->num_sta_ps); | 1106 | atomic_inc(&sdata->bss->num_sta_ps); |
1107 | set_sta_flags(sta, WLAN_STA_PS_STA); | 1107 | set_sta_flags(sta, WLAN_STA_PS_STA); |
1108 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | 1108 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
1109 | drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); | ||
1109 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG | 1110 | #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG |
1110 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", | 1111 | printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", |
1111 | sdata->name, sta->sta.addr, sta->sta.aid); | 1112 | sdata->name, sta->sta.addr, sta->sta.aid); |
@@ -1134,6 +1135,27 @@ static void ap_sta_ps_end(struct sta_info *sta) | |||
1134 | ieee80211_sta_ps_deliver_wakeup(sta); | 1135 | ieee80211_sta_ps_deliver_wakeup(sta); |
1135 | } | 1136 | } |
1136 | 1137 | ||
1138 | int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) | ||
1139 | { | ||
1140 | struct sta_info *sta_inf = container_of(sta, struct sta_info, sta); | ||
1141 | bool in_ps; | ||
1142 | |||
1143 | WARN_ON(!(sta_inf->local->hw.flags & IEEE80211_HW_AP_LINK_PS)); | ||
1144 | |||
1145 | /* Don't let the same PS state be set twice */ | ||
1146 | in_ps = test_sta_flags(sta_inf, WLAN_STA_PS_STA); | ||
1147 | if ((start && in_ps) || (!start && !in_ps)) | ||
1148 | return -EINVAL; | ||
1149 | |||
1150 | if (start) | ||
1151 | ap_sta_ps_start(sta_inf); | ||
1152 | else | ||
1153 | ap_sta_ps_end(sta_inf); | ||
1154 | |||
1155 | return 0; | ||
1156 | } | ||
1157 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); | ||
1158 | |||
1137 | static ieee80211_rx_result debug_noinline | 1159 | static ieee80211_rx_result debug_noinline |
1138 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | 1160 | ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) |
1139 | { | 1161 | { |
@@ -1178,7 +1200,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) | |||
1178 | * Change STA power saving mode only at the end of a frame | 1200 | * Change STA power saving mode only at the end of a frame |
1179 | * exchange sequence. | 1201 | * exchange sequence. |
1180 | */ | 1202 | */ |
1181 | if (!ieee80211_has_morefrags(hdr->frame_control) && | 1203 | if (!(sta->local->hw.flags & IEEE80211_HW_AP_LINK_PS) && |
1204 | !ieee80211_has_morefrags(hdr->frame_control) && | ||
1182 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && | 1205 | !(status->rx_flags & IEEE80211_RX_DEFERRED_RELEASE) && |
1183 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || | 1206 | (rx->sdata->vif.type == NL80211_IFTYPE_AP || |
1184 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { | 1207 | rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c426504ed1cf..5a11078827ab 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -899,7 +899,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) | |||
899 | struct ieee80211_local *local = sdata->local; | 899 | struct ieee80211_local *local = sdata->local; |
900 | int sent, buffered; | 900 | int sent, buffered; |
901 | 901 | ||
902 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | 902 | if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) |
903 | drv_sta_notify(local, sdata, STA_NOTIFY_AWAKE, &sta->sta); | ||
903 | 904 | ||
904 | if (!skb_queue_empty(&sta->ps_tx_buf)) | 905 | if (!skb_queue_empty(&sta->ps_tx_buf)) |
905 | sta_info_clear_tim_bit(sta); | 906 | sta_info_clear_tim_bit(sta); |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 38a797217a91..ffb0de9bc2fa 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -98,6 +98,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
98 | * (b) always process RX events before TX status events if ordering | 98 | * (b) always process RX events before TX status events if ordering |
99 | * can be unknown, for example with different interrupt status | 99 | * can be unknown, for example with different interrupt status |
100 | * bits. | 100 | * bits. |
101 | * (c) if PS mode transitions are manual (i.e. the flag | ||
102 | * %IEEE80211_HW_AP_LINK_PS is set), always process PS state | ||
103 | * changes before calling TX status events if ordering can be | ||
104 | * unknown. | ||
101 | */ | 105 | */ |
102 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && | 106 | if (test_sta_flags(sta, WLAN_STA_PS_STA) && |
103 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { | 107 | skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { |