1*03f9172cSAndroid Build Coastguard Worker /*
2*03f9172cSAndroid Build Coastguard Worker * BSS table
3*03f9172cSAndroid Build Coastguard Worker * Copyright (c) 2009-2019, Jouni Malinen <[email protected]>
4*03f9172cSAndroid Build Coastguard Worker *
5*03f9172cSAndroid Build Coastguard Worker * This software may be distributed under the terms of the BSD license.
6*03f9172cSAndroid Build Coastguard Worker * See README for more details.
7*03f9172cSAndroid Build Coastguard Worker */
8*03f9172cSAndroid Build Coastguard Worker
9*03f9172cSAndroid Build Coastguard Worker #include "utils/includes.h"
10*03f9172cSAndroid Build Coastguard Worker
11*03f9172cSAndroid Build Coastguard Worker #include "utils/common.h"
12*03f9172cSAndroid Build Coastguard Worker #include "utils/eloop.h"
13*03f9172cSAndroid Build Coastguard Worker #include "common/ieee802_11_defs.h"
14*03f9172cSAndroid Build Coastguard Worker #include "drivers/driver.h"
15*03f9172cSAndroid Build Coastguard Worker #include "eap_peer/eap.h"
16*03f9172cSAndroid Build Coastguard Worker #include "rsn_supp/wpa.h"
17*03f9172cSAndroid Build Coastguard Worker #include "wpa_supplicant_i.h"
18*03f9172cSAndroid Build Coastguard Worker #include "config.h"
19*03f9172cSAndroid Build Coastguard Worker #include "notify.h"
20*03f9172cSAndroid Build Coastguard Worker #include "scan.h"
21*03f9172cSAndroid Build Coastguard Worker #include "bssid_ignore.h"
22*03f9172cSAndroid Build Coastguard Worker #include "bss.h"
23*03f9172cSAndroid Build Coastguard Worker
wpa_bss_set_hessid(struct wpa_bss * bss)24*03f9172cSAndroid Build Coastguard Worker static void wpa_bss_set_hessid(struct wpa_bss *bss)
25*03f9172cSAndroid Build Coastguard Worker {
26*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_INTERWORKING
27*03f9172cSAndroid Build Coastguard Worker const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
28*03f9172cSAndroid Build Coastguard Worker if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
29*03f9172cSAndroid Build Coastguard Worker os_memset(bss->hessid, 0, ETH_ALEN);
30*03f9172cSAndroid Build Coastguard Worker return;
31*03f9172cSAndroid Build Coastguard Worker }
32*03f9172cSAndroid Build Coastguard Worker if (ie[1] == 7)
33*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
34*03f9172cSAndroid Build Coastguard Worker else
35*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
36*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_INTERWORKING */
37*03f9172cSAndroid Build Coastguard Worker }
38*03f9172cSAndroid Build Coastguard Worker
39*03f9172cSAndroid Build Coastguard Worker
40*03f9172cSAndroid Build Coastguard Worker /**
41*03f9172cSAndroid Build Coastguard Worker * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
42*03f9172cSAndroid Build Coastguard Worker * Returns: Allocated ANQP data structure or %NULL on failure
43*03f9172cSAndroid Build Coastguard Worker *
44*03f9172cSAndroid Build Coastguard Worker * The allocated ANQP data structure has its users count set to 1. It may be
45*03f9172cSAndroid Build Coastguard Worker * shared by multiple BSS entries and each shared entry is freed with
46*03f9172cSAndroid Build Coastguard Worker * wpa_bss_anqp_free().
47*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_anqp_alloc(void)48*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
49*03f9172cSAndroid Build Coastguard Worker {
50*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp *anqp;
51*03f9172cSAndroid Build Coastguard Worker anqp = os_zalloc(sizeof(*anqp));
52*03f9172cSAndroid Build Coastguard Worker if (anqp == NULL)
53*03f9172cSAndroid Build Coastguard Worker return NULL;
54*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_INTERWORKING
55*03f9172cSAndroid Build Coastguard Worker dl_list_init(&anqp->anqp_elems);
56*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_INTERWORKING */
57*03f9172cSAndroid Build Coastguard Worker anqp->users = 1;
58*03f9172cSAndroid Build Coastguard Worker return anqp;
59*03f9172cSAndroid Build Coastguard Worker }
60*03f9172cSAndroid Build Coastguard Worker
61*03f9172cSAndroid Build Coastguard Worker
62*03f9172cSAndroid Build Coastguard Worker /**
63*03f9172cSAndroid Build Coastguard Worker * wpa_bss_anqp_clone - Clone an ANQP data structure
64*03f9172cSAndroid Build Coastguard Worker * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
65*03f9172cSAndroid Build Coastguard Worker * Returns: Cloned ANQP data structure or %NULL on failure
66*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_anqp_clone(struct wpa_bss_anqp * anqp)67*03f9172cSAndroid Build Coastguard Worker static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
68*03f9172cSAndroid Build Coastguard Worker {
69*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp *n;
70*03f9172cSAndroid Build Coastguard Worker
71*03f9172cSAndroid Build Coastguard Worker n = os_zalloc(sizeof(*n));
72*03f9172cSAndroid Build Coastguard Worker if (n == NULL)
73*03f9172cSAndroid Build Coastguard Worker return NULL;
74*03f9172cSAndroid Build Coastguard Worker
75*03f9172cSAndroid Build Coastguard Worker #define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
76*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_INTERWORKING
77*03f9172cSAndroid Build Coastguard Worker dl_list_init(&n->anqp_elems);
78*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(capability_list);
79*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(venue_name);
80*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(network_auth_type);
81*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(roaming_consortium);
82*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(ip_addr_type_availability);
83*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(nai_realm);
84*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(anqp_3gpp);
85*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(domain_name);
86*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(fils_realm_info);
87*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_INTERWORKING */
88*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_HS20
89*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_capability_list);
90*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_operator_friendly_name);
91*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_wan_metrics);
92*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_connection_capability);
93*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_operating_class);
94*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_osu_providers_list);
95*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_operator_icon_metadata);
96*03f9172cSAndroid Build Coastguard Worker ANQP_DUP(hs20_osu_providers_nai_list);
97*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_HS20 */
98*03f9172cSAndroid Build Coastguard Worker #undef ANQP_DUP
99*03f9172cSAndroid Build Coastguard Worker
100*03f9172cSAndroid Build Coastguard Worker return n;
101*03f9172cSAndroid Build Coastguard Worker }
102*03f9172cSAndroid Build Coastguard Worker
103*03f9172cSAndroid Build Coastguard Worker
104*03f9172cSAndroid Build Coastguard Worker /**
105*03f9172cSAndroid Build Coastguard Worker * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
106*03f9172cSAndroid Build Coastguard Worker * @bss: BSS entry
107*03f9172cSAndroid Build Coastguard Worker * Returns: 0 on success, -1 on failure
108*03f9172cSAndroid Build Coastguard Worker *
109*03f9172cSAndroid Build Coastguard Worker * This function ensures the specific BSS entry has an ANQP data structure that
110*03f9172cSAndroid Build Coastguard Worker * is not shared with any other BSS entry.
111*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_anqp_unshare_alloc(struct wpa_bss * bss)112*03f9172cSAndroid Build Coastguard Worker int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
113*03f9172cSAndroid Build Coastguard Worker {
114*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp *anqp;
115*03f9172cSAndroid Build Coastguard Worker
116*03f9172cSAndroid Build Coastguard Worker if (bss->anqp && bss->anqp->users > 1) {
117*03f9172cSAndroid Build Coastguard Worker /* allocated, but shared - clone an unshared copy */
118*03f9172cSAndroid Build Coastguard Worker anqp = wpa_bss_anqp_clone(bss->anqp);
119*03f9172cSAndroid Build Coastguard Worker if (anqp == NULL)
120*03f9172cSAndroid Build Coastguard Worker return -1;
121*03f9172cSAndroid Build Coastguard Worker anqp->users = 1;
122*03f9172cSAndroid Build Coastguard Worker bss->anqp->users--;
123*03f9172cSAndroid Build Coastguard Worker bss->anqp = anqp;
124*03f9172cSAndroid Build Coastguard Worker return 0;
125*03f9172cSAndroid Build Coastguard Worker }
126*03f9172cSAndroid Build Coastguard Worker
127*03f9172cSAndroid Build Coastguard Worker if (bss->anqp)
128*03f9172cSAndroid Build Coastguard Worker return 0; /* already allocated and not shared */
129*03f9172cSAndroid Build Coastguard Worker
130*03f9172cSAndroid Build Coastguard Worker /* not allocated - allocate a new storage area */
131*03f9172cSAndroid Build Coastguard Worker bss->anqp = wpa_bss_anqp_alloc();
132*03f9172cSAndroid Build Coastguard Worker return bss->anqp ? 0 : -1;
133*03f9172cSAndroid Build Coastguard Worker }
134*03f9172cSAndroid Build Coastguard Worker
135*03f9172cSAndroid Build Coastguard Worker
136*03f9172cSAndroid Build Coastguard Worker /**
137*03f9172cSAndroid Build Coastguard Worker * wpa_bss_anqp_free - Free an ANQP data structure
138*03f9172cSAndroid Build Coastguard Worker * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
139*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_anqp_free(struct wpa_bss_anqp * anqp)140*03f9172cSAndroid Build Coastguard Worker static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
141*03f9172cSAndroid Build Coastguard Worker {
142*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_INTERWORKING
143*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp_elem *elem;
144*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_INTERWORKING */
145*03f9172cSAndroid Build Coastguard Worker
146*03f9172cSAndroid Build Coastguard Worker if (anqp == NULL)
147*03f9172cSAndroid Build Coastguard Worker return;
148*03f9172cSAndroid Build Coastguard Worker
149*03f9172cSAndroid Build Coastguard Worker anqp->users--;
150*03f9172cSAndroid Build Coastguard Worker if (anqp->users > 0) {
151*03f9172cSAndroid Build Coastguard Worker /* Another BSS entry holds a pointer to this ANQP info */
152*03f9172cSAndroid Build Coastguard Worker return;
153*03f9172cSAndroid Build Coastguard Worker }
154*03f9172cSAndroid Build Coastguard Worker
155*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_INTERWORKING
156*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->capability_list);
157*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->venue_name);
158*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->network_auth_type);
159*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->roaming_consortium);
160*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->ip_addr_type_availability);
161*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->nai_realm);
162*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->anqp_3gpp);
163*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->domain_name);
164*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->fils_realm_info);
165*03f9172cSAndroid Build Coastguard Worker
166*03f9172cSAndroid Build Coastguard Worker while ((elem = dl_list_first(&anqp->anqp_elems,
167*03f9172cSAndroid Build Coastguard Worker struct wpa_bss_anqp_elem, list))) {
168*03f9172cSAndroid Build Coastguard Worker dl_list_del(&elem->list);
169*03f9172cSAndroid Build Coastguard Worker wpabuf_free(elem->payload);
170*03f9172cSAndroid Build Coastguard Worker os_free(elem);
171*03f9172cSAndroid Build Coastguard Worker }
172*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_INTERWORKING */
173*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_HS20
174*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_capability_list);
175*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_operator_friendly_name);
176*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_wan_metrics);
177*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_connection_capability);
178*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_operating_class);
179*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_osu_providers_list);
180*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_operator_icon_metadata);
181*03f9172cSAndroid Build Coastguard Worker wpabuf_free(anqp->hs20_osu_providers_nai_list);
182*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_HS20 */
183*03f9172cSAndroid Build Coastguard Worker
184*03f9172cSAndroid Build Coastguard Worker os_free(anqp);
185*03f9172cSAndroid Build Coastguard Worker }
186*03f9172cSAndroid Build Coastguard Worker
187*03f9172cSAndroid Build Coastguard Worker
188*03f9172cSAndroid Build Coastguard Worker static struct wpa_connect_work *
wpa_bss_check_pending_connect(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)189*03f9172cSAndroid Build Coastguard Worker wpa_bss_check_pending_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
190*03f9172cSAndroid Build Coastguard Worker {
191*03f9172cSAndroid Build Coastguard Worker struct wpa_radio_work *work;
192*03f9172cSAndroid Build Coastguard Worker struct wpa_connect_work *cwork;
193*03f9172cSAndroid Build Coastguard Worker
194*03f9172cSAndroid Build Coastguard Worker work = radio_work_pending(wpa_s, "sme-connect");
195*03f9172cSAndroid Build Coastguard Worker if (!work)
196*03f9172cSAndroid Build Coastguard Worker work = radio_work_pending(wpa_s, "connect");
197*03f9172cSAndroid Build Coastguard Worker if (!work)
198*03f9172cSAndroid Build Coastguard Worker return NULL;
199*03f9172cSAndroid Build Coastguard Worker
200*03f9172cSAndroid Build Coastguard Worker cwork = work->ctx;
201*03f9172cSAndroid Build Coastguard Worker if (cwork->bss != bss)
202*03f9172cSAndroid Build Coastguard Worker return NULL;
203*03f9172cSAndroid Build Coastguard Worker
204*03f9172cSAndroid Build Coastguard Worker return cwork;
205*03f9172cSAndroid Build Coastguard Worker }
206*03f9172cSAndroid Build Coastguard Worker
207*03f9172cSAndroid Build Coastguard Worker
wpa_bss_update_pending_connect(struct wpa_connect_work * cwork,struct wpa_bss * new_bss)208*03f9172cSAndroid Build Coastguard Worker static void wpa_bss_update_pending_connect(struct wpa_connect_work *cwork,
209*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *new_bss)
210*03f9172cSAndroid Build Coastguard Worker {
211*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
212*03f9172cSAndroid Build Coastguard Worker "Update BSS pointer for the pending connect radio work");
213*03f9172cSAndroid Build Coastguard Worker cwork->bss = new_bss;
214*03f9172cSAndroid Build Coastguard Worker if (!new_bss)
215*03f9172cSAndroid Build Coastguard Worker cwork->bss_removed = 1;
216*03f9172cSAndroid Build Coastguard Worker }
217*03f9172cSAndroid Build Coastguard Worker
218*03f9172cSAndroid Build Coastguard Worker
wpa_bss_remove(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,const char * reason)219*03f9172cSAndroid Build Coastguard Worker void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
220*03f9172cSAndroid Build Coastguard Worker const char *reason)
221*03f9172cSAndroid Build Coastguard Worker {
222*03f9172cSAndroid Build Coastguard Worker struct wpa_connect_work *cwork;
223*03f9172cSAndroid Build Coastguard Worker
224*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res) {
225*03f9172cSAndroid Build Coastguard Worker unsigned int i;
226*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < wpa_s->last_scan_res_used; i++) {
227*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res[i] == bss) {
228*03f9172cSAndroid Build Coastguard Worker os_memmove(&wpa_s->last_scan_res[i],
229*03f9172cSAndroid Build Coastguard Worker &wpa_s->last_scan_res[i + 1],
230*03f9172cSAndroid Build Coastguard Worker (wpa_s->last_scan_res_used - i - 1)
231*03f9172cSAndroid Build Coastguard Worker * sizeof(struct wpa_bss *));
232*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res_used--;
233*03f9172cSAndroid Build Coastguard Worker break;
234*03f9172cSAndroid Build Coastguard Worker }
235*03f9172cSAndroid Build Coastguard Worker }
236*03f9172cSAndroid Build Coastguard Worker }
237*03f9172cSAndroid Build Coastguard Worker cwork = wpa_bss_check_pending_connect(wpa_s, bss);
238*03f9172cSAndroid Build Coastguard Worker if (cwork)
239*03f9172cSAndroid Build Coastguard Worker wpa_bss_update_pending_connect(cwork, NULL);
240*03f9172cSAndroid Build Coastguard Worker dl_list_del(&bss->list);
241*03f9172cSAndroid Build Coastguard Worker dl_list_del(&bss->list_id);
242*03f9172cSAndroid Build Coastguard Worker wpa_s->num_bss--;
243*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
244*03f9172cSAndroid Build Coastguard Worker " SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
245*03f9172cSAndroid Build Coastguard Worker wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
246*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
247*03f9172cSAndroid Build Coastguard Worker wpa_bss_anqp_free(bss->anqp);
248*03f9172cSAndroid Build Coastguard Worker os_free(bss);
249*03f9172cSAndroid Build Coastguard Worker }
250*03f9172cSAndroid Build Coastguard Worker
251*03f9172cSAndroid Build Coastguard Worker
252*03f9172cSAndroid Build Coastguard Worker /**
253*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
254*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
255*03f9172cSAndroid Build Coastguard Worker * @bssid: BSSID, or %NULL to match any BSSID
256*03f9172cSAndroid Build Coastguard Worker * @ssid: SSID
257*03f9172cSAndroid Build Coastguard Worker * @ssid_len: Length of @ssid
258*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
259*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get(struct wpa_supplicant * wpa_s,const u8 * bssid,const u8 * ssid,size_t ssid_len)260*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
261*03f9172cSAndroid Build Coastguard Worker const u8 *ssid, size_t ssid_len)
262*03f9172cSAndroid Build Coastguard Worker {
263*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
264*03f9172cSAndroid Build Coastguard Worker
265*03f9172cSAndroid Build Coastguard Worker if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid))
266*03f9172cSAndroid Build Coastguard Worker return NULL;
267*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
268*03f9172cSAndroid Build Coastguard Worker if ((!bssid || ether_addr_equal(bss->bssid, bssid)) &&
269*03f9172cSAndroid Build Coastguard Worker bss->ssid_len == ssid_len &&
270*03f9172cSAndroid Build Coastguard Worker os_memcmp(bss->ssid, ssid, ssid_len) == 0)
271*03f9172cSAndroid Build Coastguard Worker return bss;
272*03f9172cSAndroid Build Coastguard Worker }
273*03f9172cSAndroid Build Coastguard Worker return NULL;
274*03f9172cSAndroid Build Coastguard Worker }
275*03f9172cSAndroid Build Coastguard Worker
276*03f9172cSAndroid Build Coastguard Worker /**
277*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_connection - Fetch a BSS table entry based on BSSID and SSID.
278*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
279*03f9172cSAndroid Build Coastguard Worker * @bssid: BSSID, or %NULL to match any BSSID
280*03f9172cSAndroid Build Coastguard Worker * @ssid: SSID
281*03f9172cSAndroid Build Coastguard Worker * @ssid_len: Length of @ssid
282*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
283*03f9172cSAndroid Build Coastguard Worker *
284*03f9172cSAndroid Build Coastguard Worker * This function is similar to wpa_bss_get() but it will also return OWE
285*03f9172cSAndroid Build Coastguard Worker * transition mode encrypted networks for which transition-element matches
286*03f9172cSAndroid Build Coastguard Worker * @ssid.
287*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_connection(struct wpa_supplicant * wpa_s,const u8 * bssid,const u8 * ssid,size_t ssid_len)288*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_connection(struct wpa_supplicant *wpa_s,
289*03f9172cSAndroid Build Coastguard Worker const u8 *bssid,
290*03f9172cSAndroid Build Coastguard Worker const u8 *ssid, size_t ssid_len)
291*03f9172cSAndroid Build Coastguard Worker {
292*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
293*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_OWE
294*03f9172cSAndroid Build Coastguard Worker const u8 *owe, *owe_bssid, *owe_ssid;
295*03f9172cSAndroid Build Coastguard Worker size_t owe_ssid_len;
296*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_OWE */
297*03f9172cSAndroid Build Coastguard Worker
298*03f9172cSAndroid Build Coastguard Worker if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid))
299*03f9172cSAndroid Build Coastguard Worker return NULL;
300*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
301*03f9172cSAndroid Build Coastguard Worker if (bssid && !ether_addr_equal(bss->bssid, bssid))
302*03f9172cSAndroid Build Coastguard Worker continue;
303*03f9172cSAndroid Build Coastguard Worker
304*03f9172cSAndroid Build Coastguard Worker if (bss->ssid_len == ssid_len &&
305*03f9172cSAndroid Build Coastguard Worker os_memcmp(bss->ssid, ssid, ssid_len) == 0)
306*03f9172cSAndroid Build Coastguard Worker return bss;
307*03f9172cSAndroid Build Coastguard Worker
308*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_OWE
309*03f9172cSAndroid Build Coastguard Worker /* Check if OWE transition mode element is present and matches
310*03f9172cSAndroid Build Coastguard Worker * the SSID */
311*03f9172cSAndroid Build Coastguard Worker owe = wpa_bss_get_vendor_ie(bss, OWE_IE_VENDOR_TYPE);
312*03f9172cSAndroid Build Coastguard Worker if (!owe)
313*03f9172cSAndroid Build Coastguard Worker continue;
314*03f9172cSAndroid Build Coastguard Worker
315*03f9172cSAndroid Build Coastguard Worker if (wpas_get_owe_trans_network(owe, &owe_bssid, &owe_ssid,
316*03f9172cSAndroid Build Coastguard Worker &owe_ssid_len))
317*03f9172cSAndroid Build Coastguard Worker continue;
318*03f9172cSAndroid Build Coastguard Worker
319*03f9172cSAndroid Build Coastguard Worker if (owe_ssid_len == ssid_len &&
320*03f9172cSAndroid Build Coastguard Worker os_memcmp(owe_ssid, ssid, ssid_len) == 0)
321*03f9172cSAndroid Build Coastguard Worker return bss;
322*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_OWE */
323*03f9172cSAndroid Build Coastguard Worker }
324*03f9172cSAndroid Build Coastguard Worker return NULL;
325*03f9172cSAndroid Build Coastguard Worker }
326*03f9172cSAndroid Build Coastguard Worker
327*03f9172cSAndroid Build Coastguard Worker
calculate_update_time(const struct os_reltime * fetch_time,unsigned int age_ms,struct os_reltime * update_time)328*03f9172cSAndroid Build Coastguard Worker void calculate_update_time(const struct os_reltime *fetch_time,
329*03f9172cSAndroid Build Coastguard Worker unsigned int age_ms,
330*03f9172cSAndroid Build Coastguard Worker struct os_reltime *update_time)
331*03f9172cSAndroid Build Coastguard Worker {
332*03f9172cSAndroid Build Coastguard Worker os_time_t usec;
333*03f9172cSAndroid Build Coastguard Worker
334*03f9172cSAndroid Build Coastguard Worker update_time->sec = fetch_time->sec;
335*03f9172cSAndroid Build Coastguard Worker update_time->usec = fetch_time->usec;
336*03f9172cSAndroid Build Coastguard Worker update_time->sec -= age_ms / 1000;
337*03f9172cSAndroid Build Coastguard Worker usec = (age_ms % 1000) * 1000;
338*03f9172cSAndroid Build Coastguard Worker if (update_time->usec < usec) {
339*03f9172cSAndroid Build Coastguard Worker update_time->sec--;
340*03f9172cSAndroid Build Coastguard Worker update_time->usec += 1000000;
341*03f9172cSAndroid Build Coastguard Worker }
342*03f9172cSAndroid Build Coastguard Worker update_time->usec -= usec;
343*03f9172cSAndroid Build Coastguard Worker }
344*03f9172cSAndroid Build Coastguard Worker
345*03f9172cSAndroid Build Coastguard Worker
wpa_bss_copy_res(struct wpa_bss * dst,struct wpa_scan_res * src,struct os_reltime * fetch_time)346*03f9172cSAndroid Build Coastguard Worker static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src,
347*03f9172cSAndroid Build Coastguard Worker struct os_reltime *fetch_time)
348*03f9172cSAndroid Build Coastguard Worker {
349*03f9172cSAndroid Build Coastguard Worker dst->flags = src->flags;
350*03f9172cSAndroid Build Coastguard Worker os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
351*03f9172cSAndroid Build Coastguard Worker dst->freq = src->freq;
352*03f9172cSAndroid Build Coastguard Worker dst->max_cw = src->max_cw;
353*03f9172cSAndroid Build Coastguard Worker dst->beacon_int = src->beacon_int;
354*03f9172cSAndroid Build Coastguard Worker dst->caps = src->caps;
355*03f9172cSAndroid Build Coastguard Worker dst->qual = src->qual;
356*03f9172cSAndroid Build Coastguard Worker dst->noise = src->noise;
357*03f9172cSAndroid Build Coastguard Worker dst->level = src->level;
358*03f9172cSAndroid Build Coastguard Worker dst->tsf = src->tsf;
359*03f9172cSAndroid Build Coastguard Worker dst->beacon_newer = src->beacon_newer;
360*03f9172cSAndroid Build Coastguard Worker dst->est_throughput = src->est_throughput;
361*03f9172cSAndroid Build Coastguard Worker dst->snr = src->snr;
362*03f9172cSAndroid Build Coastguard Worker
363*03f9172cSAndroid Build Coastguard Worker calculate_update_time(fetch_time, src->age, &dst->last_update);
364*03f9172cSAndroid Build Coastguard Worker }
365*03f9172cSAndroid Build Coastguard Worker
366*03f9172cSAndroid Build Coastguard Worker
wpa_bss_is_wps_candidate(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)367*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_is_wps_candidate(struct wpa_supplicant *wpa_s,
368*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss)
369*03f9172cSAndroid Build Coastguard Worker {
370*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_WPS
371*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid;
372*03f9172cSAndroid Build Coastguard Worker struct wpabuf *wps_ie;
373*03f9172cSAndroid Build Coastguard Worker int pbc = 0, ret;
374*03f9172cSAndroid Build Coastguard Worker
375*03f9172cSAndroid Build Coastguard Worker wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
376*03f9172cSAndroid Build Coastguard Worker if (!wps_ie)
377*03f9172cSAndroid Build Coastguard Worker return 0;
378*03f9172cSAndroid Build Coastguard Worker
379*03f9172cSAndroid Build Coastguard Worker if (wps_is_selected_pbc_registrar(wps_ie)) {
380*03f9172cSAndroid Build Coastguard Worker pbc = 1;
381*03f9172cSAndroid Build Coastguard Worker } else if (!wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 1)) {
382*03f9172cSAndroid Build Coastguard Worker wpabuf_free(wps_ie);
383*03f9172cSAndroid Build Coastguard Worker return 0;
384*03f9172cSAndroid Build Coastguard Worker }
385*03f9172cSAndroid Build Coastguard Worker
386*03f9172cSAndroid Build Coastguard Worker for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
387*03f9172cSAndroid Build Coastguard Worker if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
388*03f9172cSAndroid Build Coastguard Worker continue;
389*03f9172cSAndroid Build Coastguard Worker if (ssid->ssid_len &&
390*03f9172cSAndroid Build Coastguard Worker (ssid->ssid_len != bss->ssid_len ||
391*03f9172cSAndroid Build Coastguard Worker os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) != 0))
392*03f9172cSAndroid Build Coastguard Worker continue;
393*03f9172cSAndroid Build Coastguard Worker
394*03f9172cSAndroid Build Coastguard Worker if (pbc)
395*03f9172cSAndroid Build Coastguard Worker ret = eap_is_wps_pbc_enrollee(&ssid->eap);
396*03f9172cSAndroid Build Coastguard Worker else
397*03f9172cSAndroid Build Coastguard Worker ret = eap_is_wps_pin_enrollee(&ssid->eap);
398*03f9172cSAndroid Build Coastguard Worker wpabuf_free(wps_ie);
399*03f9172cSAndroid Build Coastguard Worker return ret;
400*03f9172cSAndroid Build Coastguard Worker }
401*03f9172cSAndroid Build Coastguard Worker wpabuf_free(wps_ie);
402*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_WPS */
403*03f9172cSAndroid Build Coastguard Worker
404*03f9172cSAndroid Build Coastguard Worker return 0;
405*03f9172cSAndroid Build Coastguard Worker }
406*03f9172cSAndroid Build Coastguard Worker
407*03f9172cSAndroid Build Coastguard Worker
is_p2p_pending_bss(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)408*03f9172cSAndroid Build Coastguard Worker static bool is_p2p_pending_bss(struct wpa_supplicant *wpa_s,
409*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss)
410*03f9172cSAndroid Build Coastguard Worker {
411*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_P2P
412*03f9172cSAndroid Build Coastguard Worker u8 addr[ETH_ALEN];
413*03f9172cSAndroid Build Coastguard Worker
414*03f9172cSAndroid Build Coastguard Worker if (ether_addr_equal(bss->bssid, wpa_s->pending_join_iface_addr))
415*03f9172cSAndroid Build Coastguard Worker return true;
416*03f9172cSAndroid Build Coastguard Worker if (!is_zero_ether_addr(wpa_s->pending_join_dev_addr) &&
417*03f9172cSAndroid Build Coastguard Worker p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len, addr) == 0 &&
418*03f9172cSAndroid Build Coastguard Worker ether_addr_equal(addr, wpa_s->pending_join_dev_addr))
419*03f9172cSAndroid Build Coastguard Worker return true;
420*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_P2P */
421*03f9172cSAndroid Build Coastguard Worker return false;
422*03f9172cSAndroid Build Coastguard Worker }
423*03f9172cSAndroid Build Coastguard Worker
424*03f9172cSAndroid Build Coastguard Worker
wpa_bss_known(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)425*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
426*03f9172cSAndroid Build Coastguard Worker {
427*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid;
428*03f9172cSAndroid Build Coastguard Worker
429*03f9172cSAndroid Build Coastguard Worker if (is_p2p_pending_bss(wpa_s, bss))
430*03f9172cSAndroid Build Coastguard Worker return 1;
431*03f9172cSAndroid Build Coastguard Worker
432*03f9172cSAndroid Build Coastguard Worker for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
433*03f9172cSAndroid Build Coastguard Worker if (ssid->ssid == NULL || ssid->ssid_len == 0)
434*03f9172cSAndroid Build Coastguard Worker continue;
435*03f9172cSAndroid Build Coastguard Worker if (ssid->ssid_len == bss->ssid_len &&
436*03f9172cSAndroid Build Coastguard Worker os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
437*03f9172cSAndroid Build Coastguard Worker return 1;
438*03f9172cSAndroid Build Coastguard Worker }
439*03f9172cSAndroid Build Coastguard Worker
440*03f9172cSAndroid Build Coastguard Worker return 0;
441*03f9172cSAndroid Build Coastguard Worker }
442*03f9172cSAndroid Build Coastguard Worker
443*03f9172cSAndroid Build Coastguard Worker
wpa_bss_in_use(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)444*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
445*03f9172cSAndroid Build Coastguard Worker {
446*03f9172cSAndroid Build Coastguard Worker int i;
447*03f9172cSAndroid Build Coastguard Worker
448*03f9172cSAndroid Build Coastguard Worker if (bss == wpa_s->current_bss)
449*03f9172cSAndroid Build Coastguard Worker return 1;
450*03f9172cSAndroid Build Coastguard Worker
451*03f9172cSAndroid Build Coastguard Worker if (bss == wpa_s->ml_connect_probe_bss)
452*03f9172cSAndroid Build Coastguard Worker return 1;
453*03f9172cSAndroid Build Coastguard Worker
454*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_WNM
455*03f9172cSAndroid Build Coastguard Worker if (bss == wpa_s->wnm_target_bss)
456*03f9172cSAndroid Build Coastguard Worker return 1;
457*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_WNM */
458*03f9172cSAndroid Build Coastguard Worker
459*03f9172cSAndroid Build Coastguard Worker if (wpa_s->current_bss &&
460*03f9172cSAndroid Build Coastguard Worker (bss->ssid_len != wpa_s->current_bss->ssid_len ||
461*03f9172cSAndroid Build Coastguard Worker os_memcmp(bss->ssid, wpa_s->current_bss->ssid,
462*03f9172cSAndroid Build Coastguard Worker bss->ssid_len) != 0))
463*03f9172cSAndroid Build Coastguard Worker return 0; /* SSID has changed */
464*03f9172cSAndroid Build Coastguard Worker
465*03f9172cSAndroid Build Coastguard Worker if (!is_zero_ether_addr(bss->bssid) &&
466*03f9172cSAndroid Build Coastguard Worker (ether_addr_equal(bss->bssid, wpa_s->bssid) ||
467*03f9172cSAndroid Build Coastguard Worker ether_addr_equal(bss->bssid, wpa_s->pending_bssid)))
468*03f9172cSAndroid Build Coastguard Worker return 1;
469*03f9172cSAndroid Build Coastguard Worker
470*03f9172cSAndroid Build Coastguard Worker if (!wpa_s->valid_links)
471*03f9172cSAndroid Build Coastguard Worker return 0;
472*03f9172cSAndroid Build Coastguard Worker
473*03f9172cSAndroid Build Coastguard Worker for_each_link(wpa_s->valid_links, i) {
474*03f9172cSAndroid Build Coastguard Worker if (ether_addr_equal(bss->bssid, wpa_s->links[i].bssid))
475*03f9172cSAndroid Build Coastguard Worker return 1;
476*03f9172cSAndroid Build Coastguard Worker }
477*03f9172cSAndroid Build Coastguard Worker
478*03f9172cSAndroid Build Coastguard Worker return 0;
479*03f9172cSAndroid Build Coastguard Worker }
480*03f9172cSAndroid Build Coastguard Worker
481*03f9172cSAndroid Build Coastguard Worker
wpa_bss_remove_oldest_unknown(struct wpa_supplicant * wpa_s)482*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
483*03f9172cSAndroid Build Coastguard Worker {
484*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
485*03f9172cSAndroid Build Coastguard Worker
486*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
487*03f9172cSAndroid Build Coastguard Worker if (!wpa_bss_known(wpa_s, bss) &&
488*03f9172cSAndroid Build Coastguard Worker !wpa_bss_is_wps_candidate(wpa_s, bss)) {
489*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove(wpa_s, bss, __func__);
490*03f9172cSAndroid Build Coastguard Worker return 0;
491*03f9172cSAndroid Build Coastguard Worker }
492*03f9172cSAndroid Build Coastguard Worker }
493*03f9172cSAndroid Build Coastguard Worker
494*03f9172cSAndroid Build Coastguard Worker return -1;
495*03f9172cSAndroid Build Coastguard Worker }
496*03f9172cSAndroid Build Coastguard Worker
497*03f9172cSAndroid Build Coastguard Worker
wpa_bss_remove_oldest(struct wpa_supplicant * wpa_s)498*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
499*03f9172cSAndroid Build Coastguard Worker {
500*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
501*03f9172cSAndroid Build Coastguard Worker
502*03f9172cSAndroid Build Coastguard Worker /*
503*03f9172cSAndroid Build Coastguard Worker * Remove the oldest entry that does not match with any configured
504*03f9172cSAndroid Build Coastguard Worker * network.
505*03f9172cSAndroid Build Coastguard Worker */
506*03f9172cSAndroid Build Coastguard Worker if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
507*03f9172cSAndroid Build Coastguard Worker return 0;
508*03f9172cSAndroid Build Coastguard Worker
509*03f9172cSAndroid Build Coastguard Worker /*
510*03f9172cSAndroid Build Coastguard Worker * Remove the oldest entry that isn't currently in use.
511*03f9172cSAndroid Build Coastguard Worker */
512*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
513*03f9172cSAndroid Build Coastguard Worker if (!wpa_bss_in_use(wpa_s, bss)) {
514*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove(wpa_s, bss, __func__);
515*03f9172cSAndroid Build Coastguard Worker return 0;
516*03f9172cSAndroid Build Coastguard Worker }
517*03f9172cSAndroid Build Coastguard Worker }
518*03f9172cSAndroid Build Coastguard Worker
519*03f9172cSAndroid Build Coastguard Worker return -1;
520*03f9172cSAndroid Build Coastguard Worker }
521*03f9172cSAndroid Build Coastguard Worker
522*03f9172cSAndroid Build Coastguard Worker
wpa_bss_add(struct wpa_supplicant * wpa_s,const u8 * ssid,size_t ssid_len,struct wpa_scan_res * res,struct os_reltime * fetch_time)523*03f9172cSAndroid Build Coastguard Worker static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
524*03f9172cSAndroid Build Coastguard Worker const u8 *ssid, size_t ssid_len,
525*03f9172cSAndroid Build Coastguard Worker struct wpa_scan_res *res,
526*03f9172cSAndroid Build Coastguard Worker struct os_reltime *fetch_time)
527*03f9172cSAndroid Build Coastguard Worker {
528*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
529*03f9172cSAndroid Build Coastguard Worker char extra[100];
530*03f9172cSAndroid Build Coastguard Worker const u8 *ml_ie;
531*03f9172cSAndroid Build Coastguard Worker char *pos, *end;
532*03f9172cSAndroid Build Coastguard Worker int ret = 0;
533*03f9172cSAndroid Build Coastguard Worker const u8 *mld_addr;
534*03f9172cSAndroid Build Coastguard Worker
535*03f9172cSAndroid Build Coastguard Worker bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
536*03f9172cSAndroid Build Coastguard Worker if (bss == NULL)
537*03f9172cSAndroid Build Coastguard Worker return NULL;
538*03f9172cSAndroid Build Coastguard Worker bss->id = wpa_s->bss_next_id++;
539*03f9172cSAndroid Build Coastguard Worker bss->last_update_idx = wpa_s->bss_update_idx;
540*03f9172cSAndroid Build Coastguard Worker wpa_bss_copy_res(bss, res, fetch_time);
541*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->ssid, ssid, ssid_len);
542*03f9172cSAndroid Build Coastguard Worker bss->ssid_len = ssid_len;
543*03f9172cSAndroid Build Coastguard Worker bss->ie_len = res->ie_len;
544*03f9172cSAndroid Build Coastguard Worker bss->beacon_ie_len = res->beacon_ie_len;
545*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
546*03f9172cSAndroid Build Coastguard Worker wpa_bss_set_hessid(bss);
547*03f9172cSAndroid Build Coastguard Worker
548*03f9172cSAndroid Build Coastguard Worker os_memset(bss->mld_addr, 0, ETH_ALEN);
549*03f9172cSAndroid Build Coastguard Worker ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
550*03f9172cSAndroid Build Coastguard Worker if (ml_ie) {
551*03f9172cSAndroid Build Coastguard Worker mld_addr = get_basic_mle_mld_addr(&ml_ie[3], ml_ie[1] - 1);
552*03f9172cSAndroid Build Coastguard Worker if (mld_addr)
553*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
554*03f9172cSAndroid Build Coastguard Worker }
555*03f9172cSAndroid Build Coastguard Worker
556*03f9172cSAndroid Build Coastguard Worker if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
557*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove_oldest(wpa_s) != 0) {
558*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
559*03f9172cSAndroid Build Coastguard Worker "because all BSSes are in use. We should normally "
560*03f9172cSAndroid Build Coastguard Worker "not get here!", (int) wpa_s->num_bss + 1);
561*03f9172cSAndroid Build Coastguard Worker wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
562*03f9172cSAndroid Build Coastguard Worker }
563*03f9172cSAndroid Build Coastguard Worker
564*03f9172cSAndroid Build Coastguard Worker dl_list_add_tail(&wpa_s->bss, &bss->list);
565*03f9172cSAndroid Build Coastguard Worker dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
566*03f9172cSAndroid Build Coastguard Worker wpa_s->num_bss++;
567*03f9172cSAndroid Build Coastguard Worker
568*03f9172cSAndroid Build Coastguard Worker extra[0] = '\0';
569*03f9172cSAndroid Build Coastguard Worker pos = extra;
570*03f9172cSAndroid Build Coastguard Worker end = pos + sizeof(extra);
571*03f9172cSAndroid Build Coastguard Worker if (!is_zero_ether_addr(bss->hessid))
572*03f9172cSAndroid Build Coastguard Worker ret = os_snprintf(pos, end - pos, " HESSID " MACSTR,
573*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->hessid));
574*03f9172cSAndroid Build Coastguard Worker
575*03f9172cSAndroid Build Coastguard Worker if (!is_zero_ether_addr(bss->mld_addr) &&
576*03f9172cSAndroid Build Coastguard Worker !os_snprintf_error(end - pos, ret)) {
577*03f9172cSAndroid Build Coastguard Worker pos += ret;
578*03f9172cSAndroid Build Coastguard Worker ret = os_snprintf(pos, end - pos, " MLD ADDR " MACSTR,
579*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->mld_addr));
580*03f9172cSAndroid Build Coastguard Worker }
581*03f9172cSAndroid Build Coastguard Worker
582*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
583*03f9172cSAndroid Build Coastguard Worker " SSID '%s' freq %d%s",
584*03f9172cSAndroid Build Coastguard Worker bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len),
585*03f9172cSAndroid Build Coastguard Worker bss->freq, extra);
586*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
587*03f9172cSAndroid Build Coastguard Worker return bss;
588*03f9172cSAndroid Build Coastguard Worker }
589*03f9172cSAndroid Build Coastguard Worker
590*03f9172cSAndroid Build Coastguard Worker
are_ies_equal(const struct wpa_bss * old,const struct wpa_scan_res * new_res,u32 ie)591*03f9172cSAndroid Build Coastguard Worker static int are_ies_equal(const struct wpa_bss *old,
592*03f9172cSAndroid Build Coastguard Worker const struct wpa_scan_res *new_res, u32 ie)
593*03f9172cSAndroid Build Coastguard Worker {
594*03f9172cSAndroid Build Coastguard Worker const u8 *old_ie, *new_ie;
595*03f9172cSAndroid Build Coastguard Worker struct wpabuf *old_ie_buff = NULL;
596*03f9172cSAndroid Build Coastguard Worker struct wpabuf *new_ie_buff = NULL;
597*03f9172cSAndroid Build Coastguard Worker int new_ie_len, old_ie_len, ret, is_multi;
598*03f9172cSAndroid Build Coastguard Worker
599*03f9172cSAndroid Build Coastguard Worker switch (ie) {
600*03f9172cSAndroid Build Coastguard Worker case WPA_IE_VENDOR_TYPE:
601*03f9172cSAndroid Build Coastguard Worker old_ie = wpa_bss_get_vendor_ie(old, ie);
602*03f9172cSAndroid Build Coastguard Worker new_ie = wpa_scan_get_vendor_ie(new_res, ie);
603*03f9172cSAndroid Build Coastguard Worker is_multi = 0;
604*03f9172cSAndroid Build Coastguard Worker break;
605*03f9172cSAndroid Build Coastguard Worker case WPS_IE_VENDOR_TYPE:
606*03f9172cSAndroid Build Coastguard Worker old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
607*03f9172cSAndroid Build Coastguard Worker new_ie_buff = wpa_scan_get_vendor_ie_multi(new_res, ie);
608*03f9172cSAndroid Build Coastguard Worker is_multi = 1;
609*03f9172cSAndroid Build Coastguard Worker break;
610*03f9172cSAndroid Build Coastguard Worker case WLAN_EID_RSN:
611*03f9172cSAndroid Build Coastguard Worker case WLAN_EID_SUPP_RATES:
612*03f9172cSAndroid Build Coastguard Worker case WLAN_EID_EXT_SUPP_RATES:
613*03f9172cSAndroid Build Coastguard Worker old_ie = wpa_bss_get_ie(old, ie);
614*03f9172cSAndroid Build Coastguard Worker new_ie = wpa_scan_get_ie(new_res, ie);
615*03f9172cSAndroid Build Coastguard Worker is_multi = 0;
616*03f9172cSAndroid Build Coastguard Worker break;
617*03f9172cSAndroid Build Coastguard Worker default:
618*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
619*03f9172cSAndroid Build Coastguard Worker return 0;
620*03f9172cSAndroid Build Coastguard Worker }
621*03f9172cSAndroid Build Coastguard Worker
622*03f9172cSAndroid Build Coastguard Worker if (is_multi) {
623*03f9172cSAndroid Build Coastguard Worker /* in case of multiple IEs stored in buffer */
624*03f9172cSAndroid Build Coastguard Worker old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
625*03f9172cSAndroid Build Coastguard Worker new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
626*03f9172cSAndroid Build Coastguard Worker old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
627*03f9172cSAndroid Build Coastguard Worker new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
628*03f9172cSAndroid Build Coastguard Worker } else {
629*03f9172cSAndroid Build Coastguard Worker /* in case of single IE */
630*03f9172cSAndroid Build Coastguard Worker old_ie_len = old_ie ? old_ie[1] + 2 : 0;
631*03f9172cSAndroid Build Coastguard Worker new_ie_len = new_ie ? new_ie[1] + 2 : 0;
632*03f9172cSAndroid Build Coastguard Worker }
633*03f9172cSAndroid Build Coastguard Worker
634*03f9172cSAndroid Build Coastguard Worker if (!old_ie || !new_ie)
635*03f9172cSAndroid Build Coastguard Worker ret = !old_ie && !new_ie;
636*03f9172cSAndroid Build Coastguard Worker else
637*03f9172cSAndroid Build Coastguard Worker ret = (old_ie_len == new_ie_len &&
638*03f9172cSAndroid Build Coastguard Worker os_memcmp(old_ie, new_ie, old_ie_len) == 0);
639*03f9172cSAndroid Build Coastguard Worker
640*03f9172cSAndroid Build Coastguard Worker wpabuf_free(old_ie_buff);
641*03f9172cSAndroid Build Coastguard Worker wpabuf_free(new_ie_buff);
642*03f9172cSAndroid Build Coastguard Worker
643*03f9172cSAndroid Build Coastguard Worker return ret;
644*03f9172cSAndroid Build Coastguard Worker }
645*03f9172cSAndroid Build Coastguard Worker
646*03f9172cSAndroid Build Coastguard Worker
wpa_bss_compare_res(const struct wpa_bss * old,const struct wpa_scan_res * new_res)647*03f9172cSAndroid Build Coastguard Worker static u32 wpa_bss_compare_res(const struct wpa_bss *old,
648*03f9172cSAndroid Build Coastguard Worker const struct wpa_scan_res *new_res)
649*03f9172cSAndroid Build Coastguard Worker {
650*03f9172cSAndroid Build Coastguard Worker u32 changes = 0;
651*03f9172cSAndroid Build Coastguard Worker int caps_diff = old->caps ^ new_res->caps;
652*03f9172cSAndroid Build Coastguard Worker
653*03f9172cSAndroid Build Coastguard Worker if (old->freq != new_res->freq)
654*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_FREQ_CHANGED_FLAG;
655*03f9172cSAndroid Build Coastguard Worker
656*03f9172cSAndroid Build Coastguard Worker if (old->level != new_res->level)
657*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
658*03f9172cSAndroid Build Coastguard Worker
659*03f9172cSAndroid Build Coastguard Worker if (caps_diff & IEEE80211_CAP_PRIVACY)
660*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
661*03f9172cSAndroid Build Coastguard Worker
662*03f9172cSAndroid Build Coastguard Worker if (caps_diff & IEEE80211_CAP_IBSS)
663*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_MODE_CHANGED_FLAG;
664*03f9172cSAndroid Build Coastguard Worker
665*03f9172cSAndroid Build Coastguard Worker if (old->ie_len == new_res->ie_len &&
666*03f9172cSAndroid Build Coastguard Worker os_memcmp(wpa_bss_ie_ptr(old), new_res + 1, old->ie_len) == 0)
667*03f9172cSAndroid Build Coastguard Worker return changes;
668*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_IES_CHANGED_FLAG;
669*03f9172cSAndroid Build Coastguard Worker
670*03f9172cSAndroid Build Coastguard Worker if (!are_ies_equal(old, new_res, WPA_IE_VENDOR_TYPE))
671*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
672*03f9172cSAndroid Build Coastguard Worker
673*03f9172cSAndroid Build Coastguard Worker if (!are_ies_equal(old, new_res, WLAN_EID_RSN))
674*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
675*03f9172cSAndroid Build Coastguard Worker
676*03f9172cSAndroid Build Coastguard Worker if (!are_ies_equal(old, new_res, WPS_IE_VENDOR_TYPE))
677*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_WPS_CHANGED_FLAG;
678*03f9172cSAndroid Build Coastguard Worker
679*03f9172cSAndroid Build Coastguard Worker if (!are_ies_equal(old, new_res, WLAN_EID_SUPP_RATES) ||
680*03f9172cSAndroid Build Coastguard Worker !are_ies_equal(old, new_res, WLAN_EID_EXT_SUPP_RATES))
681*03f9172cSAndroid Build Coastguard Worker changes |= WPA_BSS_RATES_CHANGED_FLAG;
682*03f9172cSAndroid Build Coastguard Worker
683*03f9172cSAndroid Build Coastguard Worker return changes;
684*03f9172cSAndroid Build Coastguard Worker }
685*03f9172cSAndroid Build Coastguard Worker
686*03f9172cSAndroid Build Coastguard Worker
notify_bss_changes(struct wpa_supplicant * wpa_s,u32 changes,const struct wpa_bss * bss)687*03f9172cSAndroid Build Coastguard Worker void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
688*03f9172cSAndroid Build Coastguard Worker const struct wpa_bss *bss)
689*03f9172cSAndroid Build Coastguard Worker {
690*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
691*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_freq_changed(wpa_s, bss->id);
692*03f9172cSAndroid Build Coastguard Worker
693*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
694*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_signal_changed(wpa_s, bss->id);
695*03f9172cSAndroid Build Coastguard Worker
696*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
697*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_privacy_changed(wpa_s, bss->id);
698*03f9172cSAndroid Build Coastguard Worker
699*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_MODE_CHANGED_FLAG)
700*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_mode_changed(wpa_s, bss->id);
701*03f9172cSAndroid Build Coastguard Worker
702*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
703*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
704*03f9172cSAndroid Build Coastguard Worker
705*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
706*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
707*03f9172cSAndroid Build Coastguard Worker
708*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_WPS_CHANGED_FLAG)
709*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_wps_changed(wpa_s, bss->id);
710*03f9172cSAndroid Build Coastguard Worker
711*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_IES_CHANGED_FLAG)
712*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_ies_changed(wpa_s, bss->id);
713*03f9172cSAndroid Build Coastguard Worker
714*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_RATES_CHANGED_FLAG)
715*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_rates_changed(wpa_s, bss->id);
716*03f9172cSAndroid Build Coastguard Worker
717*03f9172cSAndroid Build Coastguard Worker wpas_notify_bss_seen(wpa_s, bss->id);
718*03f9172cSAndroid Build Coastguard Worker }
719*03f9172cSAndroid Build Coastguard Worker
720*03f9172cSAndroid Build Coastguard Worker
721*03f9172cSAndroid Build Coastguard Worker static struct wpa_bss *
wpa_bss_update(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,struct wpa_scan_res * res,struct os_reltime * fetch_time)722*03f9172cSAndroid Build Coastguard Worker wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
723*03f9172cSAndroid Build Coastguard Worker struct wpa_scan_res *res, struct os_reltime *fetch_time)
724*03f9172cSAndroid Build Coastguard Worker {
725*03f9172cSAndroid Build Coastguard Worker u32 changes;
726*03f9172cSAndroid Build Coastguard Worker
727*03f9172cSAndroid Build Coastguard Worker if (bss->last_update_idx == wpa_s->bss_update_idx) {
728*03f9172cSAndroid Build Coastguard Worker struct os_reltime update_time;
729*03f9172cSAndroid Build Coastguard Worker
730*03f9172cSAndroid Build Coastguard Worker /*
731*03f9172cSAndroid Build Coastguard Worker * Some drivers (e.g., cfg80211) include multiple BSS entries
732*03f9172cSAndroid Build Coastguard Worker * for the same BSS if that BSS's channel changes. The BSS list
733*03f9172cSAndroid Build Coastguard Worker * implementation in wpa_supplicant does not do that and we need
734*03f9172cSAndroid Build Coastguard Worker * to filter out the obsolete results here to make sure only the
735*03f9172cSAndroid Build Coastguard Worker * most current BSS information remains in the table.
736*03f9172cSAndroid Build Coastguard Worker */
737*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS: " MACSTR
738*03f9172cSAndroid Build Coastguard Worker " has multiple entries in the scan results - select the most current one",
739*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid));
740*03f9172cSAndroid Build Coastguard Worker calculate_update_time(fetch_time, res->age, &update_time);
741*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
742*03f9172cSAndroid Build Coastguard Worker "Previous last_update: %u.%06u (freq %d%s)",
743*03f9172cSAndroid Build Coastguard Worker (unsigned int) bss->last_update.sec,
744*03f9172cSAndroid Build Coastguard Worker (unsigned int) bss->last_update.usec,
745*03f9172cSAndroid Build Coastguard Worker bss->freq,
746*03f9172cSAndroid Build Coastguard Worker (bss->flags & WPA_BSS_ASSOCIATED) ? " assoc" : "");
747*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "New last_update: %u.%06u (freq %d%s)",
748*03f9172cSAndroid Build Coastguard Worker (unsigned int) update_time.sec,
749*03f9172cSAndroid Build Coastguard Worker (unsigned int) update_time.usec,
750*03f9172cSAndroid Build Coastguard Worker res->freq,
751*03f9172cSAndroid Build Coastguard Worker (res->flags & WPA_SCAN_ASSOCIATED) ? " assoc" : "");
752*03f9172cSAndroid Build Coastguard Worker if ((bss->flags & WPA_BSS_ASSOCIATED) ||
753*03f9172cSAndroid Build Coastguard Worker (!(res->flags & WPA_SCAN_ASSOCIATED) &&
754*03f9172cSAndroid Build Coastguard Worker !os_reltime_before(&bss->last_update, &update_time))) {
755*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
756*03f9172cSAndroid Build Coastguard Worker "Ignore this BSS entry since the previous update looks more current");
757*03f9172cSAndroid Build Coastguard Worker return bss;
758*03f9172cSAndroid Build Coastguard Worker }
759*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
760*03f9172cSAndroid Build Coastguard Worker "Accept this BSS entry since it looks more current than the previous update");
761*03f9172cSAndroid Build Coastguard Worker }
762*03f9172cSAndroid Build Coastguard Worker
763*03f9172cSAndroid Build Coastguard Worker changes = wpa_bss_compare_res(bss, res);
764*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
765*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS: " MACSTR " changed freq %d --> %d",
766*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid), bss->freq, res->freq);
767*03f9172cSAndroid Build Coastguard Worker bss->scan_miss_count = 0;
768*03f9172cSAndroid Build Coastguard Worker bss->last_update_idx = wpa_s->bss_update_idx;
769*03f9172cSAndroid Build Coastguard Worker wpa_bss_copy_res(bss, res, fetch_time);
770*03f9172cSAndroid Build Coastguard Worker /* Move the entry to the end of the list */
771*03f9172cSAndroid Build Coastguard Worker dl_list_del(&bss->list);
772*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_P2P
773*03f9172cSAndroid Build Coastguard Worker if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) &&
774*03f9172cSAndroid Build Coastguard Worker !wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE) &&
775*03f9172cSAndroid Build Coastguard Worker !(changes & WPA_BSS_FREQ_CHANGED_FLAG)) {
776*03f9172cSAndroid Build Coastguard Worker /*
777*03f9172cSAndroid Build Coastguard Worker * This can happen when non-P2P station interface runs a scan
778*03f9172cSAndroid Build Coastguard Worker * without P2P IE in the Probe Request frame. P2P GO would reply
779*03f9172cSAndroid Build Coastguard Worker * to that with a Probe Response that does not include P2P IE.
780*03f9172cSAndroid Build Coastguard Worker * Do not update the IEs in this BSS entry to avoid such loss of
781*03f9172cSAndroid Build Coastguard Worker * information that may be needed for P2P operations to
782*03f9172cSAndroid Build Coastguard Worker * determine group information.
783*03f9172cSAndroid Build Coastguard Worker */
784*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Do not update scan IEs for "
785*03f9172cSAndroid Build Coastguard Worker MACSTR " since that would remove P2P IE information",
786*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid));
787*03f9172cSAndroid Build Coastguard Worker } else
788*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_P2P */
789*03f9172cSAndroid Build Coastguard Worker if (bss->ie_len + bss->beacon_ie_len >=
790*03f9172cSAndroid Build Coastguard Worker res->ie_len + res->beacon_ie_len) {
791*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->ies, res + 1, res->ie_len + res->beacon_ie_len);
792*03f9172cSAndroid Build Coastguard Worker bss->ie_len = res->ie_len;
793*03f9172cSAndroid Build Coastguard Worker bss->beacon_ie_len = res->beacon_ie_len;
794*03f9172cSAndroid Build Coastguard Worker } else {
795*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *nbss;
796*03f9172cSAndroid Build Coastguard Worker struct dl_list *prev = bss->list_id.prev;
797*03f9172cSAndroid Build Coastguard Worker struct wpa_connect_work *cwork;
798*03f9172cSAndroid Build Coastguard Worker unsigned int i;
799*03f9172cSAndroid Build Coastguard Worker bool update_current_bss = wpa_s->current_bss == bss;
800*03f9172cSAndroid Build Coastguard Worker bool update_ml_probe_bss = wpa_s->ml_connect_probe_bss == bss;
801*03f9172cSAndroid Build Coastguard Worker
802*03f9172cSAndroid Build Coastguard Worker cwork = wpa_bss_check_pending_connect(wpa_s, bss);
803*03f9172cSAndroid Build Coastguard Worker
804*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < wpa_s->last_scan_res_used; i++) {
805*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res[i] == bss)
806*03f9172cSAndroid Build Coastguard Worker break;
807*03f9172cSAndroid Build Coastguard Worker }
808*03f9172cSAndroid Build Coastguard Worker
809*03f9172cSAndroid Build Coastguard Worker dl_list_del(&bss->list_id);
810*03f9172cSAndroid Build Coastguard Worker nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
811*03f9172cSAndroid Build Coastguard Worker res->beacon_ie_len);
812*03f9172cSAndroid Build Coastguard Worker if (nbss) {
813*03f9172cSAndroid Build Coastguard Worker if (i != wpa_s->last_scan_res_used)
814*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res[i] = nbss;
815*03f9172cSAndroid Build Coastguard Worker
816*03f9172cSAndroid Build Coastguard Worker if (update_current_bss)
817*03f9172cSAndroid Build Coastguard Worker wpa_s->current_bss = nbss;
818*03f9172cSAndroid Build Coastguard Worker
819*03f9172cSAndroid Build Coastguard Worker if (update_ml_probe_bss)
820*03f9172cSAndroid Build Coastguard Worker wpa_s->ml_connect_probe_bss = nbss;
821*03f9172cSAndroid Build Coastguard Worker
822*03f9172cSAndroid Build Coastguard Worker if (cwork)
823*03f9172cSAndroid Build Coastguard Worker wpa_bss_update_pending_connect(cwork, nbss);
824*03f9172cSAndroid Build Coastguard Worker
825*03f9172cSAndroid Build Coastguard Worker bss = nbss;
826*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->ies, res + 1,
827*03f9172cSAndroid Build Coastguard Worker res->ie_len + res->beacon_ie_len);
828*03f9172cSAndroid Build Coastguard Worker bss->ie_len = res->ie_len;
829*03f9172cSAndroid Build Coastguard Worker bss->beacon_ie_len = res->beacon_ie_len;
830*03f9172cSAndroid Build Coastguard Worker }
831*03f9172cSAndroid Build Coastguard Worker dl_list_add(prev, &bss->list_id);
832*03f9172cSAndroid Build Coastguard Worker }
833*03f9172cSAndroid Build Coastguard Worker if (changes & WPA_BSS_IES_CHANGED_FLAG) {
834*03f9172cSAndroid Build Coastguard Worker const u8 *ml_ie, *mld_addr;
835*03f9172cSAndroid Build Coastguard Worker
836*03f9172cSAndroid Build Coastguard Worker wpa_bss_set_hessid(bss);
837*03f9172cSAndroid Build Coastguard Worker os_memset(bss->mld_addr, 0, ETH_ALEN);
838*03f9172cSAndroid Build Coastguard Worker ml_ie = wpa_scan_get_ml_ie(res, MULTI_LINK_CONTROL_TYPE_BASIC);
839*03f9172cSAndroid Build Coastguard Worker if (ml_ie) {
840*03f9172cSAndroid Build Coastguard Worker mld_addr = get_basic_mle_mld_addr(&ml_ie[3],
841*03f9172cSAndroid Build Coastguard Worker ml_ie[1] - 1);
842*03f9172cSAndroid Build Coastguard Worker if (mld_addr)
843*03f9172cSAndroid Build Coastguard Worker os_memcpy(bss->mld_addr, mld_addr, ETH_ALEN);
844*03f9172cSAndroid Build Coastguard Worker }
845*03f9172cSAndroid Build Coastguard Worker }
846*03f9172cSAndroid Build Coastguard Worker dl_list_add_tail(&wpa_s->bss, &bss->list);
847*03f9172cSAndroid Build Coastguard Worker
848*03f9172cSAndroid Build Coastguard Worker notify_bss_changes(wpa_s, changes, bss);
849*03f9172cSAndroid Build Coastguard Worker
850*03f9172cSAndroid Build Coastguard Worker return bss;
851*03f9172cSAndroid Build Coastguard Worker }
852*03f9172cSAndroid Build Coastguard Worker
853*03f9172cSAndroid Build Coastguard Worker
854*03f9172cSAndroid Build Coastguard Worker /**
855*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_start - Start a BSS table update from scan results
856*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
857*03f9172cSAndroid Build Coastguard Worker *
858*03f9172cSAndroid Build Coastguard Worker * This function is called at the start of each BSS table update round for new
859*03f9172cSAndroid Build Coastguard Worker * scan results. The actual scan result entries are indicated with calls to
860*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_scan_res() and the update round is finished with a call to
861*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_end().
862*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_update_start(struct wpa_supplicant * wpa_s)863*03f9172cSAndroid Build Coastguard Worker void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
864*03f9172cSAndroid Build Coastguard Worker {
865*03f9172cSAndroid Build Coastguard Worker wpa_s->bss_update_idx++;
866*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
867*03f9172cSAndroid Build Coastguard Worker wpa_s->bss_update_idx);
868*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res_used = 0;
869*03f9172cSAndroid Build Coastguard Worker }
870*03f9172cSAndroid Build Coastguard Worker
871*03f9172cSAndroid Build Coastguard Worker
872*03f9172cSAndroid Build Coastguard Worker /**
873*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
874*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
875*03f9172cSAndroid Build Coastguard Worker * @res: Scan result
876*03f9172cSAndroid Build Coastguard Worker * @fetch_time: Time when the result was fetched from the driver
877*03f9172cSAndroid Build Coastguard Worker *
878*03f9172cSAndroid Build Coastguard Worker * This function updates a BSS table entry (or adds one) based on a scan result.
879*03f9172cSAndroid Build Coastguard Worker * This is called separately for each scan result between the calls to
880*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_start() and wpa_bss_update_end().
881*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_update_scan_res(struct wpa_supplicant * wpa_s,struct wpa_scan_res * res,struct os_reltime * fetch_time)882*03f9172cSAndroid Build Coastguard Worker void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
883*03f9172cSAndroid Build Coastguard Worker struct wpa_scan_res *res,
884*03f9172cSAndroid Build Coastguard Worker struct os_reltime *fetch_time)
885*03f9172cSAndroid Build Coastguard Worker {
886*03f9172cSAndroid Build Coastguard Worker const u8 *ssid, *p2p, *mesh;
887*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
888*03f9172cSAndroid Build Coastguard Worker
889*03f9172cSAndroid Build Coastguard Worker if (wpa_s->conf->ignore_old_scan_res) {
890*03f9172cSAndroid Build Coastguard Worker struct os_reltime update;
891*03f9172cSAndroid Build Coastguard Worker calculate_update_time(fetch_time, res->age, &update);
892*03f9172cSAndroid Build Coastguard Worker if (os_reltime_before(&update, &wpa_s->scan_trigger_time)) {
893*03f9172cSAndroid Build Coastguard Worker struct os_reltime age;
894*03f9172cSAndroid Build Coastguard Worker os_reltime_sub(&wpa_s->scan_trigger_time, &update,
895*03f9172cSAndroid Build Coastguard Worker &age);
896*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Ignore driver BSS "
897*03f9172cSAndroid Build Coastguard Worker "table entry that is %u.%06u seconds older "
898*03f9172cSAndroid Build Coastguard Worker "than our scan trigger",
899*03f9172cSAndroid Build Coastguard Worker (unsigned int) age.sec,
900*03f9172cSAndroid Build Coastguard Worker (unsigned int) age.usec);
901*03f9172cSAndroid Build Coastguard Worker return;
902*03f9172cSAndroid Build Coastguard Worker }
903*03f9172cSAndroid Build Coastguard Worker }
904*03f9172cSAndroid Build Coastguard Worker
905*03f9172cSAndroid Build Coastguard Worker ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
906*03f9172cSAndroid Build Coastguard Worker if (ssid == NULL) {
907*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
908*03f9172cSAndroid Build Coastguard Worker MACSTR, MAC2STR(res->bssid));
909*03f9172cSAndroid Build Coastguard Worker return;
910*03f9172cSAndroid Build Coastguard Worker }
911*03f9172cSAndroid Build Coastguard Worker if (ssid[1] > SSID_MAX_LEN) {
912*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
913*03f9172cSAndroid Build Coastguard Worker MACSTR, MAC2STR(res->bssid));
914*03f9172cSAndroid Build Coastguard Worker return;
915*03f9172cSAndroid Build Coastguard Worker }
916*03f9172cSAndroid Build Coastguard Worker
917*03f9172cSAndroid Build Coastguard Worker p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
918*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_P2P
919*03f9172cSAndroid Build Coastguard Worker if (p2p == NULL &&
920*03f9172cSAndroid Build Coastguard Worker wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
921*03f9172cSAndroid Build Coastguard Worker /*
922*03f9172cSAndroid Build Coastguard Worker * If it's a P2P specific interface, then don't update
923*03f9172cSAndroid Build Coastguard Worker * the scan result without a P2P IE.
924*03f9172cSAndroid Build Coastguard Worker */
925*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
926*03f9172cSAndroid Build Coastguard Worker " update for P2P interface", MAC2STR(res->bssid));
927*03f9172cSAndroid Build Coastguard Worker return;
928*03f9172cSAndroid Build Coastguard Worker }
929*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_P2P */
930*03f9172cSAndroid Build Coastguard Worker if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
931*03f9172cSAndroid Build Coastguard Worker os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
932*03f9172cSAndroid Build Coastguard Worker return; /* Skip P2P listen discovery results here */
933*03f9172cSAndroid Build Coastguard Worker
934*03f9172cSAndroid Build Coastguard Worker /* TODO: add option for ignoring BSSes we are not interested in
935*03f9172cSAndroid Build Coastguard Worker * (to save memory) */
936*03f9172cSAndroid Build Coastguard Worker
937*03f9172cSAndroid Build Coastguard Worker mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
938*03f9172cSAndroid Build Coastguard Worker if (mesh && mesh[1] <= SSID_MAX_LEN)
939*03f9172cSAndroid Build Coastguard Worker ssid = mesh;
940*03f9172cSAndroid Build Coastguard Worker
941*03f9172cSAndroid Build Coastguard Worker bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
942*03f9172cSAndroid Build Coastguard Worker if (bss == NULL)
943*03f9172cSAndroid Build Coastguard Worker bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
944*03f9172cSAndroid Build Coastguard Worker else {
945*03f9172cSAndroid Build Coastguard Worker bss = wpa_bss_update(wpa_s, bss, res, fetch_time);
946*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res) {
947*03f9172cSAndroid Build Coastguard Worker unsigned int i;
948*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < wpa_s->last_scan_res_used; i++) {
949*03f9172cSAndroid Build Coastguard Worker if (bss == wpa_s->last_scan_res[i]) {
950*03f9172cSAndroid Build Coastguard Worker /* Already in the list */
951*03f9172cSAndroid Build Coastguard Worker return;
952*03f9172cSAndroid Build Coastguard Worker }
953*03f9172cSAndroid Build Coastguard Worker }
954*03f9172cSAndroid Build Coastguard Worker }
955*03f9172cSAndroid Build Coastguard Worker }
956*03f9172cSAndroid Build Coastguard Worker
957*03f9172cSAndroid Build Coastguard Worker if (bss == NULL)
958*03f9172cSAndroid Build Coastguard Worker return;
959*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
960*03f9172cSAndroid Build Coastguard Worker struct wpa_bss **n;
961*03f9172cSAndroid Build Coastguard Worker unsigned int siz;
962*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res_size == 0)
963*03f9172cSAndroid Build Coastguard Worker siz = 32;
964*03f9172cSAndroid Build Coastguard Worker else
965*03f9172cSAndroid Build Coastguard Worker siz = wpa_s->last_scan_res_size * 2;
966*03f9172cSAndroid Build Coastguard Worker n = os_realloc_array(wpa_s->last_scan_res, siz,
967*03f9172cSAndroid Build Coastguard Worker sizeof(struct wpa_bss *));
968*03f9172cSAndroid Build Coastguard Worker if (n == NULL)
969*03f9172cSAndroid Build Coastguard Worker return;
970*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res = n;
971*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res_size = siz;
972*03f9172cSAndroid Build Coastguard Worker }
973*03f9172cSAndroid Build Coastguard Worker
974*03f9172cSAndroid Build Coastguard Worker if (wpa_s->last_scan_res)
975*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
976*03f9172cSAndroid Build Coastguard Worker }
977*03f9172cSAndroid Build Coastguard Worker
978*03f9172cSAndroid Build Coastguard Worker
wpa_bss_included_in_scan(const struct wpa_bss * bss,const struct scan_info * info)979*03f9172cSAndroid Build Coastguard Worker static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
980*03f9172cSAndroid Build Coastguard Worker const struct scan_info *info)
981*03f9172cSAndroid Build Coastguard Worker {
982*03f9172cSAndroid Build Coastguard Worker int found;
983*03f9172cSAndroid Build Coastguard Worker size_t i;
984*03f9172cSAndroid Build Coastguard Worker
985*03f9172cSAndroid Build Coastguard Worker if (info == NULL)
986*03f9172cSAndroid Build Coastguard Worker return 1;
987*03f9172cSAndroid Build Coastguard Worker
988*03f9172cSAndroid Build Coastguard Worker if (info->num_freqs) {
989*03f9172cSAndroid Build Coastguard Worker found = 0;
990*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < info->num_freqs; i++) {
991*03f9172cSAndroid Build Coastguard Worker if (bss->freq == info->freqs[i]) {
992*03f9172cSAndroid Build Coastguard Worker found = 1;
993*03f9172cSAndroid Build Coastguard Worker break;
994*03f9172cSAndroid Build Coastguard Worker }
995*03f9172cSAndroid Build Coastguard Worker }
996*03f9172cSAndroid Build Coastguard Worker if (!found)
997*03f9172cSAndroid Build Coastguard Worker return 0;
998*03f9172cSAndroid Build Coastguard Worker }
999*03f9172cSAndroid Build Coastguard Worker
1000*03f9172cSAndroid Build Coastguard Worker if (info->num_ssids) {
1001*03f9172cSAndroid Build Coastguard Worker found = 0;
1002*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < info->num_ssids; i++) {
1003*03f9172cSAndroid Build Coastguard Worker const struct wpa_driver_scan_ssid *s = &info->ssids[i];
1004*03f9172cSAndroid Build Coastguard Worker if ((s->ssid == NULL || s->ssid_len == 0) ||
1005*03f9172cSAndroid Build Coastguard Worker (s->ssid_len == bss->ssid_len &&
1006*03f9172cSAndroid Build Coastguard Worker os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
1007*03f9172cSAndroid Build Coastguard Worker 0)) {
1008*03f9172cSAndroid Build Coastguard Worker found = 1;
1009*03f9172cSAndroid Build Coastguard Worker break;
1010*03f9172cSAndroid Build Coastguard Worker }
1011*03f9172cSAndroid Build Coastguard Worker }
1012*03f9172cSAndroid Build Coastguard Worker if (!found)
1013*03f9172cSAndroid Build Coastguard Worker return 0;
1014*03f9172cSAndroid Build Coastguard Worker }
1015*03f9172cSAndroid Build Coastguard Worker
1016*03f9172cSAndroid Build Coastguard Worker return 1;
1017*03f9172cSAndroid Build Coastguard Worker }
1018*03f9172cSAndroid Build Coastguard Worker
1019*03f9172cSAndroid Build Coastguard Worker
1020*03f9172cSAndroid Build Coastguard Worker /**
1021*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_end - End a BSS table update from scan results
1022*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1023*03f9172cSAndroid Build Coastguard Worker * @info: Information about scan parameters
1024*03f9172cSAndroid Build Coastguard Worker * @new_scan: Whether this update round was based on a new scan
1025*03f9172cSAndroid Build Coastguard Worker *
1026*03f9172cSAndroid Build Coastguard Worker * This function is called at the end of each BSS table update round for new
1027*03f9172cSAndroid Build Coastguard Worker * scan results. The start of the update was indicated with a call to
1028*03f9172cSAndroid Build Coastguard Worker * wpa_bss_update_start().
1029*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_update_end(struct wpa_supplicant * wpa_s,struct scan_info * info,int new_scan)1030*03f9172cSAndroid Build Coastguard Worker void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
1031*03f9172cSAndroid Build Coastguard Worker int new_scan)
1032*03f9172cSAndroid Build Coastguard Worker {
1033*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, *n;
1034*03f9172cSAndroid Build Coastguard Worker
1035*03f9172cSAndroid Build Coastguard Worker os_get_reltime(&wpa_s->last_scan);
1036*03f9172cSAndroid Build Coastguard Worker if ((info && info->aborted) || !new_scan)
1037*03f9172cSAndroid Build Coastguard Worker return; /* do not expire entries without new scan */
1038*03f9172cSAndroid Build Coastguard Worker
1039*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
1040*03f9172cSAndroid Build Coastguard Worker if (wpa_bss_in_use(wpa_s, bss))
1041*03f9172cSAndroid Build Coastguard Worker continue;
1042*03f9172cSAndroid Build Coastguard Worker if (!wpa_bss_included_in_scan(bss, info))
1043*03f9172cSAndroid Build Coastguard Worker continue; /* expire only BSSes that were scanned */
1044*03f9172cSAndroid Build Coastguard Worker if (bss->last_update_idx < wpa_s->bss_update_idx)
1045*03f9172cSAndroid Build Coastguard Worker bss->scan_miss_count++;
1046*03f9172cSAndroid Build Coastguard Worker if (bss->scan_miss_count >=
1047*03f9172cSAndroid Build Coastguard Worker wpa_s->conf->bss_expiration_scan_count) {
1048*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove(wpa_s, bss, "no match in scan");
1049*03f9172cSAndroid Build Coastguard Worker }
1050*03f9172cSAndroid Build Coastguard Worker }
1051*03f9172cSAndroid Build Coastguard Worker
1052*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%zu/%zu",
1053*03f9172cSAndroid Build Coastguard Worker wpa_s->last_scan_res_used, wpa_s->last_scan_res_size);
1054*03f9172cSAndroid Build Coastguard Worker }
1055*03f9172cSAndroid Build Coastguard Worker
1056*03f9172cSAndroid Build Coastguard Worker
1057*03f9172cSAndroid Build Coastguard Worker /**
1058*03f9172cSAndroid Build Coastguard Worker * wpa_bss_flush_by_age - Flush old BSS entries
1059*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1060*03f9172cSAndroid Build Coastguard Worker * @age: Maximum entry age in seconds
1061*03f9172cSAndroid Build Coastguard Worker *
1062*03f9172cSAndroid Build Coastguard Worker * Remove BSS entries that have not been updated during the last @age seconds.
1063*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_flush_by_age(struct wpa_supplicant * wpa_s,int age)1064*03f9172cSAndroid Build Coastguard Worker void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
1065*03f9172cSAndroid Build Coastguard Worker {
1066*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, *n;
1067*03f9172cSAndroid Build Coastguard Worker struct os_reltime t;
1068*03f9172cSAndroid Build Coastguard Worker
1069*03f9172cSAndroid Build Coastguard Worker if (dl_list_empty(&wpa_s->bss))
1070*03f9172cSAndroid Build Coastguard Worker return;
1071*03f9172cSAndroid Build Coastguard Worker
1072*03f9172cSAndroid Build Coastguard Worker os_get_reltime(&t);
1073*03f9172cSAndroid Build Coastguard Worker
1074*03f9172cSAndroid Build Coastguard Worker if (t.sec < age)
1075*03f9172cSAndroid Build Coastguard Worker return; /* avoid underflow; there can be no older entries */
1076*03f9172cSAndroid Build Coastguard Worker
1077*03f9172cSAndroid Build Coastguard Worker t.sec -= age;
1078*03f9172cSAndroid Build Coastguard Worker
1079*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
1080*03f9172cSAndroid Build Coastguard Worker if (wpa_bss_in_use(wpa_s, bss))
1081*03f9172cSAndroid Build Coastguard Worker continue;
1082*03f9172cSAndroid Build Coastguard Worker
1083*03f9172cSAndroid Build Coastguard Worker if (wpa_s->reassoc_same_ess &&
1084*03f9172cSAndroid Build Coastguard Worker wpa_s->wpa_state != WPA_COMPLETED &&
1085*03f9172cSAndroid Build Coastguard Worker wpa_s->last_ssid &&
1086*03f9172cSAndroid Build Coastguard Worker bss->ssid_len == wpa_s->last_ssid->ssid_len &&
1087*03f9172cSAndroid Build Coastguard Worker os_memcmp(bss->ssid, wpa_s->last_ssid->ssid,
1088*03f9172cSAndroid Build Coastguard Worker bss->ssid_len) == 0)
1089*03f9172cSAndroid Build Coastguard Worker continue;
1090*03f9172cSAndroid Build Coastguard Worker
1091*03f9172cSAndroid Build Coastguard Worker if (os_reltime_before(&bss->last_update, &t)) {
1092*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove(wpa_s, bss, __func__);
1093*03f9172cSAndroid Build Coastguard Worker } else
1094*03f9172cSAndroid Build Coastguard Worker break;
1095*03f9172cSAndroid Build Coastguard Worker }
1096*03f9172cSAndroid Build Coastguard Worker }
1097*03f9172cSAndroid Build Coastguard Worker
1098*03f9172cSAndroid Build Coastguard Worker
1099*03f9172cSAndroid Build Coastguard Worker /**
1100*03f9172cSAndroid Build Coastguard Worker * wpa_bss_init - Initialize BSS table
1101*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1102*03f9172cSAndroid Build Coastguard Worker * Returns: 0 on success, -1 on failure
1103*03f9172cSAndroid Build Coastguard Worker *
1104*03f9172cSAndroid Build Coastguard Worker * This prepares BSS table lists and timer for periodic updates. The BSS table
1105*03f9172cSAndroid Build Coastguard Worker * is deinitialized with wpa_bss_deinit() once not needed anymore.
1106*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_init(struct wpa_supplicant * wpa_s)1107*03f9172cSAndroid Build Coastguard Worker int wpa_bss_init(struct wpa_supplicant *wpa_s)
1108*03f9172cSAndroid Build Coastguard Worker {
1109*03f9172cSAndroid Build Coastguard Worker dl_list_init(&wpa_s->bss);
1110*03f9172cSAndroid Build Coastguard Worker dl_list_init(&wpa_s->bss_id);
1111*03f9172cSAndroid Build Coastguard Worker return 0;
1112*03f9172cSAndroid Build Coastguard Worker }
1113*03f9172cSAndroid Build Coastguard Worker
1114*03f9172cSAndroid Build Coastguard Worker
1115*03f9172cSAndroid Build Coastguard Worker /**
1116*03f9172cSAndroid Build Coastguard Worker * wpa_bss_flush - Flush all unused BSS entries
1117*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1118*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_flush(struct wpa_supplicant * wpa_s)1119*03f9172cSAndroid Build Coastguard Worker void wpa_bss_flush(struct wpa_supplicant *wpa_s)
1120*03f9172cSAndroid Build Coastguard Worker {
1121*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, *n;
1122*03f9172cSAndroid Build Coastguard Worker
1123*03f9172cSAndroid Build Coastguard Worker wpa_s->clear_driver_scan_cache = 1;
1124*03f9172cSAndroid Build Coastguard Worker
1125*03f9172cSAndroid Build Coastguard Worker if (wpa_s->bss.next == NULL)
1126*03f9172cSAndroid Build Coastguard Worker return; /* BSS table not yet initialized */
1127*03f9172cSAndroid Build Coastguard Worker
1128*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
1129*03f9172cSAndroid Build Coastguard Worker if (wpa_bss_in_use(wpa_s, bss))
1130*03f9172cSAndroid Build Coastguard Worker continue;
1131*03f9172cSAndroid Build Coastguard Worker wpa_bss_remove(wpa_s, bss, __func__);
1132*03f9172cSAndroid Build Coastguard Worker }
1133*03f9172cSAndroid Build Coastguard Worker }
1134*03f9172cSAndroid Build Coastguard Worker
1135*03f9172cSAndroid Build Coastguard Worker
1136*03f9172cSAndroid Build Coastguard Worker /**
1137*03f9172cSAndroid Build Coastguard Worker * wpa_bss_deinit - Deinitialize BSS table
1138*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1139*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_deinit(struct wpa_supplicant * wpa_s)1140*03f9172cSAndroid Build Coastguard Worker void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
1141*03f9172cSAndroid Build Coastguard Worker {
1142*03f9172cSAndroid Build Coastguard Worker wpa_bss_flush(wpa_s);
1143*03f9172cSAndroid Build Coastguard Worker }
1144*03f9172cSAndroid Build Coastguard Worker
1145*03f9172cSAndroid Build Coastguard Worker
1146*03f9172cSAndroid Build Coastguard Worker /**
1147*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
1148*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1149*03f9172cSAndroid Build Coastguard Worker * @bssid: BSSID
1150*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
1151*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_bssid(struct wpa_supplicant * wpa_s,const u8 * bssid)1152*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
1153*03f9172cSAndroid Build Coastguard Worker const u8 *bssid)
1154*03f9172cSAndroid Build Coastguard Worker {
1155*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
1156*03f9172cSAndroid Build Coastguard Worker if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
1157*03f9172cSAndroid Build Coastguard Worker return NULL;
1158*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1159*03f9172cSAndroid Build Coastguard Worker if (ether_addr_equal(bss->bssid, bssid))
1160*03f9172cSAndroid Build Coastguard Worker return bss;
1161*03f9172cSAndroid Build Coastguard Worker }
1162*03f9172cSAndroid Build Coastguard Worker return NULL;
1163*03f9172cSAndroid Build Coastguard Worker }
1164*03f9172cSAndroid Build Coastguard Worker
1165*03f9172cSAndroid Build Coastguard Worker
1166*03f9172cSAndroid Build Coastguard Worker /**
1167*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_bssid_latest - Fetch the latest BSS table entry based on BSSID
1168*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1169*03f9172cSAndroid Build Coastguard Worker * @bssid: BSSID
1170*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
1171*03f9172cSAndroid Build Coastguard Worker *
1172*03f9172cSAndroid Build Coastguard Worker * This function is like wpa_bss_get_bssid(), but full BSS table is iterated to
1173*03f9172cSAndroid Build Coastguard Worker * find the entry that has the most recent update. This can help in finding the
1174*03f9172cSAndroid Build Coastguard Worker * correct entry in cases where the SSID of the AP may have changed recently
1175*03f9172cSAndroid Build Coastguard Worker * (e.g., in WPS reconfiguration cases).
1176*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_bssid_latest(struct wpa_supplicant * wpa_s,const u8 * bssid)1177*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_bssid_latest(struct wpa_supplicant *wpa_s,
1178*03f9172cSAndroid Build Coastguard Worker const u8 *bssid)
1179*03f9172cSAndroid Build Coastguard Worker {
1180*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, *found = NULL;
1181*03f9172cSAndroid Build Coastguard Worker if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
1182*03f9172cSAndroid Build Coastguard Worker return NULL;
1183*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1184*03f9172cSAndroid Build Coastguard Worker if (!ether_addr_equal(bss->bssid, bssid))
1185*03f9172cSAndroid Build Coastguard Worker continue;
1186*03f9172cSAndroid Build Coastguard Worker if (found == NULL ||
1187*03f9172cSAndroid Build Coastguard Worker os_reltime_before(&found->last_update, &bss->last_update))
1188*03f9172cSAndroid Build Coastguard Worker found = bss;
1189*03f9172cSAndroid Build Coastguard Worker }
1190*03f9172cSAndroid Build Coastguard Worker return found;
1191*03f9172cSAndroid Build Coastguard Worker }
1192*03f9172cSAndroid Build Coastguard Worker
1193*03f9172cSAndroid Build Coastguard Worker
1194*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_P2P
1195*03f9172cSAndroid Build Coastguard Worker /**
1196*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_p2p_dev_addr - Fetch the latest BSS table entry based on P2P Device Addr
1197*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1198*03f9172cSAndroid Build Coastguard Worker * @dev_addr: P2P Device Address of the GO
1199*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
1200*03f9172cSAndroid Build Coastguard Worker *
1201*03f9172cSAndroid Build Coastguard Worker * This function tries to find the entry that has the most recent update. This
1202*03f9172cSAndroid Build Coastguard Worker * can help in finding the correct entry in cases where the SSID of the P2P
1203*03f9172cSAndroid Build Coastguard Worker * Device may have changed recently.
1204*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_p2p_dev_addr(struct wpa_supplicant * wpa_s,const u8 * dev_addr)1205*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
1206*03f9172cSAndroid Build Coastguard Worker const u8 *dev_addr)
1207*03f9172cSAndroid Build Coastguard Worker {
1208*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, *found = NULL;
1209*03f9172cSAndroid Build Coastguard Worker dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
1210*03f9172cSAndroid Build Coastguard Worker u8 addr[ETH_ALEN];
1211*03f9172cSAndroid Build Coastguard Worker if (p2p_parse_dev_addr(wpa_bss_ie_ptr(bss), bss->ie_len,
1212*03f9172cSAndroid Build Coastguard Worker addr) != 0 ||
1213*03f9172cSAndroid Build Coastguard Worker !ether_addr_equal(addr, dev_addr))
1214*03f9172cSAndroid Build Coastguard Worker continue;
1215*03f9172cSAndroid Build Coastguard Worker if (!found ||
1216*03f9172cSAndroid Build Coastguard Worker os_reltime_before(&found->last_update, &bss->last_update))
1217*03f9172cSAndroid Build Coastguard Worker found = bss;
1218*03f9172cSAndroid Build Coastguard Worker }
1219*03f9172cSAndroid Build Coastguard Worker return found;
1220*03f9172cSAndroid Build Coastguard Worker }
1221*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_P2P */
1222*03f9172cSAndroid Build Coastguard Worker
1223*03f9172cSAndroid Build Coastguard Worker
1224*03f9172cSAndroid Build Coastguard Worker /**
1225*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_id - Fetch a BSS table entry based on identifier
1226*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1227*03f9172cSAndroid Build Coastguard Worker * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
1228*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
1229*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_id(struct wpa_supplicant * wpa_s,unsigned int id)1230*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
1231*03f9172cSAndroid Build Coastguard Worker {
1232*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
1233*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
1234*03f9172cSAndroid Build Coastguard Worker if (bss->id == id)
1235*03f9172cSAndroid Build Coastguard Worker return bss;
1236*03f9172cSAndroid Build Coastguard Worker }
1237*03f9172cSAndroid Build Coastguard Worker return NULL;
1238*03f9172cSAndroid Build Coastguard Worker }
1239*03f9172cSAndroid Build Coastguard Worker
1240*03f9172cSAndroid Build Coastguard Worker
1241*03f9172cSAndroid Build Coastguard Worker /**
1242*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_id_range - Fetch a BSS table entry based on identifier range
1243*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1244*03f9172cSAndroid Build Coastguard Worker * @idf: Smallest allowed identifier assigned for the entry
1245*03f9172cSAndroid Build Coastguard Worker * @idf: Largest allowed identifier assigned for the entry
1246*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the BSS entry or %NULL if not found
1247*03f9172cSAndroid Build Coastguard Worker *
1248*03f9172cSAndroid Build Coastguard Worker * This function is similar to wpa_bss_get_id() but allows a BSS entry with the
1249*03f9172cSAndroid Build Coastguard Worker * smallest id value to be fetched within the specified range without the
1250*03f9172cSAndroid Build Coastguard Worker * caller having to know the exact id.
1251*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_id_range(struct wpa_supplicant * wpa_s,unsigned int idf,unsigned int idl)1252*03f9172cSAndroid Build Coastguard Worker struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
1253*03f9172cSAndroid Build Coastguard Worker unsigned int idf, unsigned int idl)
1254*03f9172cSAndroid Build Coastguard Worker {
1255*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss;
1256*03f9172cSAndroid Build Coastguard Worker dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
1257*03f9172cSAndroid Build Coastguard Worker if (bss->id >= idf && bss->id <= idl)
1258*03f9172cSAndroid Build Coastguard Worker return bss;
1259*03f9172cSAndroid Build Coastguard Worker }
1260*03f9172cSAndroid Build Coastguard Worker return NULL;
1261*03f9172cSAndroid Build Coastguard Worker }
1262*03f9172cSAndroid Build Coastguard Worker
1263*03f9172cSAndroid Build Coastguard Worker
1264*03f9172cSAndroid Build Coastguard Worker /**
1265*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
1266*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1267*03f9172cSAndroid Build Coastguard Worker * @ie: Information element identitifier (WLAN_EID_*)
1268*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element (id field) or %NULL if not found
1269*03f9172cSAndroid Build Coastguard Worker *
1270*03f9172cSAndroid Build Coastguard Worker * This function returns the first matching information element in the BSS
1271*03f9172cSAndroid Build Coastguard Worker * entry.
1272*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_ie(const struct wpa_bss * bss,u8 ie)1273*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
1274*03f9172cSAndroid Build Coastguard Worker {
1275*03f9172cSAndroid Build Coastguard Worker return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
1276*03f9172cSAndroid Build Coastguard Worker }
1277*03f9172cSAndroid Build Coastguard Worker
1278*03f9172cSAndroid Build Coastguard Worker
1279*03f9172cSAndroid Build Coastguard Worker /**
1280*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_ie_beacon - Fetch a specified information element from a BSS entry
1281*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1282*03f9172cSAndroid Build Coastguard Worker * @ie: Information element identitifier (WLAN_EID_*)
1283*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element (id field) or %NULL if not found
1284*03f9172cSAndroid Build Coastguard Worker *
1285*03f9172cSAndroid Build Coastguard Worker * This function returns the first matching information element in the BSS
1286*03f9172cSAndroid Build Coastguard Worker * entry.
1287*03f9172cSAndroid Build Coastguard Worker *
1288*03f9172cSAndroid Build Coastguard Worker * This function is like wpa_bss_get_ie(), but uses IE buffer only from Beacon
1289*03f9172cSAndroid Build Coastguard Worker * frames instead of either Beacon or Probe Response frames.
1290*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_ie_beacon(const struct wpa_bss * bss,u8 ie)1291*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_ie_beacon(const struct wpa_bss *bss, u8 ie)
1292*03f9172cSAndroid Build Coastguard Worker {
1293*03f9172cSAndroid Build Coastguard Worker const u8 *ies;
1294*03f9172cSAndroid Build Coastguard Worker
1295*03f9172cSAndroid Build Coastguard Worker if (bss->beacon_ie_len == 0)
1296*03f9172cSAndroid Build Coastguard Worker return NULL;
1297*03f9172cSAndroid Build Coastguard Worker
1298*03f9172cSAndroid Build Coastguard Worker ies = wpa_bss_ie_ptr(bss);
1299*03f9172cSAndroid Build Coastguard Worker ies += bss->ie_len;
1300*03f9172cSAndroid Build Coastguard Worker return get_ie(ies, bss->beacon_ie_len, ie);
1301*03f9172cSAndroid Build Coastguard Worker }
1302*03f9172cSAndroid Build Coastguard Worker
1303*03f9172cSAndroid Build Coastguard Worker
1304*03f9172cSAndroid Build Coastguard Worker /**
1305*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
1306*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1307*03f9172cSAndroid Build Coastguard Worker * @ext: Information element extension identifier (WLAN_EID_EXT_*)
1308*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element (id field) or %NULL if not found
1309*03f9172cSAndroid Build Coastguard Worker *
1310*03f9172cSAndroid Build Coastguard Worker * This function returns the first matching information element in the BSS
1311*03f9172cSAndroid Build Coastguard Worker * entry.
1312*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_ie_ext(const struct wpa_bss * bss,u8 ext)1313*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext)
1314*03f9172cSAndroid Build Coastguard Worker {
1315*03f9172cSAndroid Build Coastguard Worker return get_ie_ext(wpa_bss_ie_ptr(bss), bss->ie_len, ext);
1316*03f9172cSAndroid Build Coastguard Worker }
1317*03f9172cSAndroid Build Coastguard Worker
1318*03f9172cSAndroid Build Coastguard Worker
1319*03f9172cSAndroid Build Coastguard Worker /**
1320*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
1321*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1322*03f9172cSAndroid Build Coastguard Worker * @vendor_type: Vendor type (four octets starting the IE payload)
1323*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element (id field) or %NULL if not found
1324*03f9172cSAndroid Build Coastguard Worker *
1325*03f9172cSAndroid Build Coastguard Worker * This function returns the first matching information element in the BSS
1326*03f9172cSAndroid Build Coastguard Worker * entry.
1327*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_vendor_ie(const struct wpa_bss * bss,u32 vendor_type)1328*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
1329*03f9172cSAndroid Build Coastguard Worker {
1330*03f9172cSAndroid Build Coastguard Worker const u8 *ies;
1331*03f9172cSAndroid Build Coastguard Worker const struct element *elem;
1332*03f9172cSAndroid Build Coastguard Worker
1333*03f9172cSAndroid Build Coastguard Worker ies = wpa_bss_ie_ptr(bss);
1334*03f9172cSAndroid Build Coastguard Worker
1335*03f9172cSAndroid Build Coastguard Worker for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies, bss->ie_len) {
1336*03f9172cSAndroid Build Coastguard Worker if (elem->datalen >= 4 &&
1337*03f9172cSAndroid Build Coastguard Worker vendor_type == WPA_GET_BE32(elem->data))
1338*03f9172cSAndroid Build Coastguard Worker return &elem->id;
1339*03f9172cSAndroid Build Coastguard Worker }
1340*03f9172cSAndroid Build Coastguard Worker
1341*03f9172cSAndroid Build Coastguard Worker return NULL;
1342*03f9172cSAndroid Build Coastguard Worker }
1343*03f9172cSAndroid Build Coastguard Worker
1344*03f9172cSAndroid Build Coastguard Worker
1345*03f9172cSAndroid Build Coastguard Worker /**
1346*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_vendor_ie_beacon - Fetch a vendor information from a BSS entry
1347*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1348*03f9172cSAndroid Build Coastguard Worker * @vendor_type: Vendor type (four octets starting the IE payload)
1349*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element (id field) or %NULL if not found
1350*03f9172cSAndroid Build Coastguard Worker *
1351*03f9172cSAndroid Build Coastguard Worker * This function returns the first matching information element in the BSS
1352*03f9172cSAndroid Build Coastguard Worker * entry.
1353*03f9172cSAndroid Build Coastguard Worker *
1354*03f9172cSAndroid Build Coastguard Worker * This function is like wpa_bss_get_vendor_ie(), but uses IE buffer only
1355*03f9172cSAndroid Build Coastguard Worker * from Beacon frames instead of either Beacon or Probe Response frames.
1356*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_vendor_ie_beacon(const struct wpa_bss * bss,u32 vendor_type)1357*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
1358*03f9172cSAndroid Build Coastguard Worker u32 vendor_type)
1359*03f9172cSAndroid Build Coastguard Worker {
1360*03f9172cSAndroid Build Coastguard Worker const u8 *ies;
1361*03f9172cSAndroid Build Coastguard Worker const struct element *elem;
1362*03f9172cSAndroid Build Coastguard Worker
1363*03f9172cSAndroid Build Coastguard Worker if (bss->beacon_ie_len == 0)
1364*03f9172cSAndroid Build Coastguard Worker return NULL;
1365*03f9172cSAndroid Build Coastguard Worker
1366*03f9172cSAndroid Build Coastguard Worker ies = wpa_bss_ie_ptr(bss);
1367*03f9172cSAndroid Build Coastguard Worker ies += bss->ie_len;
1368*03f9172cSAndroid Build Coastguard Worker
1369*03f9172cSAndroid Build Coastguard Worker for_each_element_id(elem, WLAN_EID_VENDOR_SPECIFIC, ies,
1370*03f9172cSAndroid Build Coastguard Worker bss->beacon_ie_len) {
1371*03f9172cSAndroid Build Coastguard Worker if (elem->datalen >= 4 &&
1372*03f9172cSAndroid Build Coastguard Worker vendor_type == WPA_GET_BE32(elem->data))
1373*03f9172cSAndroid Build Coastguard Worker return &elem->id;
1374*03f9172cSAndroid Build Coastguard Worker }
1375*03f9172cSAndroid Build Coastguard Worker
1376*03f9172cSAndroid Build Coastguard Worker return NULL;
1377*03f9172cSAndroid Build Coastguard Worker }
1378*03f9172cSAndroid Build Coastguard Worker
1379*03f9172cSAndroid Build Coastguard Worker
1380*03f9172cSAndroid Build Coastguard Worker /**
1381*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
1382*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1383*03f9172cSAndroid Build Coastguard Worker * @vendor_type: Vendor type (four octets starting the IE payload)
1384*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element payload or %NULL if not found
1385*03f9172cSAndroid Build Coastguard Worker *
1386*03f9172cSAndroid Build Coastguard Worker * This function returns concatenated payload of possibly fragmented vendor
1387*03f9172cSAndroid Build Coastguard Worker * specific information elements in the BSS entry. The caller is responsible for
1388*03f9172cSAndroid Build Coastguard Worker * freeing the returned buffer.
1389*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_vendor_ie_multi(const struct wpa_bss * bss,u32 vendor_type)1390*03f9172cSAndroid Build Coastguard Worker struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
1391*03f9172cSAndroid Build Coastguard Worker u32 vendor_type)
1392*03f9172cSAndroid Build Coastguard Worker {
1393*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
1394*03f9172cSAndroid Build Coastguard Worker const u8 *end, *pos;
1395*03f9172cSAndroid Build Coastguard Worker
1396*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(bss->ie_len);
1397*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
1398*03f9172cSAndroid Build Coastguard Worker return NULL;
1399*03f9172cSAndroid Build Coastguard Worker
1400*03f9172cSAndroid Build Coastguard Worker pos = wpa_bss_ie_ptr(bss);
1401*03f9172cSAndroid Build Coastguard Worker end = pos + bss->ie_len;
1402*03f9172cSAndroid Build Coastguard Worker
1403*03f9172cSAndroid Build Coastguard Worker while (end - pos > 1) {
1404*03f9172cSAndroid Build Coastguard Worker u8 ie, len;
1405*03f9172cSAndroid Build Coastguard Worker
1406*03f9172cSAndroid Build Coastguard Worker ie = pos[0];
1407*03f9172cSAndroid Build Coastguard Worker len = pos[1];
1408*03f9172cSAndroid Build Coastguard Worker if (len > end - pos - 2)
1409*03f9172cSAndroid Build Coastguard Worker break;
1410*03f9172cSAndroid Build Coastguard Worker pos += 2;
1411*03f9172cSAndroid Build Coastguard Worker if (ie == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
1412*03f9172cSAndroid Build Coastguard Worker vendor_type == WPA_GET_BE32(pos))
1413*03f9172cSAndroid Build Coastguard Worker wpabuf_put_data(buf, pos + 4, len - 4);
1414*03f9172cSAndroid Build Coastguard Worker pos += len;
1415*03f9172cSAndroid Build Coastguard Worker }
1416*03f9172cSAndroid Build Coastguard Worker
1417*03f9172cSAndroid Build Coastguard Worker if (wpabuf_len(buf) == 0) {
1418*03f9172cSAndroid Build Coastguard Worker wpabuf_free(buf);
1419*03f9172cSAndroid Build Coastguard Worker buf = NULL;
1420*03f9172cSAndroid Build Coastguard Worker }
1421*03f9172cSAndroid Build Coastguard Worker
1422*03f9172cSAndroid Build Coastguard Worker return buf;
1423*03f9172cSAndroid Build Coastguard Worker }
1424*03f9172cSAndroid Build Coastguard Worker
1425*03f9172cSAndroid Build Coastguard Worker
1426*03f9172cSAndroid Build Coastguard Worker /**
1427*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
1428*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1429*03f9172cSAndroid Build Coastguard Worker * @vendor_type: Vendor type (four octets starting the IE payload)
1430*03f9172cSAndroid Build Coastguard Worker * Returns: Pointer to the information element payload or %NULL if not found
1431*03f9172cSAndroid Build Coastguard Worker *
1432*03f9172cSAndroid Build Coastguard Worker * This function returns concatenated payload of possibly fragmented vendor
1433*03f9172cSAndroid Build Coastguard Worker * specific information elements in the BSS entry. The caller is responsible for
1434*03f9172cSAndroid Build Coastguard Worker * freeing the returned buffer.
1435*03f9172cSAndroid Build Coastguard Worker *
1436*03f9172cSAndroid Build Coastguard Worker * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
1437*03f9172cSAndroid Build Coastguard Worker * from Beacon frames instead of either Beacon or Probe Response frames.
1438*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss * bss,u32 vendor_type)1439*03f9172cSAndroid Build Coastguard Worker struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
1440*03f9172cSAndroid Build Coastguard Worker u32 vendor_type)
1441*03f9172cSAndroid Build Coastguard Worker {
1442*03f9172cSAndroid Build Coastguard Worker struct wpabuf *buf;
1443*03f9172cSAndroid Build Coastguard Worker const u8 *end, *pos;
1444*03f9172cSAndroid Build Coastguard Worker
1445*03f9172cSAndroid Build Coastguard Worker buf = wpabuf_alloc(bss->beacon_ie_len);
1446*03f9172cSAndroid Build Coastguard Worker if (buf == NULL)
1447*03f9172cSAndroid Build Coastguard Worker return NULL;
1448*03f9172cSAndroid Build Coastguard Worker
1449*03f9172cSAndroid Build Coastguard Worker pos = wpa_bss_ie_ptr(bss);
1450*03f9172cSAndroid Build Coastguard Worker pos += bss->ie_len;
1451*03f9172cSAndroid Build Coastguard Worker end = pos + bss->beacon_ie_len;
1452*03f9172cSAndroid Build Coastguard Worker
1453*03f9172cSAndroid Build Coastguard Worker while (end - pos > 1) {
1454*03f9172cSAndroid Build Coastguard Worker u8 id, len;
1455*03f9172cSAndroid Build Coastguard Worker
1456*03f9172cSAndroid Build Coastguard Worker id = *pos++;
1457*03f9172cSAndroid Build Coastguard Worker len = *pos++;
1458*03f9172cSAndroid Build Coastguard Worker if (len > end - pos)
1459*03f9172cSAndroid Build Coastguard Worker break;
1460*03f9172cSAndroid Build Coastguard Worker if (id == WLAN_EID_VENDOR_SPECIFIC && len >= 4 &&
1461*03f9172cSAndroid Build Coastguard Worker vendor_type == WPA_GET_BE32(pos))
1462*03f9172cSAndroid Build Coastguard Worker wpabuf_put_data(buf, pos + 4, len - 4);
1463*03f9172cSAndroid Build Coastguard Worker pos += len;
1464*03f9172cSAndroid Build Coastguard Worker }
1465*03f9172cSAndroid Build Coastguard Worker
1466*03f9172cSAndroid Build Coastguard Worker if (wpabuf_len(buf) == 0) {
1467*03f9172cSAndroid Build Coastguard Worker wpabuf_free(buf);
1468*03f9172cSAndroid Build Coastguard Worker buf = NULL;
1469*03f9172cSAndroid Build Coastguard Worker }
1470*03f9172cSAndroid Build Coastguard Worker
1471*03f9172cSAndroid Build Coastguard Worker return buf;
1472*03f9172cSAndroid Build Coastguard Worker }
1473*03f9172cSAndroid Build Coastguard Worker
1474*03f9172cSAndroid Build Coastguard Worker
1475*03f9172cSAndroid Build Coastguard Worker /**
1476*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
1477*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1478*03f9172cSAndroid Build Coastguard Worker * Returns: Maximum legacy rate in units of 500 kbps
1479*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_max_rate(const struct wpa_bss * bss)1480*03f9172cSAndroid Build Coastguard Worker int wpa_bss_get_max_rate(const struct wpa_bss *bss)
1481*03f9172cSAndroid Build Coastguard Worker {
1482*03f9172cSAndroid Build Coastguard Worker int rate = 0;
1483*03f9172cSAndroid Build Coastguard Worker const u8 *ie;
1484*03f9172cSAndroid Build Coastguard Worker int i;
1485*03f9172cSAndroid Build Coastguard Worker
1486*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1487*03f9172cSAndroid Build Coastguard Worker for (i = 0; ie && i < ie[1]; i++) {
1488*03f9172cSAndroid Build Coastguard Worker if ((ie[i + 2] & 0x7f) > rate)
1489*03f9172cSAndroid Build Coastguard Worker rate = ie[i + 2] & 0x7f;
1490*03f9172cSAndroid Build Coastguard Worker }
1491*03f9172cSAndroid Build Coastguard Worker
1492*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1493*03f9172cSAndroid Build Coastguard Worker for (i = 0; ie && i < ie[1]; i++) {
1494*03f9172cSAndroid Build Coastguard Worker if ((ie[i + 2] & 0x7f) > rate)
1495*03f9172cSAndroid Build Coastguard Worker rate = ie[i + 2] & 0x7f;
1496*03f9172cSAndroid Build Coastguard Worker }
1497*03f9172cSAndroid Build Coastguard Worker
1498*03f9172cSAndroid Build Coastguard Worker return rate;
1499*03f9172cSAndroid Build Coastguard Worker }
1500*03f9172cSAndroid Build Coastguard Worker
1501*03f9172cSAndroid Build Coastguard Worker
1502*03f9172cSAndroid Build Coastguard Worker /**
1503*03f9172cSAndroid Build Coastguard Worker * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
1504*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1505*03f9172cSAndroid Build Coastguard Worker * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
1506*03f9172cSAndroid Build Coastguard Worker * Returns: number of legacy TX rates or -1 on failure
1507*03f9172cSAndroid Build Coastguard Worker *
1508*03f9172cSAndroid Build Coastguard Worker * The caller is responsible for freeing the returned buffer with os_free() in
1509*03f9172cSAndroid Build Coastguard Worker * case of success.
1510*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_get_bit_rates(const struct wpa_bss * bss,u8 ** rates)1511*03f9172cSAndroid Build Coastguard Worker int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
1512*03f9172cSAndroid Build Coastguard Worker {
1513*03f9172cSAndroid Build Coastguard Worker const u8 *ie, *ie2;
1514*03f9172cSAndroid Build Coastguard Worker int i, j;
1515*03f9172cSAndroid Build Coastguard Worker unsigned int len;
1516*03f9172cSAndroid Build Coastguard Worker u8 *r;
1517*03f9172cSAndroid Build Coastguard Worker
1518*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
1519*03f9172cSAndroid Build Coastguard Worker ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
1520*03f9172cSAndroid Build Coastguard Worker
1521*03f9172cSAndroid Build Coastguard Worker len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
1522*03f9172cSAndroid Build Coastguard Worker
1523*03f9172cSAndroid Build Coastguard Worker r = os_malloc(len);
1524*03f9172cSAndroid Build Coastguard Worker if (!r)
1525*03f9172cSAndroid Build Coastguard Worker return -1;
1526*03f9172cSAndroid Build Coastguard Worker
1527*03f9172cSAndroid Build Coastguard Worker for (i = 0; ie && i < ie[1]; i++)
1528*03f9172cSAndroid Build Coastguard Worker r[i] = ie[i + 2] & 0x7f;
1529*03f9172cSAndroid Build Coastguard Worker
1530*03f9172cSAndroid Build Coastguard Worker for (j = 0; ie2 && j < ie2[1]; j++)
1531*03f9172cSAndroid Build Coastguard Worker r[i + j] = ie2[j + 2] & 0x7f;
1532*03f9172cSAndroid Build Coastguard Worker
1533*03f9172cSAndroid Build Coastguard Worker *rates = r;
1534*03f9172cSAndroid Build Coastguard Worker return len;
1535*03f9172cSAndroid Build Coastguard Worker }
1536*03f9172cSAndroid Build Coastguard Worker
1537*03f9172cSAndroid Build Coastguard Worker
1538*03f9172cSAndroid Build Coastguard Worker #ifdef CONFIG_FILS
wpa_bss_get_fils_cache_id(const struct wpa_bss * bss)1539*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_fils_cache_id(const struct wpa_bss *bss)
1540*03f9172cSAndroid Build Coastguard Worker {
1541*03f9172cSAndroid Build Coastguard Worker const u8 *ie;
1542*03f9172cSAndroid Build Coastguard Worker
1543*03f9172cSAndroid Build Coastguard Worker if (bss) {
1544*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_ie(bss, WLAN_EID_FILS_INDICATION);
1545*03f9172cSAndroid Build Coastguard Worker if (ie && ie[1] >= 4 && WPA_GET_LE16(ie + 2) & BIT(7))
1546*03f9172cSAndroid Build Coastguard Worker return ie + 4;
1547*03f9172cSAndroid Build Coastguard Worker }
1548*03f9172cSAndroid Build Coastguard Worker
1549*03f9172cSAndroid Build Coastguard Worker return NULL;
1550*03f9172cSAndroid Build Coastguard Worker }
1551*03f9172cSAndroid Build Coastguard Worker #endif /* CONFIG_FILS */
1552*03f9172cSAndroid Build Coastguard Worker
1553*03f9172cSAndroid Build Coastguard Worker
wpa_bss_ext_capab(const struct wpa_bss * bss,unsigned int capab)1554*03f9172cSAndroid Build Coastguard Worker int wpa_bss_ext_capab(const struct wpa_bss *bss, unsigned int capab)
1555*03f9172cSAndroid Build Coastguard Worker {
1556*03f9172cSAndroid Build Coastguard Worker if (!bss)
1557*03f9172cSAndroid Build Coastguard Worker return 0;
1558*03f9172cSAndroid Build Coastguard Worker return ieee802_11_ext_capab(wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB),
1559*03f9172cSAndroid Build Coastguard Worker capab);
1560*03f9172cSAndroid Build Coastguard Worker }
1561*03f9172cSAndroid Build Coastguard Worker
1562*03f9172cSAndroid Build Coastguard Worker
1563*03f9172cSAndroid Build Coastguard Worker static void
wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,u8 mbssid_idx,const struct ieee80211_neighbor_ap_info * ap_info,size_t len,u16 * seen,u16 * missing,struct wpa_ssid * ssid)1564*03f9172cSAndroid Build Coastguard Worker wpa_bss_parse_ml_rnr_ap_info(struct wpa_supplicant *wpa_s,
1565*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss, u8 mbssid_idx,
1566*03f9172cSAndroid Build Coastguard Worker const struct ieee80211_neighbor_ap_info *ap_info,
1567*03f9172cSAndroid Build Coastguard Worker size_t len, u16 *seen, u16 *missing,
1568*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid)
1569*03f9172cSAndroid Build Coastguard Worker {
1570*03f9172cSAndroid Build Coastguard Worker const u8 *pos, *end;
1571*03f9172cSAndroid Build Coastguard Worker const u8 *mld_params;
1572*03f9172cSAndroid Build Coastguard Worker u8 count, mld_params_offset;
1573*03f9172cSAndroid Build Coastguard Worker u8 i, type, link_id;
1574*03f9172cSAndroid Build Coastguard Worker
1575*03f9172cSAndroid Build Coastguard Worker count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
1576*03f9172cSAndroid Build Coastguard Worker type = ap_info->tbtt_info_hdr & RNR_TBTT_INFO_HDR_TYPE_MSK;
1577*03f9172cSAndroid Build Coastguard Worker
1578*03f9172cSAndroid Build Coastguard Worker /* MLD information is at offset 13 or at start */
1579*03f9172cSAndroid Build Coastguard Worker if (type == 0 && ap_info->tbtt_info_len >= RNR_TBTT_INFO_MLD_LEN) {
1580*03f9172cSAndroid Build Coastguard Worker /* MLD info is appended */
1581*03f9172cSAndroid Build Coastguard Worker mld_params_offset = RNR_TBTT_INFO_LEN;
1582*03f9172cSAndroid Build Coastguard Worker } else {
1583*03f9172cSAndroid Build Coastguard Worker /* TODO: Support NSTR AP */
1584*03f9172cSAndroid Build Coastguard Worker return;
1585*03f9172cSAndroid Build Coastguard Worker }
1586*03f9172cSAndroid Build Coastguard Worker
1587*03f9172cSAndroid Build Coastguard Worker pos = (const u8 *) ap_info;
1588*03f9172cSAndroid Build Coastguard Worker end = pos + len;
1589*03f9172cSAndroid Build Coastguard Worker pos += sizeof(*ap_info);
1590*03f9172cSAndroid Build Coastguard Worker
1591*03f9172cSAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
1592*03f9172cSAndroid Build Coastguard Worker u8 bss_params;
1593*03f9172cSAndroid Build Coastguard Worker
1594*03f9172cSAndroid Build Coastguard Worker if (end - pos < ap_info->tbtt_info_len)
1595*03f9172cSAndroid Build Coastguard Worker break;
1596*03f9172cSAndroid Build Coastguard Worker
1597*03f9172cSAndroid Build Coastguard Worker bss_params = pos[1 + ETH_ALEN + 4];
1598*03f9172cSAndroid Build Coastguard Worker mld_params = pos + mld_params_offset;
1599*03f9172cSAndroid Build Coastguard Worker
1600*03f9172cSAndroid Build Coastguard Worker link_id = *(mld_params + 1) & EHT_ML_LINK_ID_MSK;
1601*03f9172cSAndroid Build Coastguard Worker if (link_id >= MAX_NUM_MLD_LINKS)
1602*03f9172cSAndroid Build Coastguard Worker return;
1603*03f9172cSAndroid Build Coastguard Worker
1604*03f9172cSAndroid Build Coastguard Worker if (*mld_params != mbssid_idx) {
1605*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1606*03f9172cSAndroid Build Coastguard Worker "MLD: Reported link not part of MLD");
1607*03f9172cSAndroid Build Coastguard Worker } else if (!(BIT(link_id) & *seen)) {
1608*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *neigh_bss;
1609*03f9172cSAndroid Build Coastguard Worker
1610*03f9172cSAndroid Build Coastguard Worker if (ssid && ssid->ssid_len)
1611*03f9172cSAndroid Build Coastguard Worker neigh_bss = wpa_bss_get(wpa_s, pos + 1,
1612*03f9172cSAndroid Build Coastguard Worker ssid->ssid,
1613*03f9172cSAndroid Build Coastguard Worker ssid->ssid_len);
1614*03f9172cSAndroid Build Coastguard Worker else
1615*03f9172cSAndroid Build Coastguard Worker neigh_bss = wpa_bss_get_bssid(wpa_s, pos + 1);
1616*03f9172cSAndroid Build Coastguard Worker
1617*03f9172cSAndroid Build Coastguard Worker *seen |= BIT(link_id);
1618*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
1619*03f9172cSAndroid Build Coastguard Worker *mld_params, link_id);
1620*03f9172cSAndroid Build Coastguard Worker
1621*03f9172cSAndroid Build Coastguard Worker if (!neigh_bss) {
1622*03f9172cSAndroid Build Coastguard Worker *missing |= BIT(link_id);
1623*03f9172cSAndroid Build Coastguard Worker } else if ((!ssid ||
1624*03f9172cSAndroid Build Coastguard Worker (bss_params & (RNR_BSS_PARAM_SAME_SSID |
1625*03f9172cSAndroid Build Coastguard Worker RNR_BSS_PARAM_CO_LOCATED)) ||
1626*03f9172cSAndroid Build Coastguard Worker wpa_scan_res_match(wpa_s, 0, neigh_bss,
1627*03f9172cSAndroid Build Coastguard Worker ssid, 1, 0)) &&
1628*03f9172cSAndroid Build Coastguard Worker !wpa_bssid_ignore_is_listed(
1629*03f9172cSAndroid Build Coastguard Worker wpa_s, neigh_bss->bssid)) {
1630*03f9172cSAndroid Build Coastguard Worker struct mld_link *l;
1631*03f9172cSAndroid Build Coastguard Worker
1632*03f9172cSAndroid Build Coastguard Worker bss->valid_links |= BIT(link_id);
1633*03f9172cSAndroid Build Coastguard Worker l = &bss->mld_links[link_id];
1634*03f9172cSAndroid Build Coastguard Worker os_memcpy(l->bssid, pos + 1, ETH_ALEN);
1635*03f9172cSAndroid Build Coastguard Worker l->freq = neigh_bss->freq;
1636*03f9172cSAndroid Build Coastguard Worker l->disabled = mld_params[2] &
1637*03f9172cSAndroid Build Coastguard Worker RNR_TBTT_INFO_MLD_PARAM2_LINK_DISABLED;
1638*03f9172cSAndroid Build Coastguard Worker }
1639*03f9172cSAndroid Build Coastguard Worker }
1640*03f9172cSAndroid Build Coastguard Worker
1641*03f9172cSAndroid Build Coastguard Worker pos += ap_info->tbtt_info_len;
1642*03f9172cSAndroid Build Coastguard Worker }
1643*03f9172cSAndroid Build Coastguard Worker }
1644*03f9172cSAndroid Build Coastguard Worker
1645*03f9172cSAndroid Build Coastguard Worker
1646*03f9172cSAndroid Build Coastguard Worker /**
1647*03f9172cSAndroid Build Coastguard Worker * wpa_bss_parse_basic_ml_element - Parse the Basic Multi-Link element
1648*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1649*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1650*03f9172cSAndroid Build Coastguard Worker * @mld_addr: AP MLD address (or %NULL)
1651*03f9172cSAndroid Build Coastguard Worker * @link_info: Array to store link information (or %NULL),
1652*03f9172cSAndroid Build Coastguard Worker * should be initialized and #MAX_NUM_MLD_LINKS elements long
1653*03f9172cSAndroid Build Coastguard Worker * @missing_links: Result bitmask of links that were not discovered (or %NULL)
1654*03f9172cSAndroid Build Coastguard Worker * @ssid: Target SSID (or %NULL)
1655*03f9172cSAndroid Build Coastguard Worker * @ap_mld_id: On return would hold the corresponding AP MLD ID (or %NULL)
1656*03f9172cSAndroid Build Coastguard Worker * Returns: 0 on success or -1 for non-MLD or parsing failures
1657*03f9172cSAndroid Build Coastguard Worker *
1658*03f9172cSAndroid Build Coastguard Worker * Parses the Basic Multi-Link element of the BSS into @link_info using the scan
1659*03f9172cSAndroid Build Coastguard Worker * information stored in the wpa_supplicant data to fill in information for
1660*03f9172cSAndroid Build Coastguard Worker * links where possible. The @missing_links out parameter will contain any links
1661*03f9172cSAndroid Build Coastguard Worker * for which no corresponding BSS was found.
1662*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_parse_basic_ml_element(struct wpa_supplicant * wpa_s,struct wpa_bss * bss,u8 * ap_mld_addr,u16 * missing_links,struct wpa_ssid * ssid,u8 * ap_mld_id)1663*03f9172cSAndroid Build Coastguard Worker int wpa_bss_parse_basic_ml_element(struct wpa_supplicant *wpa_s,
1664*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss,
1665*03f9172cSAndroid Build Coastguard Worker u8 *ap_mld_addr,
1666*03f9172cSAndroid Build Coastguard Worker u16 *missing_links,
1667*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid,
1668*03f9172cSAndroid Build Coastguard Worker u8 *ap_mld_id)
1669*03f9172cSAndroid Build Coastguard Worker {
1670*03f9172cSAndroid Build Coastguard Worker struct ieee802_11_elems elems;
1671*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mlbuf;
1672*03f9172cSAndroid Build Coastguard Worker const struct element *elem;
1673*03f9172cSAndroid Build Coastguard Worker u8 mbssid_idx = 0;
1674*03f9172cSAndroid Build Coastguard Worker size_t ml_ie_len;
1675*03f9172cSAndroid Build Coastguard Worker const struct ieee80211_eht_ml *eht_ml;
1676*03f9172cSAndroid Build Coastguard Worker const struct eht_ml_basic_common_info *ml_basic_common_info;
1677*03f9172cSAndroid Build Coastguard Worker u8 i, link_id;
1678*03f9172cSAndroid Build Coastguard Worker const u16 control_mask =
1679*03f9172cSAndroid Build Coastguard Worker MULTI_LINK_CONTROL_TYPE_MASK |
1680*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
1681*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
1682*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
1683*03f9172cSAndroid Build Coastguard Worker const u16 control =
1684*03f9172cSAndroid Build Coastguard Worker MULTI_LINK_CONTROL_TYPE_BASIC |
1685*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
1686*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
1687*03f9172cSAndroid Build Coastguard Worker BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
1688*03f9172cSAndroid Build Coastguard Worker u16 missing = 0;
1689*03f9172cSAndroid Build Coastguard Worker u16 seen;
1690*03f9172cSAndroid Build Coastguard Worker const u8 *ies_pos = wpa_bss_ie_ptr(bss);
1691*03f9172cSAndroid Build Coastguard Worker size_t ies_len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
1692*03f9172cSAndroid Build Coastguard Worker int ret = -1;
1693*03f9172cSAndroid Build Coastguard Worker struct mld_link *l;
1694*03f9172cSAndroid Build Coastguard Worker
1695*03f9172cSAndroid Build Coastguard Worker if (ieee802_11_parse_elems(ies_pos, ies_len, &elems, 1) ==
1696*03f9172cSAndroid Build Coastguard Worker ParseFailed) {
1697*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "MLD: Failed to parse elements");
1698*03f9172cSAndroid Build Coastguard Worker return ret;
1699*03f9172cSAndroid Build Coastguard Worker }
1700*03f9172cSAndroid Build Coastguard Worker
1701*03f9172cSAndroid Build Coastguard Worker mlbuf = ieee802_11_defrag(elems.basic_mle, elems.basic_mle_len, true);
1702*03f9172cSAndroid Build Coastguard Worker if (!mlbuf) {
1703*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No Multi-Link element");
1704*03f9172cSAndroid Build Coastguard Worker return ret;
1705*03f9172cSAndroid Build Coastguard Worker }
1706*03f9172cSAndroid Build Coastguard Worker
1707*03f9172cSAndroid Build Coastguard Worker ml_ie_len = wpabuf_len(mlbuf);
1708*03f9172cSAndroid Build Coastguard Worker
1709*03f9172cSAndroid Build Coastguard Worker if (ssid) {
1710*03f9172cSAndroid Build Coastguard Worker struct wpa_ie_data ie;
1711*03f9172cSAndroid Build Coastguard Worker const u8 *rsne;
1712*03f9172cSAndroid Build Coastguard Worker size_t rsne_len;
1713*03f9172cSAndroid Build Coastguard Worker
1714*03f9172cSAndroid Build Coastguard Worker if (elems.rsne_override_2 && wpas_rsn_overriding(wpa_s)) {
1715*03f9172cSAndroid Build Coastguard Worker rsne = elems.rsne_override_2;
1716*03f9172cSAndroid Build Coastguard Worker rsne_len = elems.rsne_override_2_len;
1717*03f9172cSAndroid Build Coastguard Worker } else if (elems.rsne_override &&
1718*03f9172cSAndroid Build Coastguard Worker wpas_rsn_overriding(wpa_s)) {
1719*03f9172cSAndroid Build Coastguard Worker rsne = elems.rsne_override;
1720*03f9172cSAndroid Build Coastguard Worker rsne_len = elems.rsne_override_len;
1721*03f9172cSAndroid Build Coastguard Worker } else {
1722*03f9172cSAndroid Build Coastguard Worker rsne = elems.rsn_ie;
1723*03f9172cSAndroid Build Coastguard Worker rsne_len = elems.rsn_ie_len;
1724*03f9172cSAndroid Build Coastguard Worker }
1725*03f9172cSAndroid Build Coastguard Worker if (!rsne ||
1726*03f9172cSAndroid Build Coastguard Worker wpa_parse_wpa_ie(rsne - 2, 2 + rsne_len, &ie)) {
1727*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RSN element");
1728*03f9172cSAndroid Build Coastguard Worker goto out;
1729*03f9172cSAndroid Build Coastguard Worker }
1730*03f9172cSAndroid Build Coastguard Worker
1731*03f9172cSAndroid Build Coastguard Worker if (!(ie.capabilities & WPA_CAPABILITY_MFPC) ||
1732*03f9172cSAndroid Build Coastguard Worker wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) {
1733*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG,
1734*03f9172cSAndroid Build Coastguard Worker "MLD: No management frame protection");
1735*03f9172cSAndroid Build Coastguard Worker goto out;
1736*03f9172cSAndroid Build Coastguard Worker }
1737*03f9172cSAndroid Build Coastguard Worker
1738*03f9172cSAndroid Build Coastguard Worker ie.key_mgmt &= ~(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
1739*03f9172cSAndroid Build Coastguard Worker WPA_KEY_MGMT_PSK_SHA256);
1740*03f9172cSAndroid Build Coastguard Worker if (!(ie.key_mgmt & ssid->key_mgmt)) {
1741*03f9172cSAndroid Build Coastguard Worker wpa_dbg(wpa_s, MSG_DEBUG,
1742*03f9172cSAndroid Build Coastguard Worker "MLD: No valid key management");
1743*03f9172cSAndroid Build Coastguard Worker goto out;
1744*03f9172cSAndroid Build Coastguard Worker }
1745*03f9172cSAndroid Build Coastguard Worker }
1746*03f9172cSAndroid Build Coastguard Worker
1747*03f9172cSAndroid Build Coastguard Worker /*
1748*03f9172cSAndroid Build Coastguard Worker * for ext ID + 2 control + common info len + MLD address +
1749*03f9172cSAndroid Build Coastguard Worker * link info
1750*03f9172cSAndroid Build Coastguard Worker */
1751*03f9172cSAndroid Build Coastguard Worker if (ml_ie_len < 2UL + 1UL + ETH_ALEN + 1UL)
1752*03f9172cSAndroid Build Coastguard Worker goto out;
1753*03f9172cSAndroid Build Coastguard Worker
1754*03f9172cSAndroid Build Coastguard Worker eht_ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
1755*03f9172cSAndroid Build Coastguard Worker if ((le_to_host16(eht_ml->ml_control) & control_mask) != control) {
1756*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1757*03f9172cSAndroid Build Coastguard Worker "MLD: Unexpected Multi-Link element control=0x%x (mask 0x%x expected 0x%x)",
1758*03f9172cSAndroid Build Coastguard Worker le_to_host16(eht_ml->ml_control), control_mask,
1759*03f9172cSAndroid Build Coastguard Worker control);
1760*03f9172cSAndroid Build Coastguard Worker goto out;
1761*03f9172cSAndroid Build Coastguard Worker }
1762*03f9172cSAndroid Build Coastguard Worker
1763*03f9172cSAndroid Build Coastguard Worker ml_basic_common_info =
1764*03f9172cSAndroid Build Coastguard Worker (const struct eht_ml_basic_common_info *) eht_ml->variable;
1765*03f9172cSAndroid Build Coastguard Worker
1766*03f9172cSAndroid Build Coastguard Worker /* Common info length should be valid */
1767*03f9172cSAndroid Build Coastguard Worker if (ml_basic_common_info->len < ETH_ALEN + 1UL)
1768*03f9172cSAndroid Build Coastguard Worker goto out;
1769*03f9172cSAndroid Build Coastguard Worker
1770*03f9172cSAndroid Build Coastguard Worker /* Get the MLD address and MLD link ID */
1771*03f9172cSAndroid Build Coastguard Worker if (ap_mld_addr)
1772*03f9172cSAndroid Build Coastguard Worker os_memcpy(ap_mld_addr, ml_basic_common_info->mld_addr,
1773*03f9172cSAndroid Build Coastguard Worker ETH_ALEN);
1774*03f9172cSAndroid Build Coastguard Worker
1775*03f9172cSAndroid Build Coastguard Worker link_id = ml_basic_common_info->variable[0] & EHT_ML_LINK_ID_MSK;
1776*03f9172cSAndroid Build Coastguard Worker
1777*03f9172cSAndroid Build Coastguard Worker bss->mld_link_id = link_id;
1778*03f9172cSAndroid Build Coastguard Worker seen = bss->valid_links = BIT(link_id);
1779*03f9172cSAndroid Build Coastguard Worker
1780*03f9172cSAndroid Build Coastguard Worker l = &bss->mld_links[link_id];
1781*03f9172cSAndroid Build Coastguard Worker os_memcpy(l->bssid, bss->bssid, ETH_ALEN);
1782*03f9172cSAndroid Build Coastguard Worker l->freq = bss->freq;
1783*03f9172cSAndroid Build Coastguard Worker
1784*03f9172cSAndroid Build Coastguard Worker
1785*03f9172cSAndroid Build Coastguard Worker /*
1786*03f9172cSAndroid Build Coastguard Worker * The AP MLD ID in the RNR corresponds to the MBSSID index, see
1787*03f9172cSAndroid Build Coastguard Worker * IEEE P802.11be/D4.0, 9.4.2.169.2 (Neighbor AP Information field).
1788*03f9172cSAndroid Build Coastguard Worker *
1789*03f9172cSAndroid Build Coastguard Worker * For the transmitting BSSID it is clear that both the MBSSID index
1790*03f9172cSAndroid Build Coastguard Worker * and the AP MLD ID in the RNR are zero.
1791*03f9172cSAndroid Build Coastguard Worker *
1792*03f9172cSAndroid Build Coastguard Worker * For nontransmitted BSSIDs we will have a BSS generated from the
1793*03f9172cSAndroid Build Coastguard Worker * MBSSID element(s) using inheritance rules. Included in the elements
1794*03f9172cSAndroid Build Coastguard Worker * is the MBSSID Index Element. The RNR is copied from the Beacon/Probe
1795*03f9172cSAndroid Build Coastguard Worker * Response frame that was send by the transmitting BSSID. As such, the
1796*03f9172cSAndroid Build Coastguard Worker * reported AP MLD ID in the RNR will match the value in the MBSSID
1797*03f9172cSAndroid Build Coastguard Worker * Index Element.
1798*03f9172cSAndroid Build Coastguard Worker */
1799*03f9172cSAndroid Build Coastguard Worker elem = (const struct element *)
1800*03f9172cSAndroid Build Coastguard Worker wpa_bss_get_ie(bss, WLAN_EID_MULTIPLE_BSSID_INDEX);
1801*03f9172cSAndroid Build Coastguard Worker if (elem && elem->datalen >= 1)
1802*03f9172cSAndroid Build Coastguard Worker mbssid_idx = elem->data[0];
1803*03f9172cSAndroid Build Coastguard Worker
1804*03f9172cSAndroid Build Coastguard Worker for_each_element_id(elem, WLAN_EID_REDUCED_NEIGHBOR_REPORT,
1805*03f9172cSAndroid Build Coastguard Worker wpa_bss_ie_ptr(bss),
1806*03f9172cSAndroid Build Coastguard Worker bss->ie_len ? bss->ie_len : bss->beacon_ie_len) {
1807*03f9172cSAndroid Build Coastguard Worker const struct ieee80211_neighbor_ap_info *ap_info;
1808*03f9172cSAndroid Build Coastguard Worker const u8 *pos = elem->data;
1809*03f9172cSAndroid Build Coastguard Worker size_t len = elem->datalen;
1810*03f9172cSAndroid Build Coastguard Worker
1811*03f9172cSAndroid Build Coastguard Worker /* RNR IE may contain more than one Neighbor AP Info */
1812*03f9172cSAndroid Build Coastguard Worker while (sizeof(*ap_info) <= len) {
1813*03f9172cSAndroid Build Coastguard Worker size_t ap_info_len = sizeof(*ap_info);
1814*03f9172cSAndroid Build Coastguard Worker u8 count;
1815*03f9172cSAndroid Build Coastguard Worker
1816*03f9172cSAndroid Build Coastguard Worker ap_info = (const struct ieee80211_neighbor_ap_info *)
1817*03f9172cSAndroid Build Coastguard Worker pos;
1818*03f9172cSAndroid Build Coastguard Worker count = RNR_TBTT_INFO_COUNT_VAL(ap_info->tbtt_info_hdr) + 1;
1819*03f9172cSAndroid Build Coastguard Worker ap_info_len += count * ap_info->tbtt_info_len;
1820*03f9172cSAndroid Build Coastguard Worker
1821*03f9172cSAndroid Build Coastguard Worker if (ap_info_len > len)
1822*03f9172cSAndroid Build Coastguard Worker goto out;
1823*03f9172cSAndroid Build Coastguard Worker
1824*03f9172cSAndroid Build Coastguard Worker wpa_bss_parse_ml_rnr_ap_info(wpa_s, bss, mbssid_idx,
1825*03f9172cSAndroid Build Coastguard Worker ap_info, len, &seen,
1826*03f9172cSAndroid Build Coastguard Worker &missing, ssid);
1827*03f9172cSAndroid Build Coastguard Worker
1828*03f9172cSAndroid Build Coastguard Worker pos += ap_info_len;
1829*03f9172cSAndroid Build Coastguard Worker len -= ap_info_len;
1830*03f9172cSAndroid Build Coastguard Worker }
1831*03f9172cSAndroid Build Coastguard Worker }
1832*03f9172cSAndroid Build Coastguard Worker
1833*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MLD: valid_links=%04hx (unresolved: 0x%04hx)",
1834*03f9172cSAndroid Build Coastguard Worker bss->valid_links, missing);
1835*03f9172cSAndroid Build Coastguard Worker
1836*03f9172cSAndroid Build Coastguard Worker for_each_link(bss->valid_links, i) {
1837*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MLD: link=%u, bssid=" MACSTR,
1838*03f9172cSAndroid Build Coastguard Worker i, MAC2STR(bss->mld_links[i].bssid));
1839*03f9172cSAndroid Build Coastguard Worker }
1840*03f9172cSAndroid Build Coastguard Worker
1841*03f9172cSAndroid Build Coastguard Worker if (missing_links)
1842*03f9172cSAndroid Build Coastguard Worker *missing_links = missing;
1843*03f9172cSAndroid Build Coastguard Worker
1844*03f9172cSAndroid Build Coastguard Worker if (ap_mld_id)
1845*03f9172cSAndroid Build Coastguard Worker *ap_mld_id = mbssid_idx;
1846*03f9172cSAndroid Build Coastguard Worker
1847*03f9172cSAndroid Build Coastguard Worker ret = 0;
1848*03f9172cSAndroid Build Coastguard Worker out:
1849*03f9172cSAndroid Build Coastguard Worker wpabuf_free(mlbuf);
1850*03f9172cSAndroid Build Coastguard Worker return ret;
1851*03f9172cSAndroid Build Coastguard Worker }
1852*03f9172cSAndroid Build Coastguard Worker
1853*03f9172cSAndroid Build Coastguard Worker
1854*03f9172cSAndroid Build Coastguard Worker /*
1855*03f9172cSAndroid Build Coastguard Worker * wpa_bss_parse_reconf_ml_element - Parse the Reconfiguration ML element
1856*03f9172cSAndroid Build Coastguard Worker * @wpa_s: Pointer to wpa_supplicant data
1857*03f9172cSAndroid Build Coastguard Worker * @bss: BSS table entry
1858*03f9172cSAndroid Build Coastguard Worker * Returns: The bitmap of links that are going to be removed
1859*03f9172cSAndroid Build Coastguard Worker */
wpa_bss_parse_reconf_ml_element(struct wpa_supplicant * wpa_s,struct wpa_bss * bss)1860*03f9172cSAndroid Build Coastguard Worker u16 wpa_bss_parse_reconf_ml_element(struct wpa_supplicant *wpa_s,
1861*03f9172cSAndroid Build Coastguard Worker struct wpa_bss *bss)
1862*03f9172cSAndroid Build Coastguard Worker {
1863*03f9172cSAndroid Build Coastguard Worker struct ieee802_11_elems elems;
1864*03f9172cSAndroid Build Coastguard Worker struct wpabuf *mlbuf;
1865*03f9172cSAndroid Build Coastguard Worker const u8 *pos = wpa_bss_ie_ptr(bss);
1866*03f9172cSAndroid Build Coastguard Worker size_t len = bss->ie_len ? bss->ie_len : bss->beacon_ie_len;
1867*03f9172cSAndroid Build Coastguard Worker const struct ieee80211_eht_ml *ml;
1868*03f9172cSAndroid Build Coastguard Worker u16 removed_links = 0;
1869*03f9172cSAndroid Build Coastguard Worker u8 ml_common_len;
1870*03f9172cSAndroid Build Coastguard Worker
1871*03f9172cSAndroid Build Coastguard Worker if (ieee802_11_parse_elems(pos, len, &elems, 1) == ParseFailed)
1872*03f9172cSAndroid Build Coastguard Worker return 0;
1873*03f9172cSAndroid Build Coastguard Worker
1874*03f9172cSAndroid Build Coastguard Worker if (!elems.reconf_mle || !elems.reconf_mle_len)
1875*03f9172cSAndroid Build Coastguard Worker return 0;
1876*03f9172cSAndroid Build Coastguard Worker
1877*03f9172cSAndroid Build Coastguard Worker mlbuf = ieee802_11_defrag(elems.reconf_mle, elems.reconf_mle_len, true);
1878*03f9172cSAndroid Build Coastguard Worker if (!mlbuf)
1879*03f9172cSAndroid Build Coastguard Worker return 0;
1880*03f9172cSAndroid Build Coastguard Worker
1881*03f9172cSAndroid Build Coastguard Worker ml = (const struct ieee80211_eht_ml *) wpabuf_head(mlbuf);
1882*03f9172cSAndroid Build Coastguard Worker len = wpabuf_len(mlbuf);
1883*03f9172cSAndroid Build Coastguard Worker
1884*03f9172cSAndroid Build Coastguard Worker if (len < sizeof(*ml))
1885*03f9172cSAndroid Build Coastguard Worker goto out;
1886*03f9172cSAndroid Build Coastguard Worker
1887*03f9172cSAndroid Build Coastguard Worker ml_common_len = 1;
1888*03f9172cSAndroid Build Coastguard Worker if (ml->ml_control & RECONF_MULTI_LINK_CTRL_PRES_MLD_MAC_ADDR)
1889*03f9172cSAndroid Build Coastguard Worker ml_common_len += ETH_ALEN;
1890*03f9172cSAndroid Build Coastguard Worker
1891*03f9172cSAndroid Build Coastguard Worker if (len < sizeof(*ml) + ml_common_len) {
1892*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1893*03f9172cSAndroid Build Coastguard Worker "MLD: Unexpected Reconfiguration ML element length: (%zu < %zu)",
1894*03f9172cSAndroid Build Coastguard Worker len, sizeof(*ml) + ml_common_len);
1895*03f9172cSAndroid Build Coastguard Worker goto out;
1896*03f9172cSAndroid Build Coastguard Worker }
1897*03f9172cSAndroid Build Coastguard Worker
1898*03f9172cSAndroid Build Coastguard Worker pos = ml->variable + ml_common_len;
1899*03f9172cSAndroid Build Coastguard Worker len -= sizeof(*ml) + ml_common_len;
1900*03f9172cSAndroid Build Coastguard Worker
1901*03f9172cSAndroid Build Coastguard Worker while (len >= 2 + sizeof(struct ieee80211_eht_per_sta_profile)) {
1902*03f9172cSAndroid Build Coastguard Worker size_t sub_elem_len = *(pos + 1);
1903*03f9172cSAndroid Build Coastguard Worker
1904*03f9172cSAndroid Build Coastguard Worker if (2 + sub_elem_len > len) {
1905*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG,
1906*03f9172cSAndroid Build Coastguard Worker "MLD: Invalid link info len: %zu %zu",
1907*03f9172cSAndroid Build Coastguard Worker 2 + sub_elem_len, len);
1908*03f9172cSAndroid Build Coastguard Worker goto out;
1909*03f9172cSAndroid Build Coastguard Worker }
1910*03f9172cSAndroid Build Coastguard Worker
1911*03f9172cSAndroid Build Coastguard Worker if (*pos == EHT_ML_SUB_ELEM_PER_STA_PROFILE) {
1912*03f9172cSAndroid Build Coastguard Worker const struct ieee80211_eht_per_sta_profile *sta_prof =
1913*03f9172cSAndroid Build Coastguard Worker (const struct ieee80211_eht_per_sta_profile *)
1914*03f9172cSAndroid Build Coastguard Worker (pos + 2);
1915*03f9172cSAndroid Build Coastguard Worker u16 control = le_to_host16(sta_prof->sta_control);
1916*03f9172cSAndroid Build Coastguard Worker u8 link_id;
1917*03f9172cSAndroid Build Coastguard Worker
1918*03f9172cSAndroid Build Coastguard Worker link_id = control & EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK;
1919*03f9172cSAndroid Build Coastguard Worker removed_links |= BIT(link_id);
1920*03f9172cSAndroid Build Coastguard Worker }
1921*03f9172cSAndroid Build Coastguard Worker
1922*03f9172cSAndroid Build Coastguard Worker pos += 2 + sub_elem_len;
1923*03f9172cSAndroid Build Coastguard Worker len -= 2 + sub_elem_len;
1924*03f9172cSAndroid Build Coastguard Worker }
1925*03f9172cSAndroid Build Coastguard Worker
1926*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "MLD: Reconfiguration: removed_links=0x%x",
1927*03f9172cSAndroid Build Coastguard Worker removed_links);
1928*03f9172cSAndroid Build Coastguard Worker out:
1929*03f9172cSAndroid Build Coastguard Worker wpabuf_free(mlbuf);
1930*03f9172cSAndroid Build Coastguard Worker return removed_links;
1931*03f9172cSAndroid Build Coastguard Worker }
1932*03f9172cSAndroid Build Coastguard Worker
1933*03f9172cSAndroid Build Coastguard Worker
wpa_bss_supported_cipher(struct wpa_supplicant * wpa_s,int pairwise_cipher)1934*03f9172cSAndroid Build Coastguard Worker static bool wpa_bss_supported_cipher(struct wpa_supplicant *wpa_s,
1935*03f9172cSAndroid Build Coastguard Worker int pairwise_cipher)
1936*03f9172cSAndroid Build Coastguard Worker {
1937*03f9172cSAndroid Build Coastguard Worker if (!wpa_s->drv_enc)
1938*03f9172cSAndroid Build Coastguard Worker return true;
1939*03f9172cSAndroid Build Coastguard Worker
1940*03f9172cSAndroid Build Coastguard Worker if ((pairwise_cipher & WPA_CIPHER_CCMP) &&
1941*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP))
1942*03f9172cSAndroid Build Coastguard Worker return true;
1943*03f9172cSAndroid Build Coastguard Worker
1944*03f9172cSAndroid Build Coastguard Worker if ((pairwise_cipher & WPA_CIPHER_GCMP) &&
1945*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP))
1946*03f9172cSAndroid Build Coastguard Worker return true;
1947*03f9172cSAndroid Build Coastguard Worker
1948*03f9172cSAndroid Build Coastguard Worker if ((pairwise_cipher & WPA_CIPHER_CCMP_256) &&
1949*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_CCMP_256))
1950*03f9172cSAndroid Build Coastguard Worker return true;
1951*03f9172cSAndroid Build Coastguard Worker
1952*03f9172cSAndroid Build Coastguard Worker if ((pairwise_cipher & WPA_CIPHER_GCMP_256) &&
1953*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP_256))
1954*03f9172cSAndroid Build Coastguard Worker return true;
1955*03f9172cSAndroid Build Coastguard Worker
1956*03f9172cSAndroid Build Coastguard Worker return false;
1957*03f9172cSAndroid Build Coastguard Worker }
1958*03f9172cSAndroid Build Coastguard Worker
1959*03f9172cSAndroid Build Coastguard Worker
wpa_bss_supported_key_mgmt(struct wpa_supplicant * wpa_s,int key_mgmt)1960*03f9172cSAndroid Build Coastguard Worker static bool wpa_bss_supported_key_mgmt(struct wpa_supplicant *wpa_s,
1961*03f9172cSAndroid Build Coastguard Worker int key_mgmt)
1962*03f9172cSAndroid Build Coastguard Worker {
1963*03f9172cSAndroid Build Coastguard Worker if (!wpa_s->drv_key_mgmt)
1964*03f9172cSAndroid Build Coastguard Worker return true;
1965*03f9172cSAndroid Build Coastguard Worker
1966*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X) &&
1967*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2))
1968*03f9172cSAndroid Build Coastguard Worker return true;
1969*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) &&
1970*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_802_1X_SHA256))
1971*03f9172cSAndroid Build Coastguard Worker return true;
1972*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) &&
1973*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT))
1974*03f9172cSAndroid Build Coastguard Worker return true;
1975*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X_SHA384) &&
1976*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_802_1X_SHA384))
1977*03f9172cSAndroid Build Coastguard Worker return true;
1978*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) &&
1979*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B))
1980*03f9172cSAndroid Build Coastguard Worker return true;
1981*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) &&
1982*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192))
1983*03f9172cSAndroid Build Coastguard Worker return true;
1984*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_PSK) &&
1985*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK))
1986*03f9172cSAndroid Build Coastguard Worker return true;
1987*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_PSK) &&
1988*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK))
1989*03f9172cSAndroid Build Coastguard Worker return true;
1990*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_PSK_SHA256) &&
1991*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_PSK_SHA256))
1992*03f9172cSAndroid Build Coastguard Worker return true;
1993*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_SAE) &&
1994*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE))
1995*03f9172cSAndroid Build Coastguard Worker return true;
1996*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_SAE_EXT_KEY) &&
1997*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SAE_EXT_KEY))
1998*03f9172cSAndroid Build Coastguard Worker return true;
1999*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_SAE) &&
2000*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE))
2001*03f9172cSAndroid Build Coastguard Worker return true;
2002*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_SAE_EXT_KEY) &&
2003*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_SAE_EXT_KEY))
2004*03f9172cSAndroid Build Coastguard Worker return true;
2005*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_OWE) &&
2006*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_OWE))
2007*03f9172cSAndroid Build Coastguard Worker return true;
2008*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_DPP) &&
2009*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_DPP))
2010*03f9172cSAndroid Build Coastguard Worker return true;
2011*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FILS_SHA256) &&
2012*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256))
2013*03f9172cSAndroid Build Coastguard Worker return true;
2014*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FILS_SHA384) &&
2015*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384))
2016*03f9172cSAndroid Build Coastguard Worker return true;
2017*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA256) &&
2018*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA256))
2019*03f9172cSAndroid Build Coastguard Worker return true;
2020*03f9172cSAndroid Build Coastguard Worker if ((key_mgmt & WPA_KEY_MGMT_FT_FILS_SHA384) &&
2021*03f9172cSAndroid Build Coastguard Worker (wpa_s->drv_key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_FILS_SHA384))
2022*03f9172cSAndroid Build Coastguard Worker return true;
2023*03f9172cSAndroid Build Coastguard Worker
2024*03f9172cSAndroid Build Coastguard Worker return false;
2025*03f9172cSAndroid Build Coastguard Worker }
2026*03f9172cSAndroid Build Coastguard Worker
2027*03f9172cSAndroid Build Coastguard Worker
wpa_bss_supported_rsne(struct wpa_supplicant * wpa_s,struct wpa_ssid * ssid,const u8 * ie)2028*03f9172cSAndroid Build Coastguard Worker static bool wpa_bss_supported_rsne(struct wpa_supplicant *wpa_s,
2029*03f9172cSAndroid Build Coastguard Worker struct wpa_ssid *ssid, const u8 *ie)
2030*03f9172cSAndroid Build Coastguard Worker {
2031*03f9172cSAndroid Build Coastguard Worker struct wpa_ie_data data;
2032*03f9172cSAndroid Build Coastguard Worker
2033*03f9172cSAndroid Build Coastguard Worker if (wpa_parse_wpa_ie_rsn(ie, 2 + ie[1], &data) < 0)
2034*03f9172cSAndroid Build Coastguard Worker return false;
2035*03f9172cSAndroid Build Coastguard Worker
2036*03f9172cSAndroid Build Coastguard Worker /* Check that there is a supported AKM and pairwise cipher based on
2037*03f9172cSAndroid Build Coastguard Worker * overall capabilities */
2038*03f9172cSAndroid Build Coastguard Worker if (!data.pairwise_cipher || !data.key_mgmt)
2039*03f9172cSAndroid Build Coastguard Worker return false;
2040*03f9172cSAndroid Build Coastguard Worker
2041*03f9172cSAndroid Build Coastguard Worker if (wpa_s->drv_capa_known) {
2042*03f9172cSAndroid Build Coastguard Worker if (!wpa_bss_supported_cipher(wpa_s, data.pairwise_cipher) ||
2043*03f9172cSAndroid Build Coastguard Worker !wpa_bss_supported_key_mgmt(wpa_s, data.key_mgmt))
2044*03f9172cSAndroid Build Coastguard Worker return false;
2045*03f9172cSAndroid Build Coastguard Worker }
2046*03f9172cSAndroid Build Coastguard Worker
2047*03f9172cSAndroid Build Coastguard Worker if (ssid) {
2048*03f9172cSAndroid Build Coastguard Worker /* Check that there is a supported AKM and pairwise cipher
2049*03f9172cSAndroid Build Coastguard Worker * based on the specific network profile. */
2050*03f9172cSAndroid Build Coastguard Worker if ((ssid->pairwise_cipher & data.pairwise_cipher) == 0)
2051*03f9172cSAndroid Build Coastguard Worker return false;
2052*03f9172cSAndroid Build Coastguard Worker if ((ssid->key_mgmt & data.key_mgmt) == 0)
2053*03f9172cSAndroid Build Coastguard Worker return false;
2054*03f9172cSAndroid Build Coastguard Worker }
2055*03f9172cSAndroid Build Coastguard Worker
2056*03f9172cSAndroid Build Coastguard Worker return true;
2057*03f9172cSAndroid Build Coastguard Worker }
2058*03f9172cSAndroid Build Coastguard Worker
2059*03f9172cSAndroid Build Coastguard Worker
wpa_bss_get_rsne(struct wpa_supplicant * wpa_s,const struct wpa_bss * bss,struct wpa_ssid * ssid,bool mlo)2060*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_rsne(struct wpa_supplicant *wpa_s,
2061*03f9172cSAndroid Build Coastguard Worker const struct wpa_bss *bss, struct wpa_ssid *ssid,
2062*03f9172cSAndroid Build Coastguard Worker bool mlo)
2063*03f9172cSAndroid Build Coastguard Worker {
2064*03f9172cSAndroid Build Coastguard Worker const u8 *ie;
2065*03f9172cSAndroid Build Coastguard Worker
2066*03f9172cSAndroid Build Coastguard Worker if (wpas_rsn_overriding(wpa_s)) {
2067*03f9172cSAndroid Build Coastguard Worker if (!ssid)
2068*03f9172cSAndroid Build Coastguard Worker ssid = wpa_s->current_ssid;
2069*03f9172cSAndroid Build Coastguard Worker
2070*03f9172cSAndroid Build Coastguard Worker /* MLO cases for RSN overriding are required to use RSNE
2071*03f9172cSAndroid Build Coastguard Worker * Override 2 element and RSNXE Override element together. */
2072*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_vendor_ie(bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE);
2073*03f9172cSAndroid Build Coastguard Worker if (mlo && ie &&
2074*03f9172cSAndroid Build Coastguard Worker !wpa_bss_get_vendor_ie(bss,
2075*03f9172cSAndroid Build Coastguard Worker RSNXE_OVERRIDE_IE_VENDOR_TYPE)) {
2076*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS " MACSTR
2077*03f9172cSAndroid Build Coastguard Worker " advertises RSNE Override 2 element without RSNXE Override element - ignore RSNE Override 2 element for MLO",
2078*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid));
2079*03f9172cSAndroid Build Coastguard Worker } else if (ie && wpa_bss_supported_rsne(wpa_s, ssid, ie)) {
2080*03f9172cSAndroid Build Coastguard Worker return ie;
2081*03f9172cSAndroid Build Coastguard Worker }
2082*03f9172cSAndroid Build Coastguard Worker
2083*03f9172cSAndroid Build Coastguard Worker if (!mlo) {
2084*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_vendor_ie(
2085*03f9172cSAndroid Build Coastguard Worker bss, RSNE_OVERRIDE_IE_VENDOR_TYPE);
2086*03f9172cSAndroid Build Coastguard Worker if (ie && wpa_bss_supported_rsne(wpa_s, ssid, ie))
2087*03f9172cSAndroid Build Coastguard Worker return ie;
2088*03f9172cSAndroid Build Coastguard Worker }
2089*03f9172cSAndroid Build Coastguard Worker }
2090*03f9172cSAndroid Build Coastguard Worker
2091*03f9172cSAndroid Build Coastguard Worker return wpa_bss_get_ie(bss, WLAN_EID_RSN);
2092*03f9172cSAndroid Build Coastguard Worker }
2093*03f9172cSAndroid Build Coastguard Worker
2094*03f9172cSAndroid Build Coastguard Worker
wpa_bss_get_rsnxe(struct wpa_supplicant * wpa_s,const struct wpa_bss * bss,struct wpa_ssid * ssid,bool mlo)2095*03f9172cSAndroid Build Coastguard Worker const u8 * wpa_bss_get_rsnxe(struct wpa_supplicant *wpa_s,
2096*03f9172cSAndroid Build Coastguard Worker const struct wpa_bss *bss, struct wpa_ssid *ssid,
2097*03f9172cSAndroid Build Coastguard Worker bool mlo)
2098*03f9172cSAndroid Build Coastguard Worker {
2099*03f9172cSAndroid Build Coastguard Worker const u8 *ie;
2100*03f9172cSAndroid Build Coastguard Worker
2101*03f9172cSAndroid Build Coastguard Worker if (wpas_rsn_overriding(wpa_s)) {
2102*03f9172cSAndroid Build Coastguard Worker ie = wpa_bss_get_vendor_ie(bss, RSNXE_OVERRIDE_IE_VENDOR_TYPE);
2103*03f9172cSAndroid Build Coastguard Worker if (ie) {
2104*03f9172cSAndroid Build Coastguard Worker const u8 *tmp;
2105*03f9172cSAndroid Build Coastguard Worker
2106*03f9172cSAndroid Build Coastguard Worker tmp = wpa_bss_get_rsne(wpa_s, bss, ssid, mlo);
2107*03f9172cSAndroid Build Coastguard Worker if (!tmp || tmp[0] == WLAN_EID_RSN) {
2108*03f9172cSAndroid Build Coastguard Worker /* An acceptable RSNE override element was not
2109*03f9172cSAndroid Build Coastguard Worker * found, so need to ignore RSNXE overriding. */
2110*03f9172cSAndroid Build Coastguard Worker goto out;
2111*03f9172cSAndroid Build Coastguard Worker }
2112*03f9172cSAndroid Build Coastguard Worker
2113*03f9172cSAndroid Build Coastguard Worker return ie;
2114*03f9172cSAndroid Build Coastguard Worker }
2115*03f9172cSAndroid Build Coastguard Worker
2116*03f9172cSAndroid Build Coastguard Worker /* MLO cases for RSN overriding are required to use RSNE
2117*03f9172cSAndroid Build Coastguard Worker * Override 2 element and RSNXE Override element together. */
2118*03f9172cSAndroid Build Coastguard Worker if (mlo && wpa_bss_get_vendor_ie(
2119*03f9172cSAndroid Build Coastguard Worker bss, RSNE_OVERRIDE_2_IE_VENDOR_TYPE)) {
2120*03f9172cSAndroid Build Coastguard Worker wpa_printf(MSG_DEBUG, "BSS " MACSTR
2121*03f9172cSAndroid Build Coastguard Worker " advertises RSNXE Override element without RSNE Override 2 element - ignore RSNXE Override element for MLO",
2122*03f9172cSAndroid Build Coastguard Worker MAC2STR(bss->bssid));
2123*03f9172cSAndroid Build Coastguard Worker goto out;
2124*03f9172cSAndroid Build Coastguard Worker }
2125*03f9172cSAndroid Build Coastguard Worker }
2126*03f9172cSAndroid Build Coastguard Worker
2127*03f9172cSAndroid Build Coastguard Worker out:
2128*03f9172cSAndroid Build Coastguard Worker return wpa_bss_get_ie(bss, WLAN_EID_RSNX);
2129*03f9172cSAndroid Build Coastguard Worker }
2130