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