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