* [RFC 1/2] mac80211: allow APs to send SMPS frames
@ 2013-08-20 11:12 Emmanuel Grumbach
2013-08-20 11:12 ` [RFC 2/2] mac80211: implement SMPS for AP Emmanuel Grumbach
2013-08-21 0:57 ` [RFC 1/2] mac80211: allow APs to send SMPS frames Julian Calaby
0 siblings, 2 replies; 4+ messages in thread
From: Emmanuel Grumbach @ 2013-08-20 11:12 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
SMPS code checks all over the place that the vif is
BSS. Remove that constraint and allow SMPS for AP too.
Provide dummy implementation that will be used for
further patches.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/cfg.c | 15 ++++++++++++---
net/mac80211/debugfs_netdev.c | 24 +++++++++++++++---------
net/mac80211/ht.c | 38 ++++++++++++++++++++++++++++----------
net/mac80211/ieee80211_i.h | 13 ++++++++++---
net/mac80211/iface.c | 2 ++
net/mac80211/mlme.c | 2 +-
6 files changed, 68 insertions(+), 26 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 4cc81c3..bd6b38c 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2337,8 +2337,14 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
}
#endif
-int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode)
+int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode)
+{
+ return 0;
+}
+
+int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode)
{
const u8 *ap;
enum ieee80211_smps_mode old_req;
@@ -2346,6 +2352,9 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
lockdep_assert_held(&sdata->wdev.mtx);
+ if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION))
+ return -EINVAL;
+
old_req = sdata->u.mgd.req_smps;
sdata->u.mgd.req_smps = smps_mode;
@@ -2402,7 +2411,7 @@ static int ieee80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
/* no change, but if automatic follow powersave */
sdata_lock(sdata);
- __ieee80211_request_smps(sdata, sdata->u.mgd.req_smps);
+ __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.req_smps);
sdata_unlock(sdata);
if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index e601c9f..7609e47 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -224,12 +224,15 @@ static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata,
smps_mode == IEEE80211_SMPS_AUTOMATIC))
return -EINVAL;
- /* supported only on managed interfaces for now */
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_AP)
return -EOPNOTSUPP;
sdata_lock(sdata);
- err = __ieee80211_request_smps(sdata, smps_mode);
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ err = __ieee80211_request_smps_mgd(sdata, smps_mode);
+ else
+ err = __ieee80211_request_smps_ap(sdata, smps_mode);
sdata_unlock(sdata);
return err;
@@ -245,12 +248,15 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
char *buf, int buflen)
{
- if (sdata->vif.type != NL80211_IFTYPE_STATION)
- return -EOPNOTSUPP;
-
- return snprintf(buf, buflen, "request: %s\nused: %s\n",
- smps_modes[sdata->u.mgd.req_smps],
- smps_modes[sdata->smps_mode]);
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ return snprintf(buf, buflen, "request: %s\nused: %s\n",
+ smps_modes[sdata->u.mgd.req_smps],
+ smps_modes[sdata->smps_mode]);
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
+ return snprintf(buf, buflen, "request: %s\nused: %s\n",
+ smps_modes[sdata->u.ap.req_smps],
+ smps_modes[sdata->smps_mode]);
+ return -EINVAL;
}
static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 529bf58..2c85b96 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -448,14 +448,25 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
return 0;
}
-void ieee80211_request_smps_work(struct work_struct *work)
+void ieee80211_request_smps_mgd_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
container_of(work, struct ieee80211_sub_if_data,
u.mgd.request_smps_work);
sdata_lock(sdata);
- __ieee80211_request_smps(sdata, sdata->u.mgd.driver_smps_mode);
+ __ieee80211_request_smps_mgd(sdata, sdata->u.mgd.driver_smps_mode);
+ sdata_unlock(sdata);
+}
+
+void ieee80211_request_smps_ap_work(struct work_struct *work)
+{
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.ap.request_smps_work);
+
+ sdata_lock(sdata);
+ __ieee80211_request_smps_ap(sdata, sdata->u.ap.driver_smps_mode);
sdata_unlock(sdata);
}
@@ -464,19 +475,26 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
{
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
+ if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP))
return;
if (WARN_ON(smps_mode == IEEE80211_SMPS_OFF))
smps_mode = IEEE80211_SMPS_AUTOMATIC;
- if (sdata->u.mgd.driver_smps_mode == smps_mode)
- return;
-
- sdata->u.mgd.driver_smps_mode = smps_mode;
-
- ieee80211_queue_work(&sdata->local->hw,
- &sdata->u.mgd.request_smps_work);
+ if (vif->type == NL80211_IFTYPE_STATION) {
+ if (sdata->u.mgd.driver_smps_mode == smps_mode)
+ return;
+ sdata->u.mgd.driver_smps_mode = smps_mode;
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->u.mgd.request_smps_work);
+ } else {
+ if (sdata->u.ap.driver_smps_mode == smps_mode)
+ return;
+ sdata->u.ap.driver_smps_mode = smps_mode;
+ ieee80211_queue_work(&sdata->local->hw,
+ &sdata->u.ap.request_smps_work);
+ }
}
/* this might change ... don't want non-open drivers using it */
EXPORT_SYMBOL_GPL(ieee80211_request_smps);
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 47cf62e..7c68eac 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -265,6 +265,10 @@ struct ieee80211_if_ap {
struct ps_data ps;
atomic_t num_mcast_sta; /* number of stations receiving multicast */
+ enum ieee80211_smps_mode req_smps, /* requested smps mode */
+ driver_smps_mode; /* smps mode request */
+
+ struct work_struct request_smps_work;
};
struct ieee80211_if_wds {
@@ -1439,7 +1443,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps, const u8 *da,
const u8 *bssid);
-void ieee80211_request_smps_work(struct work_struct *work);
+void ieee80211_request_smps_ap_work(struct work_struct *work);
+void ieee80211_request_smps_mgd_work(struct work_struct *work);
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason, bool stop);
@@ -1634,8 +1639,10 @@ void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata,
struct ieee802_11_elems *elems,
enum ieee80211_band band, u32 *basic_rates);
-int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
- enum ieee80211_smps_mode smps_mode);
+int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode);
+int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
+ enum ieee80211_smps_mode smps_mode);
void ieee80211_recalc_smps(struct ieee80211_sub_if_data *sdata);
size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index cc0c4be..913ef15 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1301,6 +1301,8 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
case NL80211_IFTYPE_AP:
skb_queue_head_init(&sdata->u.ap.ps.bc_buf);
INIT_LIST_HEAD(&sdata->u.ap.vlans);
+ INIT_WORK(&sdata->u.ap.request_smps_work,
+ ieee80211_request_smps_ap_work);
sdata->vif.bss_conf.bssid = sdata->vif.addr;
break;
case NL80211_IFTYPE_P2P_CLIENT:
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 21bccd8..89e6f28 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3693,7 +3693,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
ieee80211_beacon_connection_loss_work);
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
- INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_work);
+ INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread* [RFC 2/2] mac80211: implement SMPS for AP
2013-08-20 11:12 [RFC 1/2] mac80211: allow APs to send SMPS frames Emmanuel Grumbach
@ 2013-08-20 11:12 ` Emmanuel Grumbach
2013-08-21 0:57 ` [RFC 1/2] mac80211: allow APs to send SMPS frames Julian Calaby
1 sibling, 0 replies; 4+ messages in thread
From: Emmanuel Grumbach @ 2013-08-20 11:12 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
When the driver requests to move to STATIC or DYNAMIC SMPS,
we send an action frame to each associated station and
reconfigure the channel context / driver.
Of course, non-MIMO stations are ignored.
The beacon isn't updated. The association response will
include the original capabilities. Stations that associate
while in non-OFF SMPS mode will get an action frame right
after association to inform them about our current state.
Note that we wait until the end of the EAPOL. Sending an
action frame before the EAPOL is finished can be an issue
for a few clients. Clients aren't likely to send EAPOL
frames in MIMO anyway.
When the SMPS configuration gets more permissive (e.g.
STATIC -> OFF), we don't wake up stations that are asleep
We remember that they don't know about the change and send
the action frame when they wake up.
When the SMPS configuration gets more restrictive (e.g.
OFF -> STATIC), we set the TIM bit for every sleeping STA.
uAPSD stations might send MIMO until they poll the action
frame, but this is for a short period of time.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
---
net/mac80211/cfg.c | 91 +++++++++++++++++++++++++++++++++++++++++
net/mac80211/debugfs_netdev.c | 1 +
net/mac80211/ht.c | 3 ++
net/mac80211/ieee80211_i.h | 3 ++
net/mac80211/sta_info.c | 56 +++++++++++++++++++++++++
net/mac80211/sta_info.h | 5 +++
net/mac80211/status.c | 15 ++++---
net/mac80211/util.c | 25 +++++++++++
8 files changed, 194 insertions(+), 5 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index bd6b38c..0e00c83 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1553,6 +1553,19 @@ static int ieee80211_change_station(struct wiphy *wiphy,
mutex_unlock(&local->sta_mtx);
+ if (sdata->vif.type == NL80211_IFTYPE_AP &&
+ sta->known_smps_mode != sta->sdata->smps_mode &&
+ test_sta_flag(sta, WLAN_STA_AUTHORIZED) &&
+ sta_info_tx_chains(sta) != 1) {
+ ht_dbg(sta->sdata,
+ "%pM just authorized and MIMO capable - update SMPS\n",
+ sta->sta.addr);
+ ieee80211_send_smps_action(sta->sdata,
+ sta->sdata->u.ap.req_smps,
+ sta->sta.addr,
+ sta->sdata->vif.bss_conf.bssid);
+ }
+
if (sdata->vif.type == NL80211_IFTYPE_STATION &&
params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)) {
ieee80211_recalc_ps(local, -1);
@@ -2340,6 +2353,84 @@ static int ieee80211_testmode_dump(struct wiphy *wiphy,
int __ieee80211_request_smps_ap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_smps_mode smps_mode)
{
+ struct sta_info *sta;
+ enum ieee80211_smps_mode old_req;
+ int i;
+
+ if (WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_AP))
+ return -EINVAL;
+
+ if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
+ return 0;
+
+ old_req = sdata->u.ap.req_smps;
+ sdata->u.ap.req_smps = smps_mode;
+
+ /* AUTOMATIC doesn't mean much for AP - don't allow it */
+ if (old_req == smps_mode ||
+ smps_mode == IEEE80211_SMPS_AUTOMATIC)
+ return 0;
+
+ /* If no associated stations, there's no need to do anything */
+ if (!atomic_read(&sdata->u.ap.num_mcast_sta)) {
+ sdata->smps_mode = smps_mode;
+ ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
+ return 0;
+ }
+
+ ht_dbg(sdata,
+ "SMSP %d requested in AP mode, sending Action frame to %d stations\n",
+ smps_mode, atomic_read(&sdata->u.ap.num_mcast_sta));
+
+ mutex_lock(&sdata->local->sta_mtx);
+ for (i = 0; i < STA_HASH_SIZE; i++) {
+ for (sta = rcu_dereference_protected(sdata->local->sta_hash[i],
+ lockdep_is_held(&sdata->local->sta_mtx));
+ sta;
+ sta = rcu_dereference_protected(sta->hnext,
+ lockdep_is_held(&sdata->local->sta_mtx))) {
+ if (sta->sdata != sdata)
+ continue;
+
+ /* This station doesn't support MIMO - skip it */
+ if (sta_info_tx_chains(sta) == 1) {
+ ht_dbg(sdata,
+ "Won't send SMPS to non-MIMO capable STA %pM\n",
+ sta->sta.addr);
+ continue;
+ }
+
+ /*
+ * Don't wake up a STA just to send the action frame
+ * unless we are getting more restrictive.
+ */
+ if (test_sta_flag(sta, WLAN_STA_PS_STA) &&
+ !ieee80211_smps_is_restrictive(sta->known_smps_mode,
+ smps_mode)) {
+ ht_dbg(sdata,
+ "Won't send SMPS to sleeping STA %pM\n",
+ sta->sta.addr);
+ continue;
+ }
+
+ /*
+ * If the STA is not authorized, wait until it gets
+ * authorized and the action frame will be sent then.
+ */
+ if (!test_sta_flag(sta, WLAN_STA_AUTHORIZED))
+ continue;
+
+ ht_dbg(sdata, "Sending SMPS to %pM\n", sta->sta.addr);
+ ieee80211_send_smps_action(sdata, smps_mode,
+ sta->sta.addr,
+ sdata->vif.bss_conf.bssid);
+ }
+ }
+ mutex_unlock(&sdata->local->sta_mtx);
+
+ sdata->smps_mode = smps_mode;
+ ieee80211_queue_work(&sdata->local->hw, &sdata->recalc_smps);
+
return 0;
}
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 7609e47..4e9ec9e 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -569,6 +569,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
static void add_ap_files(struct ieee80211_sub_if_data *sdata)
{
DEBUGFS_ADD(num_mcast_sta);
+ DEBUGFS_ADD_MODE(smps, 0600);
DEBUGFS_ADD(num_sta_ps);
DEBUGFS_ADD(dtim_count);
DEBUGFS_ADD(num_buffered_multicast);
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index 2c85b96..9a8be8f 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -489,6 +489,9 @@ void ieee80211_request_smps(struct ieee80211_vif *vif,
ieee80211_queue_work(&sdata->local->hw,
&sdata->u.mgd.request_smps_work);
} else {
+ /* AUTOMATIC is meaningless in AP mode */
+ if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC))
+ return;
if (sdata->u.ap.driver_smps_mode == smps_mode)
return;
sdata->u.ap.driver_smps_mode = smps_mode;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 7c68eac..85387cb 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1445,6 +1445,9 @@ int ieee80211_send_smps_action(struct ieee80211_sub_if_data *sdata,
const u8 *bssid);
void ieee80211_request_smps_ap_work(struct work_struct *work);
void ieee80211_request_smps_mgd_work(struct work_struct *work);
+bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
+ enum ieee80211_smps_mode smps_mode_new);
+
void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
u16 initiator, u16 reason, bool stop);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 9c97237..74c88ba 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -385,6 +385,25 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
sta->sta.smps_mode = IEEE80211_SMPS_OFF;
+ if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ struct ieee80211_supported_band *sband =
+ local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
+ u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >>
+ IEEE80211_HT_CAP_SM_PS_SHIFT;
+ switch (smps) {
+ case WLAN_HT_SMPS_CONTROL_DISABLED:
+ sta->known_smps_mode = IEEE80211_SMPS_OFF;
+ break;
+ case WLAN_HT_SMPS_CONTROL_STATIC:
+ sta->known_smps_mode = IEEE80211_SMPS_STATIC;
+ break;
+ case WLAN_HT_SMPS_CONTROL_DYNAMIC:
+ sta->known_smps_mode = IEEE80211_SMPS_DYNAMIC;
+ break;
+ default:
+ WARN_ON(1);
+ }
+ }
sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
@@ -1069,6 +1088,19 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta);
+ /* This station just woke up and isn't aware of our SMPS state */
+ if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
+ sdata->smps_mode) &&
+ sta->known_smps_mode != sdata->smps_mode &&
+ sta_info_tx_chains(sta) != 1) {
+ ht_dbg(sdata,
+ "%pM just woke up and MIMO capable - update SMPS\n",
+ sta->sta.addr);
+ ieee80211_send_smps_action(sdata, sdata->smps_mode,
+ sta->sta.addr,
+ sdata->vif.bss_conf.bssid);
+ }
+
local->total_ps_buffered -= buffered;
sta_info_recalc_tim(sta);
@@ -1520,3 +1552,27 @@ int sta_info_move_state(struct sta_info *sta,
return 0;
}
+
+u8 sta_info_tx_chains(struct sta_info *sta)
+{
+ struct ieee80211_sta_ht_cap *ht_cap = &sta->sta.ht_cap;
+ u8 rx_chains;
+
+ if (!sta->sta.ht_cap.ht_supported)
+ return 1;
+
+ if (ht_cap->mcs.rx_mask[3])
+ rx_chains = 4;
+ else if (ht_cap->mcs.rx_mask[2])
+ rx_chains = 3;
+ else if (ht_cap->mcs.rx_mask[1])
+ rx_chains = 2;
+ else
+ rx_chains = 1;
+
+ if (!(ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_RX_DIFF))
+ return rx_chains;
+
+ return ((ht_cap->mcs.tx_params & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK)
+ >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1;
+}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 9013969..240aef2 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -301,6 +301,8 @@ struct sta_ampdu_mlme {
* @chains: chains ever used for RX from this station
* @chain_signal_last: last signal (per chain)
* @chain_signal_avg: signal average (per chain)
+ * @known_smps_mode: the smps_mode the client thinks we are in. Relevant for
+ * AP only.
*/
struct sta_info {
/* General information, mostly static */
@@ -411,6 +413,8 @@ struct sta_info {
unsigned int lost_packets;
unsigned int beacon_loss_count;
+ enum ieee80211_smps_mode known_smps_mode;
+
/* keep last! */
struct ieee80211_sta sta;
};
@@ -613,6 +617,7 @@ void sta_set_rate_info_rx(struct sta_info *sta,
struct rate_info *rinfo);
void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata,
unsigned long exp_time);
+u8 sta_info_tx_chains(struct sta_info *sta);
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta);
void ieee80211_sta_ps_deliver_poll_response(struct sta_info *sta);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 368837f..7746cd0 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -191,8 +191,8 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_HT &&
mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS &&
- sdata->vif.type == NL80211_IFTYPE_STATION &&
ieee80211_sdata_running(sdata)) {
+ enum ieee80211_smps_mode smps_mode;
/*
* This update looks racy, but isn't -- if we come
* here we've definitely got a station that we're
@@ -202,18 +202,23 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb)
*/
switch (mgmt->u.action.u.ht_smps.smps_control) {
case WLAN_HT_SMPS_CONTROL_DYNAMIC:
- sdata->smps_mode = IEEE80211_SMPS_DYNAMIC;
+ smps_mode = IEEE80211_SMPS_DYNAMIC;
break;
case WLAN_HT_SMPS_CONTROL_STATIC:
- sdata->smps_mode = IEEE80211_SMPS_STATIC;
+ smps_mode = IEEE80211_SMPS_STATIC;
break;
case WLAN_HT_SMPS_CONTROL_DISABLED:
default: /* shouldn't happen since we don't send that */
- sdata->smps_mode = IEEE80211_SMPS_OFF;
+ smps_mode = IEEE80211_SMPS_OFF;
break;
}
- ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ sdata->smps_mode = smps_mode;
+ ieee80211_queue_work(&local->hw, &sdata->recalc_smps);
+ } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
+ sta->known_smps_mode = smps_mode;
+ }
}
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index d23c5a7..dad8262 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2295,3 +2295,28 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw)
ieee80211_queue_work(hw, &local->radar_detected_work);
}
EXPORT_SYMBOL(ieee80211_radar_detected);
+
+/*
+ * Returns true if smps_mode_new is strictly more restrictive than
+ * smps_mode_old.
+ */
+bool ieee80211_smps_is_restrictive(enum ieee80211_smps_mode smps_mode_old,
+ enum ieee80211_smps_mode smps_mode_new)
+{
+ if (WARN_ON_ONCE(smps_mode_old == IEEE80211_SMPS_AUTOMATIC ||
+ smps_mode_new == IEEE80211_SMPS_AUTOMATIC))
+ return false;
+
+ switch (smps_mode_old) {
+ case IEEE80211_SMPS_STATIC:
+ return false;
+ case IEEE80211_SMPS_DYNAMIC:
+ return smps_mode_new == IEEE80211_SMPS_STATIC;
+ case IEEE80211_SMPS_OFF:
+ return smps_mode_new != IEEE80211_SMPS_OFF;
+ default:
+ WARN_ON(1);
+ }
+
+ return false;
+}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [RFC 1/2] mac80211: allow APs to send SMPS frames
2013-08-20 11:12 [RFC 1/2] mac80211: allow APs to send SMPS frames Emmanuel Grumbach
2013-08-20 11:12 ` [RFC 2/2] mac80211: implement SMPS for AP Emmanuel Grumbach
@ 2013-08-21 0:57 ` Julian Calaby
2013-08-21 4:59 ` Emmanuel Grumbach
1 sibling, 1 reply; 4+ messages in thread
From: Julian Calaby @ 2013-08-21 0:57 UTC (permalink / raw)
To: Emmanuel Grumbach; +Cc: linux-wireless
Hi Emmanuel,
One minor thing I noticed:
On Tue, Aug 20, 2013 at 9:12 PM, Emmanuel Grumbach
<emmanuel.grumbach@intel.com> wrote:
> SMPS code checks all over the place that the vif is
> BSS. Remove that constraint and allow SMPS for AP too.
>
> Provide dummy implementation that will be used for
> further patches.
>
> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
> ---
> net/mac80211/cfg.c | 15 ++++++++++++---
> net/mac80211/debugfs_netdev.c | 24 +++++++++++++++---------
> net/mac80211/ht.c | 38 ++++++++++++++++++++++++++++----------
> net/mac80211/ieee80211_i.h | 13 ++++++++++---
> net/mac80211/iface.c | 2 ++
> net/mac80211/mlme.c | 2 +-
> 6 files changed, 68 insertions(+), 26 deletions(-)
>
> diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
> index e601c9f..7609e47 100644
> --- a/net/mac80211/debugfs_netdev.c
> +++ b/net/mac80211/debugfs_netdev.c
> @@ -245,12 +248,15 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
> static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
> char *buf, int buflen)
> {
> - if (sdata->vif.type != NL80211_IFTYPE_STATION)
> - return -EOPNOTSUPP;
> -
> - return snprintf(buf, buflen, "request: %s\nused: %s\n",
> - smps_modes[sdata->u.mgd.req_smps],
> - smps_modes[sdata->smps_mode]);
> + if (sdata->vif.type == NL80211_IFTYPE_STATION)
> + return snprintf(buf, buflen, "request: %s\nused: %s\n",
> + smps_modes[sdata->u.mgd.req_smps],
> + smps_modes[sdata->smps_mode]);
> + if (sdata->vif.type == NL80211_IFTYPE_AP)
> + return snprintf(buf, buflen, "request: %s\nused: %s\n",
> + smps_modes[sdata->u.ap.req_smps],
> + smps_modes[sdata->smps_mode]);
> + return -EINVAL;
Do you intend to change the return value for this function when we
can't do SMPS from -EOPNOTSUPP to -EINVAL?
You've also included a couple of other cases where you return -EINVAL.
I'm assuming those are correct.
Thanks,
--
Julian Calaby
Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [RFC 1/2] mac80211: allow APs to send SMPS frames
2013-08-21 0:57 ` [RFC 1/2] mac80211: allow APs to send SMPS frames Julian Calaby
@ 2013-08-21 4:59 ` Emmanuel Grumbach
0 siblings, 0 replies; 4+ messages in thread
From: Emmanuel Grumbach @ 2013-08-21 4:59 UTC (permalink / raw)
To: Julian Calaby; +Cc: Emmanuel Grumbach, linux-wireless
Hi Julian,
Thanks for the review.
> On Tue, Aug 20, 2013 at 9:12 PM, Emmanuel Grumbach
> <emmanuel.grumbach@intel.com> wrote:
>> SMPS code checks all over the place that the vif is
>> BSS. Remove that constraint and allow SMPS for AP too.
>>
>> Provide dummy implementation that will be used for
>> further patches.
>>
>> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
>> ---
>> net/mac80211/cfg.c | 15 ++++++++++++---
>> net/mac80211/debugfs_netdev.c | 24 +++++++++++++++---------
>> net/mac80211/ht.c | 38 ++++++++++++++++++++++++++++----------
>> net/mac80211/ieee80211_i.h | 13 ++++++++++---
>> net/mac80211/iface.c | 2 ++
>> net/mac80211/mlme.c | 2 +-
>> 6 files changed, 68 insertions(+), 26 deletions(-)
>>
>> diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
>> index e601c9f..7609e47 100644
>> --- a/net/mac80211/debugfs_netdev.c
>> +++ b/net/mac80211/debugfs_netdev.c
>> @@ -245,12 +248,15 @@ static const char *smps_modes[IEEE80211_SMPS_NUM_MODES] = {
>> static ssize_t ieee80211_if_fmt_smps(const struct ieee80211_sub_if_data *sdata,
>> char *buf, int buflen)
>> {
>> - if (sdata->vif.type != NL80211_IFTYPE_STATION)
>> - return -EOPNOTSUPP;
>> -
>> - return snprintf(buf, buflen, "request: %s\nused: %s\n",
>> - smps_modes[sdata->u.mgd.req_smps],
>> - smps_modes[sdata->smps_mode]);
>> + if (sdata->vif.type == NL80211_IFTYPE_STATION)
>> + return snprintf(buf, buflen, "request: %s\nused: %s\n",
>> + smps_modes[sdata->u.mgd.req_smps],
>> + smps_modes[sdata->smps_mode]);
>> + if (sdata->vif.type == NL80211_IFTYPE_AP)
>> + return snprintf(buf, buflen, "request: %s\nused: %s\n",
>> + smps_modes[sdata->u.ap.req_smps],
>> + smps_modes[sdata->smps_mode]);
>> + return -EINVAL;
>
> Do you intend to change the return value for this function when we
> can't do SMPS from -EOPNOTSUPP to -EINVAL?
You are right - v2 on the way with other comments I got internally.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-08-21 4:59 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-20 11:12 [RFC 1/2] mac80211: allow APs to send SMPS frames Emmanuel Grumbach
2013-08-20 11:12 ` [RFC 2/2] mac80211: implement SMPS for AP Emmanuel Grumbach
2013-08-21 0:57 ` [RFC 1/2] mac80211: allow APs to send SMPS frames Julian Calaby
2013-08-21 4:59 ` Emmanuel Grumbach
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox