Browse Source

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
Asutosh Mohapatra 2 years ago
parent
commit
7b08e108e0
1 changed files with 233 additions and 44 deletions
  1. 233 44
      core/hdd/src/wlan_hdd_station_info.c

+ 233 - 44
core/hdd/src/wlan_hdd_station_info.c

@@ -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_calculate_station_info_ie_size - calculate bss ie size
+ * @hdd_sta_ctx: pointer to hdd station context
+ *
+ * Return: bss ie size
+ */
+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: 0 if success else error status
+ * Return: QDF_STATUS_SUCCESS in case of success else failure
  */
-static int hdd_get_station_info(struct hdd_context *hdd_ctx,
-				struct hdd_adapter *adapter)
+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,14 +942,54 @@ 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, "
 		"Noise:%d, signal:%d, roam_count:%d, last_auth_type:%d, "