aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2016-05-03 09:58:00 -0400
committerJohannes Berg <johannes.berg@intel.com>2016-05-12 05:16:55 -0400
commit46fa38e84b656f80edf83d21144221b0cad18d61 (patch)
tree42f204b73d06436d055c0e29d85495576a65ed09
parent53873f134d285191ef6435882d55837093a36c53 (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.h27
-rw-r--r--net/mac80211/rx.c70
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 */
4010void 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 */
4024void 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}
1320EXPORT_SYMBOL(ieee80211_sta_ps_transition); 1320EXPORT_SYMBOL(ieee80211_sta_ps_transition);
1321 1321
1322void 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}
1334EXPORT_SYMBOL(ieee80211_sta_pspoll);
1335
1336void 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}
1360EXPORT_SYMBOL(ieee80211_sta_uapsd_trigger);
1361
1322static ieee80211_rx_result debug_noinline 1362static ieee80211_rx_result debug_noinline
1323ieee80211_rx_h_uapsd_and_pspoll(struct ieee80211_rx_data *rx) 1363ieee80211_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;