developer | 77ffbda | 2022-12-16 04:36:08 +0800 | [diff] [blame] | 1 | From 4791a374c9861b0d90db7fbdefe509f4e7d12247 Mon Sep 17 00:00:00 2001 |
developer | a09ec1d | 2022-11-26 11:00:33 +0800 | [diff] [blame] | 2 | From: "howard.hsu" <howard-yh.hsu@mediatek.com> |
| 3 | Date: Wed, 19 Jan 2022 19:18:07 +0800 |
developer | 77ffbda | 2022-12-16 04:36:08 +0800 | [diff] [blame] | 4 | Subject: [PATCH 99900/99910] hostapd: mtk: Add neighbor report and BSS |
developer | a09ec1d | 2022-11-26 11:00:33 +0800 | [diff] [blame] | 5 | Termination for MBO certification |
| 6 | |
| 7 | 1. Add hostapd_neighbor_count() and hostapd_neighbor_insert_buffer () |
| 8 | The first function can count the number of neighbor report in neighbore report |
| 9 | database. The second can iterate neighbor report database to build up neighbor |
| 10 | report data. |
| 11 | |
| 12 | 2. Support including neighbor report elements in ANQP response |
| 13 | 3. Support including neignbor report elements in BTM response |
| 14 | 4. Support configuring BSS Termination TSF by using hostapd_cli command |
| 15 | 5. Disable interface if BSS Termination TSF is set |
| 16 | 6. Add set_send_disassoc_frame_timer() to send disassociate frame |
| 17 | Function set_disassoc_timer() may fail if key was deleted first. This new |
| 18 | function will not ask to delete key as set_disassoc_timer() did. |
| 19 | 7. Support including neighbor report elements in BTM request |
| 20 | 8. Add hostapd_neighbor_set_own_report_pref() |
| 21 | 9. Add hostapd_neighbor_set_pref_by_non_pref_chan() |
| 22 | --- |
| 23 | hostapd/ctrl_iface.c | 5 ++ |
| 24 | src/ap/ap_config.c | 1 + |
| 25 | src/ap/ap_config.h | 1 + |
| 26 | src/ap/ctrl_iface_ap.c | 19 ++++++- |
| 27 | src/ap/gas_serv.c | 29 ++++++++++ |
| 28 | src/ap/gas_serv.h | 2 + |
| 29 | src/ap/neighbor_db.c | 119 +++++++++++++++++++++++++++++++++++++++++ |
| 30 | src/ap/neighbor_db.h | 9 ++++ |
| 31 | src/ap/wnm_ap.c | 72 +++++++++++++++++++++++-- |
| 32 | 9 files changed, 252 insertions(+), 5 deletions(-) |
| 33 | |
| 34 | diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c |
| 35 | index a258492..c2a2822 100644 |
| 36 | --- a/hostapd/ctrl_iface.c |
| 37 | +++ b/hostapd/ctrl_iface.c |
| 38 | @@ -1338,6 +1338,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd) |
| 39 | #endif /* CONFIG_DPP */ |
| 40 | } else if (os_strcasecmp(cmd, "setband") == 0) { |
| 41 | ret = hostapd_ctrl_iface_set_band(hapd, value); |
| 42 | + } else if (os_strcasecmp(cmd, "bss_termination_tsf") == 0) { |
| 43 | + int termination_sec = atoi(value); |
| 44 | + hapd->conf->bss_termination_tsf = termination_sec; |
| 45 | + wpa_printf(MSG_DEBUG, "BSS Termination TSF: value = %d", |
| 46 | + termination_sec); |
| 47 | } else { |
| 48 | ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value); |
| 49 | if (ret) |
| 50 | diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c |
| 51 | index d7a0c7c..4a20eb4 100644 |
| 52 | --- a/src/ap/ap_config.c |
| 53 | +++ b/src/ap/ap_config.c |
| 54 | @@ -170,6 +170,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) |
| 55 | /* comeback after 10 TUs */ |
| 56 | bss->pasn_comeback_after = 10; |
| 57 | #endif /* CONFIG_PASN */ |
| 58 | + bss->bss_termination_tsf = 0; |
| 59 | } |
| 60 | |
| 61 | |
| 62 | diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h |
| 63 | index ed3bec7..3f68e76 100644 |
| 64 | --- a/src/ap/ap_config.h |
| 65 | +++ b/src/ap/ap_config.h |
| 66 | @@ -557,6 +557,7 @@ struct hostapd_bss_config { |
| 67 | int wnm_sleep_mode; |
| 68 | int wnm_sleep_mode_no_keys; |
| 69 | int bss_transition; |
| 70 | + unsigned int bss_termination_tsf; |
| 71 | |
| 72 | /* IEEE 802.11u - Interworking */ |
| 73 | int interworking; |
| 74 | diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c |
| 75 | index 96209ce..18bae5c 100644 |
| 76 | --- a/src/ap/ctrl_iface_ap.c |
| 77 | +++ b/src/ap/ctrl_iface_ap.c |
| 78 | @@ -1203,6 +1203,10 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, |
| 79 | wpa_printf(MSG_DEBUG, "Invalid bss_term data"); |
| 80 | return -1; |
| 81 | } |
| 82 | + if (hapd->conf->bss_termination_tsf) { |
| 83 | + WPA_PUT_LE64(&bss_term_dur[2], hapd->conf->bss_termination_tsf); |
| 84 | + } |
| 85 | + |
| 86 | end++; |
| 87 | WPA_PUT_LE16(&bss_term_dur[10], atoi(end)); |
| 88 | } |
| 89 | @@ -1229,14 +1233,25 @@ int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd, |
| 90 | req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT; |
| 91 | } |
| 92 | |
| 93 | - if (os_strstr(cmd, " pref=1")) |
| 94 | + if (os_strstr(cmd, " pref=1")) { |
| 95 | req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; |
| 96 | + if (nei_len == 0) { |
| 97 | + // Add neigibor report from neighbor report db to nei_rep buffer |
| 98 | + nei_len = hostapd_neighbor_insert_buffer (hapd, nei_rep, 1000); |
| 99 | + } |
| 100 | + } |
| 101 | if (os_strstr(cmd, " abridged=1")) |
| 102 | req_mode |= WNM_BSS_TM_REQ_ABRIDGED; |
| 103 | - if (os_strstr(cmd, " disassoc_imminent=1")) |
| 104 | + if (os_strstr(cmd, " disassoc_imminent=1")) { |
| 105 | req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT; |
| 106 | + /* Set own BSS neighbor report preference value as 0 */ |
| 107 | + hostapd_neighbor_set_own_report_pref(hapd, nei_rep, nei_len, 0); |
| 108 | + } |
| 109 | + |
| 110 | |
| 111 | #ifdef CONFIG_MBO |
| 112 | + hostapd_neighbor_set_pref_by_non_pref_chan(hapd, sta, nei_rep, nei_len); |
| 113 | + |
| 114 | pos = os_strstr(cmd, "mbo="); |
| 115 | if (pos) { |
| 116 | unsigned int mbo_reason, cell_pref, reassoc_delay; |
| 117 | diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c |
| 118 | index 90f1577..5845ff8 100644 |
| 119 | --- a/src/ap/gas_serv.c |
| 120 | +++ b/src/ap/gas_serv.c |
| 121 | @@ -19,6 +19,7 @@ |
| 122 | #include "dpp_hostapd.h" |
| 123 | #include "sta_info.h" |
| 124 | #include "gas_serv.h" |
| 125 | +#include "neighbor_db.h" |
| 126 | |
| 127 | |
| 128 | #ifdef CONFIG_DPP |
| 129 | @@ -369,6 +370,24 @@ static void anqp_add_network_auth_type(struct hostapd_data *hapd, |
| 130 | } |
| 131 | } |
| 132 | |
| 133 | +static void anqp_add_neighbor_report(struct hostapd_data *hapd, |
| 134 | + struct wpabuf *buf) |
| 135 | +{ |
| 136 | + struct hostapd_neighbor_entry *nr; |
| 137 | + u8 *len_pos = gas_anqp_add_element(buf, ANQP_NEIGHBOR_REPORT); |
| 138 | + if (dl_list_empty(&hapd->nr_db)) { |
| 139 | + wpabuf_put_le16(buf, 0); |
| 140 | + } |
| 141 | + else { |
| 142 | + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, list ) { |
| 143 | + wpabuf_put_u8(buf, WLAN_EID_NEIGHBOR_REPORT); |
| 144 | + wpabuf_put_u8(buf, wpabuf_len(nr->nr)); |
| 145 | + wpabuf_put_buf(buf, nr->nr); |
| 146 | + } |
| 147 | + } |
| 148 | + gas_anqp_set_element_len(buf, len_pos); |
| 149 | +} |
| 150 | + |
| 151 | |
| 152 | static void anqp_add_roaming_consortium(struct hostapd_data *hapd, |
| 153 | struct wpabuf *buf) |
| 154 | @@ -986,6 +1005,9 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, |
| 155 | len += 1000; |
| 156 | if (request & ANQP_REQ_ICON_REQUEST) |
| 157 | len += 65536; |
| 158 | + if (request & ANQP_REQ_NEIGHBOR_REPORT) { |
| 159 | + len += (40 * hostapd_neighbor_count(hapd)); |
| 160 | + } |
| 161 | #ifdef CONFIG_FILS |
| 162 | if (request & ANQP_FILS_REALM_INFO) |
| 163 | len += 2 * dl_list_len(&hapd->conf->fils_realms); |
| 164 | @@ -1028,6 +1050,8 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, |
| 165 | anqp_add_elem(hapd, buf, ANQP_TDLS_CAPABILITY); |
| 166 | if (request & ANQP_REQ_EMERGENCY_NAI) |
| 167 | anqp_add_elem(hapd, buf, ANQP_EMERGENCY_NAI); |
| 168 | + if (request & ANQP_REQ_NEIGHBOR_REPORT) |
| 169 | + anqp_add_neighbor_report(hapd, buf); |
| 170 | |
| 171 | for (i = 0; i < num_extra_req; i++) { |
| 172 | #ifdef CONFIG_FILS |
| 173 | @@ -1172,6 +1196,11 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, |
| 174 | "Emergency NAI", |
| 175 | get_anqp_elem(hapd, info_id) != NULL, qi); |
| 176 | break; |
| 177 | + case ANQP_NEIGHBOR_REPORT: |
| 178 | + set_anqp_req(ANQP_REQ_NEIGHBOR_REPORT, |
| 179 | + "Neighbor Report", |
| 180 | + get_anqp_elem(hapd, info_id) != NULL, qi); |
| 181 | + break; |
| 182 | default: |
| 183 | #ifdef CONFIG_FILS |
| 184 | if (info_id == ANQP_FILS_REALM_INFO && |
| 185 | diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h |
| 186 | index 1528af4..d0241f2 100644 |
| 187 | --- a/src/ap/gas_serv.h |
| 188 | +++ b/src/ap/gas_serv.h |
| 189 | @@ -40,6 +40,8 @@ |
| 190 | (1 << (ANQP_TDLS_CAPABILITY - ANQP_QUERY_LIST)) |
| 191 | #define ANQP_REQ_EMERGENCY_NAI \ |
| 192 | (1 << (ANQP_EMERGENCY_NAI - ANQP_QUERY_LIST)) |
| 193 | +#define ANQP_REQ_NEIGHBOR_REPORT \ |
| 194 | + (1 << (ANQP_NEIGHBOR_REPORT - ANQP_QUERY_LIST)) |
| 195 | /* |
| 196 | * First 15 Hotspot 2.0 vendor specific ANQP-elements can be included in the |
| 197 | * optimized bitmap. |
| 198 | diff --git a/src/ap/neighbor_db.c b/src/ap/neighbor_db.c |
| 199 | index 52f25eb..9254d09 100644 |
| 200 | --- a/src/ap/neighbor_db.c |
| 201 | +++ b/src/ap/neighbor_db.c |
| 202 | @@ -89,6 +89,38 @@ int hostapd_neighbor_show(struct hostapd_data *hapd, char *buf, size_t buflen) |
| 203 | } |
| 204 | |
| 205 | |
| 206 | +int hostapd_neighbor_count(struct hostapd_data *hapd) |
| 207 | +{ |
| 208 | + struct hostapd_neighbor_entry *nr; |
| 209 | + int count = 0; |
| 210 | + |
| 211 | + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, |
| 212 | + list) { |
| 213 | + count++; |
| 214 | + } |
| 215 | + return count; |
| 216 | +} |
| 217 | + |
| 218 | + |
| 219 | +int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf, |
| 220 | + size_t buflen) |
| 221 | +{ |
| 222 | + struct hostapd_neighbor_entry *nr; |
| 223 | + char *pos = buf; |
| 224 | + |
| 225 | + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, |
| 226 | + list) { |
| 227 | + /* For neighbor report IE, we only need bssid and nr*/ |
| 228 | + *pos++ = WLAN_EID_NEIGHBOR_REPORT; |
| 229 | + *pos++ = wpabuf_len(nr->nr); |
| 230 | + os_memcpy(pos, wpabuf_head(nr->nr), wpabuf_len(nr->nr)); |
| 231 | + pos += wpabuf_len(nr->nr); |
| 232 | + } |
| 233 | + |
| 234 | + return pos - buf; |
| 235 | +} |
| 236 | + |
| 237 | + |
| 238 | static void hostapd_neighbor_clear_entry(struct hostapd_neighbor_entry *nr) |
| 239 | { |
| 240 | wpabuf_free(nr->nr); |
| 241 | @@ -325,3 +357,90 @@ void hostapd_neighbor_set_own_report(struct hostapd_data *hapd) |
| 242 | wpabuf_free(nr); |
| 243 | #endif /* NEED_AP_MLME */ |
| 244 | } |
| 245 | + |
| 246 | + |
| 247 | +void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf, |
| 248 | + size_t buflen, const int pref) |
| 249 | +{ |
| 250 | + struct hostapd_neighbor_entry *nr; |
| 251 | + char *pos, *next_nr; |
| 252 | + |
| 253 | + pos = nei_buf; |
| 254 | + next_nr = nei_buf; |
| 255 | + |
| 256 | + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, |
| 257 | + list) { |
| 258 | + pos = next_nr; |
| 259 | + next_nr = pos + 2 + wpabuf_len(nr->nr); |
| 260 | + /* Shift 2 bytes for Element ID and Neighbor report length */ |
| 261 | + pos = pos + 2; |
| 262 | + if(os_memcmp(pos, hapd->own_addr, ETH_ALEN) == 0) { |
| 263 | + /* Shift for BSSID + BSSID info + Op_class + channel num + PHY type */ |
| 264 | + pos = pos + 6 + 4 + 1 + 1 + 1; |
| 265 | + |
| 266 | + /* Iterate Subelement */ |
| 267 | + while (next_nr - pos > 0) { |
| 268 | + if (*pos == 3) { |
| 269 | + pos = pos + 2; |
| 270 | + *pos = pref; |
| 271 | + return; |
| 272 | + } else { |
| 273 | + pos++; |
| 274 | + int shift_len = *pos++; |
| 275 | + pos = pos + shift_len; |
| 276 | + } |
| 277 | + } |
| 278 | + } |
| 279 | + } |
| 280 | +} |
| 281 | + |
| 282 | +#ifdef CONFIG_MBO |
| 283 | +void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd, |
| 284 | + struct sta_info* sta, char *nei_buf, size_t buflen) |
| 285 | +{ |
| 286 | + struct hostapd_neighbor_entry *nr; |
| 287 | + struct mbo_non_pref_chan_info *info; |
| 288 | + u8 i; |
| 289 | + |
| 290 | + for(info = sta->non_pref_chan; info; info = info->next) { |
| 291 | + /* Check OP_Class and Channel num */ |
| 292 | + for(i = 0; i < info->num_channels; i++) { |
| 293 | + char *pos, *next_nr; |
| 294 | + |
| 295 | + pos = nei_buf; |
| 296 | + next_nr = nei_buf; |
| 297 | + |
| 298 | + /* Iterate Neighbor report database */ |
| 299 | + dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry, |
| 300 | + list) { |
| 301 | + pos = next_nr; |
| 302 | + next_nr = pos + 2 + wpabuf_len(nr->nr); |
| 303 | + /** |
| 304 | + * Shift 12 bytes for Element ID, Neighbor report length, |
| 305 | + * BSSID and BSSID info. |
| 306 | + */ |
| 307 | + pos = pos + 12; |
| 308 | + int nr_op_class = *pos++; |
| 309 | + int nr_channel = *pos; |
| 310 | + if(info->op_class == nr_op_class && info->channels[i] == nr_channel) { |
| 311 | + /* Shift for Channel Num + PHY type */ |
| 312 | + pos = pos + 1 + 1; |
| 313 | + |
| 314 | + // Iterate Subelement |
| 315 | + while(next_nr - pos > 0) { |
| 316 | + if(*pos == 3) { |
| 317 | + pos = pos + 2; |
| 318 | + *pos = info->pref; |
| 319 | + break; |
| 320 | + }else { |
| 321 | + pos++; |
| 322 | + int shift_len = *pos++; |
| 323 | + pos = pos + shift_len; |
| 324 | + } |
| 325 | + } |
| 326 | + } |
| 327 | + } |
| 328 | + } |
| 329 | + } |
| 330 | +} |
| 331 | +#endif |
| 332 | diff --git a/src/ap/neighbor_db.h b/src/ap/neighbor_db.h |
| 333 | index 992671b..a1ddc07 100644 |
| 334 | --- a/src/ap/neighbor_db.h |
| 335 | +++ b/src/ap/neighbor_db.h |
| 336 | @@ -24,4 +24,13 @@ int hostapd_neighbor_remove(struct hostapd_data *hapd, const u8 *bssid, |
| 337 | const struct wpa_ssid_value *ssid); |
| 338 | void hostapd_free_neighbor_db(struct hostapd_data *hapd); |
| 339 | |
| 340 | +int hostapd_neighbor_count(struct hostapd_data *hapd); |
| 341 | +int hostapd_neighbor_insert_buffer(struct hostapd_data *hapd, char *buf, |
| 342 | + size_t buflen); |
| 343 | +void hostapd_neighbor_set_own_report_pref(struct hostapd_data *hapd, char *nei_buf, |
| 344 | + size_t buflen, const int pref); |
| 345 | +#ifdef CONFIG_MBO |
| 346 | +void hostapd_neighbor_set_pref_by_non_pref_chan(struct hostapd_data *hapd, |
| 347 | + struct sta_info* sta, char *nei_buf, size_t buflen); |
| 348 | +#endif |
| 349 | #endif /* NEIGHBOR_DB_H */ |
| 350 | diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c |
| 351 | index 3ea92af..4349e1d 100644 |
| 352 | --- a/src/ap/wnm_ap.c |
| 353 | +++ b/src/ap/wnm_ap.c |
| 354 | @@ -20,6 +20,7 @@ |
| 355 | #include "ap/wpa_auth.h" |
| 356 | #include "mbo_ap.h" |
| 357 | #include "wnm_ap.h" |
| 358 | +#include "ap/neighbor_db.h" |
| 359 | |
| 360 | #define MAX_TFS_IE_LEN 1024 |
| 361 | |
| 362 | @@ -370,9 +371,21 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, |
| 363 | u8 *pos; |
| 364 | int res; |
| 365 | |
| 366 | - mgmt = os_zalloc(sizeof(*mgmt)); |
| 367 | - if (mgmt == NULL) |
| 368 | + int nr_num = hostapd_neighbor_count(hapd); |
| 369 | + int nr_size = ETH_ALEN + 4 + 1 + 1 + 1 + 5; |
| 370 | + int total_nr_size = nr_num * nr_size; |
| 371 | + u8 *nr_data = os_malloc(total_nr_size); |
| 372 | + int nr_data_len = 0; |
| 373 | + if(nr_data == NULL) { |
| 374 | + wpa_printf (MSG_ERROR, "Failed to allocate memory"); |
| 375 | + } else { |
| 376 | + nr_data_len = hostapd_neighbor_insert_buffer(hapd, nr_data, total_nr_size); |
| 377 | + } |
| 378 | + mgmt = os_zalloc(sizeof(*mgmt) + nr_data_len); |
| 379 | + if (mgmt == NULL) { |
| 380 | + wpa_printf (MSG_ERROR, "Failed to allocate memory for mgmt frame"); |
| 381 | return -1; |
| 382 | + } |
| 383 | os_memcpy(mgmt->da, addr, ETH_ALEN); |
| 384 | os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); |
| 385 | os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); |
| 386 | @@ -382,10 +395,18 @@ static int ieee802_11_send_bss_trans_mgmt_request(struct hostapd_data *hapd, |
| 387 | mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ; |
| 388 | mgmt->u.action.u.bss_tm_req.dialog_token = dialog_token; |
| 389 | mgmt->u.action.u.bss_tm_req.req_mode = 0; |
| 390 | + if(nr_num) { |
| 391 | + mgmt->u.action.u.bss_tm_req.req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED; |
| 392 | + } |
| 393 | mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0); |
| 394 | mgmt->u.action.u.bss_tm_req.validity_interval = 1; |
| 395 | pos = mgmt->u.action.u.bss_tm_req.variable; |
| 396 | |
| 397 | + if(nr_num) { |
| 398 | + os_memcpy(pos, nr_data, nr_data_len); |
| 399 | + pos += nr_data_len; |
| 400 | + } |
| 401 | + |
| 402 | hapd->openwrt_stats.wnm.bss_transition_request_tx++; |
| 403 | wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to " |
| 404 | MACSTR " dialog_token=%u req_mode=0x%x disassoc_timer=%u " |
| 405 | @@ -759,6 +780,50 @@ static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta, |
| 406 | } |
| 407 | |
| 408 | |
| 409 | +static void set_send_disassoc_frame_timer(struct hostapd_data *hapd, struct sta_info *sta, |
| 410 | + int disassoc_timer) |
| 411 | +{ |
| 412 | + int timeout, beacon_int; |
| 413 | + |
| 414 | + /* |
| 415 | + * Prevent STA from reconnecting using cached PMKSA to force |
| 416 | + * full authentication with the authentication server (which may |
| 417 | + * decide to reject the connection), |
| 418 | + */ |
| 419 | + wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr); |
| 420 | + |
| 421 | + beacon_int = hapd->iconf->beacon_int; |
| 422 | + if (beacon_int < 1) |
| 423 | + beacon_int = 100; /* best guess */ |
| 424 | + /* Calculate timeout in ms based on beacon_int in TU */ |
| 425 | + timeout = disassoc_timer * beacon_int * 128 / 125; |
| 426 | + wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR |
| 427 | + " set to %d ms", MAC2STR(sta->addr), timeout); |
| 428 | + |
| 429 | + u16 reason = WLAN_REASON_PREV_AUTH_NOT_VALID; |
| 430 | + |
| 431 | + hostapd_drv_sta_disassoc(hapd, sta->addr, reason); |
| 432 | + if (sta) |
| 433 | + ap_sta_disassociate(hapd, sta, reason); |
| 434 | +} |
| 435 | + |
| 436 | + |
| 437 | +void bss_termination_disable_iface(void *eloop_ctx, void *timeout_ctx) |
| 438 | +{ |
| 439 | + struct hostapd_data *hapd = eloop_ctx; |
| 440 | + hostapd_disable_iface(hapd->iface); |
| 441 | +} |
| 442 | + |
| 443 | + |
| 444 | +static void set_disable_iface_timer(struct hostapd_data *hapd, struct sta_info *sta, |
| 445 | + int disable_iface_timer) |
| 446 | +{ |
| 447 | + wpa_printf(MSG_DEBUG, "Disable interface timer set to %d secs", disable_iface_timer); |
| 448 | + eloop_register_timeout(disable_iface_timer, 0, |
| 449 | + bss_termination_disable_iface, hapd, NULL); |
| 450 | +} |
| 451 | + |
| 452 | + |
| 453 | int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd, |
| 454 | struct sta_info *sta, const char *url, |
| 455 | int disassoc_timer) |
| 456 | @@ -848,6 +913,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, |
| 457 | bss_term_dur) { |
| 458 | os_memcpy(pos, bss_term_dur, 12); |
| 459 | pos += 12; |
| 460 | + set_disable_iface_timer(hapd, sta, hapd->conf->bss_termination_tsf); |
| 461 | } |
| 462 | |
| 463 | if (url) { |
| 464 | @@ -884,7 +950,7 @@ int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta, |
| 465 | hapd->openwrt_stats.wnm.bss_transition_request_tx++; |
| 466 | if (disassoc_timer) { |
| 467 | /* send disassociation frame after time-out */ |
| 468 | - set_disassoc_timer(hapd, sta, disassoc_timer); |
| 469 | + set_send_disassoc_frame_timer(hapd, sta, disassoc_timer); |
| 470 | } |
| 471 | |
| 472 | return 0; |
| 473 | -- |
| 474 | 2.36.1 |
| 475 | |