blob: 13c14c6809d832c77d3ea18955d9af10e2ce36b0 [file] [log] [blame]
developerdd6437e2022-01-20 16:45:58 +08001From 38040b75986d6efe3d6c846cd3850c21bff94f62 Mon Sep 17 00:00:00 2001
2From: "howard.hsu" <howard-yh.hsu@mediatek.com>
3Date: Thu, 20 Jan 2022 16:39:04 +0800
4Subject: [PATCH] Add hostapd patches for WiFi Certification MBO test plan
5
6---
7 ...hbor_count-and-hostapd_neighbor_inse.patch | 72 ++
8 ...g-neighbor-report-elements-in-ANQP-r.patch | 95 ++
9 ...ster-sync-include-uapi-linux-nl80211.patch | 57 ++
10 ...g-neignbor-report-elements-in-BTM-re.patch | 68 ++
11 .../patches/904-master-zero-wait_dfs.patch | 851 ++++++++++++++++++
12 ...ing-BSS-Termination-TSF-by-using-hos.patch | 66 ++
13 ...erface-if-BSS-Termination-TSF-is-set.patch | 47 +
14 ...assoc_frame_timer-to-send-disassocia.patch | 63 ++
15 ...g-neighbor-report-elements-in-BTM-re.patch | 31 +
16 ...hostapd_neighbor_set_own_report_pref.patch | 88 ++
17 ...d_neighbor_set_pref_by_non_pref_chan.patch | 101 +++
18 11 files changed, 1539 insertions(+)
19 create mode 100644 package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch
20 create mode 100644 package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch
21 create mode 100644 package/network/services/hostapd/patches/903-master-sync-include-uapi-linux-nl80211.patch
22 create mode 100644 package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch
23 create mode 100644 package/network/services/hostapd/patches/904-master-zero-wait_dfs.patch
24 create mode 100644 package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch
25 create mode 100644 package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch
26 create mode 100644 package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch
27 create mode 100644 package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch
28 create mode 100644 package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch
29 create mode 100644 package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch
30
31diff --git a/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch b/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch
32new file mode 100644
33index 0000000..3a7e018
34--- /dev/null
35+++ b/package/network/services/hostapd/patches/902-master-Add-hostapd_neighbor_count-and-hostapd_neighbor_inse.patch
36@@ -0,0 +1,72 @@
37+From e53d12c69846446bd38a8d05f5a99d79e7907733 Mon Sep 17 00:00:00 2001
38+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
39+Date: Wed, 19 Jan 2022 19:18:07 +0800
40+Subject: [PATCH 1/9] Add hostapd_neighbor_count() and
41+ hostapd_neighbor_insert_buffer ()
42+
43+The first function can count the number of neighbor report in neighbore report
44+database. The second can iterate neighbor report database to build up neighbor
45+report data.
46+---
47+ src/ap/neighbor_db.c | 32 ++++++++++++++++++++++++++++++++
48+ src/ap/neighbor_db.h | 3 +++
49+ 2 files changed, 35 insertions(+)
50+
51+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
52+index 2bbe318..a47afd4 100644
53+--- a/src/ap/neighbor_db.c
54++++ b/src/ap/neighbor_db.c
55+@@ -88,6 +88,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
56+ }
57+
58+
59++int hostapd_neighbor_count(struct hostapd_data *hapd)
60++{
61++ struct hostapd_neighbor_entry *nr;
62++ int count = 0;
63++
64++ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
65++ list) {
66++ count++;
67++ }
68++ return count;
69++}
70++
71++
72++int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
73++ size_t buflen)
74++{
75++ struct hostapd_neighbor_entry *nr;
76++ char *pos = buf;
77++
78++ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
79++ list) {
80++ /* For neighbor report IE, we only need bssid and nr*/
81++ *pos++ = WLAN_EID_NEIGHBOR_REPORT;
82++ *pos++ = wpabuf_len(nr->nr);
83++ os_memcpy(pos, wpabuf_head(nr->nr), wpabuf_len(nr->nr));
84++ pos += wpabuf_len(nr->nr);
85++ }
86++
87++ return pos - buf;
88++}
89++
90++
91+ static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
92+ {
93+ wpabuf_free(nr->nr);
94+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
95+index bed0a2f..e93d1d5 100644
96+--- a/src/ap/neighbor_db.h
97++++ b/src/ap/neighbor_db.h
98+@@ -23,4 +23,7 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
99+ const struct wpa_ssid_value *ssid);
100+ void hostapd_free_neighbor_db(struct hostapd_data *hapd);
101+
102++int hostapd_neighbor_count(struct hostapd_data *hapd);
103++int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
104++ size_t buflen);
105+ #endif /* NEIGHBOR_DB_H */
106+--
107+2.18.0
108+
109diff --git a/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch b/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch
110new file mode 100644
111index 0000000..73c0052
112--- /dev/null
113+++ b/package/network/services/hostapd/patches/903-master-Support-including-neighbor-report-elements-in-ANQP-r.patch
114@@ -0,0 +1,95 @@
115+From 3111458bed644db0795942e825c65a14c7c12b7b Mon Sep 17 00:00:00 2001
116+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
117+Date: Wed, 19 Jan 2022 19:25:05 +0800
118+Subject: [PATCH 2/9] Support including neighbor report elements in ANQP
119+ response
120+
121+---
122+ src/ap/gas_serv.c | 29 +++++++++++++++++++++++++++++
123+ src/ap/gas_serv.h | 2 ++
124+ 2 files changed, 31 insertions(+)
125+
126+diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
127+index 90f1577..5845ff8 100644
128+--- a/src/ap/gas_serv.c
129++++ b/src/ap/gas_serv.c
130+@@ -19,6 +19,7 @@
131+ #include "dpp_hostapd.h"
132+ #include "sta_info.h"
133+ #include "gas_serv.h"
134++#include "neighbor_db.h"
135+
136+
137+ #ifdef CONFIG_DPP
138+@@ -369,6 +370,24 @@ static void anqp_add_network_auth_type(struct hostapd_data *hapd,
139+ }
140+ }
141+
142++static void anqp_add_neighbor_report(struct hostapd_data *hapd,
143++ struct wpabuf *buf)
144++{
145++ struct hostapd_neighbor_entry *nr;
146++ u8 *len_pos = gas_anqp_add_element(buf, ANQP_NEIGHBOR_REPORT);
147++ if (dl_list_empty(&hapd->nr_db)) {
148++ wpabuf_put_le16(buf, 0);
149++ }
150++ else {
151++ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list ) {
152++ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
153++ wpabuf_put_u8(buf, wpabuf_len(nr->nr));
154++ wpabuf_put_buf(buf, nr->nr);
155++ }
156++ }
157++ gas_anqp_set_element_len(buf, len_pos);
158++}
159++
160+
161+ static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
162+ struct wpabuf *buf)
163+@@ -986,6 +1005,9 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
164+ len += 1000;
165+ if (request & ANQP_REQ_ICON_REQUEST)
166+ len += 65536;
167++ if (request & ANQP_REQ_NEIGHBOR_REPORT) {
168++ len += (40 * hostapd_neighbor_count(hapd));
169++ }
170+ #ifdef CONFIG_FILS
171+ if (request & ANQP_FILS_REALM_INFO)
172+ len += 2 * dl_list_len(&hapd->conf->fils_realms);
173+@@ -1028,6 +1050,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
174+ anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
175+ if (request & ANQP_REQ_EMERGENCY_NAI)
176+ anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
177++ if (request & ANQP_REQ_NEIGHBOR_REPORT)
178++ anqp_add_neighbor_report(hapd, buf);
179+
180+ for (i = 0; i < num_extra_req; i++) {
181+ #ifdef CONFIG_FILS
182+@@ -1172,6 +1196,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
183+ "Emergency NAI",
184+ get_anqp_elem(hapd, info_id) != NULL, qi);
185+ break;
186++ case ANQP_NEIGHBOR_REPORT:
187++ set_anqp_req(ANQP_REQ_NEIGHBOR_REPORT,
188++ "Neighbor Report",
189++ get_anqp_elem(hapd, info_id) != NULL, qi);
190++ break;
191+ default:
192+ #ifdef CONFIG_FILS
193+ if (info_id == ANQP_FILS_REALM_INFO &&
194+diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
195+index 1528af4..d0241f2 100644
196+--- a/src/ap/gas_serv.h
197++++ b/src/ap/gas_serv.h
198+@@ -40,6 +40,8 @@
199+ (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
200+ #define ANQP_REQ_EMERGENCY_NAI \
201+ (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
202++#define ANQP_REQ_NEIGHBOR_REPORT \
203++ (1 << (ANQP_NEIGHBOR_REPORT - ANQP_QUERY_LIST))
204+ /*
205+ * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
206+ * optimized bitmap.
207+--
208+2.18.0
209+
210diff --git a/package/network/services/hostapd/patches/903-master-sync-include-uapi-linux-nl80211.patch b/package/network/services/hostapd/patches/903-master-sync-include-uapi-linux-nl80211.patch
211new file mode 100644
212index 0000000..fe47b57
213--- /dev/null
214+++ b/package/network/services/hostapd/patches/903-master-sync-include-uapi-linux-nl80211.patch
215@@ -0,0 +1,57 @@
216+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
217+index f962c06..f7be755 100644
218+--- a/src/drivers/nl80211_copy.h
219++++ b/src/drivers/nl80211_copy.h
220+@@ -2560,6 +2560,19 @@ enum nl80211_commands {
221+ * disassoc events to indicate that an immediate reconnect to the AP
222+ * is desired.
223+ *
224++ * @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the
225++ * %NL80211_CMD_OBSS_COLOR_COLLISION event.
226++ *
227++ * @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's
228++ * until the color switch event.
229++ * @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are
230++ * switching to
231++ * @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
232++ * information for the time while performing a color switch.
233++ *
234++ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
235++ * transmit power to stay within regulatory limits. u32, dBi.
236++ *
237+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
238+ * @NL80211_ATTR_MAX: highest attribute number currently defined
239+ * @__NL80211_ATTR_AFTER_LAST: internal use
240+@@ -3057,6 +3070,14 @@ enum nl80211_attrs {
241+
242+ NL80211_ATTR_DISABLE_HE,
243+
244++ NL80211_ATTR_OBSS_COLOR_BITMAP,
245++
246++ NL80211_ATTR_COLOR_CHANGE_COUNT,
247++ NL80211_ATTR_COLOR_CHANGE_COLOR,
248++ NL80211_ATTR_COLOR_CHANGE_ELEMS,
249++
250++ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
251++
252+ /* add attributes here, update the policy in nl80211.c */
253+
254+ __NL80211_ATTR_AFTER_LAST,
255+@@ -5950,6 +5971,9 @@ enum nl80211_feature_flags {
256+ * frame protection for all management frames exchanged during the
257+ * negotiation and range measurement procedure.
258+ *
259++ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
260++ * detection and change announcemnts.
261++ *
262+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
263+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
264+ */
265+@@ -6014,6 +6038,7 @@ enum nl80211_ext_feature_index {
266+ NL80211_EXT_FEATURE_SECURE_LTF,
267+ NL80211_EXT_FEATURE_SECURE_RTT,
268+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
269++ NL80211_EXT_FEATURE_BSS_COLOR,
270+
271+ /* add new features before the definition below */
272+ NUM_NL80211_EXT_FEATURES,
273diff --git a/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch b/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch
274new file mode 100644
275index 0000000..504c738
276--- /dev/null
277+++ b/package/network/services/hostapd/patches/904-master-Support-including-neignbor-report-elements-in-BTM-re.patch
278@@ -0,0 +1,68 @@
279+From 67e43b33cc70e63e6eabf571ac2c134a5e25b665 Mon Sep 17 00:00:00 2001
280+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
281+Date: Wed, 19 Jan 2022 19:49:09 +0800
282+Subject: [PATCH 3/9] Support including neignbor report elements in BTM
283+ response
284+
285+---
286+ src/ap/wnm_ap.c | 25 +++++++++++++++++++++++--
287+ 1 file changed, 23 insertions(+), 2 deletions(-)
288+
289+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
290+index 2f66a54..e37ddd0 100644
291+--- a/src/ap/wnm_ap.c
292++++ b/src/ap/wnm_ap.c
293+@@ -20,6 +20,7 @@
294+ #include "ap/wpa_auth.h"
295+ #include "mbo_ap.h"
296+ #include "wnm_ap.h"
297++#include "ap/neighbor_db.h"
298+
299+ #define MAX_TFS_IE_LEN 1024
300+
301+@@ -370,9 +371,21 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
302+ u8 *pos;
303+ int res;
304+
305+- mgmt = os_zalloc(sizeof(*mgmt));
306+- if (mgmt == NULL)
307++ int nr_num = hostapd_neighbor_count(hapd);
308++ int nr_size = ETH_ALEN + 4 + 1 + 1 + 1 + 5;
309++ int total_nr_size = nr_num * nr_size;
310++ u8 *nr_data = os_malloc(total_nr_size);
311++ int nr_data_len = 0;
312++ if(nr_data == NULL) {
313++ wpa_printf (MSG_ERROR, "Failed to allocate memory");
314++ } else {
315++ nr_data_len = hostapd_neighbor_insert_buffer(hapd, nr_data, total_nr_size);
316++ }
317++ mgmt = os_zalloc(sizeof(*mgmt) + nr_data_len);
318++ if (mgmt == NULL) {
319++ wpa_printf (MSG_ERROR, "Failed to allocate memory for mgmt frame");
320+ return -1;
321++ }
322+ os_memcpy(mgmt->da, addr, ETH_ALEN);
323+ os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
324+ os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
325+@@ -382,10 +395,18 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
326+ mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
327+ mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
328+ mgmt->u.action.u.bss_tm_req.req_mode = 0;
329++ if(nr_num) {
330++ mgmt->u.action.u.bss_tm_req.req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
331++ }
332+ mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
333+ mgmt->u.action.u.bss_tm_req.validity_interval = 1;
334+ pos = mgmt->u.action.u.bss_tm_req.variable;
335+
336++ if(nr_num) {
337++ os_memcpy(pos, nr_data, nr_data_len);
338++ pos += nr_data_len;
339++ }
340++
341+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
342+ wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
343+ MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
344+--
345+2.18.0
346+
347diff --git a/package/network/services/hostapd/patches/904-master-zero-wait_dfs.patch b/package/network/services/hostapd/patches/904-master-zero-wait_dfs.patch
348new file mode 100644
349index 0000000..cb11aee
350--- /dev/null
351+++ b/package/network/services/hostapd/patches/904-master-zero-wait_dfs.patch
352@@ -0,0 +1,851 @@
353+diff --git a/hostapd/config_file.c b/hostapd/config_file.c
354+index 1e1b685..8f6281a 100644
355+--- a/hostapd/config_file.c
356++++ b/hostapd/config_file.c
357+@@ -2476,6 +2476,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
358+ conf->ieee80211d = atoi(pos);
359+ } else if (os_strcmp(buf, "ieee80211h") == 0) {
360+ conf->ieee80211h = atoi(pos);
361++ } else if (os_strcmp(buf, "radar_offchan") == 0) {
362++ conf->radar_offchan = atoi(pos);
363+ } else if (os_strcmp(buf, "ieee8021x") == 0) {
364+ bss->ieee802_1x = atoi(pos);
365+ } else if (os_strcmp(buf, "eapol_version") == 0) {
366+diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
367+index a89ce9b..0c951a9 100644
368+--- a/hostapd/hostapd.conf
369++++ b/hostapd/hostapd.conf
370+@@ -143,6 +143,13 @@ ssid=test
371+ # ieee80211d=1 and local_pwr_constraint configured.
372+ #spectrum_mgmt_required=1
373+
374++# Enable radar/CAC detection through a dedicated offchannel chain available on
375++# some hw. The chain can't be used to transmits or receives frames.
376++# This feature allows to avoid CAC downtime switching on a different channel
377++# during CAC detection on the selected radar channel.
378++# (default: 0 = disabled, 1 = enabled)
379++#radar_offchan=0
380++
381+ # Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
382+ # g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
383+ # with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
384+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
385+index 28b7efe..ffc3c2c 100644
386+--- a/src/ap/ap_config.h
387++++ b/src/ap/ap_config.h
388+@@ -993,6 +993,7 @@ struct hostapd_config {
389+ int ieee80211d;
390+
391+ int ieee80211h; /* DFS */
392++ int radar_offchan;
393+
394+ /*
395+ * Local power constraint is an octet encoded as an unsigned integer in
396+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
397+index bc49079..c97ee39 100644
398+--- a/src/ap/ap_drv_ops.c
399++++ b/src/ap/ap_drv_ops.c
400+@@ -810,7 +810,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
401+ int channel, int ht_enabled, int vht_enabled,
402+ int he_enabled,
403+ int sec_channel_offset, int oper_chwidth,
404+- int center_segment0, int center_segment1)
405++ int center_segment0, int center_segment1,
406++ int radar_offchan)
407+ {
408+ struct hostapd_data *hapd = iface->bss[0];
409+ struct hostapd_freq_params data;
410+@@ -836,10 +837,14 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
411+ wpa_printf(MSG_ERROR, "Can't set freq params");
412+ return -1;
413+ }
414++ data.radar_offchan = radar_offchan;
415+
416+ res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
417+ if (!res) {
418+- iface->cac_started = 1;
419++ if (radar_offchan)
420++ iface->radar_offchan.cac_started = 1;
421++ else
422++ iface->cac_started = 1;
423+ os_get_reltime(&iface->dfs_cac_start);
424+ }
425+
426+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
427+index 61c8f64..92842a1 100644
428+--- a/src/ap/ap_drv_ops.h
429++++ b/src/ap/ap_drv_ops.h
430+@@ -130,7 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
431+ int channel, int ht_enabled, int vht_enabled,
432+ int he_enabled,
433+ int sec_channel_offset, int oper_chwidth,
434+- int center_segment0, int center_segment1);
435++ int center_segment0, int center_segment1,
436++ int radar_offchan);
437+ int hostapd_drv_do_acs(struct hostapd_data *hapd);
438+ int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
439+ u16 reason_code, const u8 *ie, size_t ielen);
440+diff --git a/src/ap/dfs.c b/src/ap/dfs.c
441+index eccda1a..3b1276f 100644
442+--- a/src/ap/dfs.c
443++++ b/src/ap/dfs.c
444+@@ -51,16 +51,31 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1)
445+ return n_chans;
446+ }
447+
448+-
449++/*
450++ * flags:
451++ * - 0: any channel
452++ * - 1: non-radar channel or radar available one
453++ * - 2: radar-only channel not yet available
454++ */
455+ static int dfs_channel_available(struct hostapd_channel_data *chan,
456+- int skip_radar)
457++ int flags)
458+ {
459++ if (flags == 2) {
460++ /* Select only radar channel where CAC has not been
461++ * performed yet
462++ */
463++ if ((chan->flag & HOSTAPD_CHAN_RADAR) &&
464++ (chan->flag & HOSTAPD_CHAN_DFS_MASK) ==
465++ HOSTAPD_CHAN_DFS_USABLE)
466++ return 1;
467++ return 0;
468++ }
469+ /*
470+ * When radar detection happens, CSA is performed. However, there's no
471+ * time for CAC, so radar channels must be skipped when finding a new
472+ * channel for CSA, unless they are available for immediate use.
473+ */
474+- if (skip_radar && (chan->flag & HOSTAPD_CHAN_RADAR) &&
475++ if (flags && (chan->flag & HOSTAPD_CHAN_RADAR) &&
476+ ((chan->flag & HOSTAPD_CHAN_DFS_MASK) !=
477+ HOSTAPD_CHAN_DFS_AVAILABLE))
478+ return 0;
479+@@ -136,10 +151,15 @@ dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
480+ return NULL;
481+ }
482+
483+-
484++/*
485++ * flags:
486++ * - 0: any channel
487++ * - 1: non-radar channel or radar available one
488++ * - 2: radar-only channel not yet available
489++ */
490+ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
491+ int first_chan_idx, int num_chans,
492+- int skip_radar)
493++ int flags)
494+ {
495+ struct hostapd_channel_data *first_chan, *chan;
496+ int i;
497+@@ -178,7 +198,7 @@ static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
498+ return 0;
499+ }
500+
501+- if (!dfs_channel_available(chan, skip_radar)) {
502++ if (!dfs_channel_available(chan, flags)) {
503+ wpa_printf(MSG_DEBUG, "DFS: channel not available %d",
504+ first_chan->freq + i * 20);
505+ return 0;
506+@@ -205,10 +225,15 @@ static int is_in_chanlist(struct hostapd_iface *iface,
507+ * - hapd->secondary_channel
508+ * - hapd->vht/he_oper_centr_freq_seg0_idx
509+ * - hapd->vht/he_oper_centr_freq_seg1_idx
510++ *
511++ * flags:
512++ * - 0: any channel
513++ * - 1: non-radar channel or radar available one
514++ * - 2: radar-only channel not yet available
515+ */
516+ static int dfs_find_channel(struct hostapd_iface *iface,
517+ struct hostapd_channel_data **ret_chan,
518+- int idx, int skip_radar)
519++ int idx, int flags)
520+ {
521+ struct hostapd_hw_modes *mode;
522+ struct hostapd_channel_data *chan;
523+@@ -233,7 +258,7 @@ static int dfs_find_channel(struct hostapd_iface *iface,
524+ }
525+
526+ /* Skip incompatible chandefs */
527+- if (!dfs_chan_range_available(mode, i, n_chans, skip_radar)) {
528++ if (!dfs_chan_range_available(mode, i, n_chans, flags)) {
529+ wpa_printf(MSG_DEBUG,
530+ "DFS: range not available for %d (%d)",
531+ chan->freq, chan->chan);
532+@@ -467,13 +492,18 @@ static int dfs_check_chans_unavailable(struct hostapd_iface *iface,
533+ return res;
534+ }
535+
536+-
537++/*
538++ * flags:
539++ * - 0: any channel
540++ * - 1: non-radar channel or radar available one
541++ * - 2: radar-only channel not yet available
542++ */
543+ static struct hostapd_channel_data *
544+ dfs_get_valid_channel(struct hostapd_iface *iface,
545+ int *secondary_channel,
546+ u8 *oper_centr_freq_seg0_idx,
547+ u8 *oper_centr_freq_seg1_idx,
548+- int skip_radar)
549++ int flags)
550+ {
551+ struct hostapd_hw_modes *mode;
552+ struct hostapd_channel_data *chan = NULL;
553+@@ -502,7 +532,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
554+ return NULL;
555+
556+ /* Get the count first */
557+- num_available_chandefs = dfs_find_channel(iface, NULL, 0, skip_radar);
558++ num_available_chandefs = dfs_find_channel(iface, NULL, 0, flags);
559+ wpa_printf(MSG_DEBUG, "DFS: num_available_chandefs=%d",
560+ num_available_chandefs);
561+ if (num_available_chandefs == 0)
562+@@ -523,7 +553,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
563+ return NULL;
564+
565+ chan_idx = _rand % num_available_chandefs;
566+- dfs_find_channel(iface, &chan, chan_idx, skip_radar);
567++ dfs_find_channel(iface, &chan, chan_idx, flags);
568+ if (!chan) {
569+ wpa_printf(MSG_DEBUG, "DFS: no random channel found");
570+ return NULL;
571+@@ -552,7 +582,7 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
572+ for (i = 0; i < num_available_chandefs - 1; i++) {
573+ /* start from chan_idx + 1, end when chan_idx - 1 */
574+ chan_idx2 = (chan_idx + 1 + i) % num_available_chandefs;
575+- dfs_find_channel(iface, &chan2, chan_idx2, skip_radar);
576++ dfs_find_channel(iface, &chan2, chan_idx2, flags);
577+ if (chan2 && abs(chan2->chan - chan->chan) > 12) {
578+ /* two channels are not adjacent */
579+ sec_chan_idx_80p80 = chan2->chan;
580+@@ -582,6 +612,27 @@ dfs_get_valid_channel(struct hostapd_iface *iface,
581+ return chan;
582+ }
583+
584++static int dfs_set_valid_channel(struct hostapd_iface *iface, int skip_radar)
585++{
586++ struct hostapd_channel_data *channel;
587++ u8 cf1 = 0, cf2 = 0;
588++ int sec = 0;
589++
590++ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
591++ skip_radar);
592++ if (!channel) {
593++ wpa_printf(MSG_ERROR, "could not get valid channel");
594++ return -1;
595++ }
596++
597++ iface->freq = channel->freq;
598++ iface->conf->channel = channel->chan;
599++ iface->conf->secondary_channel = sec;
600++ hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
601++ hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
602++
603++ return 0;
604++}
605+
606+ static int set_dfs_state_freq(struct hostapd_iface *iface, int freq, u32 state)
607+ {
608+@@ -761,6 +812,11 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
609+ return cac_time_ms;
610+ }
611+
612++static int hostapd_is_radar_offchan_enabled(struct hostapd_iface *iface)
613++{
614++ return (iface->drv_flags2 & WPA_DRIVER_RADAR_OFFCHAN) &&
615++ iface->conf->radar_offchan;
616++}
617+
618+ /*
619+ * Main DFS handler
620+@@ -770,9 +826,8 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface,
621+ */
622+ int hostapd_handle_dfs(struct hostapd_iface *iface)
623+ {
624+- struct hostapd_channel_data *channel;
625+ int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
626+- int skip_radar = 0;
627++ int skip_radar = 0, radar_offchan;
628+
629+ if (is_6ghz_freq(iface->freq))
630+ return 1;
631+@@ -825,28 +880,18 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
632+ wpa_printf(MSG_DEBUG, "DFS %d chans unavailable - choose other channel: %s",
633+ res, res ? "yes": "no");
634+ if (res) {
635+- int sec = 0;
636+- u8 cf1 = 0, cf2 = 0;
637+-
638+- channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2,
639+- skip_radar);
640+- if (!channel) {
641+- wpa_printf(MSG_ERROR, "could not get valid channel");
642++ if (dfs_set_valid_channel(iface, skip_radar) < 0) {
643+ hostapd_set_state(iface, HAPD_IFACE_DFS);
644+ return 0;
645+ }
646+-
647+- iface->freq = channel->freq;
648+- iface->conf->channel = channel->chan;
649+- iface->conf->secondary_channel = sec;
650+- hostapd_set_oper_centr_freq_seg0_idx(iface->conf, cf1);
651+- hostapd_set_oper_centr_freq_seg1_idx(iface->conf, cf2);
652+ }
653+ } while (res);
654+
655+ /* Finally start CAC */
656+ hostapd_set_state(iface, HAPD_IFACE_DFS);
657+- wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq);
658++ radar_offchan = hostapd_is_radar_offchan_enabled(iface);
659++ wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz offchan %d",
660++ iface->freq, radar_offchan);
661+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
662+ "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds",
663+ iface->freq,
664+@@ -863,13 +908,37 @@ int hostapd_handle_dfs(struct hostapd_iface *iface)
665+ iface->conf->secondary_channel,
666+ hostapd_get_oper_chwidth(iface->conf),
667+ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
668+- hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
669++ hostapd_get_oper_centr_freq_seg1_idx(iface->conf),
670++ radar_offchan);
671+
672+ if (res) {
673+ wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res);
674+ return -1;
675+ }
676+
677++ if (radar_offchan) {
678++ /* Cache offchannel radar parameters */
679++ iface->radar_offchan.channel = iface->conf->channel;
680++ iface->radar_offchan.secondary_channel =
681++ iface->conf->secondary_channel;
682++ iface->radar_offchan.freq = iface->freq;
683++ iface->radar_offchan.centr_freq_seg0_idx =
684++ hostapd_get_oper_centr_freq_seg0_idx(iface->conf);
685++ iface->radar_offchan.centr_freq_seg1_idx =
686++ hostapd_get_oper_centr_freq_seg1_idx(iface->conf);
687++
688++ /*
689++ * Let's select a random channel for the moment
690++ * and perform CAC on dedicated radar chain
691++ */
692++ res = dfs_set_valid_channel(iface, 1);
693++ if (res < 0)
694++ return res;
695++
696++ iface->radar_offchan.temp_ch = 1;
697++ return 1;
698++ }
699++
700+ return 0;
701+ }
702+
703+@@ -890,6 +959,157 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface)
704+ return dfs_check_chans_available(iface, start_chan_idx, n_chans);
705+ }
706+
707++static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface,
708++ int channel, int freq,
709++ int secondary_channel,
710++ u8 oper_centr_freq_seg0_idx,
711++ u8 oper_centr_freq_seg1_idx)
712++{
713++ struct hostapd_hw_modes *cmode = iface->current_mode;
714++ int ieee80211_mode = IEEE80211_MODE_AP, err, i;
715++ struct csa_settings csa_settings;
716++ u8 new_vht_oper_chwidth;
717++
718++ wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel);
719++ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
720++ "freq=%d chan=%d sec_chan=%d", freq, channel,
721++ secondary_channel);
722++
723++ new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
724++ hostapd_set_oper_chwidth(iface->conf,
725++ hostapd_get_oper_chwidth(iface->conf));
726++
727++ /* Setup CSA request */
728++ os_memset(&csa_settings, 0, sizeof(csa_settings));
729++ csa_settings.cs_count = 5;
730++ csa_settings.block_tx = 1;
731++#ifdef CONFIG_MESH
732++ if (iface->mconf)
733++ ieee80211_mode = IEEE80211_MODE_MESH;
734++#endif /* CONFIG_MESH */
735++ err = hostapd_set_freq_params(&csa_settings.freq_params,
736++ iface->conf->hw_mode,
737++ freq, channel,
738++ iface->conf->enable_edmg,
739++ iface->conf->edmg_channel,
740++ iface->conf->ieee80211n,
741++ iface->conf->ieee80211ac,
742++ iface->conf->ieee80211ax,
743++ secondary_channel,
744++ new_vht_oper_chwidth,
745++ oper_centr_freq_seg0_idx,
746++ oper_centr_freq_seg1_idx,
747++ cmode->vht_capab,
748++ &cmode->he_capab[ieee80211_mode]);
749++
750++ if (err) {
751++ wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
752++ hostapd_disable_iface(iface);
753++ return err;
754++ }
755++
756++ for (i = 0; i < iface->num_bss; i++) {
757++ err = hostapd_switch_channel(iface->bss[i], &csa_settings);
758++ if (err)
759++ break;
760++ }
761++
762++ if (err) {
763++ wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
764++ err);
765++ iface->freq = freq;
766++ iface->conf->channel = channel;
767++ iface->conf->secondary_channel = secondary_channel;
768++ hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
769++ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
770++ oper_centr_freq_seg0_idx);
771++ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
772++ oper_centr_freq_seg1_idx);
773++
774++ hostapd_disable_iface(iface);
775++ hostapd_enable_iface(iface);
776++
777++ return 0;
778++ }
779++
780++ /* Channel configuration will be updated once CSA completes and
781++ * ch_switch_notify event is received */
782++ wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
783++
784++ return 0;
785++}
786++
787++static struct hostapd_channel_data *
788++dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel,
789++ u8 *oper_centr_freq_seg0_idx,
790++ u8 *oper_centr_freq_seg1_idx, int *skip_radar);
791++
792++static void
793++hostpad_dfs_update_offchannel_chain(struct hostapd_iface *iface)
794++{
795++ struct hostapd_channel_data *channel;
796++ int sec = 0, flags = 2;
797++ u8 cf1 = 0, cf2 = 0;
798++
799++ channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 2);
800++ if (!channel || channel->chan == iface->conf->channel)
801++ channel = dfs_downgrade_bandwidth(iface, &sec, &cf1, &cf2,
802++ &flags);
803++ if (!channel ||
804++ hostapd_start_dfs_cac(iface, iface->conf->hw_mode,
805++ channel->freq, channel->chan,
806++ iface->conf->ieee80211n,
807++ iface->conf->ieee80211ac,
808++ iface->conf->ieee80211ax,
809++ sec, hostapd_get_oper_chwidth(iface->conf),
810++ cf1, cf2, 1)) {
811++ /*
812++ * Toggle interface state to enter DFS state
813++ * until NOP is finished.
814++ */
815++ wpa_printf(MSG_ERROR, "DFS failed start CAC offchannel");
816++ return;
817++ }
818++
819++ wpa_printf(MSG_DEBUG, "%s: setting offchannel chain to chan %d (%d MHz)",
820++ __func__, channel->chan, channel->freq);
821++
822++ iface->radar_offchan.channel = channel->chan;
823++ iface->radar_offchan.freq = channel->freq;
824++ iface->radar_offchan.secondary_channel = sec;
825++ iface->radar_offchan.centr_freq_seg0_idx = cf1;
826++ iface->radar_offchan.centr_freq_seg1_idx = cf2;
827++}
828++
829++/* FIXME: check if all channel bandwith */
830++static int
831++hostapd_dfs_is_offchan_event(struct hostapd_iface *iface, int freq)
832++{
833++ if (iface->radar_offchan.freq != freq)
834++ return 0;
835++
836++ return 1;
837++}
838++
839++static int
840++hostapd_dfs_start_channel_switch_offchan(struct hostapd_iface *iface)
841++{
842++ iface->conf->channel = iface->radar_offchan.channel;
843++ iface->freq = iface->radar_offchan.freq;
844++ iface->conf->secondary_channel =
845++ iface->radar_offchan.secondary_channel;
846++ hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
847++ iface->radar_offchan.centr_freq_seg0_idx);
848++ hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
849++ iface->radar_offchan.centr_freq_seg1_idx);
850++
851++ hostpad_dfs_update_offchannel_chain(iface);
852++
853++ return hostapd_dfs_request_channel_switch(iface, iface->conf->channel,
854++ iface->freq, iface->conf->secondary_channel,
855++ hostapd_get_oper_centr_freq_seg0_idx(iface->conf),
856++ hostapd_get_oper_centr_freq_seg1_idx(iface->conf));
857++}
858+
859+ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
860+ int ht_enabled, int chan_offset, int chan_width,
861+@@ -911,6 +1131,23 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
862+ set_dfs_state(iface, freq, ht_enabled, chan_offset,
863+ chan_width, cf1, cf2,
864+ HOSTAPD_CHAN_DFS_AVAILABLE);
865++
866++ /*
867++ * radar event from offchannel chain for selected
868++ * channel. Perfrom CSA, move main chain to selected
869++ * channel and configure offchannel chain to a new DFS
870++ * channel
871++ */
872++ if (hostapd_is_radar_offchan_enabled(iface) &&
873++ hostapd_dfs_is_offchan_event(iface, freq)) {
874++ iface->radar_offchan.cac_started = 0;
875++ if (iface->radar_offchan.temp_ch) {
876++ iface->radar_offchan.temp_ch = 0;
877++ return hostapd_dfs_start_channel_switch_offchan(iface);
878++ }
879++ return 0;
880++ }
881++
882+ /*
883+ * Just mark the channel available when CAC completion
884+ * event is received in enabled state. CAC result could
885+@@ -927,6 +1164,10 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq,
886+ iface->cac_started = 0;
887+ }
888+ }
889++ } else if (hostapd_is_radar_offchan_enabled(iface) &&
890++ hostapd_dfs_is_offchan_event(iface, freq)) {
891++ iface->radar_offchan.cac_started = 0;
892++ hostpad_dfs_update_offchannel_chain(iface);
893+ }
894+
895+ return 0;
896+@@ -1036,6 +1277,44 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface)
897+ return err;
898+ }
899+
900++static int
901++hostapd_dfs_offchan_start_channel_switch(struct hostapd_iface *iface, int freq)
902++{
903++ if (!hostapd_is_radar_offchan_enabled(iface))
904++ return -1; /* Offchannel chain not supported */
905++
906++ wpa_printf(MSG_DEBUG,
907++ "%s called (offchannel CAC active: %s, CSA active: %s)",
908++ __func__, iface->radar_offchan.cac_started ? "yes" : "no",
909++ hostapd_csa_in_progress(iface) ? "yes" : "no");
910++
911++ /* Check if CSA in progress */
912++ if (hostapd_csa_in_progress(iface))
913++ return 0;
914++
915++ /*
916++ * If offchannel radar detation is supported and radar channel
917++ * monitored by offchain is available switch to it without waiting
918++ * for the CAC otherwise let's keep a random channel.
919++ * If radar pattern is reported on offchannel chain, just switch to
920++ * monitor another radar channel.
921++ */
922++ if (hostapd_dfs_is_offchan_event(iface, freq)) {
923++ hostpad_dfs_update_offchannel_chain(iface);
924++ return 0;
925++ }
926++
927++ /* Offchannel not availanle yet. Perform CAC on main chain */
928++ if (iface->radar_offchan.cac_started) {
929++ /* We want to switch to monitored channel as soon as
930++ * CAC is completed.
931++ */
932++ iface->radar_offchan.temp_ch = 1;
933++ return -1;
934++ }
935++
936++ return hostapd_dfs_start_channel_switch_offchan(iface);
937++}
938+
939+ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
940+ {
941+@@ -1043,13 +1322,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
942+ int secondary_channel;
943+ u8 oper_centr_freq_seg0_idx;
944+ u8 oper_centr_freq_seg1_idx;
945+- u8 new_vht_oper_chwidth;
946+ int skip_radar = 1;
947+- struct csa_settings csa_settings;
948+- unsigned int i;
949+- int err = 1;
950+- struct hostapd_hw_modes *cmode = iface->current_mode;
951+- u8 current_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
952+ int ieee80211_mode = IEEE80211_MODE_AP;
953+
954+ wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)",
955+@@ -1113,73 +1386,16 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
956+ }
957+ }
958+
959+- wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d",
960+- channel->chan);
961+- wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL
962+- "freq=%d chan=%d sec_chan=%d", channel->freq,
963+- channel->chan, secondary_channel);
964+-
965+- new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf);
966+- hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth);
967+-
968+- /* Setup CSA request */
969+- os_memset(&csa_settings, 0, sizeof(csa_settings));
970+- csa_settings.cs_count = 5;
971+- csa_settings.block_tx = 1;
972+ #ifdef CONFIG_MESH
973+ if (iface->mconf)
974+ ieee80211_mode = IEEE80211_MODE_MESH;
975+ #endif /* CONFIG_MESH */
976+- err = hostapd_set_freq_params(&csa_settings.freq_params,
977+- iface->conf->hw_mode,
978+- channel->freq,
979+- channel->chan,
980+- iface->conf->enable_edmg,
981+- iface->conf->edmg_channel,
982+- iface->conf->ieee80211n,
983+- iface->conf->ieee80211ac,
984+- iface->conf->ieee80211ax,
985+- secondary_channel,
986+- new_vht_oper_chwidth,
987+- oper_centr_freq_seg0_idx,
988+- oper_centr_freq_seg1_idx,
989+- cmode->vht_capab,
990+- &cmode->he_capab[ieee80211_mode]);
991+-
992+- if (err) {
993+- wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params");
994+- hostapd_disable_iface(iface);
995+- return err;
996+- }
997+
998+- for (i = 0; i < iface->num_bss; i++) {
999+- err = hostapd_switch_channel(iface->bss[i], &csa_settings);
1000+- if (err)
1001+- break;
1002+- }
1003+-
1004+- if (err) {
1005+- wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback",
1006+- err);
1007+- iface->freq = channel->freq;
1008+- iface->conf->channel = channel->chan;
1009+- iface->conf->secondary_channel = secondary_channel;
1010+- hostapd_set_oper_chwidth(iface->conf, new_vht_oper_chwidth);
1011+- hostapd_set_oper_centr_freq_seg0_idx(iface->conf,
1012+- oper_centr_freq_seg0_idx);
1013+- hostapd_set_oper_centr_freq_seg1_idx(iface->conf,
1014+- oper_centr_freq_seg1_idx);
1015+-
1016+- hostapd_disable_iface(iface);
1017+- hostapd_enable_iface(iface);
1018+- return 0;
1019+- }
1020+-
1021+- /* Channel configuration will be updated once CSA completes and
1022+- * ch_switch_notify event is received */
1023+-
1024+- wpa_printf(MSG_DEBUG, "DFS waiting channel switch event");
1025+- return 0;
1026++ return hostapd_dfs_request_channel_switch(iface, channel->chan,
1027++ channel->freq,
1028++ secondary_channel,
1029++ oper_centr_freq_seg0_idx,
1030++ oper_centr_freq_seg1_idx);
1031+ }
1032+
1033+
1034+@@ -1208,15 +1424,19 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq,
1035+ if (!res)
1036+ return 0;
1037+
1038+- /* Skip if reported radar event not overlapped our channels */
1039+- res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2);
1040+- if (!res)
1041+- return 0;
1042++ if (!hostapd_dfs_is_offchan_event(iface, freq)) {
1043++ /* Skip if reported radar event not overlapped our channels */
1044++ res = dfs_are_channels_overlapped(iface, freq, chan_width,
1045++ cf1, cf2);
1046++ if (!res)
1047++ return 0;
1048++ }
1049+
1050+- /* radar detected while operating, switch the channel. */
1051+- res = hostapd_dfs_start_channel_switch(iface);
1052++ if (hostapd_dfs_offchan_start_channel_switch(iface, freq))
1053++ /* radar detected while operating, switch the channel. */
1054++ return hostapd_dfs_start_channel_switch(iface);
1055+
1056+- return res;
1057++ return 0;
1058+ }
1059+
1060+
1061+@@ -1284,7 +1504,11 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
1062+ "seg1=%d cac_time=%ds",
1063+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2,
1064+ iface->dfs_cac_ms / 1000);
1065+- iface->cac_started = 1;
1066++
1067++ if (hostapd_dfs_is_offchan_event(iface, freq))
1068++ iface->radar_offchan.cac_started = 1;
1069++ else
1070++ iface->cac_started = 1;
1071+ os_get_reltime(&iface->dfs_cac_start);
1072+ return 0;
1073+ }
1074+diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
1075+index 27b985d..1c6c94e 100644
1076+--- a/src/ap/hostapd.h
1077++++ b/src/ap/hostapd.h
1078+@@ -521,6 +521,21 @@ struct hostapd_iface {
1079+ int *basic_rates;
1080+ int freq;
1081+
1082++ /* Offchanel chain configuration */
1083++ struct {
1084++ int channel;
1085++ int secondary_channel;
1086++ int freq;
1087++ int centr_freq_seg0_idx;
1088++ int centr_freq_seg1_idx;
1089++ /* Main chain is on temporary channel during
1090++ * CAC detection on radar offchain
1091++ */
1092++ unsigned int temp_ch:1;
1093++ /* CAC started on radar offchain */
1094++ unsigned int cac_started:1;
1095++ } radar_offchan;
1096++
1097+ u16 hw_flags;
1098+
1099+ /* Number of associated Non-ERP stations (i.e., stations using 802.11b
1100+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
1101+index 6d9194f..7ed47c0 100644
1102+--- a/src/drivers/driver.h
1103++++ b/src/drivers/driver.h
1104+@@ -777,6 +777,11 @@ struct hostapd_freq_params {
1105+ * for IEEE 802.11ay EDMG configuration.
1106+ */
1107+ struct ieee80211_edmg_config edmg;
1108++
1109++ /**
1110++ * radar_offchan - Whether radar/CAC offchannel is requested
1111++ */
1112++ int radar_offchan;
1113+ };
1114+
1115+ /**
1116+@@ -2026,6 +2031,8 @@ struct wpa_driver_capa {
1117+ #define WPA_DRIVER_FLAGS2_OCV 0x0000000000000080ULL
1118+ /** Driver expects user space implementation of SME in AP mode */
1119+ #define WPA_DRIVER_FLAGS2_AP_SME 0x0000000000000100ULL
1120++/** Driver supports offchannel radar/CAC detection */
1121++#define WPA_DRIVER_RADAR_OFFCHAN 0x0000000000000200ULL
1122+ u64 flags2;
1123+
1124+ #define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
1125+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
1126+index 4db8cce..62c3cd8 100644
1127+--- a/src/drivers/driver_nl80211.c
1128++++ b/src/drivers/driver_nl80211.c
1129+@@ -4885,6 +4885,7 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
1130+ wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled);
1131+ wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled);
1132+ wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled);
1133++ wpa_printf(MSG_DEBUG, " * radar_offchan=%d", freq->radar_offchan);
1134+
1135+ hw_mode = ieee80211_freq_to_chan(freq->freq, &channel);
1136+ is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G ||
1137+@@ -4962,6 +4963,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
1138+ NL80211_CHAN_NO_HT))
1139+ return -ENOBUFS;
1140+ }
1141++ if (freq->radar_offchan)
1142++ nla_put_flag(msg, NL80211_ATTR_RADAR_OFFCHAN);
1143++
1144+ return 0;
1145+ }
1146+
1147+diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
1148+index cd596e3..e370ef3 100644
1149+--- a/src/drivers/driver_nl80211_capa.c
1150++++ b/src/drivers/driver_nl80211_capa.c
1151+@@ -665,6 +665,10 @@ static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
1152+ if (ext_feature_isset(ext_features, len,
1153+ NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION))
1154+ capa->flags2 |= WPA_DRIVER_FLAGS2_OCV;
1155++
1156++ if (ext_feature_isset(ext_features, len,
1157++ NL80211_EXT_FEATURE_RADAR_OFFCHAN))
1158++ capa->flags2 |= WPA_DRIVER_RADAR_OFFCHAN;
1159+ }
1160+
1161+
1162+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
1163+index f7be755..736b483 100644
1164+--- a/src/drivers/nl80211_copy.h
1165++++ b/src/drivers/nl80211_copy.h
1166+@@ -2573,6 +2573,10 @@ enum nl80211_commands {
1167+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
1168+ * transmit power to stay within regulatory limits. u32, dBi.
1169+ *
1170++ * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated chain available for radar
1171++ * detection on some hw. The chain can't be used to transmits or receives
1172++ * frames. The driver is supposed to implement CAC management in sw or fw.
1173++ *
1174+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
1175+ * @NL80211_ATTR_MAX: highest attribute number currently defined
1176+ * @__NL80211_ATTR_AFTER_LAST: internal use
1177+@@ -3078,6 +3082,8 @@ enum nl80211_attrs {
1178+
1179+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
1180+
1181++ NL80211_ATTR_RADAR_OFFCHAN,
1182++
1183+ /* add attributes here, update the policy in nl80211.c */
1184+
1185+ __NL80211_ATTR_AFTER_LAST,
1186+@@ -5974,6 +5980,9 @@ enum nl80211_feature_flags {
1187+ * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
1188+ * detection and change announcemnts.
1189+ *
1190++ * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC
1191++ * detection.
1192++ *
1193+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
1194+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
1195+ */
1196+@@ -6039,6 +6048,7 @@ enum nl80211_ext_feature_index {
1197+ NL80211_EXT_FEATURE_SECURE_RTT,
1198+ NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
1199+ NL80211_EXT_FEATURE_BSS_COLOR,
1200++ NL80211_EXT_FEATURE_RADAR_OFFCHAN,
1201+
1202+ /* add new features before the definition below */
1203+ NUM_NL80211_EXT_FEATURES,
1204diff --git a/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch b/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch
1205new file mode 100644
1206index 0000000..2f9b174
1207--- /dev/null
1208+++ b/package/network/services/hostapd/patches/905-master-Support-configuring-BSS-Termination-TSF-by-using-hos.patch
1209@@ -0,0 +1,66 @@
1210+From b97cdd75ea3f0c15a6d76cd6483941ee73fa400c Mon Sep 17 00:00:00 2001
1211+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1212+Date: Wed, 19 Jan 2022 20:20:03 +0800
1213+Subject: [PATCH 4/9] Support configuring BSS Termination TSF by using
1214+ hostapd_cli command
1215+
1216+---
1217+ hostapd/ctrl_iface.c | 9 +++++++++
1218+ src/ap/ap_config.c | 1 +
1219+ src/ap/ap_config.h | 1 +
1220+ 3 files changed, 11 insertions(+)
1221+
1222+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
1223+index 568232a..cb2bdbf 100644
1224+--- a/hostapd/ctrl_iface.c
1225++++ b/hostapd/ctrl_iface.c
1226+@@ -954,6 +954,10 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1227+ wpa_printf(MSG_DEBUG, "Invalid bss_term data");
1228+ return -1;
1229+ }
1230++ if (hapd->conf->bss_termination_tsf) {
1231++ WPA_PUT_LE64(&bss_term_dur[2], hapd->conf->bss_termination_tsf);
1232++ }
1233++
1234+ end++;
1235+ WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
1236+ }
1237+@@ -1589,6 +1593,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
1238+ #endif /* CONFIG_DPP */
1239+ } else if (os_strcasecmp(cmd, "setband") == 0) {
1240+ ret = hostapd_ctrl_iface_set_band(hapd, value);
1241++ } else if (os_strcasecmp(cmd, "bss_termination_tsf") == 0) {
1242++ int termination_sec = atoi(value);
1243++ hapd->conf->bss_termination_tsf = termination_sec;
1244++ wpa_printf(MSG_DEBUG, "BSS Termination TSF: value = %d",
1245++ termination_sec);
1246+ } else {
1247+ ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
1248+ if (ret)
1249+diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
1250+index ce281ac..fc1372a 100644
1251+--- a/src/ap/ap_config.c
1252++++ b/src/ap/ap_config.c
1253+@@ -170,6 +170,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
1254+ /* comeback after 10 TUs */
1255+ bss->pasn_comeback_after = 10;
1256+ #endif /* CONFIG_PASN */
1257++ bss->bss_termination_tsf = 0;
1258+ }
1259+
1260+
1261+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
1262+index ffc3c2c..1f3f3d8 100644
1263+--- a/src/ap/ap_config.h
1264++++ b/src/ap/ap_config.h
1265+@@ -549,6 +549,7 @@ struct hostapd_bss_config {
1266+ int wnm_sleep_mode;
1267+ int wnm_sleep_mode_no_keys;
1268+ int bss_transition;
1269++ unsigned int bss_termination_tsf;
1270+
1271+ /* IEEE 802.11u - Interworking */
1272+ int interworking;
1273+--
1274+2.18.0
1275+
1276diff --git a/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch b/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch
1277new file mode 100644
1278index 0000000..18b44fa
1279--- /dev/null
1280+++ b/package/network/services/hostapd/patches/906-master-Disable-interface-if-BSS-Termination-TSF-is-set.patch
1281@@ -0,0 +1,47 @@
1282+From d084074baaa8f9df15810323aeeeba0e98b0dbd5 Mon Sep 17 00:00:00 2001
1283+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1284+Date: Wed, 19 Jan 2022 21:03:38 +0800
1285+Subject: [PATCH 5/9] Disable interface if BSS Termination TSF is set
1286+
1287+---
1288+ src/ap/wnm_ap.c | 17 +++++++++++++++++
1289+ 1 file changed, 17 insertions(+)
1290+
1291+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
1292+index e37ddd0..ce7aca2 100644
1293+--- a/src/ap/wnm_ap.c
1294++++ b/src/ap/wnm_ap.c
1295+@@ -767,6 +767,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
1296+ }
1297+
1298+
1299++void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
1300++{
1301++ struct hostapd_data *hapd = eloop_ctx;
1302++ hostapd_disable_iface(hapd->iface);
1303++}
1304++
1305++
1306++static void set_disable_iface_timer(struct hostapd_data *hapd, struct sta_info *sta,
1307++ int disable_iface_timer)
1308++{
1309++ wpa_printf(MSG_DEBUG, "Disable interface timer set to %d secs", disable_iface_timer);
1310++ eloop_register_timeout(disable_iface_timer, 0,
1311++ bss_termination_disable_iface, hapd, NULL);
1312++}
1313++
1314++
1315+ int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
1316+ struct sta_info *sta, const char *url,
1317+ int disassoc_timer)
1318+@@ -855,6 +871,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
1319+ bss_term_dur) {
1320+ os_memcpy(pos, bss_term_dur, 12);
1321+ pos += 12;
1322++ set_disable_iface_timer(hapd, sta, hapd->conf->bss_termination_tsf);
1323+ }
1324+
1325+ if (url) {
1326+--
1327+2.18.0
1328+
1329diff --git a/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch b/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch
1330new file mode 100644
1331index 0000000..8839c25
1332--- /dev/null
1333+++ b/package/network/services/hostapd/patches/907-master-Add-set_send_disassoc_frame_timer-to-send-disassocia.patch
1334@@ -0,0 +1,63 @@
1335+From 1f4ff04758932b773df99a51055373f7610046ce Mon Sep 17 00:00:00 2001
1336+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1337+Date: Wed, 19 Jan 2022 21:15:07 +0800
1338+Subject: [PATCH 6/9] Add set_send_disassoc_frame_timer() to send disassociate
1339+ frame
1340+
1341+Function set_disassoc_timer() may fail if key was deleted first. This new
1342+function will not ask to delete key as set_disassoc_timer() did.
1343+---
1344+ src/ap/wnm_ap.c | 30 +++++++++++++++++++++++++++++-
1345+ 1 file changed, 29 insertions(+), 1 deletion(-)
1346+
1347+diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
1348+index ce7aca2..2ee9fb7 100644
1349+--- a/src/ap/wnm_ap.c
1350++++ b/src/ap/wnm_ap.c
1351+@@ -767,6 +767,34 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
1352+ }
1353+
1354+
1355++static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta,
1356++ int disassoc_timer)
1357++{
1358++ int timeout, beacon_int;
1359++
1360++ /*
1361++ * Prevent STA from reconnecting using cached PMKSA to force
1362++ * full authentication with the authentication server (which may
1363++ * decide to reject the connection),
1364++ */
1365++ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
1366++
1367++ beacon_int = hapd->iconf->beacon_int;
1368++ if (beacon_int < 1)
1369++ beacon_int = 100; /* best guess */
1370++ /* Calculate timeout in ms based on beacon_int in TU */
1371++ timeout = disassoc_timer * beacon_int * 128 / 125;
1372++ wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
1373++ " set to %d ms", MAC2STR(sta->addr), timeout);
1374++
1375++ u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
1376++
1377++ hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
1378++ if (sta)
1379++ ap_sta_disassociate(hapd, sta, reason);
1380++}
1381++
1382++
1383+ void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
1384+ {
1385+ struct hostapd_data *hapd = eloop_ctx;
1386+@@ -908,7 +936,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
1387+ hapd->openwrt_stats.wnm.bss_transition_request_tx++;
1388+ if (disassoc_timer) {
1389+ /* send disassociation frame after time-out */
1390+- set_disassoc_timer(hapd, sta, disassoc_timer);
1391++ set_send_disassoc_frame_timer(hapd, sta, disassoc_timer);
1392+ }
1393+
1394+ return 0;
1395+--
1396+2.18.0
1397+
1398diff --git a/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch b/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch
1399new file mode 100644
1400index 0000000..dd6a859
1401--- /dev/null
1402+++ b/package/network/services/hostapd/patches/908-master-Support-including-neighbor-report-elements-in-BTM-re.patch
1403@@ -0,0 +1,31 @@
1404+From f0b8ae8248f026c31e19a9c04423013a720f6136 Mon Sep 17 00:00:00 2001
1405+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1406+Date: Wed, 19 Jan 2022 21:16:45 +0800
1407+Subject: [PATCH 7/9] Support including neighbor report elements in BTM request
1408+
1409+---
1410+ hostapd/ctrl_iface.c | 7 ++++++-
1411+ 1 file changed, 6 insertions(+), 1 deletion(-)
1412+
1413+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
1414+index cb2bdbf..2c5cf4b 100644
1415+--- a/hostapd/ctrl_iface.c
1416++++ b/hostapd/ctrl_iface.c
1417+@@ -984,8 +984,13 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1418+ req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
1419+ }
1420+
1421+- if (os_strstr(cmd, " pref=1"))
1422++ if (os_strstr(cmd, " pref=1")) {
1423+ req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
1424++ if (nei_len == 0) {
1425++ // Add neigibor report from neighbor report db to nei_rep buffer
1426++ nei_len = hostapd_neighbor_insert_buffer (hapd, nei_rep, 1000);
1427++ }
1428++ }
1429+ if (os_strstr(cmd, " abridged=1"))
1430+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1431+ if (os_strstr(cmd, " disassoc_imminent=1"))
1432+--
1433+2.18.0
1434+
1435diff --git a/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch b/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch
1436new file mode 100644
1437index 0000000..4e233d4
1438--- /dev/null
1439+++ b/package/network/services/hostapd/patches/909-master-Add-hostapd_neighbor_set_own_report_pref.patch
1440@@ -0,0 +1,88 @@
1441+From de5785cfdbc90d789a9b20e160b7311a2a3841e9 Mon Sep 17 00:00:00 2001
1442+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1443+Date: Wed, 19 Jan 2022 21:27:55 +0800
1444+Subject: [PATCH 8/9] Add hostapd_neighbor_set_own_report_pref()
1445+
1446+If my own BSS is going to terminate itself, the preference value of neighbor
1447+report must be set to 0.
1448+---
1449+ hostapd/ctrl_iface.c | 5 ++++-
1450+ src/ap/neighbor_db.c | 36 ++++++++++++++++++++++++++++++++++++
1451+ src/ap/neighbor_db.h | 2 ++
1452+ 3 files changed, 42 insertions(+), 1 deletion(-)
1453+
1454+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
1455+index 2c5cf4b..5be75e5 100644
1456+--- a/hostapd/ctrl_iface.c
1457++++ b/hostapd/ctrl_iface.c
1458+@@ -993,8 +993,11 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1459+ }
1460+ if (os_strstr(cmd, " abridged=1"))
1461+ req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
1462+- if (os_strstr(cmd, " disassoc_imminent=1"))
1463++ if (os_strstr(cmd, " disassoc_imminent=1")) {
1464+ req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
1465++ /* Set own BSS neighbor report preference value as 0 */
1466++ hostapd_neighbor_set_own_report_pref(hapd, nei_rep, nei_len, 0);
1467++ }
1468+
1469+ #ifdef CONFIG_MBO
1470+ pos = os_strstr(cmd, "mbo=");
1471+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
1472+index a47afd4..6473800 100644
1473+--- a/src/ap/neighbor_db.c
1474++++ b/src/ap/neighbor_db.c
1475+@@ -348,3 +348,39 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
1476+ wpabuf_free(nr);
1477+ #endif /* NEED_AP_MLME */
1478+ }
1479++
1480++
1481++void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
1482++ size_t buflen, const int pref)
1483++{
1484++ struct hostapd_neighbor_entry *nr;
1485++ char *pos, *next_nr;
1486++
1487++ pos = nei_buf;
1488++ next_nr = nei_buf;
1489++
1490++ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
1491++ list) {
1492++ pos = next_nr;
1493++ next_nr = pos + 2 + wpabuf_len(nr->nr);
1494++ /* Shift 2 bytes for Element ID and Neighbor report length */
1495++ pos = pos + 2;
1496++ if(os_memcmp(pos, hapd->own_addr, ETH_ALEN) == 0) {
1497++ /* Shift for BSSID + BSSID info + Op_class + channel num + PHY type */
1498++ pos = pos + 6 + 4 + 1 + 1 + 1;
1499++
1500++ /* Iterate Subelement */
1501++ while (next_nr - pos > 0) {
1502++ if (*pos == 3) {
1503++ pos = pos + 2;
1504++ *pos = pref;
1505++ return;
1506++ } else {
1507++ pos++;
1508++ int shift_len = *pos++;
1509++ pos = pos + shift_len;
1510++ }
1511++ }
1512++ }
1513++ }
1514++}
1515+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
1516+index e93d1d5..dc6807b 100644
1517+--- a/src/ap/neighbor_db.h
1518++++ b/src/ap/neighbor_db.h
1519+@@ -26,4 +26,6 @@ void hostapd_free_neighbor_db(struct hostapd_data *hapd);
1520+ int hostapd_neighbor_count(struct hostapd_data *hapd);
1521+ int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
1522+ size_t buflen);
1523++void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
1524++ size_t buflen, const int pref);
1525+ #endif /* NEIGHBOR_DB_H */
1526+--
1527+2.18.0
1528+
1529diff --git a/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch b/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch
1530new file mode 100644
1531index 0000000..b38b216
1532--- /dev/null
1533+++ b/package/network/services/hostapd/patches/910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch
1534@@ -0,0 +1,101 @@
1535+From 3306cdad16655901c1b76372fa939eae20ac8b26 Mon Sep 17 00:00:00 2001
1536+From: "howard.hsu" <howard-yh.hsu@mediatek.com>
1537+Date: Wed, 19 Jan 2022 21:32:17 +0800
1538+Subject: [PATCH 9/9] Add hostapd_neighbor_set_pref_by_non_pref_chan()
1539+
1540+The preference value of neighbor report shall be modified according to struct
1541+non_pref_chan_info.
1542+---
1543+ hostapd/ctrl_iface.c | 2 ++
1544+ src/ap/neighbor_db.c | 51 ++++++++++++++++++++++++++++++++++++++++++++
1545+ src/ap/neighbor_db.h | 4 ++++
1546+ 3 files changed, 57 insertions(+)
1547+
1548+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
1549+index 5be75e5..2e11e7b 100644
1550+--- a/hostapd/ctrl_iface.c
1551++++ b/hostapd/ctrl_iface.c
1552+@@ -999,6 +999,8 @@ static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
1553+ hostapd_neighbor_set_own_report_pref(hapd, nei_rep, nei_len, 0);
1554+ }
1555+
1556++ hostapd_neighbor_set_pref_by_non_pref_chan(hapd, sta, nei_rep, nei_len);
1557++
1558+ #ifdef CONFIG_MBO
1559+ pos = os_strstr(cmd, "mbo=");
1560+ if (pos) {
1561+diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
1562+index 6473800..254dc39 100644
1563+--- a/src/ap/neighbor_db.c
1564++++ b/src/ap/neighbor_db.c
1565+@@ -384,3 +384,54 @@ void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_b
1566+ }
1567+ }
1568+ }
1569++
1570++#ifdef CONFIG_MBO
1571++void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
1572++ struct sta_info* sta, char *nei_buf, size_t buflen)
1573++{
1574++ struct hostapd_neighbor_entry *nr;
1575++ struct mbo_non_pref_chan_info *info;
1576++ u8 i;
1577++
1578++ for(info = sta->non_pref_chan; info; info = info->next) {
1579++ /* Check OP_Class and Channel num */
1580++ for(i = 0; i < info->num_channels; i++) {
1581++ char *pos, *next_nr;
1582++
1583++ pos = nei_buf;
1584++ next_nr = nei_buf;
1585++
1586++ /* Iterate Neighbor report database */
1587++ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
1588++ list) {
1589++ pos = next_nr;
1590++ next_nr = pos + 2 + wpabuf_len(nr->nr);
1591++ /**
1592++ * Shift 12 bytes for Element ID, Neighbor report length,
1593++ * BSSID and BSSID info.
1594++ */
1595++ pos = pos + 12;
1596++ int nr_op_class = *pos++;
1597++ int nr_channel = *pos;
1598++ if(info->op_class == nr_op_class && info->channels[i] == nr_channel) {
1599++ /* Shift for Channel Num + PHY type */
1600++ pos = pos + 1 + 1;
1601++
1602++ // Iterate Subelement
1603++ while(next_nr - pos > 0) {
1604++ if(*pos == 3) {
1605++ pos = pos + 2;
1606++ *pos = info->pref;
1607++ break;
1608++ }else {
1609++ pos++;
1610++ int shift_len = *pos++;
1611++ pos = pos + shift_len;
1612++ }
1613++ }
1614++ }
1615++ }
1616++ }
1617++ }
1618++}
1619++#endif
1620+diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
1621+index dc6807b..731d1b8 100644
1622+--- a/src/ap/neighbor_db.h
1623++++ b/src/ap/neighbor_db.h
1624+@@ -28,4 +28,8 @@ int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
1625+ size_t buflen);
1626+ void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
1627+ size_t buflen, const int pref);
1628++#ifdef CONFIG_MBO
1629++void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
1630++ struct sta_info* sta, char *nei_buf, size_t buflen);
1631++#endif
1632+ #endif /* NEIGHBOR_DB_H */
1633+--
1634+2.18.0
1635+
1636--
16372.18.0
1638