static void hostapd_acl_expire_queries(struct hostapd_data *hapd, struct os_reltime *now) { struct hostapd_acl_query_data *prev, *entry, *tmp; prev = NULL; entry = hapd->acl_queries; while (entry) { if (os_reltime_expired(now, &entry->timestamp, RADIUS_ACL_TIMEOUT)) { wpa_printf(MSG_DEBUG, "ACL query for " MACSTR " has expired.", MAC2STR(entry->addr)); if (prev) prev->next = entry->next; else hapd->acl_queries = entry->next; tmp = entry; entry = entry->next; hostapd_acl_query_free(tmp); continue; } prev = entry; entry = entry->next; } }
void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *da, u16 reason_code) { struct wpa_ssid *ssid; struct os_reltime now; if (wpa_s->wpa_state != WPA_COMPLETED) return; ssid = wpa_s->current_ssid; if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) return; if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) return; if (reason_code != WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA && reason_code != WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA) return; if (wpa_s->sme.sa_query_count > 0) return; os_get_reltime(&now); if (wpa_s->sme.last_unprot_disconnect.sec && !os_reltime_expired(&now, &wpa_s->sme.last_unprot_disconnect, 10)) return; /* limit SA Query procedure frequency */ wpa_s->sme.last_unprot_disconnect = now; wpa_dbg(wpa_s, MSG_DEBUG, "SME: Unprotected disconnect dropped - " "possible AP/STA state mismatch - trigger SA Query"); sme_start_sa_query(wpa_s); }
void sta_track_expire(struct hostapd_iface *iface, int force) { struct os_reltime now; struct hostapd_sta_info *info; if (!iface->num_sta_seen) return; os_get_reltime(&now); while ((info = dl_list_first(&iface->sta_seen, struct hostapd_sta_info, list))) { if (!force && !os_reltime_expired(&now, &info->last_seen, iface->conf->track_sta_max_age)) break; force = 0; wpa_printf(MSG_MSGDUMP, "%s: Expire STA tracking entry for " MACSTR, iface->bss[0]->conf->iface, MAC2STR(info->addr)); dl_list_del(&info->list); iface->num_sta_seen--; os_free(info); } }
static void hostapd_acl_expire_cache(struct hostapd_data *hapd, struct os_reltime *now) { struct hostapd_cached_radius_acl *prev, *entry, *tmp; prev = NULL; entry = hapd->acl_cache; while (entry) { if (os_reltime_expired(now, &entry->timestamp, RADIUS_ACL_TIMEOUT)) { wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR " has expired.", MAC2STR(entry->addr)); if (prev) prev->next = entry->next; else hapd->acl_cache = entry->next; hostapd_drv_set_radius_acl_expire(hapd, entry->addr); tmp = entry; entry = entry->next; hostapd_acl_cache_free_entry(tmp); continue; } prev = entry; entry = entry->next; } }
static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) { struct hostapd_iface *iface = eloop_ctx; struct os_reltime now; struct ap_info *ap; int set_beacon = 0; eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); if (!iface->ap_list) { return; } os_get_reltime(&now); while (iface->ap_list) { ap = iface->ap_list->prev; if (!os_reltime_expired(&now, &ap->last_beacon, iface->conf->ap_table_expiration_time)) { break; } ap_free_ap(iface, ap); } if (iface->olbc || iface->olbc_ht) { int olbc = 0; int olbc_ht = 0; ap = iface->ap_list; while (ap && (olbc == 0 || olbc_ht == 0)) { if (ap_list_beacon_olbc(iface, ap)) { olbc = 1; } if (!ap->ht_support) { olbc_ht = 1; } ap = ap->next; } if (!olbc && iface->olbc) { wpa_printf(MSG_DEBUG, "OLBC not detected anymore"); iface->olbc = 0; set_beacon++; } #ifdef CONFIG_IEEE80211N if (!olbc_ht && iface->olbc_ht) { wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); iface->olbc_ht = 0; hostapd_ht_operation_update(iface); set_beacon++; } #endif /* CONFIG_IEEE80211N */ } if (set_beacon) { ieee802_11_update_beacons(iface); } }
static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr, u32 *session_timeout, u32 *acct_interim_interval, int *vlan_id, struct hostapd_sta_wpa_psk_short **psk, char **identity, char **radius_cui) { struct hostapd_cached_radius_acl *entry; struct os_reltime now; wpa_printf(MSG_INFO, "WGTT: %s %s():%d\n", __FILE__, __FUNCTION__, __LINE__); os_get_reltime(&now); for (entry = hapd->acl_cache; entry; entry = entry->next) { if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0) continue; if (os_reltime_expired(&now, &entry->timestamp, RADIUS_ACL_TIMEOUT)) return -1; /* entry has expired */ if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT) if (session_timeout) *session_timeout = entry->session_timeout; if (acct_interim_interval) *acct_interim_interval = entry->acct_interim_interval; if (vlan_id) *vlan_id = entry->vlan_id; copy_psk_list(psk, entry->psk); if (identity) { if (entry->identity) *identity = os_strdup(entry->identity); else *identity = NULL; } if (radius_cui) { if (entry->radius_cui) *radius_cui = os_strdup(entry->radius_cui); else *radius_cui = NULL; } return entry->accepted; } return -1; }
static int wnm_add_cand_list(struct wpa_supplicant *wpa_s, u8 *buf, size_t len) { u8 *pos = buf; unsigned int i, pref = 255; struct os_reltime now; struct wpa_ssid *ssid = wpa_s->current_ssid; if (!ssid) return 0; /* * TODO: Define when scan results are no longer valid for the candidate * list. */ os_get_reltime(&now); if (os_reltime_expired(&now, &wpa_s->last_scan, 10)) return 0; wpa_printf(MSG_DEBUG, "WNM: Add candidate list to BSS Transition Management Response frame"); for (i = 0; i < wpa_s->last_scan_res_used && pref; i++) { struct wpa_bss *bss = wpa_s->last_scan_res[i]; int res; if (wpa_scan_res_match(wpa_s, i, bss, ssid, 1, 0)) { res = wnm_nei_rep_add_bss(wpa_s, bss, pos, len, pref--); if (res == -2) continue; /* could not build entry for BSS */ if (res < 0) break; /* no more room for candidates */ if (pref == 1) break; pos += res; len -= res; } } wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Management Response candidate list", buf, pos - buf); return pos - buf; }
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len, char *reply, size_t *reply_len, void (*msg_cb)(char *msg, size_t len)) { struct timeval tv; struct os_reltime started_at; int res; fd_set rfds; const char *_cmd; char *cmd_buf = NULL; size_t _cmd_len; #ifdef CONFIG_CTRL_IFACE_UDP if (ctrl->cookie) { char *pos; _cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len; cmd_buf = os_malloc(_cmd_len); if (cmd_buf == NULL) return -1; _cmd = cmd_buf; pos = cmd_buf; os_strlcpy(pos, ctrl->cookie, _cmd_len); pos += os_strlen(ctrl->cookie); *pos++ = ' '; os_memcpy(pos, cmd, cmd_len); } else #endif /* CONFIG_CTRL_IFACE_UDP */ { _cmd = cmd; _cmd_len = cmd_len; } errno = 0; started_at.sec = 0; started_at.usec = 0; retry_send: if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) { if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK) { /* * Must be a non-blocking socket... Try for a bit * longer before giving up. */ if (started_at.sec == 0) os_get_reltime(&started_at); else { struct os_reltime n; os_get_reltime(&n); /* Try for a few seconds. */ if (os_reltime_expired(&n, &started_at, 5)) goto send_err; } os_sleep(1, 0); goto retry_send; } send_err: os_free(cmd_buf); return -1; } os_free(cmd_buf); for (;;) { tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(ctrl->s, &rfds); res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv); if (res < 0 && errno == EINTR) continue; if (res < 0) return res; if (FD_ISSET(ctrl->s, &rfds)) { res = recv(ctrl->s, reply, *reply_len, 0); if (res < 0) return res; if (res > 0 && reply[0] == '<') { /* This is an unsolicited message from * wpa_supplicant, not the reply to the * request. Use msg_cb to report this to the * caller. */ if (msg_cb) { /* Make sure the message is nul * terminated. */ if ((size_t) res == *reply_len) res = (*reply_len) - 1; reply[res] = '\0'; msg_cb(reply, res); } continue; } *reply_len = res; break; } else { return -2; } } return 0; }
static struct wpa_bss * compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs, enum mbo_transition_reject_reason *reason) { u8 i; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_bss *target; if (!bss) return NULL; wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d", MAC2STR(wpa_s->bssid), bss->level); wnm_clear_acceptable(wpa_s); for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) { struct neighbor_report *nei; nei = &wpa_s->wnm_neighbor_report_elements[i]; if (nei->preference_present && nei->preference == 0) { wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR, MAC2STR(nei->bssid)); continue; } target = wpa_bss_get_bssid(wpa_s, nei->bssid); if (!target) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) not found in scan results", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (age_secs) { struct os_reltime now; if (os_get_reltime(&now) == 0 && os_reltime_expired(&now, &target->last_update, age_secs)) { wpa_printf(MSG_DEBUG, "Candidate BSS is more than %ld seconds old", age_secs); continue; } } if (bss->ssid_len != target->ssid_len || os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) { /* * TODO: Could consider allowing transition to another * ESS if PMF was enabled for the association. */ wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) in different ESS", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (wpa_s->current_ssid && !wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid, 1, 0)) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not match the current network profile", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1); continue; } if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) { wpa_printf(MSG_DEBUG, "MBO: Candidate BSS " MACSTR " retry delay is not over yet", MAC2STR(nei->bssid)); continue; } if (target->level < bss->level && target->level < -80) { wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR " (pref %d) does not have sufficient signal level (%d)", MAC2STR(nei->bssid), nei->preference_present ? nei->preference : -1, target->level); continue; } nei->acceptable = 1; } #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present) target = get_mbo_transition_candidate(wpa_s, reason); else target = get_first_acceptable(wpa_s); #else /* CONFIG_MBO */ target = get_first_acceptable(wpa_s); #endif /* CONFIG_MBO */ if (target) { wpa_printf(MSG_DEBUG, "WNM: Found an acceptable preferred transition candidate BSS " MACSTR " (RSSI %d)", MAC2STR(target->bssid), target->level); } return target; }
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { unsigned int beacon_int; u8 valid_int; #ifdef CONFIG_MBO const u8 *vendor; #endif /* CONFIG_MBO */ if (end - pos < 5) return; #ifdef CONFIG_MBO wpa_s->wnm_mbo_trans_reason_present = 0; wpa_s->wnm_mbo_transition_reason = 0; #endif /* CONFIG_MBO */ if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_mode = pos[1]; wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); valid_int = pos[4]; wpa_s->wnm_reply = reply; wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " "dialog_token=%u request_mode=0x%x " "disassoc_timer=%u validity_interval=%u", wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); #if defined(CONFIG_MBO) && defined(CONFIG_TESTING_OPTIONS) if (wpa_s->reject_btm_req_reason) { wpa_printf(MSG_INFO, "WNM: Testing - reject BSS Transition Management Request: reject_btm_req_reason=%d", wpa_s->reject_btm_req_reason); wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, wpa_s->reject_btm_req_reason, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); return; } #endif /* CONFIG_MBO && CONFIG_TESTING_OPTIONS */ pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (end - pos < 12) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; } os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); pos += 12; /* BSS Termination Duration */ } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; if (end - pos < 1 || 1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; } os_memcpy(url, pos + 1, pos[0]); url[pos[0]] = '\0'; pos += 1 + pos[0]; wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", wpa_sm_pmf_enabled(wpa_s->wpa), wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { /* TODO: mark current BSS less preferred for * selection */ wpa_printf(MSG_DEBUG, "Trying to find another BSS"); wpa_supplicant_req_scan(wpa_s, 0, 0); } } #ifdef CONFIG_MBO vendor = get_ie(pos, end - pos, WLAN_EID_VENDOR_SPECIFIC); if (vendor) wpas_mbo_ie_trans_req(wpa_s, vendor + 2, vendor[1]); #endif /* CONFIG_MBO */ if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { unsigned int valid_ms; wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); wnm_deallocate_memory(wpa_s); wpa_s->wnm_neighbor_report_elements = os_calloc( WNM_MAX_NEIGHBOR_REPORT, sizeof(struct neighbor_report)); if (wpa_s->wnm_neighbor_report_elements == NULL) return; while (end - pos >= 2 && wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) { u8 tag = *pos++; u8 len = *pos++; wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag); if (len > end - pos) { wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } if (tag == WLAN_EID_NEIGHBOR_REPORT) { struct neighbor_report *rep; rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); wpa_s->wnm_num_neighbor_report++; #ifdef CONFIG_MBO if (wpa_s->wnm_mbo_trans_reason_present && wpa_s->wnm_num_neighbor_report == 1) { rep->is_first = 1; wpa_printf(MSG_DEBUG, "WNM: First transition candidate is " MACSTR, MAC2STR(rep->bssid)); } #endif /* CONFIG_MBO */ } pos += len; } if (!wpa_s->wnm_num_neighbor_report) { wpa_printf(MSG_DEBUG, "WNM: Candidate list included bit is set, but no candidates found"); wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); return; } wnm_sort_cand_list(wpa_s); wnm_dump_cand_list(wpa_s); valid_ms = valid_int * beacon_int * 128 / 125; wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", valid_ms); os_get_reltime(&wpa_s->wnm_cand_valid_until); wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000; os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); /* * Fetch the latest scan results from the kernel and check for * candidates based on those results first. This can help in * finding more up-to-date information should the driver has * done some internal scanning operations after the last scan * result update in wpa_supplicant. */ if (wnm_fetch_scan_results(wpa_s) > 0) return; /* * Try to use previously received scan results, if they are * recent enough to use for a connection. */ if (wpa_s->last_scan_res_used > 0) { struct os_reltime now; os_get_reltime(&now); if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { wpa_printf(MSG_DEBUG, "WNM: Try to use recent scan results"); if (wnm_scan_process(wpa_s, 0) > 0) return; wpa_printf(MSG_DEBUG, "WNM: No match in previous scan results - try a new scan"); } } wnm_set_scan_freqs(wpa_s); if (wpa_s->wnm_num_neighbor_report == 1) { os_memcpy(wpa_s->next_scan_bssid, wpa_s->wnm_neighbor_report_elements[0].bssid, ETH_ALEN); wpa_printf(MSG_DEBUG, "WNM: Scan only for a specific BSSID since there is only a single candidate " MACSTR, MAC2STR(wpa_s->next_scan_bssid)); } wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) status = WNM_BSS_TM_ACCEPT; else { wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } wnm_send_bss_transition_mgmt_resp( wpa_s, wpa_s->wnm_dialog_token, status, MBO_TRANSITION_REASON_UNSPECIFIED, 0, NULL); } }
static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s, const u8 *pos, const u8 *end, int reply) { unsigned int beacon_int; u8 valid_int; if (pos + 5 > end) return; if (wpa_s->current_bss) beacon_int = wpa_s->current_bss->beacon_int; else beacon_int = 100; /* best guess */ wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_mode = pos[1]; wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); valid_int = pos[4]; wpa_s->wnm_reply = reply; wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: " "dialog_token=%u request_mode=0x%x " "disassoc_timer=%u validity_interval=%u", wpa_s->wnm_dialog_token, wpa_s->wnm_mode, wpa_s->wnm_dissoc_timer, valid_int); pos += 5; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) { if (pos + 12 > end) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request"); return; } os_memcpy(wpa_s->wnm_bss_termination_duration, pos, 12); pos += 12; /* BSS Termination Duration */ } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) { char url[256]; if (pos + 1 > end || pos + 1 + pos[0] > end) { wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition " "Management Request (URL)"); return; } os_memcpy(url, pos + 1, pos[0]); url[pos[0]] = '\0'; pos += 1 + pos[0]; wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s", wpa_sm_pmf_enabled(wpa_s->wpa), wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url); } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) { wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - " "Disassociation Timer %u", wpa_s->wnm_dissoc_timer); if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) { /* TODO: mark current BSS less preferred for * selection */ wpa_printf(MSG_DEBUG, "Trying to find another BSS"); wpa_supplicant_req_scan(wpa_s, 0, 0); } } if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) { unsigned int valid_ms; wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); wnm_deallocate_memory(wpa_s); wpa_s->wnm_neighbor_report_elements = os_calloc( WNM_MAX_NEIGHBOR_REPORT, sizeof(struct neighbor_report)); if (wpa_s->wnm_neighbor_report_elements == NULL) return; while (pos + 2 <= end && wpa_s->wnm_num_neighbor_report < WNM_MAX_NEIGHBOR_REPORT) { u8 tag = *pos++; u8 len = *pos++; wpa_printf(MSG_DEBUG, "WNM: Neighbor report tag %u", tag); if (pos + len > end) { wpa_printf(MSG_DEBUG, "WNM: Truncated request"); return; } if (tag == WLAN_EID_NEIGHBOR_REPORT) { struct neighbor_report *rep; rep = &wpa_s->wnm_neighbor_report_elements[ wpa_s->wnm_num_neighbor_report]; wnm_parse_neighbor_report(wpa_s, pos, len, rep); } pos += len; wpa_s->wnm_num_neighbor_report++; } wnm_sort_cand_list(wpa_s); wnm_dump_cand_list(wpa_s); valid_ms = valid_int * beacon_int * 128 / 125; wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms", valid_ms); os_get_reltime(&wpa_s->wnm_cand_valid_until); wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000; wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000; wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000; os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN); if (wpa_s->last_scan_res_used > 0) { struct os_reltime now; os_get_reltime(&now); if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) { wpa_printf(MSG_DEBUG, "WNM: Try to use recent scan results"); if (wnm_scan_process(wpa_s, 0) > 0) return; wpa_printf(MSG_DEBUG, "WNM: No match in previous scan results - try a new scan"); } } wnm_set_scan_freqs(wpa_s); wpa_supplicant_req_scan(wpa_s, 0, 0); } else if (reply) { enum bss_trans_mgmt_status_code status; if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) status = WNM_BSS_TM_ACCEPT; else { wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates"); status = WNM_BSS_TM_REJECT_UNSPECIFIED; } wnm_send_bss_transition_mgmt_resp(wpa_s, wpa_s->wnm_dialog_token, status, 0, NULL); } }