diff options
Diffstat (limited to 'wpa_supplicant/bss.c')
-rw-r--r-- | wpa_supplicant/bss.c | 114 |
1 files changed, 106 insertions, 8 deletions
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index d326bef..6223beb 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -96,6 +96,19 @@ static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp) static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const char *reason) { + if (wpa_s->last_scan_res) { + unsigned int i; + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpa_s->last_scan_res[i] == bss) { + os_memmove(&wpa_s->last_scan_res[i], + &wpa_s->last_scan_res[i + 1], + (wpa_s->last_scan_res_used - i - 1) + * sizeof(struct wpa_bss *)); + wpa_s->last_scan_res_used--; + break; + } + } + } dl_list_del(&bss->list); dl_list_del(&bss->list_id); wpa_s->num_bss--; @@ -213,15 +226,15 @@ static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s) } -static void wpa_bss_add(struct wpa_supplicant *wpa_s, - const u8 *ssid, size_t ssid_len, - struct wpa_scan_res *res) +static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s, + const u8 *ssid, size_t ssid_len, + struct wpa_scan_res *res) { struct wpa_bss *bss; bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (bss == NULL) - return; + return NULL; bss->id = wpa_s->bss_next_id++; bss->last_update_idx = wpa_s->bss_update_idx; wpa_bss_copy_res(bss, res); @@ -246,6 +259,7 @@ static void wpa_bss_add(struct wpa_supplicant *wpa_s, "not get here!", (int) wpa_s->num_bss); wpa_s->conf->bss_max_count = wpa_s->num_bss; } + return bss; } @@ -377,8 +391,9 @@ static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes, } -static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, - struct wpa_scan_res *res) +static struct wpa_bss * +wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, + struct wpa_scan_res *res) { u32 changes; @@ -400,6 +415,13 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, nbss = os_realloc(bss, sizeof(*bss) + res->ie_len + res->beacon_ie_len); if (nbss) { + unsigned int i; + for (i = 0; i < wpa_s->last_scan_res_used; i++) { + if (wpa_s->last_scan_res[i] == bss) { + wpa_s->last_scan_res[i] = nbss; + break; + } + } if (wpa_s->current_bss == bss) wpa_s->current_bss = nbss; bss = nbss; @@ -415,6 +437,8 @@ static void wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, dl_list_add_tail(&wpa_s->bss, &bss->list); notify_bss_changes(wpa_s, changes, bss); + + return bss; } @@ -423,6 +447,7 @@ void wpa_bss_update_start(struct wpa_supplicant *wpa_s) wpa_s->bss_update_idx++; wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u", wpa_s->bss_update_idx); + wpa_s->last_scan_res_used = 0; } @@ -465,9 +490,28 @@ void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s, * (to save memory) */ bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]); if (bss == NULL) - wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); + bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res); else - wpa_bss_update(wpa_s, bss, res); + bss = wpa_bss_update(wpa_s, bss, res); + + if (bss == NULL) + return; + if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) { + struct wpa_bss **n; + unsigned int siz; + if (wpa_s->last_scan_res_size == 0) + siz = 32; + else + siz = wpa_s->last_scan_res_size * 2; + n = os_realloc_array(wpa_s->last_scan_res, siz, + sizeof(struct wpa_bss *)); + if (n == NULL) + return; + wpa_s->last_scan_res = n; + wpa_s->last_scan_res_size = siz; + } + + wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss; } @@ -517,9 +561,26 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, { struct wpa_bss *bss, *n; + wpa_s->last_scan_full = 0; + os_get_time(&wpa_s->last_scan); if (!new_scan) return; /* do not expire entries without new scan */ + if (info && !info->aborted && !info->freqs) { + size_t i; + if (info->num_ssids == 0) { + wpa_s->last_scan_full = 1; + } else { + for (i = 0; i < info->num_ssids; i++) { + if (info->ssids[i].ssid == NULL || + info->ssids[i].ssid_len == 0) { + wpa_s->last_scan_full = 1; + break; + } + } + } + } + dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) { if (wpa_bss_in_use(wpa_s, bss)) continue; @@ -532,6 +593,11 @@ void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info, wpa_bss_remove(wpa_s, bss, "no match in scan"); } } + + wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u " + "last_scan_full=%d", + wpa_s->last_scan_res_used, wpa_s->last_scan_res_size, + wpa_s->last_scan_full); } @@ -712,6 +778,38 @@ struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss, } +struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss, + u32 vendor_type) +{ + struct wpabuf *buf; + const u8 *end, *pos; + + buf = wpabuf_alloc(bss->beacon_ie_len); + if (buf == NULL) + return NULL; + + pos = (const u8 *) (bss + 1); + pos += bss->ie_len; + end = pos + bss->beacon_ie_len; + + while (pos + 1 < end) { + if (pos + 2 + pos[1] > end) + break; + if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && + vendor_type == WPA_GET_BE32(&pos[2])) + wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4); + pos += 2 + pos[1]; + } + + if (wpabuf_len(buf) == 0) { + wpabuf_free(buf); + buf = NULL; + } + + return buf; +} + + int wpa_bss_get_max_rate(const struct wpa_bss *bss) { int rate = 0; |