]>
Commit | Line | Data |
---|---|---|
6fc6879b JM |
1 | /* |
2 | * WPA Supplicant - testing driver interface | |
ad08c363 | 3 | * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> |
6fc6879b JM |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * Alternatively, this software may be distributed under the terms of BSD | |
10 | * license. | |
11 | * | |
12 | * See README and COPYING for more details. | |
13 | */ | |
14 | ||
329a55b3 JM |
15 | /* Make dure we get winsock2.h for Windows build to get sockaddr_storage */ |
16 | #include "build_config.h" | |
17 | #ifdef CONFIG_NATIVE_WINDOWS | |
18 | #include <winsock2.h> | |
19 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
20 | ||
6fc6879b | 21 | #include "includes.h" |
329a55b3 JM |
22 | |
23 | #ifndef CONFIG_NATIVE_WINDOWS | |
6fc6879b JM |
24 | #include <sys/un.h> |
25 | #include <dirent.h> | |
26 | #include <sys/stat.h> | |
329a55b3 JM |
27 | #define DRIVER_TEST_UNIX |
28 | #endif /* CONFIG_NATIVE_WINDOWS */ | |
6fc6879b JM |
29 | |
30 | #include "common.h" | |
31 | #include "driver.h" | |
32 | #include "l2_packet/l2_packet.h" | |
33 | #include "eloop.h" | |
34 | #include "sha1.h" | |
35 | #include "ieee802_11_defs.h" | |
36 | ||
37 | ||
ac305589 JM |
38 | struct wpa_driver_test_global { |
39 | int dummy; | |
40 | }; | |
41 | ||
6fc6879b | 42 | struct wpa_driver_test_data { |
ac305589 | 43 | struct wpa_driver_test_global *global; |
6fc6879b JM |
44 | void *ctx; |
45 | u8 own_addr[ETH_ALEN]; | |
46 | int test_socket; | |
329a55b3 | 47 | #ifdef DRIVER_TEST_UNIX |
6fc6879b | 48 | struct sockaddr_un hostapd_addr; |
329a55b3 | 49 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b | 50 | int hostapd_addr_set; |
e33bbd8f JM |
51 | struct sockaddr_in hostapd_addr_udp; |
52 | int hostapd_addr_udp_set; | |
6fc6879b JM |
53 | char *own_socket_path; |
54 | char *test_dir; | |
55 | u8 bssid[ETH_ALEN]; | |
56 | u8 ssid[32]; | |
57 | size_t ssid_len; | |
58 | #define MAX_SCAN_RESULTS 30 | |
59 | struct wpa_scan_res *scanres[MAX_SCAN_RESULTS]; | |
60 | size_t num_scanres; | |
61 | int use_associnfo; | |
62 | u8 assoc_wpa_ie[80]; | |
63 | size_t assoc_wpa_ie_len; | |
64 | int use_mlme; | |
65 | int associated; | |
ad08c363 JM |
66 | u8 *probe_req_ie; |
67 | size_t probe_req_ie_len; | |
0d1286e4 JM |
68 | int ibss; |
69 | int privacy; | |
6fc6879b JM |
70 | }; |
71 | ||
72 | ||
73 | static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx) | |
74 | { | |
75 | struct wpa_driver_test_data *drv = eloop_ctx; | |
76 | ||
329a55b3 | 77 | #ifdef DRIVER_TEST_UNIX |
6fc6879b JM |
78 | if (drv->associated && drv->hostapd_addr_set) { |
79 | struct stat st; | |
80 | if (stat(drv->hostapd_addr.sun_path, &st) < 0) { | |
81 | wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s", | |
82 | __func__, strerror(errno)); | |
83 | drv->associated = 0; | |
84 | wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); | |
85 | } | |
86 | } | |
329a55b3 | 87 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b JM |
88 | |
89 | eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); | |
90 | } | |
91 | ||
92 | ||
93 | static int wpa_driver_test_set_wpa(void *priv, int enabled) | |
94 | { | |
95 | wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled); | |
96 | return 0; | |
97 | } | |
98 | ||
99 | ||
100 | static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx) | |
101 | { | |
102 | wpa_printf(MSG_DEBUG, "Scan timeout - try to get results"); | |
103 | wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL); | |
104 | } | |
105 | ||
106 | ||
329a55b3 | 107 | #ifdef DRIVER_TEST_UNIX |
6fc6879b JM |
108 | static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv, |
109 | const char *path) | |
110 | { | |
111 | struct dirent *dent; | |
112 | DIR *dir; | |
113 | struct sockaddr_un addr; | |
ad08c363 JM |
114 | char cmd[512], *pos, *end; |
115 | int ret; | |
6fc6879b JM |
116 | |
117 | dir = opendir(path); | |
118 | if (dir == NULL) | |
119 | return; | |
120 | ||
ad08c363 JM |
121 | end = cmd + sizeof(cmd); |
122 | pos = cmd; | |
123 | ret = os_snprintf(pos, end - pos, "SCAN " MACSTR, | |
124 | MAC2STR(drv->own_addr)); | |
125 | if (ret >= 0 && ret < end - pos) | |
126 | pos += ret; | |
127 | if (drv->probe_req_ie) { | |
128 | ret = os_snprintf(pos, end - pos, " "); | |
129 | if (ret >= 0 && ret < end - pos) | |
130 | pos += ret; | |
131 | pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie, | |
132 | drv->probe_req_ie_len); | |
133 | } | |
134 | end[-1] = '\0'; | |
135 | ||
6fc6879b | 136 | while ((dent = readdir(dir))) { |
0d1286e4 JM |
137 | if (os_strncmp(dent->d_name, "AP-", 3) != 0 && |
138 | os_strncmp(dent->d_name, "STA-", 4) != 0) | |
6fc6879b | 139 | continue; |
0d1286e4 JM |
140 | if (drv->own_socket_path) { |
141 | size_t olen, dlen; | |
142 | olen = os_strlen(drv->own_socket_path); | |
143 | dlen = os_strlen(dent->d_name); | |
144 | if (olen >= dlen && | |
145 | os_strcmp(dent->d_name, | |
146 | drv->own_socket_path + olen - dlen) == 0) | |
147 | continue; | |
148 | } | |
6fc6879b JM |
149 | wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name); |
150 | ||
151 | os_memset(&addr, 0, sizeof(addr)); | |
152 | addr.sun_family = AF_UNIX; | |
153 | os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", | |
154 | path, dent->d_name); | |
155 | ||
ad08c363 | 156 | if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0, |
6fc6879b JM |
157 | (struct sockaddr *) &addr, sizeof(addr)) < 0) { |
158 | perror("sendto(test_socket)"); | |
159 | } | |
160 | } | |
161 | closedir(dir); | |
162 | } | |
329a55b3 | 163 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b JM |
164 | |
165 | ||
f55b218a JM |
166 | static int wpa_driver_test_scan(void *priv, |
167 | struct wpa_driver_scan_params *params) | |
6fc6879b JM |
168 | { |
169 | struct wpa_driver_test_data *drv = priv; | |
f55b218a JM |
170 | size_t i; |
171 | ||
6fc6879b | 172 | wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv); |
f55b218a JM |
173 | for (i = 0; i < params->num_ssids; i++) |
174 | wpa_hexdump(MSG_DEBUG, "Scan SSID", | |
175 | params->ssids[i].ssid, params->ssids[i].ssid_len); | |
176 | wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)", | |
177 | params->extra_ies, params->extra_ies_len); | |
6fc6879b JM |
178 | |
179 | drv->num_scanres = 0; | |
180 | ||
329a55b3 | 181 | #ifdef DRIVER_TEST_UNIX |
6fc6879b JM |
182 | if (drv->test_socket >= 0 && drv->test_dir) |
183 | wpa_driver_scan_dir(drv, drv->test_dir); | |
184 | ||
185 | if (drv->test_socket >= 0 && drv->hostapd_addr_set && | |
186 | sendto(drv->test_socket, "SCAN", 4, 0, | |
187 | (struct sockaddr *) &drv->hostapd_addr, | |
188 | sizeof(drv->hostapd_addr)) < 0) { | |
189 | perror("sendto(test_socket)"); | |
190 | } | |
329a55b3 | 191 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b | 192 | |
e33bbd8f JM |
193 | if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && |
194 | sendto(drv->test_socket, "SCAN", 4, 0, | |
195 | (struct sockaddr *) &drv->hostapd_addr_udp, | |
196 | sizeof(drv->hostapd_addr_udp)) < 0) { | |
197 | perror("sendto(test_socket)"); | |
198 | } | |
199 | ||
6fc6879b JM |
200 | eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); |
201 | eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv, | |
202 | drv->ctx); | |
203 | return 0; | |
204 | } | |
205 | ||
206 | ||
207 | static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv) | |
208 | { | |
209 | struct wpa_driver_test_data *drv = priv; | |
210 | struct wpa_scan_results *res; | |
211 | size_t i; | |
212 | ||
213 | res = os_zalloc(sizeof(*res)); | |
214 | if (res == NULL) | |
215 | return NULL; | |
216 | ||
217 | res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *)); | |
218 | if (res->res == NULL) { | |
219 | os_free(res); | |
220 | return NULL; | |
221 | } | |
222 | ||
223 | for (i = 0; i < drv->num_scanres; i++) { | |
224 | struct wpa_scan_res *r; | |
225 | if (drv->scanres[i] == NULL) | |
226 | continue; | |
227 | r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len); | |
228 | if (r == NULL) | |
229 | break; | |
230 | os_memcpy(r, drv->scanres[i], | |
231 | sizeof(*r) + drv->scanres[i]->ie_len); | |
232 | res->res[res->num++] = r; | |
233 | } | |
234 | ||
235 | return res; | |
236 | } | |
237 | ||
238 | ||
239 | static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr, | |
240 | int key_idx, int set_tx, | |
241 | const u8 *seq, size_t seq_len, | |
242 | const u8 *key, size_t key_len) | |
243 | { | |
244 | wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d", | |
245 | __func__, priv, alg, key_idx, set_tx); | |
246 | if (addr) { | |
247 | wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr)); | |
248 | } | |
249 | if (seq) { | |
250 | wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len); | |
251 | } | |
252 | if (key) { | |
253 | wpa_hexdump(MSG_DEBUG, " key", key, key_len); | |
254 | } | |
255 | return 0; | |
256 | } | |
257 | ||
258 | ||
259 | static int wpa_driver_test_associate( | |
260 | void *priv, struct wpa_driver_associate_params *params) | |
261 | { | |
262 | struct wpa_driver_test_data *drv = priv; | |
263 | wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " | |
264 | "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", | |
265 | __func__, priv, params->freq, params->pairwise_suite, | |
266 | params->group_suite, params->key_mgmt_suite, | |
267 | params->auth_alg, params->mode); | |
268 | if (params->bssid) { | |
269 | wpa_printf(MSG_DEBUG, " bssid=" MACSTR, | |
270 | MAC2STR(params->bssid)); | |
271 | } | |
272 | if (params->ssid) { | |
273 | wpa_hexdump_ascii(MSG_DEBUG, " ssid", | |
274 | params->ssid, params->ssid_len); | |
275 | } | |
276 | if (params->wpa_ie) { | |
277 | wpa_hexdump(MSG_DEBUG, " wpa_ie", | |
278 | params->wpa_ie, params->wpa_ie_len); | |
279 | drv->assoc_wpa_ie_len = params->wpa_ie_len; | |
280 | if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie)) | |
281 | drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie); | |
282 | os_memcpy(drv->assoc_wpa_ie, params->wpa_ie, | |
283 | drv->assoc_wpa_ie_len); | |
284 | } else | |
285 | drv->assoc_wpa_ie_len = 0; | |
286 | ||
0d1286e4 JM |
287 | drv->ibss = params->mode == IEEE80211_MODE_IBSS; |
288 | drv->privacy = params->key_mgmt_suite & | |
289 | (WPA_KEY_MGMT_IEEE8021X | | |
290 | WPA_KEY_MGMT_PSK | | |
291 | WPA_KEY_MGMT_WPA_NONE | | |
292 | WPA_KEY_MGMT_FT_IEEE8021X | | |
293 | WPA_KEY_MGMT_FT_PSK | | |
294 | WPA_KEY_MGMT_IEEE8021X_SHA256 | | |
295 | WPA_KEY_MGMT_PSK_SHA256); | |
296 | if (params->wep_key_len[params->wep_tx_keyidx]) | |
297 | drv->privacy = 1; | |
298 | ||
329a55b3 | 299 | #ifdef DRIVER_TEST_UNIX |
0d1286e4 JM |
300 | if (drv->test_dir && params->bssid && |
301 | params->mode != IEEE80211_MODE_IBSS) { | |
6fc6879b JM |
302 | os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); |
303 | drv->hostapd_addr.sun_family = AF_UNIX; | |
304 | os_snprintf(drv->hostapd_addr.sun_path, | |
305 | sizeof(drv->hostapd_addr.sun_path), | |
306 | "%s/AP-" MACSTR, | |
307 | drv->test_dir, MAC2STR(params->bssid)); | |
308 | drv->hostapd_addr_set = 1; | |
309 | } | |
329a55b3 | 310 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b | 311 | |
e33bbd8f JM |
312 | if (drv->test_socket >= 0 && |
313 | (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) { | |
6fc6879b JM |
314 | char cmd[200], *pos, *end; |
315 | int ret; | |
316 | end = cmd + sizeof(cmd); | |
317 | pos = cmd; | |
318 | ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ", | |
319 | MAC2STR(drv->own_addr)); | |
320 | if (ret >= 0 && ret < end - pos) | |
321 | pos += ret; | |
322 | pos += wpa_snprintf_hex(pos, end - pos, params->ssid, | |
323 | params->ssid_len); | |
324 | ret = os_snprintf(pos, end - pos, " "); | |
325 | if (ret >= 0 && ret < end - pos) | |
326 | pos += ret; | |
327 | pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie, | |
328 | params->wpa_ie_len); | |
329 | end[-1] = '\0'; | |
329a55b3 | 330 | #ifdef DRIVER_TEST_UNIX |
e33bbd8f JM |
331 | if (drv->hostapd_addr_set && |
332 | sendto(drv->test_socket, cmd, os_strlen(cmd), 0, | |
6fc6879b JM |
333 | (struct sockaddr *) &drv->hostapd_addr, |
334 | sizeof(drv->hostapd_addr)) < 0) { | |
335 | perror("sendto(test_socket)"); | |
336 | return -1; | |
337 | } | |
329a55b3 | 338 | #endif /* DRIVER_TEST_UNIX */ |
e33bbd8f JM |
339 | if (drv->hostapd_addr_udp_set && |
340 | sendto(drv->test_socket, cmd, os_strlen(cmd), 0, | |
341 | (struct sockaddr *) &drv->hostapd_addr_udp, | |
342 | sizeof(drv->hostapd_addr_udp)) < 0) { | |
343 | perror("sendto(test_socket)"); | |
344 | return -1; | |
345 | } | |
6fc6879b JM |
346 | |
347 | os_memcpy(drv->ssid, params->ssid, params->ssid_len); | |
348 | drv->ssid_len = params->ssid_len; | |
349 | } else { | |
350 | drv->associated = 1; | |
0d1286e4 JM |
351 | if (params->mode == IEEE80211_MODE_IBSS) { |
352 | os_memcpy(drv->ssid, params->ssid, params->ssid_len); | |
353 | drv->ssid_len = params->ssid_len; | |
354 | if (params->bssid) | |
355 | os_memcpy(drv->bssid, params->bssid, ETH_ALEN); | |
356 | else { | |
357 | os_get_random(drv->bssid, ETH_ALEN); | |
358 | drv->bssid[0] &= ~0x01; | |
359 | drv->bssid[0] |= 0x02; | |
360 | } | |
361 | } | |
6fc6879b JM |
362 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); |
363 | } | |
364 | ||
365 | return 0; | |
366 | } | |
367 | ||
368 | ||
369 | static int wpa_driver_test_get_bssid(void *priv, u8 *bssid) | |
370 | { | |
371 | struct wpa_driver_test_data *drv = priv; | |
372 | os_memcpy(bssid, drv->bssid, ETH_ALEN); | |
373 | return 0; | |
374 | } | |
375 | ||
376 | ||
377 | static int wpa_driver_test_get_ssid(void *priv, u8 *ssid) | |
378 | { | |
379 | struct wpa_driver_test_data *drv = priv; | |
380 | os_memcpy(ssid, drv->ssid, 32); | |
381 | return drv->ssid_len; | |
382 | } | |
383 | ||
384 | ||
385 | static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv) | |
386 | { | |
329a55b3 | 387 | #ifdef DRIVER_TEST_UNIX |
6fc6879b JM |
388 | if (drv->test_socket >= 0 && |
389 | sendto(drv->test_socket, "DISASSOC", 8, 0, | |
390 | (struct sockaddr *) &drv->hostapd_addr, | |
391 | sizeof(drv->hostapd_addr)) < 0) { | |
392 | perror("sendto(test_socket)"); | |
393 | return -1; | |
394 | } | |
329a55b3 JM |
395 | #endif /* DRIVER_TEST_UNIX */ |
396 | if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set && | |
397 | sendto(drv->test_socket, "DISASSOC", 8, 0, | |
398 | (struct sockaddr *) &drv->hostapd_addr_udp, | |
399 | sizeof(drv->hostapd_addr_udp)) < 0) { | |
400 | perror("sendto(test_socket)"); | |
401 | return -1; | |
402 | } | |
6fc6879b JM |
403 | return 0; |
404 | } | |
405 | ||
406 | ||
407 | static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr, | |
408 | int reason_code) | |
409 | { | |
410 | struct wpa_driver_test_data *drv = priv; | |
411 | wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", | |
412 | __func__, MAC2STR(addr), reason_code); | |
413 | os_memset(drv->bssid, 0, ETH_ALEN); | |
414 | drv->associated = 0; | |
415 | wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); | |
416 | return wpa_driver_test_send_disassoc(drv); | |
417 | } | |
418 | ||
419 | ||
420 | static int wpa_driver_test_disassociate(void *priv, const u8 *addr, | |
421 | int reason_code) | |
422 | { | |
423 | struct wpa_driver_test_data *drv = priv; | |
424 | wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d", | |
425 | __func__, MAC2STR(addr), reason_code); | |
426 | os_memset(drv->bssid, 0, ETH_ALEN); | |
427 | drv->associated = 0; | |
428 | wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); | |
429 | return wpa_driver_test_send_disassoc(drv); | |
430 | } | |
431 | ||
432 | ||
433 | static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv, | |
329a55b3 | 434 | struct sockaddr *from, |
6fc6879b JM |
435 | socklen_t fromlen, |
436 | const char *data) | |
437 | { | |
438 | struct wpa_scan_res *res; | |
439 | const char *pos, *pos2; | |
440 | size_t len; | |
441 | u8 *ie_pos, *ie_start, *ie_end; | |
442 | #define MAX_IE_LEN 1000 | |
443 | ||
444 | wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data); | |
445 | if (drv->num_scanres >= MAX_SCAN_RESULTS) { | |
446 | wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan " | |
447 | "result"); | |
448 | return; | |
449 | } | |
450 | ||
451 | /* SCANRESP BSSID SSID IEs */ | |
452 | ||
453 | res = os_zalloc(sizeof(*res) + MAX_IE_LEN); | |
454 | if (res == NULL) | |
455 | return; | |
456 | ie_start = ie_pos = (u8 *) (res + 1); | |
457 | ie_end = ie_pos + MAX_IE_LEN; | |
458 | ||
459 | if (hwaddr_aton(data, res->bssid)) { | |
460 | wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres"); | |
461 | os_free(res); | |
462 | return; | |
463 | } | |
464 | ||
465 | pos = data + 17; | |
466 | while (*pos == ' ') | |
467 | pos++; | |
468 | pos2 = os_strchr(pos, ' '); | |
469 | if (pos2 == NULL) { | |
470 | wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination " | |
471 | "in scanres"); | |
472 | os_free(res); | |
473 | return; | |
474 | } | |
475 | len = (pos2 - pos) / 2; | |
476 | if (len > 32) | |
477 | len = 32; | |
478 | /* | |
479 | * Generate SSID IE from the SSID field since this IE is not included | |
480 | * in the main IE field. | |
481 | */ | |
482 | *ie_pos++ = WLAN_EID_SSID; | |
483 | *ie_pos++ = len; | |
484 | if (hexstr2bin(pos, ie_pos, len) < 0) { | |
485 | wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres"); | |
486 | os_free(res); | |
487 | return; | |
488 | } | |
489 | ie_pos += len; | |
490 | ||
491 | pos = pos2 + 1; | |
492 | pos2 = os_strchr(pos, ' '); | |
493 | if (pos2 == NULL) | |
494 | len = os_strlen(pos) / 2; | |
495 | else | |
496 | len = (pos2 - pos) / 2; | |
497 | if ((int) len > ie_end - ie_pos) | |
498 | len = ie_end - ie_pos; | |
499 | if (hexstr2bin(pos, ie_pos, len) < 0) { | |
500 | wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres"); | |
501 | os_free(res); | |
502 | return; | |
503 | } | |
504 | ie_pos += len; | |
505 | res->ie_len = ie_pos - ie_start; | |
506 | ||
507 | if (pos2) { | |
508 | pos = pos2 + 1; | |
509 | while (*pos == ' ') | |
510 | pos++; | |
0d1286e4 | 511 | if (os_strstr(pos, "PRIVACY")) |
6fc6879b | 512 | res->caps |= IEEE80211_CAP_PRIVACY; |
0d1286e4 JM |
513 | if (os_strstr(pos, "IBSS")) |
514 | res->caps |= IEEE80211_CAP_IBSS; | |
6fc6879b JM |
515 | } |
516 | ||
517 | os_free(drv->scanres[drv->num_scanres]); | |
518 | drv->scanres[drv->num_scanres++] = res; | |
519 | } | |
520 | ||
521 | ||
522 | static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv, | |
329a55b3 | 523 | struct sockaddr *from, |
6fc6879b JM |
524 | socklen_t fromlen, |
525 | const char *data) | |
526 | { | |
527 | /* ASSOCRESP BSSID <res> */ | |
528 | if (hwaddr_aton(data, drv->bssid)) { | |
529 | wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in " | |
530 | "assocresp"); | |
531 | } | |
532 | if (drv->use_associnfo) { | |
533 | union wpa_event_data event; | |
534 | os_memset(&event, 0, sizeof(event)); | |
535 | event.assoc_info.req_ies = drv->assoc_wpa_ie; | |
536 | event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len; | |
537 | wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event); | |
538 | } | |
539 | drv->associated = 1; | |
540 | wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL); | |
541 | } | |
542 | ||
543 | ||
544 | static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv, | |
329a55b3 | 545 | struct sockaddr *from, |
6fc6879b JM |
546 | socklen_t fromlen) |
547 | { | |
548 | drv->associated = 0; | |
549 | wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL); | |
550 | } | |
551 | ||
552 | ||
553 | static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv, | |
329a55b3 | 554 | struct sockaddr *from, |
6fc6879b JM |
555 | socklen_t fromlen, |
556 | const u8 *data, size_t data_len) | |
557 | { | |
558 | const u8 *src = drv->bssid; | |
559 | ||
560 | if (data_len > 14) { | |
561 | /* Skip Ethernet header */ | |
562 | src = data + ETH_ALEN; | |
563 | data += 14; | |
564 | data_len -= 14; | |
565 | } | |
566 | wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len); | |
567 | } | |
568 | ||
569 | ||
570 | static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv, | |
329a55b3 | 571 | struct sockaddr *from, |
6fc6879b JM |
572 | socklen_t fromlen, |
573 | const u8 *data, size_t data_len) | |
574 | { | |
147bdb3f | 575 | #ifdef CONFIG_CLIENT_MLME |
6fc6879b JM |
576 | struct ieee80211_rx_status rx_status; |
577 | os_memset(&rx_status, 0, sizeof(rx_status)); | |
578 | wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status); | |
147bdb3f | 579 | #endif /* CONFIG_CLIENT_MLME */ |
6fc6879b JM |
580 | } |
581 | ||
582 | ||
0d1286e4 JM |
583 | static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv, |
584 | struct sockaddr *from, | |
585 | socklen_t fromlen, | |
586 | const u8 *data, size_t data_len) | |
587 | { | |
588 | char buf[512], *pos, *end; | |
589 | int ret; | |
590 | ||
591 | /* data: optional [ STA-addr | ' ' | IEs(hex) ] */ | |
592 | ||
593 | if (!drv->ibss) | |
594 | return; | |
595 | ||
596 | pos = buf; | |
597 | end = buf + sizeof(buf); | |
598 | ||
599 | /* reply: SCANRESP BSSID SSID IEs */ | |
600 | ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ", | |
601 | MAC2STR(drv->bssid)); | |
602 | if (ret < 0 || ret >= end - pos) | |
603 | return; | |
604 | pos += ret; | |
605 | pos += wpa_snprintf_hex(pos, end - pos, | |
606 | drv->ssid, drv->ssid_len); | |
607 | ret = snprintf(pos, end - pos, " "); | |
608 | if (ret < 0 || ret >= end - pos) | |
609 | return; | |
610 | pos += ret; | |
611 | pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie, | |
612 | drv->assoc_wpa_ie_len); | |
613 | ||
614 | if (drv->privacy) { | |
615 | ret = snprintf(pos, end - pos, " PRIVACY"); | |
616 | if (ret < 0 || ret >= end - pos) | |
617 | return; | |
618 | pos += ret; | |
619 | } | |
620 | ||
621 | ret = snprintf(pos, end - pos, " IBSS"); | |
622 | if (ret < 0 || ret >= end - pos) | |
623 | return; | |
624 | pos += ret; | |
625 | ||
626 | sendto(drv->test_socket, buf, pos - buf, 0, | |
627 | (struct sockaddr *) from, fromlen); | |
628 | } | |
629 | ||
630 | ||
6fc6879b JM |
631 | static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx, |
632 | void *sock_ctx) | |
633 | { | |
634 | struct wpa_driver_test_data *drv = eloop_ctx; | |
635 | char *buf; | |
636 | int res; | |
329a55b3 | 637 | struct sockaddr_storage from; |
6fc6879b JM |
638 | socklen_t fromlen = sizeof(from); |
639 | const size_t buflen = 2000; | |
640 | ||
641 | buf = os_malloc(buflen); | |
642 | if (buf == NULL) | |
643 | return; | |
644 | res = recvfrom(sock, buf, buflen - 1, 0, | |
645 | (struct sockaddr *) &from, &fromlen); | |
646 | if (res < 0) { | |
647 | perror("recvfrom(test_socket)"); | |
648 | os_free(buf); | |
649 | return; | |
650 | } | |
651 | buf[res] = '\0'; | |
652 | ||
653 | wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res); | |
654 | ||
655 | if (os_strncmp(buf, "SCANRESP ", 9) == 0) { | |
329a55b3 JM |
656 | wpa_driver_test_scanresp(drv, (struct sockaddr *) &from, |
657 | fromlen, buf + 9); | |
6fc6879b | 658 | } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) { |
329a55b3 JM |
659 | wpa_driver_test_assocresp(drv, (struct sockaddr *) &from, |
660 | fromlen, buf + 10); | |
6fc6879b | 661 | } else if (os_strcmp(buf, "DISASSOC") == 0) { |
329a55b3 JM |
662 | wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, |
663 | fromlen); | |
6fc6879b | 664 | } else if (os_strcmp(buf, "DEAUTH") == 0) { |
329a55b3 JM |
665 | wpa_driver_test_disassoc(drv, (struct sockaddr *) &from, |
666 | fromlen); | |
6fc6879b | 667 | } else if (os_strncmp(buf, "EAPOL ", 6) == 0) { |
329a55b3 | 668 | wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen, |
6fc6879b JM |
669 | (const u8 *) buf + 6, res - 6); |
670 | } else if (os_strncmp(buf, "MLME ", 5) == 0) { | |
329a55b3 | 671 | wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen, |
6fc6879b | 672 | (const u8 *) buf + 5, res - 5); |
0d1286e4 JM |
673 | } else if (os_strncmp(buf, "SCAN ", 5) == 0) { |
674 | wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from, | |
675 | fromlen, | |
676 | (const u8 *) buf + 5, res - 5); | |
6fc6879b JM |
677 | } else { |
678 | wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command", | |
679 | (u8 *) buf, res); | |
680 | } | |
681 | os_free(buf); | |
682 | } | |
683 | ||
684 | ||
ac305589 JM |
685 | static void * wpa_driver_test_init2(void *ctx, const char *ifname, |
686 | void *global_priv) | |
6fc6879b JM |
687 | { |
688 | struct wpa_driver_test_data *drv; | |
689 | ||
690 | drv = os_zalloc(sizeof(*drv)); | |
691 | if (drv == NULL) | |
692 | return NULL; | |
ac305589 | 693 | drv->global = global_priv; |
6fc6879b JM |
694 | drv->ctx = ctx; |
695 | drv->test_socket = -1; | |
696 | ||
697 | /* Set dummy BSSID and SSID for testing. */ | |
698 | drv->bssid[0] = 0x02; | |
699 | drv->bssid[1] = 0x00; | |
700 | drv->bssid[2] = 0x00; | |
701 | drv->bssid[3] = 0x00; | |
702 | drv->bssid[4] = 0x00; | |
703 | drv->bssid[5] = 0x01; | |
704 | os_memcpy(drv->ssid, "test", 5); | |
705 | drv->ssid_len = 4; | |
706 | ||
707 | /* Generate a MAC address to help testing with multiple STAs */ | |
708 | drv->own_addr[0] = 0x02; /* locally administered */ | |
709 | sha1_prf((const u8 *) ifname, os_strlen(ifname), | |
710 | "wpa_supplicant test mac addr generation", | |
711 | NULL, 0, drv->own_addr + 1, ETH_ALEN - 1); | |
712 | eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL); | |
713 | ||
714 | return drv; | |
715 | } | |
716 | ||
717 | ||
718 | static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv) | |
719 | { | |
720 | if (drv->test_socket >= 0) { | |
721 | eloop_unregister_read_sock(drv->test_socket); | |
722 | close(drv->test_socket); | |
723 | drv->test_socket = -1; | |
724 | } | |
725 | ||
726 | if (drv->own_socket_path) { | |
727 | unlink(drv->own_socket_path); | |
728 | os_free(drv->own_socket_path); | |
729 | drv->own_socket_path = NULL; | |
730 | } | |
731 | } | |
732 | ||
733 | ||
734 | static void wpa_driver_test_deinit(void *priv) | |
735 | { | |
736 | struct wpa_driver_test_data *drv = priv; | |
737 | int i; | |
738 | wpa_driver_test_close_test_socket(drv); | |
739 | eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx); | |
740 | eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL); | |
741 | os_free(drv->test_dir); | |
742 | for (i = 0; i < MAX_SCAN_RESULTS; i++) | |
743 | os_free(drv->scanres[i]); | |
ad08c363 | 744 | os_free(drv->probe_req_ie); |
6fc6879b JM |
745 | os_free(drv); |
746 | } | |
747 | ||
748 | ||
749 | static int wpa_driver_test_attach(struct wpa_driver_test_data *drv, | |
750 | const char *dir) | |
751 | { | |
329a55b3 | 752 | #ifdef DRIVER_TEST_UNIX |
6fc6879b JM |
753 | static unsigned int counter = 0; |
754 | struct sockaddr_un addr; | |
755 | size_t len; | |
756 | ||
757 | os_free(drv->own_socket_path); | |
758 | if (dir) { | |
759 | len = os_strlen(dir) + 30; | |
760 | drv->own_socket_path = os_malloc(len); | |
761 | if (drv->own_socket_path == NULL) | |
762 | return -1; | |
763 | os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR, | |
764 | dir, MAC2STR(drv->own_addr)); | |
765 | } else { | |
766 | drv->own_socket_path = os_malloc(100); | |
767 | if (drv->own_socket_path == NULL) | |
768 | return -1; | |
769 | os_snprintf(drv->own_socket_path, 100, | |
770 | "/tmp/wpa_supplicant_test-%d-%d", | |
771 | getpid(), counter++); | |
772 | } | |
773 | ||
774 | drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0); | |
775 | if (drv->test_socket < 0) { | |
776 | perror("socket(PF_UNIX)"); | |
777 | os_free(drv->own_socket_path); | |
778 | drv->own_socket_path = NULL; | |
779 | return -1; | |
780 | } | |
781 | ||
782 | os_memset(&addr, 0, sizeof(addr)); | |
783 | addr.sun_family = AF_UNIX; | |
784 | os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path)); | |
785 | if (bind(drv->test_socket, (struct sockaddr *) &addr, | |
786 | sizeof(addr)) < 0) { | |
787 | perror("bind(PF_UNIX)"); | |
788 | close(drv->test_socket); | |
789 | unlink(drv->own_socket_path); | |
790 | os_free(drv->own_socket_path); | |
791 | drv->own_socket_path = NULL; | |
792 | return -1; | |
793 | } | |
794 | ||
795 | eloop_register_read_sock(drv->test_socket, | |
796 | wpa_driver_test_receive_unix, drv, NULL); | |
797 | ||
798 | return 0; | |
329a55b3 JM |
799 | #else /* DRIVER_TEST_UNIX */ |
800 | return -1; | |
801 | #endif /* DRIVER_TEST_UNIX */ | |
6fc6879b JM |
802 | } |
803 | ||
804 | ||
e33bbd8f JM |
805 | static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv, |
806 | char *dst) | |
807 | { | |
808 | char *pos; | |
809 | ||
810 | pos = os_strchr(dst, ':'); | |
811 | if (pos == NULL) | |
812 | return -1; | |
813 | *pos++ = '\0'; | |
814 | wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos); | |
815 | ||
816 | drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0); | |
817 | if (drv->test_socket < 0) { | |
818 | perror("socket(PF_INET)"); | |
819 | return -1; | |
820 | } | |
821 | ||
822 | os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp)); | |
823 | drv->hostapd_addr_udp.sin_family = AF_INET; | |
824 | #if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA) | |
825 | { | |
826 | int a[4]; | |
827 | u8 *pos; | |
828 | sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]); | |
829 | pos = (u8 *) &drv->hostapd_addr_udp.sin_addr; | |
830 | *pos++ = a[0]; | |
831 | *pos++ = a[1]; | |
832 | *pos++ = a[2]; | |
833 | *pos++ = a[3]; | |
834 | } | |
835 | #else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ | |
836 | inet_aton(dst, &drv->hostapd_addr_udp.sin_addr); | |
837 | #endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */ | |
838 | drv->hostapd_addr_udp.sin_port = htons(atoi(pos)); | |
839 | ||
840 | drv->hostapd_addr_udp_set = 1; | |
841 | ||
842 | eloop_register_read_sock(drv->test_socket, | |
843 | wpa_driver_test_receive_unix, drv, NULL); | |
844 | ||
845 | return 0; | |
846 | } | |
847 | ||
848 | ||
6fc6879b JM |
849 | static int wpa_driver_test_set_param(void *priv, const char *param) |
850 | { | |
851 | struct wpa_driver_test_data *drv = priv; | |
329a55b3 | 852 | const char *pos; |
6fc6879b JM |
853 | |
854 | wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param); | |
855 | if (param == NULL) | |
856 | return 0; | |
857 | ||
858 | wpa_driver_test_close_test_socket(drv); | |
329a55b3 JM |
859 | |
860 | #ifdef DRIVER_TEST_UNIX | |
6fc6879b JM |
861 | pos = os_strstr(param, "test_socket="); |
862 | if (pos) { | |
329a55b3 JM |
863 | const char *pos2; |
864 | size_t len; | |
865 | ||
6fc6879b JM |
866 | pos += 12; |
867 | pos2 = os_strchr(pos, ' '); | |
868 | if (pos2) | |
869 | len = pos2 - pos; | |
870 | else | |
871 | len = os_strlen(pos); | |
872 | if (len > sizeof(drv->hostapd_addr.sun_path)) | |
873 | return -1; | |
874 | os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr)); | |
875 | drv->hostapd_addr.sun_family = AF_UNIX; | |
876 | os_memcpy(drv->hostapd_addr.sun_path, pos, len); | |
877 | drv->hostapd_addr_set = 1; | |
878 | } | |
329a55b3 | 879 | #endif /* DRIVER_TEST_UNIX */ |
6fc6879b JM |
880 | |
881 | pos = os_strstr(param, "test_dir="); | |
882 | if (pos) { | |
883 | char *end; | |
884 | os_free(drv->test_dir); | |
885 | drv->test_dir = os_strdup(pos + 9); | |
886 | if (drv->test_dir == NULL) | |
887 | return -1; | |
888 | end = os_strchr(drv->test_dir, ' '); | |
889 | if (end) | |
890 | *end = '\0'; | |
e33bbd8f JM |
891 | if (wpa_driver_test_attach(drv, drv->test_dir)) |
892 | return -1; | |
893 | } else { | |
894 | pos = os_strstr(param, "test_udp="); | |
895 | if (pos) { | |
896 | char *dst, *epos; | |
897 | dst = os_strdup(pos + 9); | |
898 | if (dst == NULL) | |
899 | return -1; | |
900 | epos = os_strchr(dst, ' '); | |
901 | if (epos) | |
902 | *epos = '\0'; | |
903 | if (wpa_driver_test_attach_udp(drv, dst)) | |
904 | return -1; | |
905 | os_free(dst); | |
906 | } else if (wpa_driver_test_attach(drv, NULL)) | |
907 | return -1; | |
908 | } | |
6fc6879b JM |
909 | |
910 | if (os_strstr(param, "use_associnfo=1")) { | |
911 | wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events"); | |
912 | drv->use_associnfo = 1; | |
913 | } | |
914 | ||
915 | #ifdef CONFIG_CLIENT_MLME | |
916 | if (os_strstr(param, "use_mlme=1")) { | |
917 | wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME"); | |
918 | drv->use_mlme = 1; | |
919 | } | |
920 | #endif /* CONFIG_CLIENT_MLME */ | |
921 | ||
922 | return 0; | |
923 | } | |
924 | ||
925 | ||
926 | static const u8 * wpa_driver_test_get_mac_addr(void *priv) | |
927 | { | |
928 | struct wpa_driver_test_data *drv = priv; | |
929 | wpa_printf(MSG_DEBUG, "%s", __func__); | |
930 | return drv->own_addr; | |
931 | } | |
932 | ||
933 | ||
934 | static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto, | |
935 | const u8 *data, size_t data_len) | |
936 | { | |
937 | struct wpa_driver_test_data *drv = priv; | |
329a55b3 JM |
938 | char *msg; |
939 | size_t msg_len; | |
6fc6879b | 940 | struct l2_ethhdr eth; |
329a55b3 JM |
941 | struct sockaddr *addr; |
942 | socklen_t alen; | |
dd42f95f JM |
943 | #ifdef DRIVER_TEST_UNIX |
944 | struct sockaddr_un addr_un; | |
945 | #endif /* DRIVER_TEST_UNIX */ | |
6fc6879b JM |
946 | |
947 | wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len); | |
948 | ||
949 | os_memset(ð, 0, sizeof(eth)); | |
950 | os_memcpy(eth.h_dest, dest, ETH_ALEN); | |
951 | os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN); | |
952 | eth.h_proto = host_to_be16(proto); | |
953 | ||
329a55b3 JM |
954 | msg_len = 6 + sizeof(eth) + data_len; |
955 | msg = os_malloc(msg_len); | |
956 | if (msg == NULL) | |
957 | return -1; | |
958 | os_memcpy(msg, "EAPOL ", 6); | |
959 | os_memcpy(msg + 6, ð, sizeof(eth)); | |
960 | os_memcpy(msg + 6 + sizeof(eth), data, data_len); | |
6fc6879b | 961 | |
6fc6879b JM |
962 | if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || |
963 | drv->test_dir == NULL) { | |
e33bbd8f | 964 | if (drv->hostapd_addr_udp_set) { |
329a55b3 JM |
965 | addr = (struct sockaddr *) &drv->hostapd_addr_udp; |
966 | alen = sizeof(drv->hostapd_addr_udp); | |
e33bbd8f | 967 | } else { |
329a55b3 JM |
968 | #ifdef DRIVER_TEST_UNIX |
969 | addr = (struct sockaddr *) &drv->hostapd_addr; | |
970 | alen = sizeof(drv->hostapd_addr); | |
971 | #else /* DRIVER_TEST_UNIX */ | |
972 | os_free(msg); | |
973 | return -1; | |
974 | #endif /* DRIVER_TEST_UNIX */ | |
e33bbd8f | 975 | } |
6fc6879b | 976 | } else { |
329a55b3 | 977 | #ifdef DRIVER_TEST_UNIX |
6fc6879b | 978 | struct stat st; |
329a55b3 JM |
979 | os_memset(&addr_un, 0, sizeof(addr_un)); |
980 | addr_un.sun_family = AF_UNIX; | |
981 | os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), | |
6fc6879b | 982 | "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest)); |
329a55b3 JM |
983 | if (stat(addr_un.sun_path, &st) < 0) { |
984 | os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path), | |
6fc6879b JM |
985 | "%s/AP-" MACSTR, |
986 | drv->test_dir, MAC2STR(dest)); | |
987 | } | |
329a55b3 JM |
988 | addr = (struct sockaddr *) &addr_un; |
989 | alen = sizeof(addr_un); | |
990 | #else /* DRIVER_TEST_UNIX */ | |
991 | os_free(msg); | |
992 | return -1; | |
993 | #endif /* DRIVER_TEST_UNIX */ | |
6fc6879b JM |
994 | } |
995 | ||
329a55b3 | 996 | if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) { |
6fc6879b | 997 | perror("sendmsg(test_socket)"); |
329a55b3 | 998 | os_free(msg); |
6fc6879b JM |
999 | return -1; |
1000 | } | |
1001 | ||
329a55b3 | 1002 | os_free(msg); |
6fc6879b JM |
1003 | return 0; |
1004 | } | |
1005 | ||
1006 | ||
1007 | static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa) | |
1008 | { | |
1009 | struct wpa_driver_test_data *drv = priv; | |
1010 | os_memset(capa, 0, sizeof(*capa)); | |
1011 | capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA | | |
1012 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2 | | |
1013 | WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK | | |
1014 | WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK | | |
1015 | WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE | | |
1016 | WPA_DRIVER_CAPA_KEY_MGMT_FT | | |
1017 | WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK; | |
1018 | capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | | |
1019 | WPA_DRIVER_CAPA_ENC_WEP104 | | |
1020 | WPA_DRIVER_CAPA_ENC_TKIP | | |
1021 | WPA_DRIVER_CAPA_ENC_CCMP; | |
1022 | capa->auth = WPA_DRIVER_AUTH_OPEN | | |
1023 | WPA_DRIVER_AUTH_SHARED | | |
1024 | WPA_DRIVER_AUTH_LEAP; | |
1025 | if (drv->use_mlme) | |
1026 | capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME; | |
f55b218a | 1027 | capa->max_scan_ssids = 2; |
6fc6879b JM |
1028 | |
1029 | return 0; | |
1030 | } | |
1031 | ||
1032 | ||
1033 | static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr, | |
1034 | int protect_type, | |
1035 | int key_type) | |
1036 | { | |
1037 | wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d", | |
1038 | __func__, protect_type, key_type); | |
1039 | ||
1040 | if (addr) { | |
1041 | wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, | |
1042 | __func__, MAC2STR(addr)); | |
1043 | } | |
1044 | ||
1045 | return 0; | |
1046 | } | |
1047 | ||
1048 | ||
1049 | #ifdef CONFIG_CLIENT_MLME | |
1050 | static struct wpa_hw_modes * | |
1051 | wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags) | |
1052 | { | |
1053 | struct wpa_hw_modes *modes; | |
1054 | ||
1055 | *num_modes = 1; | |
1056 | *flags = 0; | |
1057 | modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes)); | |
1058 | if (modes == NULL) | |
1059 | return NULL; | |
1060 | modes[0].mode = WPA_MODE_IEEE80211G; | |
1061 | modes[0].num_channels = 1; | |
1062 | modes[0].num_rates = 1; | |
1063 | modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data)); | |
1064 | modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data)); | |
1065 | if (modes[0].channels == NULL || modes[0].rates == NULL) { | |
1066 | wpa_supplicant_sta_free_hw_features(modes, *num_modes); | |
1067 | return NULL; | |
1068 | } | |
1069 | modes[0].channels[0].chan = 1; | |
1070 | modes[0].channels[0].freq = 2412; | |
1071 | modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN; | |
1072 | modes[0].rates[0].rate = 10; | |
1073 | modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED | | |
1074 | WPA_RATE_CCK | WPA_RATE_MANDATORY; | |
1075 | ||
1076 | return modes; | |
1077 | } | |
1078 | ||
1079 | ||
3cf85239 JM |
1080 | static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode, |
1081 | int chan, int freq) | |
6fc6879b JM |
1082 | { |
1083 | wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d", | |
1084 | __func__, phymode, chan, freq); | |
1085 | return 0; | |
1086 | } | |
1087 | ||
1088 | ||
1089 | static int wpa_driver_test_send_mlme(void *priv, const u8 *data, | |
1090 | size_t data_len) | |
1091 | { | |
1092 | struct wpa_driver_test_data *drv = priv; | |
1093 | struct msghdr msg; | |
1094 | struct iovec io[2]; | |
1095 | struct sockaddr_un addr; | |
1096 | const u8 *dest; | |
1097 | struct dirent *dent; | |
1098 | DIR *dir; | |
1099 | ||
1100 | wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len); | |
1101 | if (data_len < 10) | |
1102 | return -1; | |
1103 | dest = data + 4; | |
1104 | ||
1105 | io[0].iov_base = "MLME "; | |
1106 | io[0].iov_len = 5; | |
1107 | io[1].iov_base = (u8 *) data; | |
1108 | io[1].iov_len = data_len; | |
1109 | ||
1110 | os_memset(&msg, 0, sizeof(msg)); | |
1111 | msg.msg_iov = io; | |
1112 | msg.msg_iovlen = 2; | |
1113 | if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 || | |
1114 | drv->test_dir == NULL) { | |
329a55b3 JM |
1115 | if (drv->hostapd_addr_udp_set) { |
1116 | msg.msg_name = &drv->hostapd_addr_udp; | |
1117 | msg.msg_namelen = sizeof(drv->hostapd_addr_udp); | |
1118 | } else { | |
1119 | #ifdef DRIVER_TEST_UNIX | |
1120 | msg.msg_name = &drv->hostapd_addr; | |
1121 | msg.msg_namelen = sizeof(drv->hostapd_addr); | |
1122 | #endif /* DRIVER_TEST_UNIX */ | |
1123 | } | |
6fc6879b JM |
1124 | } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0) |
1125 | { | |
1126 | dir = opendir(drv->test_dir); | |
1127 | if (dir == NULL) | |
1128 | return -1; | |
1129 | while ((dent = readdir(dir))) { | |
1130 | #ifdef _DIRENT_HAVE_D_TYPE | |
1131 | /* Skip the file if it is not a socket. | |
1132 | * Also accept DT_UNKNOWN (0) in case | |
1133 | * the C library or underlying file | |
1134 | * system does not support d_type. */ | |
1135 | if (dent->d_type != DT_SOCK && | |
1136 | dent->d_type != DT_UNKNOWN) | |
1137 | continue; | |
1138 | #endif /* _DIRENT_HAVE_D_TYPE */ | |
1139 | if (os_strcmp(dent->d_name, ".") == 0 || | |
1140 | os_strcmp(dent->d_name, "..") == 0) | |
1141 | continue; | |
1142 | wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s", | |
1143 | __func__, dent->d_name); | |
1144 | os_memset(&addr, 0, sizeof(addr)); | |
1145 | addr.sun_family = AF_UNIX; | |
1146 | os_snprintf(addr.sun_path, sizeof(addr.sun_path), | |
1147 | "%s/%s", drv->test_dir, dent->d_name); | |
1148 | ||
1149 | msg.msg_name = &addr; | |
1150 | msg.msg_namelen = sizeof(addr); | |
1151 | ||
1152 | if (sendmsg(drv->test_socket, &msg, 0) < 0) | |
1153 | perror("sendmsg(test_socket)"); | |
1154 | } | |
1155 | closedir(dir); | |
1156 | return 0; | |
1157 | } else { | |
1158 | struct stat st; | |
1159 | os_memset(&addr, 0, sizeof(addr)); | |
1160 | addr.sun_family = AF_UNIX; | |
1161 | os_snprintf(addr.sun_path, sizeof(addr.sun_path), | |
1162 | "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest)); | |
1163 | if (stat(addr.sun_path, &st) < 0) { | |
1164 | os_snprintf(addr.sun_path, sizeof(addr.sun_path), | |
1165 | "%s/STA-" MACSTR, | |
1166 | drv->test_dir, MAC2STR(dest)); | |
1167 | } | |
1168 | msg.msg_name = &addr; | |
1169 | msg.msg_namelen = sizeof(addr); | |
1170 | } | |
1171 | ||
1172 | if (sendmsg(drv->test_socket, &msg, 0) < 0) { | |
1173 | perror("sendmsg(test_socket)"); | |
1174 | return -1; | |
1175 | } | |
1176 | ||
1177 | return 0; | |
1178 | } | |
1179 | ||
1180 | ||
1181 | static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr, | |
1182 | const u8 *supp_rates, | |
1183 | size_t supp_rates_len) | |
1184 | { | |
1185 | wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); | |
1186 | return 0; | |
1187 | } | |
1188 | ||
1189 | ||
1190 | static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr) | |
1191 | { | |
1192 | wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr)); | |
1193 | return 0; | |
1194 | } | |
1195 | ||
1196 | ||
3cf85239 JM |
1197 | static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, |
1198 | size_t ssid_len) | |
6fc6879b JM |
1199 | { |
1200 | wpa_printf(MSG_DEBUG, "%s", __func__); | |
1201 | return 0; | |
1202 | } | |
1203 | ||
1204 | ||
3cf85239 | 1205 | static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid) |
6fc6879b JM |
1206 | { |
1207 | wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid)); | |
1208 | return 0; | |
1209 | } | |
1210 | #endif /* CONFIG_CLIENT_MLME */ | |
1211 | ||
1212 | ||
3cf85239 JM |
1213 | static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies, |
1214 | size_t ies_len) | |
ad08c363 JM |
1215 | { |
1216 | struct wpa_driver_test_data *drv = priv; | |
1217 | ||
1218 | os_free(drv->probe_req_ie); | |
1219 | if (ies) { | |
1220 | drv->probe_req_ie = os_malloc(ies_len); | |
1221 | if (drv->probe_req_ie == NULL) { | |
1222 | drv->probe_req_ie_len = 0; | |
1223 | return -1; | |
1224 | } | |
1225 | os_memcpy(drv->probe_req_ie, ies, ies_len); | |
1226 | drv->probe_req_ie_len = ies_len; | |
1227 | } else { | |
1228 | drv->probe_req_ie = NULL; | |
1229 | drv->probe_req_ie_len = 0; | |
1230 | } | |
1231 | return 0; | |
1232 | } | |
1233 | ||
1234 | ||
ac305589 JM |
1235 | static void * wpa_driver_test_global_init(void) |
1236 | { | |
1237 | struct wpa_driver_test_global *global; | |
1238 | ||
1239 | global = os_zalloc(sizeof(*global)); | |
1240 | return global; | |
1241 | } | |
1242 | ||
1243 | ||
1244 | static void wpa_driver_test_global_deinit(void *priv) | |
1245 | { | |
1246 | struct wpa_driver_test_global *global = priv; | |
1247 | os_free(global); | |
1248 | } | |
1249 | ||
1250 | ||
4b4a8ae5 JM |
1251 | static struct wpa_interface_info * |
1252 | wpa_driver_test_get_interfaces(void *global_priv) | |
1253 | { | |
1254 | /* struct wpa_driver_test_global *global = priv; */ | |
1255 | struct wpa_interface_info *iface; | |
1256 | ||
1257 | iface = os_zalloc(sizeof(*iface)); | |
1258 | if (iface == NULL) | |
1259 | return iface; | |
1260 | iface->ifname = os_strdup("sta0"); | |
1261 | iface->desc = os_strdup("test interface 0"); | |
1262 | iface->drv_name = "test"; | |
1263 | iface->next = os_zalloc(sizeof(*iface)); | |
1264 | if (iface->next) { | |
1265 | iface->next->ifname = os_strdup("sta1"); | |
1266 | iface->next->desc = os_strdup("test interface 1"); | |
1267 | iface->next->drv_name = "test"; | |
1268 | } | |
1269 | ||
1270 | return iface; | |
1271 | } | |
1272 | ||
1273 | ||
6fc6879b JM |
1274 | const struct wpa_driver_ops wpa_driver_test_ops = { |
1275 | "test", | |
1276 | "wpa_supplicant test driver", | |
1277 | wpa_driver_test_get_bssid, | |
1278 | wpa_driver_test_get_ssid, | |
1279 | wpa_driver_test_set_wpa, | |
1280 | wpa_driver_test_set_key, | |
ac305589 | 1281 | NULL /* init */, |
6fc6879b JM |
1282 | wpa_driver_test_deinit, |
1283 | wpa_driver_test_set_param, | |
1284 | NULL /* set_countermeasures */, | |
1285 | NULL /* set_drop_unencrypted */, | |
f55b218a | 1286 | NULL /* scan */, |
6fc6879b JM |
1287 | NULL /* get_scan_results */, |
1288 | wpa_driver_test_deauthenticate, | |
1289 | wpa_driver_test_disassociate, | |
1290 | wpa_driver_test_associate, | |
1291 | NULL /* set_auth_alg */, | |
1292 | NULL /* add_pmkid */, | |
1293 | NULL /* remove_pmkid */, | |
1294 | NULL /* flush_pmkid */, | |
1295 | wpa_driver_test_get_capa, | |
1296 | NULL /* poll */, | |
1297 | NULL /* get_ifname */, | |
1298 | wpa_driver_test_get_mac_addr, | |
1299 | wpa_driver_test_send_eapol, | |
1300 | NULL /* set_operstate */, | |
1301 | wpa_driver_test_mlme_setprotection, | |
1302 | #ifdef CONFIG_CLIENT_MLME | |
1303 | wpa_driver_test_get_hw_feature_data, | |
1304 | wpa_driver_test_set_channel, | |
1305 | wpa_driver_test_set_ssid, | |
1306 | wpa_driver_test_set_bssid, | |
1307 | wpa_driver_test_send_mlme, | |
1308 | wpa_driver_test_mlme_add_sta, | |
1309 | wpa_driver_test_mlme_remove_sta, | |
1310 | #else /* CONFIG_CLIENT_MLME */ | |
1311 | NULL /* get_hw_feature_data */, | |
1312 | NULL /* set_channel */, | |
1313 | NULL /* set_ssid */, | |
1314 | NULL /* set_bssid */, | |
1315 | NULL /* send_mlme */, | |
1316 | NULL /* mlme_add_sta */, | |
1317 | NULL /* mlme_remove_sta */, | |
1318 | #endif /* CONFIG_CLIENT_MLME */ | |
1319 | NULL /* update_ft_ies */, | |
1320 | NULL /* send_ft_action */, | |
1321 | wpa_driver_test_get_scan_results2, | |
3cf85239 | 1322 | wpa_driver_test_set_probe_req_ie, |
6d158490 | 1323 | NULL /* set_mode */, |
ac305589 JM |
1324 | NULL /* set_country */, |
1325 | wpa_driver_test_global_init, | |
1326 | wpa_driver_test_global_deinit, | |
4b4a8ae5 | 1327 | wpa_driver_test_init2, |
fc2b7ed5 | 1328 | wpa_driver_test_get_interfaces, |
c2a04078 | 1329 | wpa_driver_test_scan, |
d2440ba0 JM |
1330 | NULL /* authenticate */, |
1331 | NULL /* set_beacon */, | |
1332 | NULL /* set_beacon_int */ | |
6fc6879b | 1333 | }; |