Revert "Revert "[wpa_supplicant] cumilative patch from commit 3a..."

Revert submission 28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR

Reason for revert: Fixed the regression issue (ag/28389573)

Reverted changes: /q/submissionid:28102966-revert-26533062-Supplicant_merge_June24-CUATTSRBBR

Bug: 329004037
Test: Turn ON/OFF SoftAp multiple times

Change-Id: Ibfff2a847be5678f1a6d77e28506a05936812a91
diff --git a/src/ap/acs.c b/src/ap/acs.c
index e3cfe1d..28b0ba7 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -245,6 +245,8 @@
 	ACS_BW40,
 	ACS_BW80,
 	ACS_BW160,
+	ACS_BW320_1,
+	ACS_BW320_2,
 };
 
 struct bw_item {
@@ -286,10 +288,20 @@
 	{ 6435, 6575, 111 }, { 6595, 6735, 143 },
 	{ 6755, 6895, 175 }, { 6915, 7055, 207 }, { -1, -1, -1 }
 };
+static const struct bw_item bw_320_1[] = {
+	{ 5955, 6255, 31 }, { 6275, 6575, 95 }, { 6595, 6895, 159 },
+	{ -1, -1, -1 }
+};
+static const struct bw_item bw_320_2[] = {
+	{ 6115, 6415, 63 }, { 6435, 6735, 127 }, { 6755, 7055, 191 },
+	{ -1, -1, -1 }
+};
 static const struct bw_item *bw_desc[] = {
 	[ACS_BW40] = bw_40,
 	[ACS_BW80] = bw_80,
 	[ACS_BW160] = bw_160,
+	[ACS_BW320_1] = bw_320_1,
+	[ACS_BW320_2] = bw_320_2,
 };
 
 
@@ -768,6 +780,42 @@
 #endif /* CONFIG_IEEE80211BE */
 
 
+static bool
+acs_usable_bw320_chan(struct hostapd_iface *iface,
+		      struct hostapd_channel_data *chan, int *bw320_offset)
+{
+	const char *bw320_str[] = { "320 MHz", "320 MHz-1", "320 MHz-2" };
+	int conf_bw320_offset = hostapd_get_bw320_offset(iface->conf);
+
+	*bw320_offset = 0;
+	switch (conf_bw320_offset) {
+	case 1:
+		if (acs_usable_bw_chan(chan, ACS_BW320_1))
+			*bw320_offset = 1;
+		break;
+	case 2:
+		if (acs_usable_bw_chan(chan, ACS_BW320_2))
+			*bw320_offset = 2;
+		break;
+	case 0:
+	default:
+		conf_bw320_offset = 0;
+		if (acs_usable_bw_chan(chan, ACS_BW320_1))
+			*bw320_offset = 1;
+		else if (acs_usable_bw_chan(chan, ACS_BW320_2))
+			*bw320_offset = 2;
+		break;
+	}
+
+	if (!*bw320_offset)
+		wpa_printf(MSG_DEBUG,
+			   "ACS: Channel %d: not allowed as primary channel for %s bandwidth",
+			   chan->chan, bw320_str[conf_bw320_offset]);
+
+	return *bw320_offset != 0;
+}
+
+
 static void
 acs_find_ideal_chan_mode(struct hostapd_iface *iface,
 			 struct hostapd_hw_modes *mode,
@@ -779,14 +827,18 @@
 	struct hostapd_channel_data *chan, *adj_chan = NULL, *best;
 	long double factor;
 	int i, j;
+	int bw320_offset = 0, ideal_bw320_offset = 0;
 	unsigned int k;
+	int secondary_channel = 1, freq_offset;
+
+	if (is_24ghz_mode(mode->mode))
+		secondary_channel = iface->conf->secondary_channel;
 
 	for (i = 0; i < mode->num_channels; i++) {
-		double total_weight;
+		double total_weight = 0;
 		struct acs_bias *bias, tmp_bias;
-		bool update_best = true;
 
-		best = chan = &mode->channels[i];
+		chan = &mode->channels[i];
 
 		/* Since in the current ACS implementation the first channel is
 		 * always a primary channel, skip channels not available as
@@ -818,7 +870,7 @@
 		    iface->conf->country[2] == 0x4f)
 			continue;
 
-		if (!chan_bw_allowed(chan, bw, 1, 1)) {
+		if (!chan_bw_allowed(chan, bw, secondary_channel != -1, 1)) {
 			wpa_printf(MSG_DEBUG,
 				   "ACS: Channel %d: BW %u is not supported",
 				   chan->chan, bw);
@@ -839,7 +891,8 @@
 		}
 
 		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
-		    (iface->conf->ieee80211ac || iface->conf->ieee80211ax)) {
+		    (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
+		     iface->conf->ieee80211be)) {
 			if (hostapd_get_oper_chwidth(iface->conf) ==
 			    CONF_OPER_CHWIDTH_80MHZ &&
 			    !acs_usable_bw_chan(chan, ACS_BW80)) {
@@ -859,13 +912,25 @@
 			}
 		}
 
+		if (mode->mode == HOSTAPD_MODE_IEEE80211A &&
+		    iface->conf->ieee80211be) {
+			if (hostapd_get_oper_chwidth(iface->conf) ==
+			    CONF_OPER_CHWIDTH_320MHZ &&
+			    !acs_usable_bw320_chan(iface, chan, &bw320_offset))
+				continue;
+		}
+
 		factor = 0;
-		if (acs_usable_chan(chan))
+		best = NULL;
+		if (acs_usable_chan(chan)) {
 			factor = chan->interference_factor;
-		total_weight = 1;
+			total_weight = 1;
+			best = chan;
+		}
 
 		for (j = 1; j < n_chans; j++) {
-			adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
+			adj_chan = acs_find_chan(iface, chan->freq +
+						 j * secondary_channel * 20);
 			if (!adj_chan)
 				break;
 
@@ -876,16 +941,14 @@
 				break;
 			}
 
-			if (acs_usable_chan(adj_chan)) {
-				factor += adj_chan->interference_factor;
-				total_weight += 1;
-			} else {
-				update_best = false;
-			}
+			if (!acs_usable_chan(adj_chan))
+				continue;
+
+			factor += adj_chan->interference_factor;
+			total_weight += 1;
 
 			/* find the best channel in this segment */
-			if (update_best &&
-			    adj_chan->interference_factor <
+			if (!best || adj_chan->interference_factor <
 			    best->interference_factor)
 				best = adj_chan;
 		}
@@ -898,8 +961,9 @@
 
 		/* If the AP is in the 5 GHz or 6 GHz band, lets prefer a less
 		 * crowded primary channel if one was found in the segment */
-		if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
-		    chan != best) {
+		if (iface->current_mode &&
+		    iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
+		    best && chan != best) {
 			wpa_printf(MSG_DEBUG,
 				   "ACS: promoting channel %d over %d (less interference %Lg/%Lg)",
 				   best->chan, chan->chan,
@@ -912,8 +976,9 @@
 		 * channel interference factor. */
 		if (is_24ghz_mode(mode->mode)) {
 			for (j = 0; j < n_chans; j++) {
+				freq_offset = j * 20 * secondary_channel;
 				adj_chan = acs_find_chan(iface, chan->freq +
-							 (j * 20) - 5);
+							 freq_offset - 5);
 				if (adj_chan && acs_usable_chan(adj_chan)) {
 					factor += ACS_ADJ_WEIGHT *
 						adj_chan->interference_factor;
@@ -921,7 +986,7 @@
 				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
-							 (j * 20) - 10);
+							 freq_offset - 10);
 				if (adj_chan && acs_usable_chan(adj_chan)) {
 					factor += ACS_NEXT_ADJ_WEIGHT *
 						adj_chan->interference_factor;
@@ -929,7 +994,7 @@
 				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
-							 (j * 20) + 5);
+							 freq_offset + 5);
 				if (adj_chan && acs_usable_chan(adj_chan)) {
 					factor += ACS_ADJ_WEIGHT *
 						adj_chan->interference_factor;
@@ -937,7 +1002,7 @@
 				}
 
 				adj_chan = acs_find_chan(iface, chan->freq +
-							 (j * 20) + 10);
+							 freq_offset + 10);
 				if (adj_chan && acs_usable_chan(adj_chan)) {
 					factor += ACS_NEXT_ADJ_WEIGHT *
 						adj_chan->interference_factor;
@@ -946,6 +1011,9 @@
 			}
 		}
 
+		if (total_weight == 0)
+			continue;
+
 		factor /= total_weight;
 
 		bias = NULL;
@@ -983,6 +1051,7 @@
 
 			*ideal_factor = factor;
 			*ideal_chan = chan;
+			ideal_bw320_offset = bw320_offset;
 
 #ifdef CONFIG_IEEE80211BE
 			if (iface->conf->ieee80211be)
@@ -993,9 +1062,13 @@
 		}
 
 		/* This channel would at least be usable */
-		if (!(*rand_chan))
+		if (!(*rand_chan)) {
 			*rand_chan = chan;
+			ideal_bw320_offset = bw320_offset;
+		}
 	}
+
+	hostapd_set_and_check_bw320_offset(iface->conf, ideal_bw320_offset);
 }
 
 
@@ -1022,19 +1095,12 @@
 		goto bw_selected;
 	}
 
-	/* TODO: HT40- support */
-
-	if (iface->conf->ieee80211n &&
-	    iface->conf->secondary_channel == -1) {
-		wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+");
-		return NULL;
-	}
-
 	if (iface->conf->ieee80211n &&
 	    iface->conf->secondary_channel)
 		n_chans = 2;
 
-	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
+	    iface->conf->ieee80211be) {
 		switch (hostapd_get_oper_chwidth(iface->conf)) {
 		case CONF_OPER_CHWIDTH_80MHZ:
 			n_chans = 4;
@@ -1042,6 +1108,9 @@
 		case CONF_OPER_CHWIDTH_160MHZ:
 			n_chans = 8;
 			break;
+		case CONF_OPER_CHWIDTH_320MHZ:
+			n_chans = 16;
+			break;
 		default:
 			break;
 		}
@@ -1091,7 +1160,8 @@
 	    acs_find_mode(iface, iface->freq) != HOSTAPD_MODE_IEEE80211A)
 		return;
 
-	wpa_printf(MSG_DEBUG, "ACS: Adjusting HT/VHT/HE secondary frequency");
+	wpa_printf(MSG_DEBUG,
+		   "ACS: Adjusting HT/VHT/HE/EHT secondary frequency");
 
 	for (i = 0; bw_desc[ACS_BW40][i].first != -1; i++) {
 		if (iface->freq == bw_desc[ACS_BW40][i].first)
@@ -1106,7 +1176,7 @@
 {
 	int center;
 
-	wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency");
+	wpa_printf(MSG_DEBUG, "ACS: Adjusting center frequency");
 
 	switch (hostapd_get_oper_chwidth(iface->conf)) {
 	case CONF_OPER_CHWIDTH_USE_HT:
@@ -1125,11 +1195,28 @@
 	case CONF_OPER_CHWIDTH_160MHZ:
 		center = acs_get_bw_center_chan(iface->freq, ACS_BW160);
 		break;
+	case CONF_OPER_CHWIDTH_320MHZ:
+		switch (hostapd_get_bw320_offset(iface->conf)) {
+		case 1:
+			center = acs_get_bw_center_chan(iface->freq,
+							ACS_BW320_1);
+			break;
+		case 2:
+			center = acs_get_bw_center_chan(iface->freq,
+							ACS_BW320_2);
+			break;
+		default:
+			wpa_printf(MSG_INFO,
+				   "ACS: BW320 offset is not selected");
+			return;
+		}
+
+		break;
 	default:
 		/* TODO: How can this be calculated? Adjust
 		 * acs_find_ideal_chan() */
 		wpa_printf(MSG_INFO,
-			   "ACS: Only VHT20/40/80/160 is supported now");
+			   "ACS: Only VHT20/40/80/160/320 is supported now");
 		return;
 	}
 
@@ -1192,7 +1279,8 @@
 	iface->conf->punct_bitmap = ideal_chan->punct_bitmap;
 #endif /* CONFIG_IEEE80211BE */
 
-	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax) {
+	if (iface->conf->ieee80211ac || iface->conf->ieee80211ax ||
+	    iface->conf->ieee80211be) {
 		acs_adjust_secondary(iface);
 		acs_adjust_center_freq(iface);
 	}