qcacld-3.0: Allocate skb size according to destination attribute sizes

In hdd_get_station_info skb buffer gets allocated an
arbitrary large size.

To address this issue, allocate skb buffer size based
upon the destination attribute sizes.

Change-Id: Ie36b0bb67562e302a3abe6d60d0e323ce172236e
CRs-Fixed: 3363955
This commit is contained in:
Asutosh Mohapatra
2022-11-22 17:40:47 +05:30
committed by Madan Koyyalamudi
parent 7460e2b439
commit 7b08e108e0

View File

@@ -140,13 +140,6 @@
#define ASSOC_REQ_IES \
QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_REQ_IES
/*
* it may include the beacon IEs and other miscellaneous information
* in function hdd_get_station_info, malloc enough memory to save
* the data.
*/
#define WLAN_STATS_INFO_LEN 2048
/*
* MSB of rx_mc_bc_cnt indicates whether FW supports rx_mc_bc_cnt
* feature or not, if first bit is 1 it indicates that FW supports this
@@ -383,6 +376,25 @@ static int hdd_convert_dot11mode(uint32_t dot11mode)
return ret_val;
}
/**
* hdd_calculate_tx_bitrate_ie_size - calculate tx bitrate ie size
*
* Return: tx bitrate ie size
*/
static uint32_t hdd_calculate_tx_bitrate_ie_size(void)
{
uint32_t nl_buf_len = nla_total_size(0);
/* NL80211_RATE_INFO_BITRATE32 */
nl_buf_len += nla_total_size(sizeof(uint32_t)) +
/* NL80211_RATE_INFO_BITRATE */
nla_total_size(sizeof(uint16_t)) +
/* NL80211_RATE_INFO_VHT_NSS */
nla_total_size(sizeof(uint8_t));
return nl_buf_len;
}
/**
* hdd_add_tx_bitrate() - add tx bitrate attribute
* @skb: pointer to sk buff
@@ -451,6 +463,22 @@ fail:
return -EINVAL;
}
/**
* hdd_calculate_sta_info_ie_size - calculate sta info size
*
* Return: sta info ie size
*/
static uint32_t hdd_calculate_sta_info_ie_size(void)
{
uint32_t nl_buf_len = nla_total_size(0);
/* NL80211_STA_INFO_SIGNAL */
nl_buf_len += nla_total_size(sizeof(int8_t)) +
hdd_calculate_tx_bitrate_ie_size();
return nl_buf_len;
}
/**
* hdd_add_sta_info() - add station info attribute
* @skb: pointer to sk buff
@@ -499,6 +527,23 @@ fail:
return -EINVAL;
}
/**
* hdd_calculate_survey_info_ie_size - calculate survey info size
*
* Return: survey info ie size
*/
static uint32_t hdd_calculate_survey_info_ie_size(void)
{
uint32_t nl_buf_len = nla_total_size(0);
/* NL80211_SURVEY_INFO_FREQUENCY */
nl_buf_len += nla_total_size(sizeof(uint32_t)) +
/* NL80211_SURVEY_INFO_NOISE */
nla_total_size(sizeof(int8_t));
return nl_buf_len;
}
/**
* hdd_add_survey_info() - add survey info attribute
* @skb: pointer to sk buff
@@ -529,6 +574,25 @@ fail:
return -EINVAL;
}
/**
* hdd_calculate_link_standard_info_ie_size - calculate link standard info size
*
* Return: link standard info ie size
*/
static uint32_t hdd_calculate_link_standard_info_ie_size(void)
{
uint32_t nl_buf_len = nla_total_size(0);
/* NL80211_ATTR_SSID */
nl_buf_len += nla_total_size(WLAN_SSID_MAX_LEN + 1) +
/* NL80211_ATTR_MAC */
nla_total_size(QDF_MAC_ADDR_SIZE) +
hdd_calculate_survey_info_ie_size() +
hdd_calculate_sta_info_ie_size();
return nl_buf_len;
}
/**
* hdd_add_link_standard_info() - add link info attribute
* @skb: pointer to sk buff
@@ -585,6 +649,29 @@ fail:
return -EINVAL;
}
/**
* hdd_calculate_ap_standard_info_ie_size - calculate ap standard info size
* @hdd_sta_ctx: pointer to hdd station context
*
* Return: ap standard info size
*/
static uint32_t hdd_calculate_ap_standard_info_ie_size(
struct hdd_station_ctx *hdd_sta_ctx)
{
uint32_t nl_buf_len = nla_total_size(0);
/* NL80211_ATTR_VHT_CAPABILITY */
if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present)
nl_buf_len += nla_total_size(sizeof(
hdd_sta_ctx->cache_conn_info.vht_caps));
/* NL80211_ATTR_HT_CAPABILITY */
if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present)
nl_buf_len += nla_total_size(sizeof(
hdd_sta_ctx->cache_conn_info.ht_caps));
return nl_buf_len;
}
/**
* hdd_add_ap_standard_info() - add ap info attribute
* @skb: pointer to sk buff
@@ -661,6 +748,12 @@ static int32_t hdd_add_he_oper_info(struct sk_buff *skb,
hdd_sta_ctx->cache_conn_info.he_oper_len = 0;
return ret;
}
static int32_t hdd_get_he_op_len(struct hdd_station_ctx *hdd_sta_ctx)
{
return hdd_sta_ctx->cache_conn_info.he_oper_len;
}
#else
static inline uint32_t hdd_add_he_oper_info(
struct sk_buff *skb,
@@ -668,8 +761,19 @@ static inline uint32_t hdd_add_he_oper_info(
{
return 0;
}
static uint32_t hdd_get_he_op_len(struct hdd_station_ctx *hdd_sta_ctx)
{
return 0;
}
#endif
static uint32_t hdd_get_prev_connected_bss_ies_len(
struct hdd_station_ctx *hdd_sta_ctx)
{
return hdd_sta_ctx->conn_info.prev_ap_bcn_ie.len;
}
static uint32_t hdd_add_prev_connected_bss_ies(
struct sk_buff *skb,
struct hdd_station_ctx *hdd_sta_ctx)
@@ -694,43 +798,84 @@ static uint32_t hdd_add_prev_connected_bss_ies(
}
/**
* hdd_get_station_info() - send BSS information to supplicant
* @hdd_ctx: pointer to hdd context
* @adapter: pointer to adapter
* hdd_calculate_station_info_ie_size - calculate bss ie size
* @hdd_sta_ctx: pointer to hdd station context
*
* Return: 0 if success else error status
* Return: bss ie size
*/
static int hdd_get_station_info(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter)
static uint32_t hdd_calculate_station_info_ie_size(
struct hdd_station_ctx *hdd_sta_ctx)
{
/* NLA_HDRLEN */
uint32_t nl_buf_len = NLA_HDRLEN;
nl_buf_len += hdd_calculate_link_standard_info_ie_size() +
hdd_calculate_ap_standard_info_ie_size(hdd_sta_ctx);
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT */
nl_buf_len += nla_total_size(sizeof(uint32_t)) +
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM */
nla_total_size(sizeof(uint32_t)) +
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE */
nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION */
if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present)
nl_buf_len += nla_total_size(sizeof(
hdd_sta_ctx->cache_conn_info.ht_operation));
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION */
if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present)
nl_buf_len += nla_total_size(sizeof(
hdd_sta_ctx->cache_conn_info.vht_operation));
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HE_OPERATION */
nl_buf_len += nla_total_size(hdd_get_he_op_len(hdd_sta_ctx));
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION */
if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present)
nl_buf_len += nla_total_size(sizeof(
hdd_sta_ctx->cache_conn_info.hs20vendor_ie) - 1);
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_DRIVER_DISCONNECT_REASON */
nl_buf_len += nla_total_size(sizeof(uint32_t));
/* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_BEACON_IES */
if (hdd_sta_ctx->conn_info.prev_ap_bcn_ie.len)
nl_buf_len += nla_total_size(
hdd_get_prev_connected_bss_ies_len(hdd_sta_ctx));
return nl_buf_len;
}
/**
* hdd_populate_station_info_skb - populate station info in skb
* @hdd_ctx: pointer to hdd context
* @skb: pointer to socket buffer
* @adapter: pointer to adapter
* @hdd_sta_ctx: pointer to hdd station ctx
*
* Return: QDF_STATUS_SUCCESS in case of success else failure
*/
static QDF_STATUS hdd_populate_station_info_skb(struct hdd_context *hdd_ctx,
struct sk_buff *skb,
struct hdd_adapter *adapter,
struct hdd_station_ctx *hdd_sta_ctx)
{
struct sk_buff *skb = NULL;
uint8_t *tmp_hs20 = NULL;
struct hdd_station_ctx *hdd_sta_ctx;
hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
if (hdd_cm_is_vdev_connected(adapter)) {
hdd_err("Station is connected, command is not supported");
return -EINVAL;
}
skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
WLAN_STATS_INFO_LEN);
if (!skb) {
hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
return -ENOMEM;
}
if (hdd_add_link_standard_info(skb, hdd_ctx, adapter,
LINK_INFO_STANDARD_NL80211_ATTR)) {
hdd_err("put fail");
goto fail;
hdd_err("link_standard_info put fail");
return QDF_STATUS_E_FAILURE;
}
if (hdd_add_ap_standard_info(skb, hdd_sta_ctx,
AP_INFO_STANDARD_NL80211_ATTR)) {
hdd_err("put fail");
goto fail;
hdd_err("ap standard info fail");
return QDF_STATUS_E_FAILURE;
}
if (nla_put_u32(skb, INFO_ROAM_COUNT,
hdd_sta_ctx->cache_conn_info.roam_count) ||
nla_put_u32(skb, INFO_AKM,
@@ -739,15 +884,16 @@ static int hdd_get_station_info(struct hdd_context *hdd_ctx,
nla_put_u32(skb, WLAN802_11_MODE,
hdd_convert_dot11mode(
hdd_sta_ctx->cache_conn_info.dot11mode))) {
hdd_err("put fail");
goto fail;
hdd_err("Roam, AKM, dot11mode put fail");
return QDF_STATUS_E_FAILURE;
}
if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) {
if (nla_put(skb, HT_OPERATION,
(sizeof(hdd_sta_ctx->cache_conn_info.ht_operation)),
&hdd_sta_ctx->cache_conn_info.ht_operation)) {
hdd_err("put fail");
goto fail;
hdd_err("ht operation put fail");
return QDF_STATUS_E_FAILURE;
}
hdd_nofl_debug("STA HT operation:");
qdf_trace_hex_dump(
@@ -755,13 +901,14 @@ static int hdd_get_station_info(struct hdd_context *hdd_ctx,
(uint8_t *)&hdd_sta_ctx->cache_conn_info.ht_operation,
sizeof(hdd_sta_ctx->cache_conn_info.ht_operation));
}
if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) {
if (nla_put(skb, VHT_OPERATION,
(sizeof(hdd_sta_ctx->
cache_conn_info.vht_operation)),
&hdd_sta_ctx->cache_conn_info.vht_operation)) {
hdd_err("put fail");
goto fail;
hdd_err("vht operation put fail");
return QDF_STATUS_E_FAILURE;
}
hdd_nofl_debug("STA VHT operation:");
qdf_trace_hex_dump(
@@ -769,10 +916,12 @@ static int hdd_get_station_info(struct hdd_context *hdd_ctx,
(uint8_t *)&hdd_sta_ctx->cache_conn_info.vht_operation,
sizeof(hdd_sta_ctx->cache_conn_info.vht_operation));
}
if (hdd_add_he_oper_info(skb, hdd_sta_ctx)) {
hdd_err("put fail");
goto fail;
hdd_err("he operation info put fail");
return QDF_STATUS_E_FAILURE;
}
if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) {
tmp_hs20 =
(uint8_t *)&hdd_sta_ctx->cache_conn_info.hs20vendor_ie;
@@ -780,8 +929,8 @@ static int hdd_get_station_info(struct hdd_context *hdd_ctx,
(sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie)
- 1),
tmp_hs20 + 1)) {
hdd_err("put fail");
goto fail;
hdd_err("hs20 put fail");
return QDF_STATUS_E_FAILURE;
}
hdd_nofl_debug("STA hs20 vendor IE:");
qdf_trace_hex_dump(
@@ -793,13 +942,53 @@ static int hdd_get_station_info(struct hdd_context *hdd_ctx,
if (nla_put_u32(skb, DISCONNECT_REASON,
adapter->last_disconnect_reason)) {
hdd_err("Failed to put disconnect reason");
goto fail;
return QDF_STATUS_E_FAILURE;
}
if (hdd_add_prev_connected_bss_ies(skb, hdd_sta_ctx)) {
hdd_err("put fail");
goto fail;
hdd_err("disconnect_reason put fail");
return QDF_STATUS_E_FAILURE;
}
return QDF_STATUS_SUCCESS;
}
/**
* hdd_get_station_info() - send BSS information to supplicant
* @hdd_ctx: pointer to hdd context
* @adapter: pointer to adapter
*
* Return: 0 if success else error status
*/
static int hdd_get_station_info(struct hdd_context *hdd_ctx,
struct hdd_adapter *adapter)
{
struct sk_buff *skb = NULL;
uint32_t nl_buf_len;
struct hdd_station_ctx *hdd_sta_ctx;
hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter);
if (hdd_cm_is_vdev_connected(adapter)) {
hdd_err("Station is connected, command is not supported");
return -EINVAL;
}
nl_buf_len = hdd_calculate_station_info_ie_size(hdd_sta_ctx);
if (!nl_buf_len) {
hdd_err("BSS ie size calculation failed");
return -EINVAL;
}
skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
nl_buf_len);
if (!skb) {
hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
return -ENOMEM;
}
if (hdd_populate_station_info_skb(hdd_ctx, skb, adapter, hdd_sta_ctx)
!= QDF_STATUS_SUCCESS)
goto fail;
hdd_nofl_debug(
"STA Info:: SSID:" QDF_SSID_FMT ", BSSID:" QDF_MAC_ADDR_FMT ", freq:%d, "