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