blob: 4fa2dfb3fe0cfdea59ac5baf8ba6fa233127ff1f [file] [log] [blame]
developer4cc8f192023-08-01 20:47:35 +08001From bfca3c43597bf827e4d5faec91ac8f420d33c921 Mon Sep 17 00:00:00 2001
developer683be522023-05-11 14:24:50 +08002From: "howard.hsu" <howard-yh.hsu@mediatek.com>
3Date: Wed, 19 Jan 2022 19:18:07 +0800
developer4cc8f192023-08-01 20:47:35 +08004Subject: [PATCH] hostapd: mtk: Add neighbor report and BSS Termination for MBO
5 certification
developer683be522023-05-11 14:24:50 +08006
71. Add hostapd_neighbor_count() and hostapd_neighbor_insert_buffer ()
8The first function can count the number of neighbor report in neighbore report
9database. The second can iterate neighbor report database to build up neighbor
10report data.
11
122. Support including neighbor report elements in ANQP response
133. Support including neignbor report elements in BTM response
144. Support configuring BSS Termination TSF by using hostapd_cli command
155. Disable interface if BSS Termination TSF is set
developer4cc8f192023-08-01 20:47:35 +0800166. Support including neighbor report elements in BTM request
177. Add hostapd_neighbor_set_own_report_pref()
188. Add hostapd_neighbor_set_pref_by_non_pref_chan()
19
20Revert set_send_disassoc_frame_timer
developer683be522023-05-11 14:24:50 +080021---
22 hostapd/ctrl_iface.c | 5 ++
23 src/ap/ap_config.c | 1 +
24 src/ap/ap_config.h | 1 +
25 src/ap/ctrl_iface_ap.c | 19 ++++++-
26 src/ap/gas_serv.c | 29 ++++++++++
27 src/ap/gas_serv.h | 2 +
28 src/ap/neighbor_db.c | 119 +++++++++++++++++++++++++++++++++++++++++
29 src/ap/neighbor_db.h | 9 ++++
developer4cc8f192023-08-01 20:47:35 +080030 src/ap/wnm_ap.c | 42 ++++++++++++++-
31 9 files changed, 223 insertions(+), 4 deletions(-)
developer683be522023-05-11 14:24:50 +080032
33diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
developer4cc8f192023-08-01 20:47:35 +080034index 55711ab..fab1287 100644
developer683be522023-05-11 14:24:50 +080035--- a/hostapd/ctrl_iface.c
36+++ b/hostapd/ctrl_iface.c
37@@ -1347,6 +1347,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
38 #endif /* CONFIG_DPP */
39 } else if (os_strcasecmp(cmd, "setband") == 0) {
40 ret = hostapd_ctrl_iface_set_band(hapd, value);
41+ } else if (os_strcasecmp(cmd, "bss_termination_tsf") == 0) {
42+ int termination_sec = atoi(value);
43+ hapd->conf->bss_termination_tsf = termination_sec;
44+ wpa_printf(MSG_DEBUG, "BSS Termination TSF: value = %d",
45+ termination_sec);
46 } else {
47 ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
48 if (ret)
49diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
developer4cc8f192023-08-01 20:47:35 +080050index 41c7070..7d0de12 100644
developer683be522023-05-11 14:24:50 +080051--- a/src/ap/ap_config.c
52+++ b/src/ap/ap_config.c
developer27057f82023-07-10 17:23:13 +080053@@ -171,6 +171,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
developer683be522023-05-11 14:24:50 +080054 bss->pasn_comeback_after = 10;
developer27057f82023-07-10 17:23:13 +080055 bss->pasn_noauth = 1;
developer683be522023-05-11 14:24:50 +080056 #endif /* CONFIG_PASN */
57+ bss->bss_termination_tsf = 0;
58 }
59
60
61diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
developer4cc8f192023-08-01 20:47:35 +080062index 02fd494..dc60252 100644
developer683be522023-05-11 14:24:50 +080063--- a/src/ap/ap_config.h
64+++ b/src/ap/ap_config.h
65@@ -558,6 +558,7 @@ struct hostapd_bss_config {
66 int wnm_sleep_mode;
67 int wnm_sleep_mode_no_keys;
68 int bss_transition;
69+ unsigned int bss_termination_tsf;
70
71 /* IEEE 802.11u - Interworking */
72 int interworking;
73diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
developer4cc8f192023-08-01 20:47:35 +080074index 50a4dc4..cf1cff4 100644
developer683be522023-05-11 14:24:50 +080075--- a/src/ap/ctrl_iface_ap.c
76+++ b/src/ap/ctrl_iface_ap.c
developer27057f82023-07-10 17:23:13 +080077@@ -1280,6 +1280,10 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
developer683be522023-05-11 14:24:50 +080078 wpa_printf(MSG_DEBUG, "Invalid bss_term data");
79 return -1;
80 }
81+ if (hapd->conf->bss_termination_tsf) {
82+ WPA_PUT_LE64(&bss_term_dur[2], hapd->conf->bss_termination_tsf);
83+ }
84+
85 end++;
86 WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
87 }
developer27057f82023-07-10 17:23:13 +080088@@ -1306,14 +1310,25 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
developer683be522023-05-11 14:24:50 +080089 req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
90 }
91
92- if (os_strstr(cmd, " pref=1"))
93+ if (os_strstr(cmd, " pref=1")) {
94 req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
95+ if (nei_len == 0) {
96+ // Add neigibor report from neighbor report db to nei_rep buffer
97+ nei_len = hostapd_neighbor_insert_buffer (hapd, nei_rep, 1000);
98+ }
99+ }
100 if (os_strstr(cmd, " abridged=1"))
101 req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
102- if (os_strstr(cmd, " disassoc_imminent=1"))
103+ if (os_strstr(cmd, " disassoc_imminent=1")) {
104 req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
105+ /* Set own BSS neighbor report preference value as 0 */
106+ hostapd_neighbor_set_own_report_pref(hapd, nei_rep, nei_len, 0);
107+ }
108+
109
110 #ifdef CONFIG_MBO
111+ hostapd_neighbor_set_pref_by_non_pref_chan(hapd, sta, nei_rep, nei_len);
112+
113 pos = os_strstr(cmd, "mbo=");
114 if (pos) {
115 unsigned int mbo_reason, cell_pref, reassoc_delay;
116diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
developer4cc8f192023-08-01 20:47:35 +0800117index 4642e49..cce6df4 100644
developer683be522023-05-11 14:24:50 +0800118--- a/src/ap/gas_serv.c
119+++ b/src/ap/gas_serv.c
120@@ -19,6 +19,7 @@
121 #include "dpp_hostapd.h"
122 #include "sta_info.h"
123 #include "gas_serv.h"
124+#include "neighbor_db.h"
125
126
127 #ifdef CONFIG_DPP
128@@ -369,6 +370,24 @@ static void anqp_add_network_auth_type(struct hostapd_data *hapd,
129 }
130 }
131
132+static void anqp_add_neighbor_report(struct hostapd_data *hapd,
133+ struct wpabuf *buf)
134+{
135+ struct hostapd_neighbor_entry *nr;
136+ u8 *len_pos = gas_anqp_add_element(buf, ANQP_NEIGHBOR_REPORT);
137+ if (dl_list_empty(&hapd->nr_db)) {
138+ wpabuf_put_le16(buf, 0);
139+ }
140+ else {
141+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list ) {
142+ wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT);
143+ wpabuf_put_u8(buf, wpabuf_len(nr->nr));
144+ wpabuf_put_buf(buf, nr->nr);
145+ }
146+ }
147+ gas_anqp_set_element_len(buf, len_pos);
148+}
149+
150
151 static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
152 struct wpabuf *buf)
153@@ -986,6 +1005,9 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
154 len += 1000;
155 if (request & ANQP_REQ_ICON_REQUEST)
156 len += 65536;
157+ if (request & ANQP_REQ_NEIGHBOR_REPORT) {
158+ len += (40 * hostapd_neighbor_count(hapd));
159+ }
160 #ifdef CONFIG_FILS
161 if (request & ANQP_FILS_REALM_INFO)
162 len += 2 * dl_list_len(&hapd->conf->fils_realms);
163@@ -1028,6 +1050,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
164 anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY);
165 if (request & ANQP_REQ_EMERGENCY_NAI)
166 anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI);
167+ if (request & ANQP_REQ_NEIGHBOR_REPORT)
168+ anqp_add_neighbor_report(hapd, buf);
169
170 for (i = 0; i < num_extra_req; i++) {
171 #ifdef CONFIG_FILS
172@@ -1172,6 +1196,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
173 "Emergency NAI",
174 get_anqp_elem(hapd, info_id) != NULL, qi);
175 break;
176+ case ANQP_NEIGHBOR_REPORT:
177+ set_anqp_req(ANQP_REQ_NEIGHBOR_REPORT,
178+ "Neighbor Report",
179+ get_anqp_elem(hapd, info_id) != NULL, qi);
180+ break;
181 default:
182 #ifdef CONFIG_FILS
183 if (info_id == ANQP_FILS_REALM_INFO &&
184diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h
developer4cc8f192023-08-01 20:47:35 +0800185index 7646a98..ce492b5 100644
developer683be522023-05-11 14:24:50 +0800186--- a/src/ap/gas_serv.h
187+++ b/src/ap/gas_serv.h
188@@ -40,6 +40,8 @@
189 (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST))
190 #define ANQP_REQ_EMERGENCY_NAI \
191 (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST))
192+#define ANQP_REQ_NEIGHBOR_REPORT \
193+ (1 << (ANQP_NEIGHBOR_REPORT - ANQP_QUERY_LIST))
194 /*
195 * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the
196 * optimized bitmap.
197diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c
developer4cc8f192023-08-01 20:47:35 +0800198index 5b276e8..1c14b32 100644
developer683be522023-05-11 14:24:50 +0800199--- a/src/ap/neighbor_db.c
200+++ b/src/ap/neighbor_db.c
201@@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen)
202 }
203
204
205+int hostapd_neighbor_count(struct hostapd_data *hapd)
206+{
207+ struct hostapd_neighbor_entry *nr;
208+ int count = 0;
209+
210+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
211+ list) {
212+ count++;
213+ }
214+ return count;
215+}
216+
217+
218+int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
219+ size_t buflen)
220+{
221+ struct hostapd_neighbor_entry *nr;
222+ char *pos = buf;
223+
224+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
225+ list) {
226+ /* For neighbor report IE, we only need bssid and nr*/
227+ *pos++ = WLAN_EID_NEIGHBOR_REPORT;
228+ *pos++ = wpabuf_len(nr->nr);
229+ os_memcpy(pos, wpabuf_head(nr->nr), wpabuf_len(nr->nr));
230+ pos += wpabuf_len(nr->nr);
231+ }
232+
233+ return pos - buf;
234+}
235+
236+
237 static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr)
238 {
239 wpabuf_free(nr->nr);
240@@ -325,3 +357,90 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd)
241 wpabuf_free(nr);
242 #endif /* NEED_AP_MLME */
243 }
244+
245+
246+void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
247+ size_t buflen, const int pref)
248+{
249+ struct hostapd_neighbor_entry *nr;
250+ char *pos, *next_nr;
251+
252+ pos = nei_buf;
253+ next_nr = nei_buf;
254+
255+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
256+ list) {
257+ pos = next_nr;
258+ next_nr = pos + 2 + wpabuf_len(nr->nr);
259+ /* Shift 2 bytes for Element ID and Neighbor report length */
260+ pos = pos + 2;
261+ if(os_memcmp(pos, hapd->own_addr, ETH_ALEN) == 0) {
262+ /* Shift for BSSID + BSSID info + Op_class + channel num + PHY type */
263+ pos = pos + 6 + 4 + 1 + 1 + 1;
264+
265+ /* Iterate Subelement */
266+ while (next_nr - pos > 0) {
267+ if (*pos == 3) {
268+ pos = pos + 2;
269+ *pos = pref;
270+ return;
271+ } else {
272+ pos++;
273+ int shift_len = *pos++;
274+ pos = pos + shift_len;
275+ }
276+ }
277+ }
278+ }
279+}
280+
281+#ifdef CONFIG_MBO
282+void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
283+ struct sta_info* sta, char *nei_buf, size_t buflen)
284+{
285+ struct hostapd_neighbor_entry *nr;
286+ struct mbo_non_pref_chan_info *info;
287+ u8 i;
288+
289+ for(info = sta->non_pref_chan; info; info = info->next) {
290+ /* Check OP_Class and Channel num */
291+ for(i = 0; i < info->num_channels; i++) {
292+ char *pos, *next_nr;
293+
294+ pos = nei_buf;
295+ next_nr = nei_buf;
296+
297+ /* Iterate Neighbor report database */
298+ dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
299+ list) {
300+ pos = next_nr;
301+ next_nr = pos + 2 + wpabuf_len(nr->nr);
302+ /**
303+ * Shift 12 bytes for Element ID, Neighbor report length,
304+ * BSSID and BSSID info.
305+ */
306+ pos = pos + 12;
307+ int nr_op_class = *pos++;
308+ int nr_channel = *pos;
309+ if(info->op_class == nr_op_class && info->channels[i] == nr_channel) {
310+ /* Shift for Channel Num + PHY type */
311+ pos = pos + 1 + 1;
312+
313+ // Iterate Subelement
314+ while(next_nr - pos > 0) {
315+ if(*pos == 3) {
316+ pos = pos + 2;
317+ *pos = info->pref;
318+ break;
319+ }else {
320+ pos++;
321+ int shift_len = *pos++;
322+ pos = pos + shift_len;
323+ }
324+ }
325+ }
326+ }
327+ }
328+ }
329+}
330+#endif
331diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h
developer4cc8f192023-08-01 20:47:35 +0800332index 992671b..a1ddc07 100644
developer683be522023-05-11 14:24:50 +0800333--- a/src/ap/neighbor_db.h
334+++ b/src/ap/neighbor_db.h
335@@ -24,4 +24,13 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid,
336 const struct wpa_ssid_value *ssid);
337 void hostapd_free_neighbor_db(struct hostapd_data *hapd);
338
339+int hostapd_neighbor_count(struct hostapd_data *hapd);
340+int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf,
341+ size_t buflen);
342+void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf,
343+ size_t buflen, const int pref);
344+#ifdef CONFIG_MBO
345+void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd,
346+ struct sta_info* sta, char *nei_buf, size_t buflen);
347+#endif
348 #endif /* NEIGHBOR_DB_H */
349diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
developer4cc8f192023-08-01 20:47:35 +0800350index ba1dd2e..939d447 100644
developer683be522023-05-11 14:24:50 +0800351--- a/src/ap/wnm_ap.c
352+++ b/src/ap/wnm_ap.c
353@@ -20,6 +20,7 @@
354 #include "ap/wpa_auth.h"
355 #include "mbo_ap.h"
356 #include "wnm_ap.h"
357+#include "ap/neighbor_db.h"
358
359 #define MAX_TFS_IE_LEN 1024
360
361@@ -370,9 +371,21 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
362 u8 *pos;
363 int res;
364
365- mgmt = os_zalloc(sizeof(*mgmt));
366- if (mgmt == NULL)
367+ int nr_num = hostapd_neighbor_count(hapd);
368+ int nr_size = ETH_ALEN + 4 + 1 + 1 + 1 + 5;
369+ int total_nr_size = nr_num * nr_size;
370+ u8 *nr_data = os_malloc(total_nr_size);
371+ int nr_data_len = 0;
372+ if(nr_data == NULL) {
373+ wpa_printf (MSG_ERROR, "Failed to allocate memory");
374+ } else {
375+ nr_data_len = hostapd_neighbor_insert_buffer(hapd, nr_data, total_nr_size);
376+ }
377+ mgmt = os_zalloc(sizeof(*mgmt) + nr_data_len);
378+ if (mgmt == NULL) {
379+ wpa_printf (MSG_ERROR, "Failed to allocate memory for mgmt frame");
380 return -1;
381+ }
382 os_memcpy(mgmt->da, addr, ETH_ALEN);
383 os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
384 os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
385@@ -382,10 +395,18 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd,
386 mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
387 mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token;
388 mgmt->u.action.u.bss_tm_req.req_mode = 0;
389+ if(nr_num) {
390+ mgmt->u.action.u.bss_tm_req.req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
391+ }
392 mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
393 mgmt->u.action.u.bss_tm_req.validity_interval = 1;
394 pos = mgmt->u.action.u.bss_tm_req.variable;
395
396+ if(nr_num) {
397+ os_memcpy(pos, nr_data, nr_data_len);
398+ pos += nr_data_len;
399+ }
400+
401 hapd->openwrt_stats.wnm.bss_transition_request_tx++;
402 wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
403 MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u "
developer4cc8f192023-08-01 20:47:35 +0800404@@ -890,6 +911,22 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
developer683be522023-05-11 14:24:50 +0800405 }
406
407
developer683be522023-05-11 14:24:50 +0800408+void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx)
409+{
410+ struct hostapd_data *hapd = eloop_ctx;
411+ hostapd_disable_iface(hapd->iface);
412+}
413+
414+
415+static void set_disable_iface_timer(struct hostapd_data *hapd, struct sta_info *sta,
416+ int disable_iface_timer)
417+{
418+ wpa_printf(MSG_DEBUG, "Disable interface timer set to %d secs", disable_iface_timer);
419+ eloop_register_timeout(disable_iface_timer, 0,
420+ bss_termination_disable_iface, hapd, NULL);
421+}
422+
423+
424 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
425 struct sta_info *sta, const char *url,
426 int disassoc_timer)
developer4cc8f192023-08-01 20:47:35 +0800427@@ -979,6 +1016,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
developer683be522023-05-11 14:24:50 +0800428 bss_term_dur) {
429 os_memcpy(pos, bss_term_dur, 12);
430 pos += 12;
431+ set_disable_iface_timer(hapd, sta, hapd->conf->bss_termination_tsf);
432 }
433
434 if (url) {
435--
developer4cc8f192023-08-01 20:47:35 +08004362.18.0
developer683be522023-05-11 14:24:50 +0800437