[][MAC80211][MT76/Hostapd/MAC80211 internal patches refactor]

[Description]
Refactor MT76/Hostapd/MAC80211 patches for common use

[Release-log]
N/A

Change-Id: I971fa053b9a523a3e871ab2d2c3b89a3c96c04df
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5799282
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/900-master-sync-include-uapi-linux-nl80211.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/900-master-sync-include-uapi-linux-nl80211.patch
new file mode 100644
index 0000000..fe47b57
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/900-master-sync-include-uapi-linux-nl80211.patch
@@ -0,0 +1,57 @@
+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
+index f962c06..f7be755 100644
+--- a/src/drivers/nl80211_copy.h
++++ b/src/drivers/nl80211_copy.h
+@@ -2560,6 +2560,19 @@ enum nl80211_commands {
+  *	disassoc events to indicate that an immediate reconnect to the AP
+  *	is desired.
+  *
++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the
++ *	%NL80211_CMD_OBSS_COLOR_COLLISION event.
++ *
++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's
++ *	until the color switch event.
++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are
++ *	switching to
++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
++ *	information for the time while performing a color switch.
++ *
++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
++ *	transmit power to stay within regulatory limits. u32, dBi.
++ *
+  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -3057,6 +3070,14 @@ enum nl80211_attrs {
+ 
+ 	NL80211_ATTR_DISABLE_HE,
+ 
++	NL80211_ATTR_OBSS_COLOR_BITMAP,
++
++	NL80211_ATTR_COLOR_CHANGE_COUNT,
++	NL80211_ATTR_COLOR_CHANGE_COLOR,
++	NL80211_ATTR_COLOR_CHANGE_ELEMS,
++
++	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
++
+ 	/* add attributes here, update the policy in nl80211.c */
+ 
+ 	__NL80211_ATTR_AFTER_LAST,
+@@ -5950,6 +5971,9 @@ enum nl80211_feature_flags {
+  *      frame protection for all management frames exchanged during the
+  *      negotiation and range measurement procedure.
+  *
++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
++ *	detection and change announcemnts.
++ *
+  * @NUM_NL80211_EXT_FEATURES: number of extended features.
+  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+  */
+@@ -6014,6 +6038,7 @@ enum nl80211_ext_feature_index {
+ 	NL80211_EXT_FEATURE_SECURE_LTF,
+ 	NL80211_EXT_FEATURE_SECURE_RTT,
+ 	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
++	NL80211_EXT_FEATURE_BSS_COLOR,
+ 
+ 	/* add new features before the definition below */
+ 	NUM_NL80211_EXT_FEATURES,
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/901-master-zero-wait_dfs.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/901-master-zero-wait_dfs.patch
new file mode 100644
index 0000000..cb11aee
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/901-master-zero-wait_dfs.patch
@@ -0,0 +1,851 @@
+diff --git a/hostapd/config_file.c b/hostapd/config_file.c
+index 1e1b685..8f6281a 100644
+--- a/hostapd/config_file.c
++++ b/hostapd/config_file.c
+@@ -2476,6 +2476,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
+ 		conf->ieee80211d = atoi(pos);
+ 	} else if (os_strcmp(buf, "ieee80211h") == 0) {
+ 		conf->ieee80211h = atoi(pos);
++	} else if (os_strcmp(buf, "radar_offchan") == 0) {
++		conf->radar_offchan = atoi(pos);
+ 	} else if (os_strcmp(buf, "ieee8021x") == 0) {
+ 		bss->ieee802_1x = atoi(pos);
+ 	} else if (os_strcmp(buf, "eapol_version") == 0) {
+diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
+index a89ce9b..0c951a9 100644
+--- a/hostapd/hostapd.conf
++++ b/hostapd/hostapd.conf
+@@ -143,6 +143,13 @@ ssid=test
+ # ieee80211d=1 and local_pwr_constraint configured.
+ #spectrum_mgmt_required=1
+ 
++# Enable radar/CAC detection through a dedicated offchannel chain available on
++# some hw. The chain can't be used to transmits or receives frames.
++# This feature allows to avoid CAC downtime switching on a different channel
++# during CAC detection on the selected radar channel.
++# (default: 0 = disabled, 1 = enabled)
++#radar_offchan=0
++
+ # 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
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index 28b7efe..ffc3c2c 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -993,6 +993,7 @@ struct hostapd_config {
+ 	int ieee80211d;
+ 
+ 	int ieee80211h; /* DFS */
++	int radar_offchan;
+ 
+ 	/*
+ 	 * Local power constraint is an octet encoded as an unsigned integer in
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index bc49079..c97ee39 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -810,7 +810,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ 			  int channel, int ht_enabled, int vht_enabled,
+ 			  int he_enabled,
+ 			  int sec_channel_offset, int oper_chwidth,
+-			  int center_segment0, int center_segment1)
++			  int center_segment0, int center_segment1,
++			  int radar_offchan)
+ {
+ 	struct hostapd_data *hapd = iface->bss[0];
+ 	struct hostapd_freq_params data;
+@@ -836,10 +837,14 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ 		wpa_printf(MSG_ERROR, "Can't set freq params");
+ 		return -1;
+ 	}
++	data.radar_offchan = radar_offchan;
+ 
+ 	res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+ 	if (!res) {
+-		iface->cac_started = 1;
++		if (radar_offchan)
++			iface->radar_offchan.cac_started = 1;
++		else
++			iface->cac_started = 1;
+ 		os_get_reltime(&iface->dfs_cac_start);
+ 	}
+ 
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index 61c8f64..92842a1 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -130,7 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ 			  int channel, int ht_enabled, int vht_enabled,
+ 			  int he_enabled,
+ 			  int sec_channel_offset, int oper_chwidth,
+-			  int center_segment0, int center_segment1);
++			  int center_segment0, int center_segment1,
++			  int radar_offchan);
+ int hostapd_drv_do_acs(struct hostapd_data *hapd);
+ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ 			     u16 reason_code, const u8 *ie, size_t ielen);
+diff --git a/src/ap/dfs.c b/src/ap/dfs.c
+index eccda1a..3b1276f 100644
+--- a/src/ap/dfs.c
++++ b/src/ap/dfs.c
+@@ -51,16 +51,31 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
+ 	return n_chans;
+ }
+ 
+-
++/*
++ * flags:
++ * - 0: any channel
++ * - 1: non-radar channel or radar available one
++ * - 2: radar-only channel not yet available
++ */
+ static int dfs_channel_available(struct hostapd_channel_data *chan,
+-				 int skip_radar)
++				 int flags)
+ {
++	if (flags == 2) {
++		/* Select only radar channel where CAC has not been
++		 * performed yet
++		 */
++		if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
++		    (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
++		     HOSTAPD_CHAN_DFS_USABLE)
++			return 1;
++		return 0;
++	}
+ 	/*
+ 	 * When radar detection happens, CSA is performed. However, there's no
+ 	 * time for CAC, so radar channels must be skipped when finding a new
+ 	 * channel for CSA, unless they are available for immediate use.
+ 	 */
+-	if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
++	if (flags && (chan->flag & HOSTAPD_CHAN_RADAR) &&
+ 	    ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
+ 	     HOSTAPD_CHAN_DFS_AVAILABLE))
+ 		return 0;
+@@ -136,10 +151,15 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
+ 	return NULL;
+ }
+ 
+-
++/*
++ * flags:
++ * - 0: any channel
++ * - 1: non-radar channel or radar available one
++ * - 2: radar-only channel not yet available
++ */
+ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+ 				    int first_chan_idx, int num_chans,
+-				    int skip_radar)
++				    int flags)
+ {
+ 	struct hostapd_channel_data *first_chan, *chan;
+ 	int i;
+@@ -178,7 +198,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
+ 			return 0;
+ 		}
+ 
+-		if (!dfs_channel_available(chan, skip_radar)) {
++		if (!dfs_channel_available(chan, flags)) {
+ 			wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
+ 				   first_chan->freq + i * 20);
+ 			return 0;
+@@ -205,10 +225,15 @@ static int is_in_chanlist(struct hostapd_iface *iface,
+  *  - hapd->secondary_channel
+  *  - hapd->vht/he_oper_centr_freq_seg0_idx
+  *  - hapd->vht/he_oper_centr_freq_seg1_idx
++ *
++ * flags:
++ * - 0: any channel
++ * - 1: non-radar channel or radar available one
++ * - 2: radar-only channel not yet available
+  */
+ static int dfs_find_channel(struct hostapd_iface *iface,
+ 			    struct hostapd_channel_data **ret_chan,
+-			    int idx, int skip_radar)
++			    int idx, int flags)
+ {
+ 	struct hostapd_hw_modes *mode;
+ 	struct hostapd_channel_data *chan;
+@@ -233,7 +258,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
+ 		}
+ 
+ 		/* Skip incompatible chandefs */
+-		if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
++		if (!dfs_chan_range_available(mode, i, n_chans, flags)) {
+ 			wpa_printf(MSG_DEBUG,
+ 				   "DFS: range not available for %d (%d)",
+ 				   chan->freq, chan->chan);
+@@ -467,13 +492,18 @@ static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
+ 	return res;
+ }
+ 
+-
++/*
++ * flags:
++ * - 0: any channel
++ * - 1: non-radar channel or radar available one
++ * - 2: radar-only channel not yet available
++ */
+ static struct hostapd_channel_data *
+ dfs_get_valid_channel(struct hostapd_iface *iface,
+ 		      int *secondary_channel,
+ 		      u8 *oper_centr_freq_seg0_idx,
+ 		      u8 *oper_centr_freq_seg1_idx,
+-		      int skip_radar)
++		      int flags)
+ {
+ 	struct hostapd_hw_modes *mode;
+ 	struct hostapd_channel_data *chan = NULL;
+@@ -502,7 +532,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
+ 		return NULL;
+ 
+ 	/* Get the count first */
+-	num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
++	num_available_chandefs = dfs_find_channel(iface, NULL, 0, flags);
+ 	wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
+ 		   num_available_chandefs);
+ 	if (num_available_chandefs == 0)
+@@ -523,7 +553,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
+ 		return NULL;
+ 
+ 	chan_idx = _rand % num_available_chandefs;
+-	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
++	dfs_find_channel(iface, &chan, chan_idx, flags);
+ 	if (!chan) {
+ 		wpa_printf(MSG_DEBUG, "DFS: no random channel found");
+ 		return NULL;
+@@ -552,7 +582,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
+ 		for (i = 0; i < num_available_chandefs - 1; i++) {
+ 			/* start from chan_idx + 1, end when chan_idx - 1 */
+ 			chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
+-			dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
++			dfs_find_channel(iface, &chan2, chan_idx2, flags);
+ 			if (chan2 && abs(chan2->chan - chan->chan) > 12) {
+ 				/* two channels are not adjacent */
+ 				sec_chan_idx_80p80 = chan2->chan;
+@@ -582,6 +612,27 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
+ 	return chan;
+ }
+ 
++static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
++{
++	struct hostapd_channel_data *channel;
++	u8 cf1 = 0, cf2 = 0;
++	int sec = 0;
++
++	channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
++					skip_radar);
++	if (!channel) {
++		wpa_printf(MSG_ERROR, "could not get valid channel");
++		return -1;
++	}
++
++	iface->freq = channel->freq;
++	iface->conf->channel = channel->chan;
++	iface->conf->secondary_channel = sec;
++	hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
++	hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
++
++	return 0;
++}
+ 
+ static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
+ {
+@@ -761,6 +812,11 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+ 	return cac_time_ms;
+ }
+ 
++static int hostapd_is_radar_offchan_enabled(struct hostapd_iface *iface)
++{
++	return (iface->drv_flags2 & WPA_DRIVER_RADAR_OFFCHAN) &&
++	       iface->conf->radar_offchan;
++}
+ 
+ /*
+  * Main DFS handler
+@@ -770,9 +826,8 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
+  */
+ int hostapd_handle_dfs(struct hostapd_iface *iface)
+ {
+-	struct hostapd_channel_data *channel;
+ 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
+-	int skip_radar = 0;
++	int skip_radar = 0, radar_offchan;
+ 
+ 	if (is_6ghz_freq(iface->freq))
+ 		return 1;
+@@ -825,28 +880,18 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
+ 		wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
+ 			   res, res ? "yes": "no");
+ 		if (res) {
+-			int sec = 0;
+-			u8 cf1 = 0, cf2 = 0;
+-
+-			channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
+-							skip_radar);
+-			if (!channel) {
+-				wpa_printf(MSG_ERROR, "could not get valid channel");
++			if (dfs_set_valid_channel(iface, skip_radar) < 0) {
+ 				hostapd_set_state(iface, HAPD_IFACE_DFS);
+ 				return 0;
+ 			}
+-
+-			iface->freq = channel->freq;
+-			iface->conf->channel = channel->chan;
+-			iface->conf->secondary_channel = sec;
+-			hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
+-			hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
+ 		}
+ 	} while (res);
+ 
+ 	/* Finally start CAC */
+ 	hostapd_set_state(iface, HAPD_IFACE_DFS);
+-	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
++	radar_offchan = hostapd_is_radar_offchan_enabled(iface);
++	wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz offchan %d",
++		   iface->freq, radar_offchan);
+ 	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+ 		"freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
+ 		iface->freq,
+@@ -863,13 +908,37 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
+ 		iface->conf->secondary_channel,
+ 		hostapd_get_oper_chwidth(iface->conf),
+ 		hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
+-		hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
++		hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
++		radar_offchan);
+ 
+ 	if (res) {
+ 		wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
+ 		return -1;
+ 	}
+ 
++	if (radar_offchan) {
++		/* Cache offchannel radar parameters */
++		iface->radar_offchan.channel = iface->conf->channel;
++		iface->radar_offchan.secondary_channel =
++			iface->conf->secondary_channel;
++		iface->radar_offchan.freq = iface->freq;
++		iface->radar_offchan.centr_freq_seg0_idx =
++			hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
++		iface->radar_offchan.centr_freq_seg1_idx =
++			hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
++
++		/*
++		 * Let's select a random channel for the moment
++		 * and perform CAC on dedicated radar chain
++		 */
++		res = dfs_set_valid_channel(iface, 1);
++		if (res < 0)
++			return res;
++
++		iface->radar_offchan.temp_ch = 1;
++		return 1;
++	}
++
+ 	return 0;
+ }
+ 
+@@ -890,6 +959,157 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
+ 	return dfs_check_chans_available(iface, start_chan_idx, n_chans);
+ }
+ 
++static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
++					      int channel, int freq,
++					      int secondary_channel,
++					      u8 oper_centr_freq_seg0_idx,
++					      u8 oper_centr_freq_seg1_idx)
++{
++	struct hostapd_hw_modes *cmode = iface->current_mode;
++	int ieee80211_mode = IEEE80211_MODE_AP, err, i;
++	struct csa_settings csa_settings;
++	u8 new_vht_oper_chwidth;
++
++	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
++	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
++		"freq=%d chan=%d sec_chan=%d", freq, channel,
++		secondary_channel);
++
++	new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
++	hostapd_set_oper_chwidth(iface->conf,
++				 hostapd_get_oper_chwidth(iface->conf));
++
++	/* Setup CSA request */
++	os_memset(&csa_settings, 0, sizeof(csa_settings));
++	csa_settings.cs_count = 5;
++	csa_settings.block_tx = 1;
++#ifdef CONFIG_MESH
++	if (iface->mconf)
++		ieee80211_mode = IEEE80211_MODE_MESH;
++#endif /* CONFIG_MESH */
++	err = hostapd_set_freq_params(&csa_settings.freq_params,
++				      iface->conf->hw_mode,
++				      freq, channel,
++				      iface->conf->enable_edmg,
++				      iface->conf->edmg_channel,
++				      iface->conf->ieee80211n,
++				      iface->conf->ieee80211ac,
++				      iface->conf->ieee80211ax,
++				      secondary_channel,
++				      new_vht_oper_chwidth,
++				      oper_centr_freq_seg0_idx,
++				      oper_centr_freq_seg1_idx,
++				      cmode->vht_capab,
++				      &cmode->he_capab[ieee80211_mode]);
++
++	if (err) {
++		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
++		hostapd_disable_iface(iface);
++		return err;
++	}
++
++	for (i = 0; i < iface->num_bss; i++) {
++		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
++		if (err)
++			break;
++	}
++
++	if (err) {
++		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
++			   err);
++		iface->freq = freq;
++		iface->conf->channel = channel;
++		iface->conf->secondary_channel = secondary_channel;
++		hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
++		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
++						     oper_centr_freq_seg0_idx);
++		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
++						     oper_centr_freq_seg1_idx);
++
++		hostapd_disable_iface(iface);
++		hostapd_enable_iface(iface);
++
++		return 0;
++	}
++
++	/* Channel configuration will be updated once CSA completes and
++	 * ch_switch_notify event is received */
++	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
++
++	return 0;
++}
++
++static struct hostapd_channel_data *
++dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
++			u8 *oper_centr_freq_seg0_idx,
++			u8 *oper_centr_freq_seg1_idx, int *skip_radar);
++
++static void
++hostpad_dfs_update_offchannel_chain(struct hostapd_iface *iface)
++{
++	struct hostapd_channel_data *channel;
++	int sec = 0, flags = 2;
++	u8 cf1 = 0, cf2 = 0;
++
++	channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 2);
++	if (!channel || channel->chan == iface->conf->channel)
++		channel = dfs_downgrade_bandwidth(iface, &sec, &cf1, &cf2,
++						  &flags);
++	if (!channel ||
++	    hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
++				  channel->freq, channel->chan,
++				  iface->conf->ieee80211n,
++				  iface->conf->ieee80211ac,
++				  iface->conf->ieee80211ax,
++				  sec, hostapd_get_oper_chwidth(iface->conf),
++				  cf1, cf2, 1)) {
++		/*
++		 * Toggle interface state to enter DFS state
++		 * until NOP is finished.
++		 */
++		wpa_printf(MSG_ERROR, "DFS failed start CAC offchannel");
++		return;
++	}
++
++	wpa_printf(MSG_DEBUG, "%s: setting offchannel chain to chan %d (%d MHz)",
++		   __func__, channel->chan, channel->freq);
++
++	iface->radar_offchan.channel = channel->chan;
++	iface->radar_offchan.freq = channel->freq;
++	iface->radar_offchan.secondary_channel = sec;
++	iface->radar_offchan.centr_freq_seg0_idx = cf1;
++	iface->radar_offchan.centr_freq_seg1_idx = cf2;
++}
++
++/* FIXME: check if all channel bandwith */
++static int
++hostapd_dfs_is_offchan_event(struct hostapd_iface *iface, int freq)
++{
++	if (iface->radar_offchan.freq != freq)
++		return 0;
++
++	return 1;
++}
++
++static int
++hostapd_dfs_start_channel_switch_offchan(struct hostapd_iface *iface)
++{
++	iface->conf->channel = iface->radar_offchan.channel;
++	iface->freq = iface->radar_offchan.freq;
++	iface->conf->secondary_channel =
++		iface->radar_offchan.secondary_channel;
++	hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
++			iface->radar_offchan.centr_freq_seg0_idx);
++	hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
++			iface->radar_offchan.centr_freq_seg1_idx);
++
++	hostpad_dfs_update_offchannel_chain(iface);
++
++	return hostapd_dfs_request_channel_switch(iface, iface->conf->channel,
++						  iface->freq, iface->conf->secondary_channel,
++						  hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
++						  hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
++}
+ 
+ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+ 			     int ht_enabled, int chan_offset, int chan_width,
+@@ -911,6 +1131,23 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+ 			set_dfs_state(iface, freq, ht_enabled, chan_offset,
+ 				      chan_width, cf1, cf2,
+ 				      HOSTAPD_CHAN_DFS_AVAILABLE);
++
++			/*
++			 * radar event from offchannel chain for selected
++			 * channel. Perfrom CSA, move main chain to selected
++			 * channel and configure offchannel chain to a new DFS
++			 * channel
++			 */
++			if (hostapd_is_radar_offchan_enabled(iface) &&
++			    hostapd_dfs_is_offchan_event(iface, freq)) {
++				iface->radar_offchan.cac_started = 0;
++				if (iface->radar_offchan.temp_ch) {
++					iface->radar_offchan.temp_ch = 0;
++					return hostapd_dfs_start_channel_switch_offchan(iface);
++				}
++				return 0;
++			}
++
+ 			/*
+ 			 * Just mark the channel available when CAC completion
+ 			 * event is received in enabled state. CAC result could
+@@ -927,6 +1164,10 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
+ 				iface->cac_started = 0;
+ 			}
+ 		}
++	} else if (hostapd_is_radar_offchan_enabled(iface) &&
++		   hostapd_dfs_is_offchan_event(iface, freq)) {
++		iface->radar_offchan.cac_started = 0;
++		hostpad_dfs_update_offchannel_chain(iface);
+ 	}
+ 
+ 	return 0;
+@@ -1036,6 +1277,44 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
+ 	return err;
+ }
+ 
++static int
++hostapd_dfs_offchan_start_channel_switch(struct hostapd_iface *iface, int freq)
++{
++	if (!hostapd_is_radar_offchan_enabled(iface))
++		return -1; /* Offchannel chain not supported */
++
++	wpa_printf(MSG_DEBUG,
++		   "%s called (offchannel CAC active: %s, CSA active: %s)",
++		   __func__, iface->radar_offchan.cac_started ? "yes" : "no",
++		   hostapd_csa_in_progress(iface) ? "yes" : "no");
++
++	/* Check if CSA in progress */
++	if (hostapd_csa_in_progress(iface))
++		return 0;
++
++	/*
++	 * If offchannel radar detation is supported and radar channel
++	 * monitored by offchain is available switch to it without waiting
++	 * for the CAC otherwise let's keep a random channel.
++	 * If radar pattern is reported on offchannel chain, just switch to
++	 * monitor another radar channel.
++	 */
++	if (hostapd_dfs_is_offchan_event(iface, freq)) {
++		hostpad_dfs_update_offchannel_chain(iface);
++		return 0;
++	}
++
++	/* Offchannel not availanle yet. Perform CAC on main chain */
++	if (iface->radar_offchan.cac_started) {
++		/* We want to switch to monitored channel as soon as
++		 * CAC is completed.
++		 */
++		iface->radar_offchan.temp_ch = 1;
++		return -1;
++	}
++
++	return hostapd_dfs_start_channel_switch_offchan(iface);
++}
+ 
+ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ {
+@@ -1043,13 +1322,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ 	int secondary_channel;
+ 	u8 oper_centr_freq_seg0_idx;
+ 	u8 oper_centr_freq_seg1_idx;
+-	u8 new_vht_oper_chwidth;
+ 	int skip_radar = 1;
+-	struct csa_settings csa_settings;
+-	unsigned int i;
+-	int err = 1;
+-	struct hostapd_hw_modes *cmode = iface->current_mode;
+-	u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+ 	int ieee80211_mode = IEEE80211_MODE_AP;
+ 
+ 	wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
+@@ -1113,73 +1386,16 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
+ 		}
+ 	}
+ 
+-	wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
+-		   channel->chan);
+-	wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
+-		"freq=%d chan=%d sec_chan=%d", channel->freq,
+-		channel->chan, secondary_channel);
+-
+-	new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
+-	hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
+-
+-	/* Setup CSA request */
+-	os_memset(&csa_settings, 0, sizeof(csa_settings));
+-	csa_settings.cs_count = 5;
+-	csa_settings.block_tx = 1;
+ #ifdef CONFIG_MESH
+ 	if (iface->mconf)
+ 		ieee80211_mode = IEEE80211_MODE_MESH;
+ #endif /* CONFIG_MESH */
+-	err = hostapd_set_freq_params(&csa_settings.freq_params,
+-				      iface->conf->hw_mode,
+-				      channel->freq,
+-				      channel->chan,
+-				      iface->conf->enable_edmg,
+-				      iface->conf->edmg_channel,
+-				      iface->conf->ieee80211n,
+-				      iface->conf->ieee80211ac,
+-				      iface->conf->ieee80211ax,
+-				      secondary_channel,
+-				      new_vht_oper_chwidth,
+-				      oper_centr_freq_seg0_idx,
+-				      oper_centr_freq_seg1_idx,
+-				      cmode->vht_capab,
+-				      &cmode->he_capab[ieee80211_mode]);
+-
+-	if (err) {
+-		wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
+-		hostapd_disable_iface(iface);
+-		return err;
+-	}
+ 
+-	for (i = 0; i < iface->num_bss; i++) {
+-		err = hostapd_switch_channel(iface->bss[i], &csa_settings);
+-		if (err)
+-			break;
+-	}
+-
+-	if (err) {
+-		wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
+-			   err);
+-		iface->freq = channel->freq;
+-		iface->conf->channel = channel->chan;
+-		iface->conf->secondary_channel = secondary_channel;
+-		hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
+-		hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
+-						     oper_centr_freq_seg0_idx);
+-		hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
+-						     oper_centr_freq_seg1_idx);
+-
+-		hostapd_disable_iface(iface);
+-		hostapd_enable_iface(iface);
+-		return 0;
+-	}
+-
+-	/* Channel configuration will be updated once CSA completes and
+-	 * ch_switch_notify event is received */
+-
+-	wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
+-	return 0;
++	return hostapd_dfs_request_channel_switch(iface, channel->chan,
++						  channel->freq,
++						  secondary_channel,
++						  oper_centr_freq_seg0_idx,
++						  oper_centr_freq_seg1_idx);
+ }
+ 
+ 
+@@ -1208,15 +1424,19 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
+ 	if (!res)
+ 		return 0;
+ 
+-	/* Skip if reported radar event not overlapped our channels */
+-	res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
+-	if (!res)
+-		return 0;
++	if (!hostapd_dfs_is_offchan_event(iface, freq)) {
++		/* Skip if reported radar event not overlapped our channels */
++		res = dfs_are_channels_overlapped(iface, freq, chan_width,
++						  cf1, cf2);
++		if (!res)
++			return 0;
++	}
+ 
+-	/* radar detected while operating, switch the channel. */
+-	res = hostapd_dfs_start_channel_switch(iface);
++	if (hostapd_dfs_offchan_start_channel_switch(iface, freq))
++		/* radar detected while operating, switch the channel. */
++		return hostapd_dfs_start_channel_switch(iface);
+ 
+-	return res;
++	return 0;
+ }
+ 
+ 
+@@ -1284,7 +1504,11 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ 		"seg1=%d cac_time=%ds",
+ 		freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
+ 		iface->dfs_cac_ms / 1000);
+-	iface->cac_started = 1;
++
++	if (hostapd_dfs_is_offchan_event(iface, freq))
++		iface->radar_offchan.cac_started = 1;
++	else
++		iface->cac_started = 1;
+ 	os_get_reltime(&iface->dfs_cac_start);
+ 	return 0;
+ }
+diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
+index 27b985d..1c6c94e 100644
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -521,6 +521,21 @@ struct hostapd_iface {
+ 	int *basic_rates;
+ 	int freq;
+ 
++	/* Offchanel chain configuration */
++	struct {
++		int channel;
++		int secondary_channel;
++		int freq;
++		int centr_freq_seg0_idx;
++		int centr_freq_seg1_idx;
++		/* Main chain is on temporary channel during
++		 * CAC detection on radar offchain
++		 */
++		unsigned int temp_ch:1;
++		/* CAC started on radar offchain */
++		unsigned int cac_started:1;
++	} radar_offchan;
++
+ 	u16 hw_flags;
+ 
+ 	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 6d9194f..7ed47c0 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -777,6 +777,11 @@ struct hostapd_freq_params {
+ 	 * for IEEE 802.11ay EDMG configuration.
+ 	 */
+ 	struct ieee80211_edmg_config edmg;
++
++	/**
++	 * radar_offchan - Whether radar/CAC offchannel is requested
++	 */
++	int radar_offchan;
+ };
+ 
+ /**
+@@ -2026,6 +2031,8 @@ struct wpa_driver_capa {
+ #define WPA_DRIVER_FLAGS2_OCV			0x0000000000000080ULL
+ /** Driver expects user space implementation of SME in AP mode */
+ #define WPA_DRIVER_FLAGS2_AP_SME		0x0000000000000100ULL
++/** Driver supports offchannel radar/CAC detection */
++#define WPA_DRIVER_RADAR_OFFCHAN		0x0000000000000200ULL
+ 	u64 flags2;
+ 
+ #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 4db8cce..62c3cd8 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4885,6 +4885,7 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
+ 	wpa_printf(MSG_DEBUG, "  * he_enabled=%d", freq->he_enabled);
+ 	wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
+ 	wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
++	wpa_printf(MSG_DEBUG, "  * radar_offchan=%d", freq->radar_offchan);
+ 
+ 	hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
+ 	is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
+@@ -4962,6 +4963,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
+ 				NL80211_CHAN_NO_HT))
+ 			return -ENOBUFS;
+ 	}
++	if (freq->radar_offchan)
++		nla_put_flag(msg, NL80211_ATTR_RADAR_OFFCHAN);
++
+ 	return 0;
+ }
+ 
+diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
+index cd596e3..e370ef3 100644
+--- a/src/drivers/driver_nl80211_capa.c
++++ b/src/drivers/driver_nl80211_capa.c
+@@ -665,6 +665,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
+ 	if (ext_feature_isset(ext_features, len,
+ 			      NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
+ 		capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
++
++	if (ext_feature_isset(ext_features, len,
++			      NL80211_EXT_FEATURE_RADAR_OFFCHAN))
++		capa->flags2 |= WPA_DRIVER_RADAR_OFFCHAN;
+ }
+ 
+ 
+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
+index f7be755..736b483 100644
+--- a/src/drivers/nl80211_copy.h
++++ b/src/drivers/nl80211_copy.h
+@@ -2573,6 +2573,10 @@ enum nl80211_commands {
+  * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
+  *	transmit power to stay within regulatory limits. u32, dBi.
+  *
++ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated chain available for radar
++ *	detection on some hw. The chain can't be used to transmits or receives
++ *	frames. The driver is supposed to implement CAC management in sw or fw.
++ *
+  * @NUM_NL80211_ATTR: total number of nl80211_attrs available
+  * @NL80211_ATTR_MAX: highest attribute number currently defined
+  * @__NL80211_ATTR_AFTER_LAST: internal use
+@@ -3078,6 +3082,8 @@ enum nl80211_attrs {
+ 
+ 	NL80211_ATTR_WIPHY_ANTENNA_GAIN,
+ 
++	NL80211_ATTR_RADAR_OFFCHAN,
++
+ 	/* add attributes here, update the policy in nl80211.c */
+ 
+ 	__NL80211_ATTR_AFTER_LAST,
+@@ -5974,6 +5980,9 @@ enum nl80211_feature_flags {
+  * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
+  *	detection and change announcemnts.
+  *
++ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC
++ *	detection.
++ *
+  * @NUM_NL80211_EXT_FEATURES: number of extended features.
+  * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+  */
+@@ -6039,6 +6048,7 @@ enum nl80211_ext_feature_index {
+ 	NL80211_EXT_FEATURE_SECURE_RTT,
+ 	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
+ 	NL80211_EXT_FEATURE_BSS_COLOR,
++	NL80211_EXT_FEATURE_RADAR_OFFCHAN,
+ 
+ 	/* add new features before the definition below */
+ 	NUM_NL80211_EXT_FEATURES,
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch
new file mode 100644
index 0000000..e761c00
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch
@@ -0,0 +1,72 @@
+From 413cb1d917383c5f4cb4bb6b94310c4f193a9187 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 19:18:07 +0800
+Subject: [PATCH 1/9] Add hostapd_neighbor_count() and
+ hostapd_neighbor_insert_buffer ()
+
+The first function can count the number of neighbor report in neighbore report
+database. The second can iterate neighbor report database to build up neighbor
+report data.
+---
+ src/ap/neighbor_db.c | 32 ++++++++++++++++++++++++++++++++
+ src/ap/neighbor_db.h |  3 +++
+ 2 files changed, 35 insertions(+)
+
+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
+index 229edd2..ce6865d 100644
+--- a/src/ap/neighbor_db.c
++++ b/src/ap/neighbor_db.c
+@@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
+ }
+ 
+ 
++int hostapd_neighbor_count(struct hostapd_data *hapd)
++{
++	struct hostapd_neighbor_entry *nr;
++	int count = 0;
++
++	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
++			 list) {
++		count++;
++	}
++	return count;
++}
++
++
++int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
++        size_t buflen)
++{
++	struct hostapd_neighbor_entry *nr;
++	char *pos = buf;
++
++	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
++			 list) {
++		/* For neighbor report IE, we only need bssid and nr*/
++		*pos++ = WLAN_EID_NEIGHBOR_REPORT;
++		*pos++ = wpabuf_len(nr->nr);
++		os_memcpy(pos, wpabuf_head(nr->nr), wpabuf_len(nr->nr));
++		pos += wpabuf_len(nr->nr);
++	}
++
++	return pos - buf;
++}
++
++
+ static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
+ {
+ 	wpabuf_free(nr->nr);
+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
+index 992671b..1ae194d 100644
+--- a/src/ap/neighbor_db.h
++++ b/src/ap/neighbor_db.h
+@@ -24,4 +24,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
+ 			    const struct wpa_ssid_value *ssid);
+ void hostapd_free_neighbor_db(struct hostapd_data *hapd);
+ 
++int hostapd_neighbor_count(struct hostapd_data *hapd);
++int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
++        size_t buflen);
+ #endif /* NEIGHBOR_DB_H */
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch
new file mode 100644
index 0000000..3e6506a
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch
@@ -0,0 +1,95 @@
+From adacd810f97a89472f26b454805cd67d0e6f5d31 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 19:25:05 +0800
+Subject: [PATCH 2/9] Support including neighbor report elements in ANQP
+ response
+
+---
+ src/ap/gas_serv.c | 29 +++++++++++++++++++++++++++++
+ src/ap/gas_serv.h |  2 ++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
+index 90f1577..5845ff8 100644
+--- a/src/ap/gas_serv.c
++++ b/src/ap/gas_serv.c
+@@ -19,6 +19,7 @@
+ #include "dpp_hostapd.h"
+ #include "sta_info.h"
+ #include "gas_serv.h"
++#include "neighbor_db.h"
+ 
+ 
+ #ifdef CONFIG_DPP
+@@ -369,6 +370,24 @@ static void anqp_add_network_auth_type(struct hostapd_data *hapd,
+ 	}
+ }
+ 
++static void anqp_add_neighbor_report(struct hostapd_data *hapd,
++				       struct wpabuf *buf)
++{
++	struct hostapd_neighbor_entry *nr;
++	u8 *len_pos = gas_anqp_add_element(buf, ANQP_NEIGHBOR_REPORT);
++	if (dl_list_empty(&hapd->nr_db)) {
++		wpabuf_put_le16(buf, 0);
++	}
++	else {
++		dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list ) {
++			wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
++			wpabuf_put_u8(buf, wpabuf_len(nr->nr));
++			wpabuf_put_buf(buf, nr->nr);
++		}
++	}
++	gas_anqp_set_element_len(buf, len_pos);
++}
++
+ 
+ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+ 					struct wpabuf *buf)
+@@ -986,6 +1005,9 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+ 		len += 1000;
+ 	if (request & ANQP_REQ_ICON_REQUEST)
+ 		len += 65536;
++    if (request & ANQP_REQ_NEIGHBOR_REPORT) {
++        len += (40 * hostapd_neighbor_count(hapd));
++    }
+ #ifdef CONFIG_FILS
+ 	if (request & ANQP_FILS_REALM_INFO)
+ 		len += 2 * dl_list_len(&hapd->conf->fils_realms);
+@@ -1028,6 +1050,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+ 		anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
+ 	if (request & ANQP_REQ_EMERGENCY_NAI)
+ 		anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
++	if (request & ANQP_REQ_NEIGHBOR_REPORT)
++		anqp_add_neighbor_report(hapd, buf);
+ 
+ 	for (i = 0; i < num_extra_req; i++) {
+ #ifdef CONFIG_FILS
+@@ -1172,6 +1196,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+ 			     "Emergency NAI",
+ 			     get_anqp_elem(hapd, info_id) != NULL, qi);
+ 		break;
++	case ANQP_NEIGHBOR_REPORT:
++		set_anqp_req(ANQP_REQ_NEIGHBOR_REPORT,
++			     "Neighbor Report",
++			     get_anqp_elem(hapd, info_id) != NULL, qi);
++		break;
+ 	default:
+ #ifdef CONFIG_FILS
+ 		if (info_id == ANQP_FILS_REALM_INFO &&
+diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
+index 1528af4..d0241f2 100644
+--- a/src/ap/gas_serv.h
++++ b/src/ap/gas_serv.h
+@@ -40,6 +40,8 @@
+ 	(1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
+ #define ANQP_REQ_EMERGENCY_NAI \
+ 	(1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
++#define ANQP_REQ_NEIGHBOR_REPORT \
++	(1 << (ANQP_NEIGHBOR_REPORT - ANQP_QUERY_LIST))
+ /*
+  * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
+  * optimized bitmap.
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch
new file mode 100644
index 0000000..86d8fd1
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch
@@ -0,0 +1,68 @@
+From 4a7b4a0fe05dd01ae64dd4e291d05de6d5f05bb7 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 19:49:09 +0800
+Subject: [PATCH 3/9] Support including neignbor report elements in BTM
+ response
+
+---
+ src/ap/wnm_ap.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
+index 72cd126..b55b3f3 100644
+--- a/src/ap/wnm_ap.c
++++ b/src/ap/wnm_ap.c
+@@ -20,6 +20,7 @@
+ #include "ap/wpa_auth.h"
+ #include "mbo_ap.h"
+ #include "wnm_ap.h"
++#include "ap/neighbor_db.h"
+ 
+ #define MAX_TFS_IE_LEN  1024
+ 
+@@ -370,9 +371,21 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
+ 	u8 *pos;
+ 	int res;
+ 
+-	mgmt = os_zalloc(sizeof(*mgmt));
+-	if (mgmt == NULL)
++	int nr_num = hostapd_neighbor_count(hapd);
++	int nr_size = ETH_ALEN + 4 + 1 + 1 + 1 + 5;
++	int total_nr_size = nr_num * nr_size;
++	u8 *nr_data = os_malloc(total_nr_size);
++	int nr_data_len = 0;
++	if(nr_data == NULL) {
++		wpa_printf (MSG_ERROR, "Failed to allocate memory");
++	} else {
++	    nr_data_len = hostapd_neighbor_insert_buffer(hapd, nr_data, total_nr_size);
++	}
++	mgmt = os_zalloc(sizeof(*mgmt) + nr_data_len);
++	if (mgmt == NULL) {
++		wpa_printf (MSG_ERROR, "Failed to allocate memory for mgmt frame");
+ 		return -1;
++	}
+ 	os_memcpy(mgmt->da, addr, ETH_ALEN);
+ 	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+ 	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+@@ -382,10 +395,18 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
+ 	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+ 	mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
+ 	mgmt->u.action.u.bss_tm_req.req_mode = 0;
++	if(nr_num) {
++		mgmt->u.action.u.bss_tm_req.req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
++	}
+ 	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+ 	mgmt->u.action.u.bss_tm_req.validity_interval = 1;
+ 	pos = mgmt->u.action.u.bss_tm_req.variable;
+ 
++	if(nr_num) {
++		os_memcpy(pos, nr_data, nr_data_len);
++		pos += nr_data_len;
++	}
++
+ 	hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
+ 		   MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch
new file mode 100644
index 0000000..f6832e3
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch
@@ -0,0 +1,66 @@
+From 56613ad9b568a3ac7467105beaa162c68ffbbf70 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 20:20:03 +0800
+Subject: [PATCH 4/9] Support configuring BSS Termination TSF by using
+ hostapd_cli command
+
+---
+ hostapd/ctrl_iface.c | 9 +++++++++
+ src/ap/ap_config.c   | 1 +
+ src/ap/ap_config.h   | 1 +
+ 3 files changed, 11 insertions(+)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index f50fafb..1b5a091 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -954,6 +954,10 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ 			wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+ 			return -1;
+ 		}
++		if (hapd->conf->bss_termination_tsf) {
++			WPA_PUT_LE64(&bss_term_dur[2], hapd->conf->bss_termination_tsf);
++		}
++
+ 		end++;
+ 		WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
+ 	}
+@@ -1589,6 +1593,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
+ #endif /* CONFIG_DPP */
+ 	} else if (os_strcasecmp(cmd, "setband") == 0) {
+ 		ret = hostapd_ctrl_iface_set_band(hapd, value);
++	} else if (os_strcasecmp(cmd, "bss_termination_tsf") == 0) {
++		int termination_sec = atoi(value);
++		hapd->conf->bss_termination_tsf = termination_sec;
++		wpa_printf(MSG_DEBUG, "BSS Termination TSF: value = %d",
++                termination_sec);
+ 	} else {
+ 		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
+ 		if (ret)
+diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
+index 1f04686..078a3fc 100644
+--- a/src/ap/ap_config.c
++++ b/src/ap/ap_config.c
+@@ -170,6 +170,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+ 	/* comeback after 10 TUs */
+ 	bss->pasn_comeback_after = 10;
+ #endif /* CONFIG_PASN */
++	bss->bss_termination_tsf = 0;
+ }
+ 
+ 
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index f3aff36..7301bbb 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -549,6 +549,7 @@ struct hostapd_bss_config {
+ 	int wnm_sleep_mode;
+ 	int wnm_sleep_mode_no_keys;
+ 	int bss_transition;
++	unsigned int bss_termination_tsf;
+ 
+ 	/* IEEE 802.11u - Interworking */
+ 	int interworking;
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch
new file mode 100644
index 0000000..0d28e4e
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch
@@ -0,0 +1,47 @@
+From dcedb231bc62949d458792530a14ceddfee20e96 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 21:03:38 +0800
+Subject: [PATCH 5/9] Disable interface if BSS Termination TSF is set
+
+---
+ src/ap/wnm_ap.c | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
+index b55b3f3..6eac3ac 100644
+--- a/src/ap/wnm_ap.c
++++ b/src/ap/wnm_ap.c
+@@ -767,6 +767,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+ }
+ 
+ 
++void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
++{
++	struct hostapd_data *hapd = eloop_ctx;
++	hostapd_disable_iface(hapd->iface);
++}
++
++
++static void set_disable_iface_timer(struct hostapd_data *hapd, struct sta_info *sta,
++			       int disable_iface_timer)
++{
++	wpa_printf(MSG_DEBUG, "Disable interface timer set to %d secs", disable_iface_timer);
++	eloop_register_timeout(disable_iface_timer, 0,
++			       bss_termination_disable_iface, hapd, NULL);
++}
++
++
+ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
+ 				   struct sta_info *sta, const char *url,
+ 				   int disassoc_timer)
+@@ -856,6 +872,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+ 	    bss_term_dur) {
+ 		os_memcpy(pos, bss_term_dur, 12);
+ 		pos += 12;
++		set_disable_iface_timer(hapd, sta, hapd->conf->bss_termination_tsf);
+ 	}
+ 
+ 	if (url) {
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch
new file mode 100644
index 0000000..be0f823
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch
@@ -0,0 +1,63 @@
+From cb31775e39eaa2b8a0bd36f5e195ac8bff967535 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 21:15:07 +0800
+Subject: [PATCH 6/9] Add set_send_disassoc_frame_timer() to send disassociate
+ frame
+
+Function set_disassoc_timer() may fail if key was deleted first. This new
+function will not ask to delete key as set_disassoc_timer() did.
+---
+ src/ap/wnm_ap.c | 30 +++++++++++++++++++++++++++++-
+ 1 file changed, 29 insertions(+), 1 deletion(-)
+
+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
+index 6eac3ac..fad132c 100644
+--- a/src/ap/wnm_ap.c
++++ b/src/ap/wnm_ap.c
+@@ -767,6 +767,34 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+ }
+ 
+ 
++static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta,
++			       int disassoc_timer)
++{
++	int timeout, beacon_int;
++
++	/*
++	 * Prevent STA from reconnecting using cached PMKSA to force
++	 * full authentication with the authentication server (which may
++	 * decide to reject the connection),
++	 */
++	wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
++
++	beacon_int = hapd->iconf->beacon_int;
++	if (beacon_int < 1)
++		beacon_int = 100; /* best guess */
++	/* Calculate timeout in ms based on beacon_int in TU */
++	timeout = disassoc_timer * beacon_int * 128 / 125;
++	wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
++		   " set to %d ms", MAC2STR(sta->addr), timeout);
++
++	u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
++
++	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
++	if (sta)
++		ap_sta_disassociate(hapd, sta, reason);
++}
++
++
+ void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
+ {
+ 	struct hostapd_data *hapd = eloop_ctx;
+@@ -909,7 +937,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+ 	hapd->openwrt_stats.wnm.bss_transition_request_tx++;
+ 	if (disassoc_timer) {
+ 		/* send disassociation frame after time-out */
+-		set_disassoc_timer(hapd, sta, disassoc_timer);
++		set_send_disassoc_frame_timer(hapd, sta, disassoc_timer);
+ 	}
+ 
+ 	return 0;
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch
new file mode 100644
index 0000000..1bf102a
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch
@@ -0,0 +1,31 @@
+From 9043eff145701c6324ae48966301681adacb89c4 Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 21:16:45 +0800
+Subject: [PATCH 7/9] Support including neighbor report elements in BTM request
+
+---
+ hostapd/ctrl_iface.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 1b5a091..5a82ae6 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -984,8 +984,13 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ 		req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+ 	}
+ 
+-	if (os_strstr(cmd, " pref=1"))
++	if (os_strstr(cmd, " pref=1")) {
+ 		req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
++		if (nei_len == 0) {
++			// Add neigibor report from neighbor report db to nei_rep buffer
++			nei_len = hostapd_neighbor_insert_buffer (hapd, nei_rep, 1000);
++		}
++	}
+ 	if (os_strstr(cmd, " abridged=1"))
+ 		req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+ 	if (os_strstr(cmd, " disassoc_imminent=1"))
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch
new file mode 100644
index 0000000..14571fe
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch
@@ -0,0 +1,88 @@
+From 6fc069a54efb892e486dfde59cb97e0023dbbf5d Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 21:27:55 +0800
+Subject: [PATCH 8/9] Add hostapd_neighbor_set_own_report_pref()
+
+If my own BSS is going to terminate itself, the preference value of neighbor
+report must be set to 0.
+---
+ hostapd/ctrl_iface.c |  5 ++++-
+ src/ap/neighbor_db.c | 36 ++++++++++++++++++++++++++++++++++++
+ src/ap/neighbor_db.h |  2 ++
+ 3 files changed, 42 insertions(+), 1 deletion(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 5a82ae6..3146a25 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -993,8 +993,11 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ 	}
+ 	if (os_strstr(cmd, " abridged=1"))
+ 		req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+-	if (os_strstr(cmd, " disassoc_imminent=1"))
++	if (os_strstr(cmd, " disassoc_imminent=1")) {
+ 		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
++		/* Set own BSS neighbor report preference value as 0 */
++		hostapd_neighbor_set_own_report_pref(hapd, nei_rep, nei_len, 0);
++	}
+ 
+ #ifdef CONFIG_MBO
+ 	pos = os_strstr(cmd, "mbo=");
+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
+index ce6865d..bc1b163 100644
+--- a/src/ap/neighbor_db.c
++++ b/src/ap/neighbor_db.c
+@@ -352,3 +352,39 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
+ 	wpabuf_free(nr);
+ #endif /* NEED_AP_MLME */
+ }
++
++
++void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
++			 size_t buflen, const int pref)
++{
++	struct hostapd_neighbor_entry *nr;
++	char *pos, *next_nr;
++
++	pos = nei_buf;
++	next_nr = nei_buf;
++
++	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
++			 list) {
++		pos = next_nr;
++		next_nr = pos + 2 + wpabuf_len(nr->nr);
++		/* Shift 2 bytes for Element ID and Neighbor report length */
++		pos = pos + 2;
++		if(os_memcmp(pos, hapd->own_addr, ETH_ALEN) == 0) {
++			/* Shift for BSSID + BSSID info + Op_class + channel num + PHY type */
++			pos = pos + 6 + 4 + 1 + 1 + 1;
++
++			/* Iterate Subelement */
++			while (next_nr - pos > 0) {
++				if (*pos == 3) {
++					pos = pos + 2;
++					*pos = pref;
++					return;
++				} else {
++					pos++;
++					int shift_len = *pos++;
++					pos = pos + shift_len;
++				}
++			}
++		}
++	}
++}
+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
+index 1ae194d..2e16f72 100644
+--- a/src/ap/neighbor_db.h
++++ b/src/ap/neighbor_db.h
+@@ -27,4 +27,6 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd);
+ int hostapd_neighbor_count(struct hostapd_data *hapd);
+ int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
+         size_t buflen);
++void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
++			 size_t buflen, const int pref);
+ #endif /* NEIGHBOR_DB_H */
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch
new file mode 100644
index 0000000..632475c
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch
@@ -0,0 +1,101 @@
+From 7aab6cf66cfb7dea480d16e312e0f0eb08e758ab Mon Sep 17 00:00:00 2001
+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
+Date: Wed, 19 Jan 2022 21:32:17 +0800
+Subject: [PATCH 9/9] Add hostapd_neighbor_set_pref_by_non_pref_chan()
+
+The preference value of neighbor report shall be modified according to struct
+non_pref_chan_info.
+---
+ hostapd/ctrl_iface.c |  2 ++
+ src/ap/neighbor_db.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
+ src/ap/neighbor_db.h |  4 ++++
+ 3 files changed, 57 insertions(+)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 3146a25..974e5b9 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -1000,6 +1000,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+ 	}
+ 
+ #ifdef CONFIG_MBO
++	hostapd_neighbor_set_pref_by_non_pref_chan(hapd, sta, nei_rep, nei_len);
++
+ 	pos = os_strstr(cmd, "mbo=");
+ 	if (pos) {
+ 		unsigned int mbo_reason, cell_pref, reassoc_delay;
+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
+index bc1b163..75b6fcc 100644
+--- a/src/ap/neighbor_db.c
++++ b/src/ap/neighbor_db.c
+@@ -388,3 +388,54 @@ void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_b
+ 		}
+ 	}
+ }
++
++#ifdef CONFIG_MBO
++void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
++			 struct sta_info* sta, char *nei_buf, size_t buflen)
++{
++	struct hostapd_neighbor_entry *nr;
++	struct mbo_non_pref_chan_info *info;
++	u8 i;
++
++	for(info = sta->non_pref_chan; info; info = info->next) {
++		/* Check OP_Class and Channel num */
++		for(i = 0; i < info->num_channels; i++) {
++			char *pos, *next_nr;
++
++			pos = nei_buf;
++			next_nr = nei_buf;
++
++			/* Iterate Neighbor report database */
++			dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
++					 list) {
++				pos = next_nr;
++				next_nr = pos + 2 + wpabuf_len(nr->nr);
++				/**
++				 * Shift 12 bytes for Element ID, Neighbor report length,
++				 * BSSID and BSSID info.
++				 */
++				pos = pos + 12;
++				int nr_op_class = *pos++;
++				int nr_channel = *pos;
++				if(info->op_class == nr_op_class && info->channels[i] == nr_channel) {
++					/* Shift for Channel Num + PHY type */
++					pos = pos + 1 + 1;
++
++					// Iterate Subelement
++					while(next_nr - pos > 0) {
++						if(*pos == 3) {
++							pos = pos + 2;
++							*pos = info->pref;
++							break;
++						}else {
++							pos++;
++							int shift_len = *pos++;
++							pos = pos + shift_len;
++						}
++					}
++				}
++			}
++		}
++	}
++}
++#endif
+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
+index 2e16f72..a1ddc07 100644
+--- a/src/ap/neighbor_db.h
++++ b/src/ap/neighbor_db.h
+@@ -29,4 +29,8 @@ int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
+         size_t buflen);
+ void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
+ 			 size_t buflen, const int pref);
++#ifdef CONFIG_MBO
++void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
++			 struct sta_info* sta, char *nei_buf, size_t buflen);
++#endif
+ #endif /* NEIGHBOR_DB_H */
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/911-master-print-sae-groups-by-hostapd-ctrl.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/911-master-print-sae-groups-by-hostapd-ctrl.patch
new file mode 100644
index 0000000..859fdbf
--- /dev/null
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/911-master-print-sae-groups-by-hostapd-ctrl.patch
@@ -0,0 +1,22 @@
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -1584,6 +1584,19 @@ static int hostapd_ctrl_iface_get(struct
+ 		if (os_snprintf_error(buflen, res))
+ 			return -1;
+ 		return res;
++	} else if (os_strcmp(cmd, "sae_group_capability") == 0) {
++#ifdef CONFIG_SAE
++		/* see sae_set_group() */
++		res = os_snprintf(buf, buflen, "%s%s%s%s19 20 21",
++				  dh_groups_get(15) ? "15 ": "",
++				  dh_groups_get(16) ? "16 ": "",
++				  dh_groups_get(17) ? "17 ": "",
++				  dh_groups_get(18) ? "18 ": "");
++
++		if (os_snprintf_error(buflen, res))
++			return -1;
++		return res;
++#endif /* CONFIG_SAE */
+ 	}
+ 
+ 	return -1;