From 84381b4ed58498e1e3d49a4a306fec9894b8e00c Mon Sep 17 00:00:00 2001 From: Nikolay Martynov Date: Sat, 17 Dec 2011 19:39:35 -0500 Subject: mac80211: split addba retries in time Currently code allows three (HT_AGG_MAX_RETRIES) unanswered addba requests. When this limit is reached aggregation is turned off for given TID permanently. This doesn't seem right: three requests is not that much, some 'blackout' can happen, but effect of it affects whole connection indefinitely. This patch increases number of retries to 15. Also, when there have been 3 or more retries it splits further retries apart by 15 seconds instead of sending them in very short period of time. Signed-off-by: Nikolay Martynov Signed-off-by: John W. Linville --- net/mac80211/agg-tx.c | 19 +++++++++++++++++++ net/mac80211/sta_info.h | 6 +++++- 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index e92f98d32746..76be61744198 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -392,6 +392,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) #endif spin_lock_bh(&sta->lock); + sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; sta->ampdu_mlme.addba_req_num[tid]++; spin_unlock_bh(&sta->lock); @@ -492,6 +493,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, goto err_unlock_sta; } + /* + * if we have tried more than HT_AGG_BURST_RETRIES times we + * will spread our requests in time to avoid stalling connection + * for too long + */ + if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES && + time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + + HT_AGG_RETRIES_PERIOD)) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - " + "waiting a grace period after %d failed requests " + "on tid %u\n", + sta->ampdu_mlme.addba_req_num[tid], tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EBUSY; + goto err_unlock_sta; + } + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 15b3bb7d8629..dee284290464 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -83,7 +83,9 @@ enum ieee80211_sta_state { #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ -#define HT_AGG_MAX_RETRIES 0x3 +#define HT_AGG_MAX_RETRIES 15 +#define HT_AGG_BURST_RETRIES 3 +#define HT_AGG_RETRIES_PERIOD (15 * HZ) #define HT_AGG_STATE_DRV_READY 0 #define HT_AGG_STATE_RESPONSE_RECEIVED 1 @@ -179,6 +181,7 @@ struct tid_ampdu_rx { * @tid_tx: aggregation info for Tx per TID * @tid_start_tx: sessions where start was requested * @addba_req_num: number of times addBA request has been sent. + * @last_addba_req_time: timestamp of the last addBA request. * @dialog_token_allocator: dialog token enumerator for each new session; * @work: work struct for starting/stopping aggregation * @tid_rx_timer_expired: bitmap indicating on which TIDs the @@ -198,6 +201,7 @@ struct sta_ampdu_mlme { struct work_struct work; struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM]; struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM]; + unsigned long last_addba_req_time[STA_TID_NUM]; u8 addba_req_num[STA_TID_NUM]; u8 dialog_token_allocator; }; -- cgit v1.2.3 From a85e1d55974646a442d95911e3f7d7a891ea9ac5 Mon Sep 17 00:00:00 2001 From: Paul Stewart Date: Fri, 9 Dec 2011 11:01:49 -0800 Subject: cfg80211: Return beacon loss count in station If station info contains a beacon loss count, return it to userspace. Signed-off-by: Paul Stewart Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ include/net/cfg80211.h | 7 ++++++- net/mac80211/cfg.c | 4 +++- net/mac80211/mlme.c | 8 ++++++++ net/mac80211/sta_info.h | 2 ++ net/wireless/nl80211.c | 3 +++ 6 files changed, 24 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f795cb7dccdd..0f5ff3739820 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1655,6 +1655,7 @@ enum nl80211_sta_bss_param { * containing info as possible, see &enum nl80211_sta_bss_param * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update. + * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -1677,6 +1678,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_BSS_PARAM, NL80211_STA_INFO_CONNECTED_TIME, NL80211_STA_INFO_STA_FLAGS, + NL80211_STA_INFO_BEACON_LOSS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 9f85fca0b676..15f4be7d768e 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -505,6 +505,7 @@ struct station_parameters { * @STATION_INFO_CONNECTED_TIME: @connected_time filled * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled * @STATION_INFO_STA_FLAGS: @sta_flags filled + * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -525,7 +526,8 @@ enum station_info_flags { STATION_INFO_BSS_PARAM = 1<<15, STATION_INFO_CONNECTED_TIME = 1<<16, STATION_INFO_ASSOC_REQ_IES = 1<<17, - STATION_INFO_STA_FLAGS = 1<<18 + STATION_INFO_STA_FLAGS = 1<<18, + STATION_INFO_BEACON_LOSS_COUNT = 1<<19 }; /** @@ -623,6 +625,7 @@ struct sta_bss_parameters { * the cfg80211_new_sta() calls to notify user space of the IEs. * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets. * @sta_flags: station flags mask & values + * @beacon_loss_count: Number of times beacon loss event has triggered. */ struct station_info { u32 filled; @@ -650,6 +653,8 @@ struct station_info { const u8 *assoc_req_ies; size_t assoc_req_ies_len; + u32 beacon_loss_count; + /* * Note: Add a new enum station_info_flags value for each new field and * use it to check which fields are initialized. diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 66ad9d9af87f..850bb96bd680 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -355,7 +355,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) STATION_INFO_RX_DROP_MISC | STATION_INFO_BSS_PARAM | STATION_INFO_CONNECTED_TIME | - STATION_INFO_STA_FLAGS; + STATION_INFO_STA_FLAGS | + STATION_INFO_BEACON_LOSS_COUNT; do_posix_clock_monotonic_gettime(&uptime); sinfo->connected_time = uptime.tv_sec - sta->last_connected; @@ -368,6 +369,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->tx_retries = sta->tx_retry_count; sinfo->tx_failed = sta->tx_retry_failed; sinfo->rx_dropped_misc = sta->rx_dropped; + sinfo->beacon_loss_count = sta->beacon_loss_count; if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index a984f1f60ddb..57989a046fca 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1381,6 +1381,14 @@ void ieee80211_beacon_connection_loss_work(struct work_struct *work) struct ieee80211_sub_if_data *sdata = container_of(work, struct ieee80211_sub_if_data, u.mgd.beacon_connection_loss_work); + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct sta_info *sta; + + if (ifmgd->associated) { + sta = sta_info_get(sdata, ifmgd->bssid); + if (sta) + sta->beacon_loss_count++; + } if (sdata->local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR) __ieee80211_connection_loss(sdata); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index dee284290464..6f77f12dc3fc 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -275,6 +275,7 @@ struct sta_ampdu_mlme { * EAP frames before association * @sta: station information we share with the driver * @sta_state: duplicates information about station state (for debug) + * @beacon_loss_count: number of times beacon loss has triggered */ struct sta_info { /* General information, mostly static */ @@ -367,6 +368,7 @@ struct sta_info { #endif unsigned int lost_packets; + unsigned int beacon_loss_count; /* should be right in front of sta to be in the same cache line */ bool dummy; diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b07c4fc4ae22..b3d3cf8931cb 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2390,6 +2390,9 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_TX_FAILED) NLA_PUT_U32(msg, NL80211_STA_INFO_TX_FAILED, sinfo->tx_failed); + if (sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) + NLA_PUT_U32(msg, NL80211_STA_INFO_BEACON_LOSS, + sinfo->beacon_loss_count); if (sinfo->filled & STATION_INFO_BSS_PARAM) { bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM); if (!bss_param) -- cgit v1.2.3 From 1d8d3dec5fbba15864f25c734a7fda5703234091 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 16 Dec 2011 15:28:57 +0100 Subject: mac80211: handle SMPS action frames When a peer changes SMPS state we should update rate control so it doesn't have to detect it by itself. It can't detect "dynamic" mode anyway since that just requires rts-cts handshaking. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 5 ++++- net/mac80211/rx.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5b5c8a7e26d7..2a7523edd9b5 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3502,9 +3502,12 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn); * * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have * changed, rate control algorithm can update its internal state if needed. + * @IEEE80211_RC_SMPS_CHANGED: The SMPS state of the station changed, the rate + * control algorithm needs to adjust accordingly. */ enum rate_control_changed { - IEEE80211_RC_HT_CHANGED = BIT(0) + IEEE80211_RC_HT_CHANGED = BIT(0), + IEEE80211_RC_SMPS_CHANGED = BIT(1), }; /** diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2be5b7d69ad7..57832eb44f3e 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -28,6 +28,7 @@ #include "wpa.h" #include "tkip.h" #include "wme.h" +#include "rate.h" /* * monitor mode reception @@ -2233,6 +2234,63 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; switch (mgmt->u.action.category) { + case WLAN_CATEGORY_HT: + /* reject HT action frames from stations not supporting HT */ + if (!rx->sta->sta.ht_cap.ht_supported) + goto invalid; + + if (sdata->vif.type != NL80211_IFTYPE_STATION && + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && + sdata->vif.type != NL80211_IFTYPE_AP_VLAN && + sdata->vif.type != NL80211_IFTYPE_AP && + sdata->vif.type != NL80211_IFTYPE_ADHOC) + break; + + /* verify action & smps_control are present */ + if (len < IEEE80211_MIN_ACTION_SIZE + 2) + goto invalid; + + switch (mgmt->u.action.u.ht_smps.action) { + case WLAN_HT_ACTION_SMPS: { + struct ieee80211_supported_band *sband; + u8 smps; + + /* convert to HT capability */ + switch (mgmt->u.action.u.ht_smps.smps_control) { + case WLAN_HT_SMPS_CONTROL_DISABLED: + smps = WLAN_HT_CAP_SM_PS_DISABLED; + break; + case WLAN_HT_SMPS_CONTROL_STATIC: + smps = WLAN_HT_CAP_SM_PS_STATIC; + break; + case WLAN_HT_SMPS_CONTROL_DYNAMIC: + smps = WLAN_HT_CAP_SM_PS_DYNAMIC; + break; + default: + goto invalid; + } + smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT; + + /* if no change do nothing */ + if ((rx->sta->sta.ht_cap.cap & + IEEE80211_HT_CAP_SM_PS) == smps) + goto handled; + + rx->sta->sta.ht_cap.cap &= ~IEEE80211_HT_CAP_SM_PS; + rx->sta->sta.ht_cap.cap |= smps; + + sband = rx->local->hw.wiphy->bands[status->band]; + + rate_control_rate_update(local, sband, rx->sta, + IEEE80211_RC_SMPS_CHANGED, + local->_oper_channel_type); + goto handled; + } + default: + goto invalid; + } + + break; case WLAN_CATEGORY_BACK: if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_MESH_POINT && -- cgit v1.2.3 From 27bf88829f50cf1af2b052ecee2f6f0dbe4a5141 Mon Sep 17 00:00:00 2001 From: Yogesh Ashok Powar Date: Fri, 16 Dec 2011 11:47:15 +0530 Subject: mac80211: Fixing sparse warning at sta_info.c The commit 42624d4913a00219a8fdbb4bafd634d1d843be85 created following sparse warning >net/mac80211/sta_info.c:965:24: warning: incorrect type in assignment (different address spaces) >net/mac80211/sta_info.c:965:24: expected struct tid_ampdu_tx *tid_tx >net/mac80211/sta_info.c:965:24: got struct tid_ampdu_tx [noderef] * Making use of rcu_dereference_protected to fix the problem. V2: - Replacing rcu_dereference with rcu_dereference_protected as suggested by Johannes. - Adding mutex_lock/unlock to satisfy the condition at rcu_dereference_protected Cc: Nishant Sarmukadam Reported-by: Johannes Berg Signed-off-by: Yogesh Ashok Powar Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'net/mac80211') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 2db01e9541e7..3d01abb2b813 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -822,10 +822,13 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) * until the aggregation stop completes. Refer * http://thread.gmane.org/gmane.linux.kernel.wireless.general/81936 */ + + mutex_lock(&sta->ampdu_mlme.mtx); + for (i = 0; i < STA_TID_NUM; i++) { - if (!sta->ampdu_mlme.tid_tx[i]) + tid_tx = rcu_dereference_protected_tid_tx(sta, i); + if (!tid_tx) continue; - tid_tx = sta->ampdu_mlme.tid_tx[i]; if (skb_queue_len(&tid_tx->pending)) { #ifdef CONFIG_MAC80211_HT_DEBUG wiphy_debug(local->hw.wiphy, "TX A-MPDU purging %d " @@ -837,6 +840,8 @@ static int __must_check __sta_info_destroy(struct sta_info *sta) kfree_rcu(tid_tx, rcu_head); } + mutex_unlock(&sta->ampdu_mlme.mtx); + sta_info_free(local, sta); return 0; -- cgit v1.2.3 From ec2b774e7c91094d8c00de579646f1162b87b01e Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 20 Dec 2011 23:16:52 +0800 Subject: mac80211: ibss should not purge clients it is not responsible for The IBSS merge code calls ieee80211_sta_expire() with a relatively short expire timeout that purges other clients prematurely. The expire function has to check that only the clients belonging to the vif in question are purged. Signed-off-by: Marek Lindner Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/mac80211') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3d01abb2b813..f0d3b483dabd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -946,6 +946,9 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, mutex_lock(&local->sta_mtx); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) + if (sdata != sta->sdata) + continue; + if (time_after(jiffies, sta->last_rx + exp_time)) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", -- cgit v1.2.3 From aef6c928a92481f75fbd548eb8c1e840912444b8 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 21 Dec 2011 09:11:35 +0100 Subject: mac80211: Keep skb->piority for relayed frames in AP mode When mac80211 relays a frame from STA1 to STA2 in AP mode it will get re-classified in the tx path. Unfortunately the frame protocol field is always set to ETH_P_8023 while the classification only kicks in for ETH_P_IP. Hence, a high priority frame from STA1 will be send to STA2 as best effort. Instead of running classification on the frame just use the same priority as STA1 did. Do this by adding 256 to the skb->priority to allow cfg80211_classify8021d to shortcut frame classification. Signed-off-by: Helmut Schaa Signed-off-by: John W. Linville --- net/mac80211/rx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net/mac80211') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 57832eb44f3e..59f124c58333 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1827,7 +1827,12 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) } if (xmit_skb) { - /* send to wireless media */ + /* + * Send to wireless media and increase priority by 256 to + * keep the received priority instead of reclassifying + * the frame (see cfg80211_classify8021d). + */ + xmit_skb->priority += 256; xmit_skb->protocol = htons(ETH_P_802_3); skb_reset_network_header(xmit_skb); skb_reset_mac_header(xmit_skb); -- cgit v1.2.3