Browse Source

nl80211: Do not return incomplete hw capability info

If a memory allocation fails while parsing driver capabilities, drop all
mode/channel/rate information instead of returning possibly partial
information.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 9 years ago
parent
commit
747ba1067d
1 changed files with 23 additions and 8 deletions
  1. 23 8
      src/drivers/driver_nl80211_capa.c

+ 23 - 8
src/drivers/driver_nl80211_capa.c

@@ -966,6 +966,7 @@ struct phy_info_arg {
 	u16 *num_modes;
 	struct hostapd_hw_modes *modes;
 	int last_mode, last_chan_idx;
+	int failed;
 };
 
 static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
@@ -1083,7 +1084,7 @@ static int phy_info_freqs(struct phy_info_arg *phy_info,
 				   mode->num_channels + new_channels,
 				   sizeof(struct hostapd_channel_data));
 	if (!channel)
-		return NL_SKIP;
+		return NL_STOP;
 
 	mode->channels = channel;
 	mode->num_channels += new_channels;
@@ -1129,7 +1130,7 @@ static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
 
 	mode->rates = os_calloc(mode->num_rates, sizeof(int));
 	if (!mode->rates)
-		return NL_SKIP;
+		return NL_STOP;
 
 	idx = 0;
 
@@ -1158,8 +1159,10 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
 		mode = os_realloc_array(phy_info->modes,
 					*phy_info->num_modes + 1,
 					sizeof(*mode));
-		if (!mode)
-			return NL_SKIP;
+		if (!mode) {
+			phy_info->failed = 1;
+			return NL_STOP;
+		}
 		phy_info->modes = mode;
 
 		mode = &phy_info->modes[*(phy_info->num_modes)];
@@ -1195,11 +1198,12 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
 	phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
 			  tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
 	ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
-	if (ret != NL_OK)
-		return ret;
-	ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
-	if (ret != NL_OK)
+	if (ret == NL_OK)
+		ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+	if (ret != NL_OK) {
+		phy_info->failed = 1;
 		return ret;
+	}
 
 	return NL_OK;
 }
@@ -1599,6 +1603,7 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 		.num_modes = num_modes,
 		.modes = NULL,
 		.last_mode = -1,
+		.failed = 0,
 	};
 
 	*num_modes = 0;
@@ -1615,6 +1620,16 @@ nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
 
 	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
 		nl80211_set_regulatory_flags(drv, &result);
+		if (result.failed) {
+			int i;
+
+			for (i = 0; result.modes && i < *num_modes; i++) {
+				os_free(result.modes[i].channels);
+				os_free(result.modes[i].rates);
+			}
+			os_free(result.modes);
+			return NULL;
+		}
 		return wpa_driver_nl80211_postprocess_modes(result.modes,
 							    num_modes);
 	}