1 /*
2  * SPDX-FileCopyrightText: 2020-2024 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "utils/includes.h"
8 
9 #include "utils/common.h"
10 #include "common/ieee802_11_defs.h"
11 #include "common/wpa_supplicant_i.h"
12 #include "utils/wpa_debug.h"
13 #include "esp_wifi_driver.h"
14 #include "esp_wifi_types.h"
15 #include "drivers/driver.h"
16 #include "common/scan.h"
17 #include "common/bss.h"
18 #include "common/rrm.h"
19 #include "common/ieee802_11_common.h"
20 #include "esp_common_i.h"
21 #include "esp_scan_i.h"
22 #include "common/wnm_sta.h"
23 #include "esp_scan_i.h"
24 #include "esp_common_i.h"
25 
26 extern struct wpa_supplicant g_wpa_supp;
27 
scan_done_event_handler(void * arg,ETS_STATUS status)28 static void scan_done_event_handler(void *arg, ETS_STATUS status)
29 {
30 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
31 
32 	/* update last scan time */
33 	wpa_s->scan_start_tsf = esp_wifi_get_tsf_time(WIFI_IF_STA);
34 	if (wpa_s->scanning) {
35 		wpa_s->type &= ~(1 << WLAN_FC_STYPE_BEACON) & ~(1 << WLAN_FC_STYPE_PROBE_RESP);
36 		esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
37 	}
38 #ifdef CONFIG_SUPPLICANT_TASK
39 	if (esp_supplicant_post_evt(SIG_SUPPLICANT_SCAN_DONE, 0) != 0) {
40 		wpa_printf(MSG_ERROR, "Posting of scan done failed!");
41 	}
42 #else
43        esp_supplicant_handle_scan_done_evt();
44 #endif /*CONFIG_SUPPLICANT_TASK*/
45 }
46 
47 #if defined(CONFIG_IEEE80211KV)
handle_wnm_scan_done(struct wpa_supplicant * wpa_s)48 static void handle_wnm_scan_done(struct wpa_supplicant *wpa_s)
49 {
50 	struct wpa_bss *bss = wpa_bss_get_next_bss(wpa_s, wpa_s->current_bss);
51 
52 	if (wpa_s->wnm_neighbor_report_elements) {
53 		wnm_scan_process(wpa_s, 1);
54 	} else if (wpa_s->wnm_dissoc_timer) {
55 		if (wpa_s->num_bss == 1) {
56 			wpa_printf(MSG_INFO, "not able to find another candidate, do nothing");
57 			return;
58 		}
59 		/* this is a already matched bss */
60 		if (bss) {
61 			wnm_bss_tm_connect(wpa_s, bss, NULL, 1);
62 		}
63 	}
64 }
65 #endif
66 
scan_done_cleanup(struct wpa_supplicant * wpa_s)67 static void scan_done_cleanup(struct wpa_supplicant *wpa_s)
68 {
69 	wpa_s->scanning = 0;
70 	wpa_s->scan_reason = 0;
71 	/* clean scan list from net80211 */
72 	esp_wifi_clear_ap_list();
73 }
74 
esp_supplicant_handle_scan_done_evt(void)75 void esp_supplicant_handle_scan_done_evt(void)
76 {
77 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
78 
79 	wpa_printf(MSG_INFO, "scan done received");
80 #if defined(CONFIG_IEEE80211KV)
81 	/* Check which module started this, call the respective function */
82 	if (wpa_s->scan_reason == REASON_RRM_BEACON_REPORT) {
83 		wpas_beacon_rep_scan_process(wpa_s, wpa_s->scan_start_tsf);
84 	} else if (wpa_s->scan_reason == REASON_WNM_BSS_TRANS_REQ) {
85 		handle_wnm_scan_done(wpa_s);
86 	}
87 #endif
88 	if (wpa_s->scanning) {
89 		scan_done_cleanup(wpa_s);
90 	}
91 	wpa_bss_update_end(wpa_s);
92 #ifndef SCAN_CACHE_SUPPORTED
93 	wpa_bss_flush(wpa_s);
94 #endif
95 }
96 
esp_scan_init(struct wpa_supplicant * wpa_s)97 void esp_scan_init(struct wpa_supplicant *wpa_s)
98 {
99 	wpa_s->scanning = 0;
100 	wpa_bss_init(wpa_s);
101 	wpa_s->last_scan_res = NULL;
102 	wpa_s->last_scan_res_used = 0;
103 }
104 
esp_scan_deinit(struct wpa_supplicant * wpa_s)105 void esp_scan_deinit(struct wpa_supplicant *wpa_s)
106 {
107 	wpa_bss_deinit(wpa_s);
108 	os_free(wpa_s->last_scan_res);
109 	wpa_s->last_scan_res = NULL;
110 	wpa_s->last_scan_res_used = 0;
111 }
112 
esp_handle_beacon_probe(u8 type,u8 * frame,size_t len,u8 * sender,int8_t rssi,u8 channel,u64 current_tsf)113 int esp_handle_beacon_probe(u8 type, u8 *frame, size_t len, u8 *sender,
114 			    int8_t rssi, u8 channel, u64 current_tsf)
115 {
116 	struct wpa_supplicant *wpa_s = &g_wpa_supp;
117 	struct os_reltime now;
118 	struct wpa_scan_res *res;
119 	u8 *ptr;
120 
121 	if (len < 12) {
122 		wpa_printf(MSG_ERROR, "beacon/probe is having short len=%d", len);
123 		return -1;
124 	}
125 
126 	res = os_zalloc(sizeof(struct wpa_scan_res) + len - 12);
127 	if (!res) {
128 		wpa_printf(MSG_ERROR, "failed to allocate memory");
129 		return -1;
130 	}
131 
132 	ptr = (u8 *)res;
133 	os_get_time(&now);
134 	os_memcpy(res->bssid, sender, ETH_ALEN);
135 	res->tsf = WPA_GET_LE64(frame);
136 	frame += 8;
137 	len -= 8;
138 
139 	if ((wpa_s->scan_start_tsf == 0) &&
140 	    wpa_s->current_bss &&
141 	    (os_memcmp(wpa_s->current_bss, sender, ETH_ALEN) == 0)) {
142 		wpa_s->scan_start_tsf = res->tsf;
143 		os_memcpy(wpa_s->tsf_bssid, sender, ETH_ALEN);
144 	}
145 	res->beacon_int = WPA_GET_LE16(frame);
146 
147 	frame += 2;
148 	len -= 2;
149 	res->caps = WPA_GET_LE16(frame);
150 	frame += 2;
151 	len -= 2;
152 
153 	res->chan = channel;
154 	res->noise = 0;
155 	res->level = rssi;
156 	os_memcpy(res->tsf_bssid, wpa_s->tsf_bssid, ETH_ALEN);
157 	res->parent_tsf = current_tsf - wpa_s->scan_start_tsf;
158 	res->ie_len = len;
159 
160 	ptr += sizeof(struct wpa_scan_res);
161 
162 	/* update rest of the frame */
163 	os_memcpy(ptr, frame, len);
164 	wpa_bss_update_scan_res(wpa_s, res, &now);
165 	os_free(res);
166 
167 	return 0;
168 }
169 
issue_scan(struct wpa_supplicant * wpa_s,struct wpa_driver_scan_params * scan_params)170 static int issue_scan(struct wpa_supplicant *wpa_s,
171 		      struct wpa_driver_scan_params *scan_params)
172 {
173 	wifi_scan_config_t *params = NULL;
174 	int ret = 0;
175 	u64 scan_start_tsf = esp_wifi_get_tsf_time(WIFI_IF_STA);
176 
177 	/* TODO: Directly try to connect if scan results are recent */
178 	if ((scan_start_tsf -  wpa_s->scan_start_tsf) > 100000) {
179 		wpa_printf(MSG_DEBUG, "flushing old scan cache %llu",
180 				(scan_start_tsf -  wpa_s->scan_start_tsf));
181 		wpa_bss_flush(wpa_s);
182 	}
183 
184 	esp_wifi_get_macaddr_internal(WIFI_IF_STA, wpa_s->tsf_bssid);
185 
186 	if (scan_params) {
187 		params = os_zalloc(sizeof(wifi_scan_config_t));
188 		if (!params) {
189 			wpa_printf(MSG_ERROR, "failed to allocate memory");
190 			return -1;
191 		}
192 		if (scan_params->num_ssids) {
193 			params->ssid = os_zalloc(scan_params->ssids[0].ssid_len + 1);
194 			if (!params->ssid) {
195 				wpa_printf(MSG_ERROR, "failed to allocate memory");
196 				ret = -1;
197 				goto cleanup;
198 			}
199 			os_memcpy(params->ssid, scan_params->ssids[0].ssid, scan_params->ssids[0].ssid_len);
200 		} else
201 
202 		if (scan_params->mode == BEACON_REPORT_MODE_PASSIVE) {
203 			params->scan_type = ESP32_WIFI_SCAN_TYPE_PASSIVE;
204 		} else {
205 			params->scan_type = ESP32_WIFI_SCAN_TYPE_ACTIVE;
206 		}
207 
208 		if (scan_params->bssid) {
209 			params->bssid = os_zalloc(ETH_ALEN);
210 			if (!params->bssid) {
211 				wpa_printf(MSG_ERROR, "failed to allocate memory");
212 				ret = -1;
213 				goto cleanup;
214 			}
215 			os_memcpy(params->bssid, scan_params->bssid, ETH_ALEN);
216 		}
217 		if (scan_params->channel) {
218 			params->channel = scan_params->channel;
219 		}
220 
221 		if (scan_params->duration) {
222 			params->scan_time.passive = scan_params->duration;
223 			params->scan_time.active.min = scan_params->duration;
224 			params->scan_time.active.max = scan_params->duration;
225 		}
226 	}
227 
228 	wpa_s->scan_start_tsf = scan_start_tsf;
229 	/* Register frames to come to supplicant when we park on channel */
230 	wpa_s->type |= (1 << WLAN_FC_STYPE_BEACON) | (1 << WLAN_FC_STYPE_PROBE_RESP);
231 	esp_wifi_register_mgmt_frame_internal(wpa_s->type, wpa_s->subtype);
232 
233 	typedef void (* scan_done_cb_t)(void *arg, ETS_STATUS status);
234 	extern int esp_wifi_promiscuous_scan_start(wifi_scan_config_t *config, scan_done_cb_t cb);
235 	/* issue scan */
236 	if (esp_wifi_promiscuous_scan_start(params, scan_done_event_handler) < 0) {
237 		ret = -1;
238 		goto cleanup;
239 	}
240 	wpa_s->scanning = 1;
241 	wpa_bss_update_start(wpa_s);
242 	wpa_printf(MSG_INFO, "scan issued at time=%llu", wpa_s->scan_start_tsf);
243 
244 cleanup:
245     if (params) {
246         if (params->ssid)
247             os_free(params->ssid);
248         if (params->bssid)
249             os_free(params->bssid);
250         os_free(params);
251     }
252 
253 	return ret;
254 }
255 
256 /**
257  * wpa_supplicant_trigger_scan - Request driver to start a scan
258  * @wpa_s: Pointer to wpa_supplicant data
259  * @params: Scan parameters
260  * Returns: 0 on success, -1 on failure
261  */
wpa_supplicant_trigger_scan(struct wpa_supplicant * wpa_s,struct wpa_driver_scan_params * params)262 int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
263 				struct wpa_driver_scan_params *params)
264 {
265 	return issue_scan(wpa_s, params);
266 }
267 
wpa_scan_results_free(struct wpa_scan_results * res)268 void wpa_scan_results_free(struct wpa_scan_results *res)
269 {
270 	size_t i;
271 
272 	if (res == NULL)
273 		return;
274 
275 	for (i = 0; i < res->num; i++)
276 		os_free(res->res[i]);
277 	os_free(res->res);
278 	os_free(res);
279 }
280