Write the op_class in hostapd.conf file

With the addition of 6GHz band, channel number is no longer
sufficient to identify a channel since 6GHz band channels use
same numbers as 2.4/5GHz bands. Hence, for SoftAp with no ACS,
the channel number in hostapd.conf needs to be coupled with an
op_class attribute.

This commit calculates the op_class for the channel number, and
pass it in the hostapd.conf.

Bug: 146186687
Test: Manual
Change-Id: I69ee3cc89c19d825eb5076b0a14f770a1385a859
diff --git a/hostapd/hidl/1.2/hostapd.cpp b/hostapd/hidl/1.2/hostapd.cpp
index b05e2f5..b40087a 100644
--- a/hostapd/hidl/1.2/hostapd.cpp
+++ b/hostapd/hidl/1.2/hostapd.cpp
@@ -65,6 +65,144 @@
 	return "";
 }
 
+/*
+ * Get the op_class for a channel/band
+ * The logic here is based on Table E-4 in the 802.11 Specification
+ */
+int getOpClassForChannel(int channel, int band, bool support11n, bool support11ac) {
+	// 2GHz Band
+	if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
+		if (channel == 14) {
+			return 82;
+		}
+		if (channel >= 1 && channel <= 13) {
+			if (!support11n) {
+				//20MHz channel
+				return 81;
+			}
+			if (channel <= 9) {
+				// HT40 with secondary channel above primary
+				return 83;
+			}
+			// HT40 with secondary channel below primary
+			return 84;
+		}
+		// Error
+		return 0;
+	}
+
+	// 5GHz Band
+	if ((band & IHostapd::BandMask::BAND_5_GHZ) != 0) {
+		if (support11ac) {
+			switch (channel) {
+				case 42:
+				case 58:
+				case 106:
+				case 122:
+				case 138:
+				case 155:
+					// 80MHz channel
+					return 128;
+				case 50:
+				case 114:
+					// 160MHz channel
+					return 129;
+			}
+		}
+
+		if (!support11n) {
+			if (channel >= 36 && channel <= 48) {
+				return 115;
+			}
+			if (channel >= 52 && channel <= 64) {
+				return 118;
+			}
+			if (channel >= 100 && channel <= 144) {
+				return 121;
+			}
+			if (channel >= 149 && channel <= 161) {
+				return 124;
+			}
+			if (channel >= 165 && channel <= 169) {
+				return 125;
+			}
+		} else {
+			switch (channel) {
+				case 36:
+				case 44:
+					// HT40 with secondary channel above primary
+					return 116;
+				case 40:
+				case 48:
+					// HT40 with secondary channel below primary
+					return 117;
+				case 52:
+				case 60:
+					// HT40 with secondary channel above primary
+					return  119;
+				case 56:
+				case 64:
+					// HT40 with secondary channel below primary
+					return 120;
+				case 100:
+				case 108:
+				case 116:
+				case 124:
+				case 132:
+				case 140:
+					// HT40 with secondary channel above primary
+					return 122;
+				case 104:
+				case 112:
+				case 120:
+				case 128:
+				case 136:
+				case 144:
+					// HT40 with secondary channel below primary
+					return 123;
+				case 149:
+				case 157:
+					// HT40 with secondary channel above primary
+					return 126;
+				case 153:
+				case 161:
+					// HT40 with secondary channel below primary
+					return 127;
+			}
+		}
+		// Error
+		return 0;
+	}
+
+	// 6GHz Band
+	if ((band & IHostapd::BandMask::BAND_6_GHZ) != 0) {
+		// Channels 1, 5. 9, 13, ...
+		if ((channel & 0x03) == 0x01) {
+			// 20MHz channel
+			return 131;
+		}
+		// Channels 3, 11, 19, 27, ...
+		if ((channel & 0x07) == 0x03) {
+			// 40MHz channel
+			return 132;
+		}
+		// Channels 7, 23, 39, 55, ...
+		if ((channel & 0x0F) == 0x07) {
+			// 80MHz channel
+			return 133;
+		}
+		// Channels 15, 47, 69, ...
+		if ((channel & 0x1F) == 0x0F) {
+			// 160MHz channel
+			return 134;
+		}
+		// Error
+		return 0;
+	}
+
+	return 0;
+}
+
 std::string CreateHostapdConfig(
     const IHostapd::IfaceParams& iface_params,
     const IHostapd::NetworkParams& nw_params)
@@ -125,6 +263,9 @@
 		return "";
 	}
 
+	unsigned int band = 0;
+	band |= iface_params.channelParams.bandMask;
+
 	std::string channel_config_as_string;
 	bool isFirst = true;
 	if (iface_params.V1_1.V1_0.channelParams.enableAcs) {
@@ -150,14 +291,19 @@
 		    iface_params.V1_1.V1_0.channelParams.acsShouldExcludeDfs,
 		    freqList_as_string.c_str());
 	} else {
+		int op_class = getOpClassForChannel(
+		    iface_params.V1_1.V1_0.channelParams.channel,
+		    band,
+		    iface_params.V1_1.V1_0.hwModeParams.enable80211N,
+		    iface_params.V1_1.V1_0.hwModeParams.enable80211AC);
 		channel_config_as_string = StringPrintf(
-		    "channel=%d", iface_params.V1_1.V1_0.channelParams.channel);
+		    "channel=%d\n"
+		    "op_class=%d",
+		    iface_params.V1_1.V1_0.channelParams.channel, op_class);
 	}
 
 	std::string hw_mode_as_string;
 	std::string ht_cap_vht_oper_chwidth_as_string;
-	unsigned int band = 0;
-	band |= iface_params.channelParams.bandMask;
 
 	if ((band & IHostapd::BandMask::BAND_2_GHZ) != 0) {
 		if (((band & IHostapd::BandMask::BAND_5_GHZ) != 0)