mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-10 22:40:54 -04:00
qcacld-3.0: Synchronize sta_info access in host driver
Currently there is no synchronized access for sta_info. Because of this memory use after free is getting triggered. To resolve this, use a reference count for sta_info to check whether it is in use or not before freeing. Change-Id: I696461a1f53f4cc4739963f3f97ada31d3fa15f3 CRs-Fixed: 2637074
This commit is contained in:
parent
bcadcc00c3
commit
51ab1164a1
7 changed files with 98 additions and 12 deletions
|
|
@ -10399,6 +10399,7 @@ static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy,
|
|||
nss = sta_info->nss;
|
||||
freq = (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operating_chan_freq;
|
||||
rate_flags = sta_info->rate_flags;
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
} else {
|
||||
hdd_err("Not Associated! with mac "QDF_MAC_ADDR_STR,
|
||||
QDF_MAC_ADDR_ARRAY(peer_mac));
|
||||
|
|
@ -21183,6 +21184,8 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
|
|||
hdd_debug("Skip DEL STA as deauth is in progress::"
|
||||
QDF_MAC_ADDR_STR,
|
||||
QDF_MAC_ADDR_ARRAY(mac));
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info,
|
||||
true);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
|
|
@ -21190,6 +21193,7 @@ int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy,
|
|||
QDF_MAC_ADDR_ARRAY(mac));
|
||||
hdd_softap_deauth_current_sta(adapter, sta_info, hapd_state,
|
||||
param);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
}
|
||||
|
||||
fn_end:
|
||||
|
|
|
|||
|
|
@ -1530,7 +1530,7 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
|
|||
if (!cache_sta_info) {
|
||||
cache_sta_info = qdf_mem_malloc(sizeof(*cache_sta_info));
|
||||
if (!cache_sta_info)
|
||||
return;
|
||||
goto exit;
|
||||
|
||||
qdf_mem_copy(cache_sta_info, stainfo, sizeof(*cache_sta_info));
|
||||
cache_sta_info->assoc_req_ies.data =
|
||||
|
|
@ -1579,6 +1579,9 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
|
|||
hdd_sta_info_attach(&adapter->cache_sta_info_list,
|
||||
cache_sta_info);
|
||||
}
|
||||
} else {
|
||||
hdd_put_sta_info(&adapter->cache_sta_info_list,
|
||||
&cache_sta_info, true);
|
||||
}
|
||||
|
||||
hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d",
|
||||
|
|
@ -1599,6 +1602,9 @@ static void hdd_fill_station_info(struct hdd_adapter *adapter,
|
|||
stainfo->max_mcs_idx,
|
||||
stainfo->rx_mcs_map,
|
||||
stainfo->tx_mcs_map);
|
||||
exit:
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
return;
|
||||
}
|
||||
|
||||
void hdd_stop_sap_due_to_invalid_channel(struct work_struct *work)
|
||||
|
|
@ -2219,10 +2225,13 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
|
|||
&adapter->sta_info_list,
|
||||
(uint8_t *)&wrqu.addr.sa_data);
|
||||
|
||||
if (stainfo)
|
||||
if (stainfo) {
|
||||
stainfo->ecsa_capable = event->ecsa_capable;
|
||||
else
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo,
|
||||
true);
|
||||
} else {
|
||||
hdd_err("Station not found");
|
||||
}
|
||||
|
||||
if (ucfg_ipa_is_enabled()) {
|
||||
status = ucfg_ipa_wlan_evt(hdd_ctx->pdev,
|
||||
|
|
@ -2325,6 +2334,8 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
|
|||
cache_stainfo->tx_rate,
|
||||
cache_stainfo->rx_rate,
|
||||
cache_stainfo->reason_code);
|
||||
hdd_put_sta_info(&adapter->cache_sta_info_list,
|
||||
&cache_stainfo, true);
|
||||
}
|
||||
hdd_nofl_info("SAP disassociated " QDF_MAC_ADDR_STR,
|
||||
QDF_MAC_ADDR_ARRAY(wrqu.addr.sa_data));
|
||||
|
|
@ -2361,6 +2372,7 @@ QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event,
|
|||
WMA_DHCP_STOP_IND);
|
||||
stainfo->dhcp_nego_status = DHCP_NEGO_STOP;
|
||||
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
hdd_softap_deregister_sta(adapter, &stainfo);
|
||||
|
||||
ap_ctx->ap_active = false;
|
||||
|
|
|
|||
|
|
@ -389,6 +389,7 @@ int hdd_softap_inspect_dhcp_packet(struct hdd_adapter *adapter,
|
|||
hdd_debug("EXIT: phase=%d, nego_status=%d",
|
||||
hdd_sta_info->dhcp_phase,
|
||||
hdd_sta_info->dhcp_nego_status);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &hdd_sta_info, true);
|
||||
}
|
||||
|
||||
return errno;
|
||||
|
|
@ -423,7 +424,7 @@ static void __hdd_softap_hard_start_xmit(struct sk_buff *skb,
|
|||
static struct qdf_mac_addr bcast_mac_addr = QDF_MAC_ADDR_BCAST_INIT;
|
||||
void *soc = cds_get_context(QDF_MODULE_ID_SOC);
|
||||
uint32_t num_seg;
|
||||
struct hdd_station_info *sta_info;
|
||||
struct hdd_station_info *sta_info = NULL;
|
||||
|
||||
++adapter->hdd_stats.tx_rx_stats.tx_called;
|
||||
adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0;
|
||||
|
|
@ -606,12 +607,15 @@ static void __hdd_softap_hard_start_xmit(struct sk_buff *skb,
|
|||
netif_trans_update(dev);
|
||||
|
||||
wlan_hdd_sar_unsolicited_timer_start(hdd_ctx);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
|
||||
return;
|
||||
|
||||
drop_pkt_and_release_skb:
|
||||
qdf_net_buf_debug_release_skb(skb);
|
||||
drop_pkt:
|
||||
if (sta_info)
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
|
||||
qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID,
|
||||
QDF_DP_TRACE_DROP_PACKET_RECORD, 0,
|
||||
|
|
@ -744,6 +748,7 @@ QDF_STATUS hdd_softap_init_tx_rx_sta(struct hdd_adapter *adapter,
|
|||
sta_mac->bytes);
|
||||
|
||||
if (sta_info) {
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
hdd_err("Reinit of in use station " QDF_MAC_ADDR_STR,
|
||||
QDF_MAC_ADDR_ARRAY(sta_mac->bytes));
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
|
|
@ -890,6 +895,8 @@ QDF_STATUS hdd_softap_rx_packet_cbk(void *adapter_context, qdf_nbuf_t rx_buf)
|
|||
sta_info->rx_bytes += skb->len;
|
||||
sta_info->last_tx_rx_ts = qdf_system_ticks();
|
||||
hdd_softap_inspect_dhcp_packet(adapter, skb, QDF_RX);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info,
|
||||
true);
|
||||
}
|
||||
|
||||
hdd_event_eapol_log(skb, QDF_RX);
|
||||
|
|
@ -1040,6 +1047,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
|
|||
hdd_debug("clean up old entry for STA MAC " QDF_MAC_ADDR_STR,
|
||||
QDF_MAC_ADDR_ARRAY(sta_mac->bytes));
|
||||
hdd_softap_deregister_sta(adapter, &sta_info);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1090,6 +1098,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
|
|||
if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
|
||||
hdd_debug("cdp_peer_register() failed to register. Status = %d [0x%08X]",
|
||||
qdf_status, qdf_status);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
return qdf_status;
|
||||
}
|
||||
|
||||
|
|
@ -1133,6 +1142,7 @@ QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter,
|
|||
sta_info->peer_state = OL_TXRX_PEER_STATE_CONN;
|
||||
}
|
||||
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
hdd_debug("Enabling queues");
|
||||
wlan_hdd_netif_queue_control(adapter,
|
||||
WLAN_START_ALL_NETIF_QUEUE_N_CARRIER,
|
||||
|
|
@ -1256,6 +1266,7 @@ QDF_STATUS hdd_softap_change_sta_state(struct hdd_adapter *adapter,
|
|||
p2p_peer_authorized(adapter->vdev, sta_mac->bytes);
|
||||
}
|
||||
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &sta_info, true);
|
||||
hdd_exit();
|
||||
return qdf_status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container,
|
|||
|
||||
qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
|
||||
|
||||
qdf_atomic_set(&sta_info->ref_cnt, 1);
|
||||
qdf_ht_add(sta_info_container->sta_obj, &sta_info->sta_node,
|
||||
WLAN_HDD_STA_INFO_HASH(sta_info->sta_mac.bytes));
|
||||
|
||||
|
|
@ -83,19 +84,16 @@ void hdd_sta_info_detach(struct hdd_sta_info_obj *sta_info_container,
|
|||
}
|
||||
|
||||
info = *sta_info;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
|
||||
|
||||
qdf_ht_remove(&(info->sta_node));
|
||||
hdd_put_sta_info(sta_info_container, sta_info, false);
|
||||
|
||||
qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
|
||||
|
||||
if (info->assoc_req_ies.len) {
|
||||
qdf_mem_free(info->assoc_req_ies.data);
|
||||
info->assoc_req_ies.data = NULL;
|
||||
info->assoc_req_ies.len = 0;
|
||||
}
|
||||
qdf_mem_free(info);
|
||||
*sta_info = NULL;
|
||||
}
|
||||
|
||||
struct hdd_station_info *hdd_get_sta_info_by_mac(
|
||||
|
|
@ -115,6 +113,7 @@ struct hdd_station_info *hdd_get_sta_info_by_mac(
|
|||
sta_node, WLAN_HDD_STA_INFO_HASH(mac_addr)) {
|
||||
if (qdf_is_macaddr_equal(&sta_info->sta_mac,
|
||||
(struct qdf_mac_addr *)mac_addr)) {
|
||||
qdf_atomic_inc(&sta_info->ref_cnt);
|
||||
qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
|
||||
return sta_info;
|
||||
}
|
||||
|
|
@ -125,6 +124,45 @@ struct hdd_station_info *hdd_get_sta_info_by_mac(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
|
||||
struct hdd_station_info **sta_info, bool lock_required)
|
||||
{
|
||||
struct hdd_station_info *info;
|
||||
|
||||
if (!sta_info_container || !sta_info) {
|
||||
hdd_err("Parameter(s) null");
|
||||
return;
|
||||
}
|
||||
|
||||
info = *sta_info;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (lock_required)
|
||||
qdf_spin_lock_bh(&sta_info_container->sta_obj_lock);
|
||||
|
||||
qdf_atomic_dec(&info->ref_cnt);
|
||||
|
||||
if (qdf_atomic_read(&info->ref_cnt)) {
|
||||
if (lock_required)
|
||||
qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->assoc_req_ies.len) {
|
||||
qdf_mem_free(info->assoc_req_ies.data);
|
||||
info->assoc_req_ies.data = NULL;
|
||||
info->assoc_req_ies.len = 0;
|
||||
}
|
||||
|
||||
qdf_mem_free(info);
|
||||
*sta_info = NULL;
|
||||
|
||||
if (lock_required)
|
||||
qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock);
|
||||
}
|
||||
|
||||
void hdd_clear_cached_sta_info(struct hdd_sta_info_obj *sta_info_container)
|
||||
{
|
||||
struct hdd_station_info *sta_info = NULL;
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ enum dhcp_nego_status {
|
|||
* feature, if it is 0 it indicates FW doesn't support this feature
|
||||
* @sta_info: The sta_info node for the station info list maintained in adapter
|
||||
* @assoc_req_ies: Assoc request IEs of the peer station
|
||||
* @ref_cnt: Reference count to synchronize sta_info access
|
||||
*/
|
||||
struct hdd_station_info {
|
||||
bool in_use;
|
||||
|
|
@ -171,6 +172,7 @@ struct hdd_station_info {
|
|||
uint32_t rx_mc_bc_cnt;
|
||||
struct qdf_ht_entry sta_node;
|
||||
struct wlan_ies assoc_req_ies;
|
||||
qdf_atomic_t ref_cnt;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -269,6 +271,18 @@ QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container,
|
|||
struct hdd_station_info *hdd_get_sta_info_by_mac(
|
||||
struct hdd_sta_info_obj *sta_info_container,
|
||||
const uint8_t *mac_addr);
|
||||
|
||||
/**
|
||||
* hdd_put_sta_info() - Release sta_info for synchronization
|
||||
* @sta_info_container: The station info container obj that stores and maintains
|
||||
* the sta_info obj.
|
||||
* @sta_info: Station info structure to be released.
|
||||
*
|
||||
* Return: None
|
||||
*/
|
||||
void hdd_put_sta_info(struct hdd_sta_info_obj *sta_info_container,
|
||||
struct hdd_station_info **sta_info, bool lock_required);
|
||||
|
||||
/**
|
||||
* hdd_clear_cached_sta_info() - Clear the cached sta info from the container
|
||||
* @sta_info_container: The station info container obj that stores and maintains
|
||||
|
|
|
|||
|
|
@ -1059,6 +1059,7 @@ static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx,
|
|||
|
||||
skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
|
||||
if (!skb) {
|
||||
hdd_put_sta_info(&adapter->cache_sta_info_list, &stainfo, true);
|
||||
hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -1125,10 +1126,12 @@ static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx,
|
|||
}
|
||||
}
|
||||
hdd_sta_info_detach(&adapter->cache_sta_info_list, &stainfo);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
qdf_atomic_dec(&adapter->cache_sta_count);
|
||||
|
||||
return cfg80211_vendor_cmd_reply(skb);
|
||||
fail:
|
||||
hdd_put_sta_info(&adapter->cache_sta_info_list, &stainfo, true);
|
||||
if (skb)
|
||||
kfree_skb(skb);
|
||||
|
||||
|
|
@ -1286,11 +1289,13 @@ static int hdd_get_station_remote(struct hdd_context *hdd_ctx,
|
|||
if (!is_associated) {
|
||||
status = hdd_get_cached_station_remote(hdd_ctx, adapter,
|
||||
mac_addr);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = hdd_get_connected_station_info(hdd_ctx, adapter,
|
||||
mac_addr, stainfo);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4083,6 +4083,7 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
|
|||
qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE);
|
||||
status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info);
|
||||
if (status) {
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
hdd_err("fail to get peer info from fw");
|
||||
return -EPERM;
|
||||
}
|
||||
|
|
@ -4097,6 +4098,7 @@ static int wlan_hdd_get_station_remote(struct wiphy *wiphy,
|
|||
txrx_stats.rssi = peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM;
|
||||
wlan_hdd_fill_rate_info(&txrx_stats, &peer_info);
|
||||
wlan_hdd_fill_station_info(hddctx->psoc, sinfo, stainfo, &txrx_stats);
|
||||
hdd_put_sta_info(&adapter->sta_info_list, &stainfo, true);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue