diff options
author | Johannes Berg <johannes.berg@intel.com> | 2016-05-03 09:58:00 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2016-05-12 05:16:55 -0400 |
commit | 46fa38e84b656f80edf83d21144221b0cad18d61 (patch) | |
tree | 42f204b73d06436d055c0e29d85495576a65ed09 | |
parent | 53873f134d285191ef6435882d55837093a36c53 (diff) |
mac80211: allow software PS-Poll/U-APSD with AP_LINK_PS
When using RSS, frames might not be processed in the correct order,
and thus AP_LINK_PS must be used; most likely with firmware keeping
track of the powersave state, this is the case in iwlwifi now.
In this case, the driver can use ieee80211_sta_ps_transition() to
still have mac80211 manage powersave buffering. However, for U-APSD
and PS-Poll this isn't sufficient. If the device can't manage that
entirely on its own, mac80211's code should be used.
To allow this, export two functions: ieee80211_sta_uapsd_trigger()
and ieee80211_sta_pspoll().
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r-- | include/net/mac80211.h | 27 | ||||
-rw-r--r-- | net/mac80211/rx.c | 70 |
2 files changed, 71 insertions, 26 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ce2f6e3be3cf..be30b0549b88 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -3996,6 +3996,33 @@ static inline int ieee80211_sta_ps_transition_ni(struct ieee80211_sta *sta, | |||
3996 | return ret; | 3996 | return ret; |
3997 | } | 3997 | } |
3998 | 3998 | ||
3999 | /** | ||
4000 | * ieee80211_sta_pspoll - PS-Poll frame received | ||
4001 | * @sta: currently connected station | ||
4002 | * | ||
4003 | * When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS flag set, | ||
4004 | * use this function to inform mac80211 that a PS-Poll frame from a | ||
4005 | * connected station was received. | ||
4006 | * This must be used in conjunction with ieee80211_sta_ps_transition() | ||
4007 | * and possibly ieee80211_sta_uapsd_trigger(); calls to all three must | ||
4008 | * be serialized. | ||
4009 | */ | ||
4010 | void ieee80211_sta_pspoll(struct ieee80211_sta *sta); | ||
4011 | |||
4012 | /** | ||
4013 | * ieee80211_sta_uapsd_trigger - (potential) U-APSD trigger frame received | ||
4014 | * @sta: currently connected station | ||
4015 | * @tid: TID of the received (potential) trigger frame | ||
4016 | * | ||
4017 | * When operating in AP mode with the %IEEE80211_HW_AP_LINK_PS flag set, | ||
4018 | * use this function to inform mac80211 that a (potential) trigger frame | ||
4019 | * from a connected station was received. | ||
4020 | * This must be used in conjunction with ieee80211_sta_ps_transition() | ||
4021 | * and possibly ieee80211_sta_pspoll(); calls to all three must be | ||
4022 | * serialized. | ||
4023 | */ | ||
4024 | void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid); | ||
4025 | |||
3999 | /* | 4026 | /* |
4000 | * The TX headroom reserved by mac80211 for its own tx_status functions. | 4027 | * The TX headroom reserved by mac80211 for its own tx_status functions. |
4001 | * This is enough for the radiotap header. | 4028 | * This is enough for the radiotap header. |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c5678703921e..5e65e838992a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1319,13 +1319,52 @@ int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start) | |||
1319 | } | 1319 | } |
1320 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); | 1320 | EXPORT_SYMBOL(ieee80211_sta_ps_transition); |
1321 | 1321 | ||
1322 | void ieee80211_sta_pspoll(struct ieee80211_sta *pubsta) | ||
1323 | { | ||
1324 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
1325 | |||
1326 | if (test_sta_flag(sta, WLAN_STA_SP)) | ||
1327 | return; | ||
1328 | |||
1329 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
1330 | ieee80211_sta_ps_deliver_poll_response(sta); | ||
1331 | else | ||
1332 | set_sta_flag(sta, WLAN_STA_PSPOLL); | ||
1333 | } | ||
1334 | EXPORT_SYMBOL(ieee80211_sta_pspoll); | ||
1335 | |||
1336 | void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *pubsta, u8 tid) | ||
1337 | { | ||
1338 | struct sta_info *sta = container_of(pubsta, struct sta_info, sta); | ||
1339 | u8 ac = ieee802_1d_to_ac[tid & 7]; | ||
1340 | |||
1341 | /* | ||
1342 | * If this AC is not trigger-enabled do nothing. | ||
1343 | * | ||
1344 | * NB: This could/should check a separate bitmap of trigger- | ||
1345 | * enabled queues, but for now we only implement uAPSD w/o | ||
1346 | * TSPEC changes to the ACs, so they're always the same. | ||
1347 | */ | ||
1348 | if (!(sta->sta.uapsd_queues & BIT(ac))) | ||
1349 | return; | ||
1350 | |||
1351 | /* if we are in a service period, do nothing */ | ||
1352 | if (test_sta_flag(sta, WLAN_STA_SP)) | ||
1353 | return; | ||
1354 | |||
1355 | if (!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) | ||
1356 | ieee80211_sta_ps_deliver_uapsd(sta); | ||
1357 | else | ||
1358 | set_sta_flag(sta, WLAN_STA_UAPSD); | ||
1359 | } | ||
1360 | EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger); | ||
1361 | |||
1322 | static ieee80211_rx_result debug_noinline | 1362 | static ieee80211_rx_result debug_noinline |
1323 | ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) | 1363 | ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) |
1324 | { | 1364 | { |
1325 | struct ieee80211_sub_if_data *sdata = rx->sdata; | 1365 | struct ieee80211_sub_if_data *sdata = rx->sdata; |
1326 | struct ieee80211_hdr *hdr = (void *)rx->skb->data; | 1366 | struct ieee80211_hdr *hdr = (void *)rx->skb->data; |
1327 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); | 1367 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); |
1328 | int tid, ac; | ||
1329 | 1368 | ||
1330 | if (!rx->sta) | 1369 | if (!rx->sta) |
1331 | return RX_CONTINUE; | 1370 | return RX_CONTINUE; |
@@ -1351,12 +1390,7 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) | |||
1351 | return RX_CONTINUE; | 1390 | return RX_CONTINUE; |
1352 | 1391 | ||
1353 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { | 1392 | if (unlikely(ieee80211_is_pspoll(hdr->frame_control))) { |
1354 | if (!test_sta_flag(rx->sta, WLAN_STA_SP)) { | 1393 | ieee80211_sta_pspoll(&rx->sta->sta); |
1355 | if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) | ||
1356 | ieee80211_sta_ps_deliver_poll_response(rx->sta); | ||
1357 | else | ||
1358 | set_sta_flag(rx->sta, WLAN_STA_PSPOLL); | ||
1359 | } | ||
1360 | 1394 | ||
1361 | /* Free PS Poll skb here instead of returning RX_DROP that would | 1395 | /* Free PS Poll skb here instead of returning RX_DROP that would |
1362 | * count as an dropped frame. */ | 1396 | * count as an dropped frame. */ |
@@ -1368,27 +1402,11 @@ ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) | |||
1368 | ieee80211_has_pm(hdr->frame_control) && | 1402 | ieee80211_has_pm(hdr->frame_control) && |
1369 | (ieee80211_is_data_qos(hdr->frame_control) || | 1403 | (ieee80211_is_data_qos(hdr->frame_control) || |
1370 | ieee80211_is_qos_nullfunc(hdr->frame_control))) { | 1404 | ieee80211_is_qos_nullfunc(hdr->frame_control))) { |
1371 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; | 1405 | u8 tid; |
1372 | ac = ieee802_1d_to_ac[tid & 7]; | ||
1373 | 1406 | ||
1374 | /* | 1407 | tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; |
1375 | * If this AC is not trigger-enabled do nothing. | ||
1376 | * | ||
1377 | * NB: This could/should check a separate bitmap of trigger- | ||
1378 | * enabled queues, but for now we only implement uAPSD w/o | ||
1379 | * TSPEC changes to the ACs, so they're always the same. | ||
1380 | */ | ||
1381 | if (!(rx->sta->sta.uapsd_queues & BIT(ac))) | ||
1382 | return RX_CONTINUE; | ||
1383 | |||
1384 | /* if we are in a service period, do nothing */ | ||
1385 | if (test_sta_flag(rx->sta, WLAN_STA_SP)) | ||
1386 | return RX_CONTINUE; | ||
1387 | 1408 | ||
1388 | if (!test_sta_flag(rx->sta, WLAN_STA_PS_DRIVER)) | 1409 | ieee80211_sta_uapsd_trigger(&rx->sta->sta, tid); |
1389 | ieee80211_sta_ps_deliver_uapsd(rx->sta); | ||
1390 | else | ||
1391 | set_sta_flag(rx->sta, WLAN_STA_UAPSD); | ||
1392 | } | 1410 | } |
1393 | 1411 | ||
1394 | return RX_CONTINUE; | 1412 | return RX_CONTINUE; |