From 2ef479048d8f1dcf665f6aa135b4a163e518f91b Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Fri, 12 Oct 2018 21:13:57 +0530 Subject: [PATCH] qcacld-3.0: Clear oldest cached sta information Currently host is caching all the connected sta info in case of SAP, once the sta count reaches to MAX, below mentioned issues occurs: 1. Driver can not cache the information of newly connected stations. 2. Some of the info is cached at the time of connection while remaining info is cached during disconnection. In the disconnect path driver tries to cache some of the info such mc_bc count, disconnect reason code, since driver can't cache anymore info, it does not find the current station which is getting disconnected in cache sta info structure leading to an error, and driver is returning an error without completing the wait for disconnect event which is resulting in timeout. Since sta_disconnect comes with rtnl_held, any other process is not able to get the rtnl_lock until this timeout occurs. To address this issue below mentioned two measures taken care: Clear the oldest cached sta information and save the newly connected station's information. In the disconnect path, do not return any error and simply proceed with disconnection as failure to cache the information of sta should not stop the disconnection process. Change-Id: Ia955a6774033fdfa91ff1fa7c8832b3ec7e8e1a0 CRs-Fixed: 2333075 --- core/hdd/inc/wlan_hdd_main.h | 1 + core/hdd/src/wlan_hdd_hostapd.c | 76 +++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 371148a964aa..628c975f93cd 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -1042,6 +1042,7 @@ struct hdd_station_info { uint64_t rx_bytes; qdf_time_t last_tx_rx_ts; qdf_time_t assoc_ts; + qdf_time_t disassoc_ts; uint32_t tx_rate; uint32_t rx_rate; bool ampdu; diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index dca2dbe16355..b7a76473e0a5 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -1419,7 +1419,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter, tSap_StationAssocReassocCompleteEvent *event) { struct hdd_station_info *stainfo; - uint8_t i = 0; + uint8_t i = 0, oldest_disassoc_sta_idx = WLAN_MAX_STA_COUNT + 1; + qdf_time_t oldest_disassoc_sta_ts = 0; if (event->staId >= WLAN_MAX_STA_COUNT) { hdd_err("invalid sta id"); @@ -1480,11 +1481,8 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter, while (i < WLAN_MAX_STA_COUNT) { if (!qdf_mem_cmp(adapter->cache_sta_info[i].sta_mac.bytes, event->staMac.bytes, - QDF_MAC_ADDR_SIZE)) { - qdf_mem_zero(&adapter->cache_sta_info[i], - sizeof(*stainfo)); + QDF_MAC_ADDR_SIZE)) break; - } i++; } if (i >= WLAN_MAX_STA_COUNT) { @@ -1492,14 +1490,35 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter, while (i < WLAN_MAX_STA_COUNT) { if (adapter->cache_sta_info[i].in_use != TRUE) break; + + if (adapter->cache_sta_info[i].disassoc_ts && + (!oldest_disassoc_sta_ts || + (qdf_system_time_after( + oldest_disassoc_sta_ts, + adapter-> + cache_sta_info[i].disassoc_ts)))) { + oldest_disassoc_sta_ts = + adapter-> + cache_sta_info[i].disassoc_ts; + oldest_disassoc_sta_idx = i; + } i++; } } - if (i < WLAN_MAX_STA_COUNT) + + if ((i == WLAN_MAX_STA_COUNT) && oldest_disassoc_sta_ts) { + hdd_debug("reached max cached staid, removing oldest stainfo"); + i = oldest_disassoc_sta_idx; + } + if (i < WLAN_MAX_STA_COUNT) { + qdf_mem_zero(&adapter->cache_sta_info[i], + sizeof(*stainfo)); qdf_mem_copy(&adapter->cache_sta_info[i], - stainfo, sizeof(struct hdd_station_info)); - else + stainfo, sizeof(struct hdd_station_info)); + + } else { hdd_debug("reached max staid, stainfo can't be cached"); + } hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d", stainfo->ampdu, @@ -1597,7 +1616,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, eCsrPhyMode phy_mode; bool legacy_phymode; tSap_StationDisassocCompleteEvent *disassoc_comp; - struct hdd_station_info *stainfo; + struct hdd_station_info *stainfo, *cache_stainfo; mac_handle_t mac_handle; tsap_config_t *sap_config; @@ -2193,21 +2212,19 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, memcpy(wrqu.addr.sa_data, &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE); - stainfo = hdd_get_stainfo(adapter->cache_sta_info, - disassoc_comp->staMac); - if (!stainfo) { - hdd_err("peer " MAC_ADDRESS_STR " not found", - MAC_ADDR_ARRAY(wrqu.addr.sa_data)); - return -EINVAL; + cache_stainfo = hdd_get_stainfo(adapter->cache_sta_info, + disassoc_comp->staMac); + if (cache_stainfo) { + /* Cache the disassoc info */ + cache_stainfo->rssi = disassoc_comp->rssi; + cache_stainfo->tx_rate = disassoc_comp->tx_rate; + cache_stainfo->rx_rate = disassoc_comp->rx_rate; + cache_stainfo->reason_code = disassoc_comp->reason_code; + cache_stainfo->disassoc_ts = qdf_system_ticks(); } hdd_info(" disassociated " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(wrqu.addr.sa_data)); - stainfo->rssi = disassoc_comp->rssi; - stainfo->tx_rate = disassoc_comp->tx_rate; - stainfo->rx_rate = disassoc_comp->rx_rate; - stainfo->reason_code = disassoc_comp->reason_code; - qdf_status = qdf_event_set(&hostapd_state->qdf_sta_disassoc_event); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) hdd_err("Station Deauth event Set failed"); @@ -2233,14 +2250,17 @@ QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, QDF_TRACE_DEFAULT_PDEV_ID, QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); - /* Send DHCP STOP indication to FW */ - stainfo->dhcp_phase = DHCP_PHASE_ACK; - if (stainfo->dhcp_nego_status == - DHCP_NEGO_IN_PROGRESS) - hdd_post_dhcp_ind(adapter, staId, - WMA_DHCP_STOP_IND); - stainfo->dhcp_nego_status = DHCP_NEGO_STOP; - + stainfo = hdd_get_stainfo(adapter->sta_info, + disassoc_comp->staMac); + if (stainfo) { + /* Send DHCP STOP indication to FW */ + stainfo->dhcp_phase = DHCP_PHASE_ACK; + if (stainfo->dhcp_nego_status == + DHCP_NEGO_IN_PROGRESS) + hdd_post_dhcp_ind(adapter, staId, + WMA_DHCP_STOP_IND); + stainfo->dhcp_nego_status = DHCP_NEGO_STOP; + } hdd_softap_deregister_sta(adapter, staId); ap_ctx->ap_active = false;