diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index c4106c1283..21671721c0 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3154,6 +3154,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
 		else if (os_strcmp(pos, "ad") == 0)
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+		else if (os_strcmp(pos, "ax") == 0)
+			conf->hw_mode = HOSTAPD_MODE_IEEE80211AX;
 		else if (os_strcmp(pos, "any") == 0)
 			conf->hw_mode = HOSTAPD_MODE_IEEE80211ANY;
 		else {
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 71e577a89c..a25d3f0092 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -147,7 +147,8 @@ ssid=test
 # Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
 # g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
 # with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6-7 GHz this needs
+# to be set to hw_mode=ax. When using ACS (see channel parameter), a
 # special value "any" can be used to indicate that any support band can be used.
 # This special case is currently supported only with drivers with which
 # offloaded ACS is used.
@@ -800,6 +801,10 @@ wmm_ac_vo_acm=0
 #he_rts_threshold=0
 
 # HE operating channel information; see matching vht_* parameters for details.
+# On 6GHz band (hw_mode=ax) the center freq calculation starts from 5.940 offset.
+# For example idx=3 would result in 5955MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured center frequencies (See IEEE802.11ax/D4.1 Annex E)
 #he_oper_chwidth
 #he_oper_centr_freq_seg0_idx
 #he_oper_centr_freq_seg1_idx
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index c1f19e26b5..4ba4cc7437 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -158,6 +158,7 @@ int hostapd_prepare_rates(struct hostapd_iface *iface,
 		basic_rates = iface->conf->basic_rates;
 	else switch (mode->mode) {
 	case HOSTAPD_MODE_IEEE80211A:
+	case HOSTAPD_MODE_IEEE80211AX: /* same as 5GHz */
 		basic_rates = basic_rates_a;
 		break;
 	case HOSTAPD_MODE_IEEE80211B:
@@ -934,6 +935,8 @@ const char * hostapd_hw_mode_txt(int mode)
 		return "IEEE 802.11g";
 	case HOSTAPD_MODE_IEEE80211AD:
 		return "IEEE 802.11ad";
+	case HOSTAPD_MODE_IEEE80211AX:
+		return "IEEE 802.11ax";
 	default:
 		return "UNKNOWN";
 	}
diff --git a/src/common/defs.h b/src/common/defs.h
index 4faf1c8601..c6bb7c0286 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -348,6 +348,7 @@ enum hostapd_hw_mode {
 	HOSTAPD_MODE_IEEE80211G,
 	HOSTAPD_MODE_IEEE80211A,
 	HOSTAPD_MODE_IEEE80211AD,
+	HOSTAPD_MODE_IEEE80211AX,
 	HOSTAPD_MODE_IEEE80211ANY,
 	NUM_HOSTAPD_MODES
 };
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 3fdbf893d2..9996ef2bf7 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -358,6 +358,25 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
 }
 
 
+int center_idx_to_width_6ghz(u8 idx)
+{
+	/* channels: 1, 5, 9, 13... */
+	if ((idx & 0x3) == 0x1)
+		return 0; /* 20mhz */
+	/* channels 3, 11, 19... */
+	if ((idx & 0x7) == 0x3)
+		return 1; /* 40mhz */
+	/* channels 7, 23, 39.. */
+	if ((idx & 0xf) == 0x7)
+		return 2; /* 80mhz */
+	/* channels 15, 47, 79...*/
+	if ((idx & 0x1f) == 0xf)
+		return 3; /* 160mhz */
+
+	return -1;
+}
+
+
 int hostapd_set_freq_params(struct hostapd_freq_params *data,
 			    enum hostapd_hw_mode mode,
 			    int freq, int channel, int ht_enabled,
@@ -381,6 +400,71 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
 	data->center_freq2 = 0;
 	data->bandwidth = sec_channel_offset ? 40 : 20;
 
+	if (mode == HOSTAPD_MODE_IEEE80211AX) {
+		if (!data->he_enabled) {
+			wpa_printf(MSG_ERROR,
+				   "Can't set 6GHz mode - HE isn't enabled");
+			return -1;
+		}
+
+		if (center_idx_to_width_6ghz(channel) != 0) {
+			wpa_printf(MSG_ERROR,
+				   "Invalid control channel for 6Ghz band");
+			return -1;
+		}
+
+		if (!center_segment0) {
+			if (center_segment1) {
+				wpa_printf(MSG_ERROR,
+					   "Center0 freq isn't set");
+				return -1;
+			}
+
+			data->center_freq1 = data->freq;
+			data->bandwidth = 20;
+		} else {
+			int freq1, freq2 = 0;
+			int bw = center_idx_to_width_6ghz(center_segment0);
+
+			if (bw < 0 ) {
+				wpa_printf(MSG_ERROR,
+					   "Invalid center channel idx for 6GHz");
+				return -1;
+			}
+
+			freq1 = ieee80211_chan_to_freq(NULL, 131,
+						       center_segment0);
+			if (freq1 < 0) {
+				wpa_printf(MSG_ERROR,
+					   "Invalid center0 freq. for 6GHz");
+				return -1;
+			}
+
+			if (center_segment1) {
+				if (center_idx_to_width_6ghz(center_segment1) != 2 ||
+				    bw != 2) {
+					wpa_printf(MSG_ERROR,
+						   "6GHz 80+80 configuration doesn't use valid 80MHz channels");
+					return -1;
+				}
+
+				freq2 = ieee80211_chan_to_freq(NULL, 131,
+							       center_segment1);
+				if (freq2 < 0) {
+					wpa_printf(MSG_ERROR,
+						   "Invalid center1 freq. for UHB");
+					return -1;
+				}
+			}
+
+			data->bandwidth = (1 << (u8)bw) * 20;
+			data->center_freq1 = freq1;
+			data->center_freq2 = freq2;
+		}
+
+		return 0;
+	}
+
 	if (data->vht_enabled) switch (oper_chwidth) {
 	case CHANWIDTH_USE_HT:
 		if (center_segment1 ||
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 2d2a539943..c75a79746a 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -45,5 +45,6 @@ u32 num_chan_to_bw(int num_chans);
 int chan_bw_allowed(const struct hostapd_channel_data *chan, u32 bw,
 		    int ht40_plus, int pri);
 int chan_pri_allowed(const struct hostapd_channel_data *chan);
+int center_idx_to_width_6ghz(u8 idx);
 
 #endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index a081f87cc2..8096e17409 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -15,6 +15,7 @@
 #include "qca-vendor.h"
 #include "ieee802_11_defs.h"
 #include "ieee802_11_common.h"
+#include "hw_features_common.h"
 
 
 static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
@@ -882,6 +883,19 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
 		return HOSTAPD_MODE_IEEE80211AD;
 	}
 
+	if (freq > 5940 && freq <= 7105) {
+		int bw;
+		u8 idx = (freq - 5940) / 5;
+
+		bw = center_idx_to_width_6ghz(idx);
+		if (bw < 0)
+			return NUM_HOSTAPD_MODES;
+
+		*channel = idx;
+		*op_class = 131 + bw;
+		return HOSTAPD_MODE_IEEE80211AX;
+	}
+
 	return NUM_HOSTAPD_MODES;
 }
 
@@ -1161,6 +1175,14 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
 		if (chan < 36 || chan > 128)
 			return -1;
 		return 5000 + 5 * chan;
+	case 131: /* UHB channels, 20 mhz: 1, 5, 9.. */
+	case 132: /* UHB channels, 40 mhz: 3, 11, 19.. */
+	case 133: /* UHB channels, 80 mhz: 7, 23, 39.. */
+	case 134: /* UHB channels, 160 mhz: 15, 47, 79.. */
+	case 135: /* UHB channels, 80+80 mhz: 7, 23, 39.. */
+		if (chan < 1 || chan > 233)
+			return -1;
+		return 5940 + chan * 5;
 	case 180: /* 60 GHz band, channels 1..4 */
 		if (chan < 1 || chan > 4)
 			return -1;
@@ -1590,6 +1612,7 @@ const struct oper_class_map global_op_class[] = {
 	{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+	{ HOSTAPD_MODE_IEEE80211AX, 131, 1, 233, 4, BW20, NO_P2P_SUPP },
 	{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
 	{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
 };
diff --git a/wlantest/Makefile b/wlantest/Makefile
index 4195a24dd1..8d5e69dd66 100644
--- a/wlantest/Makefile
+++ b/wlantest/Makefile
@@ -54,6 +54,7 @@ CFLAGS += -DCONFIG_FILS
 
 OBJS += ../src/common/ieee802_11_common.o
 OBJS += ../src/common/wpa_common.o
+OBJS += ../src/common/hw_features_common.o
 OBJS += ../src/radius/radius.o
 OBJS += ../src/rsn_supp/wpa_ie.o
 
